xref: /plan9/sys/src/cmd/usb/serial/serial.c (revision 3468a4915d661daa200976acc4f80f51aae144b2)
1 /*
2  * This part takes care of locking except for initialization and
3  * other threads created by the hw dep. drivers.
4  */
5 
6 #include <u.h>
7 #include <libc.h>
8 #include <ctype.h>
9 #include <thread.h>
10 #include "usb.h"
11 #include "usbfs.h"
12 #include "serial.h"
13 #include "prolific.h"
14 #include "ucons.h"
15 #include "ftdi.h"
16 
17 int serialdebug;
18 
19 enum {
20 	/* Qids. Maintain order (relative to dirtabs structs) */
21 	Qroot	= 0,
22 	Qctl,
23 	Qdata,
24 	Qmax,
25 };
26 
27 typedef struct Dirtab Dirtab;
28 struct Dirtab {
29 	char	*name;
30 	int	mode;
31 };
32 
33 static Dirtab dirtab[] = {
34 	[Qroot]	"/",		DMDIR|0555,
35 	[Qdata]	"eiaU",		0660,
36 	[Qctl]	"eiaUctl",	0664,
37 };
38 
39 static int sdebug;
40 
41 static void
42 serialfatal(Serial *ser)
43 {
44 	Serialport *p;
45 	int i;
46 
47 	dsprint(2, "serial: fatal error, detaching\n");
48 	devctl(ser->dev, "detach");
49 
50 	for(i = 0; i < ser->nifcs; i++){
51 		p = &ser->p[i];
52 		if(p->isjtag)
53 			continue;
54 		usbfsdel(&p->fs);
55 		if(p->w4data != nil)
56 			chanclose(p->w4data);
57 		if(p->gotdata != nil)
58 			chanclose(p->gotdata);
59 		if(p->readc)
60 			chanclose(p->readc);
61 	}
62 }
63 
64 /* I sleep with the lock... only way to drain in general */
65 static void
66 serialdrain(Serialport *p)
67 {
68 	Serial *ser;
69 	uint baud, pipesize;
70 
71 	ser = p->s;
72 	baud = p->baud;
73 
74 	if(p->baud == ~0)
75 		return;
76 	if(ser->maxwtrans < 256)
77 		pipesize = 256;
78 	else
79 		pipesize = ser->maxwtrans;
80 	/* wait for the at least 256-byte pipe to clear */
81 	sleep(10 + pipesize/((1 + baud)*1000));
82 	if(ser->clearpipes != nil)
83 		ser->clearpipes(p);
84 }
85 
86 /* BUG: separate reset per port */
87 int
88 serialreset(Serial *ser)
89 {
90 	Serialport *p;
91 	int i;
92 
93 	/* cmd for reset */
94 	for(i = 0; i < ser->nifcs; i++){
95 		p = &ser->p[i];
96 		if(p->isjtag)
97 			continue;
98 		serialdrain(p);
99 	}
100 	if(ser->reset != nil)
101 		ser->reset(ser);
102 	return 0;
103 }
104 
105 /* call this if something goes wrong */
106 int
107 serialrecover(Serial *ser, char *err)
108 {
109 	if(strstr(err, "detached") != nil)
110 		return -1;
111 	if(ser->recover > 1)
112 		serialfatal(ser);
113 	ser->recover++;
114 	if(serialreset(ser) < 0)
115 		return -1;
116 	ser->recover = 0;
117 	return 0;
118 }
119 
120 static int
121 serialctl(Serialport *p, char *cmd)
122 {
123 	Serial *ser;
124 	int c, i, n, nf, nop, nw, par, drain, set, lines;
125 	char *f[16];
126 	uchar x;
127 
128 	ser = p->s;
129 	drain = set = lines = 0;
130 	nf = tokenize(cmd, f, nelem(f));
131 	for(i = 0; i < nf; i++){
132 		if(strncmp(f[i], "break", 5) == 0){
133 			if(ser->setbreak != nil)
134 				ser->setbreak(p, 1);
135 			continue;
136 		}
137 
138 		nop = 0;
139 		n = atoi(f[i]+1);
140 		c = *f[i];
141 		if (isascii(c) && isupper(c))
142 			c = tolower(c);
143 		switch(c){
144 		case 'b':
145 			drain++;
146 			p->baud = n;
147 			set++;
148 			break;
149 		case 'c':
150 			p->dcd = n;
151 			// lines++;
152 			++nop;
153 			break;
154 		case 'd':
155 			p->dtr = n;
156 			lines++;
157 			break;
158 		case 'e':
159 			p->dsr = n;
160 			// lines++;
161 			++nop;
162 			break;
163 		case 'f':		/* flush the pipes */
164 			drain++;
165 			break;
166 		case 'h':		/* hangup?? */
167 			p->rts = p->dtr = 0;
168 			lines++;
169 			fprint(2, "serial: %c, unsure ctl\n", c);
170 			break;
171 		case 'i':
172 			++nop;
173 			break;
174 		case 'k':
175 			drain++;
176 			ser->setbreak(p, 1);
177 			sleep(n);
178 			ser->setbreak(p, 0);
179 			break;
180 		case 'l':
181 			drain++;
182 			p->bits = n;
183 			set++;
184 			break;
185 		case 'm':
186 			drain++;
187 			if(ser->modemctl != nil)
188 				ser->modemctl(p, n);
189 			if(n == 0)
190 				p->cts = 0;
191 			break;
192 		case 'n':
193 			p->blocked = n;
194 			++nop;
195 			break;
196 		case 'p':		/* extended... */
197 			if(strlen(f[i]) != 2)
198 				return -1;
199 			drain++;
200 			par = f[i][1];
201 			if(par == 'n')
202 				p->parity = 0;
203 			else if(par == 'o')
204 				p->parity = 1;
205 			else if(par == 'e')
206 				p->parity = 2;
207 			else if(par == 'm')	/* mark parity */
208 				p->parity = 3;
209 			else if(par == 's')	/* space parity */
210 				p->parity = 4;
211 			else
212 				return -1;
213 			set++;
214 			break;
215 		case 'q':
216 			// drain++;
217 			p->limit = n;
218 			++nop;
219 			break;
220 		case 'r':
221 			drain++;
222 			p->rts = n;
223 			lines++;
224 			break;
225 		case 's':
226 			drain++;
227 			p->stop = n;
228 			set++;
229 			break;
230 		case 'w':
231 			/* ?? how do I put this */
232 			p->timer = n * 100000LL;
233 			++nop;
234 			break;
235 		case 'x':
236 			if(n == 0)
237 				x = CTLS;
238 			else
239 				x = CTLQ;
240 			if(ser->wait4write != nil)
241 				nw = ser->wait4write(p, &x, 1);
242 			else
243 				nw = write(p->epout->dfd, &x, 1);
244 			if(nw != 1){
245 				serialrecover(ser, "");
246 				return -1;
247 			}
248 			break;
249 		}
250 		/*
251 		 * don't print.  the condition is harmless and the print
252 		 * splatters all over the display.
253 		 */
254 		USED(nop);
255 		if (0 && nop)
256 			fprint(2, "serial: %c, unsupported nop ctl\n", c);
257 	}
258 	if(drain)
259 		serialdrain(p);
260 	if(lines && !set){
261 		if(ser->sendlines != nil && ser->sendlines(p) < 0)
262 			return -1;
263 	} else if(set){
264 		if(ser->setparam != nil && ser->setparam(p) < 0)
265 			return -1;
266 	}
267 	return 0;
268 }
269 
270 char *pformat = "noems";
271 
272 char *
273 serdumpst(Serialport *p, char *buf, int bufsz)
274 {
275 	char *e, *s;
276 	Serial *ser;
277 
278 	ser = p->s;
279 
280 	e = buf + bufsz;
281 	s = seprint(buf, e, "b%d ", p->baud);
282 	s = seprint(s, e, "c%d ", p->dcd);	/* unimplemented */
283 	s = seprint(s, e, "d%d ", p->dtr);
284 	s = seprint(s, e, "e%d ", p->dsr);	/* unimplemented */
285 	s = seprint(s, e, "l%d ", p->bits);
286 	s = seprint(s, e, "m%d ", p->mctl);
287 	if(p->parity >= 0 || p->parity < strlen(pformat))
288 		s = seprint(s, e, "p%c ", pformat[p->parity]);
289 	else
290 		s = seprint(s, e, "p%c ", '?');
291 	s = seprint(s, e, "r%d ", p->rts);
292 	s = seprint(s, e, "s%d ", p->stop);
293 	s = seprint(s, e, "i%d ", p->fifo);
294 	s = seprint(s, e, "\ndev(%d) ", 0);
295 	s = seprint(s, e, "type(%d)  ", ser->type);
296 	s = seprint(s, e, "framing(%d) ", p->nframeerr);
297 	s = seprint(s, e, "overruns(%d) ", p->novererr);
298 	s = seprint(s, e, "berr(%d) ", p->nbreakerr);
299 	s = seprint(s, e, " serr(%d)\n", p->nparityerr);
300 	return s;
301 }
302 
303 static int
304 serinit(Serialport *p)
305 {
306 	int res;
307 	res = 0;
308 	Serial *ser;
309 
310 	ser = p->s;
311 
312 	if(ser->init != nil)
313 		res = ser->init(p);
314 	if(ser->getparam != nil)
315 		ser->getparam(p);
316 	p->nframeerr = p->nparityerr = p->nbreakerr = p->novererr = 0;
317 
318 	return res;
319 }
320 
321 static int
322 dwalk(Usbfs *fs, Fid *fid, char *name)
323 {
324 	int i;
325 	char *dname;
326 	Qid qid;
327 	Serialport *p;
328 
329 	qid = fid->qid;
330 	if((qid.type & QTDIR) == 0){
331 		werrstr("walk in non-directory");
332 		return -1;
333 	}
334 
335 	if(strcmp(name, "..") == 0){
336 		/* must be /eiaU%d; i.e. our root dir. */
337 		fid->qid.path = Qroot | fs->qid;
338 		fid->qid.vers = 0;
339 		fid->qid.type = QTDIR;
340 		return 0;
341 	}
342 
343 	p = fs->aux;
344 	for(i = 1; i < nelem(dirtab); i++){
345 		dname = smprint(dirtab[i].name, p->fs.name);
346 		if(strcmp(name, dname) == 0){
347 			qid.path = i | fs->qid;
348 			qid.vers = 0;
349 			qid.type = dirtab[i].mode >> 24;
350 			fid->qid = qid;
351 			free(dname);
352 			return 0;
353 		} else
354 			free(dname);
355 	}
356 	werrstr(Enotfound);
357 	return -1;
358 }
359 
360 static void
361 dostat(Usbfs *fs, int path, Dir *d)
362 {
363 	Dirtab *t;
364 	Serialport *p;
365 
366 	t = &dirtab[path];
367 	d->qid.path = path;
368 	d->qid.type = t->mode >> 24;
369 	d->mode = t->mode;
370 	p = fs->aux;
371 
372 	if(strcmp(t->name, "/") == 0)
373 		d->name = t->name;
374 	else
375 		snprint(d->name, Namesz, t->name, p->fs.name);
376 	d->length = 0;
377 }
378 
379 static int
380 dstat(Usbfs *fs, Qid qid, Dir *d)
381 {
382 	int path;
383 
384 	path = qid.path & ~fs->qid;
385 	dostat(fs, path, d);
386 	d->qid.path |= fs->qid;
387 	return 0;
388 }
389 
390 static int
391 dopen(Usbfs *fs, Fid *fid, int)
392 {
393 	ulong path;
394 	Serialport *p;
395 
396 	path = fid->qid.path & ~fs->qid;
397 	p = fs->aux;
398 	switch(path){		/* BUG: unneeded? */
399 	case Qdata:
400 		dsprint(2, "serial, opened data\n");
401 		break;
402 	case Qctl:
403 		dsprint(2, "serial, opened ctl\n");
404 		serialctl(p, "l8 i1");	/* default line parameters */
405 		break;
406 	}
407 	return 0;
408 }
409 
410 
411 static void
412 filldir(Usbfs *fs, Dir *d, Dirtab *tab, int i)
413 {
414 	d->qid.path = i | fs->qid;
415 	d->mode = tab->mode;
416 	if((d->mode & DMDIR) != 0)
417 		d->qid.type = QTDIR;
418 	else
419 		d->qid.type = QTFILE;
420 	d->name = tab->name;
421 }
422 
423 static int
424 dirgen(Usbfs *fs, Qid, int i, Dir *d, void *)
425 {
426 	i++;				/* skip root */
427 	if(i >= nelem(dirtab))
428 		return -1;
429 	filldir(fs, d, &dirtab[i], i);
430 	return 0;
431 }
432 
433 enum {
434 	Serbufsize	= 255,
435 };
436 
437 static long
438 dread(Usbfs *fs, Fid *fid, void *data, long count, vlong offset)
439 {
440 	int dfd;
441 	long rcount;
442 	ulong path;
443 	char *e, *buf, *err;	/* change */
444 	Qid q;
445 	Serialport *p;
446 	Serial *ser;
447 	static int errrun, good;
448 
449 	q = fid->qid;
450 	path = fid->qid.path & ~fs->qid;
451 	p = fs->aux;
452 	ser = p->s;
453 
454 	buf = emallocz(Serbufsize, 1);
455 	err = emallocz(Serbufsize, 1);
456 	qlock(ser);
457 	switch(path){
458 	case Qroot:
459 		count = usbdirread(fs, q, data, count, offset, dirgen, nil);
460 		break;
461 	case Qdata:
462 		if(count > ser->maxread)
463 			count = ser->maxread;
464 		dsprint(2, "serial: reading from data\n");
465 		do {
466 			err[0] = 0;
467 			dfd = p->epin->dfd;
468 			if(usbdebug >= 3)
469 				dsprint(2, "serial: reading: %ld\n", count);
470 
471 			assert(count > 0);
472 			if(ser->wait4data != nil)
473 				rcount = ser->wait4data(p, data, count);
474 			else{
475 				qunlock(ser);
476 				rcount = read(dfd, data, count);
477 				qlock(ser);
478 			}
479 			/*
480 			 * if we encounter a long run of continuous read
481 			 * errors, do something drastic so that our caller
482 			 * doesn't just spin its wheels forever.
483 			 */
484 			if(rcount < 0) {
485 				snprint(err, Serbufsize, "%r");
486 				++errrun;
487 				sleep(20);
488 				if (good > 0 && errrun > 10000) {
489 					/* the line has been dropped; give up */
490 					qunlock(ser);
491 					fprint(2, "%s: line %s is gone: %r\n",
492 						argv0, p->fs.name);
493 					threadexitsall("serial line gone");
494 				}
495 			} else {
496 				errrun = 0;
497 				good++;
498 			}
499 			if(usbdebug >= 3)
500 				dsprint(2, "serial: read: %s %ld\n", err, rcount);
501 		} while(rcount < 0 && strstr(err, "timed out") != nil);
502 
503 		dsprint(2, "serial: read from bulk %ld, %10.10s\n", rcount, err);
504 		if(rcount < 0){
505 			dsprint(2, "serial: need to recover, data read %ld %r\n",
506 				count);
507 			serialrecover(ser, err);
508 		}
509 		dsprint(2, "serial: read from bulk %ld\n", rcount);
510 		count = rcount;
511 		break;
512 	case Qctl:
513 		if(offset != 0)
514 			count = 0;
515 		else {
516 			e = serdumpst(p, buf, Serbufsize);
517 			count = usbreadbuf(data, count, 0, buf, e - buf);
518 		}
519 		break;
520 	}
521 	qunlock(ser);
522 	free(err);
523 	free(buf);
524 	return count;
525 }
526 
527 static long
528 altwrite(Serialport *p, uchar *buf, long count)
529 {
530 	int nw, dfd;
531 	char err[128];
532 	Serial *ser;
533 
534 	ser = p->s;
535 	do{
536 		if(ser->wait4write != nil)
537 			/* unlocked inside later */
538 			nw = ser->wait4write(p, buf, count);
539 		else{
540 			dfd = p->epout->dfd;
541 			qunlock(ser);
542 			nw = write(dfd, buf, count);
543 			qlock(ser);
544 		}
545 		rerrstr(err, sizeof err);
546 	} while(nw < 0 && strstr(err, "timed out") != nil);
547 
548 	if(nw != count){
549 		dsprint(2, "serial: need to recover, status in write %d %r\n",
550 			nw);
551 		snprint(err, sizeof err, "%r");
552 		serialrecover(p->s, err);
553 	}
554 	return nw;
555 }
556 
557 static long
558 dwrite(Usbfs *fs, Fid *fid, void *buf, long count, vlong)
559 {
560 	ulong path;
561 	char *cmd;
562 	Serialport *p;
563 	Serial *ser;
564 
565 	p = fs->aux;
566 	ser = p->s;
567 	path = fid->qid.path & ~fs->qid;
568 
569 	qlock(ser);
570 	switch(path){
571 	case Qdata:
572 		count = altwrite(p, (uchar *)buf, count);
573 		break;
574 	case Qctl:
575 		cmd = emallocz(count+1, 1);
576 		memmove(cmd, buf, count);
577 		cmd[count] = 0;
578 		if(serialctl(p, cmd) < 0){
579 			qunlock(ser);
580 			werrstr(Ebadctl);
581 			free(cmd);
582 			return -1;
583 		}
584 		free(cmd);
585 		break;
586 	default:
587 		qunlock(ser);
588 		werrstr(Eperm);
589 		return -1;
590 	}
591 	qunlock(ser);
592 	return count;
593 }
594 
595 static int
596 openeps(Serialport *p, int epin, int epout, int epintr)
597 {
598 	Serial *ser;
599 
600 	ser = p->s;
601 	p->epin = openep(ser->dev, epin);
602 	if(p->epin == nil){
603 		fprint(2, "serial: openep %d: %r\n", epin);
604 		return -1;
605 	}
606 	p->epout = openep(ser->dev, epout);
607 	if(p->epout == nil){
608 		fprint(2, "serial: openep %d: %r\n", epout);
609 		closedev(p->epin);
610 		return -1;
611 	}
612 
613 	devctl(p->epin,  "timeout 1000");
614 	devctl(p->epout, "timeout 1000");
615 
616 	if(ser->hasepintr){
617 		p->epintr = openep(ser->dev, epintr);
618 		if(p->epintr == nil){
619 			fprint(2, "serial: openep %d: %r\n", epintr);
620 			closedev(p->epin);
621 			closedev(p->epout);
622 			return -1;
623 		}
624 		opendevdata(p->epintr, OREAD);
625 		devctl(p->epintr, "timeout 1000");
626 	}
627 
628 	if(ser->seteps!= nil)
629 		ser->seteps(p);
630 	opendevdata(p->epin, OREAD);
631 	opendevdata(p->epout, OWRITE);
632 	if(p->epin->dfd < 0 ||p->epout->dfd < 0 ||
633 	    (ser->hasepintr && p->epintr->dfd < 0)){
634 		fprint(2, "serial: open i/o ep data: %r\n");
635 		closedev(p->epin);
636 		closedev(p->epout);
637 		if(ser->hasepintr)
638 			closedev(p->epintr);
639 		return -1;
640 	}
641 	return 0;
642 }
643 
644 static int
645 findendpoints(Serial *ser, int ifc)
646 {
647 	int i, epin, epout, epintr;
648 	Ep *ep, **eps;
649 	///Usbdev *ud;
650 
651 	epintr = epin = epout = -1;
652 	//ud = ser->dev->usb;
653 
654 	/*
655 	 * interfc 0 means start from the start which is equiv to
656 	 * iterate through endpoints probably, could be done better
657 	 */
658 	eps = ser->dev->usb->conf[0]->iface[ifc]->ep;
659 
660 	for(i = 0; i < Niface; i++){
661 		if((ep = eps[i]) == nil)
662 			continue;
663 		if(ser->hasepintr && ep->type == Eintr &&
664 		    ep->dir == Ein && epintr == -1)
665 			epintr = ep->id;
666 		if(ep->type == Ebulk){
667 			if(ep->dir == Ein && epin == -1)
668 				epin = ep->id;
669 			if(ep->dir == Eout && epout == -1)
670 				epout = ep->id;
671 		}
672 	}
673 	dprint(2, "serial[%d]: ep ids: in %d out %d intr %d\n", ifc, epin, epout, epintr);
674 	if(epin == -1 || epout == -1 || (ser->hasepintr && epintr == -1))
675 		return -1;
676 
677 	if(openeps(&ser->p[ifc], epin, epout, epintr) < 0)
678 		return -1;
679 
680 	dprint(2, "serial: ep in %s out %s\n", ser->p[ifc].epin->dir, ser->p[ifc].epout->dir);
681 	if(ser->hasepintr)
682 		dprint(2, "serial: ep intr %s\n", ser->p[ifc].epintr->dir);
683 
684 	if(usbdebug > 1 || serialdebug > 2){
685 		devctl(ser->p[ifc].epin,  "debug 1");
686 		devctl(ser->p[ifc].epout, "debug 1");
687 		if(ser->hasepintr)
688 			devctl(ser->p[ifc].epintr, "debug 1");
689 		devctl(ser->dev, "debug 1");
690 	}
691 	return 0;
692 }
693 
694 /* keep in sync with main.c */
695 static int
696 usage(void)
697 {
698 	werrstr("usage: usb/serial [-dD] [-m mtpt] [-s srv]");
699 	return -1;
700 }
701 
702 static void
703 serdevfree(void *a)
704 {
705 	Serial *ser = a;
706 	Serialport *p;
707 	int i;
708 
709 	if(ser == nil)
710 		return;
711 
712 	for(i = 0; i < ser->nifcs; i++){
713 		p = &ser->p[i];
714 
715 		if(ser->hasepintr)
716 			closedev(p->epintr);
717 		closedev(p->epin);
718 		closedev(p->epout);
719 		p->epintr = p->epin = p->epout = nil;
720 		if(p->w4data != nil)
721 			chanfree(p->w4data);
722 		if(p->gotdata != nil)
723 			chanfree(p->gotdata);
724 		if(p->readc)
725 			chanfree(p->readc);
726 
727 	}
728 	free(ser);
729 }
730 
731 static Usbfs serialfs = {
732 	.walk =	dwalk,
733 	.open =	dopen,
734 	.read =	dread,
735 	.write=	dwrite,
736 	.stat =	dstat,
737 };
738 
739 static void
740 serialfsend(Usbfs *fs)
741 {
742 	Serialport *p;
743 
744 	p = fs->aux;
745 
746 	if(p->w4data != nil)
747 		chanclose(p->w4data);
748 	if(p->gotdata != nil)
749 		chanclose(p->gotdata);
750 	if(p->readc)
751 		chanclose(p->readc);
752 }
753 
754 int
755 serialmain(Dev *dev, int argc, char* argv[])
756 {
757 	Serial *ser;
758 	Serialport *p;
759 	char buf[50];
760 	int i, devid;
761 
762 	devid = dev->id;
763 	ARGBEGIN{
764 	case 'd':
765 		serialdebug++;
766 		break;
767 	case 'N':
768 		devid = atoi(EARGF(usage()));
769 		break;
770 	default:
771 		return usage();
772 	}ARGEND
773 	if(argc != 0)
774 		return usage();
775 
776 	ser = dev->aux = emallocz(sizeof(Serial), 1);
777 	ser->maxrtrans = ser->maxwtrans = sizeof ser->p[0].data;
778 	ser->maxread = ser->maxwrite = sizeof ser->p[0].data;
779 	ser->dev = dev;
780 	dev->free = serdevfree;
781 	ser->jtag = -1;
782 	ser->nifcs = 1;
783 
784 	snprint(buf, sizeof buf, "vid %#06x did %#06x",
785 		dev->usb->vid, dev->usb->did);
786 	if(plmatch(buf) == 0){
787 		ser->hasepintr = 1;
788 		ser->Serialops = plops;
789 	} else if(uconsmatch(buf) == 0)
790 		ser->Serialops = uconsops;
791 	else if(ftmatch(ser, buf) == 0)
792 		ser->Serialops = ftops;
793 	else {
794 		werrstr("serial: no serial devices found");
795 		return -1;
796 	}
797 
798 	for(i = 0; i < ser->nifcs; i++){
799 		p = &ser->p[i];
800 		p->interfc = i;
801 		if(i == ser->jtag){
802 			p->isjtag++;
803 			continue;
804 		}
805 		p->s = ser;
806 		p->fs = serialfs;
807 		if(findendpoints(ser, i) < 0){
808 			werrstr("serial: no endpoints found for ifc %d", i);
809 			return -1;
810 		}
811 		p->w4data  = chancreate(sizeof(ulong), 0);
812 		p->gotdata = chancreate(sizeof(ulong), 0);
813 	}
814 
815 	qlock(ser);
816 	serialreset(ser);
817 	for(i = 0; i < ser->nifcs; i++){
818 		p = &ser->p[i];
819 		if(p->isjtag){
820 			dsprint(2, "serial: ignoring JTAG interface %d %p\n", i, p);
821 			continue;
822 		}
823 		dprint(2, "serial: valid interface, calling serinit\n");
824 		if(serinit(p) < 0){
825 			dprint(2, "serial: serinit: %r\n");
826 			return -1;
827 		}
828 
829 		dsprint(2, "serial: adding interface %d, %p\n", p->interfc, p);
830 		if(i == 0)
831 			snprint(p->fs.name, sizeof p->fs.name, "eiaU%d", devid);
832 		else
833 			snprint(p->fs.name, sizeof p->fs.name, "eiaU%d.%d", devid, i);
834 		fprint(2, "%s\n", p->fs.name);
835 		p->fs.dev = dev;
836 		incref(dev);
837 		p->fs.aux = p;
838 		p->fs.end = serialfsend;
839 		usbfsadd(&p->fs);
840 	}
841 
842 	qunlock(ser);
843 	return 0;
844 }
845