Ignore:
File:
1 edited

Legend:

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

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