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