Subversion Repositories planix.SVN

Rev

Rev 2 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 - 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->noauto)
69
		return 0;
70
	if(dt->vid != -1 && d->vid != dt->vid)
71
		return 0;
72
	if(dt->did != -1 && d->did != dt->did)
73
		return 0;
74
	if(cspmatch(dt, d->csp))
75
		return 1;
76
	for(c = 0; c < Nconf; c++)
77
		if((cp=d->conf[c]) != nil)
78
			for(i = 0; i < Niface; i++)
79
				if(cp->iface[i] != nil)
80
					if(cspmatch(dt, cp->iface[i]->csp))
81
						return 1;
82
	return 0;
83
}
84
 
85
/* We can't use procexec to execute drivers, because
86
 * procexec mounts #| at /mnt/temp and we do *not*
87
 * have /mnt/temp at boot time.
88
 * Instead, we use access to guess if we can execute the file.
89
 * and reply as procexec. Be careful that the child inherits
90
 * all the shared state of the thread library. It should run unnoticed.
91
 */
92
static void
93
xexec(Channel *c, char *nm, char *args[])
94
{
95
	int	pid;
96
 
97
	if(access(nm, AEXEC) == 0){
98
		pid = rfork(RFFDG|RFREND|RFPROC);
99
		switch(pid){
100
		case 0:
101
			exec(nm, args);
102
			_exits("exec");
103
		case -1:
104
			break;
105
		default:
106
			sendul(c, pid);
107
			threadexits(nil);
108
		}
109
	}
110
}
111
 
112
typedef struct Sarg Sarg;
113
struct Sarg{
114
	Port *pp;
115
	Devtab* dt;
116
	Channel*rc;
117
	char fname[80];
118
	char	args[128];
119
	char	*argv[40];
120
};
121
 
122
static void
123
startdevproc(void *a)
124
{
125
	Sarg	*sa = a;
126
	Dev	*d;
127
	Devtab *dt;
128
	int	argc;
129
	char *args, *argse, **argv;
130
	char *fname;
131
 
132
	threadsetgrp(threadid());
133
	d = sa->pp->dev;
134
	dt = sa->dt;
135
	args = sa->args;
136
	argse = sa->args + sizeof sa->args;
137
	argv = sa->argv;
138
	fname = sa->fname;
139
	sa->pp->devmaskp = &dt->devmask;
140
	sa->pp->devnb = getdevnb(&dt->devmask);
141
	if(sa->pp->devnb < 0){
142
		sa->pp->devmaskp = nil;
143
		sa->pp->devnb = 0;
144
	}else
145
		args = seprint(args, argse, "-N %d", sa->pp->devnb);
146
	if(dt->args != nil)
147
		seprint(args, argse, " %s", dt->args);
148
	args = sa->args;
149
	dprint(2, "%s: start: %s %s\n", argv0, dt->name, args);
150
	argv[0] = dt->name;
151
	argc = 1;
152
	if(args[0] != 0)
153
		argc += tokenize(args, argv+1, nelem(sa->argv)-2);
154
	argv[argc] = nil;
155
	if(dt->init == nil){
156
		if(d->dfd > 0 ){
157
			close(d->dfd);
158
			d->dfd = -1;
159
		}
160
		rfork(RFCFDG);
161
		open("/dev/null", OREAD);
162
		open("/dev/cons", OWRITE);
163
		open("/dev/cons", OWRITE);
164
 
165
		xexec(sa->rc, argv[0], argv);
166
		snprint(fname, sizeof(sa->fname), "/bin/usb/%s", dt->name);
167
		xexec(sa->rc, fname, argv);
168
		snprint(fname, sizeof(sa->fname), "/boot/%s", dt->name);
169
		xexec(sa->rc, fname, argv);
170
		if(cputype == nil)
171
			cputype = getenv("cputype");
172
		if(cputype != nil){
173
			snprint(fname, sizeof(sa->fname), "/%s/bin/%s",
174
				cputype, dt->name);
175
			argv[0] = fname;
176
			xexec(sa->rc, fname, argv);
177
		}
178
		fprint(2, "%s: %s: not found. can't exec\n", argv0, dt->name);
179
		sendul(sa->rc, -1);
180
		threadexits("exec");
181
	}else{
182
		sa->pp->dev = opendev(d->dir);
183
		sendul(sa->rc, 0);
184
		if(dt->init(d, argc, argv) < 0)
185
			fprint(2, "%s: %s: %r\n", argv0, dt->name);
186
		closedev(d);
187
		free(sa);
188
	}
189
	threadexits(nil);
190
}
191
 
192
static void
193
writeinfo(Dev *d)
194
{
195
	char buf[128];
196
	char *s;
197
	char *se;
198
	Usbdev *ud;
199
	Conf *c;
200
	Iface *ifc;
201
	int i, j;
202
 
203
	ud = d->usb;
204
	s = buf;
205
	se = buf+sizeof(buf);
206
	s = seprint(s, se, "info %s csp %#08ulx", classname(ud->class), ud->csp);
207
	for(i = 0; i < ud->nconf; i++){
208
		c = ud->conf[i];
209
		if(c == nil)
210
			break;
211
		for(j = 0; j < nelem(c->iface); j++){
212
			ifc = c->iface[j];
213
			if(ifc == nil)
214
				break;
215
			if(ifc->csp != ud->csp)
216
				s = seprint(s, se, " csp %#08ulx", ifc->csp);
217
		}
218
	}
219
	s = seprint(s, se, " vid %06#x did %06#x", ud->vid, ud->did);
220
	seprint(s, se, " %q %q", ud->vendor, ud->product);
221
	devctl(d, "%s", buf);
222
}
223
 
224
int
225
startdev(Port *pp)
226
{
227
	Dev *d;
228
	Usbdev *ud;
229
	Devtab *dt;
230
	Sarg *sa;
231
	Channel *rc;
232
 
233
	d = pp->dev;
234
	assert(d);
235
	ud = d->usb;
236
	assert(ud != nil);
237
 
238
	writeinfo(d);
239
 
240
	if(ud->class == Clhub){
241
		/*
242
		 * Hubs are handled directly by this process avoiding
243
		 * concurrent operation so that at most one device
244
		 * has the config address in use.
245
		 * We cancel kernel debug for these eps. too chatty.
246
		 */
247
		pp->hub = newhub(d->dir, d);
248
		if(pp->hub == nil)
249
			fprint(2, "%s: %s: %r\n", argv0, d->dir);
250
		else
251
			fprint(2, "usb/hub... ");
252
		if(usbdebug > 1)
253
			devctl(d, "debug 0");	/* polled hubs are chatty */
254
		return pp->hub == nil ? -1 : 0;
255
	}
256
 
257
	for(dt = devtab; dt->name != nil; dt++)
258
		if(devmatch(dt, ud))
259
			break;
260
	/*
261
	 * From here on the device is for the driver.
262
	 * When we return pp->dev contains a Dev just for us
263
	 * with only the ctl open. Both devs are released on the last closedev:
264
	 * driver's upon I/O errors and ours upon port dettach.
265
	 */
266
	if(dt->name == nil){
267
		dprint(2, "%s: no configured entry for %s (csp %#08lx)\n",
268
			argv0, d->dir, ud->csp);
269
		close(d->dfd);
270
		d->dfd = -1;
271
		return 0;
272
	}
273
	sa = emallocz(sizeof(Sarg), 1);
274
	sa->pp = pp;
275
	sa->dt = dt;
276
	rc = sa->rc = chancreate(sizeof(ulong), 1);
277
	procrfork(startdevproc, sa, Stack, RFNOTEG);
278
	if(recvul(rc) != 0)
279
		free(sa);
280
	chanfree(rc);
281
	fprint(2, "usb/%s... ", dt->name);
282
 
283
	sleep(Spawndelay);		/* in case we re-spawn too fast */
284
	return 0;
285
}