Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit e6e5daac authored by jp abgrall's avatar jp abgrall Committed by Android Git Automerger
Browse files

am edeed28b: am 4a280e3d: Merge "Don\'t use control requests to read device serial numbers."

* commit 'edeed28b':
  Don't use control requests to read device serial numbers.
parents b453a9aa edeed28b
Loading
Loading
Loading
Loading
+103 −78
Original line number Diff line number Diff line
@@ -75,10 +75,18 @@ struct usb_handle
    unsigned char ep_out;
};

/* True if name isn't a valid name for a USB device in /sys/bus/usb/devices.
 * Device names are made up of numbers, dots, and dashes, e.g., '7-1.5'.
 * We reject interfaces (e.g., '7-1.5:1.0') and host controllers (e.g. 'usb1').
 * The name must also start with a digit, to disallow '.' and '..'
 */
static inline int badname(const char *name)
{
    while(*name) {
        if(!isdigit(*name++)) return 1;
    if (!isdigit(*name))
      return 1;
    while(*++name) {
        if(!isdigit(*name) && *name != '.' && *name != '-')
            return 1;
    }
    return 0;
}
@@ -95,7 +103,8 @@ static int check(void *_desc, int len, unsigned type, int size)
    return 0;
}

static int filter_usb_device(int fd, char *ptr, int len, int writable,
static int filter_usb_device(int fd, char* sysfs_name,
                             char *ptr, int len, int writable,
                             ifc_match_func callback,
                             int *ept_in_id, int *ept_out_id, int *ifc_id)
{
@@ -131,69 +140,35 @@ static int filter_usb_device(int fd, char *ptr, int len, int writable,
    info.dev_protocol = dev->bDeviceProtocol;
    info.writable = writable;

    // read device serial number (if there is one)
    info.serial_number[0] = 0;
    if (dev->iSerialNumber) {
        struct usbdevfs_ctrltransfer  ctrl;
        // Keep it short enough because some bootloaders are borked if the URB len is > 255
        // 128 is too big by 1.
        __u16 buffer[127];

        memset(buffer, 0, sizeof(buffer));

        ctrl.bRequestType = USB_DIR_IN|USB_TYPE_STANDARD|USB_RECIP_DEVICE;
        ctrl.bRequest = USB_REQ_GET_DESCRIPTOR;
        ctrl.wValue = (USB_DT_STRING << 8) | dev->iSerialNumber;
        //language ID (en-us) for serial number string
        ctrl.wIndex = 0x0409;
        ctrl.wLength = sizeof(buffer);
        ctrl.data = buffer;
        ctrl.timeout = 50;

        result = ioctl(fd, USBDEVFS_CONTROL, &ctrl);
        if (result > 0) {
            int i;
            // skip first word, and copy the rest to the serial string, changing shorts to bytes.
            result /= 2;
            for (i = 1; i < result; i++)
                info.serial_number[i - 1] = buffer[i];
            info.serial_number[i - 1] = 0;
        }
    }

    /* We need to get a path that represents a particular port on a particular
     * hub.  We are passed an fd that was obtained by opening an entry under
     * /dev/bus/usb.  Unfortunately, the names of those entries change each
     * time devices are plugged and unplugged.  So how to get a repeatable
     * path?  udevadm provided the inspiration.  We can get the major and
     * minor of the device file, read the symlink that can be found here:
     *   /sys/dev/char/<major>:<minor>
     * and then use the last element of that path.  As a concrete example, I
     * have an Android device at /dev/bus/usb/001/027 so working with bash:
     *   $ ls -l /dev/bus/usb/001/027
     *   crw-rw-r-- 1 root plugdev 189, 26 Apr  9 11:03 /dev/bus/usb/001/027
     *   $ ls -l /sys/dev/char/189:26
     *   lrwxrwxrwx 1 root root 0 Apr  9 11:03 /sys/dev/char/189:26 ->
     *           ../../devices/pci0000:00/0000:00:1a.7/usb1/1-4/1-4.2/1-4.2.3
     * So our device_path would be 1-4.2.3 which says my device is connected
     * to port 3 of a hub on port 2 of a hub on port 4 of bus 1 (per
     * http://www.linux-usb.org/FAQ.html).
    snprintf(info.device_path, sizeof(info.device_path), "usb:%s", sysfs_name);

    /* Read device serial number (if there is one).
     * We read the serial number from sysfs, since it's faster and more
     * reliable than issuing a control pipe read, and also won't
     * cause problems for devices which don't like getting descriptor
     * requests while they're in the middle of flashing.
     */
    info.device_path[0] = '\0';
    result = fstat(fd, &st);
    if (!result && S_ISCHR(st.st_mode)) {
        char cdev[128];
        char link[256];
        char *slash;
        ssize_t link_len;
        snprintf(cdev, sizeof(cdev), "/sys/dev/char/%d:%d",
                 major(st.st_rdev), minor(st.st_rdev));
        link_len = readlink(cdev, link, sizeof(link) - 1);
        if (link_len > 0) {
            link[link_len] = '\0';
            slash = strrchr(link, '/');
            if (slash)
                snprintf(info.device_path, sizeof(info.device_path), "usb:%s", slash+1);
    info.serial_number[0] = '\0';
    if (dev->iSerialNumber) {
        char path[80];
        int fd;

        snprintf(path, sizeof(path),
                 "/sys/bus/usb/devices/%s/serial", sysfs_name);
        path[sizeof(path) - 1] = '\0';

        fd = open(path, O_RDONLY);
        if (fd >= 0) {
            int chars_read = read(fd, info.serial_number,
                                  sizeof(info.serial_number) - 1);
            close(fd);

            if (chars_read <= 0)
                info.serial_number[0] = '\0';
            else if (info.serial_number[chars_read - 1] == '\n') {
                // strip trailing newline
                info.serial_number[chars_read - 1] = '\0';
            }
        }
    }

@@ -241,14 +216,73 @@ static int filter_usb_device(int fd, char *ptr, int len, int writable,
    return -1;
}

static int read_sysfs_string(const char *sysfs_name, const char *sysfs_node,
                             char* buf, int bufsize)
{
    char path[80];
    int fd, n;

    snprintf(path, sizeof(path),
             "/sys/bus/usb/devices/%s/%s", sysfs_name, sysfs_node);
    path[sizeof(path) - 1] = '\0';

    fd = open(path, O_RDONLY);
    if (fd < 0)
        return -1;

    n = read(fd, buf, bufsize - 1);
    close(fd);

    if (n < 0)
        return -1;

    buf[n] = '\0';

    return n;
}

static int read_sysfs_number(const char *sysfs_name, const char *sysfs_node)
{
    char buf[16];
    int value;

    if (read_sysfs_string(sysfs_name, sysfs_node, buf, sizeof(buf)) < 0)
        return -1;

    if (sscanf(buf, "%d", &value) != 1)
        return -1;

    return value;
}

/* Given the name of a USB device in sysfs, get the name for the same
 * device in devfs. Returns 0 for success, -1 for failure.
 */
static int convert_to_devfs_name(const char* sysfs_name,
                                 char* devname, int devname_size)
{
    int busnum, devnum;

    busnum = read_sysfs_number(sysfs_name, "busnum");
    if (busnum < 0)
        return -1;

    devnum = read_sysfs_number(sysfs_name, "devnum");
    if (devnum < 0)
        return -1;

    snprintf(devname, devname_size, "/dev/bus/usb/%03d/%03d", busnum, devnum);
    return 0;
}

static usb_handle *find_usb_device(const char *base, ifc_match_func callback)
{
    usb_handle *usb = 0;
    char busname[64], devname[64];
    char devname[64];
    char desc[1024];
    int n, in, out, ifc;

    DIR *busdir, *devdir;
    DIR *busdir;
    struct dirent *de;
    int fd;
    int writable;
@@ -259,15 +293,7 @@ static usb_handle *find_usb_device(const char *base, ifc_match_func callback)
    while((de = readdir(busdir)) && (usb == 0)) {
        if(badname(de->d_name)) continue;

        sprintf(busname, "%s/%s", base, de->d_name);
        devdir = opendir(busname);
        if(devdir == 0) continue;

//        DBG("[ scanning %s ]\n", busname);
        while((de = readdir(devdir)) && (usb == 0)) {

            if(badname(de->d_name)) continue;
            sprintf(devname, "%s/%s", busname, de->d_name);
        if(!convert_to_devfs_name(de->d_name, devname, sizeof(devname))) {

//            DBG("[ scanning %s ]\n", devname);
            writable = 1;
@@ -282,7 +308,7 @@ static usb_handle *find_usb_device(const char *base, ifc_match_func callback)

            n = read(fd, desc, sizeof(desc));

            if(filter_usb_device(fd, desc, n, writable, callback,
            if(filter_usb_device(fd, de->d_name, desc, n, writable, callback,
                                 &in, &out, &ifc) == 0) {
                usb = calloc(1, sizeof(usb_handle));
                strcpy(usb->fname, devname);
@@ -301,7 +327,6 @@ static usb_handle *find_usb_device(const char *base, ifc_match_func callback)
                close(fd);
            }
        }
        closedir(devdir);
    }
    closedir(busdir);

@@ -431,5 +456,5 @@ int usb_close(usb_handle *h)

usb_handle *usb_open(ifc_match_func callback)
{
    return find_usb_device("/dev/bus/usb", callback);
    return find_usb_device("/sys/bus/usb/devices", callback);
}