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; }
int usb_isochronous_submit(usb_dev_handle *dev, // Open usb device handle. usb_urb *iso_urb, // Pointer to URB. struct timeval *tv_submit) { // Time structure pointer. int ret; // Get actual time, of the URB submission. gettimeofday(tv_submit, NULL); // Submit the URB through an IOCTL call. ret = ioctl(dev->fd, IOCTL_USB_SUBMITURB, iso_urb); //fprintf(stderr, "start_frame now: %d\n", iso_urb->start_frame); //fprintf(stderr, "submit ioctl return value: %d\n", ret); if (ret < 0) { //fprintf(stderr, "error submitting URB: %s\n", strerror(errno)); USB_ERROR_STR(-errno, "error submitting URB: %s", strerror(errno)); } return ret; }
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_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; }
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_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; }
int usb_set_altinterface(usb_dev_handle *dev, int alternate) { int ret; struct usb_alt_interface intf; if (dev->interface < 0) USB_ERROR(-EINVAL); intf.uai_interface_index = dev->interface; intf.uai_alt_no = alternate; ret = ioctl(dev->fd, USB_SET_ALTINTERFACE, &intf); 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; }
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 int usb_isochronous_setup(usb_urb **iso_urb, // URB pointer-pointer. unsigned char ep, // Device endpoint. int pktsize, // Endpoint packet size. char *bytes, // Data buffer pointer. int size) { // Size of the buffer. struct usb_urb *local_urb; // int ret // was unused /lindi int pktcount, fullpkts, partpktsize, packets, urb_size; // No more than 32768 bytes can be transferred at a time. if (size > 32768) { USB_ERROR_STR(-errno, "error on transfer size: %s", strerror(EINVAL)); return -EINVAL; } // Determine the number of packets that need to be created based upon the // amount of data to be transferred, and the maximum packet size of the // endpoint. // Find integral number of full packets. //fprintf(stderr, "buf size: %d\n", size); //fprintf(stderr, "iso size: %d\n", pktsize); fullpkts = size / pktsize; //fprintf(stderr, "Number of full packets: %d\n", fullpkts); // Find length of partial packet. partpktsize = size % pktsize; //fprintf(stderr, "Size of partial packet: %d\n", partpktsize); // Find total number of packets to be transfered. packets = fullpkts + ((partpktsize > 0) ? 1 : 0); //fprintf(stderr, "Total number of packets: %d\n", packets); // Limit the number of packets transfered according to // the Linux usbdevfs maximum read/write buffer size. if ((packets < 1) || (packets > 128)) { USB_ERROR_STR(-errno, "error on packet size: %s", strerror(EINVAL)); return -EINVAL; } // If necessary, allocate the urb and packet // descriptor structures from the heap. local_urb = *iso_urb; if (!local_urb) { urb_size = sizeof(struct usb_urb) + packets * sizeof(struct usb_iso_packet_desc); local_urb = (struct usb_urb *) calloc(1, urb_size); if (!local_urb) { USB_ERROR_STR(-errno, "error on packet size: %s", strerror(EINVAL)); return -ENOMEM; } } // Set up each packet for the data to be transferred. for (pktcount = 0; pktcount < fullpkts; pktcount++) { struct usbdevfs_iso_packet_desc* iso_frame_desc = &local_urb->iso_frame_desc[pktcount]; iso_frame_desc->length = pktsize; iso_frame_desc->actual_length = 0; iso_frame_desc->status = 0; } // Set up the last packet for the partial data to be transferred. if (partpktsize > 0) { local_urb->iso_frame_desc[pktcount].length = partpktsize; local_urb->iso_frame_desc[pktcount].actual_length = 0; local_urb->iso_frame_desc[pktcount++].status = 0; } // Set up the URB structure. local_urb->type = USB_URB_TYPE_ISO; //fprintf(stderr, "type: %d\n", local_urb->type); local_urb->endpoint = ep; //fprintf(stderr, "endpoint: 0x%x\n", local_urb->endpoint); local_urb->status = 0; local_urb->flags = USB_URB_ISO_ASAP; // Additional flags here? //fprintf(stderr, "flags: %d\n", local_urb->flags); local_urb->buffer = bytes; //fprintf(stderr, "buffer: 0x%x\n", local_urb->buffer); local_urb->buffer_length = size; //fprintf(stderr, "buffer_length: %d\n", local_urb->buffer_length); local_urb->actual_length = 0; local_urb->start_frame = 0; //fprintf(stderr, "start_frame: %d\n", local_urb->start_frame); local_urb->number_of_packets = pktcount; //fprintf(stderr, "number_of_packets: %d\n", local_urb->number_of_packets); local_urb->error_count = 0; local_urb->signr = 0; //fprintf(stderr, "signr: %d\n", local_urb->signr); local_urb->usercontext = (void *) 0; *iso_urb = local_urb; return 0; }
int usb_isochronous_reap(usb_dev_handle *dev, // Open usb device handle. usb_urb *iso_urb, // Pointer to URB. struct timeval *tv_reap, // Time structure pointer. int timeout) { // Attempt timeout (msec). struct timeval tv_ref, tv; void *context; int waiting, ret; // Get actual time, and add the timeout value. The result is the absolute // time where we have to quit waiting for an isochronous 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; // Roll over 1e6 microseconds to one second. if (tv_ref.tv_usec > 1e6) { tv_ref.tv_usec -= 1e6; tv_ref.tv_sec++; } waiting = 1; //fprintf(stderr, "preparing to reap\n"); 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 to actual time, as the select timeout isn"t that precise */ gettimeofday(tv_reap, NULL); if ((tv_reap->tv_sec >= tv_ref.tv_sec) && (tv_reap->tv_usec >= tv_ref.tv_usec)) waiting = 0; } // Get actual time of the URB reap for maintaining data flow. gettimeofday(tv_reap, NULL); /* * If there was an error, that wasn"t EAGAIN (no completion), then * something happened during the reaping and we should return that * error now */ //fprintf(stderr, "reap ioctl return value: %d\n", ret); if (ret < 0 && errno != EAGAIN) { USB_ERROR_STR(-errno, "error reaping interrupt URB: %s", strerror(errno)); } //fprintf(stderr, "actual_length: %d\n", iso_urb->actual_length); //fprintf(stderr, "URB status: %d\n", iso_urb->status); //fprintf(stderr, "error count: %d\n", iso_urb->error_count); //fprintf(stderr, "waiting done\n"); // 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 = iso_urb->status; ret = ioctl(dev->fd, IOCTL_USB_DISCARDURB, iso_urb); //fprintf(stderr, "discard ioctl return value: %d\n", ret); if (ret < 0 && errno != EINVAL && usb_debug >= 1) { USB_ERROR_STR(-errno, "error discarding isochronous URB: %s", strerror(errno)); } //fprintf(stderr, "status: %d\n", rc); return rc; } //fprintf(stderr, "Total bytes: %d\n", bytesdone); return iso_urb->actual_length; }
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; }
/* Reading and writing are the same except for the endpoint */ static int usb_urb_transfer_sp(usb_dev_handle *dev, int ep, int urbtype, char *bytes, int size, int timeout, int *actual_length, int max_rw) { 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_rw) requested = max_rw; 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 && timeout!=32767) { // 32767 is a magic number for no 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; *actual_length = bytesdone; } 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_reset(usb_dev_handle *dev) { /* Not yet done, because I haven't needed it. */ USB_ERROR_STR(-ENOSYS, "usb_reset called, unimplemented on BSD"); }
int usb_clear_halt(usb_dev_handle *dev, unsigned int ep) { /* Not yet done, because I haven't needed it. */ USB_ERROR_STR(-ENOSYS, "usb_clear_halt called, unimplemented on BSD"); }
int usb_os_find_devices(struct usb_bus *bus, struct usb_device **devices) { struct usb_device *fdev = NULL; int cfd, dfd; int device; cfd = open(bus->dirname, O_RDONLY); if (cfd < 0) USB_ERROR_STR(-errno, "couldn't open(%s): %s", bus->dirname, strerror(errno)); for (device = 1; device < USB_MAX_DEVICES; device++) { struct usb_device_info di; struct usb_device *dev; unsigned char device_desc[DEVICE_DESC_LENGTH]; char buf[20]; di.udi_addr = device; if (ioctl(cfd, USB_DEVICEINFO, &di) < 0) continue; /* There's a device; is it one we should mess with? */ if (strncmp(di.udi_devnames[0], "ugen", 4) != 0) /* best not to play with things we don't understand */ continue; #ifdef __FreeBSD_kernel__ snprintf(buf, sizeof(buf) - 1, "/dev/%s", di.udi_devnames[0]); #else snprintf(buf, sizeof(buf) - 1, "/dev/%s.00", di.udi_devnames[0]); #endif /* Open its control endpoint */ dfd = open(buf, O_RDONLY); if (dfd < 0) { if (usb_debug >= 2) fprintf(stderr, "usb_os_find_devices: couldn't open device %s: %s\n", buf, strerror(errno)); continue; } dev = malloc(sizeof(*dev)); if (!dev) USB_ERROR(-ENOMEM); memset((void *)dev, 0, sizeof(*dev)); dev->bus = bus; /* we need to report the device name as /dev/ugenx NOT /dev/ugenx.00 * This seemed easier than having 2 variables... */ #if (__NetBSD__ || __OpenBSD__) snprintf(buf, sizeof(buf) - 1, "/dev/%s", di.udi_devnames[0]); #endif strncpy(dev->filename, buf, sizeof(dev->filename) - 1); dev->filename[sizeof(dev->filename) - 1] = 0; if (ioctl(dfd, USB_GET_DEVICE_DESC, device_desc) < 0) USB_ERROR_STR(-errno, "couldn't get device descriptor for %s: %s", buf, strerror(errno)); close(dfd); 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); } close(cfd); *devices = fdev; return 0; }