1 #include <u.h>
2 #include <libc.h>
3 #include <thread.h>
4 #include "usb.h"
5
6 typedef struct Parg Parg;
7
8 enum {
9 Ndevs = 32,
10 Arglen = 500,
11 Nargs = 64,
12 Stack = 16 * 1024,
13 };
14
15 struct Parg {
16 char* args;
17 Dev* dev;
18 int (*f)(Dev*,int,char**);
19 Channel*rc;
20 };
21
22 static void
workproc(void * a)23 workproc(void *a)
24 {
25 Parg *pa;
26 char args[Arglen];
27 char *argv[Nargs];
28 int argc;
29 Channel *rc;
30 Dev *d;
31 int (*f)(Dev*,int,char**);
32
33 pa = a;
34 threadsetname("workproc %s", pa->dev->dir);
35 strecpy(args, args+sizeof(args), pa->args); /* don't leak */
36 d = pa->dev;
37 f = pa->f;
38 rc = pa->rc;
39 free(pa->args);
40 free(pa);
41 argc = tokenize(args, argv, nelem(argv)-1);
42 argv[argc] = nil;
43 if(f(d, argc, argv) < 0){
44 closedev(d);
45 fprint(2, "%s: devmain: %r\n", argv0);
46 sendul(rc, -1);
47 threadexits("devmain: %r");
48 }
49 sendul(rc, 0);
50 threadexits(nil);
51
52 }
53
54 int
matchdevcsp(char * info,void * a)55 matchdevcsp(char *info, void *a)
56 {
57 char sbuf[40];
58 int *csps;
59
60 csps = a;
61 for(; *csps != 0; csps++){
62 snprint(sbuf, sizeof(sbuf), "csp %#08ux", *csps);
63 if(strstr(info, sbuf) != nil)
64 return 0;
65 }
66 return -1;
67 }
68
69 int
finddevs(int (* matchf)(char *,void *),void * farg,char ** dirs,int ndirs)70 finddevs(int (*matchf)(char*,void*), void *farg, char** dirs, int ndirs)
71 {
72 int fd, i, n, nd, nr;
73 char *nm;
74 char dbuf[512], fbuf[40];
75 Dir *d;
76
77 fd = open("/dev/usb", OREAD);
78 if(fd < 0)
79 sysfatal("/dev/usb: %r");
80 nd = dirreadall(fd, &d);
81 close(fd);
82 if(nd < 2)
83 sysfatal("/dev/usb: no devs");
84 for(i = n = 0; i < nd && n < ndirs; i++){
85 nm = d[i].name;
86 if(strcmp(nm, "ctl") == 0 || strstr(nm, ".0") == nil)
87 continue;
88 snprint(fbuf, sizeof(fbuf), "/dev/usb/%s/ctl", nm);
89 fd = open(fbuf, OREAD);
90 if(fd < 0)
91 continue; /* may be gone */
92 nr = read(fd, dbuf, sizeof(dbuf)-1);
93 close(fd);
94 if(nr < 0)
95 continue;
96 dbuf[nr] = 0;
97 if(strstr(dbuf, "enabled ") != nil && strstr(dbuf, " busy") == nil)
98 if(matchf(dbuf, farg) == 0)
99 dirs[n++] = smprint("/dev/usb/%s", nm);
100 }
101 free(d);
102 if(usbdebug > 1)
103 for(nd = 0; nd < n; nd++)
104 fprint(2, "finddevs: %s\n", dirs[nd]);
105 return n;
106 }
107
108 void
startdevs(char * args,char * argv[],int argc,int (* mf)(char *,void *),void * ma,int (* df)(Dev *,int,char **))109 startdevs(char *args, char *argv[], int argc, int (*mf)(char*, void*),
110 void *ma, int (*df)(Dev*, int, char**))
111 {
112 int i, ndirs, ndevs;
113 char *dirs[Ndevs];
114 char **dp;
115 Parg *parg;
116 Dev *dev;
117 Channel *rc;
118
119 if(access("/dev/usb", AEXIST) < 0 && bind("#u", "/dev", MBEFORE) < 0)
120 sysfatal("#u: %r");
121
122 if(argc > 0){
123 ndirs = argc;
124 dp = argv;
125 }else{
126 dp = dirs;
127 ndirs = finddevs(mf, ma, dp, Ndevs);
128 if(ndirs == nelem(dirs))
129 fprint(2, "%s: too many devices\n", argv0);
130 }
131 ndevs = 0;
132 rc = chancreate(sizeof(ulong), 0);
133 if(rc == nil)
134 sysfatal("no memory");
135 for(i = 0; i < ndirs; i++){
136 fprint(2, "%s: startdevs: opening #%d %s\n", argv0, i, dp[i]);
137 dev = opendev(dp[i]);
138 if(dev == nil)
139 fprint(2, "%s: %s: %r\n", argv0, dp[i]);
140 else if(configdev(dev) < 0){
141 fprint(2, "%s: %s: config: %r\n", argv0, dp[i]);
142 closedev(dev);
143 }else{
144 dprint(2, "%s: %U", argv0, dev);
145 parg = emallocz(sizeof(Parg), 0);
146 parg->args = estrdup(args);
147 parg->dev = dev;
148 parg->rc = rc;
149 parg->f = df;
150 proccreate(workproc, parg, Stack);
151 if(recvul(rc) == 0)
152 ndevs++;
153 }
154 if(dp != argv)
155 free(dirs[i]);
156 }
157 chanfree(rc);
158 if(ndevs == 0)
159 sysfatal("no unhandled devices found");
160 }
161