2 * Core functions for libusb
3 * Copyright (C) 2007-2008 Daniel Drake <dsd@gentoo.org>
4 * Copyright (c) 2001 Johannes Erdfelt <johannes@erdfelt.com>
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
32 #include <sys/ioctl.h>
33 #include <sys/types.h>
40 struct list_head usb_devs;
41 struct list_head open_devs;
42 static const char *usbfs_path = NULL;
44 static int check_usb_vfs(const char *dirname)
50 dir = opendir(dirname);
54 while ((entry = readdir(dir)) != NULL) {
55 if (entry->d_name[0] == '.')
58 /* We assume if we find any files that it must be the right place */
67 static const char *find_usbfs_path(void)
69 const char *path = "/dev/bus/usb";
70 const char *ret = NULL;
72 if (check_usb_vfs(path)) {
75 path = "/proc/bus/usb";
76 if (check_usb_vfs(path))
80 usbi_dbg("found usbfs at %s", ret);
84 /* we traverse usbfs without knowing how many devices we are going to find.
85 * so we create this discovered_devs model which is similar to a linked-list
86 * which grows when required. it can be freed once discovery has completed,
87 * eliminating the need for a list node in the libusb_device structure
89 #define DISCOVERED_DEVICES_SIZE_STEP 8
90 struct discovered_devs {
93 struct libusb_device *devices[0];
96 static struct discovered_devs *discovered_devs_alloc(void)
98 struct discovered_devs *ret =
99 malloc(sizeof(*ret) + (sizeof(void *) * DISCOVERED_DEVICES_SIZE_STEP));
103 ret->capacity = DISCOVERED_DEVICES_SIZE_STEP;
108 /* append a device to the discovered devices collection. may realloc itself,
109 * returning new discdevs. returns NULL on realloc failure. */
110 static struct discovered_devs *discovered_devs_append(
111 struct discovered_devs *discdevs, struct libusb_device *dev)
113 size_t len = discdevs->len;
116 /* if there is space, just append the device */
117 if (len < discdevs->capacity) {
118 discdevs->devices[len] = libusb_device_ref(dev);
123 /* exceeded capacity, need to grow */
124 usbi_dbg("need to increase capacity");
125 capacity = discdevs->capacity + DISCOVERED_DEVICES_SIZE_STEP;
126 discdevs = realloc(discdevs,
127 sizeof(*discdevs) + (sizeof(void *) * capacity));
129 discdevs->capacity = capacity;
130 discdevs->devices[len] = libusb_device_ref(dev);
137 static void discovered_devs_free(struct discovered_devs *discdevs)
141 for (i = 0; i < discdevs->len; i++)
142 libusb_device_unref(discdevs->devices[i]);
147 static struct libusb_device *device_new(uint8_t busnum, uint8_t devaddr)
149 char path[PATH_MAX + 1];
150 unsigned char raw_desc[DEVICE_DESC_LENGTH];
151 struct libusb_device *dev = malloc(sizeof(*dev));
161 dev->nodepath = NULL;
164 snprintf(path, PATH_MAX, "%s/%03d/%03d", usbfs_path, busnum, devaddr);
165 usbi_dbg("%s", path);
166 fd = open(path, O_RDWR);
168 usbi_dbg("open '%s' failed, ret=%d errno=%d", path, fd, errno);
169 /* FIXME this might not be an error if the file has gone away due
174 r = read(fd, raw_desc, DEVICE_DESC_LENGTH);
176 usbi_err("read failed ret=%d errno=%d", r, errno);
179 /* FIXME: short read handling? */
181 usbi_parse_descriptor(raw_desc, "bbWbbbbWWWbbbb", &dev->desc);
183 /* Now try to fetch the rest of the descriptors */
184 if (dev->desc.bNumConfigurations > USB_MAXCONFIG) {
185 usbi_err("too many configurations");
189 if (dev->desc.bNumConfigurations < 1) {
190 usbi_dbg("no configurations?");
194 tmp = dev->desc.bNumConfigurations * sizeof(struct libusb_config_descriptor);
195 dev->config = malloc(tmp);
199 memset(dev->config, 0, tmp);
200 for (i = 0; i < dev->desc.bNumConfigurations; i++) {
201 unsigned char buffer[8], *bigbuffer;
202 struct libusb_config_descriptor config;
204 /* Get the first 8 bytes to figure out what the total length is */
205 r = read(fd, buffer, sizeof(buffer));
206 if (r < sizeof(buffer)) {
207 usbi_err("short descriptor read (%d/%d)", r, sizeof(buffer));
211 usbi_parse_descriptor(buffer, "bbw", &config);
213 bigbuffer = malloc(config.wTotalLength);
217 /* Read the rest of the config descriptor */
218 memcpy(bigbuffer, buffer, sizeof(buffer));
220 tmp = config.wTotalLength - 8;
221 r = read(fd, bigbuffer + 8, tmp);
223 usbi_err("short descriptor read (%d/%d)", r, tmp);
228 r = usbi_parse_configuration(&dev->config[i], bigbuffer);
230 usbi_warn("descriptor data still left\n");
234 dev->nodepath = strdup(path);
238 dev->session_data = busnum << 8 | devaddr;
239 list_add(&dev->list, &usb_devs);
255 static struct libusb_device *get_device_by_session_id(unsigned long session_id)
257 struct libusb_device *dev;
259 list_for_each_entry(dev, &usb_devs, list)
260 if (dev->session_data == session_id)
266 /* open a device file, set up the libusb_device structure for it, and add it to
267 * discdevs. on failure (non-zero return) the pre-existing discdevs should
268 * be destroyed (and devices freed). on success, the new discdevs pointer
269 * should be used it may have been moved. */
270 static int scan_device(struct discovered_devs **_discdevs, uint8_t busnum,
273 struct discovered_devs *discdevs;
274 unsigned long session_id;
275 struct libusb_device *dev;
279 /* FIXME: session ID is not guaranteed unique as addresses can wrap and
280 * will be reused. instead we should add a simple sysfs attribute with
282 session_id = busnum << 8 | devaddr;
283 usbi_dbg("busnum %d devaddr %d session_id %ld", busnum, devaddr,
286 dev = get_device_by_session_id(session_id);
288 usbi_dbg("using existing device for %d/%d (session %ld)",
289 busnum, devaddr, session_id);
291 usbi_dbg("allocating new device for %d/%d (session %ld)",
292 busnum, devaddr, session_id);
293 dev = device_new(busnum, devaddr);
301 discdevs = discovered_devs_append(*_discdevs, dev);
305 *_discdevs = discdevs;
309 libusb_device_unref(dev);
313 /* open a bus directory and adds all discovered devices to discdevs. on
314 * failure (non-zero return) the pre-existing discdevs should be destroyed
315 * (and devices freed). on success, the new discdevs pointer should be used
316 * as it may have been moved. */
317 static int scan_busdir(struct discovered_devs **_discdevs, uint8_t busnum)
320 char dirpath[PATH_MAX + 1];
321 struct dirent *entry;
322 struct discovered_devs *discdevs = *_discdevs;
325 snprintf(dirpath, PATH_MAX, "%s/%03d", usbfs_path, busnum);
326 usbi_dbg("%s", dirpath);
327 dir = opendir(dirpath);
329 usbi_err("opendir '%s' failed, errno=%d", dirpath, errno);
330 /* FIXME: should handle valid race conditions like hub unplugged
331 * during directory iteration - this is not an error */
335 while ((entry = readdir(dir))) {
338 if (entry->d_name[0] == '.')
341 devaddr = atoi(entry->d_name);
343 usbi_dbg("unknown dir entry %s", entry->d_name);
347 r = scan_device(&discdevs, busnum, (uint8_t) devaddr);
352 *_discdevs = discdevs;
358 API_EXPORTED int libusb_get_device_list(struct libusb_device ***list)
361 struct discovered_devs *discdevs = discovered_devs_alloc();
362 struct dirent *entry;
363 struct libusb_device **ret;
372 buses = opendir(usbfs_path);
374 usbi_err("opendir buses failed errno=%d", errno);
378 while ((entry = readdir(buses))) {
379 struct discovered_devs *discdevs_new = discdevs;
382 if (entry->d_name[0] == '.')
385 busnum = atoi(entry->d_name);
387 usbi_dbg("unknown dir entry %s", entry->d_name);
391 r = scan_busdir(&discdevs_new, busnum);
394 discdevs = discdevs_new;
397 /* convert discovered_devs into a list */
399 ret = malloc(sizeof(void *) * (len + 1));
406 for (i = 0; i < len; i++) {
407 struct libusb_device *dev = discdevs->devices[i];
408 ret[i] = libusb_device_ref(dev);
413 discovered_devs_free(discdevs);
418 API_EXPORTED void libusb_free_device_list(struct libusb_device **list,
426 struct libusb_device *dev;
428 while ((dev = list[i++]) != NULL)
429 libusb_device_unref(dev);
434 API_EXPORTED struct libusb_device *libusb_device_ref(struct libusb_device *dev)
440 API_EXPORTED void libusb_device_unref(struct libusb_device *dev)
445 if (--dev->refcnt == 0) {
446 usbi_dbg("destroy device %04x:%04x", dev->desc.idVendor,
447 dev->desc.idProduct);
448 list_del(&dev->list);
455 API_EXPORTED struct libusb_device_descriptor *libusb_get_device_descriptor(
456 struct libusb_device *dev)
461 API_EXPORTED struct libusb_config_descriptor *libusb_get_config_descriptor(
462 struct libusb_device *dev)
467 API_EXPORTED struct libusb_device_handle *libusb_open(struct libusb_device *dev)
469 struct libusb_device_handle *devh;
471 usbi_dbg("open %04x:%04x", dev->desc.idVendor, dev->desc.idProduct);
473 fd = open(dev->nodepath, O_RDWR);
475 usbi_err("open failed, code %d errno %d", fd, errno);
479 devh = malloc(sizeof(*devh));
486 devh->dev = libusb_device_ref(dev);
487 list_add(&devh->list, &open_devs);
488 usbi_add_pollfd(fd, POLLOUT);
492 /* convenience function for finding a device with a particular vendor/product
493 * combination. has limitations and is hence not intended for use in "real
494 * applications": if multiple devices have the same VID+PID it'll only
495 * give you the first one, etc. */
496 API_EXPORTED struct libusb_device_handle *libusb_open_device_with_vid_pid(
497 uint16_t vendor_id, uint16_t product_id)
499 struct libusb_device **devs;
500 struct libusb_device *found = NULL;
501 struct libusb_device *dev;
502 struct libusb_device_handle *devh;
505 if (libusb_get_device_list(&devs) < 0)
508 while ((dev = devs[i++]) != NULL) {
509 struct libusb_device_descriptor *desc =
510 libusb_get_device_descriptor(dev);
511 if (desc->idVendor == vendor_id && desc->idProduct == product_id) {
518 devh = libusb_open(found);
520 libusb_free_device_list(devs, 1);
524 static void do_close(struct libusb_device_handle *devh)
526 usbi_remove_pollfd(devh->fd);
528 libusb_device_unref(devh->dev);
531 API_EXPORTED void libusb_close(struct libusb_device_handle *dev_handle)
537 list_del(&dev_handle->list);
538 do_close(dev_handle);
542 API_EXPORTED struct libusb_device *libusb_get_device(
543 struct libusb_device_handle *dev_handle)
545 return dev_handle->dev;
548 API_EXPORTED int libusb_claim_interface(struct libusb_device_handle *dev,
552 usbi_dbg("interface %d", iface);
554 r = ioctl(dev->fd, IOCTL_USB_CLAIMINTF, &iface);
556 usbi_err("claim interface failed, error %d", r);
560 API_EXPORTED int libusb_release_interface(struct libusb_device_handle *dev,
564 usbi_dbg("interface %d", iface);
566 r = ioctl(dev->fd, IOCTL_USB_RELEASEINTF, &iface);
568 usbi_err("release interface failed, error %d", r);
572 API_EXPORTED int libusb_init(void)
575 usbfs_path = find_usbfs_path();
577 usbi_err("could not find usbfs");
581 list_init(&usb_devs);
582 list_init(&open_devs);
587 API_EXPORTED void libusb_exit(void)
589 struct libusb_device_handle *devh;
591 if (!list_empty(&open_devs)) {
592 usbi_dbg("naughty app left some devices open!\n");
593 list_for_each_entry(devh, &open_devs, list)
598 API_EXPORTED size_t libusb_get_pollfds(struct libusb_pollfd **pollfds)
600 struct libusb_device_handle *devh;
601 struct libusb_pollfd *ret;
605 /* count number of open devices */
606 list_for_each_entry(devh, &open_devs, list)
610 ret = calloc(cnt, sizeof(struct libusb_pollfd));
615 list_for_each_entry(devh, &open_devs, list) {
616 ret[i++].fd = devh->fd;
617 ret[i].events = POLLOUT;
624 void usbi_log(enum usbi_log_level level, const char *function,
625 const char *format, ...)
628 FILE *stream = stdout;
635 case LOG_LEVEL_WARNING:
639 case LOG_LEVEL_ERROR:
643 case LOG_LEVEL_DEBUG:
653 fprintf(stream, "libusb:%s [%s] ", prefix, function);
655 va_start (args, format);
656 vfprintf(stream, format, args);
659 fprintf(stream, "\n");