Changes in uspace/drv/bus/usb/usbhub/usbhub.c [b7fd2a0:aa148b3] in mainline
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
uspace/drv/bus/usb/usbhub/usbhub.c
rb7fd2a0 raa148b3 51 51 #include <usb/classes/hub.h> 52 52 #include <usb/dev/poll.h> 53 #include <usb _iface.h>53 #include <usbhc_iface.h> 54 54 55 55 #include "usbhub.h" … … 58 58 #define HUB_FNC_NAME "hub" 59 59 60 /** Hub status-change endpoint description. 61 * 62 * For more information see section 11.15.1 of USB 1.1 specification. 63 */ 64 const usb_endpoint_description_t hub_status_change_endpoint_description = 65 { 66 .transfer_type = USB_TRANSFER_INTERRUPT, 67 .direction = USB_DIRECTION_IN, 68 .interface_class = USB_CLASS_HUB, 69 .interface_subclass = 0, 70 .interface_protocol = 0, 71 .flags = 0 60 #define HUB_STATUS_CHANGE_EP(protocol) { \ 61 .transfer_type = USB_TRANSFER_INTERRUPT, \ 62 .direction = USB_DIRECTION_IN, \ 63 .interface_class = USB_CLASS_HUB, \ 64 .interface_subclass = 0, \ 65 .interface_protocol = (protocol), \ 66 .flags = 0 \ 67 } 68 69 /** 70 * Hub status-change endpoint description. 71 * 72 * According to USB 2.0 specification, there are two possible arrangements of 73 * endpoints, depending on whether the hub has a MTT or not. 74 * 75 * Under any circumstances, there shall be exactly one endpoint descriptor. 76 * Though to be sure, let's map the protocol precisely. The possible 77 * combinations are: 78 * | bDeviceProtocol | bInterfaceProtocol 79 * Only single TT | 0 | 0 80 * MTT in Single-TT mode | 2 | 1 81 * MTT in MTT mode | 2 | 2 (iface alt. 1) 82 */ 83 static const usb_endpoint_description_t 84 status_change_single_tt_only = HUB_STATUS_CHANGE_EP(0), 85 status_change_mtt_available = HUB_STATUS_CHANGE_EP(1); 86 87 const usb_endpoint_description_t *usb_hub_endpoints [] = { 88 &status_change_single_tt_only, 89 &status_change_mtt_available, 72 90 }; 73 91 … … 81 99 }; 82 100 83 static errno_t usb_set_first_configuration(usb_device_t *usb_device); 84 static errno_t usb_hub_process_hub_specific_info(usb_hub_dev_t *hub_dev); 85 static void usb_hub_over_current(const usb_hub_dev_t *hub_dev, 86 usb_hub_status_t status); 87 static void usb_hub_global_interrupt(const usb_hub_dev_t *hub_dev); 88 static void usb_hub_polling_terminated_callback(usb_device_t *device, 89 bool was_error, void *data); 101 static errno_t usb_set_first_configuration(usb_device_t *); 102 static errno_t usb_hub_process_hub_specific_info(usb_hub_dev_t *); 103 static void usb_hub_over_current(const usb_hub_dev_t *, usb_hub_status_t); 104 static errno_t usb_hub_polling_init(usb_hub_dev_t *, usb_endpoint_mapping_t *); 105 static void usb_hub_global_interrupt(const usb_hub_dev_t *); 106 107 static bool usb_hub_polling_error_callback(usb_device_t *dev, 108 errno_t err_code, void *arg) 109 { 110 assert(dev); 111 assert(arg); 112 113 usb_log_error("Device %s polling error: %s", 114 usb_device_get_name(dev), str_error(err_code)); 115 116 return true; 117 } 90 118 91 119 /** … … 99 127 errno_t usb_hub_device_add(usb_device_t *usb_dev) 100 128 { 129 errno_t err; 101 130 assert(usb_dev); 131 102 132 /* Create driver soft-state structure */ 103 133 usb_hub_dev_t *hub_dev = 104 134 usb_device_data_alloc(usb_dev, sizeof(usb_hub_dev_t)); 105 135 if (hub_dev == NULL) { 106 usb_log_error("Failed to create hub driver structure. \n");136 usb_log_error("Failed to create hub driver structure."); 107 137 return ENOMEM; 108 138 } 109 139 hub_dev->usb_device = usb_dev; 110 hub_dev->pending_ops_count = 0; 111 hub_dev->running = false; 112 fibril_mutex_initialize(&hub_dev->pending_ops_mutex); 113 fibril_condvar_initialize(&hub_dev->pending_ops_cv); 140 hub_dev->speed = usb_device_get_speed(usb_dev); 114 141 115 142 /* Set hub's first configuration. (There should be only one) */ 116 errno_t opResult = usb_set_first_configuration(usb_dev); 117 if (opResult != EOK) { 118 usb_log_error("Could not set hub configuration: %s\n", 119 str_error(opResult)); 120 return opResult; 143 if ((err = usb_set_first_configuration(usb_dev))) { 144 usb_log_error("Could not set hub configuration: %s", str_error(err)); 145 return err; 121 146 } 122 147 123 148 /* Get port count and create attached_devices. */ 124 opResult = usb_hub_process_hub_specific_info(hub_dev); 125 if (opResult != EOK) { 126 usb_log_error("Could process hub specific info, %s\n", 127 str_error(opResult)); 128 return opResult; 149 if ((err = usb_hub_process_hub_specific_info(hub_dev))) { 150 usb_log_error("Could process hub specific info, %s", str_error(err)); 151 return err; 152 } 153 154 const usb_endpoint_description_t *status_change = hub_dev->mtt_available 155 ? &status_change_mtt_available 156 : &status_change_single_tt_only; 157 158 usb_endpoint_mapping_t *status_change_mapping 159 = usb_device_get_mapped_ep_desc(hub_dev->usb_device, status_change); 160 if (!status_change_mapping) { 161 usb_log_error("Failed to map the Status Change Endpoint of a hub."); 162 return EIO; 129 163 } 130 164 131 165 /* Create hub control function. */ 132 usb_log_debug("Creating DDF function '" HUB_FNC_NAME "'. \n");166 usb_log_debug("Creating DDF function '" HUB_FNC_NAME "'."); 133 167 hub_dev->hub_fun = usb_device_ddf_fun_create(hub_dev->usb_device, 134 168 fun_exposed, HUB_FNC_NAME); 135 169 if (hub_dev->hub_fun == NULL) { 136 usb_log_error("Failed to create hub function. \n");170 usb_log_error("Failed to create hub function."); 137 171 return ENOMEM; 138 172 } 139 173 140 174 /* Bind hub control function. */ 141 opResult = ddf_fun_bind(hub_dev->hub_fun); 142 if (opResult != EOK) { 143 usb_log_error("Failed to bind hub function: %s.\n", 144 str_error(opResult)); 145 ddf_fun_destroy(hub_dev->hub_fun); 146 return opResult; 175 if ((err = ddf_fun_bind(hub_dev->hub_fun))) { 176 usb_log_error("Failed to bind hub function: %s.", str_error(err)); 177 goto err_ddf_fun; 147 178 } 148 179 149 180 /* Start hub operation. */ 150 opResult = usb_device_auto_poll_desc(hub_dev->usb_device, 151 &hub_status_change_endpoint_description, 152 hub_port_changes_callback, ((hub_dev->port_count + 1 + 7) / 8), 153 -1, usb_hub_polling_terminated_callback, hub_dev); 154 if (opResult != EOK) { 155 /* Function is already bound */ 156 ddf_fun_unbind(hub_dev->hub_fun); 157 ddf_fun_destroy(hub_dev->hub_fun); 158 usb_log_error("Failed to create polling fibril: %s.\n", 159 str_error(opResult)); 160 return opResult; 161 } 162 hub_dev->running = true; 163 usb_log_info("Controlling hub '%s' (%p: %zu ports).\n", 181 if ((err = usb_hub_polling_init(hub_dev, status_change_mapping))) { 182 usb_log_error("Failed to start polling: %s.", str_error(err)); 183 goto err_bound; 184 } 185 186 usb_log_info("Controlling %s-speed hub '%s' (%p: %zu ports).", 187 usb_str_speed(hub_dev->speed), 164 188 usb_device_get_name(hub_dev->usb_device), hub_dev, 165 189 hub_dev->port_count); 166 190 167 191 return EOK; 168 } 169 170 /** 171 * Turn off power to all ports. 172 * 173 * @param usb_dev generic usb device information 174 * @return error code 175 */ 176 errno_t usb_hub_device_remove(usb_device_t *usb_dev) 177 { 178 return ENOTSUP; 179 } 180 181 /** 182 * Remove all attached devices 183 * @param usb_dev generic usb device information 184 * @return error code 185 */ 186 errno_t usb_hub_device_gone(usb_device_t *usb_dev) 187 { 188 assert(usb_dev); 189 usb_hub_dev_t *hub = usb_device_data_get(usb_dev); 190 assert(hub); 191 unsigned tries = 10; 192 while (hub->running) { 193 async_usleep(100000); 194 if (!tries--) { 195 usb_log_error("(%p): Can't remove hub, still running.", 196 hub); 197 return EBUSY; 198 } 199 } 200 201 assert(!hub->running); 192 193 err_bound: 194 ddf_fun_unbind(hub_dev->hub_fun); 195 err_ddf_fun: 196 ddf_fun_destroy(hub_dev->hub_fun); 197 return err; 198 } 199 200 static errno_t usb_hub_cleanup(usb_hub_dev_t *hub) 201 { 202 free(hub->polling.buffer); 203 usb_polling_fini(&hub->polling); 202 204 203 205 for (size_t port = 0; port < hub->port_count; ++port) { 204 const errno_t ret = usb_hub_port_fini(&hub->ports[port], hub); 205 if (ret != EOK) 206 return ret; 206 usb_port_fini(&hub->ports[port].base); 207 207 } 208 208 free(hub->ports); … … 217 217 218 218 usb_log_info("(%p) USB hub driver stopped and cleaned.", hub); 219 220 /* Device data (usb_hub_dev_t) will be freed by usbdev. */ 219 221 return EOK; 220 222 } 221 223 222 /** Callback for polling hub for changes. 224 /** 225 * Turn off power to all ports. 226 * 227 * @param usb_dev generic usb device information 228 * @return error code 229 */ 230 errno_t usb_hub_device_remove(usb_device_t *usb_dev) 231 { 232 assert(usb_dev); 233 usb_hub_dev_t *hub = usb_device_data_get(usb_dev); 234 assert(hub); 235 236 usb_log_info("(%p) USB hub removed, joining polling fibril.", hub); 237 238 /* Join polling fibril (ignoring error code). */ 239 usb_polling_join(&hub->polling); 240 usb_log_info("(%p) USB hub polling stopped, freeing memory.", hub); 241 242 /* Destroy hub. */ 243 return usb_hub_cleanup(hub); 244 } 245 246 /** 247 * Remove all attached devices 248 * @param usb_dev generic usb device information 249 * @return error code 250 */ 251 errno_t usb_hub_device_gone(usb_device_t *usb_dev) 252 { 253 assert(usb_dev); 254 usb_hub_dev_t *hub = usb_device_data_get(usb_dev); 255 assert(hub); 256 257 usb_log_info("(%p) USB hub gone, joining polling fibril.", hub); 258 259 /* Join polling fibril (ignoring error code). */ 260 usb_polling_join(&hub->polling); 261 usb_log_info("(%p) USB hub polling stopped, freeing memory.", hub); 262 263 /* Destroy hub. */ 264 return usb_hub_cleanup(hub); 265 } 266 267 /** 268 * Initialize and start the polling of the Status Change Endpoint. 269 * 270 * @param mapping The mapping of Status Change Endpoint 271 */ 272 static errno_t usb_hub_polling_init(usb_hub_dev_t *hub_dev, 273 usb_endpoint_mapping_t *mapping) 274 { 275 errno_t err; 276 usb_polling_t *polling = &hub_dev->polling; 277 278 if ((err = usb_polling_init(polling))) 279 return err; 280 281 polling->device = hub_dev->usb_device; 282 polling->ep_mapping = mapping; 283 polling->request_size = ((hub_dev->port_count + 1 + 7) / 8); 284 polling->buffer = malloc(polling->request_size); 285 polling->on_data = hub_port_changes_callback; 286 polling->on_error = usb_hub_polling_error_callback; 287 polling->arg = hub_dev; 288 289 if ((err = usb_polling_start(polling))) { 290 /* Polling is already initialized. */ 291 free(polling->buffer); 292 usb_polling_fini(polling); 293 return err; 294 } 295 296 return EOK; 297 } 298 299 /** 300 * Callback for polling hub for changes. 223 301 * 224 302 * @param dev Device where the change occured. … … 245 323 } 246 324 247 /* N + 1bit indicates change on port N */325 /* Nth bit indicates change on port N */ 248 326 for (size_t port = 0; port < hub->port_count; ++port) { 249 327 const size_t bit = port + 1; 250 328 const bool change = (change_bitmap[bit / 8] >> (bit % 8)) & 1; 251 329 if (change) { 252 usb_hub_port_process_interrupt(&hub->ports[port] , hub);330 usb_hub_port_process_interrupt(&hub->ports[port]); 253 331 } 254 332 } 255 333 return true; 334 } 335 336 static void usb_hub_power_ports(usb_hub_dev_t *hub_dev) 337 { 338 if (!hub_dev->power_switched) { 339 usb_log_info("(%p): Power switching not supported, " 340 "ports always powered.", hub_dev); 341 return; 342 } 343 344 usb_log_info("(%p): Hub port power switching enabled (%s).", hub_dev, 345 hub_dev->per_port_power ? "per port" : "ganged"); 346 347 for (unsigned int port = 0; port < hub_dev->port_count; ++port) { 348 usb_log_debug("(%p): Powering port %u.", hub_dev, port + 1); 349 const errno_t ret = usb_hub_set_port_feature(hub_dev, port + 1, 350 USB_HUB_FEATURE_PORT_POWER); 351 352 if (ret != EOK) { 353 usb_log_error("(%p-%u): Cannot power on port: %s.", 354 hub_dev, hub_dev->ports[port].port_number, 355 str_error(ret)); 356 /* Continue to try at least other ports */ 357 } 358 } 256 359 } 257 360 … … 270 373 assert(hub_dev); 271 374 375 usb_log_debug("(%p): Retrieving descriptor.", hub_dev); 376 usb_pipe_t *control_pipe = usb_device_get_default_pipe(hub_dev->usb_device); 377 378 usb_descriptor_type_t desc_type = hub_dev->speed >= USB_SPEED_SUPER 379 ? USB_DESCTYPE_SSPEED_HUB : USB_DESCTYPE_HUB; 380 272 381 /* Get hub descriptor. */ 273 usb_log_debug("(%p): Retrieving descriptor.", hub_dev);274 usb_pipe_t *control_pipe =275 usb_device_get_default_pipe(hub_dev->usb_device);276 277 382 usb_hub_descriptor_header_t descriptor; 278 383 size_t received_size; 279 384 errno_t opResult = usb_request_get_descriptor(control_pipe, 280 385 USB_REQUEST_TYPE_CLASS, USB_REQUEST_RECIPIENT_DEVICE, 281 USB_DESCTYPE_HUB, 0, 0, &descriptor,386 desc_type, 0, 0, &descriptor, 282 387 sizeof(usb_hub_descriptor_header_t), &received_size); 283 388 if (opResult != EOK) { 284 usb_log_error("(%p): Failed to receive hub descriptor: %s. \n",389 usb_log_error("(%p): Failed to receive hub descriptor: %s.", 285 390 hub_dev, str_error(opResult)); 286 391 return opResult; 287 392 } 288 393 289 usb_log_debug("(%p): Setting port count to %d. \n", hub_dev,394 usb_log_debug("(%p): Setting port count to %d.", hub_dev, 290 395 descriptor.port_count); 291 396 hub_dev->port_count = descriptor.port_count; 397 hub_dev->control_pipe = control_pipe; 398 399 usb_log_debug("(%p): Setting hub depth to %u.", hub_dev, 400 usb_device_get_depth(hub_dev->usb_device)); 401 if ((opResult = usb_hub_set_depth(hub_dev))) { 402 usb_log_error("(%p): Failed to set hub depth: %s.", 403 hub_dev, str_error(opResult)); 404 return opResult; 405 } 292 406 293 407 hub_dev->ports = calloc(hub_dev->port_count, sizeof(usb_hub_port_t)); … … 297 411 298 412 for (size_t port = 0; port < hub_dev->port_count; ++port) { 299 usb_hub_port_init( 300 &hub_dev->ports[port], port + 1, control_pipe); 413 usb_hub_port_init(&hub_dev->ports[port], hub_dev, port + 1); 301 414 } 302 415 … … 306 419 descriptor.characteristics & HUB_CHAR_POWER_PER_PORT_FLAG; 307 420 308 if (!hub_dev->power_switched) { 309 usb_log_info("(%p): Power switching not supported, " 310 "ports always powered.", hub_dev); 311 return EOK; 312 } 313 314 usb_log_info("(%p): Hub port power switching enabled (%s).\n", hub_dev, 315 hub_dev->per_port_power ? "per port" : "ganged"); 316 317 for (unsigned int port = 0; port < hub_dev->port_count; ++port) { 318 usb_log_debug("(%p): Powering port %u.", hub_dev, port); 319 const errno_t ret = usb_hub_port_set_feature( 320 &hub_dev->ports[port], USB_HUB_FEATURE_PORT_POWER); 321 322 if (ret != EOK) { 323 usb_log_error("(%p-%u): Cannot power on port: %s.\n", 324 hub_dev, hub_dev->ports[port].port_number, 325 str_error(ret)); 326 } else { 327 if (!hub_dev->per_port_power) { 328 usb_log_debug("(%p) Ganged power switching, " 329 "one port is enough.", hub_dev); 330 break; 331 } 332 } 333 } 421 const uint8_t protocol = usb_device_descriptors(hub_dev->usb_device) 422 ->device.device_protocol; 423 hub_dev->mtt_available = (protocol == 2); 424 425 usb_hub_power_ports(hub_dev); 426 334 427 return EOK; 335 428 } … … 349 442 const size_t configuration_count = 350 443 usb_device_descriptors(usb_device)->device.configuration_count; 351 usb_log_debug("Hub has %zu configurations. \n", configuration_count);444 usb_log_debug("Hub has %zu configurations.", configuration_count); 352 445 353 446 if (configuration_count < 1) { 354 usb_log_error("There are no configurations available \n");447 usb_log_error("There are no configurations available"); 355 448 return EINVAL; 356 449 } … … 369 462 /* Set configuration. Use the configuration that was in 370 463 * usb_device->descriptors.configuration i.e. The first one. */ 371 consterrno_t opResult = usb_request_set_configuration(464 errno_t opResult = usb_request_set_configuration( 372 465 usb_device_get_default_pipe(usb_device), 373 466 config_descriptor->configuration_number); 374 467 if (opResult != EOK) { 375 usb_log_error("Failed to set hub configuration: %s. \n",468 usb_log_error("Failed to set hub configuration: %s.", 376 469 str_error(opResult)); 377 470 } else { 378 usb_log_debug("\tUsed configuration %d \n",471 usb_log_debug("\tUsed configuration %d", 379 472 config_descriptor->configuration_number); 380 473 } 474 381 475 return opResult; 382 476 } … … 406 500 /* Over-current condition is gone, it is safe to turn the ports on. */ 407 501 for (size_t port = 0; port < hub_dev->port_count; ++port) { 408 const errno_t ret = usb_hub_ port_set_feature(409 &hub_dev->ports[port],USB_HUB_FEATURE_PORT_POWER);502 const errno_t ret = usb_hub_set_port_feature(hub_dev, port, 503 USB_HUB_FEATURE_PORT_POWER); 410 504 if (ret != EOK) { 411 505 usb_log_warning("(%p-%u): HUB OVER-CURRENT GONE: Cannot" … … 417 511 } 418 512 } 419 513 } 514 515 /** 516 * Set feature on the real hub port. 517 * 518 * @param port Port structure. 519 * @param feature Feature selector. 520 */ 521 errno_t usb_hub_set_depth(const usb_hub_dev_t *hub) 522 { 523 assert(hub); 524 525 /* Slower hubs do not care about depth */ 526 if (hub->speed < USB_SPEED_SUPER) 527 return EOK; 528 529 const usb_device_request_setup_packet_t set_request = { 530 .request_type = USB_HUB_REQ_TYPE_SET_HUB_DEPTH, 531 .request = USB_HUB_REQUEST_SET_HUB_DEPTH, 532 .value = uint16_host2usb(usb_device_get_depth(hub->usb_device) - 1), 533 .index = 0, 534 .length = 0, 535 }; 536 return usb_pipe_control_write(hub->control_pipe, &set_request, 537 sizeof(set_request), NULL, 0); 538 } 539 540 /** 541 * Set feature on the real hub port. 542 * 543 * @param port Port structure. 544 * @param feature Feature selector. 545 */ 546 errno_t usb_hub_set_port_feature(const usb_hub_dev_t *hub, size_t port_number, 547 usb_hub_class_feature_t feature) 548 { 549 assert(hub); 550 const usb_device_request_setup_packet_t clear_request = { 551 .request_type = USB_HUB_REQ_TYPE_SET_PORT_FEATURE, 552 .request = USB_DEVREQ_SET_FEATURE, 553 .index = uint16_host2usb(port_number), 554 .value = feature, 555 .length = 0, 556 }; 557 return usb_pipe_control_write(hub->control_pipe, &clear_request, 558 sizeof(clear_request), NULL, 0); 559 } 560 561 /** 562 * Clear feature on the real hub port. 563 * 564 * @param port Port structure. 565 * @param feature Feature selector. 566 */ 567 errno_t usb_hub_clear_port_feature(const usb_hub_dev_t *hub, size_t port_number, 568 usb_hub_class_feature_t feature) 569 { 570 assert(hub); 571 const usb_device_request_setup_packet_t clear_request = { 572 .request_type = USB_HUB_REQ_TYPE_CLEAR_PORT_FEATURE, 573 .request = USB_DEVREQ_CLEAR_FEATURE, 574 .value = feature, 575 .index = uint16_host2usb(port_number), 576 .length = 0, 577 }; 578 return usb_pipe_control_write(hub->control_pipe, 579 &clear_request, sizeof(clear_request), NULL, 0); 580 } 581 582 /** 583 * Retrieve port status. 584 * 585 * @param[in] port Port structure 586 * @param[out] status Where to store the port status. 587 * @return Error code. 588 */ 589 errno_t usb_hub_get_port_status(const usb_hub_dev_t *hub, size_t port_number, 590 usb_port_status_t *status) 591 { 592 assert(hub); 593 assert(status); 594 595 /* USB hub specific GET_PORT_STATUS request. See USB Spec 11.16.2.6 596 * Generic GET_STATUS request cannot be used because of the difference 597 * in status data size (2B vs. 4B)*/ 598 const usb_device_request_setup_packet_t request = { 599 .request_type = USB_HUB_REQ_TYPE_GET_PORT_STATUS, 600 .request = USB_HUB_REQUEST_GET_STATUS, 601 .value = 0, 602 .index = uint16_host2usb(port_number), 603 .length = sizeof(usb_port_status_t), 604 }; 605 size_t recv_size; 606 607 uint32_t buffer; 608 const errno_t rc = usb_pipe_control_read(hub->control_pipe, 609 &request, sizeof(usb_device_request_setup_packet_t), 610 &buffer, sizeof(buffer), &recv_size); 611 if (rc != EOK) 612 return rc; 613 614 if (recv_size != sizeof(*status)) 615 return ELIMIT; 616 617 *status = uint32_usb2host(buffer); 618 return EOK; 420 619 } 421 620 … … 492 691 493 692 /** 494 * callback called from hub polling fibril when the fibril terminates 495 * 496 * Does not perform cleanup, just marks the hub as not running. 497 * @param device usb device afected 498 * @param was_error indicates that the fibril is stoped due to an error 499 * @param data pointer to usb_hub_dev_t structure 500 */ 501 static void usb_hub_polling_terminated_callback(usb_device_t *device, 502 bool was_error, void *data) 503 { 504 usb_hub_dev_t *hub = data; 693 * Instead of just sleeping, we may as well sleep on a condition variable. 694 * This has the advantage that we may instantly wait other hub from the polling 695 * sleep, mitigating the delay of polling while still being synchronized with 696 * other devices in need of the default address (there shall not be any). 697 */ 698 static FIBRIL_CONDVAR_INITIALIZE(global_hub_default_address_cv); 699 static FIBRIL_MUTEX_INITIALIZE(global_hub_default_address_guard); 700 701 /** 702 * Reserve a default address for a port across all other devices connected to 703 * the bus. We aggregate requests for ports to minimize delays between 704 * connecting multiple devices from one hub - which happens e.g. when the hub 705 * is connected with already attached devices. 706 */ 707 errno_t usb_hub_reserve_default_address(usb_hub_dev_t *hub, async_exch_t *exch, 708 usb_port_t *port) 709 { 505 710 assert(hub); 506 507 fibril_mutex_lock(&hub->pending_ops_mutex); 508 509 /* The device is dead. However there might be some pending operations 510 * that we need to wait for. 511 * One of them is device adding in progress. 512 * The respective fibril is probably waiting for status change 513 * in port reset (port enable) callback. 514 * Such change would never come (otherwise we would not be here). 515 * Thus, we would flush all pending port resets. 711 assert(exch); 712 assert(port); 713 assert(fibril_mutex_is_locked(&port->guard)); 714 715 errno_t err = usbhc_reserve_default_address(exch); 716 /* 717 * EINVAL signalls that its our hub (hopefully different port) that has 718 * this address reserved 516 719 */ 517 if (hub->pending_ops_count > 0) { 518 for (size_t port = 0; port < hub->port_count; ++port) { 519 usb_hub_port_reset_fail(&hub->ports[port]); 520 } 521 } 522 /* And now wait for them. */ 523 while (hub->pending_ops_count > 0) { 524 fibril_condvar_wait(&hub->pending_ops_cv, 525 &hub->pending_ops_mutex); 526 } 527 fibril_mutex_unlock(&hub->pending_ops_mutex); 528 hub->running = false; 529 } 720 while (err == EAGAIN || err == EINVAL) { 721 /* Drop the port guard, we're going to wait */ 722 fibril_mutex_unlock(&port->guard); 723 724 /* This sleeping might be disturbed by other hub */ 725 fibril_mutex_lock(&global_hub_default_address_guard); 726 fibril_condvar_wait_timeout(&global_hub_default_address_cv, 727 &global_hub_default_address_guard, 2000000); 728 fibril_mutex_unlock(&global_hub_default_address_guard); 729 730 fibril_mutex_lock(&port->guard); 731 err = usbhc_reserve_default_address(exch); 732 } 733 734 if (err) 735 return err; 736 737 /* 738 * As we dropped the port guard, we need to check whether the device is 739 * still connected. If the release fails, we still hold the default 740 * address -- but then there is probably a bigger problem with the HC 741 * anyway. 742 */ 743 if (port->state != PORT_CONNECTING) { 744 err = usb_hub_release_default_address(hub, exch); 745 return err ? err : EINTR; 746 } 747 748 return EOK; 749 } 750 751 /** 752 * Release the default address from a port. 753 */ 754 errno_t usb_hub_release_default_address(usb_hub_dev_t *hub, async_exch_t *exch) 755 { 756 const errno_t ret = usbhc_release_default_address(exch); 757 758 /* 759 * This is an optimistic optimization - it may wake 760 * one hub from polling sleep instantly. 761 */ 762 fibril_condvar_signal(&global_hub_default_address_cv); 763 764 return ret; 765 } 766 530 767 /** 531 768 * @}
Note:
See TracChangeset
for help on using the changeset viewer.