rename states. launchpad -> pad, coast -> fast
[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 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(const struct dirent *d)
64 {
65         return strncmp(d->d_name, "tty:", 4) == 0;
66 }
67
68 static char *
69 usb_tty(char *sys)
70 {
71         char *base;
72         int num_configs;
73         int config;
74         struct dirent **namelist;
75         int interface;
76         int num_interfaces;
77         char endpoint_base[20];
78         char *endpoint_full;
79         int ntty;
80         char *tty;
81
82         base = aoview_basename(sys);
83         num_configs = load_hex(sys, "bNumConfigurations");
84         num_interfaces = load_hex(sys, "bNumInterfaces");
85         for (config = 1; config <= num_configs; config++) {
86                 for (interface = 0; interface < num_interfaces; interface++) {
87                         sprintf(endpoint_base, "%s:%d.%d",
88                                 base, config, interface);
89                         endpoint_full = aoview_fullname(sys, endpoint_base);
90                         ntty = scandir(endpoint_full, &namelist,
91                                        dir_filter_tty,
92                                        alphasort);
93                         free(endpoint_full);
94                         if (ntty > 0) {
95                                 tty = aoview_fullname("/dev", namelist[0]->d_name + 4);
96                                 free(namelist);
97                                 return tty;
98                         }
99                 }
100         }
101         return NULL;
102 }
103
104 static struct usbdev *
105 usb_scan_device(char *sys)
106 {
107         struct usbdev *usbdev;
108
109         usbdev = calloc(1, sizeof (struct usbdev));
110         if (!usbdev)
111                 return NULL;
112         usbdev->sys = strdup(sys);
113         usbdev->manufacturer = load_string(sys, "manufacturer");
114         usbdev->product = load_string(sys, "product");
115         usbdev->serial = load_string(sys, "serial");
116         usbdev->idProduct = load_hex(sys, "idProduct");
117         usbdev->idVendor = load_hex(sys, "idVendor");
118         usbdev->tty = usb_tty(sys);
119         return usbdev;
120 }
121
122 void
123 aoview_usbdev_free(struct usbdev *usbdev)
124 {
125         free(usbdev->sys);
126         free(usbdev->manufacturer);
127         free(usbdev->product);
128         free(usbdev->serial);
129         free(usbdev->tty);
130         free(usbdev);
131 }
132
133 #define USB_DEVICES     "/sys/bus/usb/devices"
134
135 static int
136 dir_filter_dev(const struct dirent *d)
137 {
138         const char      *n = d->d_name;
139         char    c;
140
141         while ((c = *n++)) {
142                 if (isdigit(c))
143                         continue;
144                 if (c == '-')
145                         continue;
146                 if (c == '.' && n != d->d_name + 1)
147                         continue;
148                 return 0;
149         }
150         return 1;
151 }
152
153 int
154 aoview_usb_scan(struct usbdev ***devs_ret)
155 {
156         int             n;
157         int             ndev = 0;
158         int             e;
159         struct dirent   **ents;
160         char            *dir;
161         struct usbdev   **devs = NULL;
162         struct usbdev   *dev;
163
164         n = scandir (USB_DEVICES, &ents,
165                      dir_filter_dev,
166                      alphasort);
167         if (!n)
168                 return 0;
169         for (e = 0; e < n; e++) {
170                 dir = aoview_fullname(USB_DEVICES, ents[e]->d_name);
171                 dev = usb_scan_device(dir);
172                 free(dir);
173                 if (dev->idVendor == 0xfffe && dev->tty) {
174                         if (devs)
175                                 devs = realloc(devs, ndev + 1 * sizeof (struct usbdev *));
176                         else
177                                 devs = malloc (sizeof (struct usbdev *));
178                         devs[ndev++] = dev;
179                 }
180         }
181         free(ents);
182         *devs_ret = devs;
183         return ndev;
184 }