1906943f9SDavid du Colombier #include <u.h>
2906943f9SDavid du Colombier #include <libc.h>
3906943f9SDavid du Colombier #include <thread.h>
4906943f9SDavid du Colombier #include "usb.h"
5906943f9SDavid du Colombier
6906943f9SDavid du Colombier typedef struct Parg Parg;
7906943f9SDavid du Colombier
816146bc9SDavid du Colombier enum {
916146bc9SDavid du Colombier Ndevs = 32,
1016146bc9SDavid du Colombier Arglen = 500,
1116146bc9SDavid du Colombier Nargs = 64,
12906943f9SDavid du Colombier Stack = 16 * 1024,
13906943f9SDavid du Colombier };
14906943f9SDavid du Colombier
1516146bc9SDavid du Colombier struct Parg {
16906943f9SDavid du Colombier char* args;
17906943f9SDavid du Colombier Dev* dev;
18906943f9SDavid du Colombier int (*f)(Dev*,int,char**);
19906943f9SDavid du Colombier Channel*rc;
20906943f9SDavid du Colombier };
21906943f9SDavid du Colombier
22906943f9SDavid du Colombier static void
workproc(void * a)23906943f9SDavid du Colombier workproc(void *a)
24906943f9SDavid du Colombier {
25906943f9SDavid du Colombier Parg *pa;
26906943f9SDavid du Colombier char args[Arglen];
27906943f9SDavid du Colombier char *argv[Nargs];
28906943f9SDavid du Colombier int argc;
29906943f9SDavid du Colombier Channel *rc;
30906943f9SDavid du Colombier Dev *d;
31906943f9SDavid du Colombier int (*f)(Dev*,int,char**);
32906943f9SDavid du Colombier
33906943f9SDavid du Colombier pa = a;
34*f1a26d48SDavid du Colombier threadsetname("workproc %s", pa->dev->dir);
35906943f9SDavid du Colombier strecpy(args, args+sizeof(args), pa->args); /* don't leak */
36906943f9SDavid du Colombier d = pa->dev;
37906943f9SDavid du Colombier f = pa->f;
38906943f9SDavid du Colombier rc = pa->rc;
39906943f9SDavid du Colombier free(pa->args);
40906943f9SDavid du Colombier free(pa);
41906943f9SDavid du Colombier argc = tokenize(args, argv, nelem(argv)-1);
42906943f9SDavid du Colombier argv[argc] = nil;
43906943f9SDavid du Colombier if(f(d, argc, argv) < 0){
44906943f9SDavid du Colombier closedev(d);
45906943f9SDavid du Colombier fprint(2, "%s: devmain: %r\n", argv0);
46906943f9SDavid du Colombier sendul(rc, -1);
47906943f9SDavid du Colombier threadexits("devmain: %r");
48906943f9SDavid du Colombier }
49906943f9SDavid du Colombier sendul(rc, 0);
50906943f9SDavid du Colombier threadexits(nil);
51906943f9SDavid du Colombier
52906943f9SDavid du Colombier }
53906943f9SDavid du Colombier
54906943f9SDavid du Colombier int
matchdevcsp(char * info,void * a)55906943f9SDavid du Colombier matchdevcsp(char *info, void *a)
56906943f9SDavid du Colombier {
57906943f9SDavid du Colombier char sbuf[40];
58906943f9SDavid du Colombier int *csps;
59906943f9SDavid du Colombier
60906943f9SDavid du Colombier csps = a;
61906943f9SDavid du Colombier for(; *csps != 0; csps++){
62906943f9SDavid du Colombier snprint(sbuf, sizeof(sbuf), "csp %#08ux", *csps);
63906943f9SDavid du Colombier if(strstr(info, sbuf) != nil)
64906943f9SDavid du Colombier return 0;
65906943f9SDavid du Colombier }
66906943f9SDavid du Colombier return -1;
67906943f9SDavid du Colombier }
68906943f9SDavid du Colombier
69906943f9SDavid du Colombier int
finddevs(int (* matchf)(char *,void *),void * farg,char ** dirs,int ndirs)70906943f9SDavid du Colombier finddevs(int (*matchf)(char*,void*), void *farg, char** dirs, int ndirs)
71906943f9SDavid du Colombier {
72d9cef801SDavid du Colombier int fd, i, n, nd, nr;
73906943f9SDavid du Colombier char *nm;
74d9cef801SDavid du Colombier char dbuf[512], fbuf[40];
75d9cef801SDavid du Colombier Dir *d;
76906943f9SDavid du Colombier
77906943f9SDavid du Colombier fd = open("/dev/usb", OREAD);
78906943f9SDavid du Colombier if(fd < 0)
79906943f9SDavid du Colombier sysfatal("/dev/usb: %r");
80906943f9SDavid du Colombier nd = dirreadall(fd, &d);
81906943f9SDavid du Colombier close(fd);
82906943f9SDavid du Colombier if(nd < 2)
83906943f9SDavid du Colombier sysfatal("/dev/usb: no devs");
84906943f9SDavid du Colombier for(i = n = 0; i < nd && n < ndirs; i++){
85906943f9SDavid du Colombier nm = d[i].name;
86906943f9SDavid du Colombier if(strcmp(nm, "ctl") == 0 || strstr(nm, ".0") == nil)
87906943f9SDavid du Colombier continue;
88906943f9SDavid du Colombier snprint(fbuf, sizeof(fbuf), "/dev/usb/%s/ctl", nm);
89906943f9SDavid du Colombier fd = open(fbuf, OREAD);
90906943f9SDavid du Colombier if(fd < 0)
91906943f9SDavid du Colombier continue; /* may be gone */
92906943f9SDavid du Colombier nr = read(fd, dbuf, sizeof(dbuf)-1);
93906943f9SDavid du Colombier close(fd);
94906943f9SDavid du Colombier if(nr < 0)
95906943f9SDavid du Colombier continue;
96906943f9SDavid du Colombier dbuf[nr] = 0;
97906943f9SDavid du Colombier if(strstr(dbuf, "enabled ") != nil && strstr(dbuf, " busy") == nil)
98906943f9SDavid du Colombier if(matchf(dbuf, farg) == 0)
99906943f9SDavid du Colombier dirs[n++] = smprint("/dev/usb/%s", nm);
100906943f9SDavid du Colombier }
101906943f9SDavid du Colombier free(d);
102906943f9SDavid du Colombier if(usbdebug > 1)
103906943f9SDavid du Colombier for(nd = 0; nd < n; nd++)
104906943f9SDavid du Colombier fprint(2, "finddevs: %s\n", dirs[nd]);
105906943f9SDavid du Colombier return n;
106906943f9SDavid du Colombier }
107906943f9SDavid du Colombier
108906943f9SDavid du Colombier void
startdevs(char * args,char * argv[],int argc,int (* mf)(char *,void *),void * ma,int (* df)(Dev *,int,char **))109d9cef801SDavid du Colombier startdevs(char *args, char *argv[], int argc, int (*mf)(char*, void*),
110d9cef801SDavid du Colombier void *ma, int (*df)(Dev*, int, char**))
111906943f9SDavid du Colombier {
11216146bc9SDavid du Colombier int i, ndirs, ndevs;
113906943f9SDavid du Colombier char *dirs[Ndevs];
114906943f9SDavid du Colombier char **dp;
115906943f9SDavid du Colombier Parg *parg;
116906943f9SDavid du Colombier Dev *dev;
117906943f9SDavid du Colombier Channel *rc;
118906943f9SDavid du Colombier
119906943f9SDavid du Colombier if(access("/dev/usb", AEXIST) < 0 && bind("#u", "/dev", MBEFORE) < 0)
120906943f9SDavid du Colombier sysfatal("#u: %r");
121906943f9SDavid du Colombier
122906943f9SDavid du Colombier if(argc > 0){
123906943f9SDavid du Colombier ndirs = argc;
124906943f9SDavid du Colombier dp = argv;
125906943f9SDavid du Colombier }else{
126906943f9SDavid du Colombier dp = dirs;
127906943f9SDavid du Colombier ndirs = finddevs(mf, ma, dp, Ndevs);
128906943f9SDavid du Colombier if(ndirs == nelem(dirs))
129906943f9SDavid du Colombier fprint(2, "%s: too many devices\n", argv0);
130906943f9SDavid du Colombier }
131906943f9SDavid du Colombier ndevs = 0;
132906943f9SDavid du Colombier rc = chancreate(sizeof(ulong), 0);
133906943f9SDavid du Colombier if(rc == nil)
134906943f9SDavid du Colombier sysfatal("no memory");
135906943f9SDavid du Colombier for(i = 0; i < ndirs; i++){
136906943f9SDavid du Colombier fprint(2, "%s: startdevs: opening #%d %s\n", argv0, i, dp[i]);
137906943f9SDavid du Colombier dev = opendev(dp[i]);
138d9cef801SDavid du Colombier if(dev == nil)
139d9cef801SDavid du Colombier fprint(2, "%s: %s: %r\n", argv0, dp[i]);
140d9cef801SDavid du Colombier else if(configdev(dev) < 0){
141906943f9SDavid du Colombier fprint(2, "%s: %s: config: %r\n", argv0, dp[i]);
142906943f9SDavid du Colombier closedev(dev);
143906943f9SDavid du Colombier }else{
144906943f9SDavid du Colombier dprint(2, "%s: %U", argv0, dev);
145906943f9SDavid du Colombier parg = emallocz(sizeof(Parg), 0);
146906943f9SDavid du Colombier parg->args = estrdup(args);
147906943f9SDavid du Colombier parg->dev = dev;
148906943f9SDavid du Colombier parg->rc = rc;
149906943f9SDavid du Colombier parg->f = df;
150906943f9SDavid du Colombier proccreate(workproc, parg, Stack);
151906943f9SDavid du Colombier if(recvul(rc) == 0)
152906943f9SDavid du Colombier ndevs++;
153906943f9SDavid du Colombier }
154906943f9SDavid du Colombier if(dp != argv)
155906943f9SDavid du Colombier free(dirs[i]);
156906943f9SDavid du Colombier }
157906943f9SDavid du Colombier chanfree(rc);
158906943f9SDavid du Colombier if(ndevs == 0)
159d9cef801SDavid du Colombier sysfatal("no unhandled devices found");
160906943f9SDavid du Colombier }
161