/* * Copyright © 2009 Keith Packard * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; version 2 of the License. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ #include "aoview.h" #include #include static char * load_string(char *dir, char *file) { char *full = aoview_fullname(dir, file); char line[4096]; char *r; FILE *f; int rlen; f = fopen(full, "r"); free(full); if (!f) return NULL; r = fgets(line, sizeof (line), f); fclose(f); if (!r) return NULL; rlen = strlen(r); if (r[rlen-1] == '\n') r[rlen-1] = '\0'; return strdup(r); } static int load_hex(char *dir, char *file) { char *line; char *end; long i; line = load_string(dir, file); if (!line) return -1; i = strtol(line, &end, 16); free(line); if (end == line) return -1; return i; } static int dir_filter_tty_colon(const struct dirent *d) { return strncmp(d->d_name, "tty:", 4) == 0; } static int dir_filter_tty(const struct dirent *d) { return strncmp(d->d_name, "tty", 3) == 0; } static char * usb_tty(char *sys) { char *base; int num_configs; int config; struct dirent **namelist; int interface; int num_interfaces; char endpoint_base[20]; char *endpoint_full; char *tty_dir; int ntty; char *tty; base = aoview_basename(sys); num_configs = load_hex(sys, "bNumConfigurations"); num_interfaces = load_hex(sys, "bNumInterfaces"); for (config = 1; config <= num_configs; config++) { for (interface = 0; interface < num_interfaces; interface++) { sprintf(endpoint_base, "%s:%d.%d", base, config, interface); endpoint_full = aoview_fullname(sys, endpoint_base); /* Check for tty:ttyACMx style names */ ntty = scandir(endpoint_full, &namelist, dir_filter_tty_colon, alphasort); if (ntty > 0) { free(endpoint_full); tty = aoview_fullname("/dev", namelist[0]->d_name + 4); free(namelist); return tty; } /* Check for tty/ttyACMx style names */ tty_dir = aoview_fullname(endpoint_full, "tty"); free(endpoint_full); ntty = scandir(tty_dir, &namelist, dir_filter_tty, alphasort); free (tty_dir); if (ntty > 0) { tty = aoview_fullname("/dev", namelist[0]->d_name); free(namelist); return tty; } } } return NULL; } static struct usbdev * usb_scan_device(char *sys) { struct usbdev *usbdev; usbdev = calloc(1, sizeof (struct usbdev)); if (!usbdev) return NULL; usbdev->sys = strdup(sys); usbdev->manufacturer = load_string(sys, "manufacturer"); usbdev->product = load_string(sys, "product"); usbdev->serial = load_string(sys, "serial"); usbdev->idProduct = load_hex(sys, "idProduct"); usbdev->idVendor = load_hex(sys, "idVendor"); usbdev->tty = usb_tty(sys); return usbdev; } void aoview_usbdev_free(struct usbdev *usbdev) { free(usbdev->sys); free(usbdev->manufacturer); free(usbdev->product); free(usbdev->serial); free(usbdev->tty); free(usbdev); } #define USB_DEVICES "/sys/bus/usb/devices" static int dir_filter_dev(const struct dirent *d) { const char *n = d->d_name; char c; while ((c = *n++)) { if (isdigit(c)) continue; if (c == '-') continue; if (c == '.' && n != d->d_name + 1) continue; return 0; } return 1; } int aoview_usb_scan(struct usbdev ***devs_ret) { int n; int ndev = 0; int e; struct dirent **ents; char *dir; struct usbdev **devs = NULL; struct usbdev *dev; n = scandir (USB_DEVICES, &ents, dir_filter_dev, alphasort); if (!n) return 0; for (e = 0; e < n; e++) { dir = aoview_fullname(USB_DEVICES, ents[e]->d_name); dev = usb_scan_device(dir); free(dir); if (dev->idVendor == 0xfffe && dev->tty) { if (devs) devs = realloc(devs, ndev + 1 * sizeof (struct usbdev *)); else devs = malloc (sizeof (struct usbdev *)); devs[ndev++] = dev; } } free(ents); *devs_ret = devs; return ndev; }