Ignore:
File:
1 edited

Legend:

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

    r3f2af64 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         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) {
    105116                return EOK;
    106117        }
    107118
    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,
    112146            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
     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;
     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 */
     207static 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 */
     295static 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 */
     332static 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;
    122408
    123409        return EOK;
     
    139425        int rc;
    140426
    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);
    149450
    150451        return driver->ops->add_device(dev);
     
    158459static int destroy_current_pipes(usb_device_t *dev)
    159460{
    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);
    166493        dev->pipes = NULL;
    167494        dev->pipes_count = 0;
     
    180507 * with usb_pipe_initialize_from_configuration().
    181508 *
    182  * @warning This is a wrapper function that does several operations that
    183  * can fail and that cannot be rollbacked easily. That means that a failure
    184  * during the SET_INTERFACE request would result in having a device with
    185  * no pipes at all (except the default control one). That is because the old
    186  * pipes needs to be unregistered at HC first and the new ones could not
    187  * be created.
    188  *
    189509 * @param dev USB device.
    190510 * @param alternate_setting Alternate setting to choose.
     
    201521        int rc;
    202522
     523        /* TODO: more transactional behavior. */
     524
    203525        /* Destroy existing pipes. */
    204526        rc = destroy_current_pipes(dev);
     
    215537
    216538        /* Create new pipes. */
    217         rc = initialize_other_pipes(endpoints, dev, (int) alternate_setting);
     539        rc = initialize_other_pipes(endpoints, dev);
    218540
    219541        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 pipes
    264  * - map endpoints to the pipes based on the descriptions
    265  * - registers endpoints with the host controller
    266  *
    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 pipes
    275  *      (not NULL terminated).
    276  * @param[out] pipes_count_ptr Where to store number of pipes
    277  *      (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 *pipes
    303             = 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 have
    365          * been registered.
    366          * This is also the target when the registration of
    367          * 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 communication
    380          * with HC. Then the only thing that needs to be done is to free
    381          * 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  * @return
    443  */
    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 context
    472  *      (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 errors
    491 
    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;
    536542}
    537543
Note: See TracChangeset for help on using the changeset viewer.