Changeset 54d1ad9 in mainline
- Timestamp:
- 2011-10-30T13:50:07Z (13 years ago)
- Branches:
- lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
- Children:
- e978ada
- Parents:
- fbe148ee
- Location:
- uspace/drv/bus/usb/usbhub
- Files:
-
- 4 edited
Legend:
- Unmodified
- Added
- Removed
-
uspace/drv/bus/usb/usbhub/main.c
rfbe148ee r54d1ad9 47 47 * For more information see section 11.15.1 of USB 1.1 specification. 48 48 */ 49 static usb_endpoint_description_t hub_status_change_endpoint_description = { 49 static const usb_endpoint_description_t hub_status_change_endpoint_description = 50 { 50 51 .transfer_type = USB_TRANSFER_INTERRUPT, 51 52 .direction = USB_DIRECTION_IN, … … 56 57 }; 57 58 58 /** 59 * USB hub driver operations 60 * 61 * The most important one is device_add, which is set to usb_hub_device_add. 62 */ 63 static usb_driver_ops_t usb_hub_driver_ops = { 59 /** USB hub driver operations. */ 60 static const usb_driver_ops_t usb_hub_driver_ops = { 64 61 .device_add = usb_hub_device_add, 62 // .device_rem = usb_hub_device_remove, 65 63 .device_gone = usb_hub_device_gone, 66 64 }; … … 72 70 }; 73 71 /** Static usb hub driver information. */ 74 static usb_driver_t usb_hub_driver = {72 static const usb_driver_t usb_hub_driver = { 75 73 .name = NAME, 76 74 .ops = &usb_hub_driver_ops, 77 75 .endpoints = usb_hub_endpoints 78 76 }; 79 80 77 81 78 int main(int argc, char *argv[]) -
uspace/drv/bus/usb/usbhub/port.h
rfbe148ee r54d1ad9 44 44 /** Information about single port on a hub. */ 45 45 typedef struct { 46 /* Port number as reporteed in descriptors. */ 46 47 size_t port_number; 48 /** Device communication pipe. */ 47 49 usb_pipe_t *control_pipe; 48 50 /** Mutex needed not only by CV for checking port reset. */ -
uspace/drv/bus/usb/usbhub/usbhub.c
rfbe148ee r54d1ad9 74 74 static void usb_hub_polling_terminated_callback(usb_device_t *device, 75 75 bool was_error, void *data); 76 /** 77 * Initialize hub device driver fibril 76 77 /** 78 * Initialize hub device driver structure. 78 79 * 79 80 * Creates hub representation and fibril that periodically checks hub's status. 80 81 * Hub representation is passed to the fibril. 82 * @param usb_dev generic usb device information 83 * @return error code 84 */ 85 int usb_hub_device_add(usb_device_t *usb_dev) 86 { 87 assert(usb_dev); 88 /* Create driver soft-state structure */ 89 usb_hub_dev_t *hub_dev = 90 usb_device_data_alloc(usb_dev, sizeof(usb_hub_dev_t)); 91 if (hub_dev == NULL) { 92 usb_log_error("Failed to create hub driver structure.\n"); 93 return ENOMEM; 94 } 95 hub_dev->usb_device = usb_dev; 96 hub_dev->pending_ops_count = 0; 97 hub_dev->running = false; 98 fibril_mutex_initialize(&hub_dev->pending_ops_mutex); 99 fibril_condvar_initialize(&hub_dev->pending_ops_cv); 100 101 /* Create hc connection */ 102 usb_log_debug("Initializing USB wire abstraction.\n"); 103 int opResult = usb_hc_connection_initialize_from_device( 104 &hub_dev->connection, hub_dev->usb_device->ddf_dev); 105 if (opResult != EOK) { 106 usb_log_error("Could not initialize connection to device: %s\n", 107 str_error(opResult)); 108 return opResult; 109 } 110 111 /* Set hub's first configuration. (There should be only one) */ 112 opResult = usb_set_first_configuration(usb_dev); 113 if (opResult != EOK) { 114 usb_log_error("Could not set hub configuration: %s\n", 115 str_error(opResult)); 116 return opResult; 117 } 118 119 /* Get port count and create attached_devices. */ 120 opResult = usb_hub_process_hub_specific_info(hub_dev); 121 if (opResult != EOK) { 122 usb_log_error("Could process hub specific info, %s\n", 123 str_error(opResult)); 124 return opResult; 125 } 126 127 /* Create hub control function. */ 128 usb_log_debug("Creating DDF function '" HUB_FNC_NAME "'.\n"); 129 hub_dev->hub_fun = ddf_fun_create(hub_dev->usb_device->ddf_dev, 130 fun_exposed, HUB_FNC_NAME); 131 if (hub_dev->hub_fun == NULL) { 132 usb_log_error("Failed to create hub function.\n"); 133 return ENOMEM; 134 } 135 136 /* Bind hub control function. */ 137 opResult = ddf_fun_bind(hub_dev->hub_fun); 138 if (opResult != EOK) { 139 usb_log_error("Failed to bind hub function: %s.\n", 140 str_error(opResult)); 141 ddf_fun_destroy(hub_dev->hub_fun); 142 return opResult; 143 } 144 145 /* Start hub operation. */ 146 opResult = usb_device_auto_poll(hub_dev->usb_device, 0, 147 hub_port_changes_callback, ((hub_dev->port_count + 1 + 8) / 8), 148 usb_hub_polling_terminated_callback, hub_dev); 149 if (opResult != EOK) { 150 /* Function is already bound */ 151 ddf_fun_unbind(hub_dev->hub_fun); 152 ddf_fun_destroy(hub_dev->hub_fun); 153 usb_log_error("Failed to create polling fibril: %s.\n", 154 str_error(opResult)); 155 return opResult; 156 } 157 hub_dev->running = true; 158 usb_log_info("Controlling hub '%s' (%zu ports).\n", 159 hub_dev->usb_device->ddf_dev->name, hub_dev->port_count); 160 161 return EOK; 162 } 163 /*----------------------------------------------------------------------------*/ 164 /** 165 * Turn off power to all ports. 166 * 167 * @param usb_dev generic usb device information 168 * @return error code 169 */ 170 int usb_hub_device_remove(usb_device_t *usb_dev) 171 { 172 assert(usb_dev); 173 usb_hub_dev_t *hub_dev = usb_dev->driver_data; 174 assert(hub_dev); 175 //TODO: Cascade the call here. 176 //TODO: Enable after cascading is implemented. 177 return ENOTSUP; 178 if (!hub_dev->power_switched) { 179 /* That is all we can do. */ 180 return EOK; 181 } 182 int ret = EOK; 183 usb_log_info("Hub is about to be removed, powering down all ports.\n"); 184 for (size_t port = 0; port < hub_dev->port_count; ++port) { 185 usb_log_debug("Powering down port %zu.\n", port); 186 int pret = usb_hub_port_clear_feature( 187 &hub_dev->ports[port], USB_HUB_FEATURE_PORT_POWER); 188 if (pret != EOK) { 189 usb_log_error("Cannot power down port %zu: %s.\n", 190 hub_dev->ports[port].port_number, str_error(pret)); 191 ret = pret; 192 } else { 193 if (!hub_dev->per_port_power) { 194 usb_log_debug("Ganged power switching mode, " 195 "one port is enough.\n"); 196 break; 197 } 198 } 199 } 200 return ret; 201 } 202 /*----------------------------------------------------------------------------*/ 203 /** 204 * Remove all attached devices 81 205 * @param usb_dev generic usb device information 82 206 * @return error code … … 120 244 } 121 245 /*----------------------------------------------------------------------------*/ 122 /**123 * Initialize hub device driver fibril124 *125 * Creates hub representation and fibril that periodically checks hub's status.126 * Hub representation is passed to the fibril.127 * @param usb_dev generic usb device information128 * @return error code129 */130 int usb_hub_device_add(usb_device_t *usb_dev)131 {132 assert(usb_dev);133 /* Create driver soft-state structure */134 usb_hub_dev_t *hub_dev =135 usb_device_data_alloc(usb_dev, sizeof(usb_hub_dev_t));136 if (hub_dev == NULL) {137 usb_log_error("Failed to create hun driver structure.\n");138 return ENOMEM;139 }140 hub_dev->usb_device = usb_dev;141 hub_dev->pending_ops_count = 0;142 hub_dev->running = false;143 fibril_mutex_initialize(&hub_dev->pending_ops_mutex);144 fibril_condvar_initialize(&hub_dev->pending_ops_cv);145 146 /* Create hc connection */147 usb_log_debug("Initializing USB wire abstraction.\n");148 int opResult = usb_hc_connection_initialize_from_device(149 &hub_dev->connection, hub_dev->usb_device->ddf_dev);150 if (opResult != EOK) {151 usb_log_error("Could not initialize connection to device: %s\n",152 str_error(opResult));153 return opResult;154 }155 156 /* Set hub's first configuration. (There should be only one) */157 opResult = usb_set_first_configuration(usb_dev);158 if (opResult != EOK) {159 usb_log_error("Could not set hub configuration: %s\n",160 str_error(opResult));161 return opResult;162 }163 164 /* Get port count and create attached_devices. */165 opResult = usb_hub_process_hub_specific_info(hub_dev);166 if (opResult != EOK) {167 usb_log_error("Could process hub specific info, %s\n",168 str_error(opResult));169 return opResult;170 }171 172 usb_log_debug("Creating DDF function '" HUB_FNC_NAME "'.\n");173 hub_dev->hub_fun = ddf_fun_create(hub_dev->usb_device->ddf_dev,174 fun_exposed, HUB_FNC_NAME);175 if (hub_dev->hub_fun == NULL) {176 usb_log_error("Failed to create hub function.\n");177 return ENOMEM;178 }179 180 opResult = ddf_fun_bind(hub_dev->hub_fun);181 if (opResult != EOK) {182 usb_log_error("Failed to bind hub function: %s.\n",183 str_error(opResult));184 ddf_fun_destroy(hub_dev->hub_fun);185 return opResult;186 }187 188 opResult = usb_device_auto_poll(hub_dev->usb_device, 0,189 hub_port_changes_callback, ((hub_dev->port_count + 1 + 8) / 8),190 usb_hub_polling_terminated_callback, hub_dev);191 if (opResult != EOK) {192 /* Function is already bound */193 ddf_fun_unbind(hub_dev->hub_fun);194 ddf_fun_destroy(hub_dev->hub_fun);195 usb_log_error("Failed to create polling fibril: %s.\n",196 str_error(opResult));197 return opResult;198 }199 hub_dev->running = true;200 usb_log_info("Controlling hub '%s' (%zu ports).\n",201 hub_dev->usb_device->ddf_dev->name, hub_dev->port_count);202 203 return EOK;204 }205 /*----------------------------------------------------------------------------*/206 246 /** Callback for polling hub for changes. 207 247 * … … 284 324 } 285 325 286 const bool is_power_switched =326 hub_dev->power_switched = 287 327 !(descriptor.characteristics & HUB_CHAR_NO_POWER_SWITCH_FLAG); 288 if (is_power_switched) { 289 usb_log_debug("Hub power switched\n"); 290 const bool per_port_power = descriptor.characteristics 291 & HUB_CHAR_POWER_PER_PORT_FLAG; 292 293 for (size_t port = 0; port < hub_dev->port_count; ++port) { 294 usb_log_debug("Powering port %zu.\n", port); 295 opResult = usb_hub_port_set_feature( 296 &hub_dev->ports[port], USB_HUB_FEATURE_PORT_POWER); 297 if (opResult != EOK) { 298 usb_log_error("Cannot power on port %zu: %s.\n", 299 port, str_error(opResult)); 300 } else { 301 if (!per_port_power) { 302 usb_log_debug( 303 "Ganged power switching mode, " 304 "one port is enough.\n"); 305 break; 306 } 328 hub_dev->per_port_power = 329 descriptor.characteristics & HUB_CHAR_POWER_PER_PORT_FLAG; 330 331 if (!hub_dev->power_switched) { 332 usb_log_info( 333 "Power switching not supported, ports always powered.\n"); 334 return EOK; 335 } 336 337 usb_log_info("Hub port power switching enabled.\n"); 338 339 for (size_t port = 0; port < hub_dev->port_count; ++port) { 340 usb_log_debug("Powering port %zu.\n", port); 341 const int ret = usb_hub_port_set_feature( 342 &hub_dev->ports[port], USB_HUB_FEATURE_PORT_POWER); 343 344 if (ret != EOK) { 345 usb_log_error("Cannot power on port %zu: %s.\n", 346 hub_dev->ports[port].port_number, str_error(ret)); 347 } else { 348 if (!hub_dev->per_port_power) { 349 usb_log_debug("Ganged power switching, " 350 "one port is enough.\n"); 351 break; 307 352 } 308 353 } 309 } else {310 usb_log_debug("Power not switched, ports always powered\n");311 354 } 312 355 return EOK; … … 375 418 usb_log_warning("Detected hub over-current condition, " 376 419 "all ports should be powered off."); 377 } else { 378 /* Over-current condition is gone, it is safe to turn the 379 * ports on. */ 380 for (size_t port = 0; port < hub_dev->port_count; ++port) { 381 const int opResult = usb_hub_port_set_feature( 382 &hub_dev->ports[port], USB_HUB_FEATURE_PORT_POWER); 383 // TODO: consider power policy here 384 if (opResult != EOK) { 385 usb_log_warning( 386 "HUB OVER-CURRENT GONE: Cannot power on " 387 "port %zu; %s\n", 388 port, str_error(opResult)); 389 } 390 } 391 } 392 const int opResult = usb_request_clear_feature( 393 &hub_dev->usb_device->ctrl_pipe, USB_REQUEST_TYPE_CLASS, 394 USB_REQUEST_RECIPIENT_DEVICE, 395 USB_HUB_FEATURE_C_HUB_LOCAL_POWER, 0); 396 if (opResult != EOK) { 397 usb_log_error( 398 "Failed to clear hub over-current change flag: %s.\n", 399 str_error(opResult)); 400 } 420 return; 421 } 422 423 /* Ports are always powered. */ 424 if (!hub_dev->power_switched) 425 return; 426 427 /* Over-current condition is gone, it is safe to turn the ports on. */ 428 for (size_t port = 0; port < hub_dev->port_count; ++port) { 429 const int ret = usb_hub_port_set_feature( 430 &hub_dev->ports[port], USB_HUB_FEATURE_PORT_POWER); 431 if (ret != EOK) { 432 usb_log_warning("HUB OVER-CURRENT GONE: Cannot power on" 433 " port %zu: %s\n", hub_dev->ports[port].port_number, 434 str_error(ret)); 435 } else { 436 if (!hub_dev->per_port_power) 437 return; 438 } 439 } 440 401 441 } 402 442 /*----------------------------------------------------------------------------*/ … … 434 474 if (status & USB_HUB_STATUS_C_OVER_CURRENT) { 435 475 usb_hub_over_current(hub_dev, status); 476 /* Ack change in hub OC flag */ 477 const int ret = usb_request_clear_feature( 478 &hub_dev->usb_device->ctrl_pipe, USB_REQUEST_TYPE_CLASS, 479 USB_REQUEST_RECIPIENT_DEVICE, 480 USB_HUB_FEATURE_C_HUB_OVER_CURRENT, 0); 481 if (ret != EOK) { 482 usb_log_error("Failed to clear hub over-current " 483 "change flag: %s.\n", str_error(opResult)); 484 } 436 485 } 437 486 … … 450 499 * Just ACK the change. 451 500 */ 452 const int opResult = usb_request_clear_feature(501 const int ret = usb_request_clear_feature( 453 502 control_pipe, USB_REQUEST_TYPE_CLASS, 454 503 USB_REQUEST_RECIPIENT_DEVICE, 455 504 USB_HUB_FEATURE_C_HUB_LOCAL_POWER, 0); 456 505 if (opResult != EOK) { 457 usb_log_error( 458 "Failed to clear hub power change flag: %s.\n", 459 str_error(opResult)); 506 usb_log_error("Failed to clear hub power change " 507 "flag: %s.\n", str_error(ret)); 460 508 } 461 509 } -
uspace/drv/bus/usb/usbhub/usbhub.h
rfbe148ee r54d1ad9 77 77 /** Status indicator */ 78 78 bool running; 79 /** Hub supports port power switching. */ 80 bool power_switched; 81 /** Each port is switched individually. */ 82 bool per_port_power; 79 83 }; 80 84 81 85 int usb_hub_device_add(usb_device_t *usb_dev); 86 int usb_hub_device_remove(usb_device_t *usb_dev); 82 87 int usb_hub_device_gone(usb_device_t *usb_dev); 83 88
Note:
See TracChangeset
for help on using the changeset viewer.