Changeset b4b534ac in mainline for uspace/lib/usbhost/src/usb_bus.c
- Timestamp:
- 2016-07-22T08:24:47Z (8 years ago)
- 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. - File:
-
- 1 moved
Legend:
- Unmodified
- Added
- Removed
-
uspace/lib/usbhost/src/usb_bus.c
r5b18137 rb4b534ac 33 33 */ 34 34 35 #include <stdbool.h> 35 #include <usb/host/usb_bus.h> 36 #include <usb/debug.h> 37 36 38 #include <assert.h> 37 39 #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 41 43 42 44 /** Endpoint compare helper function. … … 63 65 64 66 /** Get list that holds endpoints for given address. 65 * @param instance usb_ endpoint_managerstructure, non-null.67 * @param instance usb_bus structure, non-null. 66 68 * @param addr USB address, must be >= 0. 67 69 * @return Pointer to the appropriate list. 68 70 */ 69 static list_t * get_list(usb_ endpoint_manager_t *instance, usb_address_t addr)71 static list_t * get_list(usb_bus_t *instance, usb_address_t addr) 70 72 { 71 73 assert(instance); 72 74 assert(addr >= 0); 73 return &instance-> endpoint_lists[addr % ENDPOINT_LIST_COUNT];75 return &instance->devices[addr % ARRAY_SIZE(instance->devices)].endpoint_list; 74 76 } 75 77 76 78 /** Internal search function, works on locked structure. 77 * @param instance usb_ endpoint_managerstructure, non-null.79 * @param instance usb_bus structure, non-null. 78 80 * @param address USB address, must be valid. 79 81 * @param endpoint USB endpoint number. … … 83 85 * @note Assumes that the internal mutex is locked. 84 86 */ 85 static endpoint_t * find_locked(usb_ endpoint_manager_t *instance,87 static endpoint_t * find_locked(usb_bus_t *instance, 86 88 usb_address_t address, usb_endpoint_t endpoint, usb_direction_t direction) 87 89 { … … 95 97 } 96 98 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 */ 106 static 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; 97 122 } 98 123 … … 145 170 } 146 171 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 */ 179 size_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 147 191 /** Initialize to default state. 148 192 * You need to provide valid bw_count function if you plan to use 149 193 * add_endpoint/remove_endpoint pair. 150 194 * 151 * @param instance usb_ endpoint_managerstructure, non-null.195 * @param instance usb_bus structure, non-null. 152 196 * @param available_bandwidth Size of the bandwidth pool. 153 197 * @param bw_count function to use to calculate endpoint bw requirements. 154 198 * @return Error code. 155 199 */ 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)) 200 int usb_bus_init(usb_bus_t *instance, 201 size_t available_bandwidth, bw_count_func_t bw_count, usb_speed_t max_speed) 159 202 { 160 203 assert(instance); … … 162 205 instance->free_bw = available_bandwidth; 163 206 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; 166 213 } 167 214 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.h178 */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.h194 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 registered212 * as different interfaces use different endpoints,213 * unless you're changing configuration or alternative214 * 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 }227 215 } 228 216 229 217 /** Register endpoint structure. 230 218 * Checks for duplicates. 231 * @param instance usb_ endpoint_manager, non-null.219 * @param instance usb_bus, non-null. 232 220 * @param ep endpoint_t to register. 233 221 * @param data_size Size of data to transfer. 234 222 * @return Error code. 235 223 */ 236 int usb_endpoint_manager_register_ep(usb_endpoint_manager_t *instance, 237 endpoint_t *ep, size_t data_size) 224 int usb_bus_register_ep(usb_bus_t *instance, endpoint_t *ep, size_t data_size) 238 225 { 239 226 assert(instance); … … 258 245 259 246 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)); 260 250 fibril_mutex_unlock(&instance->guard); 261 251 return EOK; … … 264 254 /** Unregister endpoint structure. 265 255 * Checks for duplicates. 266 * @param instance usb_ endpoint_manager, non-null.256 * @param instance usb_bus, non-null. 267 257 * @param ep endpoint_t to unregister. 268 258 * @return Error code. 269 259 */ 270 int usb_endpoint_manager_unregister_ep( 271 usb_endpoint_manager_t *instance, endpoint_t *ep) 260 int usb_bus_unregister_ep(usb_bus_t *instance, endpoint_t *ep) 272 261 { 273 262 assert(instance); … … 282 271 list_remove(&ep->link); 283 272 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)); 284 276 fibril_mutex_unlock(&instance->guard); 285 277 return EOK; … … 287 279 288 280 /** Find endpoint_t representing the given communication route. 289 * @param instance usb_ endpoint_manager, non-null.281 * @param instance usb_bus, non-null. 290 282 * @param address 291 283 */ 292 endpoint_t * usb_ endpoint_manager_find_ep(usb_endpoint_manager_t *instance,284 endpoint_t * usb_bus_find_ep(usb_bus_t *instance, 293 285 usb_address_t address, usb_endpoint_t endpoint, usb_direction_t direction) 294 286 { … … 302 294 303 295 /** Create and register new endpoint_t structure. 304 * @param instance usb_ endpoint_managerstructure, non-null.296 * @param instance usb_bus structure, non-null. 305 297 * @param address USB address. 306 298 * @param endpoint USB endpoint number. … … 314 306 * @return Error code. 315 307 */ 316 int usb_ endpoint_manager_add_ep(usb_endpoint_manager_t *instance,308 int usb_bus_add_ep(usb_bus_t *instance, 317 309 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) 320 313 { 321 314 assert(instance); 322 315 if (instance->bw_count == NULL) 323 316 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; 335 326 } 336 327 … … 342 333 } 343 334 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); 346 347 if (!ep) { 347 348 fibril_mutex_unlock(&instance->guard); … … 365 366 366 367 /** Unregister and destroy endpoint_t structure representing given route. 367 * @param instance usb_ endpoint_managerstructure, non-null.368 * @param instance usb_bus structure, non-null. 368 369 * @param address USB address. 369 370 * @param endpoint USB endpoint number. … … 373 374 * @return Error code. 374 375 */ 375 int usb_ endpoint_manager_remove_ep(usb_endpoint_manager_t *instance,376 int usb_bus_remove_ep(usb_bus_t *instance, 376 377 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) 378 379 { 379 380 assert(instance); … … 395 396 } 396 397 398 int 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 397 418 /** Unregister and destroy all endpoints using given address. 398 * @param instance usb_ endpoint_managerstructure, non-null.419 * @param instance usb_bus structure, non-null. 399 420 * @param address USB address. 400 421 * @param endpoint USB endpoint number. … … 404 425 * @return Error code. 405 426 */ 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 li nk = list_first(list);419 while (link != NULL) {427 int 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; ) { 420 441 endpoint_t *ep = list_get_instance(link, endpoint_t, link); 421 next = list_next(link, list); 422 442 link = list_next(link, list); 423 443 if (ep->address == address) { 424 444 list_remove(&ep->link); … … 427 447 endpoint_destroy(ep); 428 448 } 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 */ 461 int 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 */ 508 int 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; 432 525 } 433 526 /**
Note:
See TracChangeset
for help on using the changeset viewer.