static int plsetparam(Serialport *p) { uint8_t buf[ParamReqSz]; int res; Serial *ser; ser = p->s; PUT4(buf, p->baud); if(p->stop == 1) buf[4] = 0; else if(p->stop == 2) buf[4] = 2; /* see comment in getparam */ buf[5] = p->parity; buf[6] = p->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(p, p->mctl); plgetparam(p); /* make sure our state corresponds */ dsprint(2, "serial: setparam res: %d\n", res); return res; }
static int ftinit(Serialport *p) { Serial *ser; uint timerval; int res; ser = p->s; if(p->isjtag) { res = ftdiwrite(p, FTSETFLOWCTRL, 0, FTDISABLEFLOWCTRL); if(res < 0) return -1; res = ftdiread(p, FTSETLATENCYTIMER, 0, (uchar *)&timerval, FTLATENCYTIMERSZ); if(res < 0) return -1; dsprint(2, "serial: jtag latency timer is %d\n", timerval); timerval = 2; ftdiwrite(p, FTLATENCYDEFAULT, 0, FTSETLATENCYTIMER); res = ftdiread(p, FTSETLATENCYTIMER, 0, (uchar *)&timerval, FTLATENCYTIMERSZ); if(res < 0) return -1; dsprint(2, "serial: jtag latency timer set to %d\n", timerval); /* 0xb is the mask for lines. plug dependant? */ ftdiwrite(p, BMMPSSE|0x0b, 0, FTSETBITMODE); } incref(ser->dev); proccreate(statusreader, p, 8*1024); return 0; }
static int ftsendlines(Serialport *p) { int res; dsprint(2, "serial: sendlines: %#2.2x\n", p->ctlstate); res = setctl(p); dsprint(2, "serial: sendlines res: %d\n", res); return 0; }
static int plinit(Serialport *p) { char *st; uint8_t *buf; uint32_t csp, maxpkt, dno; Serial *ser; ser = p->s; buf = emallocz(VendorReqSz, 1); dsprint(2, "plinit\n"); csp = ser->dev->usb->csp; maxpkt = ser->dev->maxpkt; dno = ser->dev->usb->dno; if((ser->type = revid(dno)) == TypeUnk) ser->type = heuristicid(csp, maxpkt); dsprint(2, "serial: type %d\n", ser->type); vendorread(p, 0x8484, 0, buf); vendorwrite(p, 0x0404, 0); vendorread(p, 0x8484, 0, buf); vendorread(p, 0x8383, 0, buf); vendorread(p, 0x8484, 0, buf); vendorwrite(p, 0x0404, 1); vendorread(p, 0x8484, 0, buf); vendorread(p, 0x8383, 0, buf); vendorwrite(p, Dcr0Idx|DcrSet, Dcr0Init); vendorwrite(p, Dcr1Idx|DcrSet, Dcr1Init); if(ser->type == TypeHX) vendorwrite(p, Dcr2Idx|DcrSet, Dcr2InitX); else vendorwrite(p, Dcr2Idx|DcrSet, Dcr2InitH); plgetparam(p); qunlock(ser); free(buf); st = emallocz(255, 1); qlock(ser); if(serialdebug) serdumpst(p, st, 255); dsprint(2, st); free(st); /* p gets freed by closedev, the process has a reference */ incref(ser->dev); proccreate(statusreader, p, 8*1024); return 0; }
static int vendorwrite(Serialport *p, int val, int index) { int res; Serial *ser; ser = p->s; 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 vendorread(Serialport *p, int val, int index, uint8_t *buf) { int res; Serial *ser; ser = p->s; dsprint(2, "serial: vendorread val: 0x%x idx:%d buf:%p\n", val, index, buf); res = usbcmd(ser->dev, Rd2h | Rvendor | Rdev, VendorReadReq, val, index, buf, 1); dsprint(2, "serial: vendorread res:%d\n", res); return res; }
static int ftsetparam(Serialport *p) { int res; ushort val; ulong bauddiv; val = 0; if(p->stop == 1) val |= FTSETDATASTOPBITS1; else if(p->stop == 2) val |= FTSETDATASTOPBITS2; else if(p->stop == 15) val |= FTSETDATASTOPBITS15; switch(p->parity) { case 0: val |= FTSETDATAParNONE; break; case 1: val |= FTSETDATAParODD; break; case 2: val |= FTSETDATAParEVEN; break; case 3: val |= FTSETDATAParMARK; break; case 4: val |= FTSETDATAParSPACE; break; }; dsprint(2, "serial: setparam\n"); res = ftdiwrite(p, val, 0, FTSETDATA); if(res < 0) return res; res = ftmodemctl(p, p->mctl); if(res < 0) return res; bauddiv = ftbaudcalcdiv(p->s, p->baud); res = ftdiwrite(p, bauddiv, (bauddiv>>16) & 1, FTSETBAUDRATE); dsprint(2, "serial: setparam res: %d\n", res); return res; }
static int ftdiread(Serialport *p, int index, int req, uchar *buf, int len) { int res; Serial *ser; ser = p->s; if(req != FTGETE2READ) index |= p->interfc + 1; dsprint(2, "serial: ftdiread %#p [%d] req: %#x val: %#x idx:%d buf:%p len:%d\n", p, p->interfc, req, 0, index, buf, len); res = usbcmd(ser->dev, Rd2h | Rftdireq | Rdev, req, 0, index, buf, len); dsprint(2, "serial: ftdiread res:%d\n", res); return res; }
static int ftdiwrite(Serialport *p, int val, int index, int req) { int res; Serial *ser; ser = p->s; if(req != FTGETE2READ || req != FTSETE2ERASE || req != FTSETBAUDRATE) index |= p->interfc + 1; dsprint(2, "serial: ftdiwrite %#p [%d] req: %#x val: %#x idx:%d\n", p, p->interfc, req, val, index); res = usbcmd(ser->dev, Rh2d | Rftdireq | Rdev, req, val, index, nil, 0); dsprint(2, "serial: ftdiwrite res:%d\n", res); return res; }
static void statusreader(void *u) { Areader *a; Channel *c; Packser *pk; Serialport *p; Serial *ser; int cl; p = u; ser = p->s; threadsetname("statusreader thread"); /* big buffering, fewer bytes lost */ c = chancreate(sizeof(Packser *), 128); a = emallocz(sizeof(Areader), 1); a->p = p; a->c = c; incref(ser->dev); proccreate(epreader, a, 16*1024); while((pk = recvp(c)) != nil){ memmove(p->data, pk->b, pk->nb); p->ndata = pk->nb; free(pk); dsprint(2, "serial %p: status reader %d \n", p, p->ndata); /* consume it all */ while(p->ndata != 0){ dsprint(2, "serial %p: status reader to consume: %d\n", p, p->ndata); cl = recvul(p->w4data); if(cl < 0) break; cl = sendul(p->gotdata, 1); if(cl < 0) break; } } shutdownchan(c); devctl(ser->dev, "detach"); closedev(ser->dev); usbfsdel(&p->fs); }
static int plgetparam(Serialport *p) { uint8_t buf[ParamReqSz]; int res; Serial *ser; ser = p->s; res = usbcmd(ser->dev, Rd2h | Rclass | Riface, GetLineReq, 0, 0, buf, sizeof buf); p->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) p->stop = 1; else if(buf[4] == 2) p->stop = 2; p->parity = buf[5]; p->bits = buf[6]; dsprint(2, "serial: getparam: "); if(serialdebug) dumpbuf(buf, sizeof buf); dsprint(2, "serial: getparam res: %d\n", res); return res; }
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\n", buf, info); if(strstr(info, buf) != nil) return 0; } return -1; }
static int slinit(Serialport *p) { Serial *ser; ser = p->s; dsprint(2, "slinit\n"); slput(p, Enable, 1); slops.getparam(p); /* p gets freed by closedev, the process has a reference */ incref(ser->dev); return 0; }
int ftmatch(Serial *ser, char *info) { Cinfo *ip; char buf[50]; for(ip = ftinfo; ip->vid != 0; ip++){ snprint(buf, sizeof buf, "vid %#06x did %#06x", ip->vid, ip->did); dsprint(2, "serial: %s %s\n", buf, info); if(strstr(info, buf) != nil){ if(ser != nil){ qlock(ser); ftgettype(ser); qunlock(ser); } return 0; } } return -1; }
static int plreadstatus(Serialport *p) { int nr, dfd; char err[40]; uint8_t buf[VendorReqSz]; Serial *ser; ser = p->s; qlock(ser); dsprint(2, "serial: reading from interrupt\n"); dfd = p->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, nil, nil, err) < 0){ qunlock(ser); return -1; } } if(nr < 0) dsprint(2, "serial: reading status: %r"); else if(nr >= sizeof buf - 1){ p->dcd = buf[8] & DcdStatus; p->dsr = buf[8] & DsrStatus; p->cts = buf[8] & BreakerrStatus; p->ring = buf[8] & RingStatus; p->cts = buf[8] & CtsStatus; if(buf[8] & FrerrStatus) p->nframeerr++; if(buf[8] & ParerrStatus) p->nparityerr++; if(buf[8] & OvererrStatus) p->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; }
/* ser locked */ static void ftgettype(Serial *ser) { int i, outhdrsz, dno, pksz; ulong baudbase; Conf *cnf; pksz = Packsz; /* Assume it is not the original SIO device for now. */ baudbase = ClockNew / 2; outhdrsz = 0; dno = ser->dev->usb->dno; cnf = ser->dev->usb->conf[0]; ser->nifcs = 0; for(i = 0; i < Niface; i++) if(cnf->iface[i] != nil) ser->nifcs++; if(ser->nifcs > 1) { /* * Multiple interfaces. default assume FT2232C, */ if(dno == 0x500) ser->type = FT2232C; else if(dno == 0x600) ser->type = FTKINDR; else if(dno == 0x700) { ser->type = FT2232H; pksz = Maxpacksz; } else if(dno == 0x800) { ser->type = FT4232H; pksz = Maxpacksz; } else ser->type = FT2232C; if(hasjtag(ser->dev->usb)) ser->jtag = 0; /* * BM-type devices have a bug where dno gets set * to 0x200 when serial is 0. */ if(dno < 0x500) fprint(2, "serial: warning: dno %d too low for " "multi-interface device\n", dno); } else if(dno < 0x200) { /* Old device. Assume it is the original SIO. */ ser->type = SIO; baudbase = ClockOld/16; outhdrsz = 1; } else if(dno < 0x400) /* * Assume its an FT8U232AM (or FT8U245AM) * (It might be a BM because of the iSerialNumber bug, * but it will still work as an AM device.) */ ser->type = FT8U232AM; else /* Assume it is an FT232BM (or FT245BM) */ ser->type = FT232BM; ser->maxrtrans = ser->maxwtrans = pksz; ser->baudbase = baudbase; ser->outhdrsz = outhdrsz; ser->inhdrsz = 2; ser->Serialops = ftops; dsprint (2, "serial: detected type: %#x\n", ser->type); }
static void epreader(void *u) { int dfd, rcount, cl, ntries, recov; Areader *a; Channel *c; Packser *pk; Serial *ser; Serialport *p; threadsetname("epreader proc"); a = u; p = a->p; ser = p->s; c = a->c; free(a); qlock(ser); /* this makes the reader wait end of initialization too */ dfd = p->epin->dfd; qunlock(ser); ntries = 0; pk = nil; for(;;) { if (pk == nil) pk = emallocz(sizeof(Packser), 1); Eagain: rcount = read(dfd, pk->b, sizeof pk->b); if(serialdebug > 5) dsprint(2, "%d %#ux%#ux ", rcount, p->data[0], p->data[1]); if(rcount < 0) { if(ntries++ > 100) break; qlock(ser); recov = serialrecover(ser, p, nil, "epreader: bulkin error"); qunlock(ser); if(recov >= 0) goto Eagain; } if(rcount == 0) continue; if(rcount >= ser->inhdrsz) { rcount = cpdata(ser, p, pk->b, pk->b, rcount); if(rcount != 0) { pk->nb = rcount; cl = sendp(c, pk); if(cl < 0) { /* * if it was a time-out, I don't want * to give back an error. */ rcount = 0; break; } } else free(pk); qlock(ser); ser->recover = 0; qunlock(ser); ntries = 0; pk = nil; } } if(rcount < 0) fprint(2, "%s: error reading %s: %r\n", argv0, p->name); free(pk); nbsendp(c, nil); if(p->w4data != nil) chanclose(p->w4data); if(p->gotdata != nil) chanclose(p->gotdata); devctl(ser->dev, "detach"); closedev(ser->dev); }