Changeset c83a55c in mainline for uspace/lib


Ignore:
Timestamp:
2011-10-31T06:52:54Z (14 years ago)
Author:
Frantisek Princ <frantisek.princ@…>
Branches:
lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
Children:
c25e39b
Parents:
e8ab32f (diff), 3ce78580 (diff)
Note: this is a merge changeset, the changes displayed below correspond to the merge itself.
Use the (diff) links above to see all the changes relative to each parent.
Message:

Merge with mainline

Location:
uspace/lib
Files:
13 edited

Legend:

Unmodified
Added
Removed
  • uspace/lib/usbdev/include/usb/dev/driver.h

    re8ab32f rc83a55c  
    161161} usb_driver_t;
    162162
    163 int usb_driver_main(usb_driver_t *);
     163int usb_driver_main(const usb_driver_t *);
    164164
    165165int usb_device_select_interface(usb_device_t *, uint8_t,
     
    171171    usb_endpoint_mapping_t **, size_t *);
    172172int usb_device_destroy_pipes(const ddf_dev_t *, usb_endpoint_mapping_t *, size_t);
    173 int usb_device_create(ddf_dev_t *, const usb_endpoint_description_t **,
    174     usb_device_t **, const char **);
     173int usb_device_init(usb_device_t *, ddf_dev_t *,
     174    const usb_endpoint_description_t **, const char **);
    175175void usb_device_deinit(usb_device_t *);
     176
    176177void * usb_device_data_alloc(usb_device_t *, size_t);
    177178
     
    179180int usb_alternate_interfaces_create(const uint8_t *, size_t, int,
    180181    usb_alternate_interfaces_t **);
    181 
     182void usb_alternate_interfaces_destroy(usb_alternate_interfaces_t *);
    182183#endif
    183184/**
  • uspace/lib/usbdev/src/altiface.c

    re8ab32f rc83a55c  
    9898        assert(config_descr_size > 0);
    9999
     100        *alternates_ptr = NULL;
    100101        if (interface_number < 0) {
    101                 alternates_ptr = NULL;
    102102                return EOK;
    103103        }
     
    105105        usb_alternate_interfaces_t *alternates
    106106            = malloc(sizeof(usb_alternate_interfaces_t));
    107 
    108107        if (alternates == NULL) {
    109108                return ENOMEM;
     
    119118        }
    120119
    121         alternates->alternatives = malloc(alternates->alternative_count
    122             * sizeof(usb_alternate_interface_descriptors_t));
     120        alternates->alternatives = calloc(alternates->alternative_count,
     121            sizeof(usb_alternate_interface_descriptors_t));
    123122        if (alternates->alternatives == NULL) {
    124123                free(alternates);
     
    176175}
    177176
    178 
     177void usb_alternate_interfaces_destroy(usb_alternate_interfaces_t *alternate)
     178{
     179        if (!alternate)
     180                return;
     181        free(alternate->alternatives);
     182        free(alternate);
     183}
    179184/**
    180185 * @}
  • uspace/lib/usbdev/src/devdrv.c

    re8ab32f rc83a55c  
    6464 * @return Task exit status.
    6565 */
    66 int usb_driver_main(usb_driver_t *drv)
     66int usb_driver_main(const usb_driver_t *drv)
    6767{
    6868        assert(drv != NULL);
     
    140140        assert(driver->ops->device_add);
    141141
    142         int rc;
    143 
    144         usb_device_t *dev = NULL;
     142        usb_device_t *dev = ddf_dev_data_alloc(gen_dev, sizeof(usb_device_t));
     143        if (dev == NULL) {
     144                usb_log_error("USB device `%s' structure allocation failed.\n",
     145                    gen_dev->name);
     146                return ENOMEM;
     147        }
    145148        const char *err_msg = NULL;
    146         rc = usb_device_create(gen_dev, driver->endpoints, &dev, &err_msg);
    147         if (rc != EOK) {
    148                 usb_log_error("USB device `%s' creation failed (%s): %s.\n",
     149        int rc = usb_device_init(dev, gen_dev, driver->endpoints, &err_msg);
     150        if (rc != EOK) {
     151                usb_log_error("USB device `%s' init failed (%s): %s.\n",
    149152                    gen_dev->name, err_msg, str_error(rc));
    150153                return rc;
    151154        }
    152         gen_dev->driver_data = dev;
    153155
    154156        rc = driver->ops->device_add(dev);
     
    516518
    517519
    518 /** Create new instance of USB device.
    519  *
     520/** Initialize new instance of USB device.
     521 *
     522 * @param[in] usb_dev Pointer to the new device.
    520523 * @param[in] ddf_dev Generic DDF device backing the USB one.
    521524 * @param[in] endpoints NULL terminated array of endpoints (NULL for none).
    522  * @param[out] dev_ptr Where to store pointer to the new device.
    523525 * @param[out] errstr_ptr Where to store description of context
    524526 *      (in case error occurs).
    525527 * @return Error code.
    526528 */
    527 int usb_device_create(ddf_dev_t *ddf_dev,
    528     const usb_endpoint_description_t **endpoints,
    529     usb_device_t **dev_ptr, const char **errstr_ptr)
    530 {
    531         assert(dev_ptr != NULL);
     529int usb_device_init(usb_device_t *usb_dev, ddf_dev_t *ddf_dev,
     530    const usb_endpoint_description_t **endpoints, const char **errstr_ptr)
     531{
     532        assert(usb_dev != NULL);
    532533        assert(ddf_dev != NULL);
    533534
    534         int rc;
    535 
    536         usb_device_t *dev = malloc(sizeof(usb_device_t));
    537         if (dev == NULL) {
    538                 *errstr_ptr = "structure allocation";
    539                 return ENOMEM;
    540         }
    541 
    542         // FIXME: proper deallocation in case of errors
    543 
    544         dev->ddf_dev = ddf_dev;
    545         dev->driver_data = NULL;
    546         dev->descriptors.configuration = NULL;
    547         dev->alternate_interfaces = NULL;
    548 
    549         dev->pipes_count = 0;
    550         dev->pipes = NULL;
     535        usb_dev->ddf_dev = ddf_dev;
     536        usb_dev->driver_data = NULL;
     537        usb_dev->descriptors.configuration = NULL;
     538        usb_dev->alternate_interfaces = NULL;
     539        usb_dev->pipes_count = 0;
     540        usb_dev->pipes = NULL;
    551541
    552542        /* Initialize backing wire and control pipe. */
    553         rc = init_wire_and_ctrl_pipe(dev, errstr_ptr);
     543        int rc = init_wire_and_ctrl_pipe(usb_dev, errstr_ptr);
    554544        if (rc != EOK) {
    555545                return rc;
     
    557547
    558548        /* Get our interface. */
    559         dev->interface_no = usb_device_get_assigned_interface(dev->ddf_dev);
     549        usb_dev->interface_no = usb_device_get_assigned_interface(ddf_dev);
    560550
    561551        /* Retrieve standard descriptors. */
    562         rc = usb_device_retrieve_descriptors(&dev->ctrl_pipe,
    563             &dev->descriptors);
    564         if (rc != EOK) {
     552        rc = usb_device_retrieve_descriptors(&usb_dev->ctrl_pipe,
     553            &usb_dev->descriptors);
     554        if (rc != EOK) {
     555                /* Nothing allocated, nothing to free. */
    565556                *errstr_ptr = "descriptor retrieval";
    566557                return rc;
    567558        }
    568559
    569         /* Create alternate interfaces. */
    570         rc = usb_alternate_interfaces_create(dev->descriptors.configuration,
    571             dev->descriptors.configuration_size, dev->interface_no,
    572             &dev->alternate_interfaces);
    573         if (rc != EOK) {
    574                 /* We will try to silently ignore this. */
    575                 dev->alternate_interfaces = NULL;
    576         }
    577 
    578         rc = initialize_other_pipes(endpoints, dev, 0);
    579         if (rc != EOK) {
     560        /* Create alternate interfaces. We will silently ignore failure. */
     561        //TODO Why ignore?
     562        usb_alternate_interfaces_create(usb_dev->descriptors.configuration,
     563            usb_dev->descriptors.configuration_size, usb_dev->interface_no,
     564            &usb_dev->alternate_interfaces);
     565
     566        rc = initialize_other_pipes(endpoints, usb_dev, 0);
     567        if (rc != EOK) {
     568                /* Full configuration descriptor is allocated. */
     569                free(usb_dev->descriptors.configuration);
     570                /* Alternate interfaces may be allocated */
     571                usb_alternate_interfaces_destroy(usb_dev->alternate_interfaces);
    580572                *errstr_ptr = "pipes initialization";
    581573                return rc;
     
    583575
    584576        *errstr_ptr = NULL;
    585         *dev_ptr = dev;
    586577
    587578        return EOK;
    588579}
    589580
    590 /** Destroy instance of a USB device.
     581/** Clean instance of a USB device.
    591582 *
    592583 * @param dev Device to be de-initialized.
     
    596587void usb_device_deinit(usb_device_t *dev)
    597588{
    598         if (dev == NULL) {
    599                 return;
    600         }
    601 
    602         /* Ignore errors and hope for the best. */
    603         destroy_current_pipes(dev);
    604 
    605         if (dev->alternate_interfaces != NULL) {
    606                 free(dev->alternate_interfaces->alternatives);
    607         }
    608         free(dev->alternate_interfaces);
    609         free(dev->descriptors.configuration);
    610         free(dev->driver_data);
     589        if (dev) {
     590                /* Ignore errors and hope for the best. */
     591                destroy_current_pipes(dev);
     592
     593                usb_alternate_interfaces_destroy(dev->alternate_interfaces);
     594                free(dev->descriptors.configuration);
     595                free(dev->driver_data);
     596        }
    611597}
    612598
  • uspace/lib/usbhost/include/usb/host/endpoint.h

    re8ab32f rc83a55c  
    3636#define LIBUSBHOST_HOST_ENDPOINT_H
    3737
    38 #include <assert.h>
    3938#include <bool.h>
    4039#include <adt/list.h>
    4140#include <fibril_synch.h>
    42 
    4341#include <usb/usb.h>
    4442
     43/** Host controller side endpoint structure. */
    4544typedef struct endpoint {
     45        /** Part of linked list. */
     46        link_t link;
     47        /** USB address. */
    4648        usb_address_t address;
     49        /** USB endpoint number. */
    4750        usb_endpoint_t endpoint;
     51        /** Communication direction. */
    4852        usb_direction_t direction;
     53        /** USB transfer type. */
    4954        usb_transfer_type_t transfer_type;
     55        /** Communication speed. */
    5056        usb_speed_t speed;
     57        /** Maximum size of data packets. */
    5158        size_t max_packet_size;
     59        /** Necessary bandwidth. */
     60        size_t bandwidth;
     61        /** Value of the toggle bit. */
    5262        unsigned toggle:1;
     63        /** True if there is a batch using this scheduled for this endpoint. */
     64        volatile bool active;
     65        /** Protects resources and active status changes. */
    5366        fibril_mutex_t guard;
     67        /** Signals change of active status. */
    5468        fibril_condvar_t avail;
    55         volatile bool active;
    56         void (*destroy_hook)(struct endpoint *);
     69        /** Optional device specific data. */
    5770        struct {
     71                /** Device specific data. */
    5872                void *data;
     73                /** Callback to get the value of toggle bit. */
    5974                int (*toggle_get)(void *);
     75                /** Callback to set the value of toggle bit. */
    6076                void (*toggle_set)(void *, int);
    6177        } hc_data;
    6278} endpoint_t;
    6379
    64 endpoint_t * endpoint_get(usb_address_t address, usb_endpoint_t endpoint,
     80endpoint_t * endpoint_create(usb_address_t address, usb_endpoint_t endpoint,
    6581    usb_direction_t direction, usb_transfer_type_t type, usb_speed_t speed,
    66     size_t max_packet_size);
    67 
     82    size_t max_packet_size, size_t bw);
    6883void endpoint_destroy(endpoint_t *instance);
    6984
    7085void endpoint_set_hc_data(endpoint_t *instance,
    71     void *data, void (*destroy_hook)(endpoint_t *),
    72     int (*toggle_get)(void *), void (*toggle_set)(void *, int));
    73 
     86    void *data, int (*toggle_get)(void *), void (*toggle_set)(void *, int));
    7487void endpoint_clear_hc_data(endpoint_t *instance);
    7588
    7689void endpoint_use(endpoint_t *instance);
    77 
    7890void endpoint_release(endpoint_t *instance);
    7991
    8092int endpoint_toggle_get(endpoint_t *instance);
    81 
    8293void endpoint_toggle_set(endpoint_t *instance, int toggle);
    8394
    84 void endpoint_toggle_reset_filtered(endpoint_t *instance, usb_target_t target);
     95/** list_get_instance wrapper.
     96 * @param item Pointer to link member.
     97 * @return Pointer to enpoint_t structure.
     98 */
     99static inline endpoint_t * endpoint_get_instance(link_t *item)
     100{
     101        return list_get_instance(item, endpoint_t, link);
     102}
    85103#endif
    86104/**
  • uspace/lib/usbhost/include/usb/host/hcd.h

    re8ab32f rc83a55c  
    3737
    3838#include <assert.h>
     39#include <usbhc_iface.h>
     40
    3941#include <usb/host/usb_device_manager.h>
    4042#include <usb/host/usb_endpoint_manager.h>
    4143#include <usb/host/usb_transfer_batch.h>
    42 #include <usbhc_iface.h>
    4344
    4445typedef struct hcd hcd_t;
    4546
     47/** Generic host controller driver structure. */
    4648struct hcd {
     49        /** Device manager storing handles and addresses. */
    4750        usb_device_manager_t dev_manager;
     51        /** Endpoint manager. */
    4852        usb_endpoint_manager_t ep_manager;
     53
     54        /** Device specific driver data. */
    4955        void *private_data;
    50 
     56        /** Transfer scheduling, implement in device driver. */
    5157        int (*schedule)(hcd_t *, usb_transfer_batch_t *);
     58        /** Hook called upon registering new endpoint. */
    5259        int (*ep_add_hook)(hcd_t *, endpoint_t *);
     60        /** Hook called upon removing of an endpoint. */
     61        void (*ep_remove_hook)(hcd_t *, endpoint_t *);
    5362};
    5463/*----------------------------------------------------------------------------*/
    55 static inline int hcd_init(hcd_t *hcd, size_t bandwidth,
     64/** Initialize hcd_t structure.
     65 * Initializes device and endpoint managers. Sets data nd hook pointer to NULL.
     66 * @param hcd hcd_t structure to initialize, non-null.
     67 * @param bandwidth Available bandwidth, passed to endpoint manager.
     68 * @param bw_count Bandwidth compute function, passed to endpoint manager.
     69 */
     70static inline void hcd_init(hcd_t *hcd, size_t bandwidth,
    5671    size_t (*bw_count)(usb_speed_t, usb_transfer_type_t, size_t, size_t))
    5772{
    5873        assert(hcd);
    5974        usb_device_manager_init(&hcd->dev_manager);
    60         return usb_endpoint_manager_init(&hcd->ep_manager, bandwidth, bw_count);
     75        usb_endpoint_manager_init(&hcd->ep_manager, bandwidth, bw_count);
     76        hcd->private_data = NULL;
     77        hcd->schedule = NULL;
     78        hcd->ep_add_hook = NULL;
     79        hcd->ep_remove_hook = NULL;
    6180}
    6281/*----------------------------------------------------------------------------*/
    63 static inline void hcd_destroy(hcd_t *hcd)
    64 {
    65         usb_endpoint_manager_destroy(&hcd->ep_manager);
    66 }
    67 /*----------------------------------------------------------------------------*/
    68 static inline void reset_ep_if_need(
    69     hcd_t *hcd, usb_target_t target, const char* setup_data)
     82/** Check registered endpoints and reset toggle bit if necessary.
     83 * @param hcd hcd_t structure, non-null.
     84 * @param target Control communication target.
     85 * @param setup_data Setup packet of the control communication.
     86 */
     87static inline void reset_ep_if_need(hcd_t *hcd, usb_target_t target,
     88    const char setup_data[8])
    7089{
    7190        assert(hcd);
    72         usb_endpoint_manager_reset_if_need(
     91        usb_endpoint_manager_reset_eps_if_need(
    7392            &hcd->ep_manager, target, (const uint8_t *)setup_data);
    7493}
    7594/*----------------------------------------------------------------------------*/
    76 static inline hcd_t * fun_to_hcd(ddf_fun_t *fun)
     95/** Data retrieve wrapper.
     96 * @param fun ddf function, non-null.
     97 * @return pointer cast to hcd_t*.
     98 */
     99static inline hcd_t * fun_to_hcd(const ddf_fun_t *fun)
    77100{
    78101        assert(fun);
  • uspace/lib/usbhost/include/usb/host/usb_device_manager.h

    re8ab32f rc83a55c  
    4949#define USB_ADDRESS_COUNT (USB11_ADDRESS_MAX + 1)
    5050
    51 /** Information about attached USB device. */
    52 struct usb_device_info {
    53         usb_speed_t speed;
    54         bool occupied;
    55         devman_handle_t handle;
    56 };
    57 
    5851/** Host controller device manager.
    59  * You shall not access members directly but only using functions below.
     52 * You shall not access members directly.
    6053 */
    6154typedef struct {
    62         struct usb_device_info devices[USB_ADDRESS_COUNT];
     55        /** Information about attached USB devices. */
     56        struct {
     57                usb_speed_t speed;      /**< Device speed */
     58                bool occupied;          /**< The address is in use. */
     59                devman_handle_t handle; /**< Devman handle of the device. */
     60        } devices[USB_ADDRESS_COUNT];
    6361        fibril_mutex_t guard;
     62        /** The last reserved address */
    6463        usb_address_t last_address;
    6564} usb_device_manager_t;
     
    7069    usb_device_manager_t *instance, usb_speed_t speed);
    7170
    72 void usb_device_manager_bind(usb_device_manager_t *instance,
     71int usb_device_manager_bind(usb_device_manager_t *instance,
    7372    usb_address_t address, devman_handle_t handle);
    7473
    75 void usb_device_manager_release(usb_device_manager_t *instance,
     74int usb_device_manager_release(usb_device_manager_t *instance,
    7675    usb_address_t address);
    7776
    78 usb_address_t usb_device_manager_find(usb_device_manager_t *instance,
     77usb_address_t usb_device_manager_find_address(usb_device_manager_t *instance,
    7978    devman_handle_t handle);
    8079
    81 bool usb_device_manager_find_by_address(usb_device_manager_t *instance,
    82     usb_address_t address, devman_handle_t *handle);
    83 
    84 usb_speed_t usb_device_manager_get_speed(usb_device_manager_t *instance,
    85     usb_address_t address);
     80int usb_device_manager_get_info_by_address(usb_device_manager_t *instance,
     81    usb_address_t address, devman_handle_t *handle, usb_speed_t *speed);
    8682#endif
    8783/**
  • uspace/lib/usbhost/include/usb/host/usb_endpoint_manager.h

    re8ab32f rc83a55c  
    4040#define LIBUSBHOST_HOST_USB_ENDPOINT_MANAGER_H
    4141
    42 #include <stdlib.h>
    43 #include <adt/hash_table.h>
     42#include <adt/list.h>
    4443#include <fibril_synch.h>
    4544#include <usb/usb.h>
     45
    4646#include <usb/host/endpoint.h>
    4747
    48 #define BANDWIDTH_TOTAL_USB11 12000000
     48/** Bytes per second in FULL SPEED */
     49#define BANDWIDTH_TOTAL_USB11 (12000000 / 8)
     50/** 90% of total bandwidth is available for periodic transfers */
    4951#define BANDWIDTH_AVAILABLE_USB11 ((BANDWIDTH_TOTAL_USB11 / 10) * 9)
     52/** 16 addresses per list */
     53#define ENDPOINT_LIST_COUNT 8
    5054
     55/** Endpoint management structure */
    5156typedef struct usb_endpoint_manager {
    52         hash_table_t ep_table;
     57        /** Store endpoint_t instances */
     58        list_t endpoint_lists[ENDPOINT_LIST_COUNT];
     59        /** Prevents races accessing lists */
    5360        fibril_mutex_t guard;
     61        /** Size of the bandwidth pool */
    5462        size_t free_bw;
     63        /** Use this function to count bw required by EP */
    5564        size_t (*bw_count)(usb_speed_t, usb_transfer_type_t, size_t, size_t);
    5665} usb_endpoint_manager_t;
     
    6372    size_t (*bw_count)(usb_speed_t, usb_transfer_type_t, size_t, size_t));
    6473
    65 void usb_endpoint_manager_destroy(usb_endpoint_manager_t *instance);
     74void usb_endpoint_manager_reset_eps_if_need(usb_endpoint_manager_t *instance,
     75    usb_target_t target, const uint8_t data[8]);
    6676
    67 int usb_endpoint_manager_register_ep(usb_endpoint_manager_t *instance,
    68     endpoint_t *ep, size_t data_size);
    69 
    70 int usb_endpoint_manager_unregister_ep(usb_endpoint_manager_t *instance,
     77int usb_endpoint_manager_register_ep(
     78    usb_endpoint_manager_t *instance, endpoint_t *ep, size_t data_size);
     79int usb_endpoint_manager_unregister_ep(
     80    usb_endpoint_manager_t *instance, endpoint_t *ep);
     81endpoint_t * usb_endpoint_manager_find_ep(usb_endpoint_manager_t *instance,
    7182    usb_address_t address, usb_endpoint_t ep, usb_direction_t direction);
    7283
    73 endpoint_t * usb_endpoint_manager_get_ep(usb_endpoint_manager_t *instance,
    74     usb_address_t address, usb_endpoint_t ep, usb_direction_t direction,
    75     size_t *bw);
    76 
    77 void usb_endpoint_manager_reset_if_need(
    78     usb_endpoint_manager_t *instance, usb_target_t target, const uint8_t *data);
    79 
    80 /** Wrapper combining allocation and insertion */
    81 static inline int usb_endpoint_manager_add_ep(usb_endpoint_manager_t *instance,
     84int usb_endpoint_manager_add_ep(usb_endpoint_manager_t *instance,
    8285    usb_address_t address, usb_endpoint_t endpoint, usb_direction_t direction,
    8386    usb_transfer_type_t type, usb_speed_t speed, size_t max_packet_size,
    84     size_t data_size)
    85 {
    86         endpoint_t *ep = endpoint_get(
    87             address, endpoint, direction, type, speed, max_packet_size);
    88         if (!ep)
    89                 return ENOMEM;
     87    size_t data_size, int (*callback)(endpoint_t *, void *), void *arg);
    9088
    91         const int ret =
    92             usb_endpoint_manager_register_ep(instance, ep, data_size);
    93         if (ret != EOK) {
    94                 endpoint_destroy(ep);
    95         }
    96         return ret;
    97 }
     89int usb_endpoint_manager_remove_ep(usb_endpoint_manager_t *instance,
     90    usb_address_t address, usb_endpoint_t endpoint, usb_direction_t direction,
     91    void (*callback)(endpoint_t *, void *), void *arg);
    9892#endif
    9993/**
    10094 * @}
    10195 */
    102 
  • uspace/lib/usbhost/include/usb/host/usb_transfer_batch.h

    re8ab32f rc83a55c  
    4343#define USB_SETUP_PACKET_SIZE 8
    4444
    45 typedef struct usb_transfer_batch usb_transfer_batch_t;
    4645/** Structure stores additional data needed for communication with EP */
    47 struct usb_transfer_batch {
     46typedef struct usb_transfer_batch {
    4847        /** Endpoint used for communication */
    4948        endpoint_t *ep;
     
    7776        /** Callback to properly remove driver data during destruction */
    7877        void (*private_data_dtor)(void *p_data);
    79 };
     78} usb_transfer_batch_t;
    8079
    8180/** Printf formatting string for dumping usb_transfer_batch_t. */
     
    9392
    9493
    95 usb_transfer_batch_t * usb_transfer_batch_get(
     94usb_transfer_batch_t * usb_transfer_batch_create(
    9695    endpoint_t *ep,
    9796    char *buffer,
     
    105104    void (*private_data_dtor)(void *p_data)
    106105);
     106void usb_transfer_batch_destroy(const usb_transfer_batch_t *instance);
    107107
    108 void usb_transfer_batch_finish(usb_transfer_batch_t *instance,
     108void usb_transfer_batch_finish(const usb_transfer_batch_t *instance,
    109109    const void* data, size_t size);
    110 void usb_transfer_batch_call_in(usb_transfer_batch_t *instance);
    111 void usb_transfer_batch_call_out(usb_transfer_batch_t *instance);
    112 void usb_transfer_batch_dispose(usb_transfer_batch_t *instance);
    113 
    114 /** Helper function, calls callback and correctly destroys batch structure.
    115  *
    116  * @param[in] instance Batch structure to use.
    117  */
    118 static inline void usb_transfer_batch_call_in_and_dispose(
    119     usb_transfer_batch_t *instance)
    120 {
    121         assert(instance);
    122         usb_transfer_batch_call_in(instance);
    123         usb_transfer_batch_dispose(instance);
    124 }
    125110/*----------------------------------------------------------------------------*/
    126 /** Helper function calls callback and correctly destroys batch structure.
    127  *
    128  * @param[in] instance Batch structure to use.
    129  */
    130 static inline void usb_transfer_batch_call_out_and_dispose(
    131     usb_transfer_batch_t *instance)
    132 {
    133         assert(instance);
    134         usb_transfer_batch_call_out(instance);
    135         usb_transfer_batch_dispose(instance);
    136 }
    137 /*----------------------------------------------------------------------------*/
    138 /** Helper function, sets error value and finishes transfer.
     111/** Override error value and finishes transfer.
    139112 *
    140113 * @param[in] instance Batch structure to use.
     
    151124}
    152125/*----------------------------------------------------------------------------*/
    153 /** Helper function, determines batch direction absed on the present callbacks
    154  * @param[in] instance Batch structure to use.
     126/** Determine batch direction based on the callbacks present
     127 * @param[in] instance Batch structure to use, non-null.
    155128 * @return USB_DIRECTION_IN, or USB_DIRECTION_OUT.
    156129 */
  • uspace/lib/usbhost/src/endpoint.c

    re8ab32f rc83a55c  
    2626 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
    2727 */
    28 
    29 /** @addtogroup drvusbuhcihc
     28/** @addtogroup libusbhost
    3029 * @{
    3130 */
     
    3938#include <usb/host/endpoint.h>
    4039
    41 endpoint_t * endpoint_get(usb_address_t address, usb_endpoint_t endpoint,
     40/** Allocate ad initialize endpoint_t structure.
     41 * @param address USB address.
     42 * @param endpoint USB endpoint number.
     43 * @param direction Communication direction.
     44 * @param type USB transfer type.
     45 * @param speed Communication speed.
     46 * @param max_packet_size Maximum size of data packets.
     47 * @param bw Required bandwidth.
     48 * @return Pointer to initialized endpoint_t structure, NULL on failure.
     49 */
     50endpoint_t * endpoint_create(usb_address_t address, usb_endpoint_t endpoint,
    4251    usb_direction_t direction, usb_transfer_type_t type, usb_speed_t speed,
    43     size_t max_packet_size)
     52    size_t max_packet_size, size_t bw)
    4453{
    4554        endpoint_t *instance = malloc(sizeof(endpoint_t));
     
    5160                instance->speed = speed;
    5261                instance->max_packet_size = max_packet_size;
     62                instance->bandwidth = bw;
    5363                instance->toggle = 0;
    5464                instance->active = false;
    55                 instance->destroy_hook = NULL;
    5665                instance->hc_data.data = NULL;
    5766                instance->hc_data.toggle_get = NULL;
    5867                instance->hc_data.toggle_set = NULL;
     68                link_initialize(&instance->link);
    5969                fibril_mutex_initialize(&instance->guard);
    6070                fibril_condvar_initialize(&instance->avail);
    61                 endpoint_clear_hc_data(instance);
    6271        }
    6372        return instance;
    6473}
    6574/*----------------------------------------------------------------------------*/
     75/** Properly dispose of endpoint_t structure.
     76 * @param instance endpoint_t structure.
     77 */
    6678void endpoint_destroy(endpoint_t *instance)
    6779{
    6880        assert(instance);
     81        //TODO: Do something about waiting fibrils.
    6982        assert(!instance->active);
    70         if (instance->hc_data.data) {
    71                 assert(instance->destroy_hook);
    72                 instance->destroy_hook(instance);
    73         }
     83        assert(instance->hc_data.data == NULL);
    7484        free(instance);
    7585}
    7686/*----------------------------------------------------------------------------*/
     87/** Set device specific data and hooks.
     88 * @param instance endpoint_t structure.
     89 * @param data device specific data.
     90 * @param toggle_get Hook to call when retrieving value of toggle bit.
     91 * @param toggle_set Hook to call when setting the value of toggle bit.
     92 */
    7793void endpoint_set_hc_data(endpoint_t *instance,
    78     void *data, void (*destroy_hook)(endpoint_t *),
    79     int (*toggle_get)(void *), void (*toggle_set)(void *, int))
     94    void *data, int (*toggle_get)(void *), void (*toggle_set)(void *, int))
    8095{
    8196        assert(instance);
    82         instance->destroy_hook = destroy_hook;
     97        fibril_mutex_lock(&instance->guard);
    8398        instance->hc_data.data = data;
    8499        instance->hc_data.toggle_get = toggle_get;
    85100        instance->hc_data.toggle_set = toggle_set;
     101        fibril_mutex_unlock(&instance->guard);
    86102}
    87103/*----------------------------------------------------------------------------*/
     104/** Clear device specific data and hooks.
     105 * @param instance endpoint_t structure.
     106 * @note This function does not free memory pointed to by data pointer.
     107 */
    88108void endpoint_clear_hc_data(endpoint_t *instance)
    89109{
    90110        assert(instance);
    91         instance->destroy_hook = NULL;
     111        fibril_mutex_lock(&instance->guard);
    92112        instance->hc_data.data = NULL;
    93113        instance->hc_data.toggle_get = NULL;
    94114        instance->hc_data.toggle_set = NULL;
     115        fibril_mutex_unlock(&instance->guard);
    95116}
    96117/*----------------------------------------------------------------------------*/
     118/** Mark the endpoint as active and block access for further fibrils.
     119 * @param instance endpoint_t structure.
     120 */
    97121void endpoint_use(endpoint_t *instance)
    98122{
     
    105129}
    106130/*----------------------------------------------------------------------------*/
     131/** Mark the endpoint as inactive and allow access for further fibrils.
     132 * @param instance endpoint_t structure.
     133 */
    107134void endpoint_release(endpoint_t *instance)
    108135{
     
    114141}
    115142/*----------------------------------------------------------------------------*/
     143/** Get the value of toggle bit.
     144 * @param instance endpoint_t structure.
     145 * @note Will use provided hook.
     146 */
    116147int endpoint_toggle_get(endpoint_t *instance)
    117148{
    118149        assert(instance);
     150        fibril_mutex_lock(&instance->guard);
    119151        if (instance->hc_data.toggle_get)
    120152                instance->toggle =
    121153                    instance->hc_data.toggle_get(instance->hc_data.data);
    122         return (int)instance->toggle;
     154        const int ret = instance->toggle;
     155        fibril_mutex_unlock(&instance->guard);
     156        return ret;
    123157}
    124158/*----------------------------------------------------------------------------*/
     159/** Set the value of toggle bit.
     160 * @param instance endpoint_t structure.
     161 * @note Will use provided hook.
     162 */
    125163void endpoint_toggle_set(endpoint_t *instance, int toggle)
    126164{
    127165        assert(instance);
    128166        assert(toggle == 0 || toggle == 1);
     167        fibril_mutex_lock(&instance->guard);
     168        instance->toggle = toggle;
    129169        if (instance->hc_data.toggle_set)
    130170                instance->hc_data.toggle_set(instance->hc_data.data, toggle);
    131         instance->toggle = toggle;
    132 }
    133 /*----------------------------------------------------------------------------*/
    134 void endpoint_toggle_reset_filtered(endpoint_t *instance, usb_target_t target)
    135 {
    136         assert(instance);
    137         if (instance->address == target.address &&
    138             (instance->endpoint == target.endpoint || target.endpoint == 0))
    139                 endpoint_toggle_set(instance, 0);
     171        fibril_mutex_unlock(&instance->guard);
    140172}
    141173/**
  • uspace/lib/usbhost/src/iface.c

    re8ab32f rc83a55c  
    4949        assert(hcd);
    5050
    51         int ret;
    52 
    53         size_t res_bw;
    54         endpoint_t *ep = usb_endpoint_manager_get_ep(&hcd->ep_manager,
    55             target.address, target.endpoint, direction, &res_bw);
     51        endpoint_t *ep = usb_endpoint_manager_find_ep(&hcd->ep_manager,
     52            target.address, target.endpoint, direction);
    5653        if (ep == NULL) {
    5754                usb_log_error("Endpoint(%d:%d) not registered for %s.\n",
     
    6562        const size_t bw = bandwidth_count_usb11(
    6663            ep->speed, ep->transfer_type, size, ep->max_packet_size);
    67         if (res_bw < bw) {
     64        /* Check if we have enough bandwidth reserved */
     65        if (ep->bandwidth < bw) {
    6866                usb_log_error("Endpoint(%d:%d) %s needs %zu bw "
    6967                    "but only %zu is reserved.\n",
    70                     target.address, target.endpoint, name, bw, res_bw);
     68                    ep->address, ep->endpoint, name, bw, ep->bandwidth);
    7169                return ENOSPC;
    7270        }
     
    7876        /* No private data and no private data dtor */
    7977        usb_transfer_batch_t *batch =
    80             usb_transfer_batch_get(ep, data, size, setup_data,
     78            usb_transfer_batch_create(ep, data, size, setup_data,
    8179            in, out, arg, fun, NULL, NULL);
    8280        if (!batch) {
     
    8482        }
    8583
    86         ret = hcd->schedule(hcd, batch);
     84        const int ret = hcd->schedule(hcd, batch);
    8785        if (ret != EOK)
    88                 usb_transfer_batch_dispose(batch);
     86                usb_transfer_batch_destroy(batch);
    8987
    9088        return ret;
     
    130128
    131129        usb_log_debug("Address bind %d-%" PRIun ".\n", address, handle);
    132         usb_device_manager_bind(&hcd->dev_manager, address, handle);
    133         return EOK;
     130        return usb_device_manager_bind(&hcd->dev_manager, address, handle);
    134131}
    135132/*----------------------------------------------------------------------------*/
     
    147144        hcd_t *hcd = fun_to_hcd(fun);
    148145        assert(hcd);
    149         const bool found =
    150             usb_device_manager_find_by_address(&hcd->dev_manager, address, handle);
    151         return found ? EOK : ENOENT;
     146        return usb_device_manager_get_info_by_address(
     147            &hcd->dev_manager, address, handle, NULL);
    152148}
    153149/*----------------------------------------------------------------------------*/
     
    166162        usb_device_manager_release(&hcd->dev_manager, address);
    167163        return EOK;
     164}
     165/*----------------------------------------------------------------------------*/
     166static int register_helper(endpoint_t *ep, void *arg)
     167{
     168        hcd_t *hcd = arg;
     169        assert(ep);
     170        assert(hcd);
     171        if (hcd->ep_add_hook)
     172                return hcd->ep_add_hook(hcd, ep);
     173        return EOK;
     174}
     175/*----------------------------------------------------------------------------*/
     176static void unregister_helper(endpoint_t *ep, void *arg)
     177{
     178        hcd_t *hcd = arg;
     179        assert(ep);
     180        assert(hcd);
     181        if (hcd->ep_remove_hook)
     182                hcd->ep_remove_hook(hcd, ep);
    168183}
    169184/*----------------------------------------------------------------------------*/
     
    180195        /* Default address is not bound or registered,
    181196         * thus it does not provide speed info. */
    182         const usb_speed_t speed = (address == 0) ? ep_speed :
    183             usb_device_manager_get_speed(&hcd->dev_manager, address);
     197        usb_speed_t speed = ep_speed;
     198        /* NOTE The function will return EINVAL and won't
     199         * touch speed variable for default address */
     200        usb_device_manager_get_info_by_address(
     201            &hcd->dev_manager, address, NULL, &speed);
    184202
    185203        usb_log_debug("Register endpoint %d:%d %s-%s %s %zuB %ums.\n",
     
    188206            max_packet_size, interval);
    189207
    190         endpoint_t *ep = endpoint_get(
    191             address, endpoint, direction, transfer_type, speed, max_packet_size);
    192         if (!ep)
    193                 return ENOMEM;
    194         int ret = EOK;
    195 
    196         if (hcd->ep_add_hook) {
    197                 ret = hcd->ep_add_hook(hcd, ep);
    198         }
    199         if (ret != EOK) {
    200                 endpoint_destroy(ep);
    201                 return ret;
    202         }
    203 
    204         ret = usb_endpoint_manager_register_ep(&hcd->ep_manager, ep, size);
    205         if (ret != EOK) {
    206                 endpoint_destroy(ep);
    207         }
    208         return ret;
     208        return usb_endpoint_manager_add_ep(&hcd->ep_manager, address, endpoint,
     209            direction, transfer_type, speed, max_packet_size, size,
     210            register_helper, hcd);
    209211}
    210212/*----------------------------------------------------------------------------*/
     
    218220        usb_log_debug("Unregister endpoint %d:%d %s.\n",
    219221            address, endpoint, usb_str_direction(direction));
    220         return usb_endpoint_manager_unregister_ep(&hcd->ep_manager, address,
    221             endpoint, direction);
     222        return usb_endpoint_manager_remove_ep(&hcd->ep_manager, address,
     223            endpoint, direction, unregister_helper, hcd);
    222224}
    223225/*----------------------------------------------------------------------------*/
  • uspace/lib/usbhost/src/usb_device_manager.c

    re8ab32f rc83a55c  
    3838#include <usb/host/usb_device_manager.h>
    3939
    40 /*----------------------------------------------------------------------------*/
    4140/** Initialize device manager structure.
    4241 *
     
    4847{
    4948        assert(instance);
    50         unsigned i = 0;
    51         for (; i < USB_ADDRESS_COUNT; ++i) {
     49        for (unsigned i = 0; i < USB_ADDRESS_COUNT; ++i) {
    5250                instance->devices[i].occupied = false;
    5351                instance->devices[i].handle = 0;
     
    7775                ++new_address;
    7876                if (new_address > USB11_ADDRESS_MAX)
    79                         new_address = 1;
     77                        new_address = 1; // NOTE it should be safe to put 0 here
     78                                         // TODO Use mod
    8079                if (new_address == instance->last_address) {
    8180                        fibril_mutex_unlock(&instance->guard);
     
    8685        assert(new_address != USB_ADDRESS_DEFAULT);
    8786        assert(instance->devices[new_address].occupied == false);
     87        assert(instance->devices[new_address].handle == 0);
    8888
    8989        instance->devices[new_address].occupied = true;
     
    100100 * @param[in] address Device address
    101101 * @param[in] handle Devman handle of the device.
    102  */
    103 void usb_device_manager_bind(usb_device_manager_t *instance,
     102 * @return Error code.
     103 */
     104int usb_device_manager_bind(usb_device_manager_t *instance,
    104105    usb_address_t address, devman_handle_t handle)
    105106{
    106         assert(instance);
    107         fibril_mutex_lock(&instance->guard);
    108 
    109         assert(address > 0);
    110         assert(address <= USB11_ADDRESS_MAX);
    111         assert(instance->devices[address].occupied);
    112 
     107        if ((address <= 0) || (address >= USB_ADDRESS_COUNT)) {
     108                return EINVAL;
     109        }
     110        assert(instance);
     111
     112        fibril_mutex_lock(&instance->guard);
     113        /* Not reserved */
     114        if (!instance->devices[address].occupied) {
     115                fibril_mutex_unlock(&instance->guard);
     116                return ENOENT;
     117        }
     118        /* Already bound */
     119        if (instance->devices[address].handle != 0) {
     120                fibril_mutex_unlock(&instance->guard);
     121                return EEXISTS;
     122        }
    113123        instance->devices[address].handle = handle;
    114124        fibril_mutex_unlock(&instance->guard);
     125        return EOK;
    115126}
    116127/*----------------------------------------------------------------------------*/
     
    119130 * @param[in] instance Device manager structure to use.
    120131 * @param[in] address Device address
    121  */
    122 void usb_device_manager_release(
     132 * @return Error code.
     133 */
     134int usb_device_manager_release(
    123135    usb_device_manager_t *instance, usb_address_t address)
    124136{
    125         assert(instance);
    126         assert(address > 0);
    127         assert(address <= USB11_ADDRESS_MAX);
    128 
    129         fibril_mutex_lock(&instance->guard);
    130         assert(instance->devices[address].occupied);
     137        if ((address <= 0) || (address >= USB_ADDRESS_COUNT)) {
     138                return EINVAL;
     139        }
     140        assert(instance);
     141
     142        fibril_mutex_lock(&instance->guard);
     143        if (!instance->devices[address].occupied) {
     144                fibril_mutex_unlock(&instance->guard);
     145                return ENOENT;
     146        }
    131147
    132148        instance->devices[address].occupied = false;
    133         fibril_mutex_unlock(&instance->guard);
     149        instance->devices[address].handle = 0;
     150        fibril_mutex_unlock(&instance->guard);
     151        return EOK;
    134152}
    135153/*----------------------------------------------------------------------------*/
     
    140158 * @return USB Address, or error code.
    141159 */
    142 usb_address_t usb_device_manager_find(
     160usb_address_t usb_device_manager_find_address(
    143161    usb_device_manager_t *instance, devman_handle_t handle)
    144162{
    145163        assert(instance);
    146164        fibril_mutex_lock(&instance->guard);
    147         usb_address_t address = 1;
    148         while (address <= USB11_ADDRESS_MAX) {
     165        for (usb_address_t address = 1; address <= USB11_ADDRESS_MAX; ++address)
     166        {
    149167                if (instance->devices[address].handle == handle) {
    150168                        assert(instance->devices[address].occupied);
     
    152170                        return address;
    153171                }
    154                 ++address;
    155172        }
    156173        fibril_mutex_unlock(&instance->guard);
    157174        return ENOENT;
    158175}
    159 
    160 /** Find devman handle assigned to USB address.
    161  * Intentionally refuse to find handle of default address.
     176/*----------------------------------------------------------------------------*/
     177/** Find devman handle and speed assigned to USB address.
     178 * Intentionally refuse to work on default address.
    162179 *
    163180 * @param[in] instance Device manager structure to use.
    164181 * @param[in] address Address the caller wants to find.
    165182 * @param[out] handle Where to store found handle.
    166  * @return Whether such address is currently occupied.
    167  */
    168 bool usb_device_manager_find_by_address(usb_device_manager_t *instance,
    169     usb_address_t address, devman_handle_t *handle)
    170 {
    171         assert(instance);
    172         fibril_mutex_lock(&instance->guard);
     183 * @param[out] speed Assigned speed.
     184 * @return Error code.
     185 */
     186int usb_device_manager_get_info_by_address(usb_device_manager_t *instance,
     187    usb_address_t address, devman_handle_t *handle, usb_speed_t *speed)
     188{
     189        assert(instance);
    173190        if ((address <= 0) || (address >= USB_ADDRESS_COUNT)) {
    174                 fibril_mutex_unlock(&instance->guard);
    175                 return false;
    176         }
     191                return EINVAL;
     192        }
     193
     194        fibril_mutex_lock(&instance->guard);
    177195        if (!instance->devices[address].occupied) {
    178196                fibril_mutex_unlock(&instance->guard);
    179                 return false;
     197                return ENOENT;
    180198        }
    181199
     
    183201                *handle = instance->devices[address].handle;
    184202        }
    185 
    186         fibril_mutex_unlock(&instance->guard);
    187         return true;
    188 }
    189 
    190 /*----------------------------------------------------------------------------*/
    191 /** Get speed associated with the address
    192  *
    193  * @param[in] instance Device manager structure to use.
    194  * @param[in] address Address of the device.
    195  * @return USB speed.
    196  */
    197 usb_speed_t usb_device_manager_get_speed(
    198     usb_device_manager_t *instance, usb_address_t address)
    199 {
    200         assert(instance);
    201         assert(address >= 0);
    202         assert(address <= USB11_ADDRESS_MAX);
    203 
    204         return instance->devices[address].speed;
     203        if (speed != NULL) {
     204                *speed = instance->devices[address].speed;
     205        }
     206
     207        fibril_mutex_unlock(&instance->guard);
     208        return EOK;
    205209}
    206210/**
  • uspace/lib/usbhost/src/usb_endpoint_manager.c

    re8ab32f rc83a55c  
    3434#include <usb/host/usb_endpoint_manager.h>
    3535
    36 #define BUCKET_COUNT 7
    37 
    38 #define MAX_KEYS (3)
    39 typedef struct {
    40         link_t link;
    41         size_t bw;
    42         endpoint_t *ep;
    43 } node_t;
    44 /*----------------------------------------------------------------------------*/
    45 static hash_index_t node_hash(unsigned long key[])
    46 {
    47         /* USB endpoints use 4 bits, thus ((key[0] << 4) | key[1])
    48          * produces unique value for every address.endpoint pair */
    49         return ((key[0] << 4) | key[1]) % BUCKET_COUNT;
    50 }
    51 /*----------------------------------------------------------------------------*/
    52 static int node_compare(unsigned long key[], hash_count_t keys, link_t *item)
    53 {
    54         assert(item);
    55         node_t *node = hash_table_get_instance(item, node_t, link);
    56         assert(node);
    57         assert(node->ep);
    58         bool match = true;
    59         switch (keys) {
    60         case 3:
    61                 match = match &&
    62                     ((key[2] == node->ep->direction)
    63                     || (node->ep->direction == USB_DIRECTION_BOTH));
    64         case 2:
    65                 match = match && (key[1] == (unsigned long)node->ep->endpoint);
    66         case 1:
    67                 match = match && (key[0] == (unsigned long)node->ep->address);
    68                 break;
    69         default:
    70                 match = false;
    71         }
    72         return match;
    73 }
    74 /*----------------------------------------------------------------------------*/
    75 static void node_remove(link_t *item)
    76 {
    77         assert(item);
    78         node_t *node = hash_table_get_instance(item, node_t, link);
    79         endpoint_destroy(node->ep);
    80         free(node);
    81 }
    82 /*----------------------------------------------------------------------------*/
    83 static void node_toggle_reset_filtered(link_t *item, void *arg)
    84 {
    85         assert(item);
    86         node_t *node = hash_table_get_instance(item, node_t, link);
    87         usb_target_t *target = arg;
    88         endpoint_toggle_reset_filtered(node->ep, *target);
    89 }
    90 /*----------------------------------------------------------------------------*/
    91 static hash_table_operations_t op = {
    92         .hash = node_hash,
    93         .compare = node_compare,
    94         .remove_callback = node_remove,
    95 };
    96 /*----------------------------------------------------------------------------*/
     36/** Endpoint compare helper function.
     37 *
     38 * USB_DIRECTION_BOTH matches both IN and OUT.
     39 * @param ep Endpoint to compare, non-null.
     40 * @param address Tested address.
     41 * @param endpoint Tested endpoint number.
     42 * @param direction Tested direction.
     43 * @return True if ep can be used to communicate with given device,
     44 * false otherwise.
     45 */
     46static inline bool ep_match(const endpoint_t *ep,
     47    usb_address_t address, usb_endpoint_t endpoint, usb_direction_t direction)
     48{
     49        assert(ep);
     50        return
     51            ((direction == ep->direction)
     52                || (ep->direction == USB_DIRECTION_BOTH)
     53                || (direction == USB_DIRECTION_BOTH))
     54            && (endpoint == ep->endpoint)
     55            && (address == ep->address);
     56}
     57/*----------------------------------------------------------------------------*/
     58/** Get list that holds endpints for given address.
     59 * @param instance usb_endpoint_manager structure, non-null.
     60 * @param addr USB address, must be >= 0.
     61 * @return Pointer to the appropriate list.
     62 */
     63static list_t * get_list(usb_endpoint_manager_t *instance, usb_address_t addr)
     64{
     65        assert(instance);
     66        assert(addr >= 0);
     67        return &instance->endpoint_lists[addr % ENDPOINT_LIST_COUNT];
     68}
     69/*----------------------------------------------------------------------------*/
     70/** Internal search function, works on locked structure.
     71 * @param instance usb_endpoint_manager structure, non-null.
     72 * @param address USB address, must be valid.
     73 * @param endpoint USB endpoint number.
     74 * @param direction Communication direction.
     75 * @return Pointer to endpoint_t structure representing given communication
     76 * target, NULL if there is no such endpoint registered.
     77 */
     78static endpoint_t * find_locked(usb_endpoint_manager_t *instance,
     79    usb_address_t address, usb_endpoint_t endpoint, usb_direction_t direction)
     80{
     81        assert(instance);
     82        assert(fibril_mutex_is_locked(&instance->guard));
     83        if (address < 0)
     84                return NULL;
     85        list_foreach(*get_list(instance, address), iterator) {
     86                endpoint_t *ep = endpoint_get_instance(iterator);
     87                if (ep_match(ep, address, endpoint, direction))
     88                        return ep;
     89        }
     90        return NULL;
     91}
     92/*----------------------------------------------------------------------------*/
     93/** Calculate bandwidth that needs to be reserved for communication with EP.
     94 * Calculation follows USB 1.1 specification.
     95 * @param speed Device's speed.
     96 * @param type Type of the transfer.
     97 * @param size Number of byte to transfer.
     98 * @param max_packet_size Maximum bytes in one packet.
     99 */
    97100size_t bandwidth_count_usb11(usb_speed_t speed, usb_transfer_type_t type,
    98101    size_t size, size_t max_packet_size)
     
    106109        const unsigned packet_count =
    107110            (size + max_packet_size - 1) / max_packet_size;
    108         /* TODO: It may be that ISO and INT transfers use only one data packet
    109          * per transaction, but I did not find text in UB spec that confirms
    110          * this */
     111        /* TODO: It may be that ISO and INT transfers use only one packet per
     112         * transaction, but I did not find text in USB spec to confirm this */
    111113        /* NOTE: All data packets will be considered to be max_packet_size */
    112114        switch (speed)
     
    137139}
    138140/*----------------------------------------------------------------------------*/
     141/** Initialize to default state.
     142 * You need to provide valid bw_count function if you plan to use
     143 * add_endpoint/remove_endpoint pair.
     144 *
     145 * @param instance usb_endpoint_manager structure, non-null.
     146 * @param available_bandwidth Size of the bandwidth pool.
     147 * @param bw_count function to use to calculate endpoint bw requirements.
     148 * @return Error code.
     149 */
    139150int usb_endpoint_manager_init(usb_endpoint_manager_t *instance,
    140151    size_t available_bandwidth,
     
    145156        instance->free_bw = available_bandwidth;
    146157        instance->bw_count = bw_count;
    147         const bool ht =
    148             hash_table_create(&instance->ep_table, BUCKET_COUNT, MAX_KEYS, &op);
    149         return ht ? EOK : ENOMEM;
    150 }
    151 /*----------------------------------------------------------------------------*/
    152 void usb_endpoint_manager_destroy(usb_endpoint_manager_t *instance)
    153 {
    154         hash_table_destroy(&instance->ep_table);
    155 }
    156 /*----------------------------------------------------------------------------*/
    157 int usb_endpoint_manager_register_ep(usb_endpoint_manager_t *instance,
    158     endpoint_t *ep, size_t data_size)
    159 {
    160         assert(instance);
    161         assert(instance->bw_count);
    162         assert(ep);
    163         const size_t bw = instance->bw_count(ep->speed, ep->transfer_type,
    164             data_size, ep->max_packet_size);
    165 
    166         fibril_mutex_lock(&instance->guard);
    167 
    168         if (bw > instance->free_bw) {
    169                 fibril_mutex_unlock(&instance->guard);
    170                 return ENOSPC;
    171         }
    172 
    173         unsigned long key[MAX_KEYS] =
    174             {ep->address, ep->endpoint, ep->direction};
    175 
    176         const link_t *item =
    177             hash_table_find(&instance->ep_table, key);
    178         if (item != NULL) {
    179                 fibril_mutex_unlock(&instance->guard);
    180                 return EEXISTS;
    181         }
    182 
    183         node_t *node = malloc(sizeof(node_t));
    184         if (node == NULL) {
    185                 fibril_mutex_unlock(&instance->guard);
    186                 return ENOMEM;
    187         }
    188 
    189         node->bw = bw;
    190         node->ep = ep;
    191         link_initialize(&node->link);
    192 
    193         hash_table_insert(&instance->ep_table, key, &node->link);
    194         instance->free_bw -= bw;
    195         fibril_mutex_unlock(&instance->guard);
    196         return EOK;
    197 }
    198 /*----------------------------------------------------------------------------*/
    199 int usb_endpoint_manager_unregister_ep(usb_endpoint_manager_t *instance,
    200     usb_address_t address, usb_endpoint_t endpoint, usb_direction_t direction)
    201 {
    202         assert(instance);
    203         unsigned long key[MAX_KEYS] = {address, endpoint, direction};
    204 
    205         fibril_mutex_lock(&instance->guard);
    206         link_t *item = hash_table_find(&instance->ep_table, key);
    207         if (item == NULL) {
    208                 fibril_mutex_unlock(&instance->guard);
    209                 return EINVAL;
    210         }
    211 
    212         node_t *node = hash_table_get_instance(item, node_t, link);
    213         if (node->ep->active) {
    214                 fibril_mutex_unlock(&instance->guard);
    215                 return EBUSY;
    216         }
    217 
    218         instance->free_bw += node->bw;
    219         hash_table_remove(&instance->ep_table, key, MAX_KEYS);
    220 
    221         fibril_mutex_unlock(&instance->guard);
    222         return EOK;
    223 }
    224 /*----------------------------------------------------------------------------*/
    225 endpoint_t * usb_endpoint_manager_get_ep(usb_endpoint_manager_t *instance,
    226     usb_address_t address, usb_endpoint_t endpoint, usb_direction_t direction,
    227     size_t *bw)
    228 {
    229         assert(instance);
    230         unsigned long key[MAX_KEYS] = {address, endpoint, direction};
    231 
    232         fibril_mutex_lock(&instance->guard);
    233         const link_t *item = hash_table_find(&instance->ep_table, key);
    234         if (item == NULL) {
    235                 fibril_mutex_unlock(&instance->guard);
    236                 return NULL;
    237         }
    238         const node_t *node = hash_table_get_instance(item, node_t, link);
    239         if (bw)
    240                 *bw = node->bw;
    241 
    242         fibril_mutex_unlock(&instance->guard);
    243         return node->ep;
     158        for (unsigned i = 0; i < ENDPOINT_LIST_COUNT; ++i) {
     159                list_initialize(&instance->endpoint_lists[i]);
     160        }
     161        return EOK;
    244162}
    245163/*----------------------------------------------------------------------------*/
    246164/** Check setup packet data for signs of toggle reset.
    247165 *
    248  * @param[in] instance Device keeper structure to use.
     166 * @param[in] instance usb_endpoint_manager structure, non-null.
    249167 * @param[in] target Device to receive setup packet.
    250168 * @param[in] data Setup packet data.
    251169 *
    252  * Really ugly one.
    253  */
    254 void usb_endpoint_manager_reset_if_need(
    255     usb_endpoint_manager_t *instance, usb_target_t target, const uint8_t *data)
     170 * Really ugly one. Resets toggle bit on all endpoints that need it.
     171 */
     172void usb_endpoint_manager_reset_eps_if_need(usb_endpoint_manager_t *instance,
     173    usb_target_t target, const uint8_t data[8])
    256174{
    257175        assert(instance);
     
    267185                /* Recipient is endpoint, value is zero (ENDPOINT_STALL) */
    268186                if (((data[0] & 0xf) == 1) && ((data[2] | data[3]) == 0)) {
     187                        fibril_mutex_lock(&instance->guard);
    269188                        /* endpoint number is < 16, thus first byte is enough */
    270                         usb_target_t reset_target =
    271                             { .address = target.address, data[4] };
    272                         fibril_mutex_lock(&instance->guard);
    273                         hash_table_apply(&instance->ep_table,
    274                             node_toggle_reset_filtered, &reset_target);
     189                        list_foreach(*get_list(instance, target.address), it) {
     190                                endpoint_t *ep = endpoint_get_instance(it);
     191                                if ((ep->address == target.address)
     192                                    && (ep->endpoint = data[4])) {
     193                                        endpoint_toggle_set(ep,0);
     194                                }
     195                        }
    275196                        fibril_mutex_unlock(&instance->guard);
    276197                }
     
    279200        case 0x9: /* Set Configuration */
    280201        case 0x11: /* Set Interface */
    281                 /* Recipient must be device */
     202                /* Recipient must be device, this resets all endpoints,
     203                 * In fact there should be no endpoints but EP 0 registered
     204                 * as different interfaces use different endpoints. */
    282205                if ((data[0] & 0xf) == 0) {
    283                         usb_target_t reset_target =
    284                             { .address = target.address, 0 };
    285206                        fibril_mutex_lock(&instance->guard);
    286                         hash_table_apply(&instance->ep_table,
    287                             node_toggle_reset_filtered, &reset_target);
     207                        list_foreach(*get_list(instance, target.address), it) {
     208                                endpoint_t *ep = endpoint_get_instance(it);
     209                                if (ep->address == target.address) {
     210                                        endpoint_toggle_set(ep,0);
     211                                }
     212                        }
    288213                        fibril_mutex_unlock(&instance->guard);
    289214                }
     
    291216        }
    292217}
     218/*----------------------------------------------------------------------------*/
     219/** Register endpoint structure.
     220 * Checks for duplicates.
     221 * @param instance usb_endpoint_manager, non-null.
     222 * @param ep endpoint_t to register.
     223 * @param data_size Size of data to transfer.
     224 * @return Error code.
     225 */
     226int usb_endpoint_manager_register_ep(usb_endpoint_manager_t *instance,
     227    endpoint_t *ep, size_t data_size)
     228{
     229        assert(instance);
     230        if (ep == NULL || ep->address < 0)
     231                return EINVAL;
     232
     233        fibril_mutex_lock(&instance->guard);
     234        /* Check for available bandwidth */
     235        if (ep->bandwidth > instance->free_bw) {
     236                fibril_mutex_unlock(&instance->guard);
     237                return ENOSPC;
     238        }
     239
     240        /* Check for existence */
     241        const endpoint_t *endpoint =
     242            find_locked(instance, ep->address, ep->endpoint, ep->direction);
     243        if (endpoint != NULL) {
     244                fibril_mutex_unlock(&instance->guard);
     245                return EEXISTS;
     246        }
     247        list_append(&ep->link, get_list(instance, ep->address));
     248
     249        instance->free_bw -= ep->bandwidth;
     250        fibril_mutex_unlock(&instance->guard);
     251        return EOK;
     252}
     253/*----------------------------------------------------------------------------*/
     254/** Unregister endpoint structure.
     255 * Checks for duplicates.
     256 * @param instance usb_endpoint_manager, non-null.
     257 * @param ep endpoint_t to unregister.
     258 * @return Error code.
     259 */
     260int usb_endpoint_manager_unregister_ep(
     261    usb_endpoint_manager_t *instance, endpoint_t *ep)
     262{
     263        assert(instance);
     264        if (ep == NULL || ep->address < 0)
     265                return EINVAL;
     266
     267        fibril_mutex_lock(&instance->guard);
     268        if (!list_member(&ep->link, get_list(instance, ep->address))) {
     269                fibril_mutex_unlock(&instance->guard);
     270                return ENOENT;
     271        }
     272        list_remove(&ep->link);
     273        instance->free_bw += ep->bandwidth;
     274        fibril_mutex_unlock(&instance->guard);
     275        return EOK;
     276}
     277/*----------------------------------------------------------------------------*/
     278/** Find endpoint_t representing the given communication route.
     279 * @param instance usb_endpoint_manager, non-null.
     280 * @param address
     281 */
     282endpoint_t * usb_endpoint_manager_find_ep(usb_endpoint_manager_t *instance,
     283    usb_address_t address, usb_endpoint_t endpoint, usb_direction_t direction)
     284{
     285        assert(instance);
     286
     287        fibril_mutex_lock(&instance->guard);
     288        endpoint_t *ep = find_locked(instance, address, endpoint, direction);
     289        fibril_mutex_unlock(&instance->guard);
     290        return ep;
     291}
     292/*----------------------------------------------------------------------------*/
     293/** Create and register new endpoint_t structure.
     294 * @param instance usb_endpoint_manager structure, non-null.
     295 * @param address USB address.
     296 * @param endpoint USB endpoint number.
     297 * @param direction Communication direction.
     298 * @param type USB transfer type.
     299 * @param speed USB Communication speed.
     300 * @param max_packet_size Maximum size of data packets.
     301 * @param data_size Expected communication size.
     302 * @param callback function to call just after registering.
     303 * @param arg Argument to pass to the callback function.
     304 * @return Error code.
     305 */
     306int usb_endpoint_manager_add_ep(usb_endpoint_manager_t *instance,
     307    usb_address_t address, usb_endpoint_t endpoint, usb_direction_t direction,
     308    usb_transfer_type_t type, usb_speed_t speed, size_t max_packet_size,
     309    size_t data_size, int (*callback)(endpoint_t *, void *), void *arg)
     310{
     311        assert(instance);
     312        if (instance->bw_count == NULL)
     313                return ENOTSUP;
     314        if (address < 0)
     315                return EINVAL;
     316
     317        const size_t bw =
     318            instance->bw_count(speed, type, data_size, max_packet_size);
     319
     320        fibril_mutex_lock(&instance->guard);
     321        /* Check for available bandwidth */
     322        if (bw > instance->free_bw) {
     323                fibril_mutex_unlock(&instance->guard);
     324                return ENOSPC;
     325        }
     326
     327        /* Check for existence */
     328        endpoint_t *ep = find_locked(instance, address, endpoint, direction);
     329        if (ep != NULL) {
     330                fibril_mutex_unlock(&instance->guard);
     331                return EEXISTS;
     332        }
     333
     334        ep = endpoint_create(
     335            address, endpoint, direction, type, speed, max_packet_size, bw);
     336        if (!ep) {
     337                fibril_mutex_unlock(&instance->guard);
     338                return ENOMEM;
     339        }
     340
     341        if (callback) {
     342                const int ret = callback(ep, arg);
     343                if (ret != EOK) {
     344                        fibril_mutex_unlock(&instance->guard);
     345                        endpoint_destroy(ep);
     346                        return ret;
     347                }
     348        }
     349        list_append(&ep->link, get_list(instance, ep->address));
     350
     351        instance->free_bw -= ep->bandwidth;
     352        fibril_mutex_unlock(&instance->guard);
     353        return EOK;
     354}
     355/*----------------------------------------------------------------------------*/
     356/** Unregister and destroy endpoint_t structure representing given route.
     357 * @param instance usb_endpoint_manager structure, non-null.
     358 * @param address USB address.
     359 * @param endpoint USB endpoint number.
     360 * @param direction Communication direction.
     361 * @param callback Function to call after unregister, before destruction.
     362 * @arg Argument to pass to the callback function.
     363 * @return Error code.
     364 */
     365int usb_endpoint_manager_remove_ep(usb_endpoint_manager_t *instance,
     366    usb_address_t address, usb_endpoint_t endpoint, usb_direction_t direction,
     367    void (*callback)(endpoint_t *, void *), void *arg)
     368{
     369        assert(instance);
     370        fibril_mutex_lock(&instance->guard);
     371        endpoint_t *ep = find_locked(instance, address, endpoint, direction);
     372        if (ep != NULL) {
     373                list_remove(&ep->link);
     374                instance->free_bw += ep->bandwidth;
     375        }
     376        fibril_mutex_unlock(&instance->guard);
     377        if (ep == NULL)
     378                return ENOENT;
     379
     380        if (callback) {
     381                callback(ep, arg);
     382        }
     383        endpoint_destroy(ep);
     384        return EOK;
     385}
  • uspace/lib/usbhost/src/usb_transfer_batch.c

    re8ab32f rc83a55c  
    3737#include <usb/usb.h>
    3838#include <usb/debug.h>
     39
    3940#include <usb/host/usb_transfer_batch.h>
    4041#include <usb/host/hcd.h>
    4142
    42 usb_transfer_batch_t * usb_transfer_batch_get(
     43/** Allocate and initialize usb_transfer_batch structure.
     44 * @param ep endpoint used by the transfer batch.
     45 * @param buffer data to send/recieve.
     46 * @param buffer_size Size of data buffer.
     47 * @param setup_buffer Data to send in SETUP stage of control transfer.
     48 * @param func_in callback on IN transfer completion.
     49 * @param func_out callback on OUT transfer completion.
     50 * @param arg Argument to pass to the callback function.
     51 * @param private_data driver specific per batch data.
     52 * @param private_data_dtor Function to properly destroy private_data.
     53 * @return Pointer to valid usb_transfer_batch_t structure, NULL on failure.
     54 */
     55usb_transfer_batch_t * usb_transfer_batch_create(
    4356    endpoint_t *ep,
    4457    char *buffer,
     
    5366    )
    5467{
     68        if (func_in == NULL && func_out == NULL)
     69                return NULL;
     70        if (func_in != NULL && func_out != NULL)
     71                return NULL;
     72
    5573        usb_transfer_batch_t *instance = malloc(sizeof(usb_transfer_batch_t));
    5674        if (instance) {
     
    7896}
    7997/*----------------------------------------------------------------------------*/
    80 /** Mark batch as finished and run callback.
    81  *
    82  * @param[in] instance Batch structure to use.
    83  * @param[in] data Data to copy to the output buffer.
    84  * @param[in] size Size of @p data.
    85  */
    86 void usb_transfer_batch_finish(
    87     usb_transfer_batch_t *instance, const void *data, size_t size)
    88 {
    89         assert(instance);
    90         assert(instance->ep);
    91         /* we care about the data and there are some to copy */
    92         if (instance->ep->direction != USB_DIRECTION_OUT
    93             && data) {
    94                 const size_t min_size =
    95                     size < instance->buffer_size ? size : instance->buffer_size;
    96                 memcpy(instance->buffer, data, min_size);
    97         }
    98         if (instance->callback_out)
    99                 usb_transfer_batch_call_out(instance);
    100         if (instance->callback_in)
    101                 usb_transfer_batch_call_in(instance);
    102 
    103 }
    104 /*----------------------------------------------------------------------------*/
    105 /** Prepare data, get error status and call callback in.
    106  *
    107  * @param[in] instance Batch structure to use.
    108  * Copies data from transport buffer, and calls callback with appropriate
    109  * parameters.
    110  */
    111 void usb_transfer_batch_call_in(usb_transfer_batch_t *instance)
    112 {
    113         assert(instance);
    114         assert(instance->callback_in);
    115 
    116         usb_log_debug2("Batch %p " USB_TRANSFER_BATCH_FMT " completed (%zuB): %s.\n",
    117             instance, USB_TRANSFER_BATCH_ARGS(*instance),
    118             instance->transfered_size, str_error(instance->error));
    119 
    120         instance->callback_in(instance->fun, instance->error,
    121             instance->transfered_size, instance->arg);
    122 }
    123 /*----------------------------------------------------------------------------*/
    124 /** Get error status and call callback out.
    125  *
    126  * @param[in] instance Batch structure to use.
    127  */
    128 void usb_transfer_batch_call_out(usb_transfer_batch_t *instance)
    129 {
    130         assert(instance);
    131         assert(instance->callback_out);
    132 
    133         usb_log_debug2("Batch %p " USB_TRANSFER_BATCH_FMT " completed: %s.\n",
    134             instance, USB_TRANSFER_BATCH_ARGS(*instance),
    135             str_error(instance->error));
    136 
    137         if (instance->ep->transfer_type == USB_TRANSFER_CONTROL
    138             && instance->error == EOK) {
    139                 const usb_target_t target =
    140                     {{ instance->ep->address, instance->ep->endpoint }};
    141                 reset_ep_if_need(
    142                     fun_to_hcd(instance->fun), target, instance->setup_buffer);
    143         }
    144 
    145         instance->callback_out(instance->fun,
    146             instance->error, instance->arg);
    147 }
    148 /*----------------------------------------------------------------------------*/
    14998/** Correctly dispose all used data structures.
    15099 *
    151100 * @param[in] instance Batch structure to use.
    152101 */
    153 void usb_transfer_batch_dispose(usb_transfer_batch_t *instance)
     102void usb_transfer_batch_destroy(const usb_transfer_batch_t *instance)
    154103{
    155104        if (!instance)
     
    166115        free(instance);
    167116}
     117/*----------------------------------------------------------------------------*/
     118/** Prepare data and call the right callback.
     119 *
     120 * @param[in] instance Batch structure to use.
     121 * @param[in] data Data to copy to the output buffer.
     122 * @param[in] size Size of @p data.
     123 */
     124void usb_transfer_batch_finish(
     125    const usb_transfer_batch_t *instance, const void *data, size_t size)
     126{
     127        assert(instance);
     128        usb_log_debug2("Batch %p " USB_TRANSFER_BATCH_FMT " finishing.\n",
     129            instance, USB_TRANSFER_BATCH_ARGS(*instance));
     130
     131        /* NOTE: Only one of these pointers should be set. */
     132        if (instance->callback_out) {
     133                /* Check for commands that reset toggle bit */
     134                if (instance->ep->transfer_type == USB_TRANSFER_CONTROL
     135                    && instance->error == EOK) {
     136                        const usb_target_t target =
     137                            {{ instance->ep->address, instance->ep->endpoint }};
     138                        reset_ep_if_need(fun_to_hcd(instance->fun), target,
     139                            instance->setup_buffer);
     140                }
     141                instance->callback_out(instance->fun,
     142                    instance->error, instance->arg);
     143        }
     144
     145        if (instance->callback_in) {
     146                /* We care about the data and there are some to copy */
     147                if (data) {
     148                        const size_t min_size = size < instance->buffer_size
     149                            ? size : instance->buffer_size;
     150                        memcpy(instance->buffer, data, min_size);
     151                }
     152                instance->callback_in(instance->fun, instance->error,
     153                    instance->transfered_size, instance->arg);
     154        }
     155}
    168156/**
    169157 * @}
Note: See TracChangeset for help on using the changeset viewer.