Ignore:
File:
1 edited

Legend:

Unmodified
Added
Removed
  • uspace/lib/usb/src/devdrv.c

    rc1b1944 r4ede178  
    7272}
    7373
     74/** Log out of memory error on given device.
     75 *
     76 * @param dev Device causing the trouble.
     77 */
     78static 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
    7484/** Count number of pipes the driver expects.
    7585 *
     
    98108 */
    99109static int initialize_other_pipes(usb_endpoint_description_t **endpoints,
    100     usb_device_t *dev, int alternate_setting)
    101 {
    102         usb_endpoint_mapping_t *pipes;
    103         size_t pipes_count;
    104 
    105         int rc = usb_device_create_pipes(dev->ddf_dev, &dev->wire, endpoints,
     110    usb_device_t *dev)
     111{
     112        int rc;
     113
     114        size_t pipe_count = count_other_pipes(endpoints);
     115        if (pipe_count == 0) {
     116                return EOK;
     117        }
     118
     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,
    106146            dev->descriptors.configuration, dev->descriptors.configuration_size,
    107             dev->interface_no, alternate_setting,
    108             &pipes, &pipes_count);
    109 
     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);
    110157        if (rc != EOK) {
    111158                usb_log_error(
    112                     "Failed to create endpoint pipes for `%s': %s.\n",
    113                     dev->ddf_dev->name, str_error(rc));
    114                 return rc;
    115         }
    116 
    117         dev->pipes = pipes;
    118         dev->pipes_count = pipes_count;
     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;
    119187
    120188        return EOK;
     189
     190rollback:
     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;
    121199}
    122200
     
    161239
    162240        /*
    163          * For further actions, we need open session on default control pipe.
     241         * We will do some querying of the device, it is worth to prepare
     242         * the long transfer.
    164243         */
    165         rc = usb_pipe_start_session(&dev->ctrl_pipe);
    166         if (rc != EOK) {
    167                 usb_log_error("Failed to start an IPC session: %s.\n",
     244        rc = usb_pipe_start_long_transfer(&dev->ctrl_pipe);
     245        if (rc != EOK) {
     246                usb_log_error("Failed to start transfer: %s.\n",
    168247                    str_error(rc));
    169248                return rc;
    170249        }
    171250
    172         /* Retrieve the descriptors. */
    173         rc = usb_device_retrieve_descriptors(&dev->ctrl_pipe,
    174             &dev->descriptors);
    175         if (rc != EOK) {
    176                 usb_log_error("Failed to retrieve standard device " \
    177                     "descriptors of %s: %s.\n",
     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",
    178268                    dev->ddf_dev->name, str_error(rc));
    179269                return rc;
    180270        }
    181271
    182 
    183272        if (driver->endpoints != NULL) {
    184                 rc = initialize_other_pipes(driver->endpoints, dev, 0);
    185         }
    186 
    187         /* No checking here. */
    188         usb_pipe_end_session(&dev->ctrl_pipe);
     273                rc = initialize_other_pipes(driver->endpoints, dev);
     274        }
     275
     276        usb_pipe_end_long_transfer(&dev->ctrl_pipe);
    189277
    190278        /* Rollback actions. */
     
    205293 * @return Number of alternate interfaces for @p interface_no interface.
    206294 */
    207 size_t usb_interface_count_alternates(uint8_t *config_descr,
    208     size_t config_descr_size, uint8_t interface_no)
     295static size_t count_alternate_interfaces(uint8_t *config_descr,
     296    size_t config_descr_size, int interface_no)
    209297{
    210298        assert(config_descr != NULL);
    211         assert(config_descr_size > 0);
    212 
    213299        usb_dp_parser_t dp_parser = {
    214300                .nesting = usb_dp_standard_descriptor_nesting
     
    259345
    260346        alternates->alternative_count
    261             = usb_interface_count_alternates(dev->descriptors.configuration,
     347            = count_alternate_interfaces(dev->descriptors.configuration,
    262348            dev->descriptors.configuration_size, dev->interface_no);
    263349
     
    373459static int destroy_current_pipes(usb_device_t *dev)
    374460{
    375         int rc = usb_device_destroy_pipes(dev->ddf_dev,
    376             dev->pipes, dev->pipes_count);
    377         if (rc != EOK) {
    378                 return rc;
    379         }
    380 
     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);
    381493        dev->pipes = NULL;
    382494        dev->pipes_count = 0;
     
    425537
    426538        /* Create new pipes. */
    427         rc = initialize_other_pipes(endpoints, dev, (int) alternate_setting);
     539        rc = initialize_other_pipes(endpoints, dev);
    428540
    429541        return rc;
    430 }
    431 
    432 /** Retrieve basic descriptors from the device.
    433  *
    434  * @param[in] ctrl_pipe Control pipe with opened session.
    435  * @param[out] descriptors Where to store the descriptors.
    436  * @return Error code.
    437  */
    438 int usb_device_retrieve_descriptors(usb_pipe_t *ctrl_pipe,
    439     usb_device_descriptors_t *descriptors)
    440 {
    441         assert(descriptors != NULL);
    442         assert(usb_pipe_is_session_started(ctrl_pipe));
    443 
    444         descriptors->configuration = NULL;
    445 
    446         int rc;
    447 
    448         /* Get the device descriptor. */
    449         rc = usb_request_get_device_descriptor(ctrl_pipe, &descriptors->device);
    450         if (rc != EOK) {
    451                 return rc;
    452         }
    453 
    454         /* Get the full configuration descriptor. */
    455         rc = usb_request_get_full_configuration_descriptor_alloc(
    456             ctrl_pipe, 0, (void **) &descriptors->configuration,
    457             &descriptors->configuration_size);
    458         if (rc != EOK) {
    459                 return rc;
    460         }
    461 
    462         return EOK;
    463 }
    464 
    465 /** Create pipes for a device.
    466  *
    467  * This is more or less a wrapper that does following actions:
    468  * - allocate and initialize pipes
    469  * - map endpoints to the pipes based on the descriptions
    470  * - registers endpoints with the host controller
    471  *
    472  * @param[in] dev Generic DDF device backing the USB one.
    473  * @param[in] wire Initialized backing connection to the host controller.
    474  * @param[in] endpoints Endpoints description, NULL terminated.
    475  * @param[in] config_descr Configuration descriptor of active configuration.
    476  * @param[in] config_descr_size Size of @p config_descr in bytes.
    477  * @param[in] interface_no Interface to map from.
    478  * @param[in] interface_setting Interface setting (default is usually 0).
    479  * @param[out] pipes_ptr Where to store array of created pipes
    480  *      (not NULL terminated).
    481  * @param[out] pipes_count_ptr Where to store number of pipes
    482  *      (set to if you wish to ignore the count).
    483  * @return Error code.
    484  */
    485 int usb_device_create_pipes(ddf_dev_t *dev, usb_device_connection_t *wire,
    486     usb_endpoint_description_t **endpoints,
    487     uint8_t *config_descr, size_t config_descr_size,
    488     int interface_no, int interface_setting,
    489     usb_endpoint_mapping_t **pipes_ptr, size_t *pipes_count_ptr)
    490 {
    491         assert(dev != NULL);
    492         assert(wire != NULL);
    493         assert(endpoints != NULL);
    494         assert(config_descr != NULL);
    495         assert(config_descr_size > 0);
    496         assert(pipes_ptr != NULL);
    497 
    498         size_t i;
    499         int rc;
    500 
    501         size_t pipe_count = count_other_pipes(endpoints);
    502         if (pipe_count == 0) {
    503                 *pipes_ptr = NULL;
    504                 return EOK;
    505         }
    506 
    507         usb_endpoint_mapping_t *pipes
    508             = malloc(sizeof(usb_endpoint_mapping_t) * pipe_count);
    509         if (pipes == NULL) {
    510                 return ENOMEM;
    511         }
    512 
    513         /* Initialize to NULL to allow smooth rollback. */
    514         for (i = 0; i < pipe_count; i++) {
    515                 pipes[i].pipe = NULL;
    516         }
    517 
    518         /* Now allocate and fully initialize. */
    519         for (i = 0; i < pipe_count; i++) {
    520                 pipes[i].pipe = malloc(sizeof(usb_pipe_t));
    521                 if (pipes[i].pipe == NULL) {
    522                         rc = ENOMEM;
    523                         goto rollback_free_only;
    524                 }
    525                 pipes[i].description = endpoints[i];
    526                 pipes[i].interface_no = interface_no;
    527                 pipes[i].interface_setting = interface_setting;
    528         }
    529 
    530         /* Find the mapping from configuration descriptor. */
    531         rc = usb_pipe_initialize_from_configuration(pipes, pipe_count,
    532             config_descr, config_descr_size, wire);
    533         if (rc != EOK) {
    534                 goto rollback_free_only;
    535         }
    536 
    537         /* Register the endpoints with HC. */
    538         usb_hc_connection_t hc_conn;
    539         rc = usb_hc_connection_initialize_from_device(&hc_conn, dev);
    540         if (rc != EOK) {
    541                 goto rollback_free_only;
    542         }
    543 
    544         rc = usb_hc_connection_open(&hc_conn);
    545         if (rc != EOK) {
    546                 goto rollback_free_only;
    547         }
    548 
    549         for (i = 0; i < pipe_count; i++) {
    550                 if (pipes[i].present) {
    551                         rc = usb_pipe_register(pipes[i].pipe,
    552                             pipes[i].descriptor->poll_interval, &hc_conn);
    553                         if (rc != EOK) {
    554                                 goto rollback_unregister_endpoints;
    555                         }
    556                 }
    557         }
    558 
    559         usb_hc_connection_close(&hc_conn);
    560 
    561         *pipes_ptr = pipes;
    562         if (pipes_count_ptr != NULL) {
    563                 *pipes_count_ptr = pipe_count;
    564         }
    565 
    566         return EOK;
    567 
    568         /*
    569          * Jump here if something went wrong after endpoints have
    570          * been registered.
    571          * This is also the target when the registration of
    572          * endpoints fails.
    573          */
    574 rollback_unregister_endpoints:
    575         for (i = 0; i < pipe_count; i++) {
    576                 if (pipes[i].present) {
    577                         usb_pipe_unregister(pipes[i].pipe, &hc_conn);
    578                 }
    579         }
    580 
    581         usb_hc_connection_close(&hc_conn);
    582 
    583         /*
    584          * Jump here if something went wrong before some actual communication
    585          * with HC. Then the only thing that needs to be done is to free
    586          * allocated memory.
    587          */
    588 rollback_free_only:
    589         for (i = 0; i < pipe_count; i++) {
    590                 if (pipes[i].pipe != NULL) {
    591                         free(pipes[i].pipe);
    592                 }
    593         }
    594         free(pipes);
    595 
    596         return rc;
    597 }
    598 
    599 /** Destroy pipes previously created by usb_device_create_pipes.
    600  *
    601  * @param[in] dev Generic DDF device backing the USB one.
    602  * @param[in] pipes Endpoint mapping to be destroyed.
    603  * @param[in] pipes_count Number of endpoints.
    604  */
    605 int usb_device_destroy_pipes(ddf_dev_t *dev,
    606     usb_endpoint_mapping_t *pipes, size_t pipes_count)
    607 {
    608         assert(dev != NULL);
    609         assert(((pipes != NULL) && (pipes_count > 0))
    610             || ((pipes == NULL) && (pipes_count == 0)));
    611 
    612         if (pipes_count == 0) {
    613                 return EOK;
    614         }
    615 
    616         int rc;
    617 
    618         /* Prepare connection to HC to allow endpoint unregistering. */
    619         usb_hc_connection_t hc_conn;
    620         rc = usb_hc_connection_initialize_from_device(&hc_conn, dev);
    621         if (rc != EOK) {
    622                 return rc;
    623         }
    624         rc = usb_hc_connection_open(&hc_conn);
    625         if (rc != EOK) {
    626                 return rc;
    627         }
    628 
    629         /* Destroy the pipes. */
    630         size_t i;
    631         for (i = 0; i < pipes_count; i++) {
    632                 usb_pipe_unregister(pipes[i].pipe, &hc_conn);
    633                 free(pipes[i].pipe);
    634         }
    635 
    636         usb_hc_connection_close(&hc_conn);
    637 
    638         free(pipes);
    639 
    640         return EOK;
    641542}
    642543
Note: See TracChangeset for help on using the changeset viewer.