Changes in uspace/drv/bus/usb/usbhub/usbhub.c [e0a5d4c:b7fd2a0] in mainline
- File:
-
- 1 edited
-
uspace/drv/bus/usb/usbhub/usbhub.c (modified) (15 diffs)
Legend:
- Unmodified
- Added
- Removed
-
uspace/drv/bus/usb/usbhub/usbhub.c
re0a5d4c rb7fd2a0 2 2 * Copyright (c) 2010 Matus Dekanek 3 3 * Copyright (c) 2011 Jan Vesely 4 * Copyright (c) 2018 Ondrej Hlavaty, Petr Manek5 4 * All rights reserved. 6 5 * … … 52 51 #include <usb/classes/hub.h> 53 52 #include <usb/dev/poll.h> 54 #include <usb hc_iface.h>53 #include <usb_iface.h> 55 54 56 55 #include "usbhub.h" … … 59 58 #define HUB_FNC_NAME "hub" 60 59 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, 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 91 72 }; 92 73 … … 100 81 }; 101 82 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 } 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); 119 90 120 91 /** … … 128 99 errno_t usb_hub_device_add(usb_device_t *usb_dev) 129 100 { 130 errno_t err;131 101 assert(usb_dev); 132 133 102 /* Create driver soft-state structure */ 134 103 usb_hub_dev_t *hub_dev = 135 104 usb_device_data_alloc(usb_dev, sizeof(usb_hub_dev_t)); 136 105 if (hub_dev == NULL) { 137 usb_log_error("Failed to create hub driver structure. ");106 usb_log_error("Failed to create hub driver structure.\n"); 138 107 return ENOMEM; 139 108 } 140 109 hub_dev->usb_device = usb_dev; 141 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); 142 114 143 115 /* Set hub's first configuration. (There should be only one) */ 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; 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; 147 121 } 148 122 149 123 /* Get port count and create attached_devices. */ 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; 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; 164 129 } 165 130 166 131 /* Create hub control function. */ 167 usb_log_debug("Creating DDF function '" HUB_FNC_NAME "'. ");132 usb_log_debug("Creating DDF function '" HUB_FNC_NAME "'.\n"); 168 133 hub_dev->hub_fun = usb_device_ddf_fun_create(hub_dev->usb_device, 169 134 fun_exposed, HUB_FNC_NAME); 170 135 if (hub_dev->hub_fun == NULL) { 171 usb_log_error("Failed to create hub function. ");136 usb_log_error("Failed to create hub function.\n"); 172 137 return ENOMEM; 173 138 } 174 139 175 140 /* Bind hub control function. */ 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; 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; 179 147 } 180 148 181 149 /* Start hub operation. */ 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), 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", 189 164 usb_device_get_name(hub_dev->usb_device), hub_dev, 190 165 hub_dev->port_count); 191 166 192 167 return EOK; 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); 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); 205 202 206 203 for (size_t port = 0; port < hub->port_count; ++port) { 207 usb_port_fini(&hub->ports[port].base); 204 const errno_t ret = usb_hub_port_fini(&hub->ports[port], hub); 205 if (ret != EOK) 206 return ret; 208 207 } 209 208 free(hub->ports); … … 218 217 219 218 usb_log_info("(%p) USB hub driver stopped and cleaned.", hub); 220 221 /* Device data (usb_hub_dev_t) will be freed by usbdev. */222 219 return EOK; 223 220 } 224 221 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. 222 /** Callback for polling hub for changes. 302 223 * 303 224 * @param dev Device where the change occured. … … 324 245 } 325 246 326 /* N thbit indicates change on port N */247 /* N + 1 bit indicates change on port N */ 327 248 for (size_t port = 0; port < hub->port_count; ++port) { 328 249 const size_t bit = port + 1; 329 250 const bool change = (change_bitmap[bit / 8] >> (bit % 8)) & 1; 330 251 if (change) { 331 usb_hub_port_process_interrupt(&hub->ports[port] );252 usb_hub_port_process_interrupt(&hub->ports[port], hub); 332 253 } 333 254 } 334 255 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 }360 256 } 361 257 … … 374 270 assert(hub_dev); 375 271 272 /* Get hub descriptor. */ 376 273 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 382 /* Get hub descriptor. */ 274 usb_pipe_t *control_pipe = 275 usb_device_get_default_pipe(hub_dev->usb_device); 276 383 277 usb_hub_descriptor_header_t descriptor; 384 278 size_t received_size; 385 279 errno_t opResult = usb_request_get_descriptor(control_pipe, 386 280 USB_REQUEST_TYPE_CLASS, USB_REQUEST_RECIPIENT_DEVICE, 387 desc_type, 0, 0, &descriptor,281 USB_DESCTYPE_HUB, 0, 0, &descriptor, 388 282 sizeof(usb_hub_descriptor_header_t), &received_size); 389 283 if (opResult != EOK) { 390 usb_log_error("(%p): Failed to receive hub descriptor: %s. ",284 usb_log_error("(%p): Failed to receive hub descriptor: %s.\n", 391 285 hub_dev, str_error(opResult)); 392 286 return opResult; 393 287 } 394 288 395 usb_log_debug("(%p): Setting port count to %d. ", hub_dev,289 usb_log_debug("(%p): Setting port count to %d.\n", hub_dev, 396 290 descriptor.port_count); 397 291 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 }407 292 408 293 hub_dev->ports = calloc(hub_dev->port_count, sizeof(usb_hub_port_t)); … … 412 297 413 298 for (size_t port = 0; port < hub_dev->port_count; ++port) { 414 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); 415 301 } 416 302 … … 420 306 descriptor.characteristics & HUB_CHAR_POWER_PER_PORT_FLAG; 421 307 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 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 } 428 334 return EOK; 429 335 } … … 443 349 const size_t configuration_count = 444 350 usb_device_descriptors(usb_device)->device.configuration_count; 445 usb_log_debug("Hub has %zu configurations. ", configuration_count);351 usb_log_debug("Hub has %zu configurations.\n", configuration_count); 446 352 447 353 if (configuration_count < 1) { 448 usb_log_error("There are no configurations available ");354 usb_log_error("There are no configurations available\n"); 449 355 return EINVAL; 450 356 } … … 463 369 /* Set configuration. Use the configuration that was in 464 370 * usb_device->descriptors.configuration i.e. The first one. */ 465 errno_t opResult = usb_request_set_configuration(371 const errno_t opResult = usb_request_set_configuration( 466 372 usb_device_get_default_pipe(usb_device), 467 373 config_descriptor->configuration_number); 468 374 if (opResult != EOK) { 469 usb_log_error("Failed to set hub configuration: %s. ",375 usb_log_error("Failed to set hub configuration: %s.\n", 470 376 str_error(opResult)); 471 377 } else { 472 usb_log_debug("\tUsed configuration %d ",378 usb_log_debug("\tUsed configuration %d\n", 473 379 config_descriptor->configuration_number); 474 380 } 475 476 381 return opResult; 477 382 } … … 501 406 /* Over-current condition is gone, it is safe to turn the ports on. */ 502 407 for (size_t port = 0; port < hub_dev->port_count; ++port) { 503 const errno_t ret = usb_hub_ set_port_feature(hub_dev, port,504 USB_HUB_FEATURE_PORT_POWER);408 const errno_t ret = usb_hub_port_set_feature( 409 &hub_dev->ports[port], USB_HUB_FEATURE_PORT_POWER); 505 410 if (ret != EOK) { 506 411 usb_log_warning("(%p-%u): HUB OVER-CURRENT GONE: Cannot" … … 512 417 } 513 418 } 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; 419 620 420 } 621 421 … … 692 492 693 493 /** 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 { 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; 711 505 assert(hub); 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 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. 720 516 */ 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 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 } 768 530 /** 769 531 * @}
Note:
See TracChangeset
for help on using the changeset viewer.
