resolve.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 <inttypes.h>
00036 #include <usb/hc.h>
00037 #include <devman.h>
00038 #include <errno.h>
00039 #include <str.h>
00040 #include <stdio.h>
00041 
00042 #define MAX_DEVICE_PATH 1024
00043 
00044 static bool try_parse_bus_and_address(const char *path,
00045     char **func_start,
00046     devman_handle_t *out_hc_handle, usb_address_t *out_device_address)
00047 {
00048         size_t class_index;
00049         size_t address;
00050         int rc;
00051         char *ptr;
00052 
00053         rc = str_size_t(path, &ptr, 10, false, &class_index);
00054         if (rc != EOK) {
00055                 return false;
00056         }
00057         if ((*ptr == ':') || (*ptr == '.')) {
00058                 ptr++;
00059         } else {
00060                 return false;
00061         }
00062         rc = str_size_t(ptr, func_start, 10, false, &address);
00063         if (rc != EOK) {
00064                 return false;
00065         }
00066         rc = usb_ddf_get_hc_handle_by_class(class_index, out_hc_handle);
00067         if (rc != EOK) {
00068                 return false;
00069         }
00070         if (out_device_address != NULL) {
00071                 *out_device_address = (usb_address_t) address;
00072         }
00073         return true;
00074 }
00075 
00076 static int get_device_handle_by_address(devman_handle_t hc_handle, int addr,
00077     devman_handle_t *dev_handle)
00078 {
00079         int rc;
00080         usb_hc_connection_t conn;
00081 
00082         usb_hc_connection_initialize(&conn, hc_handle);
00083         rc = usb_hc_connection_open(&conn);
00084         if (rc != EOK) {
00085                 return rc;
00086         }
00087 
00088         rc = usb_hc_get_handle_by_address(&conn, addr, dev_handle);
00089 
00090         usb_hc_connection_close(&conn);
00091 
00092         return rc;
00093 }
00094 
00114 int usb_resolve_device_handle(const char *dev_path, devman_handle_t *out_hc_handle,
00115     usb_address_t *out_dev_addr, devman_handle_t *out_dev_handle)
00116 {
00117         if (dev_path == NULL) {
00118                 return EBADMEM;
00119         }
00120 
00121         bool found_hc = false;
00122         bool found_addr = false;
00123         devman_handle_t hc_handle, dev_handle;
00124         usb_address_t dev_addr = -1;
00125         int rc;
00126         bool is_bus_addr;
00127         char *func_start = NULL;
00128         char *path = NULL;
00129 
00130         /* First try the BUS.ADDR format. */
00131         is_bus_addr = try_parse_bus_and_address(dev_path, &func_start,
00132             &hc_handle, &dev_addr);
00133         if (is_bus_addr) {
00134                 found_hc = true;
00135                 found_addr = true;
00136                 /*
00137                  * Now get the handle of the device. We will need that
00138                  * in both cases. If there is only BUS.ADDR, it will
00139                  * be the handle to be returned to the caller, otherwise
00140                  * we will need it to resolve the path to which the
00141                  * suffix would be appended.
00142                  */
00143                 /* If there is nothing behind the BUS.ADDR, we will
00144                  * get the device handle from the host controller.
00145                  * Otherwise, we will
00146                  */
00147                 rc = get_device_handle_by_address(hc_handle, dev_addr,
00148                     &dev_handle);
00149                 if (rc != EOK) {
00150                         return rc;
00151                 }
00152                 if (str_length(func_start) > 0) {
00153                         char tmp_path[MAX_DEVICE_PATH ];
00154                         rc = devman_get_device_path(dev_handle,
00155                             tmp_path, MAX_DEVICE_PATH);
00156                         if (rc != EOK) {
00157                                 return rc;
00158                         }
00159                         rc = asprintf(&path, "%s%s", tmp_path, func_start);
00160                         if (rc < 0) {
00161                                 return ENOMEM;
00162                         }
00163                 } else {
00164                         /* Everything is resolved. Get out of here. */
00165                         goto copy_out;
00166                 }
00167         } else {
00168                 path = str_dup(dev_path);
00169                 if (path == NULL) {
00170                         return ENOMEM;
00171                 }
00172         }
00173 
00174         /* First try to get the device handle. */
00175         rc = devman_device_get_handle(path, &dev_handle, 0);
00176         if (rc != EOK) {
00177                 free(path);
00178                 /* Invalid path altogether. */
00179                 return rc;
00180         }
00181 
00182         /* Remove suffixes and hope that we will encounter device node. */
00183         while (str_length(path) > 0) {
00184                 /* Get device handle first. */
00185                 devman_handle_t tmp_handle;
00186                 rc = devman_device_get_handle(path, &tmp_handle, 0);
00187                 if (rc != EOK) {
00188                         free(path);
00189                         return rc;
00190                 }
00191 
00192                 /* Try to find its host controller. */
00193                 if (!found_hc) {
00194                         rc = usb_hc_find(tmp_handle, &hc_handle);
00195                         if (rc == EOK) {
00196                                 found_hc = true;
00197                         }
00198                 }
00199 
00200                 /* Try to get its address. */
00201                 if (!found_addr) {
00202                         dev_addr = usb_hc_get_address_by_handle(tmp_handle);
00203                         if (dev_addr >= 0) {
00204                                 found_addr = true;
00205                         }
00206                 }
00207 
00208                 /* Speed-up. */
00209                 if (found_hc && found_addr) {
00210                         break;
00211                 }
00212 
00213                 /* Remove the last suffix. */
00214                 char *slash_pos = str_rchr(path, '/');
00215                 if (slash_pos != NULL) {
00216                         *slash_pos = 0;
00217                 }
00218         }
00219 
00220         free(path);
00221 
00222         if (!found_addr || !found_hc) {
00223                 return ENOENT;
00224         }
00225 
00226 copy_out:
00227         if (out_dev_addr != NULL) {
00228                 *out_dev_addr = dev_addr;
00229         }
00230         if (out_hc_handle != NULL) {
00231                 *out_hc_handle = hc_handle;
00232         }
00233         if (out_dev_handle != NULL) {
00234                 *out_dev_handle = dev_handle;
00235         }
00236 
00237         return EOK;
00238 }
00239 
00240 

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