update changelogs for Debian build
[fw/altos] / ao-view / aoview_dev.c
1 /*
2  * Copyright © 2009 Keith Packard <keithp@keithp.com>
3  *
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; version 2 of the License.
7  *
8  * This program is distributed in the hope that it will be useful, but
9  * WITHOUT ANY WARRANTY; without even the implied warranty of
10  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
11  * General Public License for more details.
12  *
13  * You should have received a copy of the GNU General Public License along
14  * with this program; if not, write to the Free Software Foundation, Inc.,
15  * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
16  */
17
18 #include "aoview.h"
19 #include <ctype.h>
20 #include <dirent.h>
21
22 static char *
23 load_string(char *dir, char *file)
24 {
25         char    *full = aoview_fullname(dir, file);
26         char    line[4096];
27         char    *r;
28         FILE    *f;
29         int     rlen;
30
31         f = fopen(full, "r");
32         free(full);
33         if (!f)
34                 return NULL;
35         r = fgets(line, sizeof (line), f);
36         fclose(f);
37         if (!r)
38                 return NULL;
39         rlen = strlen(r);
40         if (r[rlen-1] == '\n')
41                 r[rlen-1] = '\0';
42         return strdup(r);
43 }
44
45 static int
46 load_hex(char *dir, char *file)
47 {
48         char    *line;
49         char    *end;
50         long    i;
51
52         line = load_string(dir, file);
53         if (!line)
54                 return -1;
55         i = strtol(line, &end, 16);
56         free(line);
57         if (end == line)
58                 return -1;
59         return i;
60 }
61
62 static int
63 dir_filter_tty_colon(const struct dirent *d)
64 {
65         return strncmp(d->d_name, "tty:", 4) == 0;
66 }
67
68 static int
69 dir_filter_tty(const struct dirent *d)
70 {
71         return strncmp(d->d_name, "tty", 3) == 0;
72 }
73
74 static char *
75 usb_tty(char *sys)
76 {
77         char *base;
78         int num_configs;
79         int config;
80         struct dirent **namelist;
81         int interface;
82         int num_interfaces;
83         char endpoint_base[20];
84         char *endpoint_full;
85         char *tty_dir;
86         int ntty;
87         char *tty;
88
89         base = aoview_basename(sys);
90         num_configs = load_hex(sys, "bNumConfigurations");
91         num_interfaces = load_hex(sys, "bNumInterfaces");
92         for (config = 1; config <= num_configs; config++) {
93                 for (interface = 0; interface < num_interfaces; interface++) {
94                         sprintf(endpoint_base, "%s:%d.%d",
95                                 base, config, interface);
96                         endpoint_full = aoview_fullname(sys, endpoint_base);
97
98                         /* Check for tty:ttyACMx style names
99                          */
100                         ntty = scandir(endpoint_full, &namelist,
101                                        dir_filter_tty_colon,
102                                        alphasort);
103                         if (ntty > 0) {
104                                 free(endpoint_full);
105                                 tty = aoview_fullname("/dev", namelist[0]->d_name + 4);
106                                 free(namelist);
107                                 return tty;
108                         }
109
110                         /* Check for tty/ttyACMx style names
111                          */
112                         tty_dir = aoview_fullname(endpoint_full, "tty");
113                         free(endpoint_full);
114                         ntty = scandir(tty_dir, &namelist,
115                                        dir_filter_tty,
116                                        alphasort);
117                         free (tty_dir);
118                         if (ntty > 0) {
119                                 tty = aoview_fullname("/dev", namelist[0]->d_name);
120                                 free(namelist);
121                                 return tty;
122                         }
123                 }
124         }
125         return NULL;
126 }
127
128 static struct usbdev *
129 usb_scan_device(char *sys)
130 {
131         struct usbdev *usbdev;
132
133         usbdev = calloc(1, sizeof (struct usbdev));
134         if (!usbdev)
135                 return NULL;
136         usbdev->sys = strdup(sys);
137         usbdev->manufacturer = load_string(sys, "manufacturer");
138         usbdev->product = load_string(sys, "product");
139         usbdev->serial = load_string(sys, "serial");
140         usbdev->idProduct = load_hex(sys, "idProduct");
141         usbdev->idVendor = load_hex(sys, "idVendor");
142         usbdev->tty = usb_tty(sys);
143         return usbdev;
144 }
145
146 void
147 aoview_usbdev_free(struct usbdev *usbdev)
148 {
149         free(usbdev->sys);
150         free(usbdev->manufacturer);
151         free(usbdev->product);
152         free(usbdev->serial);
153         free(usbdev->tty);
154         free(usbdev);
155 }
156
157 #define USB_DEVICES     "/sys/bus/usb/devices"
158
159 static int
160 dir_filter_dev(const struct dirent *d)
161 {
162         const char      *n = d->d_name;
163         char    c;
164
165         while ((c = *n++)) {
166                 if (isdigit(c))
167                         continue;
168                 if (c == '-')
169                         continue;
170                 if (c == '.' && n != d->d_name + 1)
171                         continue;
172                 return 0;
173         }
174         return 1;
175 }
176
177 int
178 aoview_usb_scan(struct usbdev ***devs_ret)
179 {
180         int             n;
181         int             ndev = 0;
182         int             e;
183         struct dirent   **ents;
184         char            *dir;
185         struct usbdev   **devs = NULL;
186         struct usbdev   *dev;
187
188         n = scandir (USB_DEVICES, &ents,
189                      dir_filter_dev,
190                      alphasort);
191         if (!n)
192                 return 0;
193         for (e = 0; e < n; e++) {
194                 dir = aoview_fullname(USB_DEVICES, ents[e]->d_name);
195                 dev = usb_scan_device(dir);
196                 free(dir);
197                 if (dev->idVendor == 0xfffe && dev->tty) {
198                         if (devs)
199                                 devs = realloc(devs, ndev + 1 * sizeof (struct usbdev *));
200                         else
201                                 devs = malloc (sizeof (struct usbdev *));
202                         devs[ndev++] = dev;
203                 }
204         }
205         free(ents);
206         *devs_ret = devs;
207         return ndev;
208 }