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