Changeset c4e84ed6 in mainline for uspace/drv/bus/usb/usbhub/usbhub.c
- Timestamp:
- 2018-01-16T03:45:38Z (7 years ago)
- Branches:
- lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
- Children:
- c952abc4
- Parents:
- d2c3dcd
- git-author:
- Ondřej Hlavatý <aearsis@…> (2018-01-15 20:49:15)
- git-committer:
- Ondřej Hlavatý <aearsis@…> (2018-01-16 03:45:38)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
uspace/drv/bus/usb/usbhub/usbhub.c
rd2c3dcd rc4e84ed6 86 86 usb_hub_status_t status); 87 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);90 88 91 89 static bool usb_hub_polling_error_callback(usb_device_t *dev, int err_code, void *arg) … … 93 91 assert(dev); 94 92 assert(arg); 95 usb_hub_dev_t *hub = arg; 96 97 usb_log_error("Device %s polling error: %s", usb_device_get_name(dev), 98 str_error(err_code)); 99 100 /* Continue polling until the device is about to be removed. */ 101 return hub->running; 93 94 usb_log_error("Device %s polling error: %s", usb_device_get_name(dev), str_error(err_code)); 95 96 return true; 102 97 } 103 98 … … 121 116 } 122 117 hub_dev->usb_device = usb_dev; 123 hub_dev->pending_ops_count = 0;124 hub_dev->running = false;125 fibril_mutex_initialize(&hub_dev->pending_ops_mutex);126 fibril_condvar_initialize(&hub_dev->pending_ops_cv);127 118 128 119 /* Set hub's first configuration. (There should be only one) */ … … 178 169 polling->buffer = malloc(polling->request_size); 179 170 polling->on_data = hub_port_changes_callback; 180 polling->on_polling_end = usb_hub_polling_terminated_callback;181 171 polling->on_error = usb_hub_polling_error_callback; 182 172 polling->arg = hub_dev; … … 194 184 } 195 185 196 hub_dev->running = true;197 186 usb_log_info("Controlling hub '%s' (%p: %zu ports).", 198 187 usb_device_get_name(hub_dev->usb_device), hub_dev, … … 204 193 static int usb_hub_cleanup(usb_hub_dev_t *hub) 205 194 { 206 assert(!hub->running);207 208 195 free(hub->polling.buffer); 209 196 usb_polling_fini(&hub->polling); 210 197 211 198 for (size_t port = 0; port < hub->port_count; ++port) { 212 const int ret = usb_hub_port_fini(&hub->ports[port], hub); 213 if (ret != EOK) 214 return ret; 199 usb_hub_port_fini(&hub->ports[port]); 215 200 } 216 201 free(hub->ports); … … 343 328 descriptor.port_count); 344 329 hub_dev->port_count = descriptor.port_count; 330 hub_dev->control_pipe = control_pipe; 345 331 346 332 hub_dev->ports = calloc(hub_dev->port_count, sizeof(usb_hub_port_t)); … … 350 336 351 337 for (size_t port = 0; port < hub_dev->port_count; ++port) { 352 usb_hub_port_init( 353 &hub_dev->ports[port], port + 1, control_pipe); 338 usb_hub_port_init(&hub_dev->ports[port], hub_dev, port + 1); 354 339 } 355 340 … … 370 355 for (unsigned int port = 0; port < hub_dev->port_count; ++port) { 371 356 usb_log_debug("(%p): Powering port %u.", hub_dev, port); 372 const int ret = usb_hub_port_set_feature( 373 &hub_dev->ports[port], USB_HUB_FEATURE_PORT_POWER); 357 const int ret = usb_hub_set_port_feature(hub_dev, port, USB_HUB_FEATURE_PORT_POWER); 374 358 375 359 if (ret != EOK) { … … 459 443 /* Over-current condition is gone, it is safe to turn the ports on. */ 460 444 for (size_t port = 0; port < hub_dev->port_count; ++port) { 461 const int ret = usb_hub_port_set_feature( 462 &hub_dev->ports[port], USB_HUB_FEATURE_PORT_POWER); 445 const int ret = usb_hub_set_port_feature(hub_dev, port, USB_HUB_FEATURE_PORT_POWER); 463 446 if (ret != EOK) { 464 447 usb_log_warning("(%p-%u): HUB OVER-CURRENT GONE: Cannot" … … 470 453 } 471 454 } 472 455 } 456 457 /** 458 * Set feature on the real hub port. 459 * 460 * @param port Port structure. 461 * @param feature Feature selector. 462 */ 463 int usb_hub_set_port_feature(const usb_hub_dev_t *hub, size_t port_number, usb_hub_class_feature_t feature) 464 { 465 assert(hub); 466 const usb_device_request_setup_packet_t clear_request = { 467 .request_type = USB_HUB_REQ_TYPE_SET_PORT_FEATURE, 468 .request = USB_DEVREQ_SET_FEATURE, 469 .index = uint16_host2usb(port_number), 470 .value = feature, 471 .length = 0, 472 }; 473 return usb_pipe_control_write(hub->control_pipe, &clear_request, 474 sizeof(clear_request), NULL, 0); 475 } 476 477 /** 478 * Clear feature on the real hub port. 479 * 480 * @param port Port structure. 481 * @param feature Feature selector. 482 */ 483 int usb_hub_clear_port_feature(const usb_hub_dev_t *hub, size_t port_number, usb_hub_class_feature_t feature) 484 { 485 assert(hub); 486 const usb_device_request_setup_packet_t clear_request = { 487 .request_type = USB_HUB_REQ_TYPE_CLEAR_PORT_FEATURE, 488 .request = USB_DEVREQ_CLEAR_FEATURE, 489 .value = feature, 490 .index = uint16_host2usb(port_number), 491 .length = 0, 492 }; 493 return usb_pipe_control_write(hub->control_pipe, 494 &clear_request, sizeof(clear_request), NULL, 0); 495 } 496 497 /** 498 * Retrieve port status. 499 * 500 * @param[in] port Port structure 501 * @param[out] status Where to store the port status. 502 * @return Error code. 503 */ 504 int usb_hub_get_port_status(const usb_hub_dev_t *hub, size_t port_number, usb_port_status_t *status) 505 { 506 assert(hub); 507 assert(status); 508 509 /* USB hub specific GET_PORT_STATUS request. See USB Spec 11.16.2.6 510 * Generic GET_STATUS request cannot be used because of the difference 511 * in status data size (2B vs. 4B)*/ 512 const usb_device_request_setup_packet_t request = { 513 .request_type = USB_HUB_REQ_TYPE_GET_PORT_STATUS, 514 .request = USB_HUB_REQUEST_GET_STATUS, 515 .value = 0, 516 .index = uint16_host2usb(port_number), 517 .length = sizeof(usb_port_status_t), 518 }; 519 size_t recv_size; 520 521 const int rc = usb_pipe_control_read(hub->control_pipe, 522 &request, sizeof(usb_device_request_setup_packet_t), 523 status, sizeof(*status), &recv_size); 524 if (rc != EOK) 525 return rc; 526 527 if (recv_size != sizeof(*status)) 528 return ELIMIT; 529 530 return EOK; 473 531 } 474 532 … … 545 603 546 604 /** 547 * callback called from hub polling fibril when the fibril terminates548 *549 * Does not perform cleanup, just marks the hub as not running.550 * @param device usb device afected551 * @param was_error indicates that the fibril is stoped due to an error552 * @param data pointer to usb_hub_dev_t structure553 */554 static void usb_hub_polling_terminated_callback(usb_device_t *device,555 bool was_error, void *data)556 {557 usb_hub_dev_t *hub = data;558 assert(hub);559 560 fibril_mutex_lock(&hub->pending_ops_mutex);561 562 /* The device is dead. However there might be some pending operations563 * that we need to wait for.564 * One of them is device adding in progress.565 * The respective fibril is probably waiting for status change566 * in port reset (port enable) callback.567 * Such change would never come (otherwise we would not be here).568 * Thus, we would flush all pending port resets.569 */570 if (hub->pending_ops_count > 0) {571 for (size_t port = 0; port < hub->port_count; ++port) {572 usb_hub_port_reset_fail(&hub->ports[port]);573 }574 }575 /* And now wait for them. */576 while (hub->pending_ops_count > 0) {577 fibril_condvar_wait(&hub->pending_ops_cv,578 &hub->pending_ops_mutex);579 }580 fibril_mutex_unlock(&hub->pending_ops_mutex);581 hub->running = false;582 }583 584 /**585 605 * @} 586 606 */
Note:
See TracChangeset
for help on using the changeset viewer.