serial/ 775 0 0 0 11216736034 104655ustar00paureasysserial/main.c 664 0 0 2061 11214501024 11537ustar00paureasys#include #include #include #include "usb.h" #include "usbfs.h" #include "serial.h" #include "ucons.h" #include "prolific.h" typedef struct Parg Parg; enum { Arglen = 80, }; static void usage(void) { fprint(2, "usage: %s [-d] [-a n] [dev...]\n", argv0); threadexitsall("usage"); } static int matchserial(char *info, void*) { if(uconsmatch(info) == 0 || plmatch(info) == 0) return 0; return -1; } void threadmain(int argc, char **argv) { char *mnt, *srv, *as, *ae; char args[Arglen]; mnt = "/dev"; srv = nil; quotefmtinstall(); ae = args + sizeof args; as = seprint(args, ae, "serial"); ARGBEGIN{ case 'D': usbfsdebug++; break; case 'd': usbdebug++; as = seprint(as, ae, " -d"); break; case 'm': mnt = EARGF(usage()); break; case 's': srv = EARGF(usage()); break; default: usage(); break; }ARGEND; rfork(RFNOTEG); fmtinstall('U', Ufmt); threadsetgrp(threadid()); usbfsinit(srv, mnt, &usbdirfs, MAFTER|MCREATE); startdevs(args, argv, argc, matchserial, nil, serialmain); threadexits(nil); } serial/mkfile 664 0 0 662 11214504044 11633ustar00paureasys #include #include #include "usb.h" #include "usbfs.h" #include "serial.h" #include "prolific.h" Cinfo plinfo[] = { { PL2303Vid, PL2303Did }, { PL2303Vid, PL2303DidRSAQ2 }, { PL2303Vid, PL2303DidDCU11 }, { PL2303Vid, PL2303DidRSAQ3 }, { PL2303Vid, PL2303DidPHAROS }, { PL2303Vid, PL2303DidALDIGA }, { PL2303Vid, PL2303DidMMX }, { PL2303Vid, PL2303DidGPRS }, { IODATAVid, IODATADid }, { IODATAVid, IODATADidRSAQ5 }, { ATENVid, ATENDid }, { ATENVid2, ATENDid }, { ELCOMVid, ELCOMDid }, { ELCOMVid, ELCOMDidUCSGT }, { ITEGNOVid, ITEGNODid }, { ITEGNOVid, ITEGNODid2080 }, { MA620Vid, MA620Did }, { RATOCVid, RATOCDid }, { TRIPPVid, TRIPPDid }, { RADIOSHACKVid,RADIOSHACKDid }, { DCU10Vid, DCU10Did }, { SITECOMVid, SITECOMDid }, { ALCATELVid, ALCATELDid }, { SAMSUNGVid, SAMSUNGDid }, { SIEMENSVid, SIEMENSDidSX1 }, { SIEMENSVid, SIEMENSDidX65 }, { SIEMENSVid, SIEMENSDidX75 }, { SIEMENSVid, SIEMENSDidEF81 }, { SYNTECHVid, SYNTECHDid }, { NOKIACA42Vid, NOKIACA42Did }, { CA42CA42Vid, CA42CA42Did }, { SAGEMVid, SAGEMDid }, { LEADTEKVid, LEADTEK9531Did }, { SPEEDDRAGONVid,SPEEDDRAGONDid }, { DATAPILOTU2Vid,DATAPILOTU2Did }, { BELKINVid, BELKINDid }, { ALCORVid, ALCORDid }, { WS002INVid, WS002INDid }, { COREGAVid, COREGADid }, { YCCABLEVid, YCCABLEDid }, { SUPERIALVid, SUPERIALDid }, { HPVid, HPLD220Did }, { 0, 0 }, }; int plmatch(char *info) { Cinfo *ip; char buf[50]; for(ip = plinfo; ip->vid != 0; ip++){ snprint(buf, sizeof buf, "vid %#06x did %#06x", ip->vid, ip->did); dsprint(2, "serial: %s %s", buf, info); if(strstr(info, buf) != nil) return 0; } return -1; } static void statusreader(void *u); static void dumpbuf(uchar *buf, int bufsz) { int i; for(i=0; idev, Rd2h | Rvendor | Rdev, VendorReadReq, val, index, buf, 1); dsprint(2, "serial: vendorread res:%d\n", res); return res; } static int vendorwrite(Serial *ser, int val, int index) { int res; dsprint(2, "serial: vendorwrite val: 0x%x idx:%d\n", val, index); res = usbcmd(ser->dev, Rh2d | Rvendor | Rdev, VendorWriteReq, val, index, nil, 0); dsprint(2, "serial: vendorwrite res:%d\n", res); return res; } static int plgetparam(Serial *ser) { uchar buf[7]; int res; res = usbcmd(ser->dev, Rd2h | Rclass | Riface, GetLineReq, 0, 0, buf, sizeof buf); ser->baud = GET4(buf); /* * with the Pl9 interface it is not possible to set `1.5' as stop bits * for the prologic: * 0 is 1 stop bit * 1 is 1.5 stop bits * 2 is 2 stop bits */ if(buf[4] == 1) fprint(2, "warning, stop bit set to 1.5 unsupported"); else if(buf[4] == 0) ser->stop = 1; else if(buf[4] == 2) ser->stop = 2; ser->parity = buf[5]; ser->bits = buf[6]; dsprint(2, "serial: getparam: "); if(serialdebug) dumpbuf(buf, sizeof buf); dsprint(2, "serial: getparam res: %d\n", res); return res; } static int plmodemctl(Serial *ser, int set) { if(set == 0){ ser->mctl = 0; vendorwrite(ser, 0x0, 0x0); return 0; } ser->mctl = 1; if(ser->type == TypeHX) vendorwrite(ser, 0x0, Dcr0InitX); else vendorwrite(ser, 0x0, Dcr0InitH); return 0; } static int plsetparam(Serial *ser) { uchar buf[7]; int res; PUT4(buf, ser->baud); if(ser->stop == 1) buf[4] = 0; else if(ser->stop == 2) buf[4] = 2; /* see comment in getparam */ buf[5] = ser->parity; buf[6] = ser->bits; dsprint(2, "serial: setparam: "); if(serialdebug) dumpbuf(buf, sizeof buf); res = usbcmd(ser->dev, Rh2d | Rclass | Riface, SetLineReq, 0, 0, buf, sizeof buf); plmodemctl(ser, ser->mctl); plgetparam(ser); /* make sure our state corresponds */ dsprint(2, "serial: setparam res: %d\n", res); return res; } static int plinit(Serial *ser) { ulong csp; char *st; uchar *buf; buf = emallocz(VendorReqSize, 1); qlock(ser); serialreset(ser); csp = ser->dev->usb->csp; if(Class(csp) == 0x02) ser->type = Type0; else if(ser->dev->maxpkt == 0x40) ser->type = TypeHX; else if(Class(csp) == 0x00 || Class(csp) == 0xFF) ser->type = Type1; if(ser->type != ser->dev->usb->psid) fprint(2, "serial: warning, heuristics: %#ux and psid: " "%#ux, not a match\n", ser->type, ser->dev->usb->psid); dsprint(2, "serial: type %d\n", ser->type); vendorread(ser, 0x8484, 0, buf); vendorwrite(ser, 0x0404, 0); vendorread(ser, 0x8484, 0, buf); vendorread(ser, 0x8383, 0, buf); vendorread(ser, 0x8484, 0, buf); vendorwrite(ser, 0x0404, 1); vendorread(ser, 0x8484, 0, buf); vendorread(ser, 0x8383, 0, buf); vendorwrite(ser, 0, 1); vendorwrite(ser, 1, 0); if(ser->type == TypeHX) vendorwrite(ser, 2, Dcr2InitX); else vendorwrite(ser, 2, Dcr2InitH); plgetparam(ser); qunlock(ser); free(buf); st = emallocz(255, 1); qlock(ser); if(serialdebug) dumpstatus(ser, st, 255); dsprint(2, st); qunlock(ser); free(st); /* ser gets freed by closedev, the process has a reference */ incref(ser->dev); proccreate(statusreader, ser, 8*1024); return 0; } static int plsetbreak(Serial *ser, int val) { return usbcmd(ser->dev, Rh2d | Rclass | Riface, (val != 0? BreakOn: BreakOff), val, 0, nil, 0); } static int plclearpipes(Serial *ser) { if(ser->type == TypeHX){ vendorwrite(ser, 8, 0x0); vendorwrite(ser, 9, 0x0); }else{ if(unstall(ser->dev, ser->epout, Eout) < 0) dprint(2, "disk: unstall epout: %r\n"); if(unstall(ser->dev, ser->epin, Ein) < 0) dprint(2, "disk: unstall epin: %r\n"); if(unstall(ser->dev, ser->epintr, Ein) < 0) dprint(2, "disk: unstall epintr: %r\n"); } return 0; } static int setctlline(Serial *ser, uchar val) { return usbcmd(ser->dev, Rh2d | Rclass | Riface, SetCtlReq, val, 0, nil, 0); } static void composectl(Serial *ser) { if(ser->rts) ser->ctlstate |= CtlRTS; else ser->ctlstate &= ~CtlRTS; if(ser->dtr) ser->ctlstate |= CtlDTR; else ser->ctlstate &= ~CtlDTR; } int plsendlines(Serial *ser) { int res; dsprint(2, "serial: sendlines: %#2.2x\n", ser->ctlstate); composectl(ser); res = setctlline(ser, ser->ctlstate); dsprint(2, "serial: getparam res: %d\n", res); return 0; } static int plreadstatus(Serial *ser) { int nr, dfd; char err[40]; uchar buf[10]; qlock(ser); dsprint(2, "serial: reading from interrupt\n"); dfd = ser->epintr->dfd; qunlock(ser); nr = read(dfd, buf, sizeof buf); qlock(ser); snprint(err, sizeof err, "%r"); dsprint(2, "serial: interrupt read %d %r\n", nr); if(nr < 0 && strstr(err, "timed out") != nil){ dsprint(2, "serial: need to recover, status read %d %r\n", nr); if(serialrecover(ser, err) < 0){ qunlock(ser); return -1; } } if(nr < 0) dsprint(2, "serial: reading status: %r"); else if(nr >= sizeof buf - 1){ ser->dcd = buf[8] & DcdStatus; ser->dsr = buf[8] & DsrStatus; ser->cts = buf[8] & BreakerrStatus; ser->ring = buf[8] & RingStatus; ser->cts = buf[8] & CtsStatus; if (buf[8] & FrerrStatus) ser->nframeerr++; if (buf[8] & ParerrStatus) ser->nparityerr++; if (buf[8] & OvererrStatus) ser->novererr++; } else dsprint(2, "serial: bad status read %d\n", nr); dsprint(2, "serial: finished read from interrupt %d\n", nr); qunlock(ser); return 0; } static void statusreader(void *u) { Serial *ser; ser = u; threadsetname("statusreaderproc"); while(plreadstatus(ser) > 0) ; closedev(ser->dev); } Serialops plops = { .init = plinit, .getparam = plgetparam, .setparam = plsetparam, .clearpipes = plclearpipes, .sendlines = plsendlines, .modemctl = plmodemctl, .setbreak = plsetbreak, }; nil; quotefmtinstall(); ae = args + sizeof args; as = seprint(args, ae, "serial"); ARGBEGIN{ case 'D': usbfsdebug++; break; case 'd': usbdebug++; as = seprint(as, ae, " -d"); break; case 'm': mnt = EARGF(usage()); break; case 's': srv = EARGF(usage()); break; default: usage(); break; }ARGEND; rfork(RFNOTEG); fmtinstall('U', Ufmt); threadsetgrp(threadid()); usbfsinit(srv, mnt, &usbdirfs, MAFTER|MCREATE); startdevs(args, argv, argc, matserial/prolific.h 664 0 0 6206 11214504315 12442ustar00paureasysenum { /* flavours of the device */ Type0, Type1, TypeHX, /* usbcmd parameters */ SetLineReq = 0x20, SetCtlReq = 0x22, CtlDTR = 0x01, CtlRTS = 0x02, BreakReq = 0x23, BreakOn = 0xffff, BreakOff = 0x0000, GetLineReq = 0x21, VendorWriteReq = 0x01, /* BUG: is this a standard request? */ VendorReadReq = 0x01, VendorReqSize = 10, /* status read from interrupt endpoint */ DcdStatus = 0x01, DsrStatus = 0x02, BreakerrStatus= 0x04, RingStatus = 0x08, FrerrStatus = 0x10, ParerrStatus = 0x20, OvererrStatus = 0x40, CtsStatus = 0x80, /* * flow control bits, Dcr0InitH * I think, composed this list from various drivers and specs. * FlowOutCts = 0x0001, * FlowOutDsr = 0x0002, * FlowInDsr = 0x0004, * FlowInDtr = 0x0008, * FlowInRts = 0x0010, * FlowOutRts = 0x0020, * FlowOutXon = 0x0080, * FlowInXon = 0x0100, */ Dcr0InitH = 0x0041, Dcr0InitX = 0x0061, Dcr1InitH = 0x0080, Dcr1InitX = 0x0000, Dcr2InitH = 0x0024, Dcr2InitX = 0x0044, }; enum { PL2303Vid = 0x067b, PL2303Did = 0x2303, PL2303DidRSAQ2= 0x04bb, PL2303DidDCU11= 0x1234, PL2303DidPHAROS=0xaaa0, PL2303DidRSAQ3= 0xaaa2, PL2303DidALDIGA=0x0611, PL2303DidMMX = 0x0612, PL2303DidGPRS = 0x0609, ATENVid = 0x0557, ATENVid2 = 0x0547, ATENDid = 0x2008, IODATAVid = 0x04bb, IODATADid = 0x0a03, IODATADidRSAQ5= 0x0a0e, ELCOMVid = 0x056e, ELCOMDid = 0x5003, ELCOMDidUCSGT = 0x5004, ITEGNOVid = 0x0eba, ITEGNODid = 0x1080, ITEGNODid2080 = 0x2080, MA620Vid = 0x0df7, MA620Did = 0x0620, RATOCVid = 0x0584, RATOCDid = 0xb000, TRIPPVid = 0x2478, TRIPPDid = 0x2008, RADIOSHACKVid = 0x1453, RADIOSHACKDid = 0x4026, DCU10Vid = 0x0731, DCU10Did = 0x0528, SITECOMVid = 0x6189, SITECOMDid = 0x2068, /* Alcatel OT535/735 USB cable */ ALCATELVid = 0x11f7, ALCATELDid = 0x02df, /* Samsung I330 phone cradle */ SAMSUNGVid = 0x04e8, SAMSUNGDid = 0x8001, SIEMENSVid = 0x11f5, SIEMENSDidSX1 = 0x0001, SIEMENSDidX65 = 0x0003, SIEMENSDidX75 = 0x0004, SIEMENSDidEF81= 0x0005, SYNTECHVid = 0x0745, SYNTECHDid = 0x0001, /* Nokia CA-42 Cable */ NOKIACA42Vid = 0x078b, NOKIACA42Did = 0x1234, /* CA-42 CLONE Cable www.ca-42.com chipset: Prolific Technology Inc */ CA42CA42Vid = 0x10b5, CA42CA42Did = 0xac70, SAGEMVid = 0x079b, SAGEMDid = 0x0027, /* Leadtek GPS 9531 (ID 0413:2101) */ LEADTEKVid = 0x0413, LEADTEK9531Did= 0x2101, /* USB GSM cable from Speed Dragon Multimedia, Ltd */ SPEEDDRAGONVid= 0x0e55, SPEEDDRAGONDid= 0x110b, /* DATAPILOT Universal-2 Phone Cable */ BELKINVid = 0x050d, BELKINDid = 0x0257, /* Belkin "F5U257" Serial Adapter */ DATAPILOTU2Vid= 0x0731, DATAPILOTU2Did= 0x2003, ALCORVid = 0x058F, ALCORDid = 0x9720, /* Willcom WS002IN Data Driver (by NetIndex Inc.) */, WS002INVid = 0x11f6, WS002INDid = 0x2001, /* Corega CG-USBRS232R Serial Adapter */, COREGAVid = 0x07aa, COREGADid = 0x002a, /* Y.C. Cable U.S.A., Inc - USB to RS-232 */, YCCABLEVid = 0x05ad, YCCABLEDid = 0x0fba, /* "Superial" USB - Serial */, SUPERIALVid = 0x5372, SUPERIALDid = 0x2303, /* Hewlett-Packard LD220-HP POS Pole Display */, HPVid = 0x03f0, HPLD220Did = 0x3524, }; extern Serialops plops; int plmatch(char *info); static void statusreader(void *u); static void dumpbuf(uchar *buf, int bufsz) { int i; for(i=0; idev, Rd2h | Rvendor | Rdev, Veserial/serial.c 664 0 0 27506 11216734755 12152ustar00paureasys#include #include #include #include #include "usb.h" #include "usbfs.h" #include "serial.h" #include "prolific.h" #include "ucons.h" /* * BUG: This device is not really prepared to use different * serial implementations. That part must be rewritten. * * BUG: An error on the device does not make the driver exit. * It probably should. */ int serialdebug; int debugport; enum { /* Qids. Maintain order (relative to dirtabs structs) */ Qroot = 0, Qctl, Qdata, Qmax, }; typedef struct Dirtab Dirtab; struct Dirtab { char *name; int mode; }; static Dirtab dirtab[] = { [Qroot] "/", DMDIR|0555, [Qctl] "ctl", 0444, [Qdata] "data", 0640, }; static int sdebug; int serialnop(Serial *) { return 0; } int serialnopctl(Serial *, int) { return 0; } static void serialfatal(Serial *ser) { dsprint(2, "serial: fatal error, detaching\n"); devctl(ser->dev, "detach"); usbfsdel(&ser->fs); } /* I sleep with the lock... only way to drain */ static void serialdrain(Serial *ser) { uint baud; baud = ser->baud; /* wait for the 256-byte pipe to clear */ sleep(10 + 256/((1 + baud)*1000)); ser->clearpipes(ser); } int serialreset(Serial *ser) { /* cmd for reset */ fprint(2, "serial: error, resetting\n"); serialdrain(ser); return 0; } /*call this if something goes wrong */ int serialrecover(Serial *ser, char *err) { if(strstr(err, "detached") != nil) return -1; if(ser->recover > 1) serialfatal(ser); ser->recover++; if(serialreset(ser) < 0) return -1; ser->recover = 0; return 0; } static int serialctl(Serial *p, char *cmd) { int c, i, n, nf, nop, nw, par, drain, set, lines; char *f[16]; uchar x; drain = set = lines = 0; nf = tokenize(cmd, f, nelem(f)); for(i = 0; i < nf; i++){ if(strncmp(f[i], "break", 5) == 0){ p->setbreak(p, 1); continue; } nop = 0; n = atoi(f[i]+1); c = *f[i]; if (isascii(c) && isupper(c)) c = tolower(c); switch(c){ case 'b': drain++; p->baud = n; set++; break; case 'c': p->dcd = n; // lines++; ++nop; break; case 'd': p->dtr = n; lines++; break; case 'e': p->dsr = n; // lines++; ++nop; break; case 'f': /* flush the pipes */ drain++; break; case 'h': /* hangup?? */ p->rts = p->dtr = 0; lines++; fprint(2, "serial: %c, unsure ctl\n", c); break; case 'i': ++nop; break; case 'k': drain++; p->setbreak(p, 1); sleep(n); p->setbreak(p, 0); break; case 'l': drain++; p->bits = n; set++; break; case 'm': drain++; p->modemctl(p, n); if(n == 0) p->cts = 0; break; case 'n': p->blocked = n; ++nop; break; case 'p': /* extended... */ if(strlen(f[i]) != 2) return -1; drain++; par = f[i][2]; if(par == 'n') p->parity = 0; else if(par == 'o') p->parity = 1; else if(par == 'e') p->parity = 2; else if(par == 'm') /* mark parity */ p->parity = 3; else if(par == 's') /* space parity */ p->parity = 4; else return -1; set++; break; case 'q': // drain++; p->limit = n; ++nop; break; case 'r': drain++; p->rts = n; lines++; break; case 's': drain++; p->stop = n; set++; break; case 'w': /* ?? how do I put this */ p->timer = n * 100000LL; ++nop; break; case 'x': if(n == 0) x = CTLS; else x = CTLQ; nw = write(p->epout->dfd, &x, 1); if(nw != 1){ serialrecover(p, ""); return -1; } break; } if (nop) fprint(2, "serial: %c, unsupported nop ctl\n", c); } if(drain) serialdrain(p); if(lines && !set) p->sendlines(p); else if(set && p->setparam(p) < 0) return -1; return 0; } char *pformat = "noems"; char * dumpstatus(Serial *ser, char *buf, int bufsz) { char *e, *s; e = buf + bufsz; s = seprint(buf, e, "b%d ", ser->baud); s = seprint(s, e, "c%d ", ser->dcd); /* unimplemented */ s = seprint(s, e, "d%d ", ser->dtr); s = seprint(s, e, "e%d ", ser->dsr); /* unimplemented */ s = seprint(s, e, "l%d ", ser->bits); s = seprint(s, e, "m%d ", ser->mctl); if(ser->parity >= 0 || ser->parity < strlen(pformat)) s = seprint(s, e, "p%c ", pformat[ser->parity]); else s = seprint(s, e, "p%c ", '?'); s = seprint(s, e, "r%d ", ser->rts); s = seprint(s, e, "s%d ", ser->stop); s = seprint(s, e, "i%d ", ser->fifo); s = seprint(s, e, "\ndev(%d) ", 0); s = seprint(s, e, "type(%d) ", ser->type); s = seprint(s, e, "framing(%d) ", ser->nframeerr); s = seprint(s, e, "overruns(%d) ", ser->novererr); s = seprint(s, e, "berr(%d) ", ser->nbreakerr); s = seprint(s, e, " serr(%d) ", ser->nparityerr); return s; } static int serinit(Serial *ser) { int res; res = ser->init(ser); ser->nframeerr = ser->nparityerr = ser->nbreakerr = ser->novererr = 0; return res; } static int dwalk(Usbfs *fs, Fid *fid, char *name) { int i; char *dname; Qid qid; Serial *ser; qid = fid->qid; if((qid.type & QTDIR) == 0){ werrstr("walk in non-directory"); return -1; } if(strcmp(name, "..") == 0){ /* must be /eiaU%d; i.e. our root dir. */ fid->qid.path = Qroot | fs->qid; fid->qid.vers = 0; fid->qid.type = QTDIR; return 0; } ser = fs->aux; for(i = 1; i < nelem(dirtab); i++){ dname = smprint(dirtab[i].name, ser->fs.name); if(strcmp(name, dname) == 0){ qid.path = i | fs->qid; qid.vers = 0; qid.type = dirtab[i].mode >> 24; fid->qid = qid; free(dname); return 0; } else free(dname); } werrstr(Enotfound); return -1; } static void dostat(Usbfs *fs, int path, Dir *d) { Dirtab *t; Serial *ser; t = &dirtab[path]; d->qid.path = path; d->qid.type = t->mode >> 24; d->mode = t->mode; ser = fs->aux; if(strcmp(t->name, "/") == 0) d->name = t->name; else snprint(d->name, Namesz, t->name, ser->fs.name); d->length = 0; } static int dstat(Usbfs *fs, Qid qid, Dir *d) { int path; path = qid.path & ~fs->qid; dostat(fs, path, d); d->qid.path |= fs->qid; return 0; } static int dopen(Usbfs *fs, Fid *fid, int) { ulong path; // Serial *ser; path = fid->qid.path & ~fs->qid; // ser = fs->aux; switch(path){ /* BUG: unneeded? */ case Qdata: dsprint(2, "serial, opened data\n"); break; case Qctl: dsprint(2, "serial, opened ctl\n"); break; } return 0; } static void filldir(Usbfs *fs, Dir *d, Dirtab *tab, int i) { d->qid.path = i | fs->qid; d->mode = tab->mode; if((d->mode & DMDIR) != 0) d->qid.type = QTDIR; else d->qid.type = QTFILE; d->name = tab->name; } static int dirgen(Usbfs *fs, Qid, int i, Dir *d, void *) { Dirtab *tab; i++; /* skip root */ if(i < nelem(dirtab)) tab = &dirtab[i]; else return -1; filldir(fs, d, tab, i); return 0; } static long dread(Usbfs *fs, Fid *fid, void *data, long count, vlong offset) { int dfd; long rcount; ulong path; char *buf, *err; /* change */ char *e; Qid q; Serial *ser; q = fid->qid; path = fid->qid.path & ~fs->qid; ser = fs->aux; buf = emallocz(255, 1); err = emallocz(255, 1); qlock(ser); switch(path){ case Qroot: count = usbdirread(fs, q, data, count, offset, dirgen, nil); break; case Qdata: if(debugport && count > 8) count = 8; if(0)dsprint(2, "serial: reading from data\n"); do { dfd = ser->epin->dfd; qunlock(ser); err[0] = 0; rcount = read(dfd, data, count); qlock(ser); if(rcount < 0) snprint(err, 255, "%r"); } while(rcount < 0 && strstr(err, "timed out") != nil); if(rcount < 0){ dsprint(2, "serial: need to recover, data read %ld %r\n", count); serialrecover(ser, err); } if(0)dsprint(2, "serial: read from bulk %ld\n", rcount); count = rcount; break; case Qctl: if(offset != 0){ count = 0; break; } e = dumpstatus(ser, buf, 255); count = usbreadbuf(data, count, 0, buf, e - buf); break; } qunlock(ser); free(err); free(buf); return count; } static long dwrite(Usbfs *fs, Fid *fid, void *buf, long count, vlong) { int nw; ulong path; char *cmd; char err[40]; Serial *ser; ser = fs->aux; path = fid->qid.path & ~fs->qid; qlock(ser); switch(path){ case Qdata: nw = write(ser->epout->dfd, buf, count); if(nw != count){ dsprint(2, "serial: need to recover, status read %d %r\n", nw); snprint(err, sizeof err, "%r"); serialrecover(ser, err); } count = nw; break; case Qctl: cmd = emallocz(count+1, 1); memmove(cmd, buf, count); cmd[count] = 0; if(serialctl(ser, cmd) < 0){ qunlock(ser); werrstr(Ebadctl); free(cmd); return -1; } free(cmd); break; default: qunlock(ser); werrstr(Eperm); return -1; } qunlock(ser); return count; } static int openeps(Serial *ser, int epin, int epout, int epintr) { ser->epin = openep(ser->dev, epin); if(ser->epin == nil){ fprint(2, "serial: openep %d: %r\n", epin); return -1; } ser->epout = openep(ser->dev, epout); if(ser->epout == nil){ fprint(2, "serial: openep %d: %r\n", epout); closedev(ser->epin); return -1; } if(ser->hasepintr){ ser->epintr = openep(ser->dev, epintr); if(ser->epintr == nil){ fprint(2, "serial: openep %d: %r\n", epintr); closedev(ser->epin); closedev(ser->epout); return -1; } opendevdata(ser->epintr, OREAD); } if(debugport){ /* * Debug port uses 8 as maxpkt. * There should be a Serialops op to * customize the device at this point. */ devctl(ser->epin, "maxpkt 8"); devctl(ser->epout, "maxpkt 8"); } opendevdata(ser->epin, OREAD); opendevdata(ser->epout, OWRITE); if(ser->epin->dfd < 0 || ser->epout->dfd < 0 || (ser->hasepintr && ser->epintr->dfd < 0)){ fprint(2, "serial: open i/o ep data: %r\n"); closedev(ser->epin); closedev(ser->epout); if(ser->hasepintr) closedev(ser->epintr); return -1; } return 0; } static int findendpoints(Serial *ser) { int i, epin, epout, epintr; Ep *ep; Usbdev *ud; epintr = epin = epout = -1; ud = ser->dev->usb; for(i = 0; i < nelem(ud->ep); i++){ if((ep = ud->ep[i]) == nil) continue; if(ser->hasepintr && ep->type == Eintr && ep->dir == Ein && epintr == -1) epintr = ep->id; if(ep->type == Ebulk){ if(ep->dir == Ein && epin == -1) epin = ep->id; if(ep->dir == Eout && epout == -1) epout = ep->id; } } dprint(2, "serial: ep ids: in %d out %d intr %d\n", epin, epout, epintr); if(epin == -1 || epout == -1 || (ser->hasepintr && epintr == -1)) return -1; if(openeps(ser, epin, epout, epintr) < 0) return -1; dprint(2, "serial: ep in %s out %s\n", ser->epin->dir, ser->epout->dir); if(ser->hasepintr) dprint(2, "disk: ep intr %s\n", ser->epintr->dir); if(usbdebug > 1 || serialdebug > 2){ devctl(ser->epin, "debug 1"); devctl(ser->epout, "debug 1"); if(ser->hasepintr) devctl(ser->epintr, "debug 1"); devctl(ser->dev, "debug 1"); } return 0; } static int usage(void) { werrstr("usage: usb/serial [-dkmn] [-a n]"); return -1; } static void serdevfree(void *a) { Serial *ser = a; if(ser == nil) return; if(ser->hasepintr) closedev(ser->epintr); closedev(ser->epin); closedev(ser->epout); ser->epintr = ser->epin = ser->epout = nil; free(ser); } static Usbfs serialfs = { .walk = dwalk, .open = dopen, .read = dread, .write= dwrite, .stat = dstat, }; int serialmain(Dev *dev, int argc, char* argv[]) { Serial *ser; char buf[50]; ARGBEGIN{ case 'd': serialdebug++; break; default: return usage(); }ARGEND if(argc != 0) return usage(); ser = dev->aux = emallocz(sizeof(Serial), 1); ser->dev = dev; dev->free = serdevfree; snprint(buf, sizeof buf, "vid %#06x did %#06x", dev->usb->vid, dev->usb->did); ser->fs = serialfs; debugport = 0; if(plmatch(buf) == 0){ ser->hasepintr = 1; ser->Serialops = plops; } else if(uconsmatch(buf) == 0){ ser->Serialops = uconsops; debugport = 1; } if(findendpoints(ser) < 0){ werrstr("serial: endpoints not found"); return -1; } if(serinit(ser) < 0){ dprint(2, "serial: serinit: %r\n"); return -1; } snprint(ser->fs.name, sizeof(ser->fs.name), "eiaU%d", dev->id); ser->fs.dev = dev; incref(dev); ser->fs.aux = ser; usbfsadd(&ser->fs); closedev(dev); return 0; } atoi(f[i]+1); c = *f[i]; if (isascii(c) && isupper(c)) c = tolower(c); switch(c){ case 'b': drain++; p->baud = n; set++; break; case 'c': p->dcd = n; // liserial/serial.h 664 0 0 3062 11214505104 12104ustar00paureasystypedef struct Serialops Serialops; typedef struct Serial Serial; struct Serialops { int (*init)(Serial*); int (*getparam)(Serial*); int (*setparam)(Serial*); int (*clearpipes)(Serial*); int (*sendlines)(Serial*); int (*modemctl)(Serial*, int); int (*setbreak)(Serial*, int); int (*readstatus)(Serial*); }; struct Serial { QLock; Dev *dev; /* usb device*/ Dev *ep; /* endpoint to get events */ Dev *epintr; Dev *epin; Dev *epout; Usbfs fs; int type; int recover; int hasepintr; uchar ctlstate; /* serial parameters */ uint baud; int stop; int mctl; int parity; int bits; int fifo; int limit; int rts; int cts; int dsr; int dcd; int dtr; vlong timer; int blocked; /* for sw flow ctl. BUG: not implemented yet */ int nbreakerr; int ring; int nframeerr; int nparityerr; int novererr; int enabled; Serialops; }; enum { /* soft flow control chars */ CTLS = 023, CTLQ = 021, }; /* * !hget http://lxr.linux.no/source/drivers/usb/serial/pl2303.h|htmlfmt * !hget http://lxr.linux.no/source/drivers/usb/serial/pl2303.c|htmlfmt */ int serialmain(Dev *d, int argc, char *argv[]); typedef struct Cinfo Cinfo; struct Cinfo { int vid; /* usb vendor id */ int did; /* usb device/product id */ int cid; /* controller id assigned by us */ }; extern Cinfo plinfo[]; extern Cinfo uconsinfo[]; extern int serialdebug; #define dsprint if(serialdebug)fprint int serialrecover(Serial *ser, char *err); int serialreset(Serial *ser); char *dumpstatus(Serial *ser, char *buf, int bufsz); int serialnop(Serial *); int serialnopctl(Serial *, int); en(pformat)) s = seprint(s, e, "p%c ", pformat[ser->parity]); else s = seprint(s, e, "p%c ", '?'); s = seprint(s, e, "r%d ", ser->rts); s = seprint(s, e, "s%d ", ser->stop); s = seprint(s, e, "i%d ", ser->fifo); s = seprint(s, e, "\ndev(%d) ", 0); s = seprint(s, e, "type(%d) ", ser->type); s = seprint(s, e, "framing(%d) ", ser->nframeerr); s = seprint(s, e, "overruns(%d) ", ser->novererr); s = seprint(s, e, "berr(%d) ", ser->nbreakerr); s = seserial/ucons.c 664 0 0 1241 11214505347 11755ustar00paureasys#include #include #include #include "usb.h" #include "usbfs.h" #include "serial.h" #include "ucons.h" Cinfo uconsinfo[] = { { Net20DCVid, Net20DCDid }, { 0, 0 }, }; int uconsmatch(char *info) { Cinfo *ip; char buf[50]; for(ip = uconsinfo; ip->vid != 0; ip++){ snprint(buf, sizeof buf, "vid %#06x did %#06x", ip->vid, ip->did); dsprint(2, "serial: %s %s", buf, info); if(strstr(info, buf) != nil) return 0; } return -1; } Serialops uconsops = { .init = serialnop, .getparam = serialnop, .setparam = serialnop, .clearpipes = serialnop, .sendlines = serialnop, .modemctl = serialnopctl, .setbreak = serialnopctl, }; me, ser->fs.name); d->length = 0; } static int dstat(Usbfs *fs, Qid qid, Dir *d) { int path; path = qid.path & ~fs->qid; dostat(fs, path, d); d->qid.path |= fs->qid; return 0; } static int dopen(Usbfs *fs, Fid *fid, int) { ulong path; // Serial *ser; path = fid->qid.path & ~fs->qid; // ser = fs->aux; switch(path){ /* BUG: unneeded? serial/ucons.h 664 0 0 214 11214504351 11733ustar00paureasys enum { Net20DCVid = 0x0525, /* Ajays usb debug cable */ Net20DCDid = 0x127a, }; int uconsmatch(char *info); extern Serialops uconsops;