1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34#define FOR_lsusb
35#include "toys.h"
36
37GLOBALS(
38 char *i;
39 long n;
40
41 void *ids, *class;
42 int count;
43)
44
45struct dev_ids {
46 struct dev_ids *next, *child;
47 int id;
48 char name[];
49};
50
51struct scanloop {
52 char *pattern;
53 void *d1, *d2;
54};
55
56
57
58static int scan_uevent(struct dirtree *new, int len, struct scanloop *sl)
59{
60 int ii, count = 0;
61 off_t flen = sizeof(toybuf);
62 char *ss, *yy;
63
64
65 if (*new->name == '.') return 0;
66 sprintf(toybuf, "%s/uevent", new->name);
67 if (!readfileat(dirtree_parentfd(new), ss = toybuf, toybuf, &flen)) return 0;
68
69
70 while ((flen = strcspn(ss, "\n"))) {
71 if (ss[flen]) ss[flen++] = 0;
72 yy = ss+flen;
73
74
75 for (ii = 0; ii<len; ii++) {
76 if (strchr(sl[ii].pattern, '%')) {
77 if (2-!sl[ii].d2==sscanf(ss, sl[ii].pattern, sl[ii].d1, sl[ii].d2))
78 break;
79 } else if (strstart(&ss, sl[ii].pattern)) {
80 *(void **)sl[ii].d1 = ss;
81 break;
82 }
83 }
84 if (ii!=len) count++;
85 ss = yy;
86 }
87
88 return count;
89}
90
91static void get_names(struct dev_ids *ids, int id1, int id2,
92 char **name1, char **name2)
93{
94
95 *name1 = *name2 = "";
96 for (; ids; ids = ids->next) {
97 if (id1 != ids->id) continue;
98 *name1 = ids->name;
99 for (ids = ids->child; ids; ids = ids->next) {
100 if (id2 != ids->id) continue;
101 *name2 = ids->name;
102 return;
103 }
104 return;
105 }
106}
107
108
109struct dev_ids *parse_dev_ids(char *name, struct dev_ids **and)
110{
111 char *path = "/etc:/vendor:/usr/share/misc";
112 struct string_list *sl;
113 FILE *fp;
114 char *s, *ss, *sss;
115 struct dev_ids *ids = 0, *new;
116 int fd = -1, tick = 0;
117
118
119 sprintf(toybuf, "%s.gz", name);
120 if ((sl = find_in_path(path, toybuf))) {
121 signal(SIGCHLD, SIG_IGN);
122 xpopen((char *[]){"zcat", sl->str, 0}, &fd, 1);
123 } else if ((sl = find_in_path(path, name))) fd = xopen(sl->str,O_RDONLY);
124 llist_traverse(sl, free);
125 if (fd == -1) return 0;
126
127 for (fp = fdopen(fd, "r"); (s = ss = xgetline(fp)); free(s)) {
128
129 if (s[strspn(s, " \t")]=='#' || strstart(&ss, "\t\t")) continue;
130
131
132 if (strstart(&ss, "C ") && and) {
133 *and = ids;
134 and = 0;
135 tick++;
136 }
137 fd = estrtol(sss = ss, &ss, 16);
138 if (ss>sss && *ss++==' ') {
139 while (isspace(*ss)) ss++;
140 new = xmalloc(sizeof(*new)+strlen(ss)+1);
141 new->child = 0;
142 new->id = fd;
143 strcpy(new->name, ss);
144 if (!ids || *s!='\t') {
145 new->next = ids;
146 ids = new;
147 } else {
148 new->next = ids->child;
149 ids->child = new;
150 }
151 }
152 }
153 fclose(fp);
154
155 return ids;
156}
157
158static int list_usb(struct dirtree *new)
159{
160 int busnum = 0, devnum = 0, pid = 0, vid = 0;
161 char *n1, *n2;
162
163 if (!new->parent) return DIRTREE_RECURSE;
164 if (3 == scan_uevent(new, 3, (struct scanloop[]){{"BUSNUM=%u", &busnum, 0},
165 {"DEVNUM=%u", &devnum, 0}, {"PRODUCT=%x/%x", &pid, &vid}}))
166 {
167 get_names(TT.ids, pid, vid, &n1, &n2);
168 printf("Bus %03d Device %03d: ID %04x:%04x %s %s\n",
169 busnum, devnum, pid, vid, n1, n2);
170 }
171
172 return 0;
173}
174
175void lsusb_main(void)
176{
177
178 TT.ids = parse_dev_ids("usb.ids", 0);
179 dirtree_read("/sys/bus/usb/devices/", list_usb);
180}
181
182#define FOR_lspci
183#include "generated/flags.h"
184
185
186static int list_pci(struct dirtree *new)
187{
188 char *driver = 0, buf[16], *ss, *names[3];
189 int cvd[3] = {0}, ii, revision = 0;
190 off_t len = sizeof(toybuf);
191
192
193
194 if (!new->parent) return DIRTREE_RECURSE;
195 if (strlen(new->name)<6) return 0;
196 TT.count = 0;
197
198
199 sprintf(toybuf, "%s/revision", new->name);
200 if (readfileat(dirtree_parentfd(new), ss = toybuf, toybuf, &len)) {
201 strstart(&ss, "0x");
202 sscanf(ss, "%x", &revision);
203 }
204
205
206 if (3 != scan_uevent(new, 3, (struct scanloop[]){{"DRIVER=", &driver, 0},
207 {"PCI_CLASS=%x", cvd, 0}, {"PCI_ID=%x:%x", cvd+1, cvd+2}})) return 0;
208 get_names(TT.class, 255&(cvd[0]>>16), 255&(cvd[0]>>8), names, names);
209 get_names(TT.ids, cvd[1], cvd[2], names+1, names+2);
210 if (!FLAG(e)) cvd[0] >>= 8;
211
212
213 printf("%s", new->name+5);
214 for (ii = 0; ii<3; ii++) {
215 sprintf(buf, "%0*x", 6-2*(ii||!FLAG(e)), cvd[ii]);
216 if (!TT.n) printf(FLAG(m) ? " \"%s\"" : ": %s"+(ii!=1), names[ii] ? : buf);
217 else if (TT.n==1) printf(FLAG(m) ? " \"%s\"" : (ii==2) ? "%s " : " %s:", buf);
218 else if (!FLAG(m)) {
219
220 printf(" %s [%s]: %s %s [%04x:%04x]", names[0], buf, names[1], names[2],
221 cvd[1], cvd[2]);
222 break;
223 } else printf(" \"%s [%s]\"", names[ii], buf);
224 }
225 printf(FLAG(m) ? " -r%02x" : " (rev %02x)", revision);
226 if (FLAG(k)) printf(FLAG(m) ? " \"%s\"" : " %s", driver);
227 xputc('\n');
228
229 return 0;
230}
231
232void lspci_main(void)
233{
234
235 if (TT.n != 1) TT.class = parse_dev_ids("pci.ids", (void *)&TT.ids);
236 dirtree_read("/sys/bus/pci/devices/", list_pci);
237}
238