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