Changes in uspace/drv/bus/usb/usbhub/usbhub.c [9d58539:065064e6] in mainline
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
uspace/drv/bus/usb/usbhub/usbhub.c
r9d58539 r065064e6 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); 70 71 static int usb_hub_process_hub_specific_info(usb_hub_dev_t *hub_dev); 71 72 static void usb_hub_over_current(const usb_hub_dev_t *hub_dev, … … 74 75 static void usb_hub_polling_terminated_callback(usb_device_t *device, 75 76 bool was_error, void *data); 76 77 /** 78 * Initialize hub device driver structure. 77 /** 78 * Initialize hub device driver fibril 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 information83 * @return error code84 */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 information172 * @return error code173 */174 int usb_hub_device_remove(usb_device_t *usb_dev)175 {176 return ENOTSUP;177 }178 /*----------------------------------------------------------------------------*/179 /**180 * Remove all attached devices181 82 * @param usb_dev generic usb device information 182 83 * @return error code … … 220 121 } 221 122 /*----------------------------------------------------------------------------*/ 123 /** 124 * Initialize hub device driver fibril 125 * 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 information 129 * @return error code 130 */ 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 /*----------------------------------------------------------------------------*/ 222 207 /** Callback for polling hub for changes. 223 208 * … … 258 243 /*----------------------------------------------------------------------------*/ 259 244 /** 245 * create usb_hub_dev_t structure 246 * 247 * Does only basic copying of known information into new structure. 248 * @param usb_dev usb device structure 249 * @return basic usb_hub_dev_t structure 250 */ 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 /** 260 271 * Load hub-specific information into hub_dev structure and process if needed 261 272 * … … 300 311 } 301 312 302 hub_dev->power_switched =313 const bool is_power_switched = 303 314 !(descriptor.characteristics & HUB_CHAR_NO_POWER_SWITCH_FLAG); 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; 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 334 } 329 335 } 336 } else { 337 usb_log_debug("Power not switched, ports always powered\n"); 330 338 } 331 339 return EOK; … … 394 402 usb_log_warning("Detected hub over-current condition, " 395 403 "all ports should be powered off."); 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 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 } 417 428 } 418 429 /*----------------------------------------------------------------------------*/ … … 450 461 if (status & USB_HUB_STATUS_C_OVER_CURRENT) { 451 462 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 }461 463 } 462 464 … … 475 477 * Just ACK the change. 476 478 */ 477 const int ret = usb_request_clear_feature(479 const int opResult = usb_request_clear_feature( 478 480 control_pipe, USB_REQUEST_TYPE_CLASS, 479 481 USB_REQUEST_RECIPIENT_DEVICE, 480 482 USB_HUB_FEATURE_C_HUB_LOCAL_POWER, 0); 481 483 if (opResult != EOK) { 482 usb_log_error("Failed to clear hub power change " 483 "flag: %s.\n", str_error(ret)); 484 usb_log_error( 485 "Failed to clear hub power change flag: %s.\n", 486 str_error(opResult)); 484 487 } 485 488 }
Note:
See TracChangeset
for help on using the changeset viewer.