xref: /plan9/sys/src/cmd/usb/lib/devs.c (revision bfb6eab9346d861b5f68a2b1af55a1768a8fe25b)
1 #include <u.h>
2 #include <libc.h>
3 #include <thread.h>
4 #include "usb.h"
5 
6 typedef struct Parg Parg;
7 
8 enum {
9 	Ndevs = 32,
10 	Arglen = 500,
11 	Nargs = 64,
12 	Stack = 16 * 1024,
13 };
14 
15 struct Parg {
16 	char*	args;
17 	Dev*	dev;
18 	int 	(*f)(Dev*,int,char**);
19 	Channel*rc;
20 };
21 
22 static void
23 workproc(void *a)
24 {
25 	Parg *pa;
26 	char args[Arglen];
27 	char *argv[Nargs];
28 	int argc;
29 	Channel *rc;
30 	Dev *d;
31 	int (*f)(Dev*,int,char**);
32 
33 	pa = a;
34 	strecpy(args, args+sizeof(args), pa->args);	/* don't leak */
35 	d = pa->dev;
36 	f = pa->f;
37 	rc = pa->rc;
38 	free(pa->args);
39 	free(pa);
40 	argc = tokenize(args, argv, nelem(argv)-1);
41 	argv[argc] = nil;
42 	if(f(d, argc, argv) < 0){
43 		closedev(d);
44 		fprint(2, "%s: devmain: %r\n", argv0);
45 		sendul(rc, -1);
46 		threadexits("devmain: %r");
47 	}
48 	sendul(rc, 0);
49 	threadexits(nil);
50 
51 }
52 
53 int
54 matchdevcsp(char *info, void *a)
55 {
56 	char sbuf[40];
57 	int *csps;
58 
59 	csps = a;
60 	for(; *csps != 0; csps++){
61 		snprint(sbuf, sizeof(sbuf), "csp %#08ux", *csps);
62 		if(strstr(info, sbuf) != nil)
63 			return 0;
64 	}
65 	return -1;
66 }
67 
68 int
69 finddevs(int (*matchf)(char*,void*), void *farg, char** dirs, int ndirs)
70 {
71 	int fd;
72 	char fbuf[40];
73 	char dbuf[512];
74 	Dir *d;
75 	int nd, nr;
76 	int n;
77 	int i;
78 	char *nm;
79 
80 	fd = open("/dev/usb", OREAD);
81 	if(fd < 0)
82 		sysfatal("/dev/usb: %r");
83 	nd = dirreadall(fd, &d);
84 	close(fd);
85 	if(nd < 2)
86 		sysfatal("/dev/usb: no devs");
87 	for(i = n = 0; i < nd && n < ndirs; i++){
88 		nm = d[i].name;
89 		if(strcmp(nm, "ctl") == 0 || strstr(nm, ".0") == nil)
90 			continue;
91 		snprint(fbuf, sizeof(fbuf), "/dev/usb/%s/ctl", nm);
92 		fd = open(fbuf, OREAD);
93 		if(fd < 0)
94 			continue;	/* may be gone */
95 		nr = read(fd, dbuf, sizeof(dbuf)-1);
96 		close(fd);
97 		if(nr < 0)
98 			continue;
99 		dbuf[nr] = 0;
100 		if(strstr(dbuf, "enabled ") != nil && strstr(dbuf, " busy") == nil)
101 			if(matchf(dbuf, farg) == 0)
102 				dirs[n++] = smprint("/dev/usb/%s", nm);
103 	}
104 	free(d);
105 	if(usbdebug > 1)
106 		for(nd = 0; nd < n; nd++)
107 			fprint(2, "finddevs: %s\n", dirs[nd]);
108 	return n;
109 }
110 
111 void
112 startdevs(char *args, char *argv[], int argc, int (*mf)(char*,void*), void*ma, int (*df)(Dev*,int,char**))
113 {
114 	int i, ndirs, ndevs;
115 	char *dirs[Ndevs];
116 	char **dp;
117 	Parg *parg;
118 	Dev *dev;
119 	Channel *rc;
120 
121 	if(access("/dev/usb", AEXIST) < 0 && bind("#u", "/dev", MBEFORE) < 0)
122 		sysfatal("#u: %r");
123 
124 	if(argc > 0){
125 		ndirs = argc;
126 		dp = argv;
127 	}else{
128 		dp = dirs;
129 		ndirs = finddevs(mf, ma, dp, Ndevs);
130 		if(ndirs == nelem(dirs))
131 			fprint(2, "%s: too many devices\n", argv0);
132 	}
133 	ndevs = 0;
134 	rc = chancreate(sizeof(ulong), 0);
135 	if(rc == nil)
136 		sysfatal("no memory");
137 	for(i = 0; i < ndirs; i++){
138 		fprint(2, "%s: startdevs: opening #%d %s\n", argv0, i, dp[i]);
139 		dev = opendev(dp[i]);
140 		if(dev != nil){
141 			if(configdev(dev) < 0){
142 				fprint(2, "%s: %s: config: %r\n", argv0, dp[i]);
143 				closedev(dev);
144 			}else{
145 				dprint(2, "%s: %U", argv0, dev);
146 				parg = emallocz(sizeof(Parg), 0);
147 				parg->args = estrdup(args);
148 				parg->dev = dev;
149 				parg->rc = rc;
150 				parg->f = df;
151 				proccreate(workproc, parg, Stack);
152 				if(recvul(rc) == 0)
153 					ndevs++;
154 			}
155 		}else
156 			fprint(2, "%s: %s: %r\n", argv0, dp[i]);
157 		if(dp != argv)
158 			free(dirs[i]);
159 	}
160 	chanfree(rc);
161 	if(ndevs == 0)
162 		sysfatal("no device found");
163 }
164