xref: /plan9-contrib/sys/src/cmd/usb/usbd/dev.c (revision 3468a4915d661daa200976acc4f80f51aae144b2)
1 /*
2  * Framework for USB devices.
3  * Some of them may be embedded into usbd and some of
4  * them may exist as /bin/usb/* binaries on their own.
5  *
6  * When embedded, devmain() is given a ref of an already
7  * configured and open Dev. If devmain()
8  * does not fail it should release this ref when done and
9  * use incref to add further refs to it.
10  */
11 #include <u.h>
12 #include <libc.h>
13 #include <thread.h>
14 #include "usb.h"
15 #include "usbd.h"
16 
17 static Lock masklck;
18 extern Devtab devtab[];
19 static char* cputype;
20 
21 int
22 getdevnb(uvlong *maskp)
23 {
24 	int i;
25 
26 	lock(&masklck);
27 	for(i = 0; i < 8 * sizeof *maskp; i++)
28 		if((*maskp & (1ULL<<i)) == 0){
29 			*maskp |= 1ULL<<i;
30 			unlock(&masklck);
31 			return i;
32 		}
33 	unlock(&masklck);
34 	return -1;
35 }
36 
37 void
38 putdevnb(uvlong *maskp, int id)
39 {
40 	lock(&masklck);
41 	if(id >= 0)
42 		*maskp &= ~(1ULL<<id);
43 	unlock(&masklck);
44 }
45 
46 static int
47 cspmatch(Devtab *dt, int dcsp)
48 {
49 	int	i;
50 	int	csp;
51 
52 	for(i = 0; i < nelem(dt->csps); i++)
53 		if((csp=dt->csps[i]) != 0)
54 		if(csp == dcsp)
55 			return 1;
56 		else if((csp&DCL) && (csp&~DCL) == Class(dcsp))
57 			return 1;
58 	return 0;
59 }
60 
61 static int
62 devmatch(Devtab *dt, Usbdev *d)
63 {
64 	int i;
65 	int c;
66 	Conf *cp;
67 
68 	if(dt->vid != -1 && d->vid != dt->vid)
69 		return 0;
70 	if(dt->did != -1 && d->did != dt->did)
71 		return 0;
72 	if(cspmatch(dt, d->csp))
73 		return 1;
74 	for(c = 0; c < Nconf; c++)
75 		if((cp=d->conf[c]) != nil)
76 			for(i = 0; i < Niface; i++)
77 				if(cp->iface[i] != nil)
78 					if(cspmatch(dt, cp->iface[i]->csp))
79 						return 1;
80 	return 0;
81 }
82 
83 /* We can't use procexec to execute drivers, because
84  * procexec mounts #| at /mnt/temp and we do *not*
85  * have /mnt/temp at boot time.
86  * Instead, we use access to guess if we can execute the file.
87  * and reply as procexec. Be careful that the child inherits
88  * all the shared state of the thread library. It should run unnoticed.
89  */
90 static void
91 xexec(Channel *c, char *nm, char *args[])
92 {
93 	int	pid;
94 
95 	if(access(nm, AEXEC) == 0){
96 		pid = rfork(RFFDG|RFREND|RFPROC);
97 		switch(pid){
98 		case 0:
99 			exec(nm, args);
100 			_exits("exec");
101 		case -1:
102 			break;
103 		default:
104 			sendul(c, pid);
105 			threadexits(nil);
106 		}
107 	}
108 }
109 
110 typedef struct Sarg Sarg;
111 struct Sarg{
112 	Port *pp;
113 	Devtab* dt;
114 	Channel*rc;
115 	char fname[80];
116 	char	args[128];
117 	char	*argv[40];
118 };
119 
120 static void
121 startdevproc(void *a)
122 {
123 	Sarg	*sa = a;
124 	Dev	*d;
125 	Devtab *dt;
126 	int	argc;
127 	char *args, *argse, **argv;
128 	char *fname;
129 
130 	threadsetgrp(threadid());
131 	d = sa->pp->dev;
132 	dt = sa->dt;
133 	args = sa->args;
134 	argse = sa->args + sizeof sa->args;
135 	argv = sa->argv;
136 	fname = sa->fname;
137 	sa->pp->devmaskp = &dt->devmask;
138 	sa->pp->devnb = getdevnb(&dt->devmask);
139 	if(sa->pp->devnb < 0){
140 		sa->pp->devmaskp = nil;
141 		sa->pp->devnb = 0;
142 	}else
143 		args = seprint(args, argse, "-N %d", sa->pp->devnb);
144 	if(dt->args != nil)
145 		seprint(args, argse, " %s", dt->args);
146 	args = sa->args;
147 	dprint(2, "%s: start: %s %s\n", argv0, dt->name, args);
148 	argv[0] = dt->name;
149 	argc = 1;
150 	if(args[0] != 0)
151 		argc += tokenize(args, argv+1, nelem(sa->argv)-2);
152 	argv[argc] = nil;
153 	if(dt->init == nil){
154 		if(d->dfd > 0 ){
155 			close(d->dfd);
156 			d->dfd = -1;
157 		}
158 		rfork(RFCFDG);
159 		open("/dev/null", OREAD);
160 		open("/dev/cons", OWRITE);
161 		open("/dev/cons", OWRITE);
162 
163 		xexec(sa->rc, argv[0], argv);
164 		snprint(fname, sizeof(sa->fname), "/bin/usb/%s", dt->name);
165 		xexec(sa->rc, fname, argv);
166 		snprint(fname, sizeof(sa->fname), "/boot/%s", dt->name);
167 		xexec(sa->rc, fname, argv);
168 		if(cputype == nil)
169 			cputype = getenv("cputype");
170 		if(cputype != nil){
171 			snprint(fname, sizeof(sa->fname), "/%s/bin/%s",
172 				cputype, dt->name);
173 			argv[0] = fname;
174 			xexec(sa->rc, fname, argv);
175 		}
176 		fprint(2, "%s: %s: not found. can't exec\n", argv0, dt->name);
177 		sendul(sa->rc, -1);
178 		threadexits("exec");
179 	}else{
180 		sa->pp->dev = opendev(d->dir);
181 		sendul(sa->rc, 0);
182 		if(dt->init(d, argc, argv) < 0)
183 			fprint(2, "%s: %s: %r\n", argv0, dt->name);
184 		closedev(d);
185 		free(sa);
186 	}
187 	threadexits(nil);
188 }
189 
190 static void
191 writeinfo(Dev *d)
192 {
193 	char buf[128];
194 	char *s;
195 	char *se;
196 	Usbdev *ud;
197 	Conf *c;
198 	Iface *ifc;
199 	int i, j;
200 
201 	ud = d->usb;
202 	s = buf;
203 	se = buf+sizeof(buf);
204 	s = seprint(s, se, "info %s csp %#08ulx", classname(ud->class), ud->csp);
205 	for(i = 0; i < ud->nconf; i++){
206 		c = ud->conf[i];
207 		if(c == nil)
208 			break;
209 		for(j = 0; j < nelem(c->iface); j++){
210 			ifc = c->iface[j];
211 			if(ifc == nil)
212 				break;
213 			if(ifc->csp != ud->csp)
214 				s = seprint(s, se, " csp %#08ulx", ifc->csp);
215 		}
216 	}
217 	s = seprint(s, se, " vid %06#x did %06#x", ud->vid, ud->did);
218 	seprint(s, se, " %q %q", ud->vendor, ud->product);
219 	devctl(d, "%s", buf);
220 }
221 
222 int
223 startdev(Port *pp)
224 {
225 	Dev *d;
226 	Usbdev *ud;
227 	Devtab *dt;
228 	Sarg *sa;
229 	Channel *rc;
230 
231 	d = pp->dev;
232 	assert(d);
233 	ud = d->usb;
234 	assert(ud != nil);
235 
236 	writeinfo(d);
237 
238 	if(ud->class == Clhub){
239 		/*
240 		 * Hubs are handled directly by this process avoiding
241 		 * concurrent operation so that at most one device
242 		 * has the config address in use.
243 		 * We cancel kernel debug for these eps. too chatty.
244 		 */
245 		pp->hub = newhub(d->dir, d);
246 		if(pp->hub == nil)
247 			fprint(2, "%s: %s: %r\n", argv0, d->dir);
248 		else
249 			fprint(2, "usb/hub... ");
250 		if(usbdebug > 1)
251 			devctl(d, "debug 0");	/* polled hubs are chatty */
252 		return pp->hub == nil ? -1 : 0;
253 	}
254 
255 	for(dt = devtab; dt->name != nil; dt++)
256 		if(devmatch(dt, ud))
257 			break;
258 	/*
259 	 * From here on the device is for the driver.
260 	 * When we return pp->dev contains a Dev just for us
261 	 * with only the ctl open. Both devs are released on the last closedev:
262 	 * driver's upon I/O errors and ours upon port dettach.
263 	 */
264 	if(dt->name == nil){
265 		dprint(2, "%s: no configured entry for %s (csp %#08lx)\n",
266 			argv0, d->dir, ud->csp);
267 		close(d->dfd);
268 		d->dfd = -1;
269 		return 0;
270 	}
271 	sa = emallocz(sizeof(Sarg), 1);
272 	sa->pp = pp;
273 	sa->dt = dt;
274 	rc = sa->rc = chancreate(sizeof(ulong), 1);
275 	procrfork(startdevproc, sa, Stack, RFNOTEG);
276 	if(recvul(rc) != 0)
277 		free(sa);
278 	chanfree(rc);
279 	fprint(2, "usb/%s... ", dt->name);
280 
281 	sleep(Spawndelay);		/* in case we re-spawn too fast */
282 	return 0;
283 }
284