?? linux.c
字號:
/* * 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] = "";int usb_os_open(usb_dev_handle *dev){ char filename[PATH_MAX + 1]; snprintf(filename, sizeof(filename) - 1, "%s/%s/%s", usb_path, dev->bus->dirname, dev->device->filename); dev->fd = open(filename, O_RDWR); if (dev->fd < 0) { dev->fd = open(filename, O_RDONLY); if (dev->fd < 0) USB_ERROR_STR(-errno, "failed to open %s: %s", filename, strerror(errno)); } 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 usbdevfs has a limit of one page size per read/write. 4096 is *//* the most portable maximum we can do for now */#define MAX_READ_WRITE 4096int usb_bulk_write(usb_dev_handle *dev, int ep, char *bytes, int length, int timeout){ struct usb_bulktransfer bulk; int ret, sent = 0; /* Ensure the endpoint address is correct */ ep &= ~USB_ENDPOINT_IN; do { bulk.ep = ep; bulk.len = length - sent; if (bulk.len > MAX_READ_WRITE) bulk.len = MAX_READ_WRITE; bulk.timeout = timeout; bulk.data = (unsigned char *)bytes + sent; ret = ioctl(dev->fd, IOCTL_USB_BULK, &bulk); if (ret < 0) USB_ERROR_STR(-errno, "error writing to bulk endpoint %d: %s", ep, strerror(errno)); sent += ret; } while (ret > 0 && sent < length); return sent;}int usb_bulk_read(usb_dev_handle *dev, int ep, char *bytes, int size, int timeout){ struct usb_bulktransfer bulk; int ret, retrieved = 0, requested; /* Ensure the endpoint address is correct */ ep |= USB_ENDPOINT_IN; do { bulk.ep = ep; requested = size - retrieved; if (requested > MAX_READ_WRITE) requested = MAX_READ_WRITE; bulk.len = requested; bulk.timeout = timeout; bulk.data = (unsigned char *)bytes + retrieved; ret = ioctl(dev->fd, IOCTL_USB_BULK, &bulk); if (ret < 0) USB_ERROR_STR(-errno, "error reading from bulk endpoint 0x%x: %s", ep, strerror(errno)); retrieved += ret; } while (ret > 0 && retrieved < size && ret == requested); return retrieved;}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;}/* Reading and writing are the same except for the endpoint */static int usb_interrupt_transfer(usb_dev_handle *dev, int ep, char *bytes, int size, int timeout){ struct usb_urb int_urb; void *context; int ret; unsigned int bytesdone = 0, requested; struct timeval tv, tv_ref, tv_now; int waiting; /* * 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. */ /* get actual time, and add the timeout value. The result is the absolute * time where we have to quit waiting for an interrupt 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 > 1e6) { tv_ref.tv_usec -= 1e6; tv_ref.tv_sec++; } do { requested = size - bytesdone; if (requested > MAX_READ_WRITE) requested = MAX_READ_WRITE; int_urb.type = USB_URB_TYPE_INTERRUPT; int_urb.endpoint = ep; int_urb.flags = 0; int_urb.buffer = bytes + bytesdone; int_urb.buffer_length = requested; int_urb.usercontext = (void *)ep; int_urb.signr = 0; int_urb.actual_length = 0; ret = ioctl(dev->fd, IOCTL_USB_SUBMITURB, &int_urb); if (ret < 0) { USB_ERROR_STR(-errno, "error submitting URB: %s", strerror(errno)); return ret; } waiting = 1; while (((ret = ioctl(dev->fd, IOCTL_USB_REAPURBNDELAY, &context)) == -1) && waiting) { tv.tv_sec = 0; tv.tv_usec = 1000; // 1 msec select(0, NULL, NULL, NULL, &tv); //sub second wait /* 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_usec >= tv_ref.tv_usec)) waiting = 0; } /* * 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 && errno != EAGAIN) USB_ERROR_STR(-errno, "error reaping interrupt URB: %s", strerror(errno)); bytesdone += int_urb.actual_length; } while (ret > 0 && bytesdone < size && ret == requested); /* If the URB didn't complete in success or error, then let's unlink it */ if (ret < 0) { int rc; if (!waiting) rc = -ETIMEDOUT; else rc = int_urb.status; ret = ioctl(dev->fd, IOCTL_USB_DISCARDURB, &int_urb); if (ret < 0 && errno != EINVAL && usb_debug >= 1) fprintf(stderr, "error discarding interrupt URB: %s", strerror(errno)); return rc; } return bytesdone;}int usb_interrupt_write(usb_dev_handle *dev, int ep, char *bytes, int size, int timeout){ /* Ensure the endpoint address is correct */ return usb_interrupt_transfer(dev, ep & ~USB_ENDPOINT_IN, 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 */ return usb_interrupt_transfer(dev, ep | USB_ENDPOINT_IN, bytes, size, timeout);}int usb_os_find_busses(struct usb_bus **busses){ struct usb_bus *fbus = NULL;
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -