Ignore:
Timestamp:
2011-04-07T15:04:16Z (13 years ago)
Author:
Matus Dekanek <smekideki@…>
Branches:
lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
Children:
36cd378
Parents:
9d06563 (diff), a82889e (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:

partial merge form usb/development

File:
1 moved

Legend:

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

    r9d06563 ra4e18e1  
    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 
     32
     33#include <usb/host/usb_endpoint_manager.h>
     34
     35#define BUCKET_COUNT 7
     36
     37#define MAX_KEYS (3)
    3338typedef struct {
    34         usb_address_t address;
    35         usb_endpoint_t endpoint;
    36         usb_direction_t direction;
    37 } __attribute__((aligned (sizeof(unsigned long)))) transfer_t;
    38 /*----------------------------------------------------------------------------*/
    39 typedef struct {
    40         transfer_t transfer;
    4139        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[])
     40        size_t bw;
     41        endpoint_t *ep;
     42} node_t;
     43/*----------------------------------------------------------------------------*/
     44static hash_index_t node_hash(unsigned long key[])
    5045{
    5146        hash_index_t hash = 0;
     
    5853}
    5954/*----------------------------------------------------------------------------*/
    60 static int transfer_compare(
    61     unsigned long key[], hash_count_t keys, link_t *item)
     55static int node_compare(unsigned long key[], hash_count_t keys, link_t *item)
    6256{
    6357        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);
    69 }
    70 /*----------------------------------------------------------------------------*/
    71 static void transfer_remove(link_t *item)
     58        node_t *node = hash_table_get_instance(item, node_t, link);
     59        assert(node);
     60        assert(node->ep);
     61        bool match = true;
     62        switch (keys) {
     63        case 3:
     64                match = match && (key[2] == node->ep->direction);
     65        case 2:
     66                match = match && (key[1] == (unsigned long)node->ep->endpoint);
     67        case 1:
     68                match = match && (key[0] == (unsigned long)node->ep->address);
     69                break;
     70        default:
     71                match = false;
     72        }
     73        return match;
     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/*----------------------------------------------------------------------------*/
     
    8791    size_t size, size_t max_packet_size)
    8892{
     93        /* We care about bandwidth only for interrupt and isochronous. */
     94        if ((type != USB_TRANSFER_INTERRUPT)
     95            && (type != USB_TRANSFER_ISOCHRONOUS)) {
     96                return 0;
     97        }
     98
    8999        const unsigned packet_count =
    90100            (size + max_packet_size - 1) / max_packet_size;
     
    120130}
    121131/*----------------------------------------------------------------------------*/
    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))
     132int usb_endpoint_manager_init(usb_endpoint_manager_t *instance,
     133    size_t available_bandwidth)
    124134{
    125135        assert(instance);
    126136        fibril_mutex_initialize(&instance->guard);
    127         instance->free = bandwidth;
    128         instance->usage_fnc = usage_fnc;
     137        fibril_condvar_initialize(&instance->change);
     138        instance->free_bw = available_bandwidth;
    129139        bool ht =
    130             hash_table_create(&instance->reserved, BUCKET_COUNT, MAX_KEYS, &op);
     140            hash_table_create(&instance->ep_table, BUCKET_COUNT, MAX_KEYS, &op);
    131141        return ht ? EOK : ENOMEM;
    132142}
    133143/*----------------------------------------------------------------------------*/
    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 = {
    153                 .address = address,
    154                 .endpoint = endpoint,
    155                 .direction = direction,
    156         };
     144void usb_endpoint_manager_destroy(usb_endpoint_manager_t *instance)
     145{
     146        hash_table_destroy(&instance->ep_table);
     147}
     148/*----------------------------------------------------------------------------*/
     149int usb_endpoint_manager_register_ep(usb_endpoint_manager_t *instance,
     150    endpoint_t *ep, size_t data_size)
     151{
     152        assert(ep);
     153        size_t bw = bandwidth_count_usb11(ep->speed, ep->transfer_type,
     154            data_size, ep->max_packet_size);
     155        assert(instance);
     156
     157        unsigned long key[MAX_KEYS] =
     158            {ep->address, ep->endpoint, ep->direction};
    157159        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) {
     160
     161        link_t *item =
     162            hash_table_find(&instance->ep_table, key);
     163        if (item != NULL) {
     164                fibril_mutex_unlock(&instance->guard);
     165                return EEXISTS;
     166        }
     167
     168        if (bw > instance->free_bw) {
    162169                fibril_mutex_unlock(&instance->guard);
    163170                return ENOSPC;
    164171        }
    165172
    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) {
     173        node_t *node = malloc(sizeof(node_t));
     174        if (node == NULL) {
    175175                fibril_mutex_unlock(&instance->guard);
    176176                return ENOMEM;
    177177        }
    178178
    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;
     179        node->bw = bw;
     180        node->ep = ep;
     181        link_initialize(&node->link);
     182
     183        hash_table_insert(&instance->ep_table, key, &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 = {
    197                 .address = address,
    198                 .endpoint = endpoint,
    199                 .direction = direction,
    200         };
     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        unsigned long key[MAX_KEYS] = {address, endpoint, direction};
     195
    201196        fibril_mutex_lock(&instance->guard);
    202         link_t *item =
    203             hash_table_find(&instance->reserved, (unsigned long*)&trans);
     197        link_t *item = hash_table_find(&instance->ep_table, key);
    204198        if (item == NULL) {
    205199                fibril_mutex_unlock(&instance->guard);
     
    207201        }
    208202
    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);
     203        node_t *node = hash_table_get_instance(item, node_t, link);
     204        instance->free_bw += node->bw;
     205        hash_table_remove(&instance->ep_table, key, MAX_KEYS);
    216206
    217207        fibril_mutex_unlock(&instance->guard);
     208        fibril_condvar_broadcast(&instance->change);
    218209        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)
    224 {
    225         assert(instance);
    226         transfer_t trans = {
    227                 .address = address,
    228                 .endpoint = endpoint,
    229                 .direction = direction,
    230         };
     210}
     211/*----------------------------------------------------------------------------*/
     212endpoint_t * usb_endpoint_manager_get_ep(usb_endpoint_manager_t *instance,
     213    usb_address_t address, usb_endpoint_t endpoint, usb_direction_t direction,
     214    size_t *bw)
     215{
     216        assert(instance);
     217        unsigned long key[MAX_KEYS] = {address, endpoint, direction};
     218
    231219        fibril_mutex_lock(&instance->guard);
    232         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->used) {
    240                         ret = EINPROGRESS;
    241                 }
    242                 status->used = true;
    243         } else {
    244                 ret = EINVAL;
    245         }
     220        link_t *item = hash_table_find(&instance->ep_table, key);
     221        if (item == NULL) {
     222                fibril_mutex_unlock(&instance->guard);
     223                return NULL;
     224        }
     225        node_t *node = hash_table_get_instance(item, node_t, link);
     226        if (bw)
     227                *bw = node->bw;
     228
    246229        fibril_mutex_unlock(&instance->guard);
    247         return ret;
    248 }
    249 /*----------------------------------------------------------------------------*/
    250 int bandwidth_free(bandwidth_t *instance, usb_address_t address,
    251     usb_endpoint_t endpoint, usb_direction_t direction)
    252 {
    253         assert(instance);
    254         transfer_t trans = {
    255                 .address = address,
    256                 .endpoint = endpoint,
    257                 .direction = direction,
    258         };
    259         fibril_mutex_lock(&instance->guard);
    260         link_t *item =
    261             hash_table_find(&instance->reserved, (unsigned long*)&trans);
    262         int ret = EOK;
    263         if (item != NULL) {
    264                 transfer_status_t *status =
    265                     hash_table_get_instance(item, transfer_status_t, link);
    266                 assert(status);
    267                 if (!status->used) {
    268                         ret = ENOENT;
    269                 }
    270                 status->used = false;
    271         } else {
    272                 ret = EINVAL;
    273         }
    274         fibril_mutex_unlock(&instance->guard);
    275         return ret;
    276 }
     230        return node->ep;
     231}
Note: See TracChangeset for help on using the changeset viewer.