Changes in uspace/drv/bus/usb/usbhub/usbhub.c [065064e6:9d58539] in mainline
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
uspace/drv/bus/usb/usbhub/usbhub.c
r065064e6 r9d58539 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 102 int opResult = usb_pipe_start_long_transfer(&usb_dev->ctrl_pipe); 103 if (opResult != EOK) { 104 usb_log_error("Failed to start long ctrl pipe transfer: %s\n", 105 str_error(opResult)); 106 return opResult; 107 } 108 109 /* Set hub's first configuration. (There should be only one) */ 110 opResult = usb_set_first_configuration(usb_dev); 111 if (opResult != EOK) { 112 usb_pipe_end_long_transfer(&usb_dev->ctrl_pipe); 113 usb_log_error("Could not set hub configuration: %s\n", 114 str_error(opResult)); 115 return opResult; 116 } 117 118 /* Get port count and create attached_devices. */ 119 opResult = usb_hub_process_hub_specific_info(hub_dev); 120 if (opResult != EOK) { 121 usb_pipe_end_long_transfer(&usb_dev->ctrl_pipe); 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_pipe_end_long_transfer(&usb_dev->ctrl_pipe); 133 usb_log_error("Failed to create hub function.\n"); 134 return ENOMEM; 135 } 136 137 /* Bind hub control function. */ 138 opResult = ddf_fun_bind(hub_dev->hub_fun); 139 if (opResult != EOK) { 140 usb_pipe_end_long_transfer(&usb_dev->ctrl_pipe); 141 usb_log_error("Failed to bind hub function: %s.\n", 142 str_error(opResult)); 143 ddf_fun_destroy(hub_dev->hub_fun); 144 return opResult; 145 } 146 147 /* Start hub operation. */ 148 opResult = usb_device_auto_poll(hub_dev->usb_device, 0, 149 hub_port_changes_callback, ((hub_dev->port_count + 1 + 8) / 8), 150 usb_hub_polling_terminated_callback, hub_dev); 151 if (opResult != EOK) { 152 usb_pipe_end_long_transfer(&usb_dev->ctrl_pipe); 153 /* Function is already bound */ 154 ddf_fun_unbind(hub_dev->hub_fun); 155 ddf_fun_destroy(hub_dev->hub_fun); 156 usb_log_error("Failed to create polling fibril: %s.\n", 157 str_error(opResult)); 158 return opResult; 159 } 160 hub_dev->running = true; 161 usb_log_info("Controlling hub '%s' (%zu ports).\n", 162 hub_dev->usb_device->ddf_dev->name, hub_dev->port_count); 163 164 usb_pipe_end_long_transfer(&usb_dev->ctrl_pipe); 165 return EOK; 166 } 167 /*----------------------------------------------------------------------------*/ 168 /** 169 * Turn off power to all ports. 170 * 171 * @param usb_dev generic usb device information 172 * @return error code 173 */ 174 int usb_hub_device_remove(usb_device_t *usb_dev) 175 { 176 return ENOTSUP; 177 } 178 /*----------------------------------------------------------------------------*/ 179 /** 180 * Remove all attached devices 82 181 * @param usb_dev generic usb device information 83 182 * @return error code … … 121 220 } 122 221 /*----------------------------------------------------------------------------*/ 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 222 /** Callback for polling hub for changes. 208 223 * … … 243 258 /*----------------------------------------------------------------------------*/ 244 259 /** 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 260 * Load hub-specific information into hub_dev structure and process if needed 272 261 * … … 311 300 } 312 301 313 const bool is_power_switched =302 hub_dev->power_switched = 314 303 !(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 } 304 hub_dev->per_port_power = 305 descriptor.characteristics & HUB_CHAR_POWER_PER_PORT_FLAG; 306 307 if (!hub_dev->power_switched) { 308 usb_log_info( 309 "Power switching not supported, ports always powered.\n"); 310 return EOK; 311 } 312 313 usb_log_info("Hub port power switching enabled.\n"); 314 315 for (size_t port = 0; port < hub_dev->port_count; ++port) { 316 usb_log_debug("Powering port %zu.\n", port); 317 const int ret = usb_hub_port_set_feature( 318 &hub_dev->ports[port], USB_HUB_FEATURE_PORT_POWER); 319 320 if (ret != EOK) { 321 usb_log_error("Cannot power on port %zu: %s.\n", 322 hub_dev->ports[port].port_number, str_error(ret)); 323 } else { 324 if (!hub_dev->per_port_power) { 325 usb_log_debug("Ganged power switching, " 326 "one port is enough.\n"); 327 break; 334 328 } 335 329 } 336 } else {337 usb_log_debug("Power not switched, ports always powered\n");338 330 } 339 331 return EOK; … … 402 394 usb_log_warning("Detected hub over-current condition, " 403 395 "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 } 396 return; 397 } 398 399 /* Ports are always powered. */ 400 if (!hub_dev->power_switched) 401 return; 402 403 /* Over-current condition is gone, it is safe to turn the ports on. */ 404 for (size_t port = 0; port < hub_dev->port_count; ++port) { 405 const int ret = usb_hub_port_set_feature( 406 &hub_dev->ports[port], USB_HUB_FEATURE_PORT_POWER); 407 if (ret != EOK) { 408 usb_log_warning("HUB OVER-CURRENT GONE: Cannot power on" 409 " port %zu: %s\n", hub_dev->ports[port].port_number, 410 str_error(ret)); 411 } else { 412 if (!hub_dev->per_port_power) 413 return; 414 } 415 } 416 428 417 } 429 418 /*----------------------------------------------------------------------------*/ … … 461 450 if (status & USB_HUB_STATUS_C_OVER_CURRENT) { 462 451 usb_hub_over_current(hub_dev, status); 452 /* Ack change in hub OC flag */ 453 const int ret = usb_request_clear_feature( 454 &hub_dev->usb_device->ctrl_pipe, USB_REQUEST_TYPE_CLASS, 455 USB_REQUEST_RECIPIENT_DEVICE, 456 USB_HUB_FEATURE_C_HUB_OVER_CURRENT, 0); 457 if (ret != EOK) { 458 usb_log_error("Failed to clear hub over-current " 459 "change flag: %s.\n", str_error(opResult)); 460 } 463 461 } 464 462 … … 477 475 * Just ACK the change. 478 476 */ 479 const int opResult = usb_request_clear_feature(477 const int ret = usb_request_clear_feature( 480 478 control_pipe, USB_REQUEST_TYPE_CLASS, 481 479 USB_REQUEST_RECIPIENT_DEVICE, 482 480 USB_HUB_FEATURE_C_HUB_LOCAL_POWER, 0); 483 481 if (opResult != EOK) { 484 usb_log_error( 485 "Failed to clear hub power change flag: %s.\n", 486 str_error(opResult)); 482 usb_log_error("Failed to clear hub power change " 483 "flag: %s.\n", str_error(ret)); 487 484 } 488 485 }
Note:
See TracChangeset
for help on using the changeset viewer.