Add preliminary aoview code
[fw/altos] / aoview / 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 fullname (char *dir, char *file)
24 {
25         char    *new;
26         int     dlen = strlen (dir);
27         int     flen = strlen (file);
28         int     slen = 0;
29
30         if (dir[dlen-1] != '/')
31                 slen = 1;
32         new = malloc (dlen + slen + flen + 1);
33         if (!new)
34                 return 0;
35         strcpy(new, dir);
36         if (slen)
37                 strcat (new, "/");
38         strcat(new, file);
39         return new;
40 }
41
42 static char *
43 load_string(char *dir, char *file)
44 {
45         char    *full = fullname(dir, file);
46         char    line[4096];
47         char    *r;
48         FILE    *f;
49         int     rlen;
50
51         f = fopen(full, "r");
52         free(full);
53         if (!f)
54                 return NULL;
55         r = fgets(line, sizeof (line), f);
56         fclose(f);
57         if (!r)
58                 return NULL;
59         rlen = strlen(r);
60         if (r[rlen-1] == '\n')
61                 r[rlen-1] = '\0';
62         return strdup(r);
63 }
64
65 static int
66 load_hex(char *dir, char *file)
67 {
68         char    *line;
69         char    *end;
70         long    i;
71
72         line = load_string(dir, file);
73         if (!line)
74                 return -1;
75         i = strtol(line, &end, 16);
76         free(line);
77         if (end == line)
78                 return -1;
79         return i;
80 }
81
82 static char *
83 basename(char *file)
84 {
85         char *b;
86
87         b = strrchr(file, '/');
88         if (!b)
89                 return file;
90         return b + 1;
91 }
92
93 static int
94 dir_filter_tty(const struct dirent *d)
95 {
96         return strncmp(d->d_name, "tty:", 4) == 0;
97 }
98
99 static char *
100 usb_tty(char *sys)
101 {
102         char *base;
103         int num_configs;
104         int config;
105         struct dirent **namelist;
106         int interface;
107         int num_interfaces;
108         char endpoint_base[20];
109         char *endpoint_full;
110         int ntty;
111         char *tty;
112
113         base = basename(sys);
114         num_configs = load_hex(sys, "bNumConfigurations");
115         num_interfaces = load_hex(sys, "bNumInterfaces");
116         for (config = 1; config <= num_configs; config++) {
117                 for (interface = 0; interface < num_interfaces; interface++) {
118                         sprintf(endpoint_base, "%s:%d.%d",
119                                 base, config, interface);
120                         endpoint_full = fullname(sys, endpoint_base);
121                         ntty = scandir(endpoint_full, &namelist,
122                                        dir_filter_tty,
123                                        alphasort);
124                         free(endpoint_full);
125                         if (ntty) {
126                                 tty = fullname("/dev", namelist[0]->d_name + 4);
127                                 free(namelist);
128                                 return tty;
129                         }
130                 }
131         }
132         return NULL;
133 }
134
135 static struct usbdev *
136 usb_scan_device(char *sys)
137 {
138         struct usbdev *usbdev;
139
140         usbdev = calloc(1, sizeof (struct usbdev));
141         if (!usbdev)
142                 return NULL;
143         usbdev->sys = strdup(sys);
144         usbdev->manufacturer = load_string(sys, "manufacturer");
145         usbdev->product = load_string(sys, "product");
146         usbdev->serial = load_string(sys, "serial");
147         usbdev->idProduct = load_hex(sys, "idProduct");
148         usbdev->idVendor = load_hex(sys, "idVendor");
149         usbdev->tty = usb_tty(sys);
150         return usbdev;
151 }
152
153 void
154 aoview_usbdev_free(struct usbdev *usbdev)
155 {
156         free(usbdev->sys);
157         free(usbdev->manufacturer);
158         free(usbdev->product);
159         free(usbdev->serial);
160         free(usbdev->tty);
161         free(usbdev);
162 }
163
164 #define USB_DEVICES     "/sys/bus/usb/devices"
165
166 static int
167 dir_filter_dev(const struct dirent *d)
168 {
169         const char      *n = d->d_name;
170         char    c;
171
172         while ((c = *n++)) {
173                 if (isdigit(c))
174                         continue;
175                 if (c == '-')
176                         continue;
177                 return 0;
178         }
179         return 1;
180 }
181
182 int
183 aoview_usb_scan(struct usbdev ***devs_ret)
184 {
185         int             n;
186         int             ndev = 0;
187         int             e;
188         struct dirent   **ents;
189         char            *dir;
190         struct usbdev   **devs = NULL;
191         struct usbdev   *dev;
192
193         n = scandir (USB_DEVICES, &ents,
194                      dir_filter_dev,
195                      alphasort);
196         if (!n)
197                 return 0;
198         for (e = 0; e < n; e++) {
199                 dir = fullname(USB_DEVICES, ents[e]->d_name);
200                 dev = usb_scan_device(dir);
201                 free(dir);
202                 if (dev->idVendor == 0xfffe && dev->tty) {
203                         if (devs)
204                                 devs = realloc(devs, ndev + 1 * sizeof (struct usbdev *));
205                         else
206                                 devs = malloc (sizeof (struct usbdev *));
207                         devs[ndev++] = dev;
208                 }
209         }
210         free(ents);
211         *devs_ret = devs;
212         return ndev;
213 }