Changeset a4e18e1 in mainline for uspace/lib/usb/src/host/usb_endpoint_manager.c
- Timestamp:
- 2011-04-07T15:04:16Z (14 years ago)
- 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. - File:
-
- 1 moved
Legend:
- Unmodified
- Added
- Removed
-
uspace/lib/usb/src/host/usb_endpoint_manager.c
r9d06563 ra4e18e1 1 1 /* 2 2 * Copyright (c) 2011 Jan Vesely 3 * All rights reserved.3 * All rights eps. 4 4 * 5 5 * Redistribution and use in source and binary forms, with or without … … 27 27 */ 28 28 29 #include <bool.h> 29 30 #include <assert.h> 30 31 #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) 33 38 typedef 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;41 39 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 /*----------------------------------------------------------------------------*/ 44 static hash_index_t node_hash(unsigned long key[]) 50 45 { 51 46 hash_index_t hash = 0; … … 58 53 } 59 54 /*----------------------------------------------------------------------------*/ 60 static int transfer_compare( 61 unsigned long key[], hash_count_t keys, link_t *item) 55 static int node_compare(unsigned long key[], hash_count_t keys, link_t *item) 62 56 { 63 57 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 /*----------------------------------------------------------------------------*/ 76 static void node_remove(link_t *item) 72 77 { 73 78 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 /*----------------------------------------------------------------------------*/ 84 static hash_table_operations_t op = { 85 .hash = node_hash, 86 .compare = node_compare, 87 .remove_callback = node_remove, 84 88 }; 85 89 /*----------------------------------------------------------------------------*/ … … 87 91 size_t size, size_t max_packet_size) 88 92 { 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 89 99 const unsigned packet_count = 90 100 (size + max_packet_size - 1) / max_packet_size; … … 120 130 } 121 131 /*----------------------------------------------------------------------------*/ 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))132 int usb_endpoint_manager_init(usb_endpoint_manager_t *instance, 133 size_t available_bandwidth) 124 134 { 125 135 assert(instance); 126 136 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; 129 139 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); 131 141 return ht ? EOK : ENOMEM; 132 142 } 133 143 /*----------------------------------------------------------------------------*/ 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 }; 144 void usb_endpoint_manager_destroy(usb_endpoint_manager_t *instance) 145 { 146 hash_table_destroy(&instance->ep_table); 147 } 148 /*----------------------------------------------------------------------------*/ 149 int 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}; 157 159 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) { 162 169 fibril_mutex_unlock(&instance->guard); 163 170 return ENOSPC; 164 171 } 165 172 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) { 175 175 fibril_mutex_unlock(&instance->guard); 176 176 return ENOMEM; 177 177 } 178 178 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; 187 185 fibril_mutex_unlock(&instance->guard); 186 fibril_condvar_broadcast(&instance->change); 188 187 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 /*----------------------------------------------------------------------------*/ 190 int 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 201 196 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); 204 198 if (item == NULL) { 205 199 fibril_mutex_unlock(&instance->guard); … … 207 201 } 208 202 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); 216 206 217 207 fibril_mutex_unlock(&instance->guard); 208 fibril_condvar_broadcast(&instance->change); 218 209 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 /*----------------------------------------------------------------------------*/ 212 endpoint_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 231 219 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 246 229 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.