?? linux_usbfs.c
字號:
} r = get_config_descriptor(DEVICE_CTX(dev), fd, config_index, buffer, len); close(fd); *host_endian = 1; return r;}/* cache the active config descriptor in memory. a value of -1 means that * we aren't sure which one is active, so just assume the first one. * only for usbfs. */static int cache_active_config(struct libusb_device *dev, int fd, int active_config){ struct linux_device_priv *priv = __device_priv(dev); struct libusb_config_descriptor config; unsigned char tmp[8]; unsigned char *buf; int idx; int r; if (active_config == -1) { idx = 0; } else { r = usbi_get_config_index_by_value(dev, active_config, &idx); if (r < 0) return r; if (idx == -1) return LIBUSB_ERROR_NOT_FOUND; } r = get_config_descriptor(DEVICE_CTX(dev), fd, idx, tmp, sizeof(tmp)); if (r < 0) { usbi_err(DEVICE_CTX(dev), "first read error %d", r); return r; } usbi_parse_descriptor(tmp, "bbw", &config, 1); buf = malloc(config.wTotalLength); if (!buf) return LIBUSB_ERROR_NO_MEM; r = get_config_descriptor(DEVICE_CTX(dev), fd, idx, buf, config.wTotalLength); if (r < 0) { free(buf); return r; } if (priv->config_descriptor) free(priv->config_descriptor); priv->config_descriptor = buf; return 0;}/* send a control message to retrieve active configuration */static int usbfs_get_active_config(struct libusb_device *dev, int fd){ int active_config; int r; struct usbfs_ctrltransfer ctrl = { .bmRequestType = LIBUSB_ENDPOINT_IN, .bRequest = LIBUSB_REQUEST_GET_CONFIGURATION, .wValue = 0, .wIndex = 0, .wLength = 1, .timeout = 1000, .data = &active_config }; r = ioctl(fd, IOCTL_USBFS_CONTROL, &ctrl); if (r < 0) { if (errno == ENODEV) return LIBUSB_ERROR_NO_DEVICE; usbi_err(DEVICE_CTX(dev), "get_configuration failed ret=%d errno=%d", r, errno); return LIBUSB_ERROR_IO; } return active_config;}static int initialize_device(struct libusb_device *dev, uint8_t busnum, uint8_t devaddr, const char *sysfs_dir){ struct linux_device_priv *priv = __device_priv(dev); unsigned char *dev_buf; char path[PATH_MAX]; int fd; int active_config = 0; int device_configured = 1; ssize_t r; dev->bus_number = busnum; dev->device_address = devaddr; if (sysfs_dir) { priv->sysfs_dir = malloc(strlen(sysfs_dir) + 1); if (!priv->sysfs_dir) return LIBUSB_ERROR_NO_MEM; strcpy(priv->sysfs_dir, sysfs_dir); } if (sysfs_has_descriptors) return 0; /* cache device descriptor in memory so that we can retrieve it later * without waking the device up (op_get_device_descriptor) */ priv->dev_descriptor = NULL; priv->config_descriptor = NULL; if (sysfs_can_relate_devices) { int tmp = sysfs_get_active_config(dev, &active_config); if (tmp < 0) return tmp; if (active_config == -1) device_configured = 0; } __get_usbfs_path(dev, path); fd = open(path, O_RDWR); if (fd < 0 && errno == EACCES) { fd = open(path, O_RDONLY); /* if we only have read-only access to the device, we cannot * send a control message to determine the active config. just * assume the first one is active. */ active_config = -1; } if (fd < 0) { usbi_err(DEVICE_CTX(dev), "open failed, ret=%d errno=%d", fd, errno); return LIBUSB_ERROR_IO; } if (!sysfs_can_relate_devices) { if (active_config == -1) { /* if we only have read-only access to the device, we cannot * send a control message to determine the active config. just * assume the first one is active. */ usbi_warn(DEVICE_CTX(dev), "access to %s is read-only; cannot " "determine active configuration descriptor", path); } else { active_config = usbfs_get_active_config(dev, fd); if (active_config < 0) { close(fd); return active_config; } else if (active_config == 0) { /* some buggy devices have a configuration 0, but we're * reaching into the corner of a corner case here, so let's * not support buggy devices in these circumstances. * stick to the specs: a configuration value of 0 means * unconfigured. */ usbi_dbg("assuming unconfigured device"); device_configured = 0; } } } dev_buf = malloc(DEVICE_DESC_LENGTH); if (!dev_buf) { close(fd); return LIBUSB_ERROR_NO_MEM; } r = read(fd, dev_buf, DEVICE_DESC_LENGTH); if (r < 0) { usbi_err(DEVICE_CTX(dev), "read descriptor failed ret=%d errno=%d", fd, errno); free(dev_buf); close(fd); return LIBUSB_ERROR_IO; } else if (r < DEVICE_DESC_LENGTH) { usbi_err(DEVICE_CTX(dev), "short descriptor read (%d)", r); free(dev_buf); close(fd); return LIBUSB_ERROR_IO; } /* bit of a hack: set num_configurations now because cache_active_config() * calls usbi_get_config_index_by_value() which uses it */ dev->num_configurations = dev_buf[DEVICE_DESC_LENGTH - 1]; if (device_configured) { r = cache_active_config(dev, fd, active_config); if (r < 0) { close(fd); free(dev_buf); return r; } } close(fd); priv->dev_descriptor = dev_buf; return 0;}static int enumerate_device(struct libusb_context *ctx, struct discovered_devs **_discdevs, uint8_t busnum, uint8_t devaddr, const char *sysfs_dir){ struct discovered_devs *discdevs; unsigned long session_id; int need_unref = 0; struct libusb_device *dev; int r = 0; /* FIXME: session ID is not guaranteed unique as addresses can wrap and * will be reused. instead we should add a simple sysfs attribute with * a session ID. */ session_id = busnum << 8 | devaddr; usbi_dbg("busnum %d devaddr %d session_id %ld", busnum, devaddr, session_id); dev = usbi_get_device_by_session_id(ctx, session_id); if (dev) { usbi_dbg("using existing device for %d/%d (session %ld)", busnum, devaddr, session_id); } else { usbi_dbg("allocating new device for %d/%d (session %ld)", busnum, devaddr, session_id); dev = usbi_alloc_device(ctx, session_id); if (!dev) return LIBUSB_ERROR_NO_MEM; need_unref = 1; r = initialize_device(dev, busnum, devaddr, sysfs_dir); if (r < 0) goto out; r = usbi_sanitize_device(dev); if (r < 0) goto out; } discdevs = discovered_devs_append(*_discdevs, dev); if (!discdevs) r = LIBUSB_ERROR_NO_MEM; else *_discdevs = discdevs;out: if (need_unref) libusb_unref_device(dev); return r;}/* open a bus directory and adds all discovered devices to discdevs. on * failure (non-zero return) the pre-existing discdevs should be destroyed * (and devices freed). on success, the new discdevs pointer should be used * as it may have been moved. */static int usbfs_scan_busdir(struct libusb_context *ctx, struct discovered_devs **_discdevs, uint8_t busnum){ DIR *dir; char dirpath[PATH_MAX]; struct dirent *entry; struct discovered_devs *discdevs = *_discdevs; int r = 0; snprintf(dirpath, PATH_MAX, "%s/%03d", usbfs_path, busnum); usbi_dbg("%s", dirpath); dir = opendir(dirpath); if (!dir) { usbi_err(ctx, "opendir '%s' failed, errno=%d", dirpath, errno); /* FIXME: should handle valid race conditions like hub unplugged * during directory iteration - this is not an error */ return LIBUSB_ERROR_IO; } while ((entry = readdir(dir))) { int devaddr; if (entry->d_name[0] == '.') continue; devaddr = atoi(entry->d_name); if (devaddr == 0) { usbi_dbg("unknown dir entry %s", entry->d_name); continue; } r = enumerate_device(ctx, &discdevs, busnum, (uint8_t) devaddr, NULL); if (r < 0) goto out; } *_discdevs = discdevs;out: closedir(dir); return r;}static int usbfs_get_device_list(struct libusb_context *ctx, struct discovered_devs **_discdevs){ struct dirent *entry; DIR *buses = opendir(usbfs_path); struct discovered_devs *discdevs = *_discdevs; int r = 0; if (!buses) { usbi_err(ctx, "opendir buses failed errno=%d", errno); return LIBUSB_ERROR_IO; } while ((entry = readdir(buses))) { struct discovered_devs *discdevs_new = discdevs; int busnum; if (entry->d_name[0] == '.') continue; busnum = atoi(entry->d_name); if (busnum == 0) { usbi_dbg("unknown dir entry %s", entry->d_name); continue; } r = usbfs_scan_busdir(ctx, &discdevs_new, busnum); if (r < 0) goto out; discdevs = discdevs_new; }out: closedir(buses); *_discdevs = discdevs; return r;}static int sysfs_scan_device(struct libusb_context *ctx, struct discovered_devs **_discdevs, const char *devname, int *usbfs_fallback){ int r; FILE *fd; char filename[PATH_MAX]; int busnum; int devaddr; usbi_dbg("scan %s", devname); /* determine descriptors presence ahead of time, we need to know this * when we reach initialize_device */ if (sysfs_has_descriptors == -1) { struct stat statbuf; snprintf(filename, PATH_MAX, "%s/%s/descriptors", SYSFS_DEVICE_PATH, devname); r = stat(filename, &statbuf); if (r == 0 && S_ISREG(statbuf.st_mode)) { usbi_dbg("sysfs descriptors available"); sysfs_has_descriptors = 1; } else { usbi_dbg("sysfs descriptors not available"); sysfs_has_descriptors = 0; } } snprintf(filename, PATH_MAX, "%s/%s/busnum", SYSFS_DEVICE_PATH, devname); fd = fopen(filename, "r"); if (!fd) { if (errno == ENOENT) { usbi_dbg("busnum not found, cannot relate sysfs to usbfs, " "falling back on pure usbfs"); sysfs_can_relate_devices = 0; *usbfs_fallback = 1; return LIBUSB_ERROR_OTHER; } usbi_err(ctx, "open busnum failed, errno=%d", errno); return LIBUSB_ERROR_IO; } sysfs_can_relate_devices = 1; r = fscanf(fd, "%d", &busnum); fclose(fd); if (r != 1) { usbi_err(ctx, "fscanf busnum returned %d, errno=%d", r, errno); return LIBUSB_ERROR_IO; } snprintf(filename, PATH_MAX, "%s/%s/devnum", SYSFS_DEVICE_PATH, devname); fd = fopen(filename, "r"); if (!fd) { usbi_err(ctx, "open devnum failed, errno=%d", errno); return LIBUSB_ERROR_IO; } r = fscanf(fd, "%d", &devaddr); fclose(fd); if (r != 1) { usbi_err(ctx, "fscanf devnum returned %d, errno=%d", r, errno); return LIBUSB_ERROR_IO; } usbi_dbg("bus=%d dev=%d", busnum, devaddr); if (busnum > 255 || devaddr > 255) return LIBUSB_ERROR_INVALID_PARAM; return enumerate_device(ctx, _discdevs, busnum & 0xff, devaddr & 0xff, devname);}static int sysfs_get_device_list(struct libusb_context *ctx, struct discovered_devs **_discdevs, int *usbfs_fallback){ struct discovered_devs *discdevs = *_discdevs; DIR *devices = opendir(SYSFS_DEVICE_PATH); struct dirent *entry; int r = 0; if (!devices) { usbi_err(ctx, "opendir devices failed errno=%d", errno); return LIBUSB_ERROR_IO; } while ((entry = readdir(devices))) { struct discovered_devs *discdevs_new = discdevs; if ((!isdigit(entry->d_name[0]) && strncmp(entry->d_name, "usb", 3)) || strchr(entry->d_name, ':')) continue; r = sysfs_scan_device(ctx, &discdevs_new, entry->d_name, usbfs_fallback); if (r < 0) goto out; discdevs = discdevs_new; } out: closedir(devices); *_discdevs = discdevs; return r;}static int op_get_device_list(struct libusb_context *ctx, struct discovered_devs **_discdevs){ /* we can retrieve device list and descriptors from sysfs or usbfs. * sysfs is preferable, because if we use usbfs we end up resuming * any autosuspended USB devices. however, sysfs is not available * everywhere, so we need a usbfs fallback too. * * as described in the "sysfs vs usbfs" comment, sometimes we have * sysfs but not enough information to relate sysfs devices to usbfs * nodes. the usbfs_fallback variable is used to indicate that we should * fall back on usbfs. */ if (sysfs_can_relate_devices != 0) { int usbfs_fallback = 0; int r = sysfs_get_device_list(ctx, _discdevs, &usbfs_fallback); if (!usbfs_fallback) return r; } return usbfs_get_device_list(ctx, _discdevs);}static int op_open(struct libusb_device_handle *handle){ struct linux_device_handle_priv *hpriv = __device_handle_priv(handle); char filename[PATH_MAX]; __get_usbfs_path(handle->dev, filename); hpriv->fd = open(filename, O_RDWR); if (hpriv->fd < 0) { if (errno == EACCES) { fprintf(stderr, "libusb couldn't open USB device %s: " "Permission denied.\n" "libusb requires write access to USB device nodes.\n", filename); return LIBUSB_ERROR_ACCESS; } else if (errno == ENOENT) { return LIBUSB_ERROR_NO_DEVICE; } else { usbi_err(HANDLE_CTX(handle), "open failed, code %d errno %d", hpriv->fd, errno); return LIBUSB_ERROR_IO; } } return usbi_add_pollfd(HANDLE_CTX(handle), hpriv->fd, POLLOUT);}static void op_close(struct libusb_device_handle *dev_handle){ int fd = __device_handle_priv(dev_handle)->fd; usbi_remove_pollfd(HANDLE_CTX(dev_handle), fd); close(fd);}static int op_get_configuration(struct libusb_device_handle *handle, int *config){ int r; if (sysfs_can_relate_devices != 1) return LIBUSB_ERROR_NOT_SUPPORTED; r = sysfs_get_active_config(handle->dev, config);
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -