1b2495906SDavid du Colombier /*
2b2495906SDavid du Colombier * This part takes care of locking except for initialization and
3b2495906SDavid du Colombier * other threads created by the hw dep. drivers.
4b2495906SDavid du Colombier */
5b2495906SDavid du Colombier
65e4f5c78SDavid du Colombier #include <u.h>
75e4f5c78SDavid du Colombier #include <libc.h>
85e4f5c78SDavid du Colombier #include <ctype.h>
95e4f5c78SDavid du Colombier #include <thread.h>
105e4f5c78SDavid du Colombier #include "usb.h"
115e4f5c78SDavid du Colombier #include "usbfs.h"
125e4f5c78SDavid du Colombier #include "serial.h"
134d52e0f0SDavid du Colombier #include "prolific.h"
144d52e0f0SDavid du Colombier #include "ucons.h"
1580e9508eSDavid du Colombier #include "ftdi.h"
169b7bf7dfSDavid du Colombier #include "silabs.h"
174d52e0f0SDavid du Colombier
185e4f5c78SDavid du Colombier int serialdebug;
195e4f5c78SDavid du Colombier
205e4f5c78SDavid du Colombier enum {
215e4f5c78SDavid du Colombier /* Qids. Maintain order (relative to dirtabs structs) */
225e4f5c78SDavid du Colombier Qroot = 0,
235e4f5c78SDavid du Colombier Qctl,
245e4f5c78SDavid du Colombier Qdata,
255e4f5c78SDavid du Colombier Qmax,
265e4f5c78SDavid du Colombier };
275e4f5c78SDavid du Colombier
285e4f5c78SDavid du Colombier typedef struct Dirtab Dirtab;
295e4f5c78SDavid du Colombier struct Dirtab {
305e4f5c78SDavid du Colombier char *name;
315e4f5c78SDavid du Colombier int mode;
325e4f5c78SDavid du Colombier };
335e4f5c78SDavid du Colombier
345e4f5c78SDavid du Colombier static Dirtab dirtab[] = {
355e4f5c78SDavid du Colombier [Qroot] "/", DMDIR|0555,
36d584e620SDavid du Colombier [Qdata] "%s", 0660,
37d584e620SDavid du Colombier [Qctl] "%sctl", 0664,
385e4f5c78SDavid du Colombier };
395e4f5c78SDavid du Colombier
405e4f5c78SDavid du Colombier static int sdebug;
415e4f5c78SDavid du Colombier
425e4f5c78SDavid du Colombier static void
serialfatal(Serial * ser)435e4f5c78SDavid du Colombier serialfatal(Serial *ser)
445e4f5c78SDavid du Colombier {
45d5789509SDavid du Colombier Serialport *p;
46d5789509SDavid du Colombier int i;
47d5789509SDavid du Colombier
485e4f5c78SDavid du Colombier dsprint(2, "serial: fatal error, detaching\n");
495e4f5c78SDavid du Colombier devctl(ser->dev, "detach");
50d5789509SDavid du Colombier
51d5789509SDavid du Colombier for(i = 0; i < ser->nifcs; i++){
52d5789509SDavid du Colombier p = &ser->p[i];
53d5789509SDavid du Colombier usbfsdel(&p->fs);
54d5789509SDavid du Colombier if(p->w4data != nil)
55d5789509SDavid du Colombier chanclose(p->w4data);
56d5789509SDavid du Colombier if(p->gotdata != nil)
57d5789509SDavid du Colombier chanclose(p->gotdata);
58d5789509SDavid du Colombier if(p->readc)
59d5789509SDavid du Colombier chanclose(p->readc);
60d5789509SDavid du Colombier }
615e4f5c78SDavid du Colombier }
625e4f5c78SDavid du Colombier
6380e9508eSDavid du Colombier /* I sleep with the lock... only way to drain in general */
645e4f5c78SDavid du Colombier static void
serialdrain(Serialport * p)65d5789509SDavid du Colombier serialdrain(Serialport *p)
665e4f5c78SDavid du Colombier {
67d5789509SDavid du Colombier Serial *ser;
6880e9508eSDavid du Colombier uint baud, pipesize;
695e4f5c78SDavid du Colombier
70d5789509SDavid du Colombier ser = p->s;
71d5789509SDavid du Colombier baud = p->baud;
72d5789509SDavid du Colombier
73d5789509SDavid du Colombier if(p->baud == ~0)
74d5789509SDavid du Colombier return;
75d5789509SDavid du Colombier if(ser->maxwtrans < 256)
7680e9508eSDavid du Colombier pipesize = 256;
7780e9508eSDavid du Colombier else
78d5789509SDavid du Colombier pipesize = ser->maxwtrans;
7980e9508eSDavid du Colombier /* wait for the at least 256-byte pipe to clear */
8080e9508eSDavid du Colombier sleep(10 + pipesize/((1 + baud)*1000));
8180e9508eSDavid du Colombier if(ser->clearpipes != nil)
82d5789509SDavid du Colombier ser->clearpipes(p);
835e4f5c78SDavid du Colombier }
845e4f5c78SDavid du Colombier
855e4f5c78SDavid du Colombier int
serialreset(Serial * ser)865e4f5c78SDavid du Colombier serialreset(Serial *ser)
875e4f5c78SDavid du Colombier {
88d5789509SDavid du Colombier Serialport *p;
89c8a340cdSDavid du Colombier int i, res;
90d5789509SDavid du Colombier
91c8a340cdSDavid du Colombier res = 0;
925e4f5c78SDavid du Colombier /* cmd for reset */
93d5789509SDavid du Colombier for(i = 0; i < ser->nifcs; i++){
94d5789509SDavid du Colombier p = &ser->p[i];
95d5789509SDavid du Colombier serialdrain(p);
96d5789509SDavid du Colombier }
9780e9508eSDavid du Colombier if(ser->reset != nil)
98c8a340cdSDavid du Colombier res = ser->reset(ser, nil);
99c8a340cdSDavid du Colombier return res;
1005e4f5c78SDavid du Colombier }
1015e4f5c78SDavid du Colombier
102c8a340cdSDavid du Colombier /* call this if something goes wrong, must be qlocked */
1035e4f5c78SDavid du Colombier int
serialrecover(Serial * ser,Serialport * p,Dev * ep,char * err)104c8a340cdSDavid du Colombier serialrecover(Serial *ser, Serialport *p, Dev *ep, char *err)
1055e4f5c78SDavid du Colombier {
106c8a340cdSDavid du Colombier if(p != nil)
107c8a340cdSDavid du Colombier dprint(2, "serial[%d], %s: %s, level %d\n", p->interfc,
108c8a340cdSDavid du Colombier p->name, err, ser->recover);
109c8a340cdSDavid du Colombier else
110c8a340cdSDavid du Colombier dprint(2, "serial[%s], global error, level %d\n",
111c8a340cdSDavid du Colombier ser->p[0].name, ser->recover);
112c8a340cdSDavid du Colombier ser->recover++;
1135e4f5c78SDavid du Colombier if(strstr(err, "detached") != nil)
1145e4f5c78SDavid du Colombier return -1;
115c8a340cdSDavid du Colombier if(ser->recover < 3){
11684860c5dSDavid du Colombier if(p != nil){
117c8a340cdSDavid du Colombier if(ep != nil){
11884860c5dSDavid du Colombier if(ep == p->epintr)
119c8a340cdSDavid du Colombier unstall(ser->dev, p->epintr, Ein);
12084860c5dSDavid du Colombier if(ep == p->epin)
121c8a340cdSDavid du Colombier unstall(ser->dev, p->epin, Ein);
12284860c5dSDavid du Colombier if(ep == p->epout)
123c8a340cdSDavid du Colombier unstall(ser->dev, p->epout, Eout);
124c8a340cdSDavid du Colombier return 0;
125c8a340cdSDavid du Colombier }
12684860c5dSDavid du Colombier
127c8a340cdSDavid du Colombier if(p->epintr != nil)
128c8a340cdSDavid du Colombier unstall(ser->dev, p->epintr, Ein);
129c8a340cdSDavid du Colombier if(p->epin != nil)
130c8a340cdSDavid du Colombier unstall(ser->dev, p->epin, Ein);
131c8a340cdSDavid du Colombier if(p->epout != nil)
132c8a340cdSDavid du Colombier unstall(ser->dev, p->epout, Eout);
133c8a340cdSDavid du Colombier }
134c8a340cdSDavid du Colombier return 0;
135c8a340cdSDavid du Colombier }
136c8a340cdSDavid du Colombier if(ser->recover > 4 && ser->recover < 8)
1375e4f5c78SDavid du Colombier serialfatal(ser);
138c8a340cdSDavid du Colombier if(ser->recover > 8){
139c8a340cdSDavid du Colombier ser->reset(ser, p);
140c8a340cdSDavid du Colombier return 0;
141c8a340cdSDavid du Colombier }
1425e4f5c78SDavid du Colombier if(serialreset(ser) < 0)
1435e4f5c78SDavid du Colombier return -1;
1445e4f5c78SDavid du Colombier return 0;
1455e4f5c78SDavid du Colombier }
1465e4f5c78SDavid du Colombier
1475e4f5c78SDavid du Colombier static int
serialctl(Serialport * p,char * cmd)148d5789509SDavid du Colombier serialctl(Serialport *p, char *cmd)
1495e4f5c78SDavid du Colombier {
150d5789509SDavid du Colombier Serial *ser;
1515e4f5c78SDavid du Colombier int c, i, n, nf, nop, nw, par, drain, set, lines;
1525e4f5c78SDavid du Colombier char *f[16];
1535e4f5c78SDavid du Colombier uchar x;
1545e4f5c78SDavid du Colombier
155d5789509SDavid du Colombier ser = p->s;
1565e4f5c78SDavid du Colombier drain = set = lines = 0;
1575e4f5c78SDavid du Colombier nf = tokenize(cmd, f, nelem(f));
1585e4f5c78SDavid du Colombier for(i = 0; i < nf; i++){
1595e4f5c78SDavid du Colombier if(strncmp(f[i], "break", 5) == 0){
160d5789509SDavid du Colombier if(ser->setbreak != nil)
161d5789509SDavid du Colombier ser->setbreak(p, 1);
1625e4f5c78SDavid du Colombier continue;
1635e4f5c78SDavid du Colombier }
1645e4f5c78SDavid du Colombier
1655e4f5c78SDavid du Colombier nop = 0;
1665e4f5c78SDavid du Colombier n = atoi(f[i]+1);
1675e4f5c78SDavid du Colombier c = *f[i];
1685e4f5c78SDavid du Colombier if (isascii(c) && isupper(c))
1695e4f5c78SDavid du Colombier c = tolower(c);
1705e4f5c78SDavid du Colombier switch(c){
1715e4f5c78SDavid du Colombier case 'b':
1725e4f5c78SDavid du Colombier drain++;
1735e4f5c78SDavid du Colombier p->baud = n;
1745e4f5c78SDavid du Colombier set++;
1755e4f5c78SDavid du Colombier break;
1765e4f5c78SDavid du Colombier case 'c':
1775e4f5c78SDavid du Colombier p->dcd = n;
1785e4f5c78SDavid du Colombier // lines++;
1795e4f5c78SDavid du Colombier ++nop;
1805e4f5c78SDavid du Colombier break;
1815e4f5c78SDavid du Colombier case 'd':
1825e4f5c78SDavid du Colombier p->dtr = n;
1835e4f5c78SDavid du Colombier lines++;
1845e4f5c78SDavid du Colombier break;
1855e4f5c78SDavid du Colombier case 'e':
1865e4f5c78SDavid du Colombier p->dsr = n;
1875e4f5c78SDavid du Colombier // lines++;
1885e4f5c78SDavid du Colombier ++nop;
1895e4f5c78SDavid du Colombier break;
1905e4f5c78SDavid du Colombier case 'f': /* flush the pipes */
1915e4f5c78SDavid du Colombier drain++;
1925e4f5c78SDavid du Colombier break;
1935e4f5c78SDavid du Colombier case 'h': /* hangup?? */
1945e4f5c78SDavid du Colombier p->rts = p->dtr = 0;
1955e4f5c78SDavid du Colombier lines++;
1965e4f5c78SDavid du Colombier fprint(2, "serial: %c, unsure ctl\n", c);
1975e4f5c78SDavid du Colombier break;
1985e4f5c78SDavid du Colombier case 'i':
1995e4f5c78SDavid du Colombier ++nop;
2005e4f5c78SDavid du Colombier break;
2015e4f5c78SDavid du Colombier case 'k':
2025e4f5c78SDavid du Colombier drain++;
203d5789509SDavid du Colombier ser->setbreak(p, 1);
2045e4f5c78SDavid du Colombier sleep(n);
205d5789509SDavid du Colombier ser->setbreak(p, 0);
2065e4f5c78SDavid du Colombier break;
2075e4f5c78SDavid du Colombier case 'l':
2085e4f5c78SDavid du Colombier drain++;
2095e4f5c78SDavid du Colombier p->bits = n;
2105e4f5c78SDavid du Colombier set++;
2115e4f5c78SDavid du Colombier break;
2125e4f5c78SDavid du Colombier case 'm':
2135e4f5c78SDavid du Colombier drain++;
214d5789509SDavid du Colombier if(ser->modemctl != nil)
215d5789509SDavid du Colombier ser->modemctl(p, n);
2165e4f5c78SDavid du Colombier if(n == 0)
2175e4f5c78SDavid du Colombier p->cts = 0;
2185e4f5c78SDavid du Colombier break;
2195e4f5c78SDavid du Colombier case 'n':
2205e4f5c78SDavid du Colombier p->blocked = n;
2215e4f5c78SDavid du Colombier ++nop;
2225e4f5c78SDavid du Colombier break;
2235e4f5c78SDavid du Colombier case 'p': /* extended... */
2245e4f5c78SDavid du Colombier if(strlen(f[i]) != 2)
2255e4f5c78SDavid du Colombier return -1;
2265e4f5c78SDavid du Colombier drain++;
22780e9508eSDavid du Colombier par = f[i][1];
2285e4f5c78SDavid du Colombier if(par == 'n')
2295e4f5c78SDavid du Colombier p->parity = 0;
2305e4f5c78SDavid du Colombier else if(par == 'o')
2315e4f5c78SDavid du Colombier p->parity = 1;
2325e4f5c78SDavid du Colombier else if(par == 'e')
2335e4f5c78SDavid du Colombier p->parity = 2;
2345e4f5c78SDavid du Colombier else if(par == 'm') /* mark parity */
2355e4f5c78SDavid du Colombier p->parity = 3;
2365e4f5c78SDavid du Colombier else if(par == 's') /* space parity */
2375e4f5c78SDavid du Colombier p->parity = 4;
2385e4f5c78SDavid du Colombier else
2395e4f5c78SDavid du Colombier return -1;
2405e4f5c78SDavid du Colombier set++;
2415e4f5c78SDavid du Colombier break;
2425e4f5c78SDavid du Colombier case 'q':
2435e4f5c78SDavid du Colombier // drain++;
2445e4f5c78SDavid du Colombier p->limit = n;
2455e4f5c78SDavid du Colombier ++nop;
2465e4f5c78SDavid du Colombier break;
2475e4f5c78SDavid du Colombier case 'r':
2485e4f5c78SDavid du Colombier drain++;
2495e4f5c78SDavid du Colombier p->rts = n;
2505e4f5c78SDavid du Colombier lines++;
2515e4f5c78SDavid du Colombier break;
2525e4f5c78SDavid du Colombier case 's':
2535e4f5c78SDavid du Colombier drain++;
2545e4f5c78SDavid du Colombier p->stop = n;
2555e4f5c78SDavid du Colombier set++;
2565e4f5c78SDavid du Colombier break;
2575e4f5c78SDavid du Colombier case 'w':
2585e4f5c78SDavid du Colombier /* ?? how do I put this */
2595e4f5c78SDavid du Colombier p->timer = n * 100000LL;
2605e4f5c78SDavid du Colombier ++nop;
2615e4f5c78SDavid du Colombier break;
2625e4f5c78SDavid du Colombier case 'x':
2635e4f5c78SDavid du Colombier if(n == 0)
2645e4f5c78SDavid du Colombier x = CTLS;
2655e4f5c78SDavid du Colombier else
2665e4f5c78SDavid du Colombier x = CTLQ;
267d5789509SDavid du Colombier if(ser->wait4write != nil)
268d5789509SDavid du Colombier nw = ser->wait4write(p, &x, 1);
26980e9508eSDavid du Colombier else
2705e4f5c78SDavid du Colombier nw = write(p->epout->dfd, &x, 1);
2715e4f5c78SDavid du Colombier if(nw != 1){
27284860c5dSDavid du Colombier serialrecover(ser, p, p->epout, "");
2735e4f5c78SDavid du Colombier return -1;
2745e4f5c78SDavid du Colombier }
2755e4f5c78SDavid du Colombier break;
2765e4f5c78SDavid du Colombier }
277ecc2a7c8SDavid du Colombier /*
278ecc2a7c8SDavid du Colombier * don't print. the condition is harmless and the print
279ecc2a7c8SDavid du Colombier * splatters all over the display.
280ecc2a7c8SDavid du Colombier */
281ecc2a7c8SDavid du Colombier USED(nop);
282ecc2a7c8SDavid du Colombier if (0 && nop)
2835e4f5c78SDavid du Colombier fprint(2, "serial: %c, unsupported nop ctl\n", c);
2845e4f5c78SDavid du Colombier }
2855e4f5c78SDavid du Colombier if(drain)
2865e4f5c78SDavid du Colombier serialdrain(p);
28780e9508eSDavid du Colombier if(lines && !set){
288d5789509SDavid du Colombier if(ser->sendlines != nil && ser->sendlines(p) < 0)
2895e4f5c78SDavid du Colombier return -1;
29080e9508eSDavid du Colombier } else if(set){
291d5789509SDavid du Colombier if(ser->setparam != nil && ser->setparam(p) < 0)
29280e9508eSDavid du Colombier return -1;
29380e9508eSDavid du Colombier }
294c8a340cdSDavid du Colombier ser->recover = 0;
2955e4f5c78SDavid du Colombier return 0;
2965e4f5c78SDavid du Colombier }
2975e4f5c78SDavid du Colombier
2985e4f5c78SDavid du Colombier char *pformat = "noems";
2995e4f5c78SDavid du Colombier
3005e4f5c78SDavid du Colombier char *
serdumpst(Serialport * p,char * buf,int bufsz)301d5789509SDavid du Colombier serdumpst(Serialport *p, char *buf, int bufsz)
3025e4f5c78SDavid du Colombier {
3035e4f5c78SDavid du Colombier char *e, *s;
304d5789509SDavid du Colombier Serial *ser;
305d5789509SDavid du Colombier
306d5789509SDavid du Colombier ser = p->s;
3075e4f5c78SDavid du Colombier
3085e4f5c78SDavid du Colombier e = buf + bufsz;
309d5789509SDavid du Colombier s = seprint(buf, e, "b%d ", p->baud);
310d5789509SDavid du Colombier s = seprint(s, e, "c%d ", p->dcd); /* unimplemented */
311d5789509SDavid du Colombier s = seprint(s, e, "d%d ", p->dtr);
312d5789509SDavid du Colombier s = seprint(s, e, "e%d ", p->dsr); /* unimplemented */
313d5789509SDavid du Colombier s = seprint(s, e, "l%d ", p->bits);
314d5789509SDavid du Colombier s = seprint(s, e, "m%d ", p->mctl);
315d5789509SDavid du Colombier if(p->parity >= 0 || p->parity < strlen(pformat))
316d5789509SDavid du Colombier s = seprint(s, e, "p%c ", pformat[p->parity]);
3175e4f5c78SDavid du Colombier else
3185e4f5c78SDavid du Colombier s = seprint(s, e, "p%c ", '?');
319d5789509SDavid du Colombier s = seprint(s, e, "r%d ", p->rts);
320d5789509SDavid du Colombier s = seprint(s, e, "s%d ", p->stop);
321d5789509SDavid du Colombier s = seprint(s, e, "i%d ", p->fifo);
3225e4f5c78SDavid du Colombier s = seprint(s, e, "\ndev(%d) ", 0);
3235e4f5c78SDavid du Colombier s = seprint(s, e, "type(%d) ", ser->type);
324d5789509SDavid du Colombier s = seprint(s, e, "framing(%d) ", p->nframeerr);
325d5789509SDavid du Colombier s = seprint(s, e, "overruns(%d) ", p->novererr);
326d5789509SDavid du Colombier s = seprint(s, e, "berr(%d) ", p->nbreakerr);
327ed868a7cSDavid du Colombier s = seprint(s, e, " serr(%d)\n", p->nparityerr);
3285e4f5c78SDavid du Colombier return s;
3295e4f5c78SDavid du Colombier }
3305e4f5c78SDavid du Colombier
3315e4f5c78SDavid du Colombier static int
serinit(Serialport * p)332d5789509SDavid du Colombier serinit(Serialport *p)
3335e4f5c78SDavid du Colombier {
3345e4f5c78SDavid du Colombier int res;
33580e9508eSDavid du Colombier res = 0;
336d5789509SDavid du Colombier Serial *ser;
337d5789509SDavid du Colombier
338d5789509SDavid du Colombier ser = p->s;
339d5789509SDavid du Colombier
34080e9508eSDavid du Colombier if(ser->init != nil)
341d5789509SDavid du Colombier res = ser->init(p);
34280e9508eSDavid du Colombier if(ser->getparam != nil)
343d5789509SDavid du Colombier ser->getparam(p);
344d5789509SDavid du Colombier p->nframeerr = p->nparityerr = p->nbreakerr = p->novererr = 0;
345d5789509SDavid du Colombier
3465e4f5c78SDavid du Colombier return res;
3475e4f5c78SDavid du Colombier }
3485e4f5c78SDavid du Colombier
3495e4f5c78SDavid du Colombier static int
dwalk(Usbfs * fs,Fid * fid,char * name)3505e4f5c78SDavid du Colombier dwalk(Usbfs *fs, Fid *fid, char *name)
3515e4f5c78SDavid du Colombier {
3525e4f5c78SDavid du Colombier int i;
3535e4f5c78SDavid du Colombier char *dname;
3545e4f5c78SDavid du Colombier Qid qid;
355d5789509SDavid du Colombier Serialport *p;
3565e4f5c78SDavid du Colombier
3575e4f5c78SDavid du Colombier qid = fid->qid;
3585e4f5c78SDavid du Colombier if((qid.type & QTDIR) == 0){
3595e4f5c78SDavid du Colombier werrstr("walk in non-directory");
3605e4f5c78SDavid du Colombier return -1;
3615e4f5c78SDavid du Colombier }
3625e4f5c78SDavid du Colombier
3635e4f5c78SDavid du Colombier if(strcmp(name, "..") == 0){
3645e4f5c78SDavid du Colombier /* must be /eiaU%d; i.e. our root dir. */
3655e4f5c78SDavid du Colombier fid->qid.path = Qroot | fs->qid;
3665e4f5c78SDavid du Colombier fid->qid.vers = 0;
3675e4f5c78SDavid du Colombier fid->qid.type = QTDIR;
3685e4f5c78SDavid du Colombier return 0;
3695e4f5c78SDavid du Colombier }
3705e4f5c78SDavid du Colombier
371d5789509SDavid du Colombier p = fs->aux;
3725e4f5c78SDavid du Colombier for(i = 1; i < nelem(dirtab); i++){
373d584e620SDavid du Colombier dname = smprint(dirtab[i].name, p->name);
3745e4f5c78SDavid du Colombier if(strcmp(name, dname) == 0){
3755e4f5c78SDavid du Colombier qid.path = i | fs->qid;
3765e4f5c78SDavid du Colombier qid.vers = 0;
3775e4f5c78SDavid du Colombier qid.type = dirtab[i].mode >> 24;
3785e4f5c78SDavid du Colombier fid->qid = qid;
3795e4f5c78SDavid du Colombier free(dname);
3805e4f5c78SDavid du Colombier return 0;
3815e4f5c78SDavid du Colombier } else
3825e4f5c78SDavid du Colombier free(dname);
3835e4f5c78SDavid du Colombier }
3845e4f5c78SDavid du Colombier werrstr(Enotfound);
3855e4f5c78SDavid du Colombier return -1;
3865e4f5c78SDavid du Colombier }
3875e4f5c78SDavid du Colombier
3885e4f5c78SDavid du Colombier static void
dostat(Usbfs * fs,int path,Dir * d)3895e4f5c78SDavid du Colombier dostat(Usbfs *fs, int path, Dir *d)
3905e4f5c78SDavid du Colombier {
3915e4f5c78SDavid du Colombier Dirtab *t;
392d5789509SDavid du Colombier Serialport *p;
3935e4f5c78SDavid du Colombier
3945e4f5c78SDavid du Colombier t = &dirtab[path];
3955e4f5c78SDavid du Colombier d->qid.path = path;
3965e4f5c78SDavid du Colombier d->qid.type = t->mode >> 24;
3975e4f5c78SDavid du Colombier d->mode = t->mode;
398d5789509SDavid du Colombier p = fs->aux;
3995e4f5c78SDavid du Colombier
4005e4f5c78SDavid du Colombier if(strcmp(t->name, "/") == 0)
4015e4f5c78SDavid du Colombier d->name = t->name;
4025e4f5c78SDavid du Colombier else
403d5789509SDavid du Colombier snprint(d->name, Namesz, t->name, p->fs.name);
4045e4f5c78SDavid du Colombier d->length = 0;
4055e4f5c78SDavid du Colombier }
4065e4f5c78SDavid du Colombier
4075e4f5c78SDavid du Colombier static int
dstat(Usbfs * fs,Qid qid,Dir * d)4085e4f5c78SDavid du Colombier dstat(Usbfs *fs, Qid qid, Dir *d)
4095e4f5c78SDavid du Colombier {
4105e4f5c78SDavid du Colombier int path;
4115e4f5c78SDavid du Colombier
4125e4f5c78SDavid du Colombier path = qid.path & ~fs->qid;
4135e4f5c78SDavid du Colombier dostat(fs, path, d);
4145e4f5c78SDavid du Colombier d->qid.path |= fs->qid;
4155e4f5c78SDavid du Colombier return 0;
4165e4f5c78SDavid du Colombier }
4175e4f5c78SDavid du Colombier
4185e4f5c78SDavid du Colombier static int
dopen(Usbfs * fs,Fid * fid,int)4195e4f5c78SDavid du Colombier dopen(Usbfs *fs, Fid *fid, int)
4205e4f5c78SDavid du Colombier {
4215e4f5c78SDavid du Colombier ulong path;
422ed868a7cSDavid du Colombier Serialport *p;
4235e4f5c78SDavid du Colombier
4245e4f5c78SDavid du Colombier path = fid->qid.path & ~fs->qid;
425ed868a7cSDavid du Colombier p = fs->aux;
4265e4f5c78SDavid du Colombier switch(path){ /* BUG: unneeded? */
4275e4f5c78SDavid du Colombier case Qdata:
4284d52e0f0SDavid du Colombier dsprint(2, "serial, opened data\n");
4295e4f5c78SDavid du Colombier break;
4305e4f5c78SDavid du Colombier case Qctl:
4314d52e0f0SDavid du Colombier dsprint(2, "serial, opened ctl\n");
432d584e620SDavid du Colombier if(p->isjtag)
433d584e620SDavid du Colombier return 0;
434ed868a7cSDavid du Colombier serialctl(p, "l8 i1"); /* default line parameters */
4355e4f5c78SDavid du Colombier break;
4365e4f5c78SDavid du Colombier }
4375e4f5c78SDavid du Colombier return 0;
4385e4f5c78SDavid du Colombier }
4395e4f5c78SDavid du Colombier
4405e4f5c78SDavid du Colombier
4415e4f5c78SDavid du Colombier static void
filldir(Usbfs * fs,Dir * d,Dirtab * tab,int i,void * v)442d584e620SDavid du Colombier filldir(Usbfs *fs, Dir *d, Dirtab *tab, int i, void *v)
4435e4f5c78SDavid du Colombier {
444d584e620SDavid du Colombier Serialport *p;
445d584e620SDavid du Colombier
446d584e620SDavid du Colombier p = v;
4475e4f5c78SDavid du Colombier d->qid.path = i | fs->qid;
4485e4f5c78SDavid du Colombier d->mode = tab->mode;
4495e4f5c78SDavid du Colombier if((d->mode & DMDIR) != 0)
4505e4f5c78SDavid du Colombier d->qid.type = QTDIR;
4515e4f5c78SDavid du Colombier else
4525e4f5c78SDavid du Colombier d->qid.type = QTFILE;
453d584e620SDavid du Colombier sprint(d->name, tab->name, p->name); /* hope it fits */
4545e4f5c78SDavid du Colombier }
4555e4f5c78SDavid du Colombier
4565e4f5c78SDavid du Colombier static int
dirgen(Usbfs * fs,Qid,int i,Dir * d,void * p)457d584e620SDavid du Colombier dirgen(Usbfs *fs, Qid, int i, Dir *d, void *p)
4585e4f5c78SDavid du Colombier {
4595e4f5c78SDavid du Colombier i++; /* skip root */
46080e9508eSDavid du Colombier if(i >= nelem(dirtab))
4615e4f5c78SDavid du Colombier return -1;
462d584e620SDavid du Colombier filldir(fs, d, &dirtab[i], i, p);
4635e4f5c78SDavid du Colombier return 0;
4645e4f5c78SDavid du Colombier }
4655e4f5c78SDavid du Colombier
466bfb6eab9SDavid du Colombier enum {
467*853458f3SDavid du Colombier Serbufsize = 256,
468bfb6eab9SDavid du Colombier };
469bfb6eab9SDavid du Colombier
4705e4f5c78SDavid du Colombier static long
dread(Usbfs * fs,Fid * fid,void * data,long count,vlong offset)4715e4f5c78SDavid du Colombier dread(Usbfs *fs, Fid *fid, void *data, long count, vlong offset)
4725e4f5c78SDavid du Colombier {
4735e4f5c78SDavid du Colombier int dfd;
4745e4f5c78SDavid du Colombier long rcount;
4755e4f5c78SDavid du Colombier ulong path;
47680e9508eSDavid du Colombier char *e, *buf, *err; /* change */
4775e4f5c78SDavid du Colombier Qid q;
478d5789509SDavid du Colombier Serialport *p;
4795e4f5c78SDavid du Colombier Serial *ser;
480ecc2a7c8SDavid du Colombier static int errrun, good;
4815e4f5c78SDavid du Colombier
4825e4f5c78SDavid du Colombier q = fid->qid;
4835e4f5c78SDavid du Colombier path = fid->qid.path & ~fs->qid;
484d5789509SDavid du Colombier p = fs->aux;
485d5789509SDavid du Colombier ser = p->s;
4865e4f5c78SDavid du Colombier
487bfb6eab9SDavid du Colombier buf = emallocz(Serbufsize, 1);
488bfb6eab9SDavid du Colombier err = emallocz(Serbufsize, 1);
4895e4f5c78SDavid du Colombier qlock(ser);
4905e4f5c78SDavid du Colombier switch(path){
4915e4f5c78SDavid du Colombier case Qroot:
492d584e620SDavid du Colombier count = usbdirread(fs, q, data, count, offset, dirgen, p);
4935e4f5c78SDavid du Colombier break;
4945e4f5c78SDavid du Colombier case Qdata:
49580e9508eSDavid du Colombier if(count > ser->maxread)
49680e9508eSDavid du Colombier count = ser->maxread;
497*853458f3SDavid du Colombier
49880e9508eSDavid du Colombier dsprint(2, "serial: reading from data\n");
4995e4f5c78SDavid du Colombier do {
5004d52e0f0SDavid du Colombier err[0] = 0;
501d5789509SDavid du Colombier dfd = p->epin->dfd;
50280e9508eSDavid du Colombier if(usbdebug >= 3)
50380e9508eSDavid du Colombier dsprint(2, "serial: reading: %ld\n", count);
50480e9508eSDavid du Colombier
505ecc2a7c8SDavid du Colombier assert(count > 0);
50680e9508eSDavid du Colombier if(ser->wait4data != nil)
507d5789509SDavid du Colombier rcount = ser->wait4data(p, data, count);
50880e9508eSDavid du Colombier else{
50980e9508eSDavid du Colombier qunlock(ser);
5105e4f5c78SDavid du Colombier rcount = read(dfd, data, count);
5115e4f5c78SDavid du Colombier qlock(ser);
51280e9508eSDavid du Colombier }
51325fc6993SDavid du Colombier /*
51425fc6993SDavid du Colombier * if we encounter a long run of continuous read
51525fc6993SDavid du Colombier * errors, do something drastic so that our caller
51625fc6993SDavid du Colombier * doesn't just spin its wheels forever.
51725fc6993SDavid du Colombier */
51825fc6993SDavid du Colombier if(rcount < 0) {
519bfb6eab9SDavid du Colombier snprint(err, Serbufsize, "%r");
520ecc2a7c8SDavid du Colombier ++errrun;
521ecc2a7c8SDavid du Colombier sleep(20);
522ecc2a7c8SDavid du Colombier if (good > 0 && errrun > 10000) {
52325fc6993SDavid du Colombier /* the line has been dropped; give up */
52425fc6993SDavid du Colombier qunlock(ser);
525ecc2a7c8SDavid du Colombier fprint(2, "%s: line %s is gone: %r\n",
526d5789509SDavid du Colombier argv0, p->fs.name);
52725fc6993SDavid du Colombier threadexitsall("serial line gone");
52825fc6993SDavid du Colombier }
529ecc2a7c8SDavid du Colombier } else {
53025fc6993SDavid du Colombier errrun = 0;
531ecc2a7c8SDavid du Colombier good++;
532ecc2a7c8SDavid du Colombier }
53380e9508eSDavid du Colombier if(usbdebug >= 3)
53480e9508eSDavid du Colombier dsprint(2, "serial: read: %s %ld\n", err, rcount);
5355e4f5c78SDavid du Colombier } while(rcount < 0 && strstr(err, "timed out") != nil);
5365e4f5c78SDavid du Colombier
53780e9508eSDavid du Colombier dsprint(2, "serial: read from bulk %ld, %10.10s\n", rcount, err);
5385e4f5c78SDavid du Colombier if(rcount < 0){
5395e4f5c78SDavid du Colombier dsprint(2, "serial: need to recover, data read %ld %r\n",
5405e4f5c78SDavid du Colombier count);
54184860c5dSDavid du Colombier serialrecover(ser, p, p->epin, err);
5425e4f5c78SDavid du Colombier }
54380e9508eSDavid du Colombier dsprint(2, "serial: read from bulk %ld\n", rcount);
5445e4f5c78SDavid du Colombier count = rcount;
5455e4f5c78SDavid du Colombier break;
5465e4f5c78SDavid du Colombier case Qctl:
547eae8f8c7SDavid du Colombier if(offset != 0 || p->isjtag)
5485e4f5c78SDavid du Colombier count = 0;
54980e9508eSDavid du Colombier else {
550d5789509SDavid du Colombier e = serdumpst(p, buf, Serbufsize);
5515e4f5c78SDavid du Colombier count = usbreadbuf(data, count, 0, buf, e - buf);
55280e9508eSDavid du Colombier }
5535e4f5c78SDavid du Colombier break;
5545e4f5c78SDavid du Colombier }
555c8a340cdSDavid du Colombier if(count >= 0)
556c8a340cdSDavid du Colombier ser->recover = 0;
5575e4f5c78SDavid du Colombier qunlock(ser);
5585e4f5c78SDavid du Colombier free(err);
5595e4f5c78SDavid du Colombier free(buf);
5605e4f5c78SDavid du Colombier return count;
5615e4f5c78SDavid du Colombier }
5625e4f5c78SDavid du Colombier
5635e4f5c78SDavid du Colombier static long
altwrite(Serialport * p,uchar * buf,long count)564d5789509SDavid du Colombier altwrite(Serialport *p, uchar *buf, long count)
56580e9508eSDavid du Colombier {
56680e9508eSDavid du Colombier int nw, dfd;
56780e9508eSDavid du Colombier char err[128];
568d5789509SDavid du Colombier Serial *ser;
56980e9508eSDavid du Colombier
570d5789509SDavid du Colombier ser = p->s;
57180e9508eSDavid du Colombier do{
572d584e620SDavid du Colombier dsprint(2, "serial: write to bulk %ld\n", count);
573d584e620SDavid du Colombier
57480e9508eSDavid du Colombier if(ser->wait4write != nil)
57580e9508eSDavid du Colombier /* unlocked inside later */
576d5789509SDavid du Colombier nw = ser->wait4write(p, buf, count);
57780e9508eSDavid du Colombier else{
578d5789509SDavid du Colombier dfd = p->epout->dfd;
57980e9508eSDavid du Colombier qunlock(ser);
58080e9508eSDavid du Colombier nw = write(dfd, buf, count);
58180e9508eSDavid du Colombier qlock(ser);
58280e9508eSDavid du Colombier }
58380e9508eSDavid du Colombier rerrstr(err, sizeof err);
584d584e620SDavid du Colombier dsprint(2, "serial: written %s %d\n", err, nw);
58580e9508eSDavid du Colombier } while(nw < 0 && strstr(err, "timed out") != nil);
58680e9508eSDavid du Colombier
58780e9508eSDavid du Colombier if(nw != count){
58880e9508eSDavid du Colombier dsprint(2, "serial: need to recover, status in write %d %r\n",
58980e9508eSDavid du Colombier nw);
59080e9508eSDavid du Colombier snprint(err, sizeof err, "%r");
59184860c5dSDavid du Colombier serialrecover(p->s, p, p->epout, err);
59280e9508eSDavid du Colombier }
59380e9508eSDavid du Colombier return nw;
59480e9508eSDavid du Colombier }
59580e9508eSDavid du Colombier
59680e9508eSDavid du Colombier static long
dwrite(Usbfs * fs,Fid * fid,void * buf,long count,vlong)5975e4f5c78SDavid du Colombier dwrite(Usbfs *fs, Fid *fid, void *buf, long count, vlong)
5985e4f5c78SDavid du Colombier {
5995e4f5c78SDavid du Colombier ulong path;
6005e4f5c78SDavid du Colombier char *cmd;
601d5789509SDavid du Colombier Serialport *p;
6025e4f5c78SDavid du Colombier Serial *ser;
6035e4f5c78SDavid du Colombier
604d5789509SDavid du Colombier p = fs->aux;
605d5789509SDavid du Colombier ser = p->s;
6065e4f5c78SDavid du Colombier path = fid->qid.path & ~fs->qid;
6075e4f5c78SDavid du Colombier
6085e4f5c78SDavid du Colombier qlock(ser);
6095e4f5c78SDavid du Colombier switch(path){
6105e4f5c78SDavid du Colombier case Qdata:
611d5789509SDavid du Colombier count = altwrite(p, (uchar *)buf, count);
6125e4f5c78SDavid du Colombier break;
6135e4f5c78SDavid du Colombier case Qctl:
614d584e620SDavid du Colombier if(p->isjtag)
615d584e620SDavid du Colombier break;
6165e4f5c78SDavid du Colombier cmd = emallocz(count+1, 1);
6175e4f5c78SDavid du Colombier memmove(cmd, buf, count);
6185e4f5c78SDavid du Colombier cmd[count] = 0;
619d5789509SDavid du Colombier if(serialctl(p, cmd) < 0){
6205e4f5c78SDavid du Colombier qunlock(ser);
6215e4f5c78SDavid du Colombier werrstr(Ebadctl);
6225e4f5c78SDavid du Colombier free(cmd);
6235e4f5c78SDavid du Colombier return -1;
6245e4f5c78SDavid du Colombier }
6255e4f5c78SDavid du Colombier free(cmd);
6265e4f5c78SDavid du Colombier break;
6275e4f5c78SDavid du Colombier default:
6285e4f5c78SDavid du Colombier qunlock(ser);
6295e4f5c78SDavid du Colombier werrstr(Eperm);
6305e4f5c78SDavid du Colombier return -1;
6315e4f5c78SDavid du Colombier }
632c8a340cdSDavid du Colombier if(count >= 0)
633c8a340cdSDavid du Colombier ser->recover = 0;
634c8a340cdSDavid du Colombier else
63584860c5dSDavid du Colombier serialrecover(ser, p, p->epout, "writing");
6365e4f5c78SDavid du Colombier qunlock(ser);
6375e4f5c78SDavid du Colombier return count;
6385e4f5c78SDavid du Colombier }
6395e4f5c78SDavid du Colombier
6405e4f5c78SDavid du Colombier static int
openeps(Serialport * p,int epin,int epout,int epintr)641d5789509SDavid du Colombier openeps(Serialport *p, int epin, int epout, int epintr)
6425e4f5c78SDavid du Colombier {
643d5789509SDavid du Colombier Serial *ser;
644d5789509SDavid du Colombier
645d5789509SDavid du Colombier ser = p->s;
646d5789509SDavid du Colombier p->epin = openep(ser->dev, epin);
647d5789509SDavid du Colombier if(p->epin == nil){
6485e4f5c78SDavid du Colombier fprint(2, "serial: openep %d: %r\n", epin);
6495e4f5c78SDavid du Colombier return -1;
6505e4f5c78SDavid du Colombier }
6519b7bf7dfSDavid du Colombier if(epout == epin){
6529b7bf7dfSDavid du Colombier incref(p->epin);
6539b7bf7dfSDavid du Colombier p->epout = p->epin;
6549b7bf7dfSDavid du Colombier }else
655d5789509SDavid du Colombier p->epout = openep(ser->dev, epout);
656d5789509SDavid du Colombier if(p->epout == nil){
6575e4f5c78SDavid du Colombier fprint(2, "serial: openep %d: %r\n", epout);
658d5789509SDavid du Colombier closedev(p->epin);
6595e4f5c78SDavid du Colombier return -1;
6605e4f5c78SDavid du Colombier }
6614d52e0f0SDavid du Colombier
662d584e620SDavid du Colombier if(!p->isjtag){
663d5789509SDavid du Colombier devctl(p->epin, "timeout 1000");
664d5789509SDavid du Colombier devctl(p->epout, "timeout 1000");
665d584e620SDavid du Colombier }
6664d52e0f0SDavid du Colombier
6674d52e0f0SDavid du Colombier if(ser->hasepintr){
668d5789509SDavid du Colombier p->epintr = openep(ser->dev, epintr);
669d5789509SDavid du Colombier if(p->epintr == nil){
6705e4f5c78SDavid du Colombier fprint(2, "serial: openep %d: %r\n", epintr);
671d5789509SDavid du Colombier closedev(p->epin);
672d5789509SDavid du Colombier closedev(p->epout);
6735e4f5c78SDavid du Colombier return -1;
6745e4f5c78SDavid du Colombier }
675d5789509SDavid du Colombier opendevdata(p->epintr, OREAD);
676d5789509SDavid du Colombier devctl(p->epintr, "timeout 1000");
6774d52e0f0SDavid du Colombier }
6785e4f5c78SDavid du Colombier
67980e9508eSDavid du Colombier if(ser->seteps!= nil)
680d5789509SDavid du Colombier ser->seteps(p);
6819b7bf7dfSDavid du Colombier if(p->epin == p->epout)
6829b7bf7dfSDavid du Colombier opendevdata(p->epin, ORDWR);
6839b7bf7dfSDavid du Colombier else{
684d5789509SDavid du Colombier opendevdata(p->epin, OREAD);
685d5789509SDavid du Colombier opendevdata(p->epout, OWRITE);
6869b7bf7dfSDavid du Colombier }
687d5789509SDavid du Colombier if(p->epin->dfd < 0 ||p->epout->dfd < 0 ||
688d5789509SDavid du Colombier (ser->hasepintr && p->epintr->dfd < 0)){
6895e4f5c78SDavid du Colombier fprint(2, "serial: open i/o ep data: %r\n");
690d5789509SDavid du Colombier closedev(p->epin);
691d5789509SDavid du Colombier closedev(p->epout);
6924d52e0f0SDavid du Colombier if(ser->hasepintr)
693d5789509SDavid du Colombier closedev(p->epintr);
6945e4f5c78SDavid du Colombier return -1;
6955e4f5c78SDavid du Colombier }
6965e4f5c78SDavid du Colombier return 0;
6975e4f5c78SDavid du Colombier }
6985e4f5c78SDavid du Colombier
6995e4f5c78SDavid du Colombier static int
findendpoints(Serial * ser,int ifc)700d5789509SDavid du Colombier findendpoints(Serial *ser, int ifc)
7015e4f5c78SDavid du Colombier {
7025e4f5c78SDavid du Colombier int i, epin, epout, epintr;
70380e9508eSDavid du Colombier Ep *ep, **eps;
7045e4f5c78SDavid du Colombier
7055e4f5c78SDavid du Colombier epintr = epin = epout = -1;
70680e9508eSDavid du Colombier
70780e9508eSDavid du Colombier /*
70880e9508eSDavid du Colombier * interfc 0 means start from the start which is equiv to
70980e9508eSDavid du Colombier * iterate through endpoints probably, could be done better
71080e9508eSDavid du Colombier */
711d5789509SDavid du Colombier eps = ser->dev->usb->conf[0]->iface[ifc]->ep;
71280e9508eSDavid du Colombier
71380e9508eSDavid du Colombier for(i = 0; i < Niface; i++){
71480e9508eSDavid du Colombier if((ep = eps[i]) == nil)
7155e4f5c78SDavid du Colombier continue;
71680e9508eSDavid du Colombier if(ser->hasepintr && ep->type == Eintr &&
71780e9508eSDavid du Colombier ep->dir == Ein && epintr == -1)
7185e4f5c78SDavid du Colombier epintr = ep->id;
7195e4f5c78SDavid du Colombier if(ep->type == Ebulk){
7209b7bf7dfSDavid du Colombier if((ep->dir == Ein || ep->dir == Eboth) && epin == -1)
7215e4f5c78SDavid du Colombier epin = ep->id;
7223f8719e6SDavid du Colombier if((ep->dir == Eout || ep->dir == Eboth) && epout == -1)
7235e4f5c78SDavid du Colombier epout = ep->id;
7245e4f5c78SDavid du Colombier }
7255e4f5c78SDavid du Colombier }
726d5789509SDavid du Colombier dprint(2, "serial[%d]: ep ids: in %d out %d intr %d\n", ifc, epin, epout, epintr);
7274d52e0f0SDavid du Colombier if(epin == -1 || epout == -1 || (ser->hasepintr && epintr == -1))
7285e4f5c78SDavid du Colombier return -1;
7294d52e0f0SDavid du Colombier
730d5789509SDavid du Colombier if(openeps(&ser->p[ifc], epin, epout, epintr) < 0)
7315e4f5c78SDavid du Colombier return -1;
7325e4f5c78SDavid du Colombier
733d5789509SDavid du Colombier dprint(2, "serial: ep in %s out %s\n", ser->p[ifc].epin->dir, ser->p[ifc].epout->dir);
7344d52e0f0SDavid du Colombier if(ser->hasepintr)
735d5789509SDavid du Colombier dprint(2, "serial: ep intr %s\n", ser->p[ifc].epintr->dir);
7365e4f5c78SDavid du Colombier
7375e4f5c78SDavid du Colombier if(usbdebug > 1 || serialdebug > 2){
738d5789509SDavid du Colombier devctl(ser->p[ifc].epin, "debug 1");
739d5789509SDavid du Colombier devctl(ser->p[ifc].epout, "debug 1");
7404d52e0f0SDavid du Colombier if(ser->hasepintr)
741d5789509SDavid du Colombier devctl(ser->p[ifc].epintr, "debug 1");
7425e4f5c78SDavid du Colombier devctl(ser->dev, "debug 1");
7435e4f5c78SDavid du Colombier }
7445e4f5c78SDavid du Colombier return 0;
7455e4f5c78SDavid du Colombier }
7465e4f5c78SDavid du Colombier
74780e9508eSDavid du Colombier /* keep in sync with main.c */
7485e4f5c78SDavid du Colombier static int
usage(void)7495e4f5c78SDavid du Colombier usage(void)
7505e4f5c78SDavid du Colombier {
75180e9508eSDavid du Colombier werrstr("usage: usb/serial [-dD] [-m mtpt] [-s srv]");
7525e4f5c78SDavid du Colombier return -1;
7535e4f5c78SDavid du Colombier }
7545e4f5c78SDavid du Colombier
7555e4f5c78SDavid du Colombier static void
serdevfree(void * a)7565e4f5c78SDavid du Colombier serdevfree(void *a)
7575e4f5c78SDavid du Colombier {
7585e4f5c78SDavid du Colombier Serial *ser = a;
759d5789509SDavid du Colombier Serialport *p;
760d5789509SDavid du Colombier int i;
7615e4f5c78SDavid du Colombier
7625e4f5c78SDavid du Colombier if(ser == nil)
7635e4f5c78SDavid du Colombier return;
764d5789509SDavid du Colombier
765d5789509SDavid du Colombier for(i = 0; i < ser->nifcs; i++){
766d5789509SDavid du Colombier p = &ser->p[i];
767d5789509SDavid du Colombier
7684d52e0f0SDavid du Colombier if(ser->hasepintr)
769d5789509SDavid du Colombier closedev(p->epintr);
770d5789509SDavid du Colombier closedev(p->epin);
771d5789509SDavid du Colombier closedev(p->epout);
772d5789509SDavid du Colombier p->epintr = p->epin = p->epout = nil;
773d5789509SDavid du Colombier if(p->w4data != nil)
774d5789509SDavid du Colombier chanfree(p->w4data);
775d5789509SDavid du Colombier if(p->gotdata != nil)
776d5789509SDavid du Colombier chanfree(p->gotdata);
777d5789509SDavid du Colombier if(p->readc)
778d5789509SDavid du Colombier chanfree(p->readc);
779d5789509SDavid du Colombier
780d5789509SDavid du Colombier }
7815e4f5c78SDavid du Colombier free(ser);
7825e4f5c78SDavid du Colombier }
7835e4f5c78SDavid du Colombier
7845e4f5c78SDavid du Colombier static Usbfs serialfs = {
7855e4f5c78SDavid du Colombier .walk = dwalk,
7865e4f5c78SDavid du Colombier .open = dopen,
7875e4f5c78SDavid du Colombier .read = dread,
7885e4f5c78SDavid du Colombier .write= dwrite,
7895e4f5c78SDavid du Colombier .stat = dstat,
7905e4f5c78SDavid du Colombier };
7915e4f5c78SDavid du Colombier
792d5789509SDavid du Colombier static void
serialfsend(Usbfs * fs)793d5789509SDavid du Colombier serialfsend(Usbfs *fs)
794d5789509SDavid du Colombier {
795d5789509SDavid du Colombier Serialport *p;
796d5789509SDavid du Colombier
797d5789509SDavid du Colombier p = fs->aux;
798d5789509SDavid du Colombier
799d5789509SDavid du Colombier if(p->w4data != nil)
800d5789509SDavid du Colombier chanclose(p->w4data);
801d5789509SDavid du Colombier if(p->gotdata != nil)
802d5789509SDavid du Colombier chanclose(p->gotdata);
803d5789509SDavid du Colombier if(p->readc)
804d5789509SDavid du Colombier chanclose(p->readc);
805d5789509SDavid du Colombier }
806d5789509SDavid du Colombier
8075e4f5c78SDavid du Colombier int
serialmain(Dev * dev,int argc,char * argv[])8085e4f5c78SDavid du Colombier serialmain(Dev *dev, int argc, char* argv[])
8095e4f5c78SDavid du Colombier {
8105e4f5c78SDavid du Colombier Serial *ser;
811d5789509SDavid du Colombier Serialport *p;
8124d52e0f0SDavid du Colombier char buf[50];
813ed868a7cSDavid du Colombier int i, devid;
8145e4f5c78SDavid du Colombier
815ed868a7cSDavid du Colombier devid = dev->id;
8165e4f5c78SDavid du Colombier ARGBEGIN{
8175e4f5c78SDavid du Colombier case 'd':
8185e4f5c78SDavid du Colombier serialdebug++;
8195e4f5c78SDavid du Colombier break;
820ed868a7cSDavid du Colombier case 'N':
821ed868a7cSDavid du Colombier devid = atoi(EARGF(usage()));
822ed868a7cSDavid du Colombier break;
8235e4f5c78SDavid du Colombier default:
8245e4f5c78SDavid du Colombier return usage();
8255e4f5c78SDavid du Colombier }ARGEND
8265e4f5c78SDavid du Colombier if(argc != 0)
8275e4f5c78SDavid du Colombier return usage();
8285e4f5c78SDavid du Colombier
8295e4f5c78SDavid du Colombier ser = dev->aux = emallocz(sizeof(Serial), 1);
830d5789509SDavid du Colombier ser->maxrtrans = ser->maxwtrans = sizeof ser->p[0].data;
831d5789509SDavid du Colombier ser->maxread = ser->maxwrite = sizeof ser->p[0].data;
8325e4f5c78SDavid du Colombier ser->dev = dev;
8335e4f5c78SDavid du Colombier dev->free = serdevfree;
834d5789509SDavid du Colombier ser->jtag = -1;
835d5789509SDavid du Colombier ser->nifcs = 1;
8364d52e0f0SDavid du Colombier
8374d52e0f0SDavid du Colombier snprint(buf, sizeof buf, "vid %#06x did %#06x",
8384d52e0f0SDavid du Colombier dev->usb->vid, dev->usb->did);
8394d52e0f0SDavid du Colombier if(plmatch(buf) == 0){
8404d52e0f0SDavid du Colombier ser->hasepintr = 1;
8414d52e0f0SDavid du Colombier ser->Serialops = plops;
84280e9508eSDavid du Colombier } else if(uconsmatch(buf) == 0)
8434d52e0f0SDavid du Colombier ser->Serialops = uconsops;
84480e9508eSDavid du Colombier else if(ftmatch(ser, buf) == 0)
84580e9508eSDavid du Colombier ser->Serialops = ftops;
8469b7bf7dfSDavid du Colombier else if(slmatch(buf) == 0)
8479b7bf7dfSDavid du Colombier ser->Serialops = slops;
84880e9508eSDavid du Colombier else {
84980e9508eSDavid du Colombier werrstr("serial: no serial devices found");
8505e4f5c78SDavid du Colombier return -1;
8515e4f5c78SDavid du Colombier }
852d5789509SDavid du Colombier for(i = 0; i < ser->nifcs; i++){
853d5789509SDavid du Colombier p = &ser->p[i];
854d5789509SDavid du Colombier p->interfc = i;
855d5789509SDavid du Colombier p->s = ser;
856d5789509SDavid du Colombier p->fs = serialfs;
857d584e620SDavid du Colombier if(i == ser->jtag){
858d584e620SDavid du Colombier p->isjtag++;
859d584e620SDavid du Colombier }
860d5789509SDavid du Colombier if(findendpoints(ser, i) < 0){
861d5789509SDavid du Colombier werrstr("serial: no endpoints found for ifc %d", i);
86280e9508eSDavid du Colombier return -1;
86380e9508eSDavid du Colombier }
864d5789509SDavid du Colombier p->w4data = chancreate(sizeof(ulong), 0);
865d5789509SDavid du Colombier p->gotdata = chancreate(sizeof(ulong), 0);
866d5789509SDavid du Colombier }
867d5789509SDavid du Colombier
868d5789509SDavid du Colombier qlock(ser);
869d5789509SDavid du Colombier serialreset(ser);
870d5789509SDavid du Colombier for(i = 0; i < ser->nifcs; i++){
871d5789509SDavid du Colombier p = &ser->p[i];
872d5789509SDavid du Colombier dprint(2, "serial: valid interface, calling serinit\n");
873d5789509SDavid du Colombier if(serinit(p) < 0){
8745e4f5c78SDavid du Colombier dprint(2, "serial: serinit: %r\n");
8755e4f5c78SDavid du Colombier return -1;
8765e4f5c78SDavid du Colombier }
8775e4f5c78SDavid du Colombier
878d5789509SDavid du Colombier dsprint(2, "serial: adding interface %d, %p\n", p->interfc, p);
879d584e620SDavid du Colombier if(p->isjtag){
880d584e620SDavid du Colombier snprint(p->name, sizeof p->name, "jtag");
881d584e620SDavid du Colombier dsprint(2, "serial: JTAG interface %d %p\n", i, p);
882d584e620SDavid du Colombier snprint(p->fs.name, sizeof p->fs.name, "jtag%d.%d", devid, i);
883d584e620SDavid du Colombier } else {
884d584e620SDavid du Colombier snprint(p->name, sizeof p->name, "eiaU");
885ed868a7cSDavid du Colombier if(i == 0)
886ed868a7cSDavid du Colombier snprint(p->fs.name, sizeof p->fs.name, "eiaU%d", devid);
887ed868a7cSDavid du Colombier else
888ed868a7cSDavid du Colombier snprint(p->fs.name, sizeof p->fs.name, "eiaU%d.%d", devid, i);
889d584e620SDavid du Colombier }
890c8a340cdSDavid du Colombier fprint(2, "%s...", p->fs.name);
891d5789509SDavid du Colombier p->fs.dev = dev;
8925e4f5c78SDavid du Colombier incref(dev);
893d5789509SDavid du Colombier p->fs.aux = p;
894d5789509SDavid du Colombier p->fs.end = serialfsend;
895d5789509SDavid du Colombier usbfsadd(&p->fs);
896d5789509SDavid du Colombier }
8975e4f5c78SDavid du Colombier
898d5789509SDavid du Colombier qunlock(ser);
8995e4f5c78SDavid du Colombier return 0;
9005e4f5c78SDavid du Colombier }
901