summaryrefslogtreecommitdiffstats
path: root/libusb/linux.c
diff options
context:
space:
mode:
Diffstat (limited to 'libusb/linux.c')
-rw-r--r--libusb/linux.c733
1 files changed, 0 insertions, 733 deletions
diff --git a/libusb/linux.c b/libusb/linux.c
deleted file mode 100644
index 3a1ce0c..0000000
--- a/libusb/linux.c
+++ /dev/null
@@ -1,733 +0,0 @@
-/*
- * Linux USB support
- *
- * Copyright (c) 2000-2003 Johannes Erdfelt <johannes@erdfelt.com>
- *
- * This library is covered by the LGPL, read LICENSE for details.
- */
-
-#include <stdlib.h> /* getenv, etc */
-#include <unistd.h>
-#include <string.h>
-#include <stdio.h>
-#include <fcntl.h>
-#include <errno.h>
-#include <sys/time.h>
-#include <dirent.h>
-
-#include "linux.h"
-#include "usbi.h"
-
-static char usb_path[PATH_MAX + 1] = "";
-
-static int device_open(struct usb_device *dev)
-{
- char filename[PATH_MAX + 1];
- int fd;
-
- snprintf(filename, sizeof(filename) - 1, "%s/%s/%s",
- usb_path, dev->bus->dirname, dev->filename);
-
- fd = open(filename, O_RDWR);
- if (fd < 0) {
- fd = open(filename, O_RDONLY);
- if (fd < 0)
- USB_ERROR_STR(-errno, "failed to open %s: %s",
- filename, strerror(errno));
- }
-
- return fd;
-}
-
-int usb_os_open(usb_dev_handle *dev)
-{
- dev->fd = device_open(dev->device);
-
- return 0;
-}
-
-int usb_os_close(usb_dev_handle *dev)
-{
- if (dev->fd < 0)
- return 0;
-
- if (close(dev->fd) == -1)
- /* Failing trying to close a file really isn't an error, so return 0 */
- USB_ERROR_STR(0, "tried to close device fd %d: %s", dev->fd,
- strerror(errno));
-
- return 0;
-}
-
-int usb_set_configuration(usb_dev_handle *dev, int configuration)
-{
- int ret;
-
- ret = ioctl(dev->fd, IOCTL_USB_SETCONFIG, &configuration);
- if (ret < 0)
- USB_ERROR_STR(-errno, "could not set config %d: %s", configuration,
- strerror(errno));
-
- dev->config = configuration;
-
- return 0;
-}
-
-int usb_claim_interface(usb_dev_handle *dev, int interface)
-{
- int ret;
-
- ret = ioctl(dev->fd, IOCTL_USB_CLAIMINTF, &interface);
- if (ret < 0) {
- if (errno == EBUSY && usb_debug > 0)
- fprintf(stderr, "Check that you have permissions to write to %s/%s and, if you don't, that you set up hotplug (http://linux-hotplug.sourceforge.net/) correctly.\n", dev->bus->dirname, dev->device->filename);
-
- USB_ERROR_STR(-errno, "could not claim interface %d: %s", interface,
- strerror(errno));
- }
-
- dev->interface = interface;
-
- return 0;
-}
-
-int usb_release_interface(usb_dev_handle *dev, int interface)
-{
- int ret;
-
- ret = ioctl(dev->fd, IOCTL_USB_RELEASEINTF, &interface);
- if (ret < 0)
- USB_ERROR_STR(-errno, "could not release intf %d: %s", interface,
- strerror(errno));
-
- dev->interface = -1;
-
- return 0;
-}
-
-int usb_set_altinterface(usb_dev_handle *dev, int alternate)
-{
- int ret;
- struct usb_setinterface setintf;
-
- if (dev->interface < 0)
- USB_ERROR(-EINVAL);
-
- setintf.interface = dev->interface;
- setintf.altsetting = alternate;
-
- ret = ioctl(dev->fd, IOCTL_USB_SETINTF, &setintf);
- if (ret < 0)
- USB_ERROR_STR(-errno, "could not set alt intf %d/%d: %s",
- dev->interface, alternate, strerror(errno));
-
- dev->altsetting = alternate;
-
- return 0;
-}
-
-/*
- * Linux usbfs has a limit of one page size for synchronous bulk read/write.
- * 4096 is the most portable maximum we can do for now.
- * Linux usbfs has a limit of 16KB for the URB interface. We use this now
- * to get better performance for USB 2.0 devices.
- */
-#define MAX_READ_WRITE (16 * 1024)
-
-int usb_control_msg(usb_dev_handle *dev, int requesttype, int request,
- int value, int index, char *bytes, int size, int timeout)
-{
- struct usb_ctrltransfer ctrl;
- int ret;
-
- ctrl.bRequestType = requesttype;
- ctrl.bRequest = request;
- ctrl.wValue = value;
- ctrl.wIndex = index;
- ctrl.wLength = size;
-
- ctrl.data = bytes;
- ctrl.timeout = timeout;
-
- ret = ioctl(dev->fd, IOCTL_USB_CONTROL, &ctrl);
- if (ret < 0)
- USB_ERROR_STR(-errno, "error sending control message: %s", strerror(errno));
-
- return ret;
-}
-
-#define URB_USERCONTEXT_COOKIE ((void *)0x1)
-
-/* Reading and writing are the same except for the endpoint */
-static int usb_urb_transfer(usb_dev_handle *dev, int ep, int urbtype,
- char *bytes, int size, int timeout)
-{
- struct usb_urb urb;
- int bytesdone = 0, requested;
- struct timeval tv, tv_ref, tv_now;
- struct usb_urb *context;
- int ret, waiting;
-
- /*
- * HACK: The use of urb.usercontext is a hack to get threaded applications
- * sort of working again. Threaded support is still not recommended, but
- * this should allow applications to work in the common cases. Basically,
- * if we get the completion for an URB we're not waiting for, then we update
- * the usercontext pointer to 1 for the other threads URB and it will see
- * the change after it wakes up from the the timeout. Ugly, but it works.
- */
-
- /*
- * Get actual time, and add the timeout value. The result is the absolute
- * time where we have to quit waiting for an message.
- */
- gettimeofday(&tv_ref, NULL);
- tv_ref.tv_sec = tv_ref.tv_sec + timeout / 1000;
- tv_ref.tv_usec = tv_ref.tv_usec + (timeout % 1000) * 1000;
-
- if (tv_ref.tv_usec > 1000000) {
- tv_ref.tv_usec -= 1000000;
- tv_ref.tv_sec++;
- }
-
- do {
- fd_set writefds;
-
- requested = size - bytesdone;
- if (requested > MAX_READ_WRITE)
- requested = MAX_READ_WRITE;
-
- urb.type = urbtype;
- urb.endpoint = ep;
- urb.flags = 0;
- urb.buffer = bytes + bytesdone;
- urb.buffer_length = requested;
- urb.signr = 0;
- urb.actual_length = 0;
- urb.number_of_packets = 0; /* don't do isochronous yet */
- urb.usercontext = NULL;
-
- ret = ioctl(dev->fd, IOCTL_USB_SUBMITURB, &urb);
- if (ret < 0) {
- USB_ERROR_STR(-errno, "error submitting URB: %s", strerror(errno));
- return ret;
- }
-
- FD_ZERO(&writefds);
- FD_SET(dev->fd, &writefds);
-
-restart:
- waiting = 1;
- context = NULL;
- while (!urb.usercontext && ((ret = ioctl(dev->fd, IOCTL_USB_REAPURBNDELAY, &context)) == -1) && waiting) {
- tv.tv_sec = 0;
- tv.tv_usec = 1000; // 1 msec
- select(dev->fd + 1, NULL, &writefds, NULL, &tv); //sub second wait
-
- if (timeout) {
- /* compare with actual time, as the select timeout is not that precise */
- gettimeofday(&tv_now, NULL);
-
- if ((tv_now.tv_sec > tv_ref.tv_sec) ||
- ((tv_now.tv_sec == tv_ref.tv_sec) && (tv_now.tv_usec >= tv_ref.tv_usec)))
- waiting = 0;
- }
- }
-
- if (context && context != &urb) {
- context->usercontext = URB_USERCONTEXT_COOKIE;
- /* We need to restart since we got a successful URB, but not ours */
- goto restart;
- }
-
- /*
- * If there was an error, that wasn't EAGAIN (no completion), then
- * something happened during the reaping and we should return that
- * error now
- */
- if (ret < 0 && !urb.usercontext && errno != EAGAIN)
- USB_ERROR_STR(-errno, "error reaping URB: %s", strerror(errno));
-
- bytesdone += urb.actual_length;
- } while ((ret == 0 || urb.usercontext) && bytesdone < size && urb.actual_length == requested);
-
- /* If the URB didn't complete in success or error, then let's unlink it */
- if (ret < 0 && !urb.usercontext) {
- int rc;
-
- if (!waiting)
- rc = -ETIMEDOUT;
- else
- rc = urb.status;
-
- ret = ioctl(dev->fd, IOCTL_USB_DISCARDURB, &urb);
- if (ret < 0 && errno != EINVAL && usb_debug >= 1)
- fprintf(stderr, "error discarding URB: %s", strerror(errno));
-
- /*
- * When the URB is unlinked, it gets moved to the completed list and
- * then we need to reap it or else the next time we call this function,
- * we'll get the previous completion and exit early
- */
- ioctl(dev->fd, IOCTL_USB_REAPURB, &context);
-
- return rc;
- }
-
- return bytesdone;
-}
-
-int usb_bulk_write(usb_dev_handle *dev, int ep, char *bytes, int size,
- int timeout)
-{
- /* Ensure the endpoint address is correct */
- return usb_urb_transfer(dev, ep, USB_URB_TYPE_BULK, bytes, size,
- timeout);
-}
-
-int usb_bulk_read(usb_dev_handle *dev, int ep, char *bytes, int size,
- int timeout)
-{
- /* Ensure the endpoint address is correct */
- ep |= USB_ENDPOINT_IN;
- return usb_urb_transfer(dev, ep, USB_URB_TYPE_BULK, bytes, size,
- timeout);
-}
-
-/*
- * FIXME: Packetize large buffers here. 2.4 HCDs (atleast, haven't checked
- * 2.5 HCDs yet) don't handle multi-packet Interrupt transfers. So we need
- * to lookup the endpoint packet size and packetize appropriately here.
- */
-int usb_interrupt_write(usb_dev_handle *dev, int ep, char *bytes, int size,
- int timeout)
-{
- /* Ensure the endpoint address is correct */
- return usb_urb_transfer(dev, ep, USB_URB_TYPE_INTERRUPT, bytes, size,
- timeout);
-}
-
-int usb_interrupt_read(usb_dev_handle *dev, int ep, char *bytes, int size,
- int timeout)
-{
- /* Ensure the endpoint address is correct */
- ep |= USB_ENDPOINT_IN;
- return usb_urb_transfer(dev, ep, USB_URB_TYPE_INTERRUPT, bytes, size,
- timeout);
-}
-
-int usb_os_find_busses(struct usb_bus **busses)
-{
- struct usb_bus *fbus = NULL;
- DIR *dir;
- struct dirent *entry;
-
- dir = opendir(usb_path);
- if (!dir)
- USB_ERROR_STR(-errno, "couldn't opendir(%s): %s", usb_path,
- strerror(errno));
-
- while ((entry = readdir(dir)) != NULL) {
- struct usb_bus *bus;
-
- /* Skip anything starting with a . */
- if (entry->d_name[0] == '.')
- continue;
-
- if (!strchr("0123456789", entry->d_name[strlen(entry->d_name) - 1])) {
- if (usb_debug >= 2)
- fprintf(stderr, "usb_os_find_busses: Skipping non bus directory %s\n",
- entry->d_name);
- continue;
- }
-
- bus = malloc(sizeof(*bus));
- if (!bus)
- USB_ERROR(-ENOMEM);
-
- memset((void *)bus, 0, sizeof(*bus));
-
- strncpy(bus->dirname, entry->d_name, sizeof(bus->dirname) - 1);
- bus->dirname[sizeof(bus->dirname) - 1] = 0;
-
- LIST_ADD(fbus, bus);
-
- if (usb_debug >= 2)
- fprintf(stderr, "usb_os_find_busses: Found %s\n", bus->dirname);
- }
-
- closedir(dir);
-
- *busses = fbus;
-
- return 0;
-}
-
-int usb_os_find_devices(struct usb_bus *bus, struct usb_device **devices)
-{
- struct usb_device *fdev = NULL;
- DIR *dir;
- struct dirent *entry;
- char dirpath[PATH_MAX + 1];
-
- snprintf(dirpath, PATH_MAX, "%s/%s", usb_path, bus->dirname);
-
- dir = opendir(dirpath);
- if (!dir)
- USB_ERROR_STR(-errno, "couldn't opendir(%s): %s", dirpath,
- strerror(errno));
-
- while ((entry = readdir(dir)) != NULL) {
- unsigned char device_desc[DEVICE_DESC_LENGTH];
- char filename[PATH_MAX + 1];
- struct usb_device *dev;
- struct usb_connectinfo connectinfo;
- int i, fd, ret;
-
- /* Skip anything starting with a . */
- if (entry->d_name[0] == '.')
- continue;
-
- dev = malloc(sizeof(*dev));
- if (!dev)
- USB_ERROR(-ENOMEM);
-
- memset((void *)dev, 0, sizeof(*dev));
-
- dev->bus = bus;
-
- strncpy(dev->filename, entry->d_name, sizeof(dev->filename) - 1);
- dev->filename[sizeof(dev->filename) - 1] = 0;
-
- snprintf(filename, sizeof(filename) - 1, "%s/%s", dirpath, entry->d_name);
- fd = open(filename, O_RDWR);
- if (fd < 0) {
- fd = open(filename, O_RDONLY);
- if (fd < 0) {
- if (usb_debug >= 2)
- fprintf(stderr, "usb_os_find_devices: Couldn't open %s\n",
- filename);
-
- free(dev);
- continue;
- }
- }
-
- /* Get the device number */
- ret = ioctl(fd, IOCTL_USB_CONNECTINFO, &connectinfo);
- if (ret < 0) {
- if (usb_debug)
- fprintf(stderr, "usb_os_find_devices: couldn't get connect info\n");
- } else
- dev->devnum = connectinfo.devnum;
-
- ret = read(fd, (void *)device_desc, DEVICE_DESC_LENGTH);
- if (ret < 0) {
- if (usb_debug)
- fprintf(stderr, "usb_os_find_devices: Couldn't read descriptor\n");
-
- free(dev);
-
- goto err;
- }
-
- /*
- * Linux kernel converts the words in this descriptor to CPU endian, so
- * we use the undocumented W character for usb_parse_descriptor() that
- * doesn't convert endianess when parsing the descriptor
- */
- usb_parse_descriptor(device_desc, "bbWbbbbWWWbbbb", &dev->descriptor);
-
- LIST_ADD(fdev, dev);
-
- if (usb_debug >= 2)
- fprintf(stderr, "usb_os_find_devices: Found %s on %s\n",
- dev->filename, bus->dirname);
-
- /* Now try to fetch the rest of the descriptors */
- if (dev->descriptor.bNumConfigurations > USB_MAXCONFIG)
- /* Silent since we'll try again later */
- goto err;
-
- if (dev->descriptor.bNumConfigurations < 1)
- /* Silent since we'll try again later */
- goto err;
-
- dev->config = (struct usb_config_descriptor *)malloc(dev->descriptor.bNumConfigurations * sizeof(struct usb_config_descriptor));
- if (!dev->config)
- /* Silent since we'll try again later */
- goto err;
-
- memset(dev->config, 0, dev->descriptor.bNumConfigurations *
- sizeof(struct usb_config_descriptor));
-
- for (i = 0; i < dev->descriptor.bNumConfigurations; i++) {
- unsigned char buffer[8], *bigbuffer;
- struct usb_config_descriptor config;
-
- /* Get the first 8 bytes so we can figure out what the total length is */
- ret = read(fd, (void *)buffer, 8);
- if (ret < 8) {
- if (usb_debug >= 1) {
- if (ret < 0)
- fprintf(stderr, "Unable to get descriptor (%d)\n", ret);
- else
- fprintf(stderr, "Config descriptor too short (expected %d, got %d)\n", 8, ret);
- }
-
- goto err;
- }
-
- usb_parse_descriptor(buffer, "bbw", &config);
-
- bigbuffer = malloc(config.wTotalLength);
- if (!bigbuffer) {
- if (usb_debug >= 1)
- fprintf(stderr, "Unable to allocate memory for descriptors\n");
- goto err;
- }
-
- /* Read the rest of the config descriptor */
- memcpy(bigbuffer, buffer, 8);
-
- ret = read(fd, (void *)(bigbuffer + 8), config.wTotalLength - 8);
- if (ret < config.wTotalLength - 8) {
- if (usb_debug >= 1) {
- if (ret < 0)
- fprintf(stderr, "Unable to get descriptor (%d)\n", ret);
- else
- fprintf(stderr, "Config descriptor too short (expected %d, got %d)\n", config.wTotalLength, ret);
- }
-
- free(bigbuffer);
- goto err;
- }
-
- ret = usb_parse_configuration(&dev->config[i], bigbuffer);
- if (usb_debug >= 2) {
- if (ret > 0)
- fprintf(stderr, "Descriptor data still left\n");
- else if (ret < 0)
- fprintf(stderr, "Unable to parse descriptors\n");
- }
-
- free(bigbuffer);
- }
-
-err:
- close(fd);
- }
-
- closedir(dir);
-
- *devices = fdev;
-
- return 0;
-}
-
-int usb_os_determine_children(struct usb_bus *bus)
-{
- struct usb_device *dev, *devices[256];
- struct usb_ioctl command;
- int ret, i, i1;
-
- /* Create a list of devices first */
- memset(devices, 0, sizeof(devices));
- for (dev = bus->devices; dev; dev = dev->next)
- if (dev->devnum)
- devices[dev->devnum] = dev;
-
- /* Now fetch the children for each device */
- for (dev = bus->devices; dev; dev = dev->next) {
- struct usb_hub_portinfo portinfo;
- int fd;
-
- fd = device_open(dev);
- if (fd < 0)
- continue;
-
- /* Query the hub driver for the children of this device */
- if (dev->config && dev->config->interface && dev->config->interface->altsetting)
- command.ifno = dev->config->interface->altsetting->bInterfaceNumber;
- else
- command.ifno = 0;
- command.ioctl_code = IOCTL_USB_HUB_PORTINFO;
- command.data = &portinfo;
- ret = ioctl(fd, IOCTL_USB_IOCTL, &command);
- if (ret < 0) {
- /* errno == ENOSYS means the device probably wasn't a hub */
- if (errno != ENOSYS && usb_debug > 1)
- fprintf(stderr, "error obtaining child information: %s\n",
- strerror(errno));
-
- close(fd);
- continue;
- }
-
- dev->num_children = 0;
- for (i = 0; i < portinfo.numports; i++)
- if (portinfo.port[i])
- dev->num_children++;
-
- /* Free any old children first */
- free(dev->children);
-
- dev->children = malloc(sizeof(struct usb_device *) * dev->num_children);
- if (!dev->children) {
- if (usb_debug > 1)
- fprintf(stderr, "error allocating %zu bytes memory for dev->children\n",
- sizeof(struct usb_device *) * dev->num_children);
-
- dev->num_children = 0;
- close(fd);
- continue;
- }
-
- for (i = 0, i1 = 0; i < portinfo.numports; i++) {
- if (!portinfo.port[i])
- continue;
-
- dev->children[i1++] = devices[portinfo.port[i]];
-
- devices[portinfo.port[i]] = NULL;
- }
-
- close(fd);
- }
-
- /*
- * There should be one device left in the devices list and that should be
- * the root device
- */
- for (i = 0; i < sizeof(devices) / sizeof(devices[0]); i++) {
- if (devices[i])
- bus->root_dev = devices[i];
- }
-
- return 0;
-}
-
-static int check_usb_vfs(const char *dirname)
-{
- DIR *dir;
- struct dirent *entry;
- int found = 0;
-
- dir = opendir(dirname);
- if (!dir)
- return 0;
-
- while ((entry = readdir(dir)) != NULL) {
- /* Skip anything starting with a . */
- if (entry->d_name[0] == '.')
- continue;
-
- /* We assume if we find any files that it must be the right place */
- found = 1;
- break;
- }
-
- closedir(dir);
-
- return found;
-}
-
-void usb_os_init(void)
-{
- /* Find the path to the virtual filesystem */
- if (getenv("USB_DEVFS_PATH")) {
- if (check_usb_vfs(getenv("USB_DEVFS_PATH"))) {
- strncpy(usb_path, getenv("USB_DEVFS_PATH"), sizeof(usb_path) - 1);
- usb_path[sizeof(usb_path) - 1] = 0;
- } else if (usb_debug)
- fprintf(stderr, "usb_os_init: couldn't find USB VFS in USB_DEVFS_PATH\n");
- }
-
- if (!usb_path[0]) {
- if (check_usb_vfs("/dev/bus/usb")) {
- strncpy(usb_path, "/dev/bus/usb", sizeof(usb_path) - 1);
- usb_path[sizeof(usb_path) - 1] = 0;
- } else if (check_usb_vfs("/proc/bus/usb")) {
- strncpy(usb_path, "/proc/bus/usb", sizeof(usb_path) - 1);
- usb_path[sizeof(usb_path) - 1] = 0;
- } else
- usb_path[0] = 0; /* No path, no USB support */
- }
-
- if (usb_debug) {
- if (usb_path[0])
- fprintf(stderr, "usb_os_init: Found USB VFS at %s\n", usb_path);
- else
- fprintf(stderr, "usb_os_init: No USB VFS found, is it mounted?\n");
- }
-}
-
-int usb_resetep(usb_dev_handle *dev, unsigned int ep)
-{
- int ret;
-
- ret = ioctl(dev->fd, IOCTL_USB_RESETEP, &ep);
- if (ret)
- USB_ERROR_STR(-errno, "could not reset ep %d: %s", ep,
- strerror(errno));
-
- return 0;
-}
-
-int usb_clear_halt(usb_dev_handle *dev, unsigned int ep)
-{
- int ret;
-
- ret = ioctl(dev->fd, IOCTL_USB_CLEAR_HALT, &ep);
- if (ret)
- USB_ERROR_STR(-errno, "could not clear/halt ep %d: %s", ep,
- strerror(errno));
-
- return 0;
-}
-
-int usb_reset(usb_dev_handle *dev)
-{
- int ret;
-
- ret = ioctl(dev->fd, IOCTL_USB_RESET, NULL);
- if (ret)
- USB_ERROR_STR(-errno, "could not reset: %s", strerror(errno));
-
- return 0;
-}
-
-int usb_get_driver_np(usb_dev_handle *dev, int interface, char *name,
- unsigned int namelen)
-{
- struct usb_getdriver getdrv;
- int ret;
-
- getdrv.interface = interface;
- ret = ioctl(dev->fd, IOCTL_USB_GETDRIVER, &getdrv);
- if (ret)
- USB_ERROR_STR(-errno, "could not get bound driver: %s", strerror(errno));
-
- strncpy(name, getdrv.driver, namelen - 1);
- name[namelen - 1] = 0;
-
- return 0;
-}
-
-int usb_detach_kernel_driver_np(usb_dev_handle *dev, int interface)
-{
- struct usb_ioctl command;
- int ret;
-
- command.ifno = interface;
- command.ioctl_code = IOCTL_USB_DISCONNECT;
- command.data = NULL;
-
- ret = ioctl(dev->fd, IOCTL_USB_IOCTL, &command);
- if (ret)
- USB_ERROR_STR(-errno, "could not detach kernel driver from interface %d: %s",
- interface, strerror(errno));
-
- return 0;
-}
-