Changes in uspace/drv/bus/usb/usbhub/usbhub.c [065064e6:32cd37f] in mainline
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
uspace/drv/bus/usb/usbhub/usbhub.c
r065064e6 r32cd37f 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 static int usb_hub_process_hub_specific_info(usb_hub_ dev_t *hub_dev);72 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, 73 73 usb_hub_status_t status); 74 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); 75 75 static void usb_hub_polling_terminated_callback(usb_device_t *device, 76 76 bool was_error, void *data); 77 77 78 /** 78 79 * Initialize hub device driver fibril … … 83 84 * @return error code 84 85 */ 85 int usb_hub_device_gone(usb_device_t *usb_dev) 86 { 87 assert(usb_dev); 88 usb_hub_dev_t *hub = usb_dev->driver_data; 89 assert(hub); 90 unsigned tries = 10; 91 while (hub->running) { 92 async_usleep(100000); 93 if (!tries--) { 94 usb_log_error("Can't remove hub, still running.\n"); 95 return EINPROGRESS; 96 } 97 } 98 99 assert(!hub->running); 100 101 for (size_t port = 0; port < hub->port_count; ++port) { 102 if (hub->ports[port].attached_device.fun) { 103 const int ret = 104 usb_hub_port_fini(&hub->ports[port], hub); 105 if (ret != EOK) 106 return ret; 107 } 108 } 109 free(hub->ports); 110 111 const int ret = ddf_fun_unbind(hub->hub_fun); 112 if (ret != EOK) { 113 usb_log_error("Failed to unbind '%s' function: %s.\n", 114 HUB_FNC_NAME, str_error(ret)); 115 return ret; 116 } 117 ddf_fun_destroy(hub->hub_fun); 118 119 usb_log_info("USB hub driver, stopped and cleaned.\n"); 120 return EOK; 121 } 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) 86 int usb_hub_add_device(usb_device_t *usb_dev) 132 87 { 133 88 assert(usb_dev); 134 89 /* Create driver soft-state structure */ 135 usb_hub_ dev_t *hub_dev = usb_hub_dev_create(usb_dev);136 if (hub_ dev== NULL) {90 usb_hub_info_t *hub_info = usb_hub_info_create(usb_dev); 91 if (hub_info == NULL) { 137 92 usb_log_error("Failed to create hun driver structure.\n"); 138 93 return ENOMEM; … … 142 97 usb_log_debug("Initializing USB wire abstraction.\n"); 143 98 int opResult = usb_hc_connection_initialize_from_device( 144 &hub_ dev->connection, hub_dev->usb_device->ddf_dev);99 &hub_info->connection, hub_info->usb_device->ddf_dev); 145 100 if (opResult != EOK) { 146 101 usb_log_error("Could not initialize connection to device: %s\n", 147 102 str_error(opResult)); 148 free(hub_ dev);103 free(hub_info); 149 104 return opResult; 150 105 } … … 155 110 usb_log_error("Could not set hub configuration: %s\n", 156 111 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);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); 163 118 if (opResult != EOK) { 164 119 usb_log_error("Could process hub specific info, %s\n", 165 120 str_error(opResult)); 166 free(hub_ dev);121 free(hub_info); 167 122 return opResult; 168 123 } 169 124 170 125 usb_log_debug("Creating DDF function '" HUB_FNC_NAME "'.\n"); 171 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, 172 127 fun_exposed, HUB_FNC_NAME); 173 if (hub_ dev->hub_fun == NULL) {128 if (hub_fun == NULL) { 174 129 usb_log_error("Failed to create hub function.\n"); 175 free(hub_ dev);130 free(hub_info); 176 131 return ENOMEM; 177 132 } 178 133 179 opResult = ddf_fun_bind(hub_ dev->hub_fun);134 opResult = ddf_fun_bind(hub_fun); 180 135 if (opResult != EOK) { 181 136 usb_log_error("Failed to bind hub function: %s.\n", 182 137 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); 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); 196 149 usb_log_error("Failed to create polling fibril: %s.\n", 197 150 str_error(opResult)); 198 151 return opResult; 199 152 } 200 hub_dev->running = true;201 153 usb_log_info("Controlling hub '%s' (%zu ports).\n", 202 hub_ dev->usb_device->ddf_dev->name, hub_dev->port_count);154 hub_info->usb_device->ddf_dev->name, hub_info->port_count); 203 155 204 156 return EOK; … … 210 162 * @param change_bitmap Bitmap of changed ports. 211 163 * @param change_bitmap_size Size of the bitmap in bytes. 212 * @param arg Custom argument, points to @c usb_hub_ dev_t.164 * @param arg Custom argument, points to @c usb_hub_info_t. 213 165 * @return Whether to continue polling. 214 166 */ … … 217 169 { 218 170 usb_log_debug("hub_port_changes_callback\n"); 219 usb_hub_ dev_t *hub = arg;171 usb_hub_info_t *hub = arg; 220 172 assert(hub); 221 173 … … 232 184 233 185 /* N + 1 bit indicates change on port N */ 234 for (size_t port = 0; port < hub->port_count + 1; port++) {235 const size_t bit = port + 1;236 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; 237 189 if (change) { 238 190 usb_hub_port_process_interrupt(&hub->ports[port], hub); … … 243 195 /*----------------------------------------------------------------------------*/ 244 196 /** 245 * create usb_hub_ dev_t structure197 * create usb_hub_info_t structure 246 198 * 247 199 * Does only basic copying of known information into new structure. 248 200 * @param usb_dev usb device structure 249 * @return basic usb_hub_ dev_t structure250 */ 251 static usb_hub_ dev_t * usb_hub_dev_create(usb_device_t *usb_dev)201 * @return basic usb_hub_info_t structure 202 */ 203 static usb_hub_info_t * usb_hub_info_create(usb_device_t *usb_dev) 252 204 { 253 205 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) 206 usb_hub_info_t *info = malloc(sizeof(usb_hub_info_t)); 207 if (!info) 257 208 return NULL; 258 209 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 * Load hub-specific information into hub_ devstructure and process if needed210 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 272 223 * 273 224 * Read port count and initialize structures holding per port information. … … 275 226 * This function is hub-specific and should be run only after the hub is 276 227 * configured using usb_set_first_configuration function. 277 * @param hub_ devhub representation228 * @param hub_info hub representation 278 229 * @return error code 279 230 */ 280 static int usb_hub_process_hub_specific_info(usb_hub_ dev_t *hub_dev)281 { 282 assert(hub_ dev);231 static int usb_hub_process_hub_specific_info(usb_hub_info_t *hub_info) 232 { 233 assert(hub_info); 283 234 284 235 /* Get hub descriptor. */ 285 236 usb_log_debug("Retrieving descriptor\n"); 286 usb_pipe_t *control_pipe = &hub_ dev->usb_device->ctrl_pipe;237 usb_pipe_t *control_pipe = &hub_info->usb_device->ctrl_pipe; 287 238 288 239 usb_hub_descriptor_header_t descriptor; … … 299 250 300 251 usb_log_debug("Setting port count to %d.\n", descriptor.port_count); 301 hub_dev->port_count = descriptor.port_count; 302 303 hub_dev->ports = calloc(hub_dev->port_count, sizeof(usb_hub_port_t)); 304 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) { 305 258 return ENOMEM; 306 259 } 307 260 308 for (size_t port = 0; port < hub_dev->port_count; ++port) {309 usb_hub_port_init(310 &hub_dev->ports[port], port + 1, control_pipe);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); 311 264 } 312 265 … … 318 271 & HUB_CHAR_POWER_PER_PORT_FLAG; 319 272 320 for ( size_t port = 0; port < hub_dev->port_count; ++port) {273 for (port = 1; port <= hub_info->port_count; ++port) { 321 274 usb_log_debug("Powering port %zu.\n", port); 322 275 opResult = usb_hub_port_set_feature( 323 &hub_ dev->ports[port], USB_HUB_FEATURE_PORT_POWER);276 &hub_info->ports[port], USB_HUB_FEATURE_PORT_POWER); 324 277 if (opResult != EOK) { 325 278 usb_log_error("Cannot power on port %zu: %s.\n", … … 361 314 } 362 315 363 if (usb_device->descriptors.configuration_size 364 < sizeof(usb_standard_configuration_descriptor_t)) { 365 usb_log_error("Configuration descriptor is not big enough" 366 " to fit standard configuration descriptor.\n"); 367 return EOVERFLOW; 368 } 369 370 // TODO: Make sure that the cast is correct 316 // TODO: Make sure that there is enough data and the cast is correct 371 317 usb_standard_configuration_descriptor_t *config_descriptor 372 318 = (usb_standard_configuration_descriptor_t *) … … 391 337 * 392 338 * This means either to power off the hub or power it on. 393 * @param hub_ devhub instance339 * @param hub_info hub instance 394 340 * @param status hub status bitmask 395 341 * @return error code 396 342 */ 397 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, 398 344 usb_hub_status_t status) 399 345 { … … 405 351 /* Over-current condition is gone, it is safe to turn the 406 352 * ports on. */ 407 for (size_t port = 0; port < hub_dev->port_count; ++port) { 353 size_t port; 354 for (port = 1; port <= hub_info->port_count; ++port) { 408 355 const int opResult = usb_hub_port_set_feature( 409 &hub_dev->ports[port], USB_HUB_FEATURE_PORT_POWER); 410 // TODO: consider power policy here 356 &hub_info->ports[port], USB_HUB_FEATURE_PORT_POWER); 411 357 if (opResult != EOK) { 412 358 usb_log_warning( … … 418 364 } 419 365 const int opResult = usb_request_clear_feature( 420 &hub_ dev->usb_device->ctrl_pipe, USB_REQUEST_TYPE_CLASS,366 &hub_info->usb_device->ctrl_pipe, USB_REQUEST_TYPE_CLASS, 421 367 USB_REQUEST_RECIPIENT_DEVICE, 422 368 USB_HUB_FEATURE_C_HUB_LOCAL_POWER, 0); … … 432 378 * 433 379 * The change can be either in the over-current condition or local-power change. 434 * @param hub_ devhub instance435 */ 436 static void usb_hub_global_interrupt(const usb_hub_ dev_t *hub_dev)437 { 438 assert(hub_ dev);439 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); 440 386 usb_log_debug("Global interrupt on a hub\n"); 441 usb_pipe_t *control_pipe = &hub_ dev->usb_device->ctrl_pipe;387 usb_pipe_t *control_pipe = &hub_info->usb_device->ctrl_pipe; 442 388 443 389 usb_hub_status_t status; … … 460 406 /* Handle status changes */ 461 407 if (status & USB_HUB_STATUS_C_OVER_CURRENT) { 462 usb_hub_over_current(hub_ dev, status);408 usb_hub_over_current(hub_info, status); 463 409 } 464 410 … … 492 438 * callback called from hub polling fibril when the fibril terminates 493 439 * 494 * Does not perform cleanup, just marks the hub as not running.440 * Should perform a cleanup - deletes hub_info. 495 441 * @param device usb device afected 496 442 * @param was_error indicates that the fibril is stoped due to an error 497 * @param data pointer to usb_hub_ dev_t structure443 * @param data pointer to usb_hub_info_t structure 498 444 */ 499 445 static void usb_hub_polling_terminated_callback(usb_device_t *device, 500 446 bool was_error, void *data) 501 447 { 502 usb_hub_ dev_t *hub = data;448 usb_hub_info_t *hub = data; 503 449 assert(hub); 504 450 … … 514 460 */ 515 461 if (hub->pending_ops_count > 0) { 516 for (size_t port = 0; port < hub->port_count; ++port) { 462 size_t port; 463 for (port = 0; port < hub->port_count; port++) { 517 464 usb_hub_port_reset_fail(&hub->ports[port]); 518 465 } … … 524 471 } 525 472 fibril_mutex_unlock(&hub->pending_ops_mutex); 526 hub->running = false; 473 474 usb_device_destroy(hub->usb_device); 475 476 free(hub->ports); 477 free(hub); 527 478 } 528 479 /**
Note:
See TracChangeset
for help on using the changeset viewer.