Changes in uspace/drv/bus/usb/usbhub/usbhub.c [e231d26:cae002c] in mainline
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
uspace/drv/bus/usb/usbhub/usbhub.c
re231d26 rcae002c 68 68 69 69 static int usb_set_first_configuration(usb_device_t *usb_device); 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, 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, 73 72 usb_hub_status_t status); 74 static void usb_hub_global_interrupt(const usb_hub_ info_t *hub_info);73 static void usb_hub_global_interrupt(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 76 78 77 /** 79 * Initialize hub device driver fibril78 * Initialize hub device driver structure. 80 79 * 81 80 * Creates hub representation and fibril that periodically checks hub's status. … … 84 83 * @return error code 85 84 */ 86 int usb_hub_ add_device(usb_device_t *usb_dev)85 int usb_hub_device_add(usb_device_t *usb_dev) 87 86 { 88 87 assert(usb_dev); 89 88 /* Create driver soft-state structure */ 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"); 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 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); 95 100 96 101 /* Create hc connection */ 97 102 usb_log_debug("Initializing USB wire abstraction.\n"); 98 103 int opResult = usb_hc_connection_initialize_from_device( 99 &hub_ info->connection, hub_info->usb_device->ddf_dev);104 &hub_dev->connection, hub_dev->usb_device->ddf_dev); 100 105 if (opResult != EOK) { 101 106 usb_log_error("Could not initialize connection to device: %s\n", 102 107 str_error(opResult)); 103 free(hub_info);104 108 return opResult; 105 109 } … … 110 114 usb_log_error("Could not set hub configuration: %s\n", 111 115 str_error(opResult)); 112 free(hub_info);113 116 return opResult; 114 117 } 115 118 116 / /get port count and create attached_devs117 opResult = usb_hub_process_hub_specific_info(hub_ info);119 /* Get port count and create attached_devices. */ 120 opResult = usb_hub_process_hub_specific_info(hub_dev); 118 121 if (opResult != EOK) { 119 122 usb_log_error("Could process hub specific info, %s\n", 120 123 str_error(opResult)); 121 free(hub_info);122 124 return opResult; 123 125 } 124 126 127 /* Create hub control function. */ 125 128 usb_log_debug("Creating DDF function '" HUB_FNC_NAME "'.\n"); 126 ddf_fun_t *hub_fun = ddf_fun_create(hub_info->usb_device->ddf_dev,129 hub_dev->hub_fun = ddf_fun_create(hub_dev->usb_device->ddf_dev, 127 130 fun_exposed, HUB_FNC_NAME); 128 if (hub_ fun == NULL) {131 if (hub_dev->hub_fun == NULL) { 129 132 usb_log_error("Failed to create hub function.\n"); 130 free(hub_info);131 133 return ENOMEM; 132 134 } 133 135 134 opResult = ddf_fun_bind(hub_fun); 136 /* Bind hub control function. */ 137 opResult = ddf_fun_bind(hub_dev->hub_fun); 135 138 if (opResult != EOK) { 136 139 usb_log_error("Failed to bind hub function: %s.\n", 137 140 str_error(opResult)); 138 free(hub_info); 139 ddf_fun_destroy(hub_fun); 141 ddf_fun_destroy(hub_dev->hub_fun); 140 142 return opResult; 141 143 } 142 144 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); 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); 149 153 usb_log_error("Failed to create polling fibril: %s.\n", 150 154 str_error(opResult)); 151 155 return opResult; 152 156 } 157 hub_dev->running = true; 153 158 usb_log_info("Controlling hub '%s' (%zu ports).\n", 154 hub_info->usb_device->ddf_dev->name, hub_info->port_count); 155 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"); 156 215 return EOK; 157 216 } … … 162 221 * @param change_bitmap Bitmap of changed ports. 163 222 * @param change_bitmap_size Size of the bitmap in bytes. 164 * @param arg Custom argument, points to @c usb_hub_ info_t.223 * @param arg Custom argument, points to @c usb_hub_dev_t. 165 224 * @return Whether to continue polling. 166 225 */ … … 169 228 { 170 229 usb_log_debug("hub_port_changes_callback\n"); 171 usb_hub_ info_t *hub = arg;230 usb_hub_dev_t *hub = arg; 172 231 assert(hub); 173 232 … … 184 243 185 244 /* N + 1 bit indicates change on port N */ 186 size_t port = 1;187 for (; port < hub->port_count + 1; port++) {188 const bool change = (change_bitmap[ port / 8] >> (port % 8)) & 1;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; 189 248 if (change) { 190 249 usb_hub_port_process_interrupt(&hub->ports[port], hub); … … 195 254 /*----------------------------------------------------------------------------*/ 196 255 /** 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 256 * Load hub-specific information into hub_dev structure and process if needed 223 257 * 224 258 * Read port count and initialize structures holding per port information. … … 226 260 * This function is hub-specific and should be run only after the hub is 227 261 * configured using usb_set_first_configuration function. 228 * @param hub_ infohub representation262 * @param hub_dev hub representation 229 263 * @return error code 230 264 */ 231 static int usb_hub_process_hub_specific_info(usb_hub_ info_t *hub_info)232 { 233 assert(hub_ info);265 static int usb_hub_process_hub_specific_info(usb_hub_dev_t *hub_dev) 266 { 267 assert(hub_dev); 234 268 235 269 /* Get hub descriptor. */ 236 270 usb_log_debug("Retrieving descriptor\n"); 237 usb_pipe_t *control_pipe = &hub_ info->usb_device->ctrl_pipe;271 usb_pipe_t *control_pipe = &hub_dev->usb_device->ctrl_pipe; 238 272 239 273 usb_hub_descriptor_header_t descriptor; … … 242 276 USB_REQUEST_TYPE_CLASS, USB_REQUEST_RECIPIENT_DEVICE, 243 277 USB_DESCTYPE_HUB, 0, 0, &descriptor, 244 sizeof(usb_hub_descriptor_ t), &received_size);278 sizeof(usb_hub_descriptor_header_t), &received_size); 245 279 if (opResult != EOK) { 246 280 usb_log_error("Failed to receive hub descriptor: %s.\n", … … 250 284 251 285 usb_log_debug("Setting port count to %d.\n", descriptor.port_count); 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) { 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) { 258 290 return ENOMEM; 259 291 } 260 292 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 =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 = 267 299 !(descriptor.characteristics & HUB_CHAR_NO_POWER_SWITCH_FLAG); 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 } 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; 287 324 } 288 325 } 289 } else {290 usb_log_debug("Power not switched, ports always powered\n");291 326 } 292 327 return EOK; … … 314 349 } 315 350 316 // TODO: Make sure that there is enough data and the cast is correct 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 317 359 usb_standard_configuration_descriptor_t *config_descriptor 318 360 = (usb_standard_configuration_descriptor_t *) … … 337 379 * 338 380 * This means either to power off the hub or power it on. 339 * @param hub_ infohub instance381 * @param hub_dev hub instance 340 382 * @param status hub status bitmask 341 383 * @return error code 342 384 */ 343 static void usb_hub_over_current(const usb_hub_ info_t *hub_info,385 static void usb_hub_over_current(const usb_hub_dev_t *hub_dev, 344 386 usb_hub_status_t status) 345 387 { … … 348 390 usb_log_warning("Detected hub over-current condition, " 349 391 "all ports should be powered off."); 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 } 363 } 364 } 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 } 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; 410 } 411 } 412 374 413 } 375 414 /*----------------------------------------------------------------------------*/ … … 378 417 * 379 418 * The change can be either in the over-current condition or local-power change. 380 * @param hub_ infohub instance381 */ 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);419 * @param hub_dev hub instance 420 */ 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); 386 425 usb_log_debug("Global interrupt on a hub\n"); 387 usb_pipe_t *control_pipe = &hub_ info->usb_device->ctrl_pipe;426 usb_pipe_t *control_pipe = &hub_dev->usb_device->ctrl_pipe; 388 427 389 428 usb_hub_status_t status; … … 406 445 /* Handle status changes */ 407 446 if (status & USB_HUB_STATUS_C_OVER_CURRENT) { 408 usb_hub_over_current(hub_info, status); 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 } 409 457 } 410 458 … … 423 471 * Just ACK the change. 424 472 */ 425 const int opResult = usb_request_clear_feature(473 const int ret = usb_request_clear_feature( 426 474 control_pipe, USB_REQUEST_TYPE_CLASS, 427 475 USB_REQUEST_RECIPIENT_DEVICE, 428 476 USB_HUB_FEATURE_C_HUB_LOCAL_POWER, 0); 429 477 if (opResult != EOK) { 430 usb_log_error( 431 "Failed to clear hub power change flag: %s.\n", 432 str_error(opResult)); 478 usb_log_error("Failed to clear hub power change " 479 "flag: %s.\n", str_error(ret)); 433 480 } 434 481 } … … 438 485 * callback called from hub polling fibril when the fibril terminates 439 486 * 440 * Should perform a cleanup - deletes hub_info.487 * Does not perform cleanup, just marks the hub as not running. 441 488 * @param device usb device afected 442 489 * @param was_error indicates that the fibril is stoped due to an error 443 * @param data pointer to usb_hub_ info_t structure490 * @param data pointer to usb_hub_dev_t structure 444 491 */ 445 492 static void usb_hub_polling_terminated_callback(usb_device_t *device, 446 493 bool was_error, void *data) 447 494 { 448 usb_hub_ info_t *hub = data;495 usb_hub_dev_t *hub = data; 449 496 assert(hub); 450 497 … … 460 507 */ 461 508 if (hub->pending_ops_count > 0) { 462 size_t port; 463 for (port = 0; port < hub->port_count; port++) { 509 for (size_t port = 0; port < hub->port_count; ++port) { 464 510 usb_hub_port_reset_fail(&hub->ports[port]); 465 511 } … … 471 517 } 472 518 fibril_mutex_unlock(&hub->pending_ops_mutex); 473 474 usb_device_destroy(hub->usb_device); 475 476 free(hub->ports); 477 free(hub); 519 hub->running = false; 478 520 } 479 521 /**
Note:
See TracChangeset
for help on using the changeset viewer.