1*cf5a6c84SAndroid Build Coastguard Worker /* lsusb.c - list available USB devices
2*cf5a6c84SAndroid Build Coastguard Worker *
3*cf5a6c84SAndroid Build Coastguard Worker * Copyright 2013 Andre Renaud <[email protected]>
4*cf5a6c84SAndroid Build Coastguard Worker * Copyright 2013 Isaac Dunham <[email protected]>
5*cf5a6c84SAndroid Build Coastguard Worker
6*cf5a6c84SAndroid Build Coastguard Worker USE_LSUSB(NEWTOY(lsusb, "i:", TOYFLAG_USR|TOYFLAG_BIN))
7*cf5a6c84SAndroid Build Coastguard Worker USE_LSPCI(NEWTOY(lspci, "eDmkn@x@i:", TOYFLAG_USR|TOYFLAG_BIN))
8*cf5a6c84SAndroid Build Coastguard Worker
9*cf5a6c84SAndroid Build Coastguard Worker config LSPCI
10*cf5a6c84SAndroid Build Coastguard Worker bool "lspci"
11*cf5a6c84SAndroid Build Coastguard Worker default y
12*cf5a6c84SAndroid Build Coastguard Worker help
13*cf5a6c84SAndroid Build Coastguard Worker usage: lspci [-ekmn] [-i FILE]
14*cf5a6c84SAndroid Build Coastguard Worker
15*cf5a6c84SAndroid Build Coastguard Worker List PCI devices.
16*cf5a6c84SAndroid Build Coastguard Worker
17*cf5a6c84SAndroid Build Coastguard Worker -e Extended (6 digit) class
18*cf5a6c84SAndroid Build Coastguard Worker -i ID database (default /etc/pci.ids[.gz])
19*cf5a6c84SAndroid Build Coastguard Worker -k Show kernel driver
20*cf5a6c84SAndroid Build Coastguard Worker -m Machine readable
21*cf5a6c84SAndroid Build Coastguard Worker -n Numeric output (-nn for both)
22*cf5a6c84SAndroid Build Coastguard Worker -D Print domain numbers
23*cf5a6c84SAndroid Build Coastguard Worker -x Hex dump of config space (64 bytes; -xxx for 256, -xxxx for 4096)
24*cf5a6c84SAndroid Build Coastguard Worker
25*cf5a6c84SAndroid Build Coastguard Worker config LSUSB
26*cf5a6c84SAndroid Build Coastguard Worker bool "lsusb"
27*cf5a6c84SAndroid Build Coastguard Worker default y
28*cf5a6c84SAndroid Build Coastguard Worker help
29*cf5a6c84SAndroid Build Coastguard Worker usage: lsusb [-i]
30*cf5a6c84SAndroid Build Coastguard Worker
31*cf5a6c84SAndroid Build Coastguard Worker List USB hosts/devices.
32*cf5a6c84SAndroid Build Coastguard Worker
33*cf5a6c84SAndroid Build Coastguard Worker -i ID database (default /etc/usb.ids[.gz])
34*cf5a6c84SAndroid Build Coastguard Worker */
35*cf5a6c84SAndroid Build Coastguard Worker
36*cf5a6c84SAndroid Build Coastguard Worker #define FOR_lsusb
37*cf5a6c84SAndroid Build Coastguard Worker #include "toys.h"
38*cf5a6c84SAndroid Build Coastguard Worker
39*cf5a6c84SAndroid Build Coastguard Worker GLOBALS(
40*cf5a6c84SAndroid Build Coastguard Worker char *i;
41*cf5a6c84SAndroid Build Coastguard Worker long x, n;
42*cf5a6c84SAndroid Build Coastguard Worker
43*cf5a6c84SAndroid Build Coastguard Worker void *ids, *class;
44*cf5a6c84SAndroid Build Coastguard Worker int count;
45*cf5a6c84SAndroid Build Coastguard Worker )
46*cf5a6c84SAndroid Build Coastguard Worker
47*cf5a6c84SAndroid Build Coastguard Worker struct dev_ids {
48*cf5a6c84SAndroid Build Coastguard Worker struct dev_ids *next, *child;
49*cf5a6c84SAndroid Build Coastguard Worker int id;
50*cf5a6c84SAndroid Build Coastguard Worker char name[];
51*cf5a6c84SAndroid Build Coastguard Worker };
52*cf5a6c84SAndroid Build Coastguard Worker
53*cf5a6c84SAndroid Build Coastguard Worker struct scanloop {
54*cf5a6c84SAndroid Build Coastguard Worker char *pattern;
55*cf5a6c84SAndroid Build Coastguard Worker void *d1, *d2;
56*cf5a6c84SAndroid Build Coastguard Worker };
57*cf5a6c84SAndroid Build Coastguard Worker
58*cf5a6c84SAndroid Build Coastguard Worker // Common function to read uevent file under /proc for both pci and usb
59*cf5a6c84SAndroid Build Coastguard Worker // note that %s is omitted (because pointer is into toybuf, avoiding copy).
scan_uevent(struct dirtree * new,int len,struct scanloop * sl)60*cf5a6c84SAndroid Build Coastguard Worker static int scan_uevent(struct dirtree *new, int len, struct scanloop *sl)
61*cf5a6c84SAndroid Build Coastguard Worker {
62*cf5a6c84SAndroid Build Coastguard Worker int ii, saw = 0;
63*cf5a6c84SAndroid Build Coastguard Worker off_t flen = sizeof(toybuf);
64*cf5a6c84SAndroid Build Coastguard Worker char *ss, *yy;
65*cf5a6c84SAndroid Build Coastguard Worker
66*cf5a6c84SAndroid Build Coastguard Worker // Read data
67*cf5a6c84SAndroid Build Coastguard Worker if (*new->name == '.') return 0;
68*cf5a6c84SAndroid Build Coastguard Worker sprintf(toybuf, "%s/uevent", new->name);
69*cf5a6c84SAndroid Build Coastguard Worker if (!readfileat(dirtree_parentfd(new), ss = toybuf, toybuf, &flen)) return 0;
70*cf5a6c84SAndroid Build Coastguard Worker
71*cf5a6c84SAndroid Build Coastguard Worker // Loop over lines
72*cf5a6c84SAndroid Build Coastguard Worker while ((flen = strcspn(ss, "\n"))) {
73*cf5a6c84SAndroid Build Coastguard Worker if (ss[flen]) ss[flen++] = 0;
74*cf5a6c84SAndroid Build Coastguard Worker yy = ss+flen;
75*cf5a6c84SAndroid Build Coastguard Worker
76*cf5a6c84SAndroid Build Coastguard Worker // Try each pattern
77*cf5a6c84SAndroid Build Coastguard Worker for (ii = 0; ii<len; ii++) {
78*cf5a6c84SAndroid Build Coastguard Worker if (strchr(sl[ii].pattern, '%')) {
79*cf5a6c84SAndroid Build Coastguard Worker if (2-!sl[ii].d2!=sscanf(ss, sl[ii].pattern, sl[ii].d1, sl[ii].d2))
80*cf5a6c84SAndroid Build Coastguard Worker continue;
81*cf5a6c84SAndroid Build Coastguard Worker } else if (strstart(&ss, sl[ii].pattern)) *(void **)sl[ii].d1 = ss;
82*cf5a6c84SAndroid Build Coastguard Worker else continue;
83*cf5a6c84SAndroid Build Coastguard Worker saw |= 1<<ii;
84*cf5a6c84SAndroid Build Coastguard Worker
85*cf5a6c84SAndroid Build Coastguard Worker break;
86*cf5a6c84SAndroid Build Coastguard Worker }
87*cf5a6c84SAndroid Build Coastguard Worker ss = yy;
88*cf5a6c84SAndroid Build Coastguard Worker }
89*cf5a6c84SAndroid Build Coastguard Worker
90*cf5a6c84SAndroid Build Coastguard Worker return saw;
91*cf5a6c84SAndroid Build Coastguard Worker }
92*cf5a6c84SAndroid Build Coastguard Worker
get_names(struct dev_ids * ids,int id1,int id2,char ** name1,char ** name2)93*cf5a6c84SAndroid Build Coastguard Worker static void get_names(struct dev_ids *ids, int id1, int id2,
94*cf5a6c84SAndroid Build Coastguard Worker char **name1, char **name2)
95*cf5a6c84SAndroid Build Coastguard Worker {
96*cf5a6c84SAndroid Build Coastguard Worker // Look up matching dev_ids (if any)
97*cf5a6c84SAndroid Build Coastguard Worker *name1 = *name2 = "";
98*cf5a6c84SAndroid Build Coastguard Worker for (; ids; ids = ids->next) {
99*cf5a6c84SAndroid Build Coastguard Worker if (id1 != ids->id) continue;
100*cf5a6c84SAndroid Build Coastguard Worker *name1 = ids->name;
101*cf5a6c84SAndroid Build Coastguard Worker for (ids = ids->child; ids; ids = ids->next) {
102*cf5a6c84SAndroid Build Coastguard Worker if (id2 != ids->id) continue;
103*cf5a6c84SAndroid Build Coastguard Worker *name2 = ids->name;
104*cf5a6c84SAndroid Build Coastguard Worker return;
105*cf5a6c84SAndroid Build Coastguard Worker }
106*cf5a6c84SAndroid Build Coastguard Worker return;
107*cf5a6c84SAndroid Build Coastguard Worker }
108*cf5a6c84SAndroid Build Coastguard Worker }
109*cf5a6c84SAndroid Build Coastguard Worker
110*cf5a6c84SAndroid Build Coastguard Worker // Search for pci.ids or usb.ids and return parsed structure or NULL
parse_dev_ids(char * name,struct dev_ids ** and)111*cf5a6c84SAndroid Build Coastguard Worker struct dev_ids *parse_dev_ids(char *name, struct dev_ids **and)
112*cf5a6c84SAndroid Build Coastguard Worker {
113*cf5a6c84SAndroid Build Coastguard Worker char *path = "/etc:/vendor:/usr/share/hwdata:/usr/share/misc";
114*cf5a6c84SAndroid Build Coastguard Worker struct string_list *sl = 0;
115*cf5a6c84SAndroid Build Coastguard Worker FILE *fp;
116*cf5a6c84SAndroid Build Coastguard Worker char *s, *ss, *sss;
117*cf5a6c84SAndroid Build Coastguard Worker struct dev_ids *ids = 0, *new;
118*cf5a6c84SAndroid Build Coastguard Worker int fd = -1;
119*cf5a6c84SAndroid Build Coastguard Worker
120*cf5a6c84SAndroid Build Coastguard Worker // Open compressed or uncompressed file
121*cf5a6c84SAndroid Build Coastguard Worker signal(SIGCHLD, SIG_IGN);
122*cf5a6c84SAndroid Build Coastguard Worker s = TT.i;
123*cf5a6c84SAndroid Build Coastguard Worker if (!s) {
124*cf5a6c84SAndroid Build Coastguard Worker sprintf(toybuf, "%s.gz", name);
125*cf5a6c84SAndroid Build Coastguard Worker if ((sl = find_in_path(path, toybuf)) || (sl = find_in_path(path, name)))
126*cf5a6c84SAndroid Build Coastguard Worker s = sl->str;
127*cf5a6c84SAndroid Build Coastguard Worker }
128*cf5a6c84SAndroid Build Coastguard Worker if (s && strend(s, ".gz")) xpopen((char *[]){"zcat", sl->str, 0}, &fd, 1);
129*cf5a6c84SAndroid Build Coastguard Worker else if (s) fd = xopen(s, O_RDONLY);
130*cf5a6c84SAndroid Build Coastguard Worker llist_traverse(sl, free);
131*cf5a6c84SAndroid Build Coastguard Worker if (fd == -1) return 0;
132*cf5a6c84SAndroid Build Coastguard Worker
133*cf5a6c84SAndroid Build Coastguard Worker for (fp = fdopen(fd, "r"); (s = ss = xgetline(fp)); free(s)) {
134*cf5a6c84SAndroid Build Coastguard Worker // TODO parse and use third level instead of skipping it here
135*cf5a6c84SAndroid Build Coastguard Worker if (s[strspn(s, " \t")]=='#' || strstart(&ss, "\t\t")) continue;
136*cf5a6c84SAndroid Build Coastguard Worker
137*cf5a6c84SAndroid Build Coastguard Worker // Switch to device class list?
138*cf5a6c84SAndroid Build Coastguard Worker if (strstart(&ss, "C ") && and) {
139*cf5a6c84SAndroid Build Coastguard Worker *and = ids;
140*cf5a6c84SAndroid Build Coastguard Worker and = 0;
141*cf5a6c84SAndroid Build Coastguard Worker }
142*cf5a6c84SAndroid Build Coastguard Worker fd = estrtol(sss = ss, &ss, 16);
143*cf5a6c84SAndroid Build Coastguard Worker if (ss>sss && *ss++==' ') {
144*cf5a6c84SAndroid Build Coastguard Worker while (isspace(*ss)) ss++;
145*cf5a6c84SAndroid Build Coastguard Worker new = xmalloc(sizeof(*new)+strlen(ss)+1);
146*cf5a6c84SAndroid Build Coastguard Worker new->child = 0;
147*cf5a6c84SAndroid Build Coastguard Worker new->id = fd;
148*cf5a6c84SAndroid Build Coastguard Worker strcpy(new->name, ss);
149*cf5a6c84SAndroid Build Coastguard Worker if (!ids || *s!='\t') {
150*cf5a6c84SAndroid Build Coastguard Worker new->next = ids;
151*cf5a6c84SAndroid Build Coastguard Worker ids = new;
152*cf5a6c84SAndroid Build Coastguard Worker } else {
153*cf5a6c84SAndroid Build Coastguard Worker new->next = ids->child;
154*cf5a6c84SAndroid Build Coastguard Worker ids->child = new;
155*cf5a6c84SAndroid Build Coastguard Worker }
156*cf5a6c84SAndroid Build Coastguard Worker }
157*cf5a6c84SAndroid Build Coastguard Worker }
158*cf5a6c84SAndroid Build Coastguard Worker fclose(fp);
159*cf5a6c84SAndroid Build Coastguard Worker
160*cf5a6c84SAndroid Build Coastguard Worker return ids;
161*cf5a6c84SAndroid Build Coastguard Worker }
162*cf5a6c84SAndroid Build Coastguard Worker
list_usb(struct dirtree * new)163*cf5a6c84SAndroid Build Coastguard Worker static int list_usb(struct dirtree *new)
164*cf5a6c84SAndroid Build Coastguard Worker {
165*cf5a6c84SAndroid Build Coastguard Worker int busnum = 0, devnum = 0, pid = 0, vid = 0;
166*cf5a6c84SAndroid Build Coastguard Worker char *n1, *n2;
167*cf5a6c84SAndroid Build Coastguard Worker
168*cf5a6c84SAndroid Build Coastguard Worker if (!new->parent) return DIRTREE_RECURSE;
169*cf5a6c84SAndroid Build Coastguard Worker if (7 == scan_uevent(new, 3, (struct scanloop[]){{"BUSNUM=%u", &busnum, 0},
170*cf5a6c84SAndroid Build Coastguard Worker {"DEVNUM=%u", &devnum, 0}, {"PRODUCT=%x/%x", &pid, &vid}}))
171*cf5a6c84SAndroid Build Coastguard Worker {
172*cf5a6c84SAndroid Build Coastguard Worker get_names(TT.ids, pid, vid, &n1, &n2);
173*cf5a6c84SAndroid Build Coastguard Worker printf("Bus %03d Device %03d: ID %04x:%04x %s %s\n",
174*cf5a6c84SAndroid Build Coastguard Worker busnum, devnum, pid, vid, n1, n2);
175*cf5a6c84SAndroid Build Coastguard Worker }
176*cf5a6c84SAndroid Build Coastguard Worker
177*cf5a6c84SAndroid Build Coastguard Worker return 0;
178*cf5a6c84SAndroid Build Coastguard Worker }
179*cf5a6c84SAndroid Build Coastguard Worker
lsusb_main(void)180*cf5a6c84SAndroid Build Coastguard Worker void lsusb_main(void)
181*cf5a6c84SAndroid Build Coastguard Worker {
182*cf5a6c84SAndroid Build Coastguard Worker // Parse http://www.linux-usb.org/usb.ids file (if available)
183*cf5a6c84SAndroid Build Coastguard Worker TT.ids = parse_dev_ids("usb.ids", 0);
184*cf5a6c84SAndroid Build Coastguard Worker dirtree_read("/sys/bus/usb/devices/", list_usb);
185*cf5a6c84SAndroid Build Coastguard Worker }
186*cf5a6c84SAndroid Build Coastguard Worker
187*cf5a6c84SAndroid Build Coastguard Worker #define FOR_lspci
188*cf5a6c84SAndroid Build Coastguard Worker #include "generated/flags.h"
189*cf5a6c84SAndroid Build Coastguard Worker
190*cf5a6c84SAndroid Build Coastguard Worker // TODO: -v
list_pci(struct dirtree * new)191*cf5a6c84SAndroid Build Coastguard Worker static int list_pci(struct dirtree *new)
192*cf5a6c84SAndroid Build Coastguard Worker {
193*cf5a6c84SAndroid Build Coastguard Worker char *driver = 0, buf[16], *ss, *names[3];
194*cf5a6c84SAndroid Build Coastguard Worker int cvd[3] = {0}, ii, revision = 0;
195*cf5a6c84SAndroid Build Coastguard Worker off_t len = sizeof(toybuf);
196*cf5a6c84SAndroid Build Coastguard Worker /* skip 0000: part by default */
197*cf5a6c84SAndroid Build Coastguard Worker char *bus = strchr(new->name, ':') + 1;
198*cf5a6c84SAndroid Build Coastguard Worker
199*cf5a6c84SAndroid Build Coastguard Worker // Output formats: -n, -nn, -m, -nm, -nnm, -k
200*cf5a6c84SAndroid Build Coastguard Worker
201*cf5a6c84SAndroid Build Coastguard Worker if (!new->parent) return DIRTREE_RECURSE;
202*cf5a6c84SAndroid Build Coastguard Worker if (!bus || strlen(new->name)<6) return 0;
203*cf5a6c84SAndroid Build Coastguard Worker TT.count = 0;
204*cf5a6c84SAndroid Build Coastguard Worker
205*cf5a6c84SAndroid Build Coastguard Worker // Load revision
206*cf5a6c84SAndroid Build Coastguard Worker sprintf(toybuf, "%s/revision", new->name);
207*cf5a6c84SAndroid Build Coastguard Worker if (readfileat(dirtree_parentfd(new), ss = toybuf, toybuf, &len)) {
208*cf5a6c84SAndroid Build Coastguard Worker strstart(&ss, "0x");
209*cf5a6c84SAndroid Build Coastguard Worker sscanf(ss, "%x", &revision);
210*cf5a6c84SAndroid Build Coastguard Worker }
211*cf5a6c84SAndroid Build Coastguard Worker
212*cf5a6c84SAndroid Build Coastguard Worker // Load uevent data, look up names in database
213*cf5a6c84SAndroid Build Coastguard Worker if (6>scan_uevent(new, 3, (struct scanloop[]){{"DRIVER=", &driver, 0},
214*cf5a6c84SAndroid Build Coastguard Worker {"PCI_CLASS=%x", cvd, 0}, {"PCI_ID=%x:%x", cvd+1, cvd+2}})) return 0;
215*cf5a6c84SAndroid Build Coastguard Worker get_names(TT.class, 255&(cvd[0]>>16), 255&(cvd[0]>>8), names, names);
216*cf5a6c84SAndroid Build Coastguard Worker get_names(TT.ids, cvd[1], cvd[2], names+1, names+2);
217*cf5a6c84SAndroid Build Coastguard Worker if (!FLAG(e)) cvd[0] >>= 8;
218*cf5a6c84SAndroid Build Coastguard Worker
219*cf5a6c84SAndroid Build Coastguard Worker // Output line according to flags
220*cf5a6c84SAndroid Build Coastguard Worker if (FLAG(D) || strncmp(new->name, "0000:", bus-new->name)) bus = new->name;
221*cf5a6c84SAndroid Build Coastguard Worker printf("%s", bus);
222*cf5a6c84SAndroid Build Coastguard Worker for (ii = 0; ii<3; ii++) {
223*cf5a6c84SAndroid Build Coastguard Worker sprintf(buf, "%0*x", 6-2*(ii||!FLAG(e)), cvd[ii]);
224*cf5a6c84SAndroid Build Coastguard Worker if (!TT.n) printf(FLAG(m) ? " \"%s\"" : ": %s"+(ii!=1), names[ii] ? : buf);
225*cf5a6c84SAndroid Build Coastguard Worker else if (TT.n==1) printf(FLAG(m) ? " \"%s\"" : (ii==2)?"%s ":" %s:", buf);
226*cf5a6c84SAndroid Build Coastguard Worker else if (!FLAG(m)) {
227*cf5a6c84SAndroid Build Coastguard Worker // This one permutes the order, so do it all first time and abort loop
228*cf5a6c84SAndroid Build Coastguard Worker printf(" %s [%s]: %s %s [%04x:%04x]", names[0], buf, names[1], names[2],
229*cf5a6c84SAndroid Build Coastguard Worker cvd[1], cvd[2]);
230*cf5a6c84SAndroid Build Coastguard Worker break;
231*cf5a6c84SAndroid Build Coastguard Worker } else printf(" \"%s [%s]\"", names[ii], buf);
232*cf5a6c84SAndroid Build Coastguard Worker }
233*cf5a6c84SAndroid Build Coastguard Worker if (revision) printf(FLAG(m) ? " -r%02x" : " (rev %02x)", revision);
234*cf5a6c84SAndroid Build Coastguard Worker if (FLAG(k) && driver) printf(FLAG(m) ? " \"%s\"" : " %s", driver);
235*cf5a6c84SAndroid Build Coastguard Worker xputc('\n');
236*cf5a6c84SAndroid Build Coastguard Worker
237*cf5a6c84SAndroid Build Coastguard Worker if (TT.x) {
238*cf5a6c84SAndroid Build Coastguard Worker FILE *fp;
239*cf5a6c84SAndroid Build Coastguard Worker int b, col = 0, max = (TT.x >= 4) ? 4096 : ((TT.x >= 3) ? 256 : 64);
240*cf5a6c84SAndroid Build Coastguard Worker
241*cf5a6c84SAndroid Build Coastguard Worker snprintf(toybuf, sizeof(toybuf), "/sys/bus/pci/devices/%s/config", new->name);
242*cf5a6c84SAndroid Build Coastguard Worker fp = xfopen(toybuf, "r");
243*cf5a6c84SAndroid Build Coastguard Worker while ((b = fgetc(fp)) != EOF) {
244*cf5a6c84SAndroid Build Coastguard Worker if ((col % 16) == 0) printf("%02x: ", col & 0xf0);
245*cf5a6c84SAndroid Build Coastguard Worker printf("%02x ", (b & 0xff));
246*cf5a6c84SAndroid Build Coastguard Worker if ((++col % 16) == 0) xputc('\n');
247*cf5a6c84SAndroid Build Coastguard Worker if (col == max) break;
248*cf5a6c84SAndroid Build Coastguard Worker }
249*cf5a6c84SAndroid Build Coastguard Worker xputc('\n');
250*cf5a6c84SAndroid Build Coastguard Worker fclose(fp);
251*cf5a6c84SAndroid Build Coastguard Worker }
252*cf5a6c84SAndroid Build Coastguard Worker
253*cf5a6c84SAndroid Build Coastguard Worker return 0;
254*cf5a6c84SAndroid Build Coastguard Worker }
255*cf5a6c84SAndroid Build Coastguard Worker
lspci_main(void)256*cf5a6c84SAndroid Build Coastguard Worker void lspci_main(void)
257*cf5a6c84SAndroid Build Coastguard Worker {
258*cf5a6c84SAndroid Build Coastguard Worker // Parse https://pci-ids.ucw.cz/v2.2/pci.ids (if available)
259*cf5a6c84SAndroid Build Coastguard Worker if (TT.n != 1) TT.class = parse_dev_ids("pci.ids", (void *)&TT.ids);
260*cf5a6c84SAndroid Build Coastguard Worker dirtree_read("/sys/bus/pci/devices/", list_pci);
261*cf5a6c84SAndroid Build Coastguard Worker }
262