xref: /plan9/sys/src/cmd/usb/lib/dev.c (revision bfb6eab9346d861b5f68a2b1af55a1768a8fe25b)
1 #include <u.h>
2 #include <libc.h>
3 #include <thread.h>
4 #include "usb.h"
5 
6 /*
7  * epN.M -> N
8  */
9 static int
nameid(char * s)10 nameid(char *s)
11 {
12 	char *r;
13 	char nm[20];
14 
15 	r = strrchr(s, 'p');
16 	if(r == nil)
17 		return -1;
18 	strecpy(nm, nm+sizeof(nm), r+1);
19 	r = strchr(nm, '.');
20 	if(r == nil)
21 		return -1;
22 	*r = 0;
23 	return atoi(nm);
24 }
25 
26 Dev*
openep(Dev * d,int id)27 openep(Dev *d, int id)
28 {
29 	char *mode;	/* How many modes? */
30 	Ep *ep;
31 	Altc *ac;
32 	Dev *epd;
33 	Usbdev *ud;
34 	char name[40];
35 
36 	if(access("/dev/usb", AEXIST) < 0 && bind("#u", "/dev", MBEFORE) < 0)
37 		return nil;
38 	if(d->cfd < 0 || d->usb == nil){
39 		werrstr("device not configured");
40 		return nil;
41 	}
42 	ud = d->usb;
43 	if(id < 0 || id >= nelem(ud->ep) || ud->ep[id] == nil){
44 		werrstr("bad enpoint number");
45 		return nil;
46 	}
47 	ep = ud->ep[id];
48 	mode = "rw";
49 	if(ep->dir == Ein)
50 		mode = "r";
51 	if(ep->dir == Eout)
52 		mode = "w";
53 	snprint(name, sizeof(name), "/dev/usb/ep%d.%d", d->id, id);
54 	if(access(name, AEXIST) == 0){
55 		dprint(2, "%s: %s already exists; trying to open\n", argv0, name);
56 		epd = opendev(name);
57 		if(epd != nil)
58 			epd->maxpkt = ep->maxpkt;	/* guess */
59 		return epd;
60 	}
61 	if(devctl(d, "new %d %d %s", id, ep->type, mode) < 0){
62 		dprint(2, "%s: %s: new: %r\n", argv0, d->dir);
63 		return nil;
64 	}
65 	epd = opendev(name);
66 	if(epd == nil)
67 		return nil;
68 	epd->id = id;
69 	if(devctl(epd, "maxpkt %d", ep->maxpkt) < 0)
70 		fprint(2, "%s: %s: openep: maxpkt: %r\n", argv0, epd->dir);
71 	else
72 		dprint(2, "%s: %s: maxpkt %d\n", argv0, epd->dir, ep->maxpkt);
73 	epd->maxpkt = ep->maxpkt;
74 	ac = ep->iface->altc[0];
75 	if(ep->ntds > 1 && devctl(epd, "ntds %d", ep->ntds) < 0)
76 		fprint(2, "%s: %s: openep: ntds: %r\n", argv0, epd->dir);
77 	else
78 		dprint(2, "%s: %s: ntds %d\n", argv0, epd->dir, ep->ntds);
79 
80 	/*
81 	 * For iso endpoints and high speed interrupt endpoints the pollival is
82 	 * actually 2ⁿ and not n.
83 	 * The kernel usb driver must take that into account.
84 	 * It's simpler this way.
85 	 */
86 
87 	if(ac != nil && (ep->type == Eintr || ep->type == Eiso) && ac->interval != 0)
88 		if(devctl(epd, "pollival %d", ac->interval) < 0)
89 			fprint(2, "%s: %s: openep: pollival: %r\n", argv0, epd->dir);
90 	return epd;
91 }
92 
93 Dev*
opendev(char * fn)94 opendev(char *fn)
95 {
96 	Dev *d;
97 	int l;
98 
99 	if(access("/dev/usb", AEXIST) < 0 && bind("#u", "/dev", MBEFORE) < 0)
100 		return nil;
101 	d = emallocz(sizeof(Dev), 1);
102 	incref(d);
103 
104 	l = strlen(fn);
105 	d->dfd = -1;
106 	/*
107 	 * +30 to allocate extra size to concat "/<epfilename>"
108 	 * we should probably remove that feature from the manual
109 	 * and from the code after checking out that nobody relies on
110 	 * that.
111 	 */
112 	d->dir = emallocz(l + 30, 0);
113 	strcpy(d->dir, fn);
114 	strcpy(d->dir+l, "/ctl");
115 	d->cfd = open(d->dir, ORDWR|OCEXEC);
116 	d->dir[l] = 0;
117 	d->id = nameid(fn);
118 	if(d->cfd < 0){
119 		werrstr("can't open endpoint %s: %r", d->dir);
120 		free(d->dir);
121 		free(d);
122 		return nil;
123 	}
124 	dprint(2, "%s: opendev %#p %s\n", argv0, d, fn);
125 	return d;
126 }
127 
128 int
opendevdata(Dev * d,int mode)129 opendevdata(Dev *d, int mode)
130 {
131 	char buf[80]; /* more than enough for a usb path */
132 
133 	seprint(buf, buf+sizeof(buf), "%s/data", d->dir);
134 	d->dfd = open(buf, mode|OCEXEC);
135 	return d->dfd;
136 }
137 
138 enum
139 {
140 	/*
141 	 * Max device conf is also limited by max control request size as
142 	 * limited by Maxctllen in the kernel usb.h (both limits are arbitrary).
143 	 */
144 	Maxdevconf = 4 * 1024,	/* asking for 16K kills Newsham's disk */
145 };
146 
147 int
loaddevconf(Dev * d,int n)148 loaddevconf(Dev *d, int n)
149 {
150 	uchar *buf;
151 	int nr;
152 	int type;
153 
154 	if(n >= nelem(d->usb->conf)){
155 		werrstr("loaddevconf: bug: out of configurations in device");
156 		fprint(2, "%s: %r\n", argv0);
157 		return -1;
158 	}
159 	buf = emallocz(Maxdevconf, 0);
160 	type = Rd2h|Rstd|Rdev;
161 	nr = usbcmd(d, type, Rgetdesc, Dconf<<8|n, 0, buf, Maxdevconf);
162 	if(nr < Dconflen){
163 		free(buf);
164 		return -1;
165 	}
166 	if(d->usb->conf[n] == nil)
167 		d->usb->conf[n] = emallocz(sizeof(Conf), 1);
168 	nr = parseconf(d->usb, d->usb->conf[n], buf, nr);
169 	free(buf);
170 	return nr;
171 }
172 
173 Ep*
mkep(Usbdev * d,int id)174 mkep(Usbdev *d, int id)
175 {
176 	Ep *ep;
177 
178 	d->ep[id] = ep = emallocz(sizeof(Ep), 1);
179 	ep->id = id;
180 	return ep;
181 }
182 
183 static char*
mkstr(uchar * b,int n)184 mkstr(uchar *b, int n)
185 {
186 	Rune r;
187 	char *us;
188 	char *s;
189 	char *e;
190 
191 	if(n <= 2 || (n & 1) != 0)
192 		return strdup("none");
193 	n = (n - 2)/2;
194 	b += 2;
195 	us = s = emallocz(n*UTFmax+1, 0);
196 	e = s + n*UTFmax+1;
197 	for(; --n >= 0; b += 2){
198 		r = GET2(b);
199 		s = seprint(s, e, "%C", r);
200 	}
201 	return us;
202 }
203 
204 char*
loaddevstr(Dev * d,int sid)205 loaddevstr(Dev *d, int sid)
206 {
207 	uchar buf[128];
208 	int type;
209 	int nr;
210 
211 	if(sid == 0)
212 		return estrdup("none");
213 	type = Rd2h|Rstd|Rdev;
214 	nr=usbcmd(d, type, Rgetdesc, Dstr<<8|sid, 0, buf, sizeof(buf));
215 	return mkstr(buf, nr);
216 }
217 
218 int
loaddevdesc(Dev * d)219 loaddevdesc(Dev *d)
220 {
221 	uchar buf[Ddevlen+255];
222 	int nr;
223 	int type;
224 	Ep *ep0;
225 
226 	type = Rd2h|Rstd|Rdev;
227 	nr = sizeof(buf);
228 	memset(buf, 0, Ddevlen);
229 	if((nr=usbcmd(d, type, Rgetdesc, Ddev<<8|0, 0, buf, nr)) < 0)
230 		return -1;
231 	/*
232 	 * Several hubs are returning descriptors of 17 bytes, not 18.
233 	 * We accept them and leave number of configurations as zero.
234 	 * (a get configuration descriptor also fails for them!)
235 	 */
236 	if(nr < Ddevlen){
237 		print("%s: %s: warning: device with short descriptor\n",
238 			argv0, d->dir);
239 		if(nr < Ddevlen-1){
240 			werrstr("short device descriptor (%d bytes)", nr);
241 			return -1;
242 		}
243 	}
244 	d->usb = emallocz(sizeof(Usbdev), 1);
245 	ep0 = mkep(d->usb, 0);
246 	ep0->dir = Eboth;
247 	ep0->type = Econtrol;
248 	ep0->maxpkt = d->maxpkt = 8;		/* a default */
249 	nr = parsedev(d, buf, nr);
250 	if(nr >= 0){
251 		d->usb->vendor = loaddevstr(d, d->usb->vsid);
252 		if(strcmp(d->usb->vendor, "none") != 0){
253 			d->usb->product = loaddevstr(d, d->usb->psid);
254 			d->usb->serial = loaddevstr(d, d->usb->ssid);
255 		}
256 	}
257 	return nr;
258 }
259 
260 int
configdev(Dev * d)261 configdev(Dev *d)
262 {
263 	int i;
264 
265 	if(d->dfd < 0)
266 		opendevdata(d, ORDWR);
267 	if(loaddevdesc(d) < 0)
268 		return -1;
269 	for(i = 0; i < d->usb->nconf; i++)
270 		if(loaddevconf(d, i) < 0)
271 			return -1;
272 	return 0;
273 }
274 
275 static void
closeconf(Conf * c)276 closeconf(Conf *c)
277 {
278 	int i;
279 	int a;
280 
281 	if(c == nil)
282 		return;
283 	for(i = 0; i < nelem(c->iface); i++)
284 		if(c->iface[i] != nil){
285 			for(a = 0; a < nelem(c->iface[i]->altc); a++)
286 				free(c->iface[i]->altc[a]);
287 			free(c->iface[i]);
288 		}
289 	free(c);
290 }
291 
292 void
closedev(Dev * d)293 closedev(Dev *d)
294 {
295 	int i;
296 	Usbdev *ud;
297 
298 	if(d==nil || decref(d) != 0)
299 		return;
300 	dprint(2, "%s: closedev %#p %s\n", argv0, d, d->dir);
301 	if(d->free != nil)
302 		d->free(d->aux);
303 	if(d->cfd >= 0)
304 		close(d->cfd);
305 	if(d->dfd >= 0)
306 		close(d->dfd);
307 	d->cfd = d->dfd = -1;
308 	free(d->dir);
309 	d->dir = nil;
310 	ud = d->usb;
311 	d->usb = nil;
312 	if(ud != nil){
313 		free(ud->vendor);
314 		free(ud->product);
315 		free(ud->serial);
316 		for(i = 0; i < nelem(ud->ep); i++)
317 			free(ud->ep[i]);
318 		for(i = 0; i < nelem(ud->ddesc); i++)
319 			free(ud->ddesc[i]);
320 
321 		for(i = 0; i < nelem(ud->conf); i++)
322 			closeconf(ud->conf[i]);
323 		free(ud);
324 	}
325 	free(d);
326 }
327 
328 static char*
reqstr(int type,int req)329 reqstr(int type, int req)
330 {
331 	char *s;
332 	static char* ds[] = { "dev", "if", "ep", "oth" };
333 	static char buf[40];
334 
335 	if(type&Rd2h)
336 		s = seprint(buf, buf+sizeof(buf), "d2h");
337 	else
338 		s = seprint(buf, buf+sizeof(buf), "h2d");
339 	if(type&Rclass)
340 		s = seprint(s, buf+sizeof(buf), "|cls");
341 	else if(type&Rvendor)
342 		s = seprint(s, buf+sizeof(buf), "|vnd");
343 	else
344 		s = seprint(s, buf+sizeof(buf), "|std");
345 	s = seprint(s, buf+sizeof(buf), "|%s", ds[type&3]);
346 
347 	switch(req){
348 	case Rgetstatus: s = seprint(s, buf+sizeof(buf), " getsts"); break;
349 	case Rclearfeature: s = seprint(s, buf+sizeof(buf), " clrfeat"); break;
350 	case Rsetfeature: s = seprint(s, buf+sizeof(buf), " setfeat"); break;
351 	case Rsetaddress: s = seprint(s, buf+sizeof(buf), " setaddr"); break;
352 	case Rgetdesc: s = seprint(s, buf+sizeof(buf), " getdesc"); break;
353 	case Rsetdesc: s = seprint(s, buf+sizeof(buf), " setdesc"); break;
354 	case Rgetconf: s = seprint(s, buf+sizeof(buf), " getcnf"); break;
355 	case Rsetconf: s = seprint(s, buf+sizeof(buf), " setcnf"); break;
356 	case Rgetiface: s = seprint(s, buf+sizeof(buf), " getif"); break;
357 	case Rsetiface: s = seprint(s, buf+sizeof(buf), " setif"); break;
358 	}
359 	USED(s);
360 	return buf;
361 }
362 
363 static int
cmdreq(Dev * d,int type,int req,int value,int index,uchar * data,int count)364 cmdreq(Dev *d, int type, int req, int value, int index, uchar *data, int count)
365 {
366 	int ndata, n;
367 	uchar *wp;
368 	uchar buf[8];
369 	char *hd, *rs;
370 
371 	assert(d != nil);
372 	if(data == nil){
373 		wp = buf;
374 		ndata = 0;
375 	}else{
376 		ndata = count;
377 		wp = emallocz(8+ndata, 0);
378 	}
379 	wp[0] = type;
380 	wp[1] = req;
381 	PUT2(wp+2, value);
382 	PUT2(wp+4, index);
383 	PUT2(wp+6, count);
384 	if(data != nil)
385 		memmove(wp+8, data, ndata);
386 	if(usbdebug>2){
387 		hd = hexstr(wp, ndata+8);
388 		rs = reqstr(type, req);
389 		fprint(2, "%s: %s val %d|%d idx %d cnt %d out[%d] %s\n",
390 			d->dir, rs, value>>8, value&0xFF,
391 			index, count, ndata+8, hd);
392 		free(hd);
393 	}
394 	n = write(d->dfd, wp, 8+ndata);
395 	if(wp != buf)
396 		free(wp);
397 	if(n < 0)
398 		return -1;
399 	if(n != 8+ndata){
400 		dprint(2, "%s: cmd: short write: %d\n", argv0, n);
401 		return -1;
402 	}
403 	return n;
404 }
405 
406 static int
cmdrep(Dev * d,void * buf,int nb)407 cmdrep(Dev *d, void *buf, int nb)
408 {
409 	char *hd;
410 
411 	nb = read(d->dfd, buf, nb);
412 	if(nb >0 && usbdebug > 2){
413 		hd = hexstr(buf, nb);
414 		fprint(2, "%s: in[%d] %s\n", d->dir, nb, hd);
415 		free(hd);
416 	}
417 	return nb;
418 }
419 
420 int
usbcmd(Dev * d,int type,int req,int value,int index,uchar * data,int count)421 usbcmd(Dev *d, int type, int req, int value, int index, uchar *data, int count)
422 {
423 	int i, r, nerr;
424 	char err[64];
425 
426 	/*
427 	 * Some devices do not respond to commands some times.
428 	 * Others even report errors but later work just fine. Retry.
429 	 */
430 	r = -1;
431 	*err = 0;
432 	for(i = nerr = 0; i < Uctries; i++){
433 		if(type & Rd2h)
434 			r = cmdreq(d, type, req, value, index, nil, count);
435 		else
436 			r = cmdreq(d, type, req, value, index, data, count);
437 		if(r > 0){
438 			if((type & Rd2h) == 0)
439 				break;
440 			r = cmdrep(d, data, count);
441 			if(r > 0)
442 				break;
443 			if(r == 0)
444 				werrstr("no data from device");
445 		}
446 		nerr++;
447 		if(*err == 0)
448 			rerrstr(err, sizeof(err));
449 		sleep(Ucdelay);
450 	}
451 	if(r > 0 && i >= 2)
452 		/* let the user know the device is not in good shape */
453 		fprint(2, "%s: usbcmd: %s: required %d attempts (%s)\n",
454 			argv0, d->dir, i, err);
455 	return r;
456 }
457 
458 int
unstall(Dev * dev,Dev * ep,int dir)459 unstall(Dev *dev, Dev *ep, int dir)
460 {
461 	int r;
462 
463 	if(dir == Ein)
464 		dir = 0x80;
465 	else
466 		dir = 0;
467 	r = Rh2d|Rstd|Rep;
468 	if(usbcmd(dev, r, Rclearfeature, Fhalt, ep->id|dir, nil, 0)<0){
469 		werrstr("unstall: %s: %r", ep->dir);
470 		return -1;
471 	}
472 	if(devctl(ep, "clrhalt") < 0){
473 		werrstr("clrhalt: %s: %r", ep->dir);
474 		return -1;
475 	}
476 	return 0;
477 }
478 
479 /*
480  * To be sure it uses a single write.
481  */
482 int
devctl(Dev * dev,char * fmt,...)483 devctl(Dev *dev, char *fmt, ...)
484 {
485 	char buf[128];
486 	va_list arg;
487 	char *e;
488 
489 	va_start(arg, fmt);
490 	e = vseprint(buf, buf+sizeof(buf), fmt, arg);
491 	va_end(arg);
492 	return write(dev->cfd, buf, e-buf);
493 }
494