devdrv.c

Go to the documentation of this file.
00001 /*
00002  * Copyright (c) 2011 Vojtech Horky
00003  * All rights reserved.
00004  *
00005  * Redistribution and use in source and binary forms, with or without
00006  * modification, are permitted provided that the following conditions
00007  * are met:
00008  *
00009  * - Redistributions of source code must retain the above copyright
00010  *   notice, this list of conditions and the following disclaimer.
00011  * - Redistributions in binary form must reproduce the above copyright
00012  *   notice, this list of conditions and the following disclaimer in the
00013  *   documentation and/or other materials provided with the distribution.
00014  * - The name of the author may not be used to endorse or promote products
00015  *   derived from this software without specific prior written permission.
00016  *
00017  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
00018  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
00019  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
00020  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
00021  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
00022  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
00023  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
00024  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
00025  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
00026  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00027  */
00028 
00035 #include <usb/dev/driver.h>
00036 #include <usb/dev/request.h>
00037 #include <usb/debug.h>
00038 #include <usb/dev/dp.h>
00039 #include <errno.h>
00040 #include <str_error.h>
00041 #include <assert.h>
00042 
00043 static int generic_add_device(ddf_dev_t *);
00044 
00045 static driver_ops_t generic_driver_ops = {
00046         .add_device = generic_add_device
00047 };
00048 static driver_t generic_driver = {
00049         .driver_ops = &generic_driver_ops
00050 };
00051 
00052 static usb_driver_t *driver = NULL;
00053 
00054 
00062 int usb_driver_main(usb_driver_t *drv)
00063 {
00064         assert(drv != NULL);
00065 
00066         /* Prepare the generic driver. */
00067         generic_driver.name = drv->name;
00068 
00069         driver = drv;
00070 
00071         return ddf_driver_main(&generic_driver);
00072 }
00073 
00079 static size_t count_other_pipes(usb_endpoint_description_t **endpoints)
00080 {
00081         size_t count = 0;
00082         if (endpoints == NULL) {
00083                 return 0;
00084         }
00085 
00086         while (endpoints[count] != NULL) {
00087                 count++;
00088         }
00089 
00090         return count;
00091 }
00092 
00099 static int initialize_other_pipes(usb_endpoint_description_t **endpoints,
00100     usb_device_t *dev, int alternate_setting)
00101 {
00102         if (endpoints == NULL) {
00103                 dev->pipes = NULL;
00104                 dev->pipes_count = 0;
00105                 return EOK;
00106         }
00107 
00108         usb_endpoint_mapping_t *pipes;
00109         size_t pipes_count;
00110 
00111         int rc = usb_device_create_pipes(dev->ddf_dev, &dev->wire, endpoints,
00112             dev->descriptors.configuration, dev->descriptors.configuration_size,
00113             dev->interface_no, alternate_setting,
00114             &pipes, &pipes_count);
00115 
00116         if (rc != EOK) {
00117                 return rc;
00118         }
00119 
00120         dev->pipes = pipes;
00121         dev->pipes_count = pipes_count;
00122 
00123         return EOK;
00124 }
00125 
00133 int generic_add_device(ddf_dev_t *gen_dev)
00134 {
00135         assert(driver);
00136         assert(driver->ops);
00137         assert(driver->ops->add_device);
00138 
00139         int rc;
00140 
00141         usb_device_t *dev = NULL;
00142         const char *err_msg = NULL;
00143         rc = usb_device_create(gen_dev, driver->endpoints, &dev, &err_msg);
00144         if (rc != EOK) {
00145                 usb_log_error("USB device `%s' creation failed (%s): %s.\n",
00146                     gen_dev->name, err_msg, str_error(rc));
00147                 return rc;
00148         }
00149 
00150         return driver->ops->add_device(dev);
00151 }
00152 
00158 static int destroy_current_pipes(usb_device_t *dev)
00159 {
00160         int rc = usb_device_destroy_pipes(dev->ddf_dev,
00161             dev->pipes, dev->pipes_count);
00162         if (rc != EOK) {
00163                 return rc;
00164         }
00165 
00166         dev->pipes = NULL;
00167         dev->pipes_count = 0;
00168 
00169         return EOK;
00170 }
00171 
00194 int usb_device_select_interface(usb_device_t *dev, uint8_t alternate_setting,
00195     usb_endpoint_description_t **endpoints)
00196 {
00197         if (dev->interface_no < 0) {
00198                 return EINVAL;
00199         }
00200 
00201         int rc;
00202 
00203         /* Destroy existing pipes. */
00204         rc = destroy_current_pipes(dev);
00205         if (rc != EOK) {
00206                 return rc;
00207         }
00208 
00209         /* Change the interface itself. */
00210         rc = usb_request_set_interface(&dev->ctrl_pipe, dev->interface_no,
00211             alternate_setting);
00212         if (rc != EOK) {
00213                 return rc;
00214         }
00215 
00216         /* Create new pipes. */
00217         rc = initialize_other_pipes(endpoints, dev, (int) alternate_setting);
00218 
00219         return rc;
00220 }
00221 
00228 int usb_device_retrieve_descriptors(usb_pipe_t *ctrl_pipe,
00229     usb_device_descriptors_t *descriptors)
00230 {
00231         assert(descriptors != NULL);
00232 
00233         descriptors->configuration = NULL;
00234 
00235         int rc;
00236 
00237         /* It is worth to start a long transfer. */
00238         usb_pipe_start_long_transfer(ctrl_pipe);
00239 
00240         /* Get the device descriptor. */
00241         rc = usb_request_get_device_descriptor(ctrl_pipe, &descriptors->device);
00242         if (rc != EOK) {
00243                 goto leave;
00244         }
00245 
00246         /* Get the full configuration descriptor. */
00247         rc = usb_request_get_full_configuration_descriptor_alloc(
00248             ctrl_pipe, 0, (void **) &descriptors->configuration,
00249             &descriptors->configuration_size);
00250 
00251 leave:
00252         usb_pipe_end_long_transfer(ctrl_pipe);
00253 
00254         return rc;
00255 }
00256 
00277 int usb_device_create_pipes(ddf_dev_t *dev, usb_device_connection_t *wire,
00278     usb_endpoint_description_t **endpoints,
00279     uint8_t *config_descr, size_t config_descr_size,
00280     int interface_no, int interface_setting,
00281     usb_endpoint_mapping_t **pipes_ptr, size_t *pipes_count_ptr)
00282 {
00283         assert(dev != NULL);
00284         assert(wire != NULL);
00285         assert(endpoints != NULL);
00286         assert(config_descr != NULL);
00287         assert(config_descr_size > 0);
00288         assert(pipes_ptr != NULL);
00289 
00290         size_t i;
00291         int rc;
00292 
00293         size_t pipe_count = count_other_pipes(endpoints);
00294         if (pipe_count == 0) {
00295                 *pipes_ptr = NULL;
00296                 return EOK;
00297         }
00298 
00299         usb_endpoint_mapping_t *pipes
00300             = malloc(sizeof(usb_endpoint_mapping_t) * pipe_count);
00301         if (pipes == NULL) {
00302                 return ENOMEM;
00303         }
00304 
00305         /* Initialize to NULL to allow smooth rollback. */
00306         for (i = 0; i < pipe_count; i++) {
00307                 pipes[i].pipe = NULL;
00308         }
00309 
00310         /* Now allocate and fully initialize. */
00311         for (i = 0; i < pipe_count; i++) {
00312                 pipes[i].pipe = malloc(sizeof(usb_pipe_t));
00313                 if (pipes[i].pipe == NULL) {
00314                         rc = ENOMEM;
00315                         goto rollback_free_only;
00316                 }
00317                 pipes[i].description = endpoints[i];
00318                 pipes[i].interface_no = interface_no;
00319                 pipes[i].interface_setting = interface_setting;
00320         }
00321 
00322         /* Find the mapping from configuration descriptor. */
00323         rc = usb_pipe_initialize_from_configuration(pipes, pipe_count,
00324             config_descr, config_descr_size, wire);
00325         if (rc != EOK) {
00326                 goto rollback_free_only;
00327         }
00328 
00329         /* Register the endpoints with HC. */
00330         usb_hc_connection_t hc_conn;
00331         rc = usb_hc_connection_initialize_from_device(&hc_conn, dev);
00332         if (rc != EOK) {
00333                 goto rollback_free_only;
00334         }
00335 
00336         rc = usb_hc_connection_open(&hc_conn);
00337         if (rc != EOK) {
00338                 goto rollback_free_only;
00339         }
00340 
00341         for (i = 0; i < pipe_count; i++) {
00342                 if (pipes[i].present) {
00343                         rc = usb_pipe_register(pipes[i].pipe,
00344                             pipes[i].descriptor->poll_interval, &hc_conn);
00345                         if (rc != EOK) {
00346                                 goto rollback_unregister_endpoints;
00347                         }
00348                 }
00349         }
00350 
00351         usb_hc_connection_close(&hc_conn);
00352 
00353         *pipes_ptr = pipes;
00354         if (pipes_count_ptr != NULL) {
00355                 *pipes_count_ptr = pipe_count;
00356         }
00357 
00358         return EOK;
00359 
00360         /*
00361          * Jump here if something went wrong after endpoints have
00362          * been registered.
00363          * This is also the target when the registration of
00364          * endpoints fails.
00365          */
00366 rollback_unregister_endpoints:
00367         for (i = 0; i < pipe_count; i++) {
00368                 if (pipes[i].present) {
00369                         usb_pipe_unregister(pipes[i].pipe, &hc_conn);
00370                 }
00371         }
00372 
00373         usb_hc_connection_close(&hc_conn);
00374 
00375         /*
00376          * Jump here if something went wrong before some actual communication
00377          * with HC. Then the only thing that needs to be done is to free
00378          * allocated memory.
00379          */
00380 rollback_free_only:
00381         for (i = 0; i < pipe_count; i++) {
00382                 if (pipes[i].pipe != NULL) {
00383                         free(pipes[i].pipe);
00384                 }
00385         }
00386         free(pipes);
00387 
00388         return rc;
00389 }
00390 
00397 int usb_device_destroy_pipes(ddf_dev_t *dev,
00398     usb_endpoint_mapping_t *pipes, size_t pipes_count)
00399 {
00400         assert(dev != NULL);
00401         assert(((pipes != NULL) && (pipes_count > 0))
00402             || ((pipes == NULL) && (pipes_count == 0)));
00403 
00404         if (pipes_count == 0) {
00405                 return EOK;
00406         }
00407 
00408         int rc;
00409 
00410         /* Prepare connection to HC to allow endpoint unregistering. */
00411         usb_hc_connection_t hc_conn;
00412         rc = usb_hc_connection_initialize_from_device(&hc_conn, dev);
00413         if (rc != EOK) {
00414                 return rc;
00415         }
00416         rc = usb_hc_connection_open(&hc_conn);
00417         if (rc != EOK) {
00418                 return rc;
00419         }
00420 
00421         /* Destroy the pipes. */
00422         size_t i;
00423         for (i = 0; i < pipes_count; i++) {
00424                 usb_pipe_unregister(pipes[i].pipe, &hc_conn);
00425                 free(pipes[i].pipe);
00426         }
00427 
00428         usb_hc_connection_close(&hc_conn);
00429 
00430         free(pipes);
00431 
00432         return EOK;
00433 }
00434 
00441 static int init_wire_and_ctrl_pipe(usb_device_t *dev, const char **errmsg)
00442 {
00443         int rc;
00444 
00445         rc = usb_device_connection_initialize_from_device(&dev->wire,
00446             dev->ddf_dev);
00447         if (rc != EOK) {
00448                 *errmsg = "device connection initialization";
00449                 return rc;
00450         }
00451 
00452         rc = usb_pipe_initialize_default_control(&dev->ctrl_pipe,
00453             &dev->wire);
00454         if (rc != EOK) {
00455                 *errmsg = "default control pipe initialization";
00456                 return rc;
00457         }
00458 
00459         return EOK;
00460 }
00461 
00462 
00472 int usb_device_create(ddf_dev_t *ddf_dev,
00473     usb_endpoint_description_t **endpoints,
00474     usb_device_t **dev_ptr, const char **errstr_ptr)
00475 {
00476         assert(dev_ptr != NULL);
00477         assert(ddf_dev != NULL);
00478 
00479         int rc;
00480 
00481         usb_device_t *dev = malloc(sizeof(usb_device_t));
00482         if (dev == NULL) {
00483                 *errstr_ptr = "structure allocation";
00484                 return ENOMEM;
00485         }
00486 
00487         // FIXME: proper deallocation in case of errors
00488 
00489         dev->ddf_dev = ddf_dev;
00490         dev->driver_data = NULL;
00491         dev->descriptors.configuration = NULL;
00492         dev->alternate_interfaces = NULL;
00493 
00494         dev->pipes_count = 0;
00495         dev->pipes = NULL;
00496 
00497         /* Initialize backing wire and control pipe. */
00498         rc = init_wire_and_ctrl_pipe(dev, errstr_ptr);
00499         if (rc != EOK) {
00500                 return rc;
00501         }
00502 
00503         /* Get our interface. */
00504         dev->interface_no = usb_device_get_assigned_interface(dev->ddf_dev);
00505 
00506         /* Retrieve standard descriptors. */
00507         rc = usb_device_retrieve_descriptors(&dev->ctrl_pipe,
00508             &dev->descriptors);
00509         if (rc != EOK) {
00510                 *errstr_ptr = "descriptor retrieval";
00511                 return rc;
00512         }
00513 
00514         /* Create alternate interfaces. */
00515         rc = usb_alternate_interfaces_create(dev->descriptors.configuration,
00516             dev->descriptors.configuration_size, dev->interface_no,
00517             &dev->alternate_interfaces);
00518         if (rc != EOK) {
00519                 /* We will try to silently ignore this. */
00520                 dev->alternate_interfaces = NULL;
00521         }
00522 
00523         rc = initialize_other_pipes(endpoints, dev, 0);
00524         if (rc != EOK) {
00525                 *errstr_ptr = "pipes initialization";
00526                 return rc;
00527         }
00528 
00529         *errstr_ptr = NULL;
00530         *dev_ptr = dev;
00531 
00532         return EOK;
00533 }
00534 
00539 void usb_device_destroy(usb_device_t *dev)
00540 {
00541         if (dev == NULL) {
00542                 return;
00543         }
00544 
00545         /* Ignore errors and hope for the best. */
00546         usb_device_destroy_pipes(dev->ddf_dev, dev->pipes, dev->pipes_count);
00547         if (dev->descriptors.configuration != NULL) {
00548                 free(dev->descriptors.configuration);
00549         }
00550 
00551         if (dev->alternate_interfaces != NULL) {
00552                 if (dev->alternate_interfaces->alternatives != NULL) {
00553                         free(dev->alternate_interfaces->alternatives);
00554                 }
00555                 free(dev->alternate_interfaces);
00556         }
00557 
00558         free(dev);
00559 }
00560 

Generated on Thu Jun 2 07:45:48 2011 for HelenOS/USB by  doxygen 1.4.7