Changeset c83a55c in mainline for uspace/drv/bus/usb/usbhub/usbhub.c
- Timestamp:
- 2011-10-31T06:52:54Z (13 years ago)
- Branches:
- lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
- Children:
- c25e39b
- Parents:
- e8ab32f (diff), 3ce78580 (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. - File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
uspace/drv/bus/usb/usbhub/usbhub.c
re8ab32f rc83a55c 68 68 69 69 static int usb_set_first_configuration(usb_device_t *usb_device); 70 static usb_hub_dev_t * usb_hub_dev_create(usb_device_t *usb_dev);71 70 static int usb_hub_process_hub_specific_info(usb_hub_dev_t *hub_dev); 72 71 static void usb_hub_over_current(const usb_hub_dev_t *hub_dev, … … 75 74 static void usb_hub_polling_terminated_callback(usb_device_t *device, 76 75 bool was_error, void *data); 77 /** 78 * Initialize hub device driver fibril 76 77 /** 78 * Initialize hub device driver structure. 79 79 * 80 80 * Creates hub representation and fibril that periodically checks hub's status. 81 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 82 205 * @param usb_dev generic usb device information 83 206 * @return error code … … 121 244 } 122 245 /*----------------------------------------------------------------------------*/ 123 /**124 * Initialize hub device driver fibril125 *126 * Creates hub representation and fibril that periodically checks hub's status.127 * Hub representation is passed to the fibril.128 * @param usb_dev generic usb device information129 * @return error code130 */131 int usb_hub_device_add(usb_device_t *usb_dev)132 {133 assert(usb_dev);134 /* Create driver soft-state structure */135 usb_hub_dev_t *hub_dev = usb_hub_dev_create(usb_dev);136 if (hub_dev == NULL) {137 usb_log_error("Failed to create hun driver structure.\n");138 return ENOMEM;139 }140 141 /* Create hc connection */142 usb_log_debug("Initializing USB wire abstraction.\n");143 int opResult = usb_hc_connection_initialize_from_device(144 &hub_dev->connection, hub_dev->usb_device->ddf_dev);145 if (opResult != EOK) {146 usb_log_error("Could not initialize connection to device: %s\n",147 str_error(opResult));148 free(hub_dev);149 return opResult;150 }151 152 /* Set hub's first configuration. (There should be only one) */153 opResult = usb_set_first_configuration(usb_dev);154 if (opResult != EOK) {155 usb_log_error("Could not set hub configuration: %s\n",156 str_error(opResult));157 free(hub_dev);158 return opResult;159 }160 161 /* Get port count and create attached_devices. */162 opResult = usb_hub_process_hub_specific_info(hub_dev);163 if (opResult != EOK) {164 usb_log_error("Could process hub specific info, %s\n",165 str_error(opResult));166 free(hub_dev);167 return opResult;168 }169 170 usb_log_debug("Creating DDF function '" HUB_FNC_NAME "'.\n");171 hub_dev->hub_fun = ddf_fun_create(hub_dev->usb_device->ddf_dev,172 fun_exposed, HUB_FNC_NAME);173 if (hub_dev->hub_fun == NULL) {174 usb_log_error("Failed to create hub function.\n");175 free(hub_dev);176 return ENOMEM;177 }178 179 opResult = ddf_fun_bind(hub_dev->hub_fun);180 if (opResult != EOK) {181 usb_log_error("Failed to bind hub function: %s.\n",182 str_error(opResult));183 free(hub_dev);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 free(hub_dev);196 usb_log_error("Failed to create polling fibril: %s.\n",197 str_error(opResult));198 return opResult;199 }200 hub_dev->running = true;201 usb_log_info("Controlling hub '%s' (%zu ports).\n",202 hub_dev->usb_device->ddf_dev->name, hub_dev->port_count);203 204 return EOK;205 }206 /*----------------------------------------------------------------------------*/207 246 /** Callback for polling hub for changes. 208 247 * … … 243 282 /*----------------------------------------------------------------------------*/ 244 283 /** 245 * create usb_hub_dev_t structure246 *247 * Does only basic copying of known information into new structure.248 * @param usb_dev usb device structure249 * @return basic usb_hub_dev_t structure250 */251 static usb_hub_dev_t * usb_hub_dev_create(usb_device_t *usb_dev)252 {253 assert(usb_dev);254 usb_hub_dev_t *hub_dev =255 usb_device_data_alloc(usb_dev, sizeof(usb_hub_dev_t));256 if (!hub_dev)257 return NULL;258 259 hub_dev->usb_device = usb_dev;260 hub_dev->ports = NULL;261 hub_dev->port_count = 0;262 hub_dev->pending_ops_count = 0;263 hub_dev->running = false;264 fibril_mutex_initialize(&hub_dev->pending_ops_mutex);265 fibril_condvar_initialize(&hub_dev->pending_ops_cv);266 267 return hub_dev;268 }269 /*----------------------------------------------------------------------------*/270 /**271 284 * Load hub-specific information into hub_dev structure and process if needed 272 285 * … … 311 324 } 312 325 313 const bool is_power_switched =326 hub_dev->power_switched = 314 327 !(descriptor.characteristics & HUB_CHAR_NO_POWER_SWITCH_FLAG); 315 if (is_power_switched) { 316 usb_log_debug("Hub power switched\n"); 317 const bool per_port_power = descriptor.characteristics 318 & HUB_CHAR_POWER_PER_PORT_FLAG; 319 320 for (size_t port = 0; port < hub_dev->port_count; ++port) { 321 usb_log_debug("Powering port %zu.\n", port); 322 opResult = usb_hub_port_set_feature( 323 &hub_dev->ports[port], USB_HUB_FEATURE_PORT_POWER); 324 if (opResult != EOK) { 325 usb_log_error("Cannot power on port %zu: %s.\n", 326 port, str_error(opResult)); 327 } else { 328 if (!per_port_power) { 329 usb_log_debug( 330 "Ganged power switching mode, " 331 "one port is enough.\n"); 332 break; 333 } 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; 334 352 } 335 353 } 336 } else {337 usb_log_debug("Power not switched, ports always powered\n");338 354 } 339 355 return EOK; … … 402 418 usb_log_warning("Detected hub over-current condition, " 403 419 "all ports should be powered off."); 404 } else { 405 /* Over-current condition is gone, it is safe to turn the 406 * ports on. */ 407 for (size_t port = 0; port < hub_dev->port_count; ++port) { 408 const int opResult = usb_hub_port_set_feature( 409 &hub_dev->ports[port], USB_HUB_FEATURE_PORT_POWER); 410 // TODO: consider power policy here 411 if (opResult != EOK) { 412 usb_log_warning( 413 "HUB OVER-CURRENT GONE: Cannot power on " 414 "port %zu; %s\n", 415 port, str_error(opResult)); 416 } 417 } 418 } 419 const int opResult = usb_request_clear_feature( 420 &hub_dev->usb_device->ctrl_pipe, USB_REQUEST_TYPE_CLASS, 421 USB_REQUEST_RECIPIENT_DEVICE, 422 USB_HUB_FEATURE_C_HUB_LOCAL_POWER, 0); 423 if (opResult != EOK) { 424 usb_log_error( 425 "Failed to clear hub over-current change flag: %s.\n", 426 str_error(opResult)); 427 } 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 428 441 } 429 442 /*----------------------------------------------------------------------------*/ … … 461 474 if (status & USB_HUB_STATUS_C_OVER_CURRENT) { 462 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 } 463 485 } 464 486 … … 477 499 * Just ACK the change. 478 500 */ 479 const int opResult = usb_request_clear_feature(501 const int ret = usb_request_clear_feature( 480 502 control_pipe, USB_REQUEST_TYPE_CLASS, 481 503 USB_REQUEST_RECIPIENT_DEVICE, 482 504 USB_HUB_FEATURE_C_HUB_LOCAL_POWER, 0); 483 505 if (opResult != EOK) { 484 usb_log_error( 485 "Failed to clear hub power change flag: %s.\n", 486 str_error(opResult)); 506 usb_log_error("Failed to clear hub power change " 507 "flag: %s.\n", str_error(ret)); 487 508 } 488 509 }
Note:
See TracChangeset
for help on using the changeset viewer.