Ignore:
File:
1 edited

Legend:

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

    r0b4e7ca r3f2af64  
    7272}
    7373
    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 
    8474/** Count number of pipes the driver expects.
    8575 *
     
    10898 */
    10999static int initialize_other_pipes(usb_endpoint_description_t **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) {
     100    usb_device_t *dev, int alternate_setting)
     101{
     102        if (endpoints == NULL) {
     103                dev->pipes = NULL;
     104                dev->pipes_count = 0;
    116105                return EOK;
    117106        }
    118107
    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,
     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,
    146112            dev->descriptors.configuration, dev->descriptors.configuration_size,
    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          * For further actions, we need open session on default control pipe.
    242          */
    243         rc = usb_pipe_start_session(&dev->ctrl_pipe);
    244         if (rc != EOK) {
    245                 usb_log_error("Failed to start an IPC session: %s.\n",
    246                     str_error(rc));
    247                 return rc;
    248         }
    249 
    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",
    265                     dev->ddf_dev->name, str_error(rc));
    266                 return rc;
    267         }
    268 
    269         if (driver->endpoints != NULL) {
    270                 rc = initialize_other_pipes(driver->endpoints, dev);
    271         }
    272 
    273         /* No checking here. */
    274         usb_pipe_end_session(&dev->ctrl_pipe);
    275 
    276         /* Rollback actions. */
    277         if (rc != EOK) {
    278                 if (dev->descriptors.configuration != NULL) {
    279                         free(dev->descriptors.configuration);
    280                 }
    281         }
    282 
    283         return rc;
    284 }
    285 
    286 /** Count number of alternate settings of a interface.
    287  *
    288  * @param config_descr Full configuration descriptor.
    289  * @param config_descr_size Size of @p config_descr in bytes.
    290  * @param interface_no Interface number.
    291  * @return Number of alternate interfaces for @p interface_no interface.
    292  */
    293 static size_t count_alternate_interfaces(uint8_t *config_descr,
    294     size_t config_descr_size, int interface_no)
    295 {
    296         assert(config_descr != NULL);
    297         usb_dp_parser_t dp_parser = {
    298                 .nesting = usb_dp_standard_descriptor_nesting
    299         };
    300         usb_dp_parser_data_t dp_data = {
    301                 .data = config_descr,
    302                 .size = config_descr_size,
    303                 .arg = NULL
    304         };
    305 
    306         size_t alternate_count = 0;
    307 
    308         uint8_t *iface_ptr = usb_dp_get_nested_descriptor(&dp_parser,
    309             &dp_data, config_descr);
    310         while (iface_ptr != NULL) {
    311                 usb_standard_interface_descriptor_t *iface
    312                     = (usb_standard_interface_descriptor_t *) iface_ptr;
    313                 if (iface->descriptor_type == USB_DESCTYPE_INTERFACE) {
    314                         if (iface->interface_number == interface_no) {
    315                                 alternate_count++;
    316                         }
    317                 }
    318                 iface_ptr = usb_dp_get_sibling_descriptor(&dp_parser, &dp_data,
    319                     config_descr, iface_ptr);
    320         }
    321 
    322         return alternate_count;
    323 }
    324 
    325 /** Initialize structures related to alternate interfaces.
    326  *
    327  * @param dev Device where alternate settings shall be initialized.
    328  * @return Error code.
    329  */
    330 static int initialize_alternate_interfaces(usb_device_t *dev)
    331 {
    332         if (dev->interface_no < 0) {
    333                 dev->alternate_interfaces = NULL;
    334                 return EOK;
    335         }
    336 
    337         usb_alternate_interfaces_t *alternates
    338             = malloc(sizeof(usb_alternate_interfaces_t));
    339 
    340         if (alternates == NULL) {
    341                 return ENOMEM;
    342         }
    343 
    344         alternates->alternative_count
    345             = count_alternate_interfaces(dev->descriptors.configuration,
    346             dev->descriptors.configuration_size, dev->interface_no);
    347 
    348         if (alternates->alternative_count == 0) {
    349                 free(alternates);
    350                 return ENOENT;
    351         }
    352 
    353         alternates->alternatives = malloc(alternates->alternative_count
    354             * sizeof(usb_alternate_interface_descriptors_t));
    355         if (alternates->alternatives == NULL) {
    356                 free(alternates);
    357                 return ENOMEM;
    358         }
    359 
    360         alternates->current = 0;
    361 
    362         usb_dp_parser_t dp_parser = {
    363                 .nesting = usb_dp_standard_descriptor_nesting
    364         };
    365         usb_dp_parser_data_t dp_data = {
    366                 .data = dev->descriptors.configuration,
    367                 .size = dev->descriptors.configuration_size,
    368                 .arg = NULL
    369         };
    370 
    371         usb_alternate_interface_descriptors_t *cur_alt_iface
    372             = &alternates->alternatives[0];
    373 
    374         uint8_t *iface_ptr = usb_dp_get_nested_descriptor(&dp_parser,
    375             &dp_data, dp_data.data);
    376         while (iface_ptr != NULL) {
    377                 usb_standard_interface_descriptor_t *iface
    378                     = (usb_standard_interface_descriptor_t *) iface_ptr;
    379                 if ((iface->descriptor_type != USB_DESCTYPE_INTERFACE)
    380                     || (iface->interface_number != dev->interface_no)) {
    381                         iface_ptr = usb_dp_get_sibling_descriptor(&dp_parser,
    382                             &dp_data,
    383                             dp_data.data, iface_ptr);
    384                         continue;
    385                 }
    386 
    387                 cur_alt_iface->interface = iface;
    388                 cur_alt_iface->nested_descriptors = iface_ptr + sizeof(*iface);
    389 
    390                 /* Find next interface to count size of nested descriptors. */
    391                 iface_ptr = usb_dp_get_sibling_descriptor(&dp_parser, &dp_data,
    392                     dp_data.data, iface_ptr);
    393                 if (iface_ptr == NULL) {
    394                         uint8_t *next = dp_data.data + dp_data.size;
    395                         cur_alt_iface->nested_descriptors_size
    396                             = next - cur_alt_iface->nested_descriptors;
    397                 } else {
    398                         cur_alt_iface->nested_descriptors_size
    399                             = iface_ptr - cur_alt_iface->nested_descriptors;
    400                 }
    401 
    402                 cur_alt_iface++;
    403         }
    404 
    405         dev->alternate_interfaces = alternates;
     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;
    406122
    407123        return EOK;
     
    423139        int rc;
    424140
    425         usb_device_t *dev = malloc(sizeof(usb_device_t));
    426         if (dev == NULL) {
    427                 usb_log_error("Out of memory when adding device `%s'.\n",
    428                     gen_dev->name);
    429                 return ENOMEM;
    430         }
    431 
    432 
    433         dev->ddf_dev = gen_dev;
    434         dev->ddf_dev->driver_data = dev;
    435         dev->driver_data = NULL;
    436         dev->descriptors.configuration = NULL;
    437 
    438         dev->pipes_count = 0;
    439         dev->pipes = NULL;
    440 
    441         rc = initialize_pipes(dev);
    442         if (rc != EOK) {
    443                 free(dev);
    444                 return rc;
    445         }
    446 
    447         (void) initialize_alternate_interfaces(dev);
     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        }
    448149
    449150        return driver->ops->add_device(dev);
     
    457158static int destroy_current_pipes(usb_device_t *dev)
    458159{
    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);
     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
    491166        dev->pipes = NULL;
    492167        dev->pipes_count = 0;
     
    505180 * with usb_pipe_initialize_from_configuration().
    506181 *
     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 *
    507189 * @param dev USB device.
    508190 * @param alternate_setting Alternate setting to choose.
     
    519201        int rc;
    520202
    521         /* TODO: more transactional behavior. */
    522 
    523203        /* Destroy existing pipes. */
    524204        rc = destroy_current_pipes(dev);
     
    535215
    536216        /* Create new pipes. */
    537         rc = initialize_other_pipes(endpoints, dev);
     217        rc = initialize_other_pipes(endpoints, dev, (int) alternate_setting);
    538218
    539219        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 */
     228int 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
     254leave:
     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 */
     280int 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         */
     369rollback_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         */
     383rollback_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 */
     400int 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 */
     444static 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 */
     475int 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;
    540536}
    541537
Note: See TracChangeset for help on using the changeset viewer.