2 * Copyright © 2009 Keith Packard <keithp@keithp.com>
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
9 * This program is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * General Public License for more details.
14 * You should have received a copy of the GNU General Public License along
15 * with this program; if not, write to the Free Software Foundation, Inc.,
16 * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
28 load_string(char *dir, char *file)
30 char *full = cc_fullname(dir, file);
40 r = fgets(line, sizeof (line), f);
45 if (r[rlen-1] == '\n')
51 load_hex(char *dir, char *file)
57 line = load_string(dir, file);
60 i = strtol(line, &end, 16);
68 load_dec(char *dir, char *file)
74 line = load_string(dir, file);
77 i = strtol(line, &end, 10);
85 dir_filter_tty_colon(const struct dirent *d)
87 return strncmp(d->d_name, "tty:", 4) == 0;
91 dir_filter_tty(const struct dirent *d)
93 return strncmp(d->d_name, "tty", 3) == 0;
102 struct dirent **namelist;
105 char endpoint_base[20];
111 base = cc_basename(sys);
112 num_configs = load_hex(sys, "bNumConfigurations");
113 num_interfaces = load_hex(sys, "bNumInterfaces");
114 for (config = 1; config <= num_configs; config++) {
115 for (interface = 0; interface < num_interfaces; interface++) {
116 sprintf(endpoint_base, "%s:%d.%d",
117 base, config, interface);
118 endpoint_full = cc_fullname(sys, endpoint_base);
120 /* Check for tty:ttyACMx style names
122 ntty = scandir(endpoint_full, &namelist,
123 dir_filter_tty_colon,
127 tty = cc_fullname("/dev", namelist[0]->d_name + 4);
132 /* Check for tty/ttyACMx style names
134 tty_dir = cc_fullname(endpoint_full, "tty");
135 ntty = scandir(tty_dir, &namelist,
140 tty = cc_fullname("/dev", namelist[0]->d_name);
146 /* Check for ttyACMx style names
148 ntty = scandir(endpoint_full, &namelist,
153 tty = cc_fullname("/dev", namelist[0]->d_name);
162 static struct cc_usbdev *
163 usb_scan_device(char *sys)
165 struct cc_usbdev *usbdev;
167 usbdev = calloc(1, sizeof (struct cc_usbdev));
170 usbdev->sys = strdup(sys);
171 usbdev->manufacturer = load_string(sys, "manufacturer");
172 usbdev->product = load_string(sys, "product");
173 usbdev->serial = load_dec(sys, "serial");
174 usbdev->idProduct = load_hex(sys, "idProduct");
175 usbdev->idVendor = load_hex(sys, "idVendor");
176 usbdev->tty = usb_tty(sys);
181 usbdev_free(struct cc_usbdev *usbdev)
184 free(usbdev->manufacturer);
185 free(usbdev->product);
186 /* this can get used as a return value */
192 #define USB_DEVICES "/sys/bus/usb/devices"
195 dir_filter_dev(const struct dirent *d)
197 const char *n = d->d_name;
205 if (c == '.' && n != d->d_name + 1)
213 is_am(int idVendor, int idProduct) {
214 if (idVendor == 0xfffe)
216 if (idVendor == 0x0403 && idProduct == 0x6015)
222 cc_usbdevs_scan(int non_tty)
225 struct dirent **ents;
227 struct cc_usbdev *dev;
228 struct cc_usbdevs *devs;
231 devs = calloc(1, sizeof (struct cc_usbdevs));
235 n = scandir (USB_DEVICES, &ents,
240 for (e = 0; e < n; e++) {
241 dir = cc_fullname(USB_DEVICES, ents[e]->d_name);
242 dev = usb_scan_device(dir);
244 if (is_am(dev->idVendor, dev->idProduct) && (non_tty || dev->tty)) {
246 devs->dev = realloc(devs->dev,
247 (devs->ndev + 1) * sizeof (struct usbdev *));
249 devs->dev = malloc (sizeof (struct usbdev *));
250 devs->dev[devs->ndev++] = dev;
258 cc_usbdevs_free(struct cc_usbdevs *usbdevs)
264 for (i = 0; i < usbdevs->ndev; i++)
265 usbdev_free(usbdevs->dev[i]);
270 match_dev(char *product, int serial)
272 struct cc_usbdevs *devs;
273 struct cc_usbdev *dev;
277 devs = cc_usbdevs_scan(FALSE);
280 for (i = 0; i < devs->ndev; i++) {
282 if (product && strncmp (product, dev->product, strlen(product)) != 0)
284 if (serial && serial != dev->serial)
288 if (i < devs->ndev) {
289 tty = devs->dev[i]->tty;
290 devs->dev[i]->tty = NULL;
292 cc_usbdevs_free(devs);
297 cc_usbdevs_find_by_arg(char *arg, char *default_product)
307 /* check for <serial> */
308 serial = strtol(arg, &end, 0);
314 /* check for <product>:<serial> */
315 colon = strchr(arg, ':');
317 product = strndup(arg, colon - arg);
318 serial = strtol(colon + 1, &end, 0);
331 if (!product && default_product)
332 tty = match_dev(default_product, serial);
334 tty = match_dev(product, serial);
335 if (product && product != arg)