Changeset 45bf63c in mainline


Ignore:
Timestamp:
2011-10-30T15:35:36Z (12 years ago)
Author:
Jan Vesely <jano.vesely@…>
Branches:
lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
Children:
20a3465, 3ce78580
Parents:
1737bfb (diff), e978ada (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 from USB branch.

Cleanup libusbhost interfaces.
Fix few possible memory corruption/crashes and memory leaks.
Add device_remove hooks for usbflbk, usbhid.

Location:
uspace
Files:
36 edited

Legend:

Unmodified
Added
Removed
  • uspace/drv/bus/usb/ohci/endpoint_list.c

    r1737bfb r45bf63c  
    7373 * Does not check whether this replaces an existing list.
    7474 */
    75 void endpoint_list_set_next(endpoint_list_t *instance, endpoint_list_t *next)
     75void endpoint_list_set_next(
     76    const endpoint_list_t *instance, const endpoint_list_t *next)
    7677{
    7778        assert(instance);
  • uspace/drv/bus/usb/ohci/endpoint_list.h

    r1737bfb r45bf63c  
    6868
    6969int endpoint_list_init(endpoint_list_t *instance, const char *name);
    70 void endpoint_list_set_next(endpoint_list_t *instance, endpoint_list_t *next);
     70void endpoint_list_set_next(
     71    const endpoint_list_t *instance, const endpoint_list_t *next);
    7172void endpoint_list_add_ep(endpoint_list_t *instance, ohci_endpoint_t *ep);
    7273void endpoint_list_remove_ep(endpoint_list_t *instance, ohci_endpoint_t *ep);
  • uspace/drv/bus/usb/ohci/hc.c

    r1737bfb r45bf63c  
    142142if (ret != EOK) { \
    143143        usb_log_error(message); \
    144         usb_endpoint_manager_unregister_ep( \
    145             &instance->generic.ep_manager, hub_address, 0, USB_DIRECTION_BOTH);\
     144        usb_endpoint_manager_remove_ep( \
     145            &instance->generic.ep_manager, hub_address, 0, USB_DIRECTION_BOTH, \
     146            NULL, NULL);\
    146147        usb_device_manager_release( \
    147148            &instance->generic.dev_manager, hub_address); \
     
    150151        int ret = usb_endpoint_manager_add_ep(
    151152            &instance->generic.ep_manager, hub_address, 0, USB_DIRECTION_BOTH,
    152             USB_TRANSFER_CONTROL, USB_SPEED_FULL, 64, 0);
     153            USB_TRANSFER_CONTROL, USB_SPEED_FULL, 64, 0, NULL, NULL);
    153154        CHECK_RET_UNREG_RETURN(ret,
    154155            "Failed to register root hub control endpoint: %s.\n",
     
    192193        list_initialize(&instance->pending_batches);
    193194
    194         ret = hcd_init(&instance->generic, BANDWIDTH_AVAILABLE_USB11,
     195        hcd_init(&instance->generic, BANDWIDTH_AVAILABLE_USB11,
    195196            bandwidth_count_usb11);
    196         CHECK_RET_RETURN(ret, "Failed to initialize generic driver: %s.\n",
    197             str_error(ret));
    198197        instance->generic.private_data = instance;
    199198        instance->generic.schedule = hc_schedule;
    200199        instance->generic.ep_add_hook = ohci_endpoint_init;
     200        instance->generic.ep_remove_hook = ohci_endpoint_fini;
    201201
    202202        ret = hc_init_memory(instance);
     
    221221}
    222222/*----------------------------------------------------------------------------*/
    223 void hc_enqueue_endpoint(hc_t *instance, endpoint_t *ep)
    224 {
     223void hc_enqueue_endpoint(hc_t *instance, const endpoint_t *ep)
     224{
     225        assert(instance);
     226        assert(ep);
     227
    225228        endpoint_list_t *list = &instance->lists[ep->transfer_type];
    226229        ohci_endpoint_t *ohci_ep = ohci_endpoint_get(ep);
     230        assert(list);
     231        assert(ohci_ep);
     232
    227233        /* Enqueue ep */
    228234        switch (ep->transfer_type) {
     
    247253}
    248254/*----------------------------------------------------------------------------*/
    249 void hc_dequeue_endpoint(hc_t *instance, endpoint_t *ep)
    250 {
     255void hc_dequeue_endpoint(hc_t *instance, const endpoint_t *ep)
     256{
     257        assert(instance);
     258        assert(ep);
     259
    251260        /* Dequeue ep */
    252261        endpoint_list_t *list = &instance->lists[ep->transfer_type];
    253262        ohci_endpoint_t *ohci_ep = ohci_endpoint_get(ep);
     263
     264        assert(list);
     265        assert(ohci_ep);
    254266        switch (ep->transfer_type) {
    255267        case USB_TRANSFER_CONTROL:
  • uspace/drv/bus/usb/ohci/hc.h

    r1737bfb r45bf63c  
    8686static inline void hc_fini(hc_t *instance) { /* TODO: implement*/ };
    8787
    88 void hc_enqueue_endpoint(hc_t *instance, endpoint_t *ep);
    89 void hc_dequeue_endpoint(hc_t *instance, endpoint_t *ep);
     88void hc_enqueue_endpoint(hc_t *instance, const endpoint_t *ep);
     89void hc_dequeue_endpoint(hc_t *instance, const endpoint_t *ep);
    9090
    9191void hc_interrupt(hc_t *instance, uint32_t status);
  • uspace/drv/bus/usb/ohci/ohci.c

    r1737bfb r45bf63c  
    8989            &dev_to_ohci(fun->dev)->hc.generic.dev_manager;
    9090
    91         const usb_address_t addr = usb_device_manager_find(manager, handle);
     91        const usb_address_t addr =
     92            usb_device_manager_find_address(manager, handle);
    9293        if (addr < 0) {
    9394                return addr;
  • uspace/drv/bus/usb/ohci/ohci_batch.c

    r1737bfb r45bf63c  
    5959                free(ohci_batch->tds);
    6060        }
    61         usb_transfer_batch_dispose(ohci_batch->usb_batch);
     61        usb_transfer_batch_destroy(ohci_batch->usb_batch);
    6262        free32(ohci_batch->device_buffer);
    6363        free(ohci_batch);
  • uspace/drv/bus/usb/ohci/ohci_endpoint.c

    r1737bfb r45bf63c  
    6262}
    6363/*----------------------------------------------------------------------------*/
    64 /** Disposes hcd endpoint structure
    65  *
    66  * @param[in] hcd_ep endpoint structure
    67  */
    68 static void ohci_endpoint_fini(endpoint_t *ep)
    69 {
    70         ohci_endpoint_t *instance = ep->hc_data.data;
    71         hc_dequeue_endpoint(instance->hcd->private_data, ep);
    72         if (instance) {
    73                 free32(instance->ed);
    74                 free32(instance->td);
    75                 free(instance);
    76         }
    77 }
    78 /*----------------------------------------------------------------------------*/
    7964/** Creates new hcd endpoint representation.
    8065 *
    8166 * @param[in] ep USBD endpoint structure
    82  * @return pointer to a new hcd endpoint structure, NULL on failure.
     67 * @return Error code.
    8368 */
    8469int ohci_endpoint_init(hcd_t *hcd, endpoint_t *ep)
     
    10489        ed_init(ohci_ep->ed, ep, ohci_ep->td);
    10590        endpoint_set_hc_data(
    106             ep, ohci_ep, ohci_endpoint_fini, ohci_ep_toggle_get, ohci_ep_toggle_set);
    107         ohci_ep->hcd = hcd;
     91            ep, ohci_ep, ohci_ep_toggle_get, ohci_ep_toggle_set);
    10892        hc_enqueue_endpoint(hcd->private_data, ep);
    10993        return EOK;
     94}
     95/*----------------------------------------------------------------------------*/
     96/** Disposes hcd endpoint structure
     97 *
     98 * @param[in] hcd driver using this instance.
     99 * @param[in] ep endpoint structure.
     100 */
     101void ohci_endpoint_fini(hcd_t *hcd, endpoint_t *ep)
     102{
     103        assert(hcd);
     104        assert(ep);
     105        ohci_endpoint_t *instance = ohci_endpoint_get(ep);
     106        hc_dequeue_endpoint(hcd->private_data, ep);
     107        if (instance) {
     108                free32(instance->ed);
     109                free32(instance->td);
     110                free(instance);
     111        }
     112        endpoint_clear_hc_data(ep);
    110113}
    111114/**
  • uspace/drv/bus/usb/ohci/ohci_endpoint.h

    r1737bfb r45bf63c  
    5151        /** Linked list used by driver software */
    5252        link_t link;
    53         /** Device using this ep */
    54         hcd_t *hcd;
    5553} ohci_endpoint_t;
    5654
    5755int ohci_endpoint_init(hcd_t *hcd, endpoint_t *ep);
     56void ohci_endpoint_fini(hcd_t *hcd, endpoint_t *ep);
    5857
    5958/** Get and convert assigned ohci_endpoint_t structure
     
    6160 * @return Pointer to assigned hcd endpoint structure
    6261 */
    63 static inline ohci_endpoint_t * ohci_endpoint_get(endpoint_t *ep)
     62static inline ohci_endpoint_t * ohci_endpoint_get(const endpoint_t *ep)
    6463{
    6564        assert(ep);
  • uspace/drv/bus/usb/ohci/ohci_regs.h

    r1737bfb r45bf63c  
    2626 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
    2727 */
    28 /** @addtogroup drvusbohcihc
     28/** @addtogroup drvusbohci
    2929 * @{
    3030 */
  • uspace/drv/bus/usb/ohci/root_hub.c

    r1737bfb r45bf63c  
    235235                usb_transfer_batch_finish_error(request, NULL, 0, EINVAL);
    236236        }
    237         usb_transfer_batch_dispose(request);
     237        usb_transfer_batch_destroy(request);
    238238}
    239239/*----------------------------------------------------------------------------*/
     
    254254                interrupt_request(instance->unfinished_interrupt_transfer,
    255255                    mask, instance->interrupt_mask_size);
    256                 usb_transfer_batch_dispose(
     256                usb_transfer_batch_destroy(
    257257                    instance->unfinished_interrupt_transfer);
    258258                instance->unfinished_interrupt_transfer = NULL;
  • uspace/drv/bus/usb/uhci/hc.c

    r1737bfb r45bf63c  
    192192            "Device registers at %p (%zuB) accessible.\n", io, reg_size);
    193193
    194         ret = hcd_init(&instance->generic, BANDWIDTH_AVAILABLE_USB11,
     194        ret = hc_init_mem_structures(instance);
     195        CHECK_RET_RETURN(ret,
     196            "Failed to initialize UHCI memory structures: %s.\n",
     197            str_error(ret));
     198
     199#undef CHECK_RET_RETURN
     200
     201        hcd_init(&instance->generic, BANDWIDTH_AVAILABLE_USB11,
    195202            bandwidth_count_usb11);
    196         CHECK_RET_RETURN(ret, "Failed to initialize HCD generic driver: %s.\n",
    197             str_error(ret));
    198203
    199204        instance->generic.private_data = instance;
    200205        instance->generic.schedule = hc_schedule;
    201206        instance->generic.ep_add_hook = NULL;
    202 
    203 #undef CHECK_RET_DEST_FUN_RETURN
    204 
    205         ret = hc_init_mem_structures(instance);
    206         if (ret != EOK) {
    207                 usb_log_error(
    208                     "Failed to initialize UHCI memory structures: %s.\n",
    209                     str_error(ret));
    210                 hcd_destroy(&instance->generic);
    211                 return ret;
    212         }
    213207
    214208        hc_init_hw(instance);
  • uspace/drv/bus/usb/uhci/uhci.c

    r1737bfb r45bf63c  
    101101        usb_device_manager_t *manager =
    102102            &dev_to_uhci(fun->dev)->hc.generic.dev_manager;
    103         const usb_address_t addr = usb_device_manager_find(manager, handle);
     103        const usb_address_t addr =
     104            usb_device_manager_find_address(manager, handle);
    104105
    105106        if (addr < 0) {
  • uspace/drv/bus/usb/uhci/uhci_batch.c

    r1737bfb r45bf63c  
    4848{
    4949        if (uhci_batch) {
    50                 usb_transfer_batch_dispose(uhci_batch->usb_batch);
     50                usb_transfer_batch_destroy(uhci_batch->usb_batch);
    5151                free32(uhci_batch->device_buffer);
    5252                free(uhci_batch);
  • uspace/drv/bus/usb/usbflbk/main.c

    r1737bfb r45bf63c  
    7474}
    7575
     76/** Callback when new device is about to be removed.
     77 *
     78 * @param dev Representation of a generic DDF device.
     79 * @return Error code.
     80 */
     81static int usbfallback_device_remove(usb_device_t *dev)
     82{
     83        return EOK;
     84}
     85
    7686/** Callback when new device is removed and recognized as gone by DDF.
    7787 *
     
    93103        return EOK;
    94104}
     105
    95106/** USB fallback driver ops. */
    96 static usb_driver_ops_t usbfallback_driver_ops = {
     107static const usb_driver_ops_t usbfallback_driver_ops = {
    97108        .device_add = usbfallback_device_add,
     109        .device_rem = usbfallback_device_remove,
    98110        .device_gone = usbfallback_device_gone,
    99111};
    100112
    101113/** USB fallback driver. */
    102 static usb_driver_t usbfallback_driver = {
     114static const usb_driver_t usbfallback_driver = {
    103115        .name = NAME,
    104116        .ops = &usbfallback_driver_ops,
  • uspace/drv/bus/usb/usbhid/main.c

    r1737bfb r45bf63c  
    4646#include "usbhid.h"
    4747
    48 /*----------------------------------------------------------------------------*/
    49 
    5048#define NAME "usbhid"
    5149
     
    6765 *
    6866 * @param dev Device to add.
    69  *
    70  * @retval EOK if successful.
    71  * @retval ENOMEM if there
    72  * @return Other error code inherited from one of functions usb_kbd_init(),
    73  *         ddf_fun_bind() and ddf_fun_add_to_class().
     67 * @return Error code.
    7468 */
    7569static int usb_hid_try_add_device(usb_device_t *dev)
     
    138132        return EOK;
    139133}
    140 
    141134/*----------------------------------------------------------------------------*/
    142135/**
     
    146139 *
    147140 * @param dev Structure representing the new device.
    148  *
    149  * @retval EOK if successful.
    150  * @retval EREFUSED if the device is not supported.
     141 * @return Error code.
    151142 */
    152143static int usb_hid_device_add(usb_device_t *dev)
     
    179170        return EOK;
    180171}
    181 
    182 /*----------------------------------------------------------------------------*/
    183 
     172/*----------------------------------------------------------------------------*/
     173/**
     174 * Callback for a device about to be removed from the driver.
     175 *
     176 * @param dev Structure representing the device.
     177 * @return Error code.
     178 */
     179static int usb_hid_device_rem(usb_device_t *dev)
     180{
     181        return EOK;
     182}
     183/*----------------------------------------------------------------------------*/
    184184/**
    185185 * Callback for removing a device from the driver.
    186186 *
    187187 * @param dev Structure representing the device.
    188  *
    189  * @retval EOK if successful.
    190  * @retval EREFUSED if the device is not supported.
     188 * @return Error code.
    191189 */
    192190static int usb_hid_device_gone(usb_device_t *dev)
     
    198196                if (!tries--) {
    199197                        usb_log_error("Can't remove hub, still running.\n");
    200                         return EINPROGRESS;
     198                        return EBUSY;
    201199                }
    202200        }
     
    207205        return EOK;
    208206}
    209 
     207/*----------------------------------------------------------------------------*/
    210208/** USB generic driver callbacks */
    211 static usb_driver_ops_t usb_hid_driver_ops = {
     209static const usb_driver_ops_t usb_hid_driver_ops = {
    212210        .device_add = usb_hid_device_add,
     211        .device_rem = usb_hid_device_rem,
    213212        .device_gone = usb_hid_device_gone,
    214213};
    215 
    216 
     214/*----------------------------------------------------------------------------*/
    217215/** The driver itself. */
    218 static usb_driver_t usb_hid_driver = {
     216static const usb_driver_t usb_hid_driver = {
    219217        .name = NAME,
    220218        .ops = &usb_hid_driver_ops,
    221219        .endpoints = usb_hid_endpoints
    222220};
    223 
    224 /*----------------------------------------------------------------------------*/
    225 
     221/*----------------------------------------------------------------------------*/
    226222int main(int argc, char *argv[])
    227223{
     
    232228        return usb_driver_main(&usb_hid_driver);
    233229}
    234 
    235230/**
    236231 * @}
  • uspace/drv/bus/usb/usbhub/main.c

    r1737bfb r45bf63c  
    4747 * For more information see section 11.15.1 of USB 1.1 specification.
    4848 */
    49 static usb_endpoint_description_t hub_status_change_endpoint_description = {
     49static const usb_endpoint_description_t hub_status_change_endpoint_description =
     50{
    5051        .transfer_type = USB_TRANSFER_INTERRUPT,
    5152        .direction = USB_DIRECTION_IN,
     
    5657};
    5758
    58 /**
    59  * USB hub driver operations
    60  *
    61  * The most important one is device_add, which is set to usb_hub_device_add.
    62  */
    63 static usb_driver_ops_t usb_hub_driver_ops = {
     59/** USB hub driver operations. */
     60static const usb_driver_ops_t usb_hub_driver_ops = {
    6461        .device_add = usb_hub_device_add,
     62//      .device_rem = usb_hub_device_remove,
    6563        .device_gone = usb_hub_device_gone,
    6664};
     
    7270};
    7371/** Static usb hub driver information. */
    74 static usb_driver_t usb_hub_driver = {
     72static const usb_driver_t usb_hub_driver = {
    7573        .name = NAME,
    7674        .ops = &usb_hub_driver_ops,
    7775        .endpoints = usb_hub_endpoints
    7876};
    79 
    8077
    8178int main(int argc, char *argv[])
  • uspace/drv/bus/usb/usbhub/port.h

    r1737bfb r45bf63c  
    4444/** Information about single port on a hub. */
    4545typedef struct {
     46        /* Port number as reporteed in descriptors. */
    4647        size_t port_number;
     48        /** Device communication pipe. */
    4749        usb_pipe_t *control_pipe;
    4850        /** Mutex needed not only by CV for checking port reset. */
  • uspace/drv/bus/usb/usbhub/usbhub.c

    r1737bfb r45bf63c  
    6868
    6969static int usb_set_first_configuration(usb_device_t *usb_device);
    70 static usb_hub_dev_t * usb_hub_dev_create(usb_device_t *usb_dev);
    7170static int usb_hub_process_hub_specific_info(usb_hub_dev_t *hub_dev);
    7271static void usb_hub_over_current(const usb_hub_dev_t *hub_dev,
     
    7574static void usb_hub_polling_terminated_callback(usb_device_t *device,
    7675    bool was_error, void *data);
    77 /**
    78  * Initialize hub device driver fibril
     76
     77/**
     78 * Initialize hub device driver structure.
    7979 *
    8080 * Creates hub representation and fibril that periodically checks hub's status.
    8181 * Hub representation is passed to the fibril.
     82 * @param usb_dev generic usb device information
     83 * @return error code
     84 */
     85int usb_hub_device_add(usb_device_t *usb_dev)
     86{
     87        assert(usb_dev);
     88        /* Create driver soft-state structure */
     89        usb_hub_dev_t *hub_dev =
     90            usb_device_data_alloc(usb_dev, sizeof(usb_hub_dev_t));
     91        if (hub_dev == NULL) {
     92                usb_log_error("Failed to create hub driver structure.\n");
     93                return ENOMEM;
     94        }
     95        hub_dev->usb_device = usb_dev;
     96        hub_dev->pending_ops_count = 0;
     97        hub_dev->running = false;
     98        fibril_mutex_initialize(&hub_dev->pending_ops_mutex);
     99        fibril_condvar_initialize(&hub_dev->pending_ops_cv);
     100
     101        /* Create hc connection */
     102        usb_log_debug("Initializing USB wire abstraction.\n");
     103        int opResult = usb_hc_connection_initialize_from_device(
     104            &hub_dev->connection, hub_dev->usb_device->ddf_dev);
     105        if (opResult != EOK) {
     106                usb_log_error("Could not initialize connection to device: %s\n",
     107                    str_error(opResult));
     108                return opResult;
     109        }
     110
     111        /* Set hub's first configuration. (There should be only one) */
     112        opResult = usb_set_first_configuration(usb_dev);
     113        if (opResult != EOK) {
     114                usb_log_error("Could not set hub configuration: %s\n",
     115                    str_error(opResult));
     116                return opResult;
     117        }
     118
     119        /* Get port count and create attached_devices. */
     120        opResult = usb_hub_process_hub_specific_info(hub_dev);
     121        if (opResult != EOK) {
     122                usb_log_error("Could process hub specific info, %s\n",
     123                    str_error(opResult));
     124                return opResult;
     125        }
     126
     127        /* Create hub control function. */
     128        usb_log_debug("Creating DDF function '" HUB_FNC_NAME "'.\n");
     129        hub_dev->hub_fun = ddf_fun_create(hub_dev->usb_device->ddf_dev,
     130            fun_exposed, HUB_FNC_NAME);
     131        if (hub_dev->hub_fun == NULL) {
     132                usb_log_error("Failed to create hub function.\n");
     133                return ENOMEM;
     134        }
     135
     136        /* Bind hub control function. */
     137        opResult = ddf_fun_bind(hub_dev->hub_fun);
     138        if (opResult != EOK) {
     139                usb_log_error("Failed to bind hub function: %s.\n",
     140                   str_error(opResult));
     141                ddf_fun_destroy(hub_dev->hub_fun);
     142                return opResult;
     143        }
     144
     145        /* Start hub operation. */
     146        opResult = usb_device_auto_poll(hub_dev->usb_device, 0,
     147            hub_port_changes_callback, ((hub_dev->port_count + 1 + 8) / 8),
     148            usb_hub_polling_terminated_callback, hub_dev);
     149        if (opResult != EOK) {
     150                /* Function is already bound */
     151                ddf_fun_unbind(hub_dev->hub_fun);
     152                ddf_fun_destroy(hub_dev->hub_fun);
     153                usb_log_error("Failed to create polling fibril: %s.\n",
     154                    str_error(opResult));
     155                return opResult;
     156        }
     157        hub_dev->running = true;
     158        usb_log_info("Controlling hub '%s' (%zu ports).\n",
     159            hub_dev->usb_device->ddf_dev->name, hub_dev->port_count);
     160
     161        return EOK;
     162}
     163/*----------------------------------------------------------------------------*/
     164/**
     165 * Turn off power to all ports.
     166 *
     167 * @param usb_dev generic usb device information
     168 * @return error code
     169 */
     170int usb_hub_device_remove(usb_device_t *usb_dev)
     171{
     172        assert(usb_dev);
     173        usb_hub_dev_t *hub_dev = usb_dev->driver_data;
     174        assert(hub_dev);
     175        //TODO: Cascade the call here.
     176        //TODO: Enable after cascading is implemented.
     177        return ENOTSUP;
     178        if (!hub_dev->power_switched) {
     179                /* That is all we can do. */
     180                return EOK;
     181        }
     182        int ret = EOK;
     183        usb_log_info("Hub is about to be removed, powering down all ports.\n");
     184        for (size_t port = 0; port < hub_dev->port_count; ++port) {
     185                usb_log_debug("Powering down port %zu.\n", port);
     186                int pret = usb_hub_port_clear_feature(
     187                    &hub_dev->ports[port], USB_HUB_FEATURE_PORT_POWER);
     188                if (pret != EOK) {
     189                        usb_log_error("Cannot power down port %zu: %s.\n",
     190                            hub_dev->ports[port].port_number, str_error(pret));
     191                        ret = pret;
     192                } else {
     193                        if (!hub_dev->per_port_power) {
     194                                usb_log_debug("Ganged power switching mode, "
     195                                   "one port is enough.\n");
     196                                break;
     197                        }
     198                }
     199        }
     200        return ret;
     201}
     202/*----------------------------------------------------------------------------*/
     203/**
     204 * Remove all attached devices
    82205 * @param usb_dev generic usb device information
    83206 * @return error code
     
    121244}
    122245/*----------------------------------------------------------------------------*/
    123 /**
    124  * Initialize hub device driver fibril
    125  *
    126  * Creates hub representation and fibril that periodically checks hub's status.
    127  * Hub representation is passed to the fibril.
    128  * @param usb_dev generic usb device information
    129  * @return error code
    130  */
    131 int usb_hub_device_add(usb_device_t *usb_dev)
    132 {
    133         assert(usb_dev);
    134         /* Create driver soft-state structure */
    135         usb_hub_dev_t *hub_dev = usb_hub_dev_create(usb_dev);
    136         if (hub_dev == NULL) {
    137                 usb_log_error("Failed to create hun driver structure.\n");
    138                 return ENOMEM;
    139         }
    140 
    141         /* Create hc connection */
    142         usb_log_debug("Initializing USB wire abstraction.\n");
    143         int opResult = usb_hc_connection_initialize_from_device(
    144             &hub_dev->connection, hub_dev->usb_device->ddf_dev);
    145         if (opResult != EOK) {
    146                 usb_log_error("Could not initialize connection to device: %s\n",
    147                     str_error(opResult));
    148                 free(hub_dev);
    149                 return opResult;
    150         }
    151 
    152         /* Set hub's first configuration. (There should be only one) */
    153         opResult = usb_set_first_configuration(usb_dev);
    154         if (opResult != EOK) {
    155                 usb_log_error("Could not set hub configuration: %s\n",
    156                     str_error(opResult));
    157                 free(hub_dev);
    158                 return opResult;
    159         }
    160 
    161         /* Get port count and create attached_devices. */
    162         opResult = usb_hub_process_hub_specific_info(hub_dev);
    163         if (opResult != EOK) {
    164                 usb_log_error("Could process hub specific info, %s\n",
    165                     str_error(opResult));
    166                 free(hub_dev);
    167                 return opResult;
    168         }
    169 
    170         usb_log_debug("Creating DDF function '" HUB_FNC_NAME "'.\n");
    171         hub_dev->hub_fun = ddf_fun_create(hub_dev->usb_device->ddf_dev,
    172             fun_exposed, HUB_FNC_NAME);
    173         if (hub_dev->hub_fun == NULL) {
    174                 usb_log_error("Failed to create hub function.\n");
    175                 free(hub_dev);
    176                 return ENOMEM;
    177         }
    178 
    179         opResult = ddf_fun_bind(hub_dev->hub_fun);
    180         if (opResult != EOK) {
    181                 usb_log_error("Failed to bind hub function: %s.\n",
    182                    str_error(opResult));
    183                 free(hub_dev);
    184                 ddf_fun_destroy(hub_dev->hub_fun);
    185                 return opResult;
    186         }
    187 
    188         opResult = usb_device_auto_poll(hub_dev->usb_device, 0,
    189             hub_port_changes_callback, ((hub_dev->port_count + 1 + 8) / 8),
    190             usb_hub_polling_terminated_callback, hub_dev);
    191         if (opResult != EOK) {
    192                 /* Function is already bound */
    193                 ddf_fun_unbind(hub_dev->hub_fun);
    194                 ddf_fun_destroy(hub_dev->hub_fun);
    195                 free(hub_dev);
    196                 usb_log_error("Failed to create polling fibril: %s.\n",
    197                     str_error(opResult));
    198                 return opResult;
    199         }
    200         hub_dev->running = true;
    201         usb_log_info("Controlling hub '%s' (%zu ports).\n",
    202             hub_dev->usb_device->ddf_dev->name, hub_dev->port_count);
    203 
    204         return EOK;
    205 }
    206 /*----------------------------------------------------------------------------*/
    207246/** Callback for polling hub for changes.
    208247 *
     
    243282/*----------------------------------------------------------------------------*/
    244283/**
    245  * create usb_hub_dev_t structure
    246  *
    247  * Does only basic copying of known information into new structure.
    248  * @param usb_dev usb device structure
    249  * @return basic usb_hub_dev_t structure
    250  */
    251 static usb_hub_dev_t * usb_hub_dev_create(usb_device_t *usb_dev)
    252 {
    253         assert(usb_dev);
    254         usb_hub_dev_t *hub_dev =
    255             usb_device_data_alloc(usb_dev, sizeof(usb_hub_dev_t));
    256         if (!hub_dev)
    257             return NULL;
    258 
    259         hub_dev->usb_device = usb_dev;
    260         hub_dev->ports = NULL;
    261         hub_dev->port_count = 0;
    262         hub_dev->pending_ops_count = 0;
    263         hub_dev->running = false;
    264         fibril_mutex_initialize(&hub_dev->pending_ops_mutex);
    265         fibril_condvar_initialize(&hub_dev->pending_ops_cv);
    266 
    267         return hub_dev;
    268 }
    269 /*----------------------------------------------------------------------------*/
    270 /**
    271284 * Load hub-specific information into hub_dev structure and process if needed
    272285 *
     
    311324        }
    312325
    313         const bool is_power_switched =
     326        hub_dev->power_switched =
    314327            !(descriptor.characteristics & HUB_CHAR_NO_POWER_SWITCH_FLAG);
    315         if (is_power_switched) {
    316                 usb_log_debug("Hub power switched\n");
    317                 const bool per_port_power = descriptor.characteristics
    318                     & HUB_CHAR_POWER_PER_PORT_FLAG;
    319 
    320                 for (size_t port = 0; port < hub_dev->port_count; ++port) {
    321                         usb_log_debug("Powering port %zu.\n", port);
    322                         opResult = usb_hub_port_set_feature(
    323                             &hub_dev->ports[port], USB_HUB_FEATURE_PORT_POWER);
    324                         if (opResult != EOK) {
    325                                 usb_log_error("Cannot power on port %zu: %s.\n",
    326                                     port, str_error(opResult));
    327                         } else {
    328                                 if (!per_port_power) {
    329                                         usb_log_debug(
    330                                             "Ganged power switching mode, "
    331                                             "one port is enough.\n");
    332                                         break;
    333                                 }
     328        hub_dev->per_port_power =
     329            descriptor.characteristics & HUB_CHAR_POWER_PER_PORT_FLAG;
     330
     331        if (!hub_dev->power_switched) {
     332                usb_log_info(
     333                   "Power switching not supported, ports always powered.\n");
     334                return EOK;
     335        }
     336
     337        usb_log_info("Hub port power switching enabled.\n");
     338
     339        for (size_t port = 0; port < hub_dev->port_count; ++port) {
     340                usb_log_debug("Powering port %zu.\n", port);
     341                const int ret = usb_hub_port_set_feature(
     342                    &hub_dev->ports[port], USB_HUB_FEATURE_PORT_POWER);
     343
     344                if (ret != EOK) {
     345                        usb_log_error("Cannot power on port %zu: %s.\n",
     346                            hub_dev->ports[port].port_number, str_error(ret));
     347                } else {
     348                        if (!hub_dev->per_port_power) {
     349                                usb_log_debug("Ganged power switching, "
     350                                    "one port is enough.\n");
     351                                break;
    334352                        }
    335353                }
    336         } else {
    337                 usb_log_debug("Power not switched, ports always powered\n");
    338354        }
    339355        return EOK;
     
    402418                usb_log_warning("Detected hub over-current condition, "
    403419                    "all ports should be powered off.");
    404         } else {
    405                 /* Over-current condition is gone, it is safe to turn the
    406                  * ports on. */
    407                 for (size_t port = 0; port < hub_dev->port_count; ++port) {
    408                         const int opResult = usb_hub_port_set_feature(
    409                             &hub_dev->ports[port], USB_HUB_FEATURE_PORT_POWER);
    410                         // TODO: consider power policy here
    411                         if (opResult != EOK) {
    412                                 usb_log_warning(
    413                                     "HUB OVER-CURRENT GONE: Cannot power on "
    414                                     "port %zu;  %s\n",
    415                                     port, str_error(opResult));
    416                         }
    417                 }
    418         }
    419         const int opResult = usb_request_clear_feature(
    420             &hub_dev->usb_device->ctrl_pipe, USB_REQUEST_TYPE_CLASS,
    421             USB_REQUEST_RECIPIENT_DEVICE,
    422             USB_HUB_FEATURE_C_HUB_LOCAL_POWER, 0);
    423         if (opResult != EOK) {
    424                 usb_log_error(
    425                     "Failed to clear hub over-current change flag: %s.\n",
    426                     str_error(opResult));
    427         }
     420                return;
     421        }
     422
     423        /* Ports are always powered. */
     424        if (!hub_dev->power_switched)
     425                return;
     426
     427        /* Over-current condition is gone, it is safe to turn the ports on. */
     428        for (size_t port = 0; port < hub_dev->port_count; ++port) {
     429                const int ret = usb_hub_port_set_feature(
     430                    &hub_dev->ports[port], USB_HUB_FEATURE_PORT_POWER);
     431                if (ret != EOK) {
     432                        usb_log_warning("HUB OVER-CURRENT GONE: Cannot power on"
     433                            " port %zu: %s\n", hub_dev->ports[port].port_number,
     434                            str_error(ret));
     435                } else {
     436                        if (!hub_dev->per_port_power)
     437                                return;
     438                }
     439        }
     440
    428441}
    429442/*----------------------------------------------------------------------------*/
     
    461474        if (status & USB_HUB_STATUS_C_OVER_CURRENT) {
    462475                usb_hub_over_current(hub_dev, status);
     476                /* Ack change in hub OC flag */
     477                const int ret = usb_request_clear_feature(
     478                    &hub_dev->usb_device->ctrl_pipe, USB_REQUEST_TYPE_CLASS,
     479                    USB_REQUEST_RECIPIENT_DEVICE,
     480                    USB_HUB_FEATURE_C_HUB_OVER_CURRENT, 0);
     481                if (ret != EOK) {
     482                        usb_log_error("Failed to clear hub over-current "
     483                            "change flag: %s.\n", str_error(opResult));
     484                }
    463485        }
    464486
     
    477499                 * Just ACK the change.
    478500                 */
    479                 const int opResult = usb_request_clear_feature(
     501                const int ret = usb_request_clear_feature(
    480502                    control_pipe, USB_REQUEST_TYPE_CLASS,
    481503                    USB_REQUEST_RECIPIENT_DEVICE,
    482504                    USB_HUB_FEATURE_C_HUB_LOCAL_POWER, 0);
    483505                if (opResult != EOK) {
    484                         usb_log_error(
    485                             "Failed to clear hub power change flag: %s.\n",
    486                             str_error(opResult));
     506                        usb_log_error("Failed to clear hub power change "
     507                            "flag: %s.\n", str_error(ret));
    487508                }
    488509        }
  • uspace/drv/bus/usb/usbhub/usbhub.h

    r1737bfb r45bf63c  
    7777        /** Status indicator */
    7878        bool running;
     79        /** Hub supports port power switching. */
     80        bool power_switched;
     81        /** Each port is switched individually. */
     82        bool per_port_power;
    7983};
    8084
    8185int usb_hub_device_add(usb_device_t *usb_dev);
     86int usb_hub_device_remove(usb_device_t *usb_dev);
    8287int usb_hub_device_gone(usb_device_t *usb_dev);
    8388
  • uspace/drv/bus/usb/usbmast/main.c

    r1737bfb r45bf63c  
    5555#define GET_BULK_OUT(dev) ((dev)->pipes[BULK_OUT_EP].pipe)
    5656
    57 static usb_endpoint_description_t bulk_in_ep = {
     57static const usb_endpoint_description_t bulk_in_ep = {
    5858        .transfer_type = USB_TRANSFER_BULK,
    5959        .direction = USB_DIRECTION_IN,
     
    6363        .flags = 0
    6464};
    65 static usb_endpoint_description_t bulk_out_ep = {
     65static const usb_endpoint_description_t bulk_out_ep = {
    6666        .transfer_type = USB_TRANSFER_BULK,
    6767        .direction = USB_DIRECTION_OUT,
     
    106106}
    107107
     108/** Callback when a device is about to be removed.
     109 *
     110 * @param dev Representation of USB device.
     111 * @return Error code.
     112 */
     113static int usbmast_device_remove(usb_device_t *dev)
     114{
     115        //TODO: flush buffers, or whatever.
     116        return ENOTSUP;
     117}
     118
    108119/** Callback when new device is attached and recognized as a mass storage.
    109120 *
    110  * @param dev Representation of a the USB device.
     121 * @param dev Representation of USB device.
    111122 * @return Error code.
    112123 */
     
    336347
    337348/** USB mass storage driver ops. */
    338 static usb_driver_ops_t usbmast_driver_ops = {
     349static const usb_driver_ops_t usbmast_driver_ops = {
    339350        .device_add = usbmast_device_add,
     351        .device_rem = usbmast_device_remove,
    340352        .device_gone = usbmast_device_gone,
    341353};
    342354
    343355/** USB mass storage driver. */
    344 static usb_driver_t usbmast_driver = {
     356static const usb_driver_t usbmast_driver = {
    345357        .name = NAME,
    346358        .ops = &usbmast_driver_ops,
  • uspace/drv/bus/usb/usbmid/main.c

    r1737bfb r45bf63c  
    6565        return EOK;
    6666}
     67/*----------------------------------------------------------------------------*/
     68/** Callback when a MID device is about to be removed from the host.
     69 *
     70 * @param gen_dev Generic DDF device representing the removed device.
     71 * @return Error code.
     72 */
     73static int usbmid_device_remove(usb_device_t *dev)
     74{
     75        assert(dev);
     76        int ret = ENOTSUP;
     77        usb_mid_t *usb_mid = dev->driver_data;
     78        assert(usb_mid);
    6779
     80        /* Signal all interface functions */
     81        list_foreach(usb_mid->interface_list, item) {
     82                usbmid_interface_t *iface = usbmid_interface_from_link(item);
     83
     84                usb_log_info("Signaling remove to child for interface "
     85                    "%d (%s).\n", iface->interface_no,
     86                    usb_str_class(iface->interface->interface_class));
     87                // TODO cascade the call.
     88        }
     89        return ret;
     90}
     91/*----------------------------------------------------------------------------*/
     92/** Callback when a MID device was removed from the host.
     93 *
     94 * @param gen_dev Generic DDF device representing the removed device.
     95 * @return Error code.
     96 */
    6897static int usbmid_device_gone(usb_device_t *dev)
    6998{
     
    86115                list_remove(item);
    87116
    88                 usbmid_interface_t *iface = list_get_instance(item,
    89                     usbmid_interface_t, link);
     117                usbmid_interface_t *iface = usbmid_interface_from_link(item);
    90118
    91119                usb_log_info("Removing child for interface %d (%s).\n",
     
    107135
    108136/** USB MID driver ops. */
    109 static usb_driver_ops_t mid_driver_ops = {
     137static const usb_driver_ops_t mid_driver_ops = {
    110138        .device_add = usbmid_device_add,
     139        .device_rem = usbmid_device_remove,
    111140        .device_gone = usbmid_device_gone,
    112141};
    113142
    114143/** USB MID driver. */
    115 static usb_driver_t mid_driver = {
     144static const usb_driver_t mid_driver = {
    116145        .name = NAME,
    117146        .ops = &mid_driver_ops,
  • uspace/drv/bus/usb/usbmid/usbmid.h

    r1737bfb r45bf63c  
    7171int usbmid_interface_destroy(usbmid_interface_t *mid_iface);
    7272
     73static inline usbmid_interface_t * usbmid_interface_from_link(link_t *item)
     74{
     75        return list_get_instance(item, usbmid_interface_t, link);
     76}
     77
    7378#endif
    7479/**
  • uspace/drv/bus/usb/vhc/connhost.c

    r1737bfb r45bf63c  
    104104{
    105105        VHC_DATA(vhc, fun);
    106         bool found =
    107             usb_device_manager_find_by_address(&vhc->dev_manager, address, handle);
    108         return found ? EOK : ENOENT;
     106        return usb_device_manager_get_info_by_address(
     107            &vhc->dev_manager, address, handle, NULL);
    109108}
    110109
     
    141140    size_t max_packet_size, unsigned int interval)
    142141{
    143         /* TODO: Use usb_endpoint_manager_add_ep */
    144         VHC_DATA(vhc, fun);
    145 
    146         endpoint_t *ep = endpoint_get(
    147             address, endpoint, direction, transfer_type, USB_SPEED_FULL, 1);
    148         if (ep == NULL) {
    149                 return ENOMEM;
    150         }
    151 
    152         int rc = usb_endpoint_manager_register_ep(&vhc->ep_manager, ep, 1);
    153         if (rc != EOK) {
    154                 endpoint_destroy(ep);
    155                 return rc;
    156         }
    157 
    158         return EOK;
     142        VHC_DATA(vhc, fun);
     143
     144        return usb_endpoint_manager_add_ep(&vhc->ep_manager,
     145            address, endpoint, direction, transfer_type, USB_SPEED_FULL, 1, 0,
     146            NULL, NULL);
     147
    159148}
    160149
     
    172161        VHC_DATA(vhc, fun);
    173162
    174         int rc = usb_endpoint_manager_unregister_ep(&vhc->ep_manager,
    175             address, endpoint, direction);
     163        int rc = usb_endpoint_manager_remove_ep(&vhc->ep_manager,
     164            address, endpoint, direction, NULL, NULL);
    176165
    177166        return rc;
     
    414403        VHC_DATA(vhc, fun);
    415404
    416         endpoint_t *ep = usb_endpoint_manager_get_ep(&vhc->ep_manager,
    417             target.address, target.endpoint, USB_DIRECTION_IN, NULL);
     405        endpoint_t *ep = usb_endpoint_manager_find_ep(&vhc->ep_manager,
     406            target.address, target.endpoint, USB_DIRECTION_IN);
    418407        if (ep == NULL) {
    419408                return ENOENT;
     
    456445        VHC_DATA(vhc, fun);
    457446
    458         endpoint_t *ep = usb_endpoint_manager_get_ep(&vhc->ep_manager,
    459             target.address, target.endpoint, USB_DIRECTION_OUT, NULL);
     447        endpoint_t *ep = usb_endpoint_manager_find_ep(&vhc->ep_manager,
     448            target.address, target.endpoint, USB_DIRECTION_OUT);
    460449        if (ep == NULL) {
    461450                return ENOENT;
     
    518507
    519508        usb_log_debug("tell_address_rh(handle=%" PRIun ")\n", handle);
    520         usb_address_t addr = usb_device_manager_find(&vhc->dev_manager, handle);
     509        const usb_address_t addr =
     510            usb_device_manager_find_address(&vhc->dev_manager, handle);
    521511        if (addr < 0) {
    522512                return addr;
  • uspace/lib/usbdev/include/usb/dev/driver.h

    r1737bfb r45bf63c  
    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

    r1737bfb r45bf63c  
    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

    r1737bfb r45bf63c  
    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

    r1737bfb r45bf63c  
    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

    r1737bfb r45bf63c  
    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

    r1737bfb r45bf63c  
    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

    r1737bfb r45bf63c  
    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

    r1737bfb r45bf63c  
    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

    r1737bfb r45bf63c  
    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

    r1737bfb r45bf63c  
    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

    r1737bfb r45bf63c  
    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

    r1737bfb r45bf63c  
    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

    r1737bfb r45bf63c  
    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.