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