Changes in uspace/drv/bus/usb/usbhub/usbhub.c [cae002c:e231d26] in mainline
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
uspace/drv/bus/usb/usbhub/usbhub.c
rcae002c re231d26 68 68 69 69 static int usb_set_first_configuration(usb_device_t *usb_device); 70 static int usb_hub_process_hub_specific_info(usb_hub_dev_t *hub_dev); 71 static void usb_hub_over_current(const usb_hub_dev_t *hub_dev, 70 static usb_hub_info_t * usb_hub_info_create(usb_device_t *usb_dev); 71 static int usb_hub_process_hub_specific_info(usb_hub_info_t *hub_info); 72 static void usb_hub_over_current(const usb_hub_info_t *hub_info, 72 73 usb_hub_status_t status); 73 static void usb_hub_global_interrupt(const usb_hub_ dev_t *hub_dev);74 static void usb_hub_global_interrupt(const usb_hub_info_t *hub_info); 74 75 static void usb_hub_polling_terminated_callback(usb_device_t *device, 75 76 bool was_error, void *data); 76 77 77 78 /** 78 * Initialize hub device driver structure.79 * Initialize hub device driver fibril 79 80 * 80 81 * Creates hub representation and fibril that periodically checks hub's status. … … 83 84 * @return error code 84 85 */ 85 int usb_hub_ device_add(usb_device_t *usb_dev)86 int usb_hub_add_device(usb_device_t *usb_dev) 86 87 { 87 88 assert(usb_dev); 88 89 /* 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"); 90 usb_hub_info_t *hub_info = usb_hub_info_create(usb_dev); 91 if (hub_info == NULL) { 92 usb_log_error("Failed to create hun driver structure.\n"); 93 93 return ENOMEM; 94 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 95 101 96 /* Create hc connection */ 102 97 usb_log_debug("Initializing USB wire abstraction.\n"); 103 98 int opResult = usb_hc_connection_initialize_from_device( 104 &hub_ dev->connection, hub_dev->usb_device->ddf_dev);99 &hub_info->connection, hub_info->usb_device->ddf_dev); 105 100 if (opResult != EOK) { 106 101 usb_log_error("Could not initialize connection to device: %s\n", 107 102 str_error(opResult)); 103 free(hub_info); 108 104 return opResult; 109 105 } … … 114 110 usb_log_error("Could not set hub configuration: %s\n", 115 111 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); 112 free(hub_info); 113 return opResult; 114 } 115 116 //get port count and create attached_devs 117 opResult = usb_hub_process_hub_specific_info(hub_info); 121 118 if (opResult != EOK) { 122 119 usb_log_error("Could process hub specific info, %s\n", 123 120 str_error(opResult)); 124 return opResult;125 }126 127 /* Create hub control function. */ 121 free(hub_info); 122 return opResult; 123 } 124 128 125 usb_log_debug("Creating DDF function '" HUB_FNC_NAME "'.\n"); 129 hub_dev->hub_fun = ddf_fun_create(hub_dev->usb_device->ddf_dev,126 ddf_fun_t *hub_fun = ddf_fun_create(hub_info->usb_device->ddf_dev, 130 127 fun_exposed, HUB_FNC_NAME); 131 if (hub_ dev->hub_fun == NULL) {128 if (hub_fun == NULL) { 132 129 usb_log_error("Failed to create hub function.\n"); 130 free(hub_info); 133 131 return ENOMEM; 134 132 } 135 133 136 /* Bind hub control function. */ 137 opResult = ddf_fun_bind(hub_dev->hub_fun); 134 opResult = ddf_fun_bind(hub_fun); 138 135 if (opResult != EOK) { 139 136 usb_log_error("Failed to bind hub function: %s.\n", 140 137 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); 138 free(hub_info); 139 ddf_fun_destroy(hub_fun); 140 return opResult; 141 } 142 143 opResult = usb_device_auto_poll(hub_info->usb_device, 0, 144 hub_port_changes_callback, ((hub_info->port_count + 1) / 8) + 1, 145 usb_hub_polling_terminated_callback, hub_info); 146 if (opResult != EOK) { 147 ddf_fun_destroy(hub_fun); 148 free(hub_info); 153 149 usb_log_error("Failed to create polling fibril: %s.\n", 154 150 str_error(opResult)); 155 151 return opResult; 156 152 } 157 hub_dev->running = true;158 153 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 return ENOTSUP; 173 } 174 /*----------------------------------------------------------------------------*/ 175 /** 176 * Remove all attached devices 177 * @param usb_dev generic usb device information 178 * @return error code 179 */ 180 int usb_hub_device_gone(usb_device_t *usb_dev) 181 { 182 assert(usb_dev); 183 usb_hub_dev_t *hub = usb_dev->driver_data; 184 assert(hub); 185 unsigned tries = 10; 186 while (hub->running) { 187 async_usleep(100000); 188 if (!tries--) { 189 usb_log_error("Can't remove hub, still running.\n"); 190 return EINPROGRESS; 191 } 192 } 193 194 assert(!hub->running); 195 196 for (size_t port = 0; port < hub->port_count; ++port) { 197 if (hub->ports[port].attached_device.fun) { 198 const int ret = 199 usb_hub_port_fini(&hub->ports[port], hub); 200 if (ret != EOK) 201 return ret; 202 } 203 } 204 free(hub->ports); 205 206 const int ret = ddf_fun_unbind(hub->hub_fun); 207 if (ret != EOK) { 208 usb_log_error("Failed to unbind '%s' function: %s.\n", 209 HUB_FNC_NAME, str_error(ret)); 210 return ret; 211 } 212 ddf_fun_destroy(hub->hub_fun); 213 214 usb_log_info("USB hub driver, stopped and cleaned.\n"); 154 hub_info->usb_device->ddf_dev->name, hub_info->port_count); 155 215 156 return EOK; 216 157 } … … 221 162 * @param change_bitmap Bitmap of changed ports. 222 163 * @param change_bitmap_size Size of the bitmap in bytes. 223 * @param arg Custom argument, points to @c usb_hub_ dev_t.164 * @param arg Custom argument, points to @c usb_hub_info_t. 224 165 * @return Whether to continue polling. 225 166 */ … … 228 169 { 229 170 usb_log_debug("hub_port_changes_callback\n"); 230 usb_hub_ dev_t *hub = arg;171 usb_hub_info_t *hub = arg; 231 172 assert(hub); 232 173 … … 243 184 244 185 /* N + 1 bit indicates change on port N */ 245 for (size_t port = 0; port < hub->port_count + 1; port++) {246 const size_t bit = port + 1;247 const bool change = (change_bitmap[ bit / 8] >> (bit % 8)) & 1;186 size_t port = 1; 187 for (; port < hub->port_count + 1; port++) { 188 const bool change = (change_bitmap[port / 8] >> (port % 8)) & 1; 248 189 if (change) { 249 190 usb_hub_port_process_interrupt(&hub->ports[port], hub); … … 254 195 /*----------------------------------------------------------------------------*/ 255 196 /** 256 * Load hub-specific information into hub_dev structure and process if needed 197 * create usb_hub_info_t structure 198 * 199 * Does only basic copying of known information into new structure. 200 * @param usb_dev usb device structure 201 * @return basic usb_hub_info_t structure 202 */ 203 static usb_hub_info_t * usb_hub_info_create(usb_device_t *usb_dev) 204 { 205 assert(usb_dev); 206 usb_hub_info_t *info = malloc(sizeof(usb_hub_info_t)); 207 if (!info) 208 return NULL; 209 210 info->usb_device = usb_dev; 211 212 info->ports = NULL; 213 info->port_count = -1; 214 fibril_mutex_initialize(&info->pending_ops_mutex); 215 fibril_condvar_initialize(&info->pending_ops_cv); 216 info->pending_ops_count = 0; 217 218 return info; 219 } 220 /*----------------------------------------------------------------------------*/ 221 /** 222 * Load hub-specific information into hub_info structure and process if needed 257 223 * 258 224 * Read port count and initialize structures holding per port information. … … 260 226 * This function is hub-specific and should be run only after the hub is 261 227 * configured using usb_set_first_configuration function. 262 * @param hub_ devhub representation228 * @param hub_info hub representation 263 229 * @return error code 264 230 */ 265 static int usb_hub_process_hub_specific_info(usb_hub_ dev_t *hub_dev)266 { 267 assert(hub_ dev);231 static int usb_hub_process_hub_specific_info(usb_hub_info_t *hub_info) 232 { 233 assert(hub_info); 268 234 269 235 /* Get hub descriptor. */ 270 236 usb_log_debug("Retrieving descriptor\n"); 271 usb_pipe_t *control_pipe = &hub_ dev->usb_device->ctrl_pipe;237 usb_pipe_t *control_pipe = &hub_info->usb_device->ctrl_pipe; 272 238 273 239 usb_hub_descriptor_header_t descriptor; … … 276 242 USB_REQUEST_TYPE_CLASS, USB_REQUEST_RECIPIENT_DEVICE, 277 243 USB_DESCTYPE_HUB, 0, 0, &descriptor, 278 sizeof(usb_hub_descriptor_ header_t), &received_size);244 sizeof(usb_hub_descriptor_t), &received_size); 279 245 if (opResult != EOK) { 280 246 usb_log_error("Failed to receive hub descriptor: %s.\n", … … 284 250 285 251 usb_log_debug("Setting port count to %d.\n", descriptor.port_count); 286 hub_dev->port_count = descriptor.port_count; 287 288 hub_dev->ports = calloc(hub_dev->port_count, sizeof(usb_hub_port_t)); 289 if (!hub_dev->ports) { 252 hub_info->port_count = descriptor.port_count; 253 254 // TODO: +1 hack is no longer necessary 255 hub_info->ports = 256 malloc(sizeof(usb_hub_port_t) * (hub_info->port_count + 1)); 257 if (!hub_info->ports) { 290 258 return ENOMEM; 291 259 } 292 260 293 for (size_t port = 0; port < hub_dev->port_count; ++port) {294 usb_hub_port_init(295 &hub_dev->ports[port], port + 1, control_pipe);296 } 297 298 hub_dev->power_switched =261 size_t port; 262 for (port = 0; port < hub_info->port_count + 1; ++port) { 263 usb_hub_port_init(&hub_info->ports[port], port, control_pipe); 264 } 265 266 const bool is_power_switched = 299 267 !(descriptor.characteristics & HUB_CHAR_NO_POWER_SWITCH_FLAG); 300 hub_dev->per_port_power = 301 descriptor.characteristics & HUB_CHAR_POWER_PER_PORT_FLAG; 302 303 if (!hub_dev->power_switched) { 304 usb_log_info( 305 "Power switching not supported, ports always powered.\n"); 306 return EOK; 307 } 308 309 usb_log_info("Hub port power switching enabled.\n"); 310 311 for (size_t port = 0; port < hub_dev->port_count; ++port) { 312 usb_log_debug("Powering port %zu.\n", port); 313 const int ret = usb_hub_port_set_feature( 314 &hub_dev->ports[port], USB_HUB_FEATURE_PORT_POWER); 315 316 if (ret != EOK) { 317 usb_log_error("Cannot power on port %zu: %s.\n", 318 hub_dev->ports[port].port_number, str_error(ret)); 319 } else { 320 if (!hub_dev->per_port_power) { 321 usb_log_debug("Ganged power switching, " 322 "one port is enough.\n"); 323 break; 268 if (is_power_switched) { 269 usb_log_debug("Hub power switched\n"); 270 const bool per_port_power = descriptor.characteristics 271 & HUB_CHAR_POWER_PER_PORT_FLAG; 272 273 for (port = 1; port <= hub_info->port_count; ++port) { 274 usb_log_debug("Powering port %zu.\n", port); 275 opResult = usb_hub_port_set_feature( 276 &hub_info->ports[port], USB_HUB_FEATURE_PORT_POWER); 277 if (opResult != EOK) { 278 usb_log_error("Cannot power on port %zu: %s.\n", 279 port, str_error(opResult)); 280 } else { 281 if (!per_port_power) { 282 usb_log_debug( 283 "Ganged power switching mode, " 284 "one port is enough.\n"); 285 break; 286 } 324 287 } 325 288 } 289 } else { 290 usb_log_debug("Power not switched, ports always powered\n"); 326 291 } 327 292 return EOK; … … 349 314 } 350 315 351 if (usb_device->descriptors.configuration_size 352 < sizeof(usb_standard_configuration_descriptor_t)) { 353 usb_log_error("Configuration descriptor is not big enough" 354 " to fit standard configuration descriptor.\n"); 355 return EOVERFLOW; 356 } 357 358 // TODO: Make sure that the cast is correct 316 // TODO: Make sure that there is enough data and the cast is correct 359 317 usb_standard_configuration_descriptor_t *config_descriptor 360 318 = (usb_standard_configuration_descriptor_t *) … … 379 337 * 380 338 * This means either to power off the hub or power it on. 381 * @param hub_ devhub instance339 * @param hub_info hub instance 382 340 * @param status hub status bitmask 383 341 * @return error code 384 342 */ 385 static void usb_hub_over_current(const usb_hub_ dev_t *hub_dev,343 static void usb_hub_over_current(const usb_hub_info_t *hub_info, 386 344 usb_hub_status_t status) 387 345 { … … 390 348 usb_log_warning("Detected hub over-current condition, " 391 349 "all ports should be powered off."); 392 return; 393 } 394 395 /* Ports are always powered. */ 396 if (!hub_dev->power_switched) 397 return; 398 399 /* Over-current condition is gone, it is safe to turn the ports on. */ 400 for (size_t port = 0; port < hub_dev->port_count; ++port) { 401 const int ret = usb_hub_port_set_feature( 402 &hub_dev->ports[port], USB_HUB_FEATURE_PORT_POWER); 403 if (ret != EOK) { 404 usb_log_warning("HUB OVER-CURRENT GONE: Cannot power on" 405 " port %zu: %s\n", hub_dev->ports[port].port_number, 406 str_error(ret)); 407 } else { 408 if (!hub_dev->per_port_power) 409 return; 350 } else { 351 /* Over-current condition is gone, it is safe to turn the 352 * ports on. */ 353 size_t port; 354 for (port = 1; port <= hub_info->port_count; ++port) { 355 const int opResult = usb_hub_port_set_feature( 356 &hub_info->ports[port], USB_HUB_FEATURE_PORT_POWER); 357 if (opResult != EOK) { 358 usb_log_warning( 359 "HUB OVER-CURRENT GONE: Cannot power on " 360 "port %zu; %s\n", 361 port, str_error(opResult)); 362 } 410 363 } 411 364 } 412 365 const int opResult = usb_request_clear_feature( 366 &hub_info->usb_device->ctrl_pipe, USB_REQUEST_TYPE_CLASS, 367 USB_REQUEST_RECIPIENT_DEVICE, 368 USB_HUB_FEATURE_C_HUB_LOCAL_POWER, 0); 369 if (opResult != EOK) { 370 usb_log_error( 371 "Failed to clear hub over-current change flag: %s.\n", 372 str_error(opResult)); 373 } 413 374 } 414 375 /*----------------------------------------------------------------------------*/ … … 417 378 * 418 379 * The change can be either in the over-current condition or local-power change. 419 * @param hub_ devhub instance420 */ 421 static void usb_hub_global_interrupt(const usb_hub_ dev_t *hub_dev)422 { 423 assert(hub_ dev);424 assert(hub_ dev->usb_device);380 * @param hub_info hub instance 381 */ 382 static void usb_hub_global_interrupt(const usb_hub_info_t *hub_info) 383 { 384 assert(hub_info); 385 assert(hub_info->usb_device); 425 386 usb_log_debug("Global interrupt on a hub\n"); 426 usb_pipe_t *control_pipe = &hub_ dev->usb_device->ctrl_pipe;387 usb_pipe_t *control_pipe = &hub_info->usb_device->ctrl_pipe; 427 388 428 389 usb_hub_status_t status; … … 445 406 /* Handle status changes */ 446 407 if (status & USB_HUB_STATUS_C_OVER_CURRENT) { 447 usb_hub_over_current(hub_dev, status); 448 /* Ack change in hub OC flag */ 449 const int ret = usb_request_clear_feature( 450 &hub_dev->usb_device->ctrl_pipe, USB_REQUEST_TYPE_CLASS, 451 USB_REQUEST_RECIPIENT_DEVICE, 452 USB_HUB_FEATURE_C_HUB_OVER_CURRENT, 0); 453 if (ret != EOK) { 454 usb_log_error("Failed to clear hub over-current " 455 "change flag: %s.\n", str_error(opResult)); 456 } 408 usb_hub_over_current(hub_info, status); 457 409 } 458 410 … … 471 423 * Just ACK the change. 472 424 */ 473 const int ret = usb_request_clear_feature(425 const int opResult = usb_request_clear_feature( 474 426 control_pipe, USB_REQUEST_TYPE_CLASS, 475 427 USB_REQUEST_RECIPIENT_DEVICE, 476 428 USB_HUB_FEATURE_C_HUB_LOCAL_POWER, 0); 477 429 if (opResult != EOK) { 478 usb_log_error("Failed to clear hub power change " 479 "flag: %s.\n", str_error(ret)); 430 usb_log_error( 431 "Failed to clear hub power change flag: %s.\n", 432 str_error(opResult)); 480 433 } 481 434 } … … 485 438 * callback called from hub polling fibril when the fibril terminates 486 439 * 487 * Does not perform cleanup, just marks the hub as not running.440 * Should perform a cleanup - deletes hub_info. 488 441 * @param device usb device afected 489 442 * @param was_error indicates that the fibril is stoped due to an error 490 * @param data pointer to usb_hub_ dev_t structure443 * @param data pointer to usb_hub_info_t structure 491 444 */ 492 445 static void usb_hub_polling_terminated_callback(usb_device_t *device, 493 446 bool was_error, void *data) 494 447 { 495 usb_hub_ dev_t *hub = data;448 usb_hub_info_t *hub = data; 496 449 assert(hub); 497 450 … … 507 460 */ 508 461 if (hub->pending_ops_count > 0) { 509 for (size_t port = 0; port < hub->port_count; ++port) { 462 size_t port; 463 for (port = 0; port < hub->port_count; port++) { 510 464 usb_hub_port_reset_fail(&hub->ports[port]); 511 465 } … … 517 471 } 518 472 fibril_mutex_unlock(&hub->pending_ops_mutex); 519 hub->running = false; 473 474 usb_device_destroy(hub->usb_device); 475 476 free(hub->ports); 477 free(hub); 520 478 } 521 479 /**
Note:
See TracChangeset
for help on using the changeset viewer.