Ignore:
File:
1 edited

Legend:

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

    rc1b1944 r0b4e7ca  
    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
     
    170248        }
    171249
    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",
     250        /* Get the device descriptor. */
     251        rc = usb_request_get_device_descriptor(&dev->ctrl_pipe,
     252            &dev->descriptors.device);
     253        if (rc != EOK) {
     254                usb_log_error("Failed to retrieve device descriptor: %s.\n",
     255                    str_error(rc));
     256                return rc;
     257        }
     258
     259        /* Get the full configuration descriptor. */
     260        rc = usb_request_get_full_configuration_descriptor_alloc(
     261            &dev->ctrl_pipe, 0, (void **) &dev->descriptors.configuration,
     262            &dev->descriptors.configuration_size);
     263        if (rc != EOK) {
     264                usb_log_error("Failed retrieving configuration descriptor: %s.\n",
    178265                    dev->ddf_dev->name, str_error(rc));
    179266                return rc;
    180267        }
    181268
    182 
    183269        if (driver->endpoints != NULL) {
    184                 rc = initialize_other_pipes(driver->endpoints, dev, 0);
     270                rc = initialize_other_pipes(driver->endpoints, dev);
    185271        }
    186272
     
    205291 * @return Number of alternate interfaces for @p interface_no interface.
    206292 */
    207 size_t usb_interface_count_alternates(uint8_t *config_descr,
    208     size_t config_descr_size, uint8_t interface_no)
     293static size_t count_alternate_interfaces(uint8_t *config_descr,
     294    size_t config_descr_size, int interface_no)
    209295{
    210296        assert(config_descr != NULL);
    211         assert(config_descr_size > 0);
    212 
    213297        usb_dp_parser_t dp_parser = {
    214298                .nesting = usb_dp_standard_descriptor_nesting
     
    259343
    260344        alternates->alternative_count
    261             = usb_interface_count_alternates(dev->descriptors.configuration,
     345            = count_alternate_interfaces(dev->descriptors.configuration,
    262346            dev->descriptors.configuration_size, dev->interface_no);
    263347
     
    373457static int destroy_current_pipes(usb_device_t *dev)
    374458{
    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 
     459        size_t i;
     460        int rc;
     461
     462        /* TODO: this shall be done under some device mutex. */
     463
     464        /* First check that no session is opened. */
     465        for (i = 0; i < dev->pipes_count; i++) {
     466                if (usb_pipe_is_session_started(dev->pipes[i].pipe)) {
     467                        return EBUSY;
     468                }
     469        }
     470
     471        /* Prepare connection to HC. */
     472        usb_hc_connection_t hc_conn;
     473        rc = usb_hc_connection_initialize_from_device(&hc_conn, dev->ddf_dev);
     474        if (rc != EOK) {
     475                return rc;
     476        }
     477        rc = usb_hc_connection_open(&hc_conn);
     478        if (rc != EOK) {
     479                return rc;
     480        }
     481
     482        /* Destroy the pipes. */
     483        for (i = 0; i < dev->pipes_count; i++) {
     484                usb_pipe_unregister(dev->pipes[i].pipe, &hc_conn);
     485                free(dev->pipes[i].pipe);
     486        }
     487
     488        usb_hc_connection_close(&hc_conn);
     489
     490        free(dev->pipes);
    381491        dev->pipes = NULL;
    382492        dev->pipes_count = 0;
     
    425535
    426536        /* Create new pipes. */
    427         rc = initialize_other_pipes(endpoints, dev, (int) alternate_setting);
     537        rc = initialize_other_pipes(endpoints, dev);
    428538
    429539        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;
    641540}
    642541
Note: See TracChangeset for help on using the changeset viewer.