Changes in uspace/lib/usb/src/devdrv.c [3f2af64:4ede178] in mainline
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
uspace/lib/usb/src/devdrv.c
r3f2af64 r4ede178 72 72 } 73 73 74 /** Log out of memory error on given device. 75 * 76 * @param dev Device causing the trouble. 77 */ 78 static void usb_log_oom(ddf_dev_t *dev) 79 { 80 usb_log_error("Out of memory when adding device `%s'.\n", 81 dev->name); 82 } 83 74 84 /** Count number of pipes the driver expects. 75 85 * … … 98 108 */ 99 109 static int initialize_other_pipes(usb_endpoint_description_t **endpoints, 100 usb_device_t *dev, int alternate_setting) 101 { 102 if (endpoints == NULL) { 103 dev->pipes = NULL; 104 dev->pipes_count = 0; 110 usb_device_t *dev) 111 { 112 int rc; 113 114 size_t pipe_count = count_other_pipes(endpoints); 115 if (pipe_count == 0) { 105 116 return EOK; 106 117 } 107 118 108 usb_endpoint_mapping_t *pipes; 109 size_t pipes_count; 110 111 int rc = usb_device_create_pipes(dev->ddf_dev, &dev->wire, endpoints, 119 dev->pipes = malloc(sizeof(usb_endpoint_mapping_t) * pipe_count); 120 if (dev->pipes == NULL) { 121 usb_log_oom(dev->ddf_dev); 122 return ENOMEM; 123 } 124 125 size_t i; 126 127 /* Initialize to NULL first for rollback purposes. */ 128 for (i = 0; i < pipe_count; i++) { 129 dev->pipes[i].pipe = NULL; 130 } 131 132 for (i = 0; i < pipe_count; i++) { 133 dev->pipes[i].pipe = malloc(sizeof(usb_pipe_t)); 134 if (dev->pipes[i].pipe == NULL) { 135 usb_log_oom(dev->ddf_dev); 136 rc = ENOMEM; 137 goto rollback; 138 } 139 140 dev->pipes[i].description = endpoints[i]; 141 dev->pipes[i].interface_no = dev->interface_no; 142 dev->pipes[i].interface_setting = 0; 143 } 144 145 rc = usb_pipe_initialize_from_configuration(dev->pipes, pipe_count, 112 146 dev->descriptors.configuration, dev->descriptors.configuration_size, 113 dev->interface_no, alternate_setting, 114 &pipes, &pipes_count); 115 116 if (rc != EOK) { 117 return rc; 118 } 119 120 dev->pipes = pipes; 121 dev->pipes_count = pipes_count; 147 &dev->wire); 148 if (rc != EOK) { 149 usb_log_error("Failed initializing USB endpoints: %s.\n", 150 str_error(rc)); 151 goto rollback; 152 } 153 154 /* Register the endpoints. */ 155 usb_hc_connection_t hc_conn; 156 rc = usb_hc_connection_initialize_from_device(&hc_conn, dev->ddf_dev); 157 if (rc != EOK) { 158 usb_log_error( 159 "Failed initializing connection to host controller: %s.\n", 160 str_error(rc)); 161 goto rollback; 162 } 163 rc = usb_hc_connection_open(&hc_conn); 164 if (rc != EOK) { 165 usb_log_error("Failed to connect to host controller: %s.\n", 166 str_error(rc)); 167 goto rollback; 168 } 169 for (i = 0; i < pipe_count; i++) { 170 if (dev->pipes[i].present) { 171 rc = usb_pipe_register(dev->pipes[i].pipe, 172 dev->pipes[i].descriptor->poll_interval, 173 &hc_conn); 174 /* Ignore error when operation not supported by HC. */ 175 if ((rc != EOK) && (rc != ENOTSUP)) { 176 /* FIXME: what shall we do? */ 177 dev->pipes[i].present = false; 178 free(dev->pipes[i].pipe); 179 dev->pipes[i].pipe = NULL; 180 } 181 } 182 } 183 /* Ignoring errors here. */ 184 usb_hc_connection_close(&hc_conn); 185 186 dev->pipes_count = pipe_count; 187 188 return EOK; 189 190 rollback: 191 for (i = 0; i < pipe_count; i++) { 192 if (dev->pipes[i].pipe != NULL) { 193 free(dev->pipes[i].pipe); 194 } 195 } 196 free(dev->pipes); 197 198 return rc; 199 } 200 201 /** Initialize all endpoint pipes. 202 * 203 * @param drv The driver. 204 * @param dev The device to be initialized. 205 * @return Error code. 206 */ 207 static int initialize_pipes(usb_device_t *dev) 208 { 209 int rc; 210 211 rc = usb_device_connection_initialize_from_device(&dev->wire, 212 dev->ddf_dev); 213 if (rc != EOK) { 214 usb_log_error( 215 "Failed initializing connection on device `%s'. %s.\n", 216 dev->ddf_dev->name, str_error(rc)); 217 return rc; 218 } 219 220 rc = usb_pipe_initialize_default_control(&dev->ctrl_pipe, 221 &dev->wire); 222 if (rc != EOK) { 223 usb_log_error("Failed to initialize default control pipe " \ 224 "on device `%s': %s.\n", 225 dev->ddf_dev->name, str_error(rc)); 226 return rc; 227 } 228 229 rc = usb_pipe_probe_default_control(&dev->ctrl_pipe); 230 if (rc != EOK) { 231 usb_log_error( 232 "Probing default control pipe on device `%s' failed: %s.\n", 233 dev->ddf_dev->name, str_error(rc)); 234 return rc; 235 } 236 237 /* Get our interface. */ 238 dev->interface_no = usb_device_get_assigned_interface(dev->ddf_dev); 239 240 /* 241 * We will do some querying of the device, it is worth to prepare 242 * the long transfer. 243 */ 244 rc = usb_pipe_start_long_transfer(&dev->ctrl_pipe); 245 if (rc != EOK) { 246 usb_log_error("Failed to start transfer: %s.\n", 247 str_error(rc)); 248 return rc; 249 } 250 251 /* Get the device descriptor. */ 252 rc = usb_request_get_device_descriptor(&dev->ctrl_pipe, 253 &dev->descriptors.device); 254 if (rc != EOK) { 255 usb_pipe_end_long_transfer(&dev->ctrl_pipe); 256 usb_log_error("Failed to retrieve device descriptor: %s.\n", 257 str_error(rc)); 258 return rc; 259 } 260 261 /* Get the full configuration descriptor. */ 262 rc = usb_request_get_full_configuration_descriptor_alloc( 263 &dev->ctrl_pipe, 0, (void **) &dev->descriptors.configuration, 264 &dev->descriptors.configuration_size); 265 if (rc != EOK) { 266 usb_pipe_end_long_transfer(&dev->ctrl_pipe); 267 usb_log_error("Failed retrieving configuration descriptor: %s. %s\n", 268 dev->ddf_dev->name, str_error(rc)); 269 return rc; 270 } 271 272 if (driver->endpoints != NULL) { 273 rc = initialize_other_pipes(driver->endpoints, dev); 274 } 275 276 usb_pipe_end_long_transfer(&dev->ctrl_pipe); 277 278 /* Rollback actions. */ 279 if (rc != EOK) { 280 if (dev->descriptors.configuration != NULL) { 281 free(dev->descriptors.configuration); 282 } 283 } 284 285 return rc; 286 } 287 288 /** Count number of alternate settings of a interface. 289 * 290 * @param config_descr Full configuration descriptor. 291 * @param config_descr_size Size of @p config_descr in bytes. 292 * @param interface_no Interface number. 293 * @return Number of alternate interfaces for @p interface_no interface. 294 */ 295 static size_t count_alternate_interfaces(uint8_t *config_descr, 296 size_t config_descr_size, int interface_no) 297 { 298 assert(config_descr != NULL); 299 usb_dp_parser_t dp_parser = { 300 .nesting = usb_dp_standard_descriptor_nesting 301 }; 302 usb_dp_parser_data_t dp_data = { 303 .data = config_descr, 304 .size = config_descr_size, 305 .arg = NULL 306 }; 307 308 size_t alternate_count = 0; 309 310 uint8_t *iface_ptr = usb_dp_get_nested_descriptor(&dp_parser, 311 &dp_data, config_descr); 312 while (iface_ptr != NULL) { 313 usb_standard_interface_descriptor_t *iface 314 = (usb_standard_interface_descriptor_t *) iface_ptr; 315 if (iface->descriptor_type == USB_DESCTYPE_INTERFACE) { 316 if (iface->interface_number == interface_no) { 317 alternate_count++; 318 } 319 } 320 iface_ptr = usb_dp_get_sibling_descriptor(&dp_parser, &dp_data, 321 config_descr, iface_ptr); 322 } 323 324 return alternate_count; 325 } 326 327 /** Initialize structures related to alternate interfaces. 328 * 329 * @param dev Device where alternate settings shall be initialized. 330 * @return Error code. 331 */ 332 static int initialize_alternate_interfaces(usb_device_t *dev) 333 { 334 if (dev->interface_no < 0) { 335 dev->alternate_interfaces = NULL; 336 return EOK; 337 } 338 339 usb_alternate_interfaces_t *alternates 340 = malloc(sizeof(usb_alternate_interfaces_t)); 341 342 if (alternates == NULL) { 343 return ENOMEM; 344 } 345 346 alternates->alternative_count 347 = count_alternate_interfaces(dev->descriptors.configuration, 348 dev->descriptors.configuration_size, dev->interface_no); 349 350 if (alternates->alternative_count == 0) { 351 free(alternates); 352 return ENOENT; 353 } 354 355 alternates->alternatives = malloc(alternates->alternative_count 356 * sizeof(usb_alternate_interface_descriptors_t)); 357 if (alternates->alternatives == NULL) { 358 free(alternates); 359 return ENOMEM; 360 } 361 362 alternates->current = 0; 363 364 usb_dp_parser_t dp_parser = { 365 .nesting = usb_dp_standard_descriptor_nesting 366 }; 367 usb_dp_parser_data_t dp_data = { 368 .data = dev->descriptors.configuration, 369 .size = dev->descriptors.configuration_size, 370 .arg = NULL 371 }; 372 373 usb_alternate_interface_descriptors_t *cur_alt_iface 374 = &alternates->alternatives[0]; 375 376 uint8_t *iface_ptr = usb_dp_get_nested_descriptor(&dp_parser, 377 &dp_data, dp_data.data); 378 while (iface_ptr != NULL) { 379 usb_standard_interface_descriptor_t *iface 380 = (usb_standard_interface_descriptor_t *) iface_ptr; 381 if ((iface->descriptor_type != USB_DESCTYPE_INTERFACE) 382 || (iface->interface_number != dev->interface_no)) { 383 iface_ptr = usb_dp_get_sibling_descriptor(&dp_parser, 384 &dp_data, 385 dp_data.data, iface_ptr); 386 continue; 387 } 388 389 cur_alt_iface->interface = iface; 390 cur_alt_iface->nested_descriptors = iface_ptr + sizeof(*iface); 391 392 /* Find next interface to count size of nested descriptors. */ 393 iface_ptr = usb_dp_get_sibling_descriptor(&dp_parser, &dp_data, 394 dp_data.data, iface_ptr); 395 if (iface_ptr == NULL) { 396 uint8_t *next = dp_data.data + dp_data.size; 397 cur_alt_iface->nested_descriptors_size 398 = next - cur_alt_iface->nested_descriptors; 399 } else { 400 cur_alt_iface->nested_descriptors_size 401 = iface_ptr - cur_alt_iface->nested_descriptors; 402 } 403 404 cur_alt_iface++; 405 } 406 407 dev->alternate_interfaces = alternates; 122 408 123 409 return EOK; … … 139 425 int rc; 140 426 141 usb_device_t *dev = NULL; 142 const char *err_msg = NULL; 143 rc = usb_device_create(gen_dev, driver->endpoints, &dev, &err_msg); 144 if (rc != EOK) { 145 usb_log_error("USB device `%s' creation failed (%s): %s.\n", 146 gen_dev->name, err_msg, str_error(rc)); 147 return rc; 148 } 427 usb_device_t *dev = malloc(sizeof(usb_device_t)); 428 if (dev == NULL) { 429 usb_log_error("Out of memory when adding device `%s'.\n", 430 gen_dev->name); 431 return ENOMEM; 432 } 433 434 435 dev->ddf_dev = gen_dev; 436 dev->ddf_dev->driver_data = dev; 437 dev->driver_data = NULL; 438 dev->descriptors.configuration = NULL; 439 440 dev->pipes_count = 0; 441 dev->pipes = NULL; 442 443 rc = initialize_pipes(dev); 444 if (rc != EOK) { 445 free(dev); 446 return rc; 447 } 448 449 (void) initialize_alternate_interfaces(dev); 149 450 150 451 return driver->ops->add_device(dev); … … 158 459 static int destroy_current_pipes(usb_device_t *dev) 159 460 { 160 int rc = usb_device_destroy_pipes(dev->ddf_dev, 161 dev->pipes, dev->pipes_count); 162 if (rc != EOK) { 163 return rc; 164 } 165 461 size_t i; 462 int rc; 463 464 /* TODO: this shall be done under some device mutex. */ 465 466 /* First check that no session is opened. */ 467 for (i = 0; i < dev->pipes_count; i++) { 468 if (usb_pipe_is_session_started(dev->pipes[i].pipe)) { 469 return EBUSY; 470 } 471 } 472 473 /* Prepare connection to HC. */ 474 usb_hc_connection_t hc_conn; 475 rc = usb_hc_connection_initialize_from_device(&hc_conn, dev->ddf_dev); 476 if (rc != EOK) { 477 return rc; 478 } 479 rc = usb_hc_connection_open(&hc_conn); 480 if (rc != EOK) { 481 return rc; 482 } 483 484 /* Destroy the pipes. */ 485 for (i = 0; i < dev->pipes_count; i++) { 486 usb_pipe_unregister(dev->pipes[i].pipe, &hc_conn); 487 free(dev->pipes[i].pipe); 488 } 489 490 usb_hc_connection_close(&hc_conn); 491 492 free(dev->pipes); 166 493 dev->pipes = NULL; 167 494 dev->pipes_count = 0; … … 180 507 * with usb_pipe_initialize_from_configuration(). 181 508 * 182 * @warning This is a wrapper function that does several operations that183 * can fail and that cannot be rollbacked easily. That means that a failure184 * during the SET_INTERFACE request would result in having a device with185 * no pipes at all (except the default control one). That is because the old186 * pipes needs to be unregistered at HC first and the new ones could not187 * be created.188 *189 509 * @param dev USB device. 190 510 * @param alternate_setting Alternate setting to choose. … … 201 521 int rc; 202 522 523 /* TODO: more transactional behavior. */ 524 203 525 /* Destroy existing pipes. */ 204 526 rc = destroy_current_pipes(dev); … … 215 537 216 538 /* Create new pipes. */ 217 rc = initialize_other_pipes(endpoints, dev , (int) alternate_setting);539 rc = initialize_other_pipes(endpoints, dev); 218 540 219 541 return rc; 220 }221 222 /** Retrieve basic descriptors from the device.223 *224 * @param[in] ctrl_pipe Control endpoint pipe.225 * @param[out] descriptors Where to store the descriptors.226 * @return Error code.227 */228 int usb_device_retrieve_descriptors(usb_pipe_t *ctrl_pipe,229 usb_device_descriptors_t *descriptors)230 {231 assert(descriptors != NULL);232 233 descriptors->configuration = NULL;234 235 int rc;236 237 /* It is worth to start a long transfer. */238 rc = usb_pipe_start_long_transfer(ctrl_pipe);239 if (rc != EOK) {240 return rc;241 }242 243 /* Get the device descriptor. */244 rc = usb_request_get_device_descriptor(ctrl_pipe, &descriptors->device);245 if (rc != EOK) {246 goto leave;247 }248 249 /* Get the full configuration descriptor. */250 rc = usb_request_get_full_configuration_descriptor_alloc(251 ctrl_pipe, 0, (void **) &descriptors->configuration,252 &descriptors->configuration_size);253 254 leave:255 usb_pipe_end_long_transfer(ctrl_pipe);256 257 return rc;258 }259 260 /** Create pipes for a device.261 *262 * This is more or less a wrapper that does following actions:263 * - allocate and initialize pipes264 * - map endpoints to the pipes based on the descriptions265 * - registers endpoints with the host controller266 *267 * @param[in] dev Generic DDF device backing the USB one.268 * @param[in] wire Initialized backing connection to the host controller.269 * @param[in] endpoints Endpoints description, NULL terminated.270 * @param[in] config_descr Configuration descriptor of active configuration.271 * @param[in] config_descr_size Size of @p config_descr in bytes.272 * @param[in] interface_no Interface to map from.273 * @param[in] interface_setting Interface setting (default is usually 0).274 * @param[out] pipes_ptr Where to store array of created pipes275 * (not NULL terminated).276 * @param[out] pipes_count_ptr Where to store number of pipes277 * (set to if you wish to ignore the count).278 * @return Error code.279 */280 int usb_device_create_pipes(ddf_dev_t *dev, usb_device_connection_t *wire,281 usb_endpoint_description_t **endpoints,282 uint8_t *config_descr, size_t config_descr_size,283 int interface_no, int interface_setting,284 usb_endpoint_mapping_t **pipes_ptr, size_t *pipes_count_ptr)285 {286 assert(dev != NULL);287 assert(wire != NULL);288 assert(endpoints != NULL);289 assert(config_descr != NULL);290 assert(config_descr_size > 0);291 assert(pipes_ptr != NULL);292 293 size_t i;294 int rc;295 296 size_t pipe_count = count_other_pipes(endpoints);297 if (pipe_count == 0) {298 *pipes_ptr = NULL;299 return EOK;300 }301 302 usb_endpoint_mapping_t *pipes303 = malloc(sizeof(usb_endpoint_mapping_t) * pipe_count);304 if (pipes == NULL) {305 return ENOMEM;306 }307 308 /* Initialize to NULL to allow smooth rollback. */309 for (i = 0; i < pipe_count; i++) {310 pipes[i].pipe = NULL;311 }312 313 /* Now allocate and fully initialize. */314 for (i = 0; i < pipe_count; i++) {315 pipes[i].pipe = malloc(sizeof(usb_pipe_t));316 if (pipes[i].pipe == NULL) {317 rc = ENOMEM;318 goto rollback_free_only;319 }320 pipes[i].description = endpoints[i];321 pipes[i].interface_no = interface_no;322 pipes[i].interface_setting = interface_setting;323 }324 325 /* Find the mapping from configuration descriptor. */326 rc = usb_pipe_initialize_from_configuration(pipes, pipe_count,327 config_descr, config_descr_size, wire);328 if (rc != EOK) {329 goto rollback_free_only;330 }331 332 /* Register the endpoints with HC. */333 usb_hc_connection_t hc_conn;334 rc = usb_hc_connection_initialize_from_device(&hc_conn, dev);335 if (rc != EOK) {336 goto rollback_free_only;337 }338 339 rc = usb_hc_connection_open(&hc_conn);340 if (rc != EOK) {341 goto rollback_free_only;342 }343 344 for (i = 0; i < pipe_count; i++) {345 if (pipes[i].present) {346 rc = usb_pipe_register(pipes[i].pipe,347 pipes[i].descriptor->poll_interval, &hc_conn);348 if (rc != EOK) {349 goto rollback_unregister_endpoints;350 }351 }352 }353 354 usb_hc_connection_close(&hc_conn);355 356 *pipes_ptr = pipes;357 if (pipes_count_ptr != NULL) {358 *pipes_count_ptr = pipe_count;359 }360 361 return EOK;362 363 /*364 * Jump here if something went wrong after endpoints have365 * been registered.366 * This is also the target when the registration of367 * endpoints fails.368 */369 rollback_unregister_endpoints:370 for (i = 0; i < pipe_count; i++) {371 if (pipes[i].present) {372 usb_pipe_unregister(pipes[i].pipe, &hc_conn);373 }374 }375 376 usb_hc_connection_close(&hc_conn);377 378 /*379 * Jump here if something went wrong before some actual communication380 * with HC. Then the only thing that needs to be done is to free381 * allocated memory.382 */383 rollback_free_only:384 for (i = 0; i < pipe_count; i++) {385 if (pipes[i].pipe != NULL) {386 free(pipes[i].pipe);387 }388 }389 free(pipes);390 391 return rc;392 }393 394 /** Destroy pipes previously created by usb_device_create_pipes.395 *396 * @param[in] dev Generic DDF device backing the USB one.397 * @param[in] pipes Endpoint mapping to be destroyed.398 * @param[in] pipes_count Number of endpoints.399 */400 int usb_device_destroy_pipes(ddf_dev_t *dev,401 usb_endpoint_mapping_t *pipes, size_t pipes_count)402 {403 assert(dev != NULL);404 assert(((pipes != NULL) && (pipes_count > 0))405 || ((pipes == NULL) && (pipes_count == 0)));406 407 if (pipes_count == 0) {408 return EOK;409 }410 411 int rc;412 413 /* Prepare connection to HC to allow endpoint unregistering. */414 usb_hc_connection_t hc_conn;415 rc = usb_hc_connection_initialize_from_device(&hc_conn, dev);416 if (rc != EOK) {417 return rc;418 }419 rc = usb_hc_connection_open(&hc_conn);420 if (rc != EOK) {421 return rc;422 }423 424 /* Destroy the pipes. */425 size_t i;426 for (i = 0; i < pipes_count; i++) {427 usb_pipe_unregister(pipes[i].pipe, &hc_conn);428 free(pipes[i].pipe);429 }430 431 usb_hc_connection_close(&hc_conn);432 433 free(pipes);434 435 return EOK;436 }437 438 /** Initialize control pipe in a device.439 *440 * @param dev USB device in question.441 * @param errmsg Where to store error context.442 * @return443 */444 static int init_wire_and_ctrl_pipe(usb_device_t *dev, const char **errmsg)445 {446 int rc;447 448 rc = usb_device_connection_initialize_from_device(&dev->wire,449 dev->ddf_dev);450 if (rc != EOK) {451 *errmsg = "device connection initialization";452 return rc;453 }454 455 rc = usb_pipe_initialize_default_control(&dev->ctrl_pipe,456 &dev->wire);457 if (rc != EOK) {458 *errmsg = "default control pipe initialization";459 return rc;460 }461 462 return EOK;463 }464 465 466 /** Create new instance of USB device.467 *468 * @param[in] ddf_dev Generic DDF device backing the USB one.469 * @param[in] endpoints NULL terminated array of endpoints (NULL for none).470 * @param[out] dev_ptr Where to store pointer to the new device.471 * @param[out] errstr_ptr Where to store description of context472 * (in case error occurs).473 * @return Error code.474 */475 int usb_device_create(ddf_dev_t *ddf_dev,476 usb_endpoint_description_t **endpoints,477 usb_device_t **dev_ptr, const char **errstr_ptr)478 {479 assert(dev_ptr != NULL);480 assert(ddf_dev != NULL);481 482 int rc;483 484 usb_device_t *dev = malloc(sizeof(usb_device_t));485 if (dev == NULL) {486 *errstr_ptr = "structure allocation";487 return ENOMEM;488 }489 490 // FIXME: proper deallocation in case of errors491 492 dev->ddf_dev = ddf_dev;493 dev->driver_data = NULL;494 dev->descriptors.configuration = NULL;495 dev->alternate_interfaces = NULL;496 497 dev->pipes_count = 0;498 dev->pipes = NULL;499 500 /* Initialize backing wire and control pipe. */501 rc = init_wire_and_ctrl_pipe(dev, errstr_ptr);502 if (rc != EOK) {503 return rc;504 }505 506 /* Get our interface. */507 dev->interface_no = usb_device_get_assigned_interface(dev->ddf_dev);508 509 /* Retrieve standard descriptors. */510 rc = usb_device_retrieve_descriptors(&dev->ctrl_pipe,511 &dev->descriptors);512 if (rc != EOK) {513 *errstr_ptr = "descriptor retrieval";514 return rc;515 }516 517 /* Create alternate interfaces. */518 rc = usb_alternate_interfaces_create(dev->descriptors.configuration,519 dev->descriptors.configuration_size, dev->interface_no,520 &dev->alternate_interfaces);521 if (rc != EOK) {522 /* We will try to silently ignore this. */523 dev->alternate_interfaces = NULL;524 }525 526 rc = initialize_other_pipes(endpoints, dev, 0);527 if (rc != EOK) {528 *errstr_ptr = "pipes initialization";529 return rc;530 }531 532 *errstr_ptr = NULL;533 *dev_ptr = dev;534 535 return EOK;536 542 } 537 543
Note:
See TracChangeset
for help on using the changeset viewer.