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