⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 linux.c

📁 This libusb version 0.1.12. libusb is a library which allows userspace application access to USB de
💻 C
📖 第 1 页 / 共 2 页
字号:
/* * 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){

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -