It now initializes the endpoints for jtag. Some errors in the ftdi protocol have been corrected too. Reference: /n/sources/patch/applied/serialjtag Date: Thu Dec 2 15:43:12 CET 2010 Signed-off-by: paurea@lsub.org --- /sys/src/cmd/usb/serial/serial.c Thu Dec 2 15:42:10 2010 +++ /sys/src/cmd/usb/serial/serial.c Thu Dec 2 15:42:06 2010 @@ -32,8 +32,8 @@ static Dirtab dirtab[] = { [Qroot] "/", DMDIR|0555, - [Qdata] "eiaU", 0660, - [Qctl] "eiaUctl", 0664, + [Qdata] "%s", 0660, + [Qctl] "%sctl", 0664, }; static int sdebug; @@ -49,8 +49,6 @@ for(i = 0; i < ser->nifcs; i++){ p = &ser->p[i]; - if(p->isjtag) - continue; usbfsdel(&p->fs); if(p->w4data != nil) chanclose(p->w4data); @@ -93,8 +91,6 @@ /* cmd for reset */ for(i = 0; i < ser->nifcs; i++){ p = &ser->p[i]; - if(p->isjtag) - continue; serialdrain(p); } if(ser->reset != nil) @@ -342,7 +338,7 @@ p = fs->aux; for(i = 1; i < nelem(dirtab); i++){ - dname = smprint(dirtab[i].name, p->fs.name); + dname = smprint(dirtab[i].name, p->name); if(strcmp(name, dname) == 0){ qid.path = i | fs->qid; qid.vers = 0; @@ -401,6 +397,8 @@ break; case Qctl: dsprint(2, "serial, opened ctl\n"); + if(p->isjtag) + return 0; serialctl(p, "l8 i1"); /* default line parameters */ break; } @@ -409,24 +407,27 @@ static void -filldir(Usbfs *fs, Dir *d, Dirtab *tab, int i) +filldir(Usbfs *fs, Dir *d, Dirtab *tab, int i, void *v) { + Serialport *p; + + p = v; 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; + sprint(d->name, tab->name, p->name); } static int -dirgen(Usbfs *fs, Qid, int i, Dir *d, void *) +dirgen(Usbfs *fs, Qid, int i, Dir *d, void *p) { i++; /* skip root */ if(i >= nelem(dirtab)) return -1; - filldir(fs, d, &dirtab[i], i); + filldir(fs, d, &dirtab[i], i, p); return 0; } @@ -456,7 +457,7 @@ qlock(ser); switch(path){ case Qroot: - count = usbdirread(fs, q, data, count, offset, dirgen, nil); + count = usbdirread(fs, q, data, count, offset, dirgen, p); break; case Qdata: if(count > ser->maxread) @@ -513,8 +514,10 @@ if(offset != 0) count = 0; else { - e = serdumpst(p, buf, Serbufsize); - count = usbreadbuf(data, count, 0, buf, e - buf); + if(!p->isjtag){ + e = serdumpst(p, buf, Serbufsize); + count = usbreadbuf(data, count, 0, buf, e - buf); + } } break; } @@ -533,6 +536,8 @@ ser = p->s; do{ + dsprint(2, "serial: write to bulk %ld\n", count); + if(ser->wait4write != nil) /* unlocked inside later */ nw = ser->wait4write(p, buf, count); @@ -543,6 +548,7 @@ qlock(ser); } rerrstr(err, sizeof err); + dsprint(2, "serial: written %s %d\n", err, nw); } while(nw < 0 && strstr(err, "timed out") != nil); if(nw != count){ @@ -572,6 +578,8 @@ count = altwrite(p, (uchar *)buf, count); break; case Qctl: + if(p->isjtag) + break; cmd = emallocz(count+1, 1); memmove(cmd, buf, count); cmd[count] = 0; @@ -610,8 +618,10 @@ return -1; } - devctl(p->epin, "timeout 1000"); - devctl(p->epout, "timeout 1000"); + if(!p->isjtag){ + devctl(p->epin, "timeout 1000"); + devctl(p->epout, "timeout 1000"); + } if(ser->hasepintr){ p->epintr = openep(ser->dev, epintr); @@ -646,10 +656,8 @@ { int i, epin, epout, epintr; Ep *ep, **eps; - ///Usbdev *ud; epintr = epin = epout = -1; - //ud = ser->dev->usb; /* * interfc 0 means start from the start which is equiv to @@ -798,12 +806,11 @@ for(i = 0; i < ser->nifcs; i++){ p = &ser->p[i]; p->interfc = i; + p->s = ser; + p->fs = serialfs; if(i == ser->jtag){ p->isjtag++; - continue; } - p->s = ser; - p->fs = serialfs; if(findendpoints(ser, i) < 0){ werrstr("serial: no endpoints found for ifc %d", i); return -1; @@ -816,10 +823,6 @@ serialreset(ser); for(i = 0; i < ser->nifcs; i++){ p = &ser->p[i]; - if(p->isjtag){ - dsprint(2, "serial: ignoring JTAG interface %d %p\n", i, p); - continue; - } dprint(2, "serial: valid interface, calling serinit\n"); if(serinit(p) < 0){ dprint(2, "serial: serinit: %r\n"); @@ -827,10 +830,17 @@ } dsprint(2, "serial: adding interface %d, %p\n", p->interfc, p); - if(i == 0) - snprint(p->fs.name, sizeof p->fs.name, "eiaU%d", devid); - else - snprint(p->fs.name, sizeof p->fs.name, "eiaU%d.%d", devid, i); + if(p->isjtag){ + sprint(p->name, "jtag"); + dsprint(2, "serial: JTAG interface %d %p\n", i, p); + snprint(p->fs.name, sizeof p->fs.name, "jtag%d.%d", devid, i); + } else { + sprint(p->name, "eiaU"); + if(i == 0) + snprint(p->fs.name, sizeof p->fs.name, "eiaU%d", devid); + else + snprint(p->fs.name, sizeof p->fs.name, "eiaU%d.%d", devid, i); + } fprint(2, "%s\n", p->fs.name); p->fs.dev = dev; incref(dev); --- /sys/src/cmd/usb/serial/serial.h Thu Dec 2 15:42:19 2010 +++ /sys/src/cmd/usb/serial/serial.h Thu Dec 2 15:42:15 2010 @@ -24,6 +24,7 @@ struct Serialport { + char name[32]; Serial *s; /* device we belong to */ int isjtag; --- /sys/src/cmd/usb/serial/ftdi.c Thu Dec 2 15:42:30 2010 +++ /sys/src/cmd/usb/serial/ftdi.c Thu Dec 2 15:42:23 2010 @@ -211,7 +211,7 @@ }; static int -ftdiread(Serialport *p, int val, int index, int req, uchar *buf) +ftdiread(Serialport *p, int index, int req, uchar *buf, int len) { int res; Serial *ser; @@ -220,9 +220,9 @@ if(req != FTGETE2READ) index |= p->interfc + 1; - dsprint(2, "serial: ftdiread %#p [%d] req: %#x val: %#x idx:%d buf:%p\n", - p, p->interfc, req, val, index, buf); - res = usbcmd(ser->dev, Rd2h | Rftdireq | Rdev, req, val, index, buf, 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; } @@ -235,7 +235,8 @@ ser = p->s; - index |= p->interfc + 1; + 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); @@ -445,7 +446,7 @@ return res; bauddiv = ftbaudcalcdiv(p->s, p->baud); - res = ftdiwrite(p, bauddiv, (bauddiv>>16) & 1, FTSETBaudRate); + res = ftdiwrite(p, bauddiv, (bauddiv>>16) & 1, FTSETBAUDRATE); dsprint(2, "serial: setparam res: %d\n", res); return res; @@ -762,11 +763,11 @@ memmove(p->data, pk->b, pk->nb); p->ndata = pk->nb; free(pk); - dsprint(2, "serial: status reader %d \n", p->ndata); + dsprint(2, "serial %p: status reader %d \n", p, p->ndata); /* consume it all */ while(p->ndata != 0){ - dsprint(2, "serial: status reader to consume: %d\n", - p->ndata); + dsprint(2, "serial %p: status reader to consume: %d\n", + p, p->ndata); cl = recvul(p->w4data); if(cl < 0) break; @@ -790,7 +791,7 @@ p = ser->p; for(i = 0; i < Maxifc; i++) - if(!p[i].isjtag && p[i].s != nil) + if(p[i].s != nil) ftdiwrite(&p[i], FTRESETCTLVAL, 0, FTRESET); return 0; } @@ -799,8 +800,31 @@ 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); + /* may be unnecessary */ + devctl(p->epin, "timeout 5000"); + devctl(p->epout, "timeout 5000"); + /* 0xb is the mask for lines. plug dependant? */ + ftdiwrite(p, BMMPSSE|0x0b, 0, FTSETBITMODE); + } incref(ser->dev); threadcreate(statusreader, p, 8*1024); return 0; --- /sys/src/cmd/usb/serial/ftdi.h Thu Dec 2 15:42:39 2010 +++ /sys/src/cmd/usb/serial/ftdi.h Thu Dec 2 15:42:34 2010 @@ -393,18 +393,25 @@ FTRESET = 0, /* Reset the port */ FTSETMODEMCTRL, /* Set the modem control register */ FTSETFLOWCTRL, /* Set flow control register */ - FTSETBaudRate, /* Set baud rate */ + FTSETBAUDRATE, /* Set baud rate */ FTSETDATA, /* Set the parameters, parity */ FTGETMODEMSTATUS, /* Retrieve current value of modem ctl */ FTSETEVENTCHAR, /* Set the event character */ FTSETERRORCHAR, /* Set the error character */ + FTUNKNOWN, FTSETLATENCYTIMER, /* Set the latency timer */ FTGETLATENCYTIMER, /* Get the latency timer */ - FTSETBITMODE, /* Set bigbang mode */ + FTSETBITMODE, /* Set bit mode */ FTGETPINS, /* Read pins state */ - FTGETE2READ = 0x90, /* Read an address from EEPROM */ - FTSETE2WRITE, /* Write to address on the EEPROM */ - FTSETE2ERASE, /* Erase address on the EEPROM */ + FTGETE2READ = 0x90, /* Read an address from 128-byte I2C EEPROM */ + FTSETE2WRITE, /* Write to address on the 128-byte I2C EEPROM */ + FTSETE2ERASE, /* Erase address on the 128-byte I2C EEPROM */ +}; + +/* Port Identifier Table, index for interfaces */ +enum { + PITDEFAULT = 0, /* SIOA */ + PITA, /* SIOA jtag if there is one */ }; enum { @@ -417,22 +424,31 @@ * Gets have wValue = 0 */ enum { - FTGETMODEMSTATUSSZ = 1, - FTGETLATENCYTIMERSZ = 0, /* Get the latency timer */ - FTGETE2READSZ = 2, /* Read an address */ + FTMODEMSTATUSSZ = 1, + FTLATENCYTIMERSZ = 1, + FTPINSSZ = 1, + FTE2READSZ = 2, }; /* * bRequest: FTGETE2READ * wIndex: Address of word to read - * Data: Will return a word of data from E2Address + * Data: Will return a word (2 bytes) of data from E2Address + * Results put in the I2C 128 byte EEPROM string eeprom+(2*index) */ -/* Port Identifier Table */ -enum { - PITDEFAULT = 0, /* SIOA */ - PITA, /* SIOA */ -}; +/* + * bRequest: FTSETE2WRITE + * wIndex: Address of word to read + * wValue: Value of the word + * Data: Will return a word (2 bytes) of data from E2Address + */ + +/* + * bRequest: FTSETE2ERASE + * Erases the EEPROM + * wIndex: 0 + */ /* * bRequest: FTRESET @@ -447,7 +463,7 @@ /* * BmRequestType: SET - * bRequest: FTSETBaudRate + * bRequest: FTSETBAUDRATE * wValue: BaudDivisor value - see below * Bits 15 to 0 of the 17-bit divisor are placed in the request value. * Bit 16 is placed in bit 0 of the request index. @@ -480,6 +496,7 @@ /* * bRequest: FTSETDATA * wValue: Data characteristics + * bits 0-7 number of data bits * wIndex: Port */ enum { @@ -520,25 +537,60 @@ */ /* + * bRequest: FTSETBITMODE + * wIndex: Port + * either it is big bang mode, in which case + * wValue: 1 byte L is the big bang mode BIG* + * or BM is + * wValue: 1 byte bitbang mode H, 1 byte bitmask for lines L + */ +enum { + BMSERIAL = 0, /* reset, turn off bitbang mode */ + + BIGBMNORMAL = 1, /* normal big bang mode */ + BIGBMSPI = 2, /* spi big bang mode */ + + BMABM = 1<<8, /* async mode */ + BMMPSSE = 2<<8, + BMSYNCBB = 4<<8, /* sync bitbang -- 2232x and R-type */ + BMMCU = 8<<8, /* MCU Host Bus -- 2232x */ + BMOPTO = 0x10<<8, /* opto-isolated<<8, 2232x */ + BMCBUS = 0x20<<8, /* CBUS pins of R-type chips */ + BMSYNCFF = 0x40<<8, /* Single Channel Sync FIFO, 2232H only */ +}; + +/* * bRequest: FTSETLATENCYTIMER - * wValue: Latency (milliseconds) + * wValue: Latency (milliseconds 1-255ms) * wIndex: Port */ +enum { + FTLATENCYDEFAULT = 2, +}; /* * BmRequestType: SET * bRequest: FTSETEVENTCHAR * wValue: EventChar * wIndex: Port + * 0-7 lower bits event char + * 8 enable */ +enum { + FTEVCHARENAB = 1<<8, +}; /* * BmRequestType: SET * bRequest: FTSETERRORCHAR * wValue: Error Char * wIndex: Port + * 0-7 lower bits event char + * 8 enable */ - +enum { + FTERRCHARENAB = 1<<8, +}; /* * BmRequestType: GET * bRequest: FTGETMODEMSTATUS