Ignore:
File:
1 edited

Legend:

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

    rb7fd2a0 rf9b2cb4c  
    2929
    3030#include <usb/dev.h>
     31#include <usb/hc.h>
    3132#include <errno.h>
    3233#include <usb_iface.h>
    3334#include <str.h>
    3435#include <stdio.h>
     36
     37#define MAX_DEVICE_PATH 1024
     38
     39/** Find host controller handle, address and iface number for the device.
     40 *
     41 * @param[in] device_handle Device devman handle.
     42 * @param[out] hc_handle Where to store handle of host controller
     43 *      controlling device with @p device_handle handle.
     44 * @param[out] address Place to store the device's address
     45 * @param[out] iface Place to stoer the assigned USB interface number.
     46 * @return Error code.
     47 */
     48int usb_get_info_by_handle(devman_handle_t device_handle,
     49    devman_handle_t *hc_handle, usb_address_t *address, int *iface)
     50{
     51        async_sess_t *parent_sess =
     52            devman_parent_device_connect(device_handle, IPC_FLAG_BLOCKING);
     53        if (!parent_sess)
     54                return ENOMEM;
     55
     56        async_exch_t *exch = async_exchange_begin(parent_sess);
     57        if (!exch) {
     58                async_hangup(parent_sess);
     59                return ENOMEM;
     60        }
     61
     62        usb_address_t tmp_address;
     63        devman_handle_t tmp_handle;
     64        int tmp_iface;
     65
     66        if (address) {
     67                const int ret = usb_get_my_address(exch, &tmp_address);
     68                if (ret != EOK) {
     69                        async_exchange_end(exch);
     70                        async_hangup(parent_sess);
     71                        return ret;
     72                }
     73        }
     74
     75        if (hc_handle) {
     76                const int ret = usb_get_hc_handle(exch, &tmp_handle);
     77                if (ret != EOK) {
     78                        async_exchange_end(exch);
     79                        async_hangup(parent_sess);
     80                        return ret;
     81                }
     82        }
     83
     84        if (iface) {
     85                const int ret = usb_get_my_interface(exch, &tmp_iface);
     86                switch (ret) {
     87                case ENOTSUP:
     88                        /* Implementing GET_MY_INTERFACE is voluntary. */
     89                        tmp_iface = -1;
     90                case EOK:
     91                        break;
     92                default:
     93                        async_exchange_end(exch);
     94                        async_hangup(parent_sess);
     95                        return ret;
     96                }
     97        }
     98
     99        if (hc_handle)
     100                *hc_handle = tmp_handle;
     101
     102        if (address)
     103                *address = tmp_address;
     104
     105        if (iface)
     106                *iface = tmp_iface;
     107
     108        async_exchange_end(exch);
     109        async_hangup(parent_sess);
     110
     111        return EOK;
     112}
     113
     114static bool try_parse_bus_and_address(const char *path,
     115    const char **func_start,
     116    devman_handle_t *out_hc_handle, usb_address_t *out_device_address)
     117{
     118        uint64_t sid;
     119        size_t address;
     120        int rc;
     121        const char *ptr;
     122
     123        rc = str_uint64_t(path, &ptr, 10, false, &sid);
     124        if (rc != EOK) {
     125                return false;
     126        }
     127        if ((*ptr == ':') || (*ptr == '.')) {
     128                ptr++;
     129        } else {
     130                return false;
     131        }
     132        rc = str_size_t(ptr, func_start, 10, false, &address);
     133        if (rc != EOK) {
     134                return false;
     135        }
     136        rc = usb_ddf_get_hc_handle_by_sid(sid, out_hc_handle);
     137        if (rc != EOK) {
     138                return false;
     139        }
     140        if (out_device_address != NULL) {
     141                *out_device_address = (usb_address_t) address;
     142        }
     143        return true;
     144}
     145
     146static int get_device_handle_by_address(devman_handle_t hc_handle, int addr,
     147    devman_handle_t *dev_handle)
     148{
     149        usb_hc_connection_t conn;
     150        usb_hc_connection_initialize(&conn, hc_handle);
     151
     152        const int rc = usb_hc_get_handle_by_address(&conn, addr, dev_handle);
     153
     154        return rc;
     155}
    35156
    36157/** Resolve handle and address of USB device from its path.
     
    53174 * @return Error code.
    54175 */
    55 errno_t usb_resolve_device_handle(const char *dev_path, devman_handle_t *dev_handle)
     176int usb_resolve_device_handle(const char *dev_path, devman_handle_t *out_hc_handle,
     177    usb_address_t *out_dev_addr, devman_handle_t *out_dev_handle)
    56178{
    57         if (dev_path == NULL || dev_handle == NULL) {
     179        if (dev_path == NULL) {
    58180                return EBADMEM;
    59181        }
    60182
    61         /* First, try to get the device handle. */
    62         errno_t rc = devman_fun_get_handle(dev_path, dev_handle, 0);
    63 
    64         /* Next, try parsing dev_handle from the provided string */
     183        bool found_hc = false;
     184        bool found_addr = false;
     185        devman_handle_t hc_handle, dev_handle;
     186        usb_address_t dev_addr = -1;
     187        int rc;
     188        bool is_bus_addr;
     189        const char *func_start = NULL;
     190        char *path = NULL;
     191
     192        /* First try the BUS.ADDR format. */
     193        is_bus_addr = try_parse_bus_and_address(dev_path, &func_start,
     194            &hc_handle, &dev_addr);
     195        if (is_bus_addr) {
     196                found_hc = true;
     197                found_addr = true;
     198                /*
     199                 * Now get the handle of the device. We will need that
     200                 * in both cases. If there is only BUS.ADDR, it will
     201                 * be the handle to be returned to the caller, otherwise
     202                 * we will need it to resolve the path to which the
     203                 * suffix would be appended.
     204                 */
     205                /* If there is nothing behind the BUS.ADDR, we will
     206                 * get the device handle from the host controller.
     207                 * Otherwise, we will
     208                 */
     209                rc = get_device_handle_by_address(hc_handle, dev_addr,
     210                    &dev_handle);
     211                if (rc != EOK) {
     212                        return rc;
     213                }
     214                if (str_length(func_start) > 0) {
     215                        char tmp_path[MAX_DEVICE_PATH];
     216                        rc = devman_fun_get_path(dev_handle,
     217                            tmp_path, MAX_DEVICE_PATH);
     218                        if (rc != EOK) {
     219                                return rc;
     220                        }
     221                        rc = asprintf(&path, "%s%s", tmp_path, func_start);
     222                        if (rc < 0) {
     223                                return ENOMEM;
     224                        }
     225                } else {
     226                        /* Everything is resolved. Get out of here. */
     227                        goto copy_out;
     228                }
     229        } else {
     230                path = str_dup(dev_path);
     231                if (path == NULL) {
     232                        return ENOMEM;
     233                }
     234        }
     235
     236        /* First try to get the device handle. */
     237        rc = devman_fun_get_handle(path, &dev_handle, 0);
    65238        if (rc != EOK) {
    66                 *dev_handle = strtoul(dev_path, NULL, 10);
    67                 //FIXME: check errno
    68                 rc = EOK;
    69         }
    70         return rc;
     239                free(path);
     240                /* Invalid path altogether. */
     241                return rc;
     242        }
     243
     244        /* Remove suffixes and hope that we will encounter device node. */
     245        while (str_length(path) > 0) {
     246                /* Get device handle first. */
     247                devman_handle_t tmp_handle;
     248                rc = devman_fun_get_handle(path, &tmp_handle, 0);
     249                if (rc != EOK) {
     250                        free(path);
     251                        return rc;
     252                }
     253
     254                /* Try to find its host controller. */
     255                if (!found_hc) {
     256                        rc = usb_get_hc_by_handle(tmp_handle, &hc_handle);
     257                        if (rc == EOK) {
     258                                found_hc = true;
     259                        }
     260                }
     261
     262                /* Try to get its address. */
     263                if (!found_addr) {
     264                        rc = usb_get_address_by_handle(tmp_handle, &dev_addr);
     265                        if (rc == 0) {
     266                                found_addr = true;
     267                        }
     268                }
     269
     270                /* Speed-up. */
     271                if (found_hc && found_addr) {
     272                        break;
     273                }
     274
     275                /* Remove the last suffix. */
     276                char *slash_pos = str_rchr(path, '/');
     277                if (slash_pos != NULL) {
     278                        *slash_pos = 0;
     279                }
     280        }
     281
     282        free(path);
     283
     284        if (!found_addr || !found_hc) {
     285                return ENOENT;
     286        }
     287
     288copy_out:
     289        if (out_dev_addr != NULL) {
     290                *out_dev_addr = dev_addr;
     291        }
     292        if (out_hc_handle != NULL) {
     293                *out_hc_handle = hc_handle;
     294        }
     295        if (out_dev_handle != NULL) {
     296                *out_dev_handle = dev_handle;
     297        }
     298
     299        return EOK;
    71300}
Note: See TracChangeset for help on using the changeset viewer.