libusb:在Android上无法获得配置描述符

时间:2013-07-30 05:43:18

标签: android libusb libusb-1.0

我正在调试使用libusb-compat和libusb-1.0在Android上打开设备(在Android代码和从connection.getFileDescriptor()收到的文件描述符中授予的权限),我收到错误:

07-30 11:24:15.673: WARN/System.err(8934): libusb: 0.000122 error [op_get_config_descriptor] open '/dev/bus/usb/001/002' failed, ret=-1 errno=13

我在libusb.h找不到错误13。

我的调试输出(fprintf)的初始代码(来自libusb-compat)是:

static int initialize_device(struct usb_device *dev)
{
    libusb_device *newlib_dev = dev->dev;
    int num_configurations;
    size_t alloc_size;
    int r;
    int i;

    /* Device descriptor is identical in both libs */
    r = libusb_get_device_descriptor(newlib_dev, (struct libusb_device_descriptor *) &dev->descriptor); // Error here!
    if (r < 0) {
        usbi_err("error %d getting device descriptor", r);
        return compat_err(r);
    } else {
        // 4ntoine
        fprintf(stderr, "pid=%i vid=%i serial=%i\n",
            dev->descriptor.idProduct, dev->descriptor.idVendor, dev->descriptor.iSerialNumber);
    }

    num_configurations = dev->descriptor.bNumConfigurations;
    alloc_size = sizeof(struct usb_config_descriptor) * num_configurations;
    dev->config = malloc(alloc_size);
    if (!dev->config)
        return -ENOMEM;
    memset(dev->config, 0, alloc_size);

    /* Even though structures are identical, we can't just use libusb-1.0's
     * config descriptors because we have to store all configurations in
     * a single flat memory area (libusb-1.0 provides separate allocations).
     * we hand-copy libusb-1.0's descriptors into our own structures. */

    // 4ntoine
    fprintf(stderr, "%i configurations\n", num_configurations);

    for (i = 0; i < num_configurations; i++) {
        struct libusb_config_descriptor *newlib_config;
        r = libusb_get_config_descriptor(newlib_dev, i, &newlib_config);

        if (r < 0) {
            // 4ntoine
            fprintf(stderr, "failed to libusb_get_config_descriptor: %i\n", r);

            clear_device(dev);
            free(dev->config);
            return compat_err(r);
        }

        // 4ntoine - print information
        fprintf(stderr, "Interfaces: %i\n", (int)config->bNumInterfaces);
        const libusb_interface *inter;
        const libusb_interface_descriptor *interdesc;
        const libusb_endpoint_descriptor *epdesc;
        for(int i=0; i<(int)config->bNumInterfaces; i++) {
            inter = &config->interface[i];
            fprintf(stderr, "Number of alternate settings: %i\n", inter->num_altsetting;
            for(int j=0; j<inter->num_altsetting; j++) {
                interdesc = &inter->altsetting[j];
                fprintf(stderr, "Interface Number: %i\n", (int)interdesc->bInterfaceNumber);
                fprintf(stderr, "Number of endpoints: %i\n", (int)interdesc->bNumEndpoints);
                for(int k=0; k<(int)interdesc->bNumEndpoints; k++) {
                    epdesc = &interdesc->endpoint[k];
                    fprintf(stderr, "Descriptor Type: %i\n", (int)epdesc->bDescriptorType);
                    fprintf(stderr, "EP Address: %i\n", (int)epdesc->bEndpointAddress);
                }
            }
        }

        r = copy_config_descriptor(dev->config + i, newlib_config);
        libusb_free_config_descriptor(newlib_config);
        if (r < 0) {
            // 4ntoine
            fprintf(stderr, "failed to copy_config_descriptor: %i\n", r);

            clear_device(dev);
            free(dev->config);
            return r;
        }
    }

    /* libusb doesn't implement this and it doesn't seem that important. If
     * someone asks for it, we can implement it in v1.1 or later. */
    dev->num_children = 0;
    dev->children = NULL;

    libusb_ref_device(newlib_dev);
    return 0;
}

更新:我正在接近解决我的问题。我发现op_get_config_descriptor(linux_usbfs.c)使用设备路径来使用open()获取fd,但它已经从Android连接接收并应该被使用。所以我不得不更改代码以将fd传递给op_get_config_descriptor()并将其重命名为op_get_config_descriptor2():

static int op_get_config_descriptor2(
    struct libusb_device *dev,
    uint8_t config_index,
    unsigned char *buffer,
    size_t len,
    int *host_endian,
    int fd)
{
    char filename[PATH_MAX];
    int _fd = fd;
    int r;

    /* Always read from usbfs: sysfs only has the active descriptor
     * this will involve waking the device up, but oh well! */

    /* FIXME: the above is no longer true, new kernels have all descriptors
     * in the descriptors file. but its kinda hard to detect if the kernel
     * is sufficiently new. */

    // 4ntoine
     if (_fd < 0) {
        _get_usbfs_path(dev, filename);
        _fd = open(filename, O_RDONLY);
        if (_fd < 0) {
            usbi_err(DEVICE_CTX(dev),
                "open '%s' failed, ret=%d errno=%d", filename, _fd, errno);
            return LIBUSB_ERROR_IO;
        }
    }
    else {
        usbi_dbg("using fd = %i\n", _fd);
    }

    r = get_config_descriptor(DEVICE_CTX(dev), _fd, config_index, buffer, len);
    close(_fd);
    return r;
}

现在的问题是找不到使用该fd的USB设备(它通过Unix套接字传递给AVRDUDE,我检查它是肯定的int,所以我相信它是好的): lseek(fd, DEVICE_DESC_LENGTH, SEEK_SET)返回负值

输出结果为:

07-30 15:39:08.723: WARN/System.err(30394): [ 07-30 15:39:08.723 30394: 1764 W/System.err ]
        libusb: 0.004884 error [get_config_descriptor] seek failed ret=-1 errno=9

如何解决此问题?

1 个答案:

答案 0 :(得分:0)

我通过删除close(_fd);解决了这个问题。第一次调用关闭设备,第二次调用失败,因为它(文件描述符c):

int API_EXPORTED libusb_get_config_descriptor(
    libusb_device *dev,
    uint8_t config_index,
    struct libusb_config_descriptor **config,
    int fd)
{
    struct libusb_config_descriptor *_config;
    unsigned char tmp[8];
    unsigned char *buf = NULL;
    int host_endian = 0;
    int r;
    usbi_dbg("index %d\n", config_index);
    if (config_index >= dev->num_configurations)
        return LIBUSB_ERROR_NOT_FOUND;

    _config = malloc(sizeof(*_config));
    if (!_config)
        return LIBUSB_ERROR_NO_MEM;

    usbi_dbg("get_config_descriptor2 1\n"); // 1st invocation
    r = usbi_backend->get_config_descriptor2(dev, config_index, tmp, sizeof(tmp), &host_endian, fd);
    if (r < 0)
        goto err;

    usbi_parse_descriptor(tmp, "bbw", _config, host_endian);
    usbi_dbg("usbi_parse_descriptor: length=%i\n", _config->wTotalLength);
    buf = malloc(_config->wTotalLength);
    if (!buf) {
        r = LIBUSB_ERROR_NO_MEM;
        goto err;
    }

    host_endian = 0;
    usbi_dbg("get_config_descriptor2 2\n"); // 2nd invocation - error here!
    r = usbi_backend->get_config_descriptor2(dev, config_index, buf, _config->wTotalLength, &host_endian, fd);
    if (r < 0)
        goto err;

    usbi_dbg("parse_configuration\n");
    r = parse_configuration(dev->ctx, _config, buf, host_endian);
    if (r < 0) {
        usbi_err(dev->ctx, "parse_configuration failed with error %d", r);
        goto err;
    }
    else
        if (r > 0) {
            usbi_warn(dev->ctx, "descriptor data still left");
        }

    free(buf);
    *config = _config;
    return 0;

    err:
          free(_config);
          if (buf)
              free(buf);
          return r;
}