Changeset dcaf819 in mainline for uspace/lib/usb/src


Ignore:
Timestamp:
2011-04-06T22:33:08Z (14 years ago)
Author:
Jan Vesely <jano.vesely@…>
Branches:
lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
Children:
9a7e5b4
Parents:
6bf9bc4 (diff), 87305bb (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:

OHCI structures, bandwidth reworked

Initial support for endpoint registration and a new way of bandwidth reservation
New usb_endpoint_manager to manage endpoints, bandwidth, and toggle states.
Further work:

switch communication collision avoidance to the new endpoint manager (requires registration of all endpoints)

use endpoint registration in default address reservation

Location:
uspace/lib/usb/src/host
Files:
1 added
2 edited
1 moved

Legend:

Unmodified
Added
Removed
  • uspace/lib/usb/src/host/batch.c

    r6bf9bc4 rdcaf819  
    5454    void *arg,
    5555    ddf_fun_t *fun,
     56                endpoint_t *ep,
    5657    void *private_data
    5758    )
     
    7778        instance->next_step = NULL;
    7879        instance->error = EOK;
    79 
     80        instance->ep = ep;
    8081}
    8182/*----------------------------------------------------------------------------*/
  • uspace/lib/usb/src/host/device_keeper.c

    r6bf9bc4 rdcaf819  
    5656                instance->devices[i].control_used = 0;
    5757                instance->devices[i].handle = 0;
    58                 instance->devices[i].toggle_status[0] = 0;
    59                 instance->devices[i].toggle_status[1] = 0;
    60         }
     58                list_initialize(&instance->devices[i].endpoints);
     59        }
     60}
     61/*----------------------------------------------------------------------------*/
     62void usb_device_keeper_add_ep(
     63    usb_device_keeper_t *instance, usb_address_t address, endpoint_t *ep)
     64{
     65        assert(instance);
     66        fibril_mutex_lock(&instance->guard);
     67        assert(instance->devices[address].occupied);
     68        list_append(&ep->same_device_eps, &instance->devices[address].endpoints);
     69        fibril_mutex_unlock(&instance->guard);
    6170}
    6271/*----------------------------------------------------------------------------*/
     
    6675 * @param[in] speed Speed of the device requesting default address.
    6776 */
    68 void usb_device_keeper_reserve_default_address(usb_device_keeper_t *instance,
    69     usb_speed_t speed)
     77void usb_device_keeper_reserve_default_address(
     78    usb_device_keeper_t *instance, usb_speed_t speed)
    7079{
    7180        assert(instance);
     
    101110 * Really ugly one.
    102111 */
    103 void usb_device_keeper_reset_if_need(usb_device_keeper_t *instance,
    104     usb_target_t target, const uint8_t *data)
     112void usb_device_keeper_reset_if_need(
     113    usb_device_keeper_t *instance, usb_target_t target, const uint8_t *data)
    105114{
    106115        assert(instance);
     
    120129                if (((data[0] & 0xf) == 1) && ((data[2] | data[3]) == 0)) {
    121130                        /* endpoint number is < 16, thus first byte is enough */
    122                         instance->devices[target.address].toggle_status[0] &=
    123                             ~(1 << data[4]);
    124                         instance->devices[target.address].toggle_status[1] &=
    125                             ~(1 << data[4]);
     131                        assert(!"NOT IMPLEMENTED!");
    126132                }
    127133        break;
     
    131137                /* target must be device */
    132138                if ((data[0] & 0xf) == 0) {
    133                         instance->devices[target.address].toggle_status[0] = 0;
    134                         instance->devices[target.address].toggle_status[1] = 0;
     139                        link_t *current =
     140                            instance->devices[target.address].endpoints.next;
     141                        while (current !=
     142                           &instance->devices[target.address].endpoints)
     143                        {
     144                                endpoint_toggle_reset(current);
     145                                current = current->next;
     146                        }
    135147                }
    136148        break;
    137149        }
    138150        fibril_mutex_unlock(&instance->guard);
    139 }
    140 /*----------------------------------------------------------------------------*/
    141 /** Get current value of endpoint toggle.
    142  *
    143  * @param[in] instance Device keeper structure to use.
    144  * @param[in] target Device and endpoint used.
    145  * @return Error code
    146  */
    147 int usb_device_keeper_get_toggle(usb_device_keeper_t *instance,
    148     usb_target_t target, usb_direction_t direction)
    149 {
    150         assert(instance);
    151         /* only control pipes are bi-directional and those do not need toggle */
    152         if (direction == USB_DIRECTION_BOTH)
    153                 return ENOENT;
    154         int ret;
    155         fibril_mutex_lock(&instance->guard);
    156         if (target.endpoint > 15 || target.endpoint < 0
    157             || target.address >= USB_ADDRESS_COUNT || target.address < 0
    158             || !instance->devices[target.address].occupied) {
    159                 usb_log_error("Invalid data when asking for toggle value.\n");
    160                 ret = EINVAL;
    161         } else {
    162                 ret = (instance->devices[target.address].toggle_status[direction]
    163                         >> target.endpoint) & 1;
    164         }
    165         fibril_mutex_unlock(&instance->guard);
    166         return ret;
    167 }
    168 /*----------------------------------------------------------------------------*/
    169 /** Set current value of endpoint toggle.
    170  *
    171  * @param[in] instance Device keeper structure to use.
    172  * @param[in] target Device and endpoint used.
    173  * @param[in] toggle Toggle value.
    174  * @return Error code.
    175  */
    176 int usb_device_keeper_set_toggle(usb_device_keeper_t *instance,
    177     usb_target_t target, usb_direction_t direction, bool toggle)
    178 {
    179         assert(instance);
    180         /* only control pipes are bi-directional and those do not need toggle */
    181         if (direction == USB_DIRECTION_BOTH)
    182                 return ENOENT;
    183         int ret;
    184         fibril_mutex_lock(&instance->guard);
    185         if (target.endpoint > 15 || target.endpoint < 0
    186             || target.address >= USB_ADDRESS_COUNT || target.address < 0
    187             || !instance->devices[target.address].occupied) {
    188                 usb_log_error("Invalid data when setting toggle value.\n");
    189                 ret = EINVAL;
    190         } else {
    191                 if (toggle) {
    192                         instance->devices[target.address].toggle_status[direction]
    193                             |= (1 << target.endpoint);
    194                 } else {
    195                         instance->devices[target.address].toggle_status[direction]
    196                             &= ~(1 << target.endpoint);
    197                 }
    198                 ret = EOK;
    199         }
    200         fibril_mutex_unlock(&instance->guard);
    201         return ret;
    202151}
    203152/*----------------------------------------------------------------------------*/
     
    208157 * @return Free address, or error code.
    209158 */
    210 usb_address_t device_keeper_get_free_address(usb_device_keeper_t *instance,
    211     usb_speed_t speed)
     159usb_address_t device_keeper_get_free_address(
     160    usb_device_keeper_t *instance, usb_speed_t speed)
    212161{
    213162        assert(instance);
     
    229178        instance->devices[new_address].occupied = true;
    230179        instance->devices[new_address].speed = speed;
    231         instance->devices[new_address].toggle_status[0] = 0;
    232         instance->devices[new_address].toggle_status[1] = 0;
    233180        instance->last_address = new_address;
    234181        fibril_mutex_unlock(&instance->guard);
     
    259206 * @param[in] address Device address
    260207 */
    261 void usb_device_keeper_release(usb_device_keeper_t *instance,
    262     usb_address_t address)
     208void usb_device_keeper_release(
     209    usb_device_keeper_t *instance, usb_address_t address)
    263210{
    264211        assert(instance);
     
    278225 * @return USB Address, or error code.
    279226 */
    280 usb_address_t usb_device_keeper_find(usb_device_keeper_t *instance,
    281     devman_handle_t handle)
     227usb_address_t usb_device_keeper_find(
     228    usb_device_keeper_t *instance, devman_handle_t handle)
    282229{
    283230        assert(instance);
     
    301248 * @return USB speed.
    302249 */
    303 usb_speed_t usb_device_keeper_get_speed(usb_device_keeper_t *instance,
    304     usb_address_t address)
     250usb_speed_t usb_device_keeper_get_speed(
     251    usb_device_keeper_t *instance, usb_address_t address)
    305252{
    306253        assert(instance);
     
    310257}
    311258/*----------------------------------------------------------------------------*/
    312 void usb_device_keeper_use_control(usb_device_keeper_t *instance,
    313     usb_target_t target)
     259void usb_device_keeper_use_control(
     260    usb_device_keeper_t *instance, usb_target_t target)
    314261{
    315262        assert(instance);
     
    323270}
    324271/*----------------------------------------------------------------------------*/
    325 void usb_device_keeper_release_control(usb_device_keeper_t *instance,
    326     usb_target_t target)
     272void usb_device_keeper_release_control(
     273    usb_device_keeper_t *instance, usb_target_t target)
    327274{
    328275        assert(instance);
  • uspace/lib/usb/src/host/usb_endpoint_manager.c

    r6bf9bc4 rdcaf819  
    11/*
    22 * Copyright (c) 2011 Jan Vesely
    3  * All rights reserved.
     3 * All rights eps.
    44 *
    55 * Redistribution and use in source and binary forms, with or without
     
    2727 */
    2828
     29#include <bool.h>
    2930#include <assert.h>
    3031#include <errno.h>
    31 #include <usb/host/bandwidth.h>
    32 
    33 typedef struct {
     32
     33#include <usb/host/usb_endpoint_manager.h>
     34
     35#define BUCKET_COUNT 7
     36
     37typedef struct {
    3438        usb_address_t address;
    3539        usb_endpoint_t endpoint;
    3640        usb_direction_t direction;
    37 } __attribute__((aligned (sizeof(unsigned long)))) transfer_t;
    38 /*----------------------------------------------------------------------------*/
     41} __attribute__((aligned (sizeof(unsigned long)))) id_t;
     42#define MAX_KEYS (sizeof(id_t) / sizeof(unsigned long))
    3943typedef struct {
    40         transfer_t transfer;
     44        union {
     45                id_t id;
     46                unsigned long key[MAX_KEYS];
     47        };
    4148        link_t link;
    42         bool used;
    43         size_t required;
    44 } transfer_status_t;
    45 /*----------------------------------------------------------------------------*/
    46 #define BUCKET_COUNT 7
    47 #define MAX_KEYS (sizeof(transfer_t) / sizeof(unsigned long))
    48 /*----------------------------------------------------------------------------*/
    49 static hash_index_t transfer_hash(unsigned long key[])
     49        size_t bw;
     50        endpoint_t *ep;
     51} node_t;
     52/*----------------------------------------------------------------------------*/
     53static hash_index_t node_hash(unsigned long key[])
    5054{
    5155        hash_index_t hash = 0;
     
    5862}
    5963/*----------------------------------------------------------------------------*/
    60 static int transfer_compare(
    61     unsigned long key[], hash_count_t keys, link_t *item)
     64static int node_compare(unsigned long key[], hash_count_t keys, link_t *item)
    6265{
    6366        assert(item);
    64         transfer_status_t *status =
    65             hash_table_get_instance(item, transfer_status_t, link);
    66         const size_t bytes =
    67             keys < MAX_KEYS ? keys * sizeof(unsigned long) : sizeof(transfer_t);
    68         return bcmp(key, &status->transfer, bytes) == 0;
    69 }
    70 /*----------------------------------------------------------------------------*/
    71 static void transfer_remove(link_t *item)
     67        node_t *node = hash_table_get_instance(item, node_t, link);
     68        hash_count_t i = 0;
     69        for (; i < keys; ++i) {
     70                if (key[i] != node->key[i])
     71                        return false;
     72        }
     73        return true;
     74}
     75/*----------------------------------------------------------------------------*/
     76static void node_remove(link_t *item)
    7277{
    7378        assert(item);
    74         transfer_status_t *status =
    75             hash_table_get_instance(item, transfer_status_t, link);
    76         assert(status);
    77         free(status);
    78 }
    79 /*----------------------------------------------------------------------------*/
    80 hash_table_operations_t op = {
    81         .hash = transfer_hash,
    82         .compare = transfer_compare,
    83         .remove_callback = transfer_remove,
     79        node_t *node = hash_table_get_instance(item, node_t, link);
     80        endpoint_destroy(node->ep);
     81        free(node);
     82}
     83/*----------------------------------------------------------------------------*/
     84static hash_table_operations_t op = {
     85        .hash = node_hash,
     86        .compare = node_compare,
     87        .remove_callback = node_remove,
    8488};
    8589/*----------------------------------------------------------------------------*/
     
    120124}
    121125/*----------------------------------------------------------------------------*/
    122 int bandwidth_init(bandwidth_t *instance, size_t bandwidth,
    123     size_t (*usage_fnc)(usb_speed_t, usb_transfer_type_t, size_t, size_t))
     126int usb_endpoint_manager_init(usb_endpoint_manager_t *instance,
     127    size_t available_bandwidth)
    124128{
    125129        assert(instance);
    126130        fibril_mutex_initialize(&instance->guard);
    127         instance->free = bandwidth;
    128         instance->usage_fnc = usage_fnc;
     131        fibril_condvar_initialize(&instance->change);
     132        instance->free_bw = available_bandwidth;
    129133        bool ht =
    130             hash_table_create(&instance->reserved, BUCKET_COUNT, MAX_KEYS, &op);
     134            hash_table_create(&instance->ep_table, BUCKET_COUNT, MAX_KEYS, &op);
    131135        return ht ? EOK : ENOMEM;
    132136}
    133137/*----------------------------------------------------------------------------*/
    134 void bandwidth_destroy(bandwidth_t *instance)
    135 {
    136         hash_table_destroy(&instance->reserved);
    137 }
    138 /*----------------------------------------------------------------------------*/
    139 int bandwidth_reserve(bandwidth_t *instance, usb_address_t address,
    140     usb_endpoint_t endpoint, usb_direction_t direction, usb_speed_t speed,
    141     usb_transfer_type_t transfer_type, size_t max_packet_size, size_t size,
    142     unsigned interval)
    143 {
    144         if (transfer_type != USB_TRANSFER_ISOCHRONOUS &&
    145             transfer_type != USB_TRANSFER_INTERRUPT) {
    146                 return ENOTSUP;
    147         }
    148 
    149         assert(instance);
    150         assert(instance->usage_fnc);
    151 
    152         transfer_t trans = {
     138void usb_endpoint_manager_destroy(usb_endpoint_manager_t *instance)
     139{
     140        hash_table_destroy(&instance->ep_table);
     141}
     142/*----------------------------------------------------------------------------*/
     143int usb_endpoint_manager_register_ep(usb_endpoint_manager_t *instance,
     144    usb_address_t address, usb_endpoint_t endpoint, usb_direction_t direction,
     145    endpoint_t *ep, size_t data_size)
     146{
     147        assert(ep);
     148        size_t bw = bandwidth_count_usb11(ep->speed, ep->transfer_type,
     149            data_size, ep->max_packet_size);
     150        assert(instance);
     151
     152        id_t id = {
    153153                .address = address,
    154154                .endpoint = endpoint,
     
    156156        };
    157157        fibril_mutex_lock(&instance->guard);
    158         const size_t required =
    159             instance->usage_fnc(speed, transfer_type, size, max_packet_size);
    160 
    161         if (required > instance->free) {
     158
     159        link_t *item =
     160            hash_table_find(&instance->ep_table, (unsigned long*)&id);
     161        if (item != NULL) {
     162                fibril_mutex_unlock(&instance->guard);
     163                return EEXISTS;
     164        }
     165
     166        if (bw > instance->free_bw) {
    162167                fibril_mutex_unlock(&instance->guard);
    163168                return ENOSPC;
    164169        }
    165170
    166         link_t *item =
    167             hash_table_find(&instance->reserved, (unsigned long*)&trans);
    168         if (item != NULL) {
    169                 fibril_mutex_unlock(&instance->guard);
    170                 return EEXISTS;
    171         }
    172 
    173         transfer_status_t *status = malloc(sizeof(transfer_status_t));
    174         if (status == NULL) {
     171        node_t *node = malloc(sizeof(node_t));
     172        if (node == NULL) {
    175173                fibril_mutex_unlock(&instance->guard);
    176174                return ENOMEM;
    177175        }
    178176
    179         status->transfer = trans;
    180         status->required = required;
    181         status->used = false;
    182         link_initialize(&status->link);
    183 
    184         hash_table_insert(&instance->reserved,
    185             (unsigned long*)&status->transfer, &status->link);
    186         instance->free -= required;
     177        node->id = id;
     178        node->bw = bw;
     179        node->ep = ep;
     180        link_initialize(&node->link);
     181
     182        hash_table_insert(&instance->ep_table,
     183            (unsigned long*)&id, &node->link);
     184        instance->free_bw -= bw;
    187185        fibril_mutex_unlock(&instance->guard);
     186        fibril_condvar_broadcast(&instance->change);
    188187        return EOK;
    189         /* TODO: compute bandwidth used */
    190 }
    191 /*----------------------------------------------------------------------------*/
    192 int bandwidth_release(bandwidth_t *instance, usb_address_t address,
    193     usb_endpoint_t endpoint, usb_direction_t direction)
    194 {
    195         assert(instance);
    196         transfer_t trans = {
     188}
     189/*----------------------------------------------------------------------------*/
     190int usb_endpoint_manager_unregister_ep(usb_endpoint_manager_t *instance,
     191    usb_address_t address, usb_endpoint_t endpoint, usb_direction_t direction)
     192{
     193        assert(instance);
     194        id_t id = {
    197195                .address = address,
    198196                .endpoint = endpoint,
     
    201199        fibril_mutex_lock(&instance->guard);
    202200        link_t *item =
    203             hash_table_find(&instance->reserved, (unsigned long*)&trans);
     201            hash_table_find(&instance->ep_table, (unsigned long*)&id);
    204202        if (item == NULL) {
    205203                fibril_mutex_unlock(&instance->guard);
     
    207205        }
    208206
    209         transfer_status_t *status =
    210             hash_table_get_instance(item, transfer_status_t, link);
    211 
    212         instance->free += status->required;
    213 
    214         hash_table_remove(&instance->reserved,
    215             (unsigned long*)&trans, MAX_KEYS);
     207        node_t *node = hash_table_get_instance(item, node_t, link);
     208        instance->free_bw += node->bw;
     209        hash_table_remove(&instance->ep_table, (unsigned long*)&id, MAX_KEYS);
    216210
    217211        fibril_mutex_unlock(&instance->guard);
     212        fibril_condvar_broadcast(&instance->change);
    218213        return EOK;
    219         /* TODO: compute bandwidth freed */
    220 }
    221 /*----------------------------------------------------------------------------*/
    222 int bandwidth_use(bandwidth_t *instance, usb_address_t address,
    223     usb_endpoint_t endpoint, usb_direction_t direction, size_t bw)
    224 {
    225         assert(instance);
    226         transfer_t trans = {
     214}
     215/*----------------------------------------------------------------------------*/
     216endpoint_t * usb_endpoint_manager_get_ep(usb_endpoint_manager_t *instance,
     217    usb_address_t address, usb_endpoint_t endpoint, usb_direction_t direction,
     218    size_t *bw)
     219{
     220        assert(instance);
     221        id_t id = {
    227222                .address = address,
    228223                .endpoint = endpoint,
     
    231226        fibril_mutex_lock(&instance->guard);
    232227        link_t *item =
    233             hash_table_find(&instance->reserved, (unsigned long*)&trans);
    234         int ret = EOK;
    235         if (item != NULL) {
    236                 transfer_status_t *status =
    237                     hash_table_get_instance(item, transfer_status_t, link);
    238                 assert(status);
    239                 if (status->required >= bw) {
    240                         if (status->used) {
    241                                 ret = EINPROGRESS;
    242                         }
    243                         status->used = true;
    244                 } else {
    245                         ret = ENOSPC;
    246                 }
    247         } else {
    248                 ret = EINVAL;
    249         }
     228            hash_table_find(&instance->ep_table, (unsigned long*)&id);
     229        if (item == NULL) {
     230                fibril_mutex_unlock(&instance->guard);
     231                return NULL;
     232        }
     233        node_t *node = hash_table_get_instance(item, node_t, link);
     234        if (bw)
     235                *bw = node->bw;
     236
    250237        fibril_mutex_unlock(&instance->guard);
    251         return ret;
    252 }
    253 /*----------------------------------------------------------------------------*/
    254 int bandwidth_free(bandwidth_t *instance, usb_address_t address,
    255     usb_endpoint_t endpoint, usb_direction_t direction)
    256 {
    257         assert(instance);
    258         transfer_t trans = {
    259                 .address = address,
    260                 .endpoint = endpoint,
    261                 .direction = direction,
    262         };
    263         fibril_mutex_lock(&instance->guard);
    264         link_t *item =
    265             hash_table_find(&instance->reserved, (unsigned long*)&trans);
    266         int ret = EOK;
    267         if (item != NULL) {
    268                 transfer_status_t *status =
    269                     hash_table_get_instance(item, transfer_status_t, link);
    270                 assert(status);
    271                 if (!status->used) {
    272                         ret = ENOENT;
    273                 }
    274                 status->used = false;
    275         } else {
    276                 ret = EINVAL;
    277         }
    278         fibril_mutex_unlock(&instance->guard);
    279         return ret;
    280 }
     238        return node->ep;
     239}
Note: See TracChangeset for help on using the changeset viewer.