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