Changes in uspace/drv/bus/usb/usbhub/usbhub.c [54d1ad9:065064e6] in mainline
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
uspace/drv/bus/usb/usbhub/usbhub.c
r54d1ad9 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 /* 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 information168 * @return error code169 */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 devices205 82 * @param usb_dev generic usb device information 206 83 * @return error code … … 244 121 } 245 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 /*----------------------------------------------------------------------------*/ 246 207 /** Callback for polling hub for changes. 247 208 * … … 282 243 /*----------------------------------------------------------------------------*/ 283 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 /** 284 271 * Load hub-specific information into hub_dev structure and process if needed 285 272 * … … 324 311 } 325 312 326 hub_dev->power_switched =313 const bool is_power_switched = 327 314 !(descriptor.characteristics & HUB_CHAR_NO_POWER_SWITCH_FLAG); 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; 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 } 352 334 } 353 335 } 336 } else { 337 usb_log_debug("Power not switched, ports always powered\n"); 354 338 } 355 339 return EOK; … … 418 402 usb_log_warning("Detected hub over-current condition, " 419 403 "all ports should be powered off."); 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 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 } 441 428 } 442 429 /*----------------------------------------------------------------------------*/ … … 474 461 if (status & USB_HUB_STATUS_C_OVER_CURRENT) { 475 462 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 }485 463 } 486 464 … … 499 477 * Just ACK the change. 500 478 */ 501 const int ret = usb_request_clear_feature(479 const int opResult = usb_request_clear_feature( 502 480 control_pipe, USB_REQUEST_TYPE_CLASS, 503 481 USB_REQUEST_RECIPIENT_DEVICE, 504 482 USB_HUB_FEATURE_C_HUB_LOCAL_POWER, 0); 505 483 if (opResult != EOK) { 506 usb_log_error("Failed to clear hub power change " 507 "flag: %s.\n", str_error(ret)); 484 usb_log_error( 485 "Failed to clear hub power change flag: %s.\n", 486 str_error(opResult)); 508 487 } 509 488 }
Note:
See TracChangeset
for help on using the changeset viewer.