Changes in uspace/drv/bus/usb/usbhub/usbhub.c [34d750c:58563585] in mainline
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
uspace/drv/bus/usb/usbhub/usbhub.c
r34d750c r58563585 51 51 #include <usb/classes/hub.h> 52 52 #include <usb/dev/poll.h> 53 #include <usb hc_iface.h>53 #include <usb_iface.h> 54 54 55 55 #include "usbhub.h" … … 58 58 #define HUB_FNC_NAME "hub" 59 59 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, 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 90 72 }; 91 73 … … 99 81 }; 100 82 101 static int usb_set_first_configuration(usb_device_t *); 102 static int 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 int 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 int 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 } 83 static int usb_set_first_configuration(usb_device_t *usb_device); 84 static int 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); 118 90 119 91 /** … … 127 99 int usb_hub_device_add(usb_device_t *usb_dev) 128 100 { 129 int err;130 101 assert(usb_dev); 131 132 102 /* Create driver soft-state structure */ 133 103 usb_hub_dev_t *hub_dev = 134 104 usb_device_data_alloc(usb_dev, sizeof(usb_hub_dev_t)); 135 105 if (hub_dev == NULL) { 136 usb_log_error("Failed to create hub driver structure. ");106 usb_log_error("Failed to create hub driver structure.\n"); 137 107 return ENOMEM; 138 108 } 139 109 hub_dev->usb_device = usb_dev; 140 hub_dev->speed = usb_device_get_speed(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); 141 114 142 115 /* Set hub's first configuration. (There should be only one) */ 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; 116 int 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; 146 121 } 147 122 148 123 /* Get port count and create attached_devices. */ 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; 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; 163 129 } 164 130 165 131 /* Create hub control function. */ 166 usb_log_debug("Creating DDF function '" HUB_FNC_NAME "'. ");132 usb_log_debug("Creating DDF function '" HUB_FNC_NAME "'.\n"); 167 133 hub_dev->hub_fun = usb_device_ddf_fun_create(hub_dev->usb_device, 168 134 fun_exposed, HUB_FNC_NAME); 169 135 if (hub_dev->hub_fun == NULL) { 170 usb_log_error("Failed to create hub function. ");136 usb_log_error("Failed to create hub function.\n"); 171 137 return ENOMEM; 172 138 } 173 139 174 140 /* Bind hub control function. */ 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; 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; 178 147 } 179 148 180 149 /* Start hub operation. */ 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), 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", 188 164 usb_device_get_name(hub_dev->usb_device), hub_dev, 189 165 hub_dev->port_count); 190 166 191 167 return EOK; 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 int usb_hub_cleanup(usb_hub_dev_t *hub) 201 { 202 free(hub->polling.buffer); 203 usb_polling_fini(&hub->polling); 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 int 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 int 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); 204 202 205 203 for (size_t port = 0; port < hub->port_count; ++port) { 206 usb_port_fini(&hub->ports[port].base); 204 const int ret = usb_hub_port_fini(&hub->ports[port], hub); 205 if (ret != EOK) 206 return ret; 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. */221 219 return EOK; 222 220 } 223 221 224 /** 225 * Turn off power to all ports. 226 * 227 * @param usb_dev generic usb device information 228 * @return error code 229 */ 230 int 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 int 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 int usb_hub_polling_init(usb_hub_dev_t *hub_dev, 273 usb_endpoint_mapping_t *mapping) 274 { 275 int 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. 222 /** Callback for polling hub for changes. 301 223 * 302 224 * @param dev Device where the change occured. … … 323 245 } 324 246 325 /* N thbit indicates change on port N */247 /* N + 1 bit indicates change on port N */ 326 248 for (size_t port = 0; port < hub->port_count; ++port) { 327 249 const size_t bit = port + 1; 328 250 const bool change = (change_bitmap[bit / 8] >> (bit % 8)) & 1; 329 251 if (change) { 330 usb_hub_port_process_interrupt(&hub->ports[port] );252 usb_hub_port_process_interrupt(&hub->ports[port], hub); 331 253 } 332 254 } 333 255 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 int 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 }359 256 } 360 257 … … 373 270 assert(hub_dev); 374 271 272 /* Get hub descriptor. */ 375 273 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 381 /* Get hub descriptor. */ 274 usb_pipe_t *control_pipe = 275 usb_device_get_default_pipe(hub_dev->usb_device); 276 382 277 usb_hub_descriptor_header_t descriptor; 383 278 size_t received_size; 384 279 int opResult = usb_request_get_descriptor(control_pipe, 385 280 USB_REQUEST_TYPE_CLASS, USB_REQUEST_RECIPIENT_DEVICE, 386 desc_type, 0, 0, &descriptor,281 USB_DESCTYPE_HUB, 0, 0, &descriptor, 387 282 sizeof(usb_hub_descriptor_header_t), &received_size); 388 283 if (opResult != EOK) { 389 usb_log_error("(%p): Failed to receive hub descriptor: %s. ",284 usb_log_error("(%p): Failed to receive hub descriptor: %s.\n", 390 285 hub_dev, str_error(opResult)); 391 286 return opResult; 392 287 } 393 288 394 usb_log_debug("(%p): Setting port count to %d. ", hub_dev,289 usb_log_debug("(%p): Setting port count to %d.\n", hub_dev, 395 290 descriptor.port_count); 396 291 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 }406 292 407 293 hub_dev->ports = calloc(hub_dev->port_count, sizeof(usb_hub_port_t)); … … 411 297 412 298 for (size_t port = 0; port < hub_dev->port_count; ++port) { 413 usb_hub_port_init(&hub_dev->ports[port], hub_dev, port + 1); 299 usb_hub_port_init( 300 &hub_dev->ports[port], port + 1, control_pipe); 414 301 } 415 302 … … 419 306 descriptor.characteristics & HUB_CHAR_POWER_PER_PORT_FLAG; 420 307 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 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 int 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 } 427 334 return EOK; 428 335 } … … 442 349 const size_t configuration_count = 443 350 usb_device_descriptors(usb_device)->device.configuration_count; 444 usb_log_debug("Hub has %zu configurations. ", configuration_count);351 usb_log_debug("Hub has %zu configurations.\n", configuration_count); 445 352 446 353 if (configuration_count < 1) { 447 usb_log_error("There are no configurations available ");354 usb_log_error("There are no configurations available\n"); 448 355 return EINVAL; 449 356 } … … 462 369 /* Set configuration. Use the configuration that was in 463 370 * usb_device->descriptors.configuration i.e. The first one. */ 464 int opResult = usb_request_set_configuration(371 const int opResult = usb_request_set_configuration( 465 372 usb_device_get_default_pipe(usb_device), 466 373 config_descriptor->configuration_number); 467 374 if (opResult != EOK) { 468 usb_log_error("Failed to set hub configuration: %s. ",375 usb_log_error("Failed to set hub configuration: %s.\n", 469 376 str_error(opResult)); 470 377 } else { 471 usb_log_debug("\tUsed configuration %d ",378 usb_log_debug("\tUsed configuration %d\n", 472 379 config_descriptor->configuration_number); 473 380 } 474 475 381 return opResult; 476 382 } … … 500 406 /* Over-current condition is gone, it is safe to turn the ports on. */ 501 407 for (size_t port = 0; port < hub_dev->port_count; ++port) { 502 const int ret = usb_hub_ set_port_feature(hub_dev, port,503 USB_HUB_FEATURE_PORT_POWER);408 const int ret = usb_hub_port_set_feature( 409 &hub_dev->ports[port], USB_HUB_FEATURE_PORT_POWER); 504 410 if (ret != EOK) { 505 411 usb_log_warning("(%p-%u): HUB OVER-CURRENT GONE: Cannot" … … 511 417 } 512 418 } 513 } 514 515 /** 516 * Set feature on the real hub port. 517 * 518 * @param port Port structure. 519 * @param feature Feature selector. 520 */ 521 int 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 int 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 int 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 int 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 int 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; 419 619 420 } 620 421 … … 691 492 692 493 /** 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 int usb_hub_reserve_default_address(usb_hub_dev_t *hub, async_exch_t *exch, 708 usb_port_t *port) 709 { 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; 710 505 assert(hub); 711 assert(exch); 712 assert(port); 713 assert(fibril_mutex_is_locked(&port->guard)); 714 715 int err = usbhc_reserve_default_address(exch); 716 /* 717 * EINVAL signalls that its our hub (hopefully different port) that has 718 * this address reserved 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. 719 516 */ 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 int usb_hub_release_default_address(usb_hub_dev_t *hub, async_exch_t *exch) 755 { 756 const int 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 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 } 767 530 /** 768 531 * @}
Note:
See TracChangeset
for help on using the changeset viewer.