質問

I'm debugging opening a device on Android (permission granted in Android code and file descriptor received from connection.getFileDescriptor()) using libusb-compat and libusb-1.0, and I'm getting an error:

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

I can't find errno 13 in libusb.h.

The init code (from libusb-compat) with my debug output (fprintf's) is:

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;
}

UPDATE: I'm getting closer to fix my problem. I found that op_get_config_descriptor (linux_usbfs.c) uses the device path to get fd using open(), but it was already received from the Android connection and should be used. So I had to change the code to pass fd to op_get_config_descriptor() and rename it to 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;
}

Now the problem is that a USB device can't be found using that fd (it is passed to AVRDUDE via Unix socket, and I check it to be positive int, so I believe it's okay): lseek(fd, DEVICE_DESC_LENGTH, SEEK_SET) returns negative value

The output is:

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

How can I fix this problem?

役に立ちましたか?

解決

I solved by removing close(_fd);. The first invocation closes the device and the second fails because of it (file descriptor.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;
}
ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top