xref: /plan9/sys/src/cmd/usb/lib/devs.c (revision d9cef801fc51c266194b94a670d6ca1644c1d6a9)
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
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;
34906943f9SDavid du Colombier 	strecpy(args, args+sizeof(args), pa->args);	/* don't leak */
35906943f9SDavid du Colombier 	d = pa->dev;
36906943f9SDavid du Colombier 	f = pa->f;
37906943f9SDavid du Colombier 	rc = pa->rc;
38906943f9SDavid du Colombier 	free(pa->args);
39906943f9SDavid du Colombier 	free(pa);
40906943f9SDavid du Colombier 	argc = tokenize(args, argv, nelem(argv)-1);
41906943f9SDavid du Colombier 	argv[argc] = nil;
42906943f9SDavid du Colombier 	if(f(d, argc, argv) < 0){
43906943f9SDavid du Colombier 		closedev(d);
44906943f9SDavid du Colombier 		fprint(2, "%s: devmain: %r\n", argv0);
45906943f9SDavid du Colombier 		sendul(rc, -1);
46906943f9SDavid du Colombier 		threadexits("devmain: %r");
47906943f9SDavid du Colombier 	}
48906943f9SDavid du Colombier 	sendul(rc, 0);
49906943f9SDavid du Colombier 	threadexits(nil);
50906943f9SDavid du Colombier 
51906943f9SDavid du Colombier }
52906943f9SDavid du Colombier 
53906943f9SDavid du Colombier int
54906943f9SDavid du Colombier matchdevcsp(char *info, void *a)
55906943f9SDavid du Colombier {
56906943f9SDavid du Colombier 	char sbuf[40];
57906943f9SDavid du Colombier 	int *csps;
58906943f9SDavid du Colombier 
59906943f9SDavid du Colombier 	csps = a;
60906943f9SDavid du Colombier 	for(; *csps != 0; csps++){
61906943f9SDavid du Colombier 		snprint(sbuf, sizeof(sbuf), "csp %#08ux", *csps);
62906943f9SDavid du Colombier 		if(strstr(info, sbuf) != nil)
63906943f9SDavid du Colombier 			return 0;
64906943f9SDavid du Colombier 	}
65906943f9SDavid du Colombier 	return -1;
66906943f9SDavid du Colombier }
67906943f9SDavid du Colombier 
68906943f9SDavid du Colombier int
69906943f9SDavid du Colombier finddevs(int (*matchf)(char*,void*), void *farg, char** dirs, int ndirs)
70906943f9SDavid du Colombier {
71*d9cef801SDavid du Colombier 	int fd, i, n, nd, nr;
72906943f9SDavid du Colombier 	char *nm;
73*d9cef801SDavid du Colombier 	char dbuf[512], fbuf[40];
74*d9cef801SDavid du Colombier 	Dir *d;
75906943f9SDavid du Colombier 
76906943f9SDavid du Colombier 	fd = open("/dev/usb", OREAD);
77906943f9SDavid du Colombier 	if(fd < 0)
78906943f9SDavid du Colombier 		sysfatal("/dev/usb: %r");
79906943f9SDavid du Colombier 	nd = dirreadall(fd, &d);
80906943f9SDavid du Colombier 	close(fd);
81906943f9SDavid du Colombier 	if(nd < 2)
82906943f9SDavid du Colombier 		sysfatal("/dev/usb: no devs");
83906943f9SDavid du Colombier 	for(i = n = 0; i < nd && n < ndirs; i++){
84906943f9SDavid du Colombier 		nm = d[i].name;
85906943f9SDavid du Colombier 		if(strcmp(nm, "ctl") == 0 || strstr(nm, ".0") == nil)
86906943f9SDavid du Colombier 			continue;
87906943f9SDavid du Colombier 		snprint(fbuf, sizeof(fbuf), "/dev/usb/%s/ctl", nm);
88906943f9SDavid du Colombier 		fd = open(fbuf, OREAD);
89906943f9SDavid du Colombier 		if(fd < 0)
90906943f9SDavid du Colombier 			continue;	/* may be gone */
91906943f9SDavid du Colombier 		nr = read(fd, dbuf, sizeof(dbuf)-1);
92906943f9SDavid du Colombier 		close(fd);
93906943f9SDavid du Colombier 		if(nr < 0)
94906943f9SDavid du Colombier 			continue;
95906943f9SDavid du Colombier 		dbuf[nr] = 0;
96906943f9SDavid du Colombier 		if(strstr(dbuf, "enabled ") != nil && strstr(dbuf, " busy") == nil)
97906943f9SDavid du Colombier 			if(matchf(dbuf, farg) == 0)
98906943f9SDavid du Colombier 				dirs[n++] = smprint("/dev/usb/%s", nm);
99906943f9SDavid du Colombier 	}
100906943f9SDavid du Colombier 	free(d);
101906943f9SDavid du Colombier 	if(usbdebug > 1)
102906943f9SDavid du Colombier 		for(nd = 0; nd < n; nd++)
103906943f9SDavid du Colombier 			fprint(2, "finddevs: %s\n", dirs[nd]);
104906943f9SDavid du Colombier 	return n;
105906943f9SDavid du Colombier }
106906943f9SDavid du Colombier 
107906943f9SDavid du Colombier void
108*d9cef801SDavid du Colombier startdevs(char *args, char *argv[], int argc, int (*mf)(char*, void*),
109*d9cef801SDavid du Colombier 	void *ma, int (*df)(Dev*, int, char**))
110906943f9SDavid du Colombier {
11116146bc9SDavid du Colombier 	int i, ndirs, ndevs;
112906943f9SDavid du Colombier 	char *dirs[Ndevs];
113906943f9SDavid du Colombier 	char **dp;
114906943f9SDavid du Colombier 	Parg *parg;
115906943f9SDavid du Colombier 	Dev *dev;
116906943f9SDavid du Colombier 	Channel *rc;
117906943f9SDavid du Colombier 
118906943f9SDavid du Colombier 	if(access("/dev/usb", AEXIST) < 0 && bind("#u", "/dev", MBEFORE) < 0)
119906943f9SDavid du Colombier 		sysfatal("#u: %r");
120906943f9SDavid du Colombier 
121906943f9SDavid du Colombier 	if(argc > 0){
122906943f9SDavid du Colombier 		ndirs = argc;
123906943f9SDavid du Colombier 		dp = argv;
124906943f9SDavid du Colombier 	}else{
125906943f9SDavid du Colombier 		dp = dirs;
126906943f9SDavid du Colombier 		ndirs = finddevs(mf, ma, dp, Ndevs);
127906943f9SDavid du Colombier 		if(ndirs == nelem(dirs))
128906943f9SDavid du Colombier 			fprint(2, "%s: too many devices\n", argv0);
129906943f9SDavid du Colombier 	}
130906943f9SDavid du Colombier 	ndevs = 0;
131906943f9SDavid du Colombier 	rc = chancreate(sizeof(ulong), 0);
132906943f9SDavid du Colombier 	if(rc == nil)
133906943f9SDavid du Colombier 		sysfatal("no memory");
134906943f9SDavid du Colombier 	for(i = 0; i < ndirs; i++){
135906943f9SDavid du Colombier 		fprint(2, "%s: startdevs: opening #%d %s\n", argv0, i, dp[i]);
136906943f9SDavid du Colombier 		dev = opendev(dp[i]);
137*d9cef801SDavid du Colombier 		if(dev == nil)
138*d9cef801SDavid du Colombier 			fprint(2, "%s: %s: %r\n", argv0, dp[i]);
139*d9cef801SDavid du Colombier 		else if(configdev(dev) < 0){
140906943f9SDavid du Colombier 			fprint(2, "%s: %s: config: %r\n", argv0, dp[i]);
141906943f9SDavid du Colombier 			closedev(dev);
142906943f9SDavid du Colombier 		}else{
143906943f9SDavid du Colombier 			dprint(2, "%s: %U", argv0, dev);
144906943f9SDavid du Colombier 			parg = emallocz(sizeof(Parg), 0);
145906943f9SDavid du Colombier 			parg->args = estrdup(args);
146906943f9SDavid du Colombier 			parg->dev = dev;
147906943f9SDavid du Colombier 			parg->rc = rc;
148906943f9SDavid du Colombier 			parg->f = df;
149906943f9SDavid du Colombier 			proccreate(workproc, parg, Stack);
150906943f9SDavid du Colombier 			if(recvul(rc) == 0)
151906943f9SDavid du Colombier 				ndevs++;
152906943f9SDavid du Colombier 		}
153906943f9SDavid du Colombier 		if(dp != argv)
154906943f9SDavid du Colombier 			free(dirs[i]);
155906943f9SDavid du Colombier 	}
156906943f9SDavid du Colombier 	chanfree(rc);
157906943f9SDavid du Colombier 	if(ndevs == 0)
158*d9cef801SDavid du Colombier 		sysfatal("no unhandled devices found");
159906943f9SDavid du Colombier }
160