diff options
Diffstat (limited to 'ao-tools/lib')
-rw-r--r-- | ao-tools/lib/Makefile.am | 3 | ||||
-rw-r--r-- | ao-tools/lib/cc-usbdev.c | 228 | ||||
-rw-r--r-- | ao-tools/lib/cc-util.c | 80 | ||||
-rw-r--r-- | ao-tools/lib/cc.h | 51 |
4 files changed, 362 insertions, 0 deletions
diff --git a/ao-tools/lib/Makefile.am b/ao-tools/lib/Makefile.am index 9584e216..f66ee0a9 100644 --- a/ao-tools/lib/Makefile.am +++ b/ao-tools/lib/Makefile.am @@ -16,6 +16,9 @@ libao_tools_a_SOURCES = \ ccdbg-state.c \ cc-usb.c \ cc-usb.h \ + cc.h \ + cc-usbdev.c \ + cc-util.c \ cc-bitbang.c \ cc-bitbang.h \ cp-usb-async.c \ diff --git a/ao-tools/lib/cc-usbdev.c b/ao-tools/lib/cc-usbdev.c new file mode 100644 index 00000000..d8bb8b11 --- /dev/null +++ b/ao-tools/lib/cc-usbdev.c @@ -0,0 +1,228 @@ +/* + * Copyright © 2009 Keith Packard <keithp@keithp.com> + * + * 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; either version 2 of the License, or + * (at your option) any later version. + * + * 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 "cc.h" + +#include <ctype.h> +#include <dirent.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +static char * +load_string(char *dir, char *file) +{ + char *full = cc_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 = cc_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 = cc_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 = cc_fullname("/dev", namelist[0]->d_name + 4); + free(namelist); + return tty; + } + + /* Check for tty/ttyACMx style names + */ + tty_dir = cc_fullname(endpoint_full, "tty"); + free(endpoint_full); + ntty = scandir(tty_dir, &namelist, + dir_filter_tty, + alphasort); + free (tty_dir); + if (ntty > 0) { + tty = cc_fullname("/dev", namelist[0]->d_name); + free(namelist); + return tty; + } + } + } + return NULL; +} + +static struct cc_usbdev * +usb_scan_device(char *sys) +{ + struct cc_usbdev *usbdev; + + usbdev = calloc(1, sizeof (struct cc_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; +} + +static void +usbdev_free(struct cc_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; +} + +struct cc_usbdevs * +cc_usbdevs_scan(void) +{ + int e; + struct dirent **ents; + char *dir; + struct cc_usbdev *dev; + struct cc_usbdevs *devs; + int n; + + devs = calloc(1, sizeof (struct cc_usbdevs)); + if (!devs) + return NULL; + + n = scandir (USB_DEVICES, &ents, + dir_filter_dev, + alphasort); + if (!n) + return 0; + for (e = 0; e < n; e++) { + dir = cc_fullname(USB_DEVICES, ents[e]->d_name); + dev = usb_scan_device(dir); + free(dir); + if (dev->idVendor == 0xfffe && dev->tty) { + if (devs->dev) + devs->dev = realloc(devs->dev, + devs->ndev + 1 * sizeof (struct usbdev *)); + else + devs->dev = malloc (sizeof (struct usbdev *)); + devs->dev[devs->ndev++] = dev; + } + } + free(ents); + return devs; +} + +void +cc_usbdevs_free(struct cc_usbdevs *usbdevs) +{ + int i; + + if (!usbdevs) + return; + for (i = 0; i < usbdevs->ndev; i++) + usbdev_free(usbdevs->dev[i]); + free(usbdevs); +} diff --git a/ao-tools/lib/cc-util.c b/ao-tools/lib/cc-util.c new file mode 100644 index 00000000..7104470c --- /dev/null +++ b/ao-tools/lib/cc-util.c @@ -0,0 +1,80 @@ +/* + * Copyright © 2009 Keith Packard <keithp@keithp.com> + * + * 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 "cc.h" +#define _GNU_SOURCE +#include <string.h> +#include <stdlib.h> +#include <unistd.h> +#include <sys/stat.h> +#include <sys/types.h> +#include <errno.h> + +char * +cc_fullname (char *dir, char *file) +{ + char *new; + int dlen = strlen (dir); + int flen = strlen (file); + int slen = 0; + + if (dir[dlen-1] != '/') + slen = 1; + new = malloc (dlen + slen + flen + 1); + if (!new) + return 0; + strcpy(new, dir); + if (slen) + strcat (new, "/"); + strcat(new, file); + return new; +} + +char * +cc_basename(char *file) +{ + char *b; + + b = strrchr(file, '/'); + if (!b) + return file; + return b + 1; +} + +int +cc_mkdir(char *dir) +{ + char *slash; + char *d; + char *part; + + d = dir; + for (;;) { + slash = strchr (d, '/'); + if (!slash) + slash = d + strlen(d); + if (!*slash) + break; + part = strndup(dir, slash - dir); + if (!access(part, F_OK)) + if (mkdir(part, 0777) < 0) + return -errno; + free(part); + d = slash + 1; + } + return 0; +} diff --git a/ao-tools/lib/cc.h b/ao-tools/lib/cc.h new file mode 100644 index 00000000..dad11bf3 --- /dev/null +++ b/ao-tools/lib/cc.h @@ -0,0 +1,51 @@ +/* + * Copyright © 2009 Keith Packard <keithp@keithp.com> + * + * 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. + */ + +#ifndef _CC_H_ +#define _CC_H_ + +char * +cc_fullname (char *dir, char *file); + +char * +cc_basename(char *file); + +int +cc_mkdir(char *dir); + +struct cc_usbdev { + char *sys; + char *tty; + char *manufacturer; + char *product; + char *serial; + int idProduct; + int idVendor; +}; + +struct cc_usbdevs { + struct cc_usbdev **dev; + int ndev; +}; + +void +cc_usbdevs_free(struct cc_usbdevs *usbdevs); + +struct cc_usbdevs * +cc_usbdevs_scan(void); + +#endif /* _CC_H_ */ |