xref: /plan9/sys/src/cmd/usb/lib/devs.c (revision 16146bc9f7f774945213b79ebee114e739fe0b99)
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 
8*16146bc9SDavid du Colombier enum {
9*16146bc9SDavid du Colombier 	Ndevs = 32,
10*16146bc9SDavid du Colombier 	Arglen = 500,
11*16146bc9SDavid du Colombier 	Nargs = 64,
12906943f9SDavid du Colombier 	Stack = 16 * 1024,
13906943f9SDavid du Colombier };
14906943f9SDavid du Colombier 
15*16146bc9SDavid 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 {
71906943f9SDavid du Colombier 	int fd;
72906943f9SDavid du Colombier 	char fbuf[40];
73906943f9SDavid du Colombier 	char dbuf[512];
74906943f9SDavid du Colombier 	Dir *d;
75906943f9SDavid du Colombier 	int nd, nr;
76906943f9SDavid du Colombier 	int n;
77906943f9SDavid du Colombier 	int i;
78906943f9SDavid du Colombier 	char *nm;
79906943f9SDavid du Colombier 
80906943f9SDavid du Colombier 	fd = open("/dev/usb", OREAD);
81906943f9SDavid du Colombier 	if(fd < 0)
82906943f9SDavid du Colombier 		sysfatal("/dev/usb: %r");
83906943f9SDavid du Colombier 	nd = dirreadall(fd, &d);
84906943f9SDavid du Colombier 	close(fd);
85906943f9SDavid du Colombier 	if(nd < 2)
86906943f9SDavid du Colombier 		sysfatal("/dev/usb: no devs");
87906943f9SDavid du Colombier 	for(i = n = 0; i < nd && n < ndirs; i++){
88906943f9SDavid du Colombier 		nm = d[i].name;
89906943f9SDavid du Colombier 		if(strcmp(nm, "ctl") == 0 || strstr(nm, ".0") == nil)
90906943f9SDavid du Colombier 			continue;
91906943f9SDavid du Colombier 		snprint(fbuf, sizeof(fbuf), "/dev/usb/%s/ctl", nm);
92906943f9SDavid du Colombier 		fd = open(fbuf, OREAD);
93906943f9SDavid du Colombier 		if(fd < 0)
94906943f9SDavid du Colombier 			continue;	/* may be gone */
95906943f9SDavid du Colombier 		nr = read(fd, dbuf, sizeof(dbuf)-1);
96906943f9SDavid du Colombier 		close(fd);
97906943f9SDavid du Colombier 		if(nr < 0)
98906943f9SDavid du Colombier 			continue;
99906943f9SDavid du Colombier 		dbuf[nr] = 0;
100906943f9SDavid du Colombier 		if(strstr(dbuf, "enabled ") != nil && strstr(dbuf, " busy") == nil)
101906943f9SDavid du Colombier 			if(matchf(dbuf, farg) == 0)
102906943f9SDavid du Colombier 				dirs[n++] = smprint("/dev/usb/%s", nm);
103906943f9SDavid du Colombier 	}
104906943f9SDavid du Colombier 	free(d);
105906943f9SDavid du Colombier 	if(usbdebug > 1)
106906943f9SDavid du Colombier 		for(nd = 0; nd < n; nd++)
107906943f9SDavid du Colombier 			fprint(2, "finddevs: %s\n", dirs[nd]);
108906943f9SDavid du Colombier 	return n;
109906943f9SDavid du Colombier }
110906943f9SDavid du Colombier 
111906943f9SDavid du Colombier void
112906943f9SDavid du Colombier startdevs(char *args, char *argv[], int argc, int (*mf)(char*,void*), void*ma, int (*df)(Dev*,int,char**))
113906943f9SDavid du Colombier {
114*16146bc9SDavid du Colombier 	int i, ndirs, ndevs;
115906943f9SDavid du Colombier 	char *dirs[Ndevs];
116906943f9SDavid du Colombier 	char **dp;
117906943f9SDavid du Colombier 	Parg *parg;
118906943f9SDavid du Colombier 	Dev *dev;
119906943f9SDavid du Colombier 	Channel *rc;
120906943f9SDavid du Colombier 
121906943f9SDavid du Colombier 	if(access("/dev/usb", AEXIST) < 0 && bind("#u", "/dev", MBEFORE) < 0)
122906943f9SDavid du Colombier 		sysfatal("#u: %r");
123906943f9SDavid du Colombier 
124906943f9SDavid du Colombier 	if(argc > 0){
125906943f9SDavid du Colombier 		ndirs = argc;
126906943f9SDavid du Colombier 		dp = argv;
127906943f9SDavid du Colombier 	}else{
128906943f9SDavid du Colombier 		dp = dirs;
129906943f9SDavid du Colombier 		ndirs = finddevs(mf, ma, dp, Ndevs);
130906943f9SDavid du Colombier 		if(ndirs == nelem(dirs))
131906943f9SDavid du Colombier 			fprint(2, "%s: too many devices\n", argv0);
132906943f9SDavid du Colombier 	}
133906943f9SDavid du Colombier 	ndevs = 0;
134906943f9SDavid du Colombier 	rc = chancreate(sizeof(ulong), 0);
135906943f9SDavid du Colombier 	if(rc == nil)
136906943f9SDavid du Colombier 		sysfatal("no memory");
137906943f9SDavid du Colombier 	for(i = 0; i < ndirs; i++){
138906943f9SDavid du Colombier 		fprint(2, "%s: startdevs: opening #%d %s\n", argv0, i, dp[i]);
139906943f9SDavid du Colombier 		dev = opendev(dp[i]);
140906943f9SDavid du Colombier 		if(dev != nil){
141906943f9SDavid du Colombier 			if(configdev(dev) < 0){
142906943f9SDavid du Colombier 				fprint(2, "%s: %s: config: %r\n", argv0, dp[i]);
143906943f9SDavid du Colombier 				closedev(dev);
144906943f9SDavid du Colombier 			}else{
145906943f9SDavid du Colombier 				dprint(2, "%s: %U", argv0, dev);
146906943f9SDavid du Colombier 				parg = emallocz(sizeof(Parg), 0);
147906943f9SDavid du Colombier 				parg->args = estrdup(args);
148906943f9SDavid du Colombier 				parg->dev = dev;
149906943f9SDavid du Colombier 				parg->rc = rc;
150906943f9SDavid du Colombier 				parg->f = df;
151906943f9SDavid du Colombier 				proccreate(workproc, parg, Stack);
152906943f9SDavid du Colombier 				if(recvul(rc) == 0)
153906943f9SDavid du Colombier 					ndevs++;
154906943f9SDavid du Colombier 			}
155906943f9SDavid du Colombier 		}else
156906943f9SDavid du Colombier 			fprint(2, "%s: %s: %r\n", argv0, dp[i]);
157906943f9SDavid du Colombier 		if(dp != argv)
158906943f9SDavid du Colombier 			free(dirs[i]);
159906943f9SDavid du Colombier 	}
160906943f9SDavid du Colombier 	chanfree(rc);
161906943f9SDavid du Colombier 	if(ndevs == 0)
162906943f9SDavid du Colombier 		sysfatal("no device found");
163906943f9SDavid du Colombier }
164