Changeset b4b534ac in mainline for uspace/lib/usbhost/src/usb_bus.c


Ignore:
Timestamp:
2016-07-22T08:24:47Z (8 years ago)
Author:
Jakub Jermar <jakub@…>
Branches:
lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
Children:
f76d2c2
Parents:
5b18137 (diff), 8351f9a4 (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 lp:~jan.vesely/helenos/usb

File:
1 moved

Legend:

Unmodified
Added
Removed
  • uspace/lib/usbhost/src/usb_bus.c

    r5b18137 rb4b534ac  
    3333 */
    3434
    35 #include <stdbool.h>
     35#include <usb/host/usb_bus.h>
     36#include <usb/debug.h>
     37
    3638#include <assert.h>
    3739#include <errno.h>
    38 
    39 #include <usb/debug.h>
    40 #include <usb/host/usb_endpoint_manager.h>
     40#include <macros.h>
     41#include <stdbool.h>
     42
    4143
    4244/** Endpoint compare helper function.
     
    6365
    6466/** Get list that holds endpoints for given address.
    65  * @param instance usb_endpoint_manager structure, non-null.
     67 * @param instance usb_bus structure, non-null.
    6668 * @param addr USB address, must be >= 0.
    6769 * @return Pointer to the appropriate list.
    6870 */
    69 static list_t * get_list(usb_endpoint_manager_t *instance, usb_address_t addr)
     71static list_t * get_list(usb_bus_t *instance, usb_address_t addr)
    7072{
    7173        assert(instance);
    7274        assert(addr >= 0);
    73         return &instance->endpoint_lists[addr % ENDPOINT_LIST_COUNT];
     75        return &instance->devices[addr % ARRAY_SIZE(instance->devices)].endpoint_list;
    7476}
    7577
    7678/** Internal search function, works on locked structure.
    77  * @param instance usb_endpoint_manager structure, non-null.
     79 * @param instance usb_bus structure, non-null.
    7880 * @param address USB address, must be valid.
    7981 * @param endpoint USB endpoint number.
     
    8385 * @note Assumes that the internal mutex is locked.
    8486 */
    85 static endpoint_t * find_locked(usb_endpoint_manager_t *instance,
     87static endpoint_t * find_locked(usb_bus_t *instance,
    8688    usb_address_t address, usb_endpoint_t endpoint, usb_direction_t direction)
    8789{
     
    9597        }
    9698        return NULL;
     99}
     100
     101/** Get a free USB address
     102 *
     103 * @param[in] instance Device manager structure to use.
     104 * @return Free address, or error code.
     105 */
     106static usb_address_t usb_bus_get_free_address(usb_bus_t *instance)
     107{
     108
     109        usb_address_t new_address = instance->last_address;
     110        do {
     111                new_address = (new_address + 1) % USB_ADDRESS_COUNT;
     112                if (new_address == USB_ADDRESS_DEFAULT)
     113                        new_address = 1;
     114                if (new_address == instance->last_address)
     115                        return ENOSPC;
     116        } while (instance->devices[new_address].occupied);
     117
     118        assert(new_address != USB_ADDRESS_DEFAULT);
     119        instance->last_address = new_address;
     120
     121        return new_address;
    97122}
    98123
     
    145170}
    146171
     172/** Calculate bandwidth that needs to be reserved for communication with EP.
     173 * Calculation follows USB 2.0 specification.
     174 * @param speed Device's speed.
     175 * @param type Type of the transfer.
     176 * @param size Number of byte to transfer.
     177 * @param max_packet_size Maximum bytes in one packet.
     178 */
     179size_t bandwidth_count_usb20(usb_speed_t speed, usb_transfer_type_t type,
     180    size_t size, size_t max_packet_size)
     181{
     182        /* We care about bandwidth only for interrupt and isochronous. */
     183        if ((type != USB_TRANSFER_INTERRUPT)
     184            && (type != USB_TRANSFER_ISOCHRONOUS)) {
     185                return 0;
     186        }
     187        //TODO Implement
     188        return 0;
     189}
     190
    147191/** Initialize to default state.
    148192 * You need to provide valid bw_count function if you plan to use
    149193 * add_endpoint/remove_endpoint pair.
    150194 *
    151  * @param instance usb_endpoint_manager structure, non-null.
     195 * @param instance usb_bus structure, non-null.
    152196 * @param available_bandwidth Size of the bandwidth pool.
    153197 * @param bw_count function to use to calculate endpoint bw requirements.
    154198 * @return Error code.
    155199 */
    156 int usb_endpoint_manager_init(usb_endpoint_manager_t *instance,
    157     size_t available_bandwidth,
    158     size_t (*bw_count)(usb_speed_t, usb_transfer_type_t, size_t, size_t))
     200int usb_bus_init(usb_bus_t *instance,
     201    size_t available_bandwidth, bw_count_func_t bw_count, usb_speed_t max_speed)
    159202{
    160203        assert(instance);
     
    162205        instance->free_bw = available_bandwidth;
    163206        instance->bw_count = bw_count;
    164         for (unsigned i = 0; i < ENDPOINT_LIST_COUNT; ++i) {
    165                 list_initialize(&instance->endpoint_lists[i]);
     207        instance->last_address = 0;
     208        instance->max_speed = max_speed;
     209        for (unsigned i = 0; i < ARRAY_SIZE(instance->devices); ++i) {
     210                list_initialize(&instance->devices[i].endpoint_list);
     211                instance->devices[i].speed = USB_SPEED_MAX;
     212                instance->devices[i].occupied = false;
    166213        }
    167214        return EOK;
    168 }
    169 
    170 /** Check setup packet data for signs of toggle reset.
    171  *
    172  * @param[in] instance usb_endpoint_manager structure, non-null.
    173  * @param[in] target Device to receive setup packet.
    174  * @param[in] data Setup packet data.
    175  *
    176  * Really ugly one. Resets toggle bit on all endpoints that need it.
    177  * @TODO Use tools from libusbdev requests.h
    178  */
    179 void usb_endpoint_manager_reset_eps_if_need(usb_endpoint_manager_t *instance,
    180     usb_target_t target, const uint8_t data[8])
    181 {
    182         assert(instance);
    183         if (!usb_target_is_valid(target)) {
    184                 usb_log_error("Invalid data when checking for toggle reset.\n");
    185                 return;
    186         }
    187 
    188         assert(data);
    189         switch (data[1])
    190         {
    191         case 0x01: /* Clear Feature -- resets only cleared ep */
    192                 /* Recipient is endpoint, value is zero (ENDPOINT_STALL) */
    193                 // TODO Use macros in libusbdev requests.h
    194                 if (((data[0] & 0xf) == 1) && ((data[2] | data[3]) == 0)) {
    195                         fibril_mutex_lock(&instance->guard);
    196                         /* endpoint number is < 16, thus first byte is enough */
    197                         list_foreach(*get_list(instance, target.address),
    198                             link, endpoint_t, ep) {
    199                                 if ((ep->address == target.address)
    200                                     && (ep->endpoint = data[4])) {
    201                                         endpoint_toggle_set(ep,0);
    202                                 }
    203                         }
    204                         fibril_mutex_unlock(&instance->guard);
    205                 }
    206         break;
    207 
    208         case 0x9: /* Set Configuration */
    209         case 0x11: /* Set Interface */
    210                 /* Recipient must be device, this resets all endpoints,
    211                  * In fact there should be no endpoints but EP 0 registered
    212                  * as different interfaces use different endpoints,
    213                  * unless you're changing configuration or alternative
    214                  * interface of an already setup device. */
    215                 if ((data[0] & 0xf) == 0) {
    216                         fibril_mutex_lock(&instance->guard);
    217                         list_foreach(*get_list(instance, target.address),
    218                             link, endpoint_t, ep) {
    219                                 if (ep->address == target.address) {
    220                                         endpoint_toggle_set(ep,0);
    221                                 }
    222                         }
    223                         fibril_mutex_unlock(&instance->guard);
    224                 }
    225         break;
    226         }
    227215}
    228216
    229217/** Register endpoint structure.
    230218 * Checks for duplicates.
    231  * @param instance usb_endpoint_manager, non-null.
     219 * @param instance usb_bus, non-null.
    232220 * @param ep endpoint_t to register.
    233221 * @param data_size Size of data to transfer.
    234222 * @return Error code.
    235223 */
    236 int usb_endpoint_manager_register_ep(usb_endpoint_manager_t *instance,
    237     endpoint_t *ep, size_t data_size)
     224int usb_bus_register_ep(usb_bus_t *instance, endpoint_t *ep, size_t data_size)
    238225{
    239226        assert(instance);
     
    258245
    259246        instance->free_bw -= ep->bandwidth;
     247        usb_log_debug("Registered EP(%d:%d:%s:%s)\n", ep->address, ep->endpoint,
     248            usb_str_transfer_type_short(ep->transfer_type),
     249            usb_str_direction(ep->direction));
    260250        fibril_mutex_unlock(&instance->guard);
    261251        return EOK;
     
    264254/** Unregister endpoint structure.
    265255 * Checks for duplicates.
    266  * @param instance usb_endpoint_manager, non-null.
     256 * @param instance usb_bus, non-null.
    267257 * @param ep endpoint_t to unregister.
    268258 * @return Error code.
    269259 */
    270 int usb_endpoint_manager_unregister_ep(
    271     usb_endpoint_manager_t *instance, endpoint_t *ep)
     260int usb_bus_unregister_ep(usb_bus_t *instance, endpoint_t *ep)
    272261{
    273262        assert(instance);
     
    282271        list_remove(&ep->link);
    283272        instance->free_bw += ep->bandwidth;
     273        usb_log_debug("Unregistered EP(%d:%d:%s:%s)\n", ep->address,
     274            ep->endpoint, usb_str_transfer_type_short(ep->transfer_type),
     275            usb_str_direction(ep->direction));
    284276        fibril_mutex_unlock(&instance->guard);
    285277        return EOK;
     
    287279
    288280/** Find endpoint_t representing the given communication route.
    289  * @param instance usb_endpoint_manager, non-null.
     281 * @param instance usb_bus, non-null.
    290282 * @param address
    291283 */
    292 endpoint_t * usb_endpoint_manager_find_ep(usb_endpoint_manager_t *instance,
     284endpoint_t * usb_bus_find_ep(usb_bus_t *instance,
    293285    usb_address_t address, usb_endpoint_t endpoint, usb_direction_t direction)
    294286{
     
    302294
    303295/** Create and register new endpoint_t structure.
    304  * @param instance usb_endpoint_manager structure, non-null.
     296 * @param instance usb_bus structure, non-null.
    305297 * @param address USB address.
    306298 * @param endpoint USB endpoint number.
     
    314306 * @return Error code.
    315307 */
    316 int usb_endpoint_manager_add_ep(usb_endpoint_manager_t *instance,
     308int usb_bus_add_ep(usb_bus_t *instance,
    317309    usb_address_t address, usb_endpoint_t endpoint, usb_direction_t direction,
    318     usb_transfer_type_t type, usb_speed_t speed, size_t max_packet_size,
    319     size_t data_size, int (*callback)(endpoint_t *, void *), void *arg)
     310    usb_transfer_type_t type, size_t max_packet_size, unsigned packets,
     311    size_t data_size, ep_add_callback_t callback, void *arg,
     312    usb_address_t tt_address, unsigned tt_port)
    320313{
    321314        assert(instance);
    322315        if (instance->bw_count == NULL)
    323316                return ENOTSUP;
    324         if (address < 0)
    325                 return EINVAL;
    326 
    327         const size_t bw =
    328             instance->bw_count(speed, type, data_size, max_packet_size);
    329 
    330         fibril_mutex_lock(&instance->guard);
    331         /* Check for available bandwidth */
    332         if (bw > instance->free_bw) {
    333                 fibril_mutex_unlock(&instance->guard);
    334                 return ENOSPC;
     317        if (!usb_address_is_valid(address))
     318                return EINVAL;
     319
     320
     321        fibril_mutex_lock(&instance->guard);
     322        /* Check for speed and address */
     323        if (!instance->devices[address].occupied) {
     324                fibril_mutex_unlock(&instance->guard);
     325                return ENOENT;
    335326        }
    336327
     
    342333        }
    343334
    344         ep = endpoint_create(
    345             address, endpoint, direction, type, speed, max_packet_size, bw);
     335        const usb_speed_t speed = instance->devices[address].speed;
     336        const size_t bw =
     337            instance->bw_count(speed, type, data_size, max_packet_size);
     338
     339        /* Check for available bandwidth */
     340        if (bw > instance->free_bw) {
     341                fibril_mutex_unlock(&instance->guard);
     342                return ENOSPC;
     343        }
     344
     345        ep = endpoint_create(address, endpoint, direction, type, speed,
     346            max_packet_size, packets, bw, tt_address, tt_port);
    346347        if (!ep) {
    347348                fibril_mutex_unlock(&instance->guard);
     
    365366
    366367/** Unregister and destroy endpoint_t structure representing given route.
    367  * @param instance usb_endpoint_manager structure, non-null.
     368 * @param instance usb_bus structure, non-null.
    368369 * @param address USB address.
    369370 * @param endpoint USB endpoint number.
     
    373374 * @return Error code.
    374375 */
    375 int usb_endpoint_manager_remove_ep(usb_endpoint_manager_t *instance,
     376int usb_bus_remove_ep(usb_bus_t *instance,
    376377    usb_address_t address, usb_endpoint_t endpoint, usb_direction_t direction,
    377     void (*callback)(endpoint_t *, void *), void *arg)
     378    ep_remove_callback_t callback, void *arg)
    378379{
    379380        assert(instance);
     
    395396}
    396397
     398int usb_bus_reset_toggle(usb_bus_t *instance, usb_target_t target, bool all)
     399{
     400        assert(instance);
     401        if (!usb_target_is_valid(target))
     402                return EINVAL;
     403
     404        int ret = ENOENT;
     405
     406        fibril_mutex_lock(&instance->guard);
     407        list_foreach(*get_list(instance, target.address), link, endpoint_t, ep) {
     408                if ((ep->address == target.address)
     409                    && (all || ep->endpoint == target.endpoint)) {
     410                        endpoint_toggle_set(ep, 0);
     411                        ret = EOK;
     412                }
     413        }
     414        fibril_mutex_unlock(&instance->guard);
     415        return ret;
     416}
     417
    397418/** Unregister and destroy all endpoints using given address.
    398  * @param instance usb_endpoint_manager structure, non-null.
     419 * @param instance usb_bus structure, non-null.
    399420 * @param address USB address.
    400421 * @param endpoint USB endpoint number.
     
    404425 * @return Error code.
    405426 */
    406 void usb_endpoint_manager_remove_address(usb_endpoint_manager_t *instance,
    407     usb_address_t address, void (*callback)(endpoint_t *, void *), void *arg)
    408 {
    409         list_t *list;
    410         link_t *link;
    411         link_t *next;
    412 
    413         assert(address >= 0);
    414         assert(instance);
    415         fibril_mutex_lock(&instance->guard);
    416 
    417         list = get_list(instance, address);
    418         link = list_first(list);
    419         while (link != NULL) {
     427int usb_bus_remove_address(usb_bus_t *instance,
     428    usb_address_t address, ep_remove_callback_t callback, void *arg)
     429{
     430        assert(instance);
     431        if (!usb_address_is_valid(address))
     432                return EINVAL;
     433
     434        fibril_mutex_lock(&instance->guard);
     435
     436        const int ret = instance->devices[address].occupied ? EOK : ENOENT;
     437        instance->devices[address].occupied = false;
     438
     439        list_t *list = get_list(instance, address);
     440        for (link_t *link = list_first(list); link != NULL; ) {
    420441                endpoint_t *ep = list_get_instance(link, endpoint_t, link);
    421                 next = list_next(link, list);
    422 
     442                link = list_next(link, list);
    423443                if (ep->address == address) {
    424444                        list_remove(&ep->link);
     
    427447                        endpoint_destroy(ep);
    428448                }
    429                 link = next;
    430         }
    431         fibril_mutex_unlock(&instance->guard);
     449        }
     450        fibril_mutex_unlock(&instance->guard);
     451        return ret;
     452}
     453
     454/** Request USB address.
     455 * @param instance usb_device_manager
     456 * @param address Pointer to requested address value, place to store new address
     457 * @parma strict Fail if the requested address is not available.
     458 * @return Error code.
     459 * @note Default address is only available in strict mode.
     460 */
     461int usb_bus_request_address(usb_bus_t *instance,
     462    usb_address_t *address, bool strict, usb_speed_t speed)
     463{
     464        assert(instance);
     465        assert(address);
     466        if (speed > instance->max_speed)
     467                return ENOTSUP;
     468
     469        if (!usb_address_is_valid(*address))
     470                return EINVAL;
     471
     472        usb_address_t addr = *address;
     473
     474        fibril_mutex_lock(&instance->guard);
     475        /* Only grant default address to strict requests */
     476        if ((addr == USB_ADDRESS_DEFAULT) && !strict) {
     477                addr = usb_bus_get_free_address(instance);
     478        }
     479
     480        if (instance->devices[addr].occupied) {
     481                if (strict) {
     482                        fibril_mutex_unlock(&instance->guard);
     483                        return ENOENT;
     484                }
     485                addr = usb_bus_get_free_address(instance);
     486        }
     487        if (usb_address_is_valid(addr)) {
     488                assert(instance->devices[addr].occupied == false);
     489                assert(addr != USB_ADDRESS_DEFAULT || strict);
     490
     491                instance->devices[addr].occupied = true;
     492                instance->devices[addr].speed = speed;
     493                *address = addr;
     494                addr = 0;
     495        }
     496
     497        fibril_mutex_unlock(&instance->guard);
     498        return addr;
     499}
     500
     501/** Get speed assigned to USB address.
     502 *
     503 * @param[in] instance Device manager structure to use.
     504 * @param[in] address Address the caller wants to find.
     505 * @param[out] speed Assigned speed.
     506 * @return Error code.
     507 */
     508int usb_bus_get_speed(usb_bus_t *instance, usb_address_t address,
     509    usb_speed_t *speed)
     510{
     511        assert(instance);
     512        if (!usb_address_is_valid(address)) {
     513                return EINVAL;
     514        }
     515
     516        fibril_mutex_lock(&instance->guard);
     517
     518        const int ret = instance->devices[address].occupied ? EOK : ENOENT;
     519        if (speed && instance->devices[address].occupied) {
     520                *speed = instance->devices[address].speed;
     521        }
     522
     523        fibril_mutex_unlock(&instance->guard);
     524        return ret;
    432525}
    433526/**
Note: See TracChangeset for help on using the changeset viewer.