added nusb/serial
This commit is contained in:
parent
2ba1b4c476
commit
9f4184892c
10 changed files with 3297 additions and 0 deletions
|
@ -5,6 +5,8 @@ DIRS=\
|
||||||
kb\
|
kb\
|
||||||
audio\
|
audio\
|
||||||
usbd\
|
usbd\
|
||||||
|
disk\
|
||||||
|
serial\
|
||||||
|
|
||||||
UPDATE=\
|
UPDATE=\
|
||||||
mkfile\
|
mkfile\
|
||||||
|
|
960
sys/src/cmd/nusb/serial/ftdi.c
Normal file
960
sys/src/cmd/nusb/serial/ftdi.c
Normal file
|
@ -0,0 +1,960 @@
|
||||||
|
/* Future Technology Devices International serial ports */
|
||||||
|
#include <u.h>
|
||||||
|
#include <libc.h>
|
||||||
|
#include <thread.h>
|
||||||
|
#include <fcall.h>
|
||||||
|
#include <9p.h>
|
||||||
|
#include "usb.h"
|
||||||
|
#include "serial.h"
|
||||||
|
#include "ftdi.h"
|
||||||
|
|
||||||
|
/*
|
||||||
|
* BUG: This keeps growing, there has to be a better way, but without
|
||||||
|
* devices to try it... We can probably simply look for FTDI in the
|
||||||
|
* string, or use regular expressions somehow.
|
||||||
|
*/
|
||||||
|
Cinfo ftinfo[] = {
|
||||||
|
{ FTVid, FTACTZWAVEDid },
|
||||||
|
{ FTSheevaVid, FTSheevaDid },
|
||||||
|
{ FTVid, FTOpenRDUltDid},
|
||||||
|
{ FTVid, FTIRTRANSDid },
|
||||||
|
{ FTVid, FTIPLUSDid },
|
||||||
|
{ FTVid, FTSIODid },
|
||||||
|
{ FTVid, FT8U232AMDid },
|
||||||
|
{ FTVid, FT8U232AMALTDid },
|
||||||
|
{ FTVid, FT8U2232CDid },
|
||||||
|
{ FTVid, FTRELAISDid },
|
||||||
|
{ INTERBIOMVid, INTERBIOMIOBRDDid },
|
||||||
|
{ INTERBIOMVid, INTERBIOMMINIIOBRDDid },
|
||||||
|
{ FTVid, FTXF632Did },
|
||||||
|
{ FTVid, FTXF634Did },
|
||||||
|
{ FTVid, FTXF547Did },
|
||||||
|
{ FTVid, FTXF633Did },
|
||||||
|
{ FTVid, FTXF631Did },
|
||||||
|
{ FTVid, FTXF635Did },
|
||||||
|
{ FTVid, FTXF640Did },
|
||||||
|
{ FTVid, FTXF642Did },
|
||||||
|
{ FTVid, FTDSS20Did },
|
||||||
|
{ FTNFRICVid, FTNFRICDid },
|
||||||
|
{ FTVid, FTVNHCPCUSBDDid },
|
||||||
|
{ FTVid, FTMTXORB0Did },
|
||||||
|
{ FTVid, FTMTXORB1Did },
|
||||||
|
{ FTVid, FTMTXORB2Did },
|
||||||
|
{ FTVid, FTMTXORB3Did },
|
||||||
|
{ FTVid, FTMTXORB4Did },
|
||||||
|
{ FTVid, FTMTXORB5Did },
|
||||||
|
{ FTVid, FTMTXORB6Did },
|
||||||
|
{ FTVid, FTPERLEULTRAPORTDid },
|
||||||
|
{ FTVid, FTPIEGROUPDid },
|
||||||
|
{ SEALEVELVid, SEALEVEL2101Did },
|
||||||
|
{ SEALEVELVid, SEALEVEL2102Did },
|
||||||
|
{ SEALEVELVid, SEALEVEL2103Did },
|
||||||
|
{ SEALEVELVid, SEALEVEL2104Did },
|
||||||
|
{ SEALEVELVid, SEALEVEL22011Did },
|
||||||
|
{ SEALEVELVid, SEALEVEL22012Did },
|
||||||
|
{ SEALEVELVid, SEALEVEL22021Did },
|
||||||
|
{ SEALEVELVid, SEALEVEL22022Did },
|
||||||
|
{ SEALEVELVid, SEALEVEL22031Did },
|
||||||
|
{ SEALEVELVid, SEALEVEL22032Did },
|
||||||
|
{ SEALEVELVid, SEALEVEL24011Did },
|
||||||
|
{ SEALEVELVid, SEALEVEL24012Did },
|
||||||
|
{ SEALEVELVid, SEALEVEL24013Did },
|
||||||
|
{ SEALEVELVid, SEALEVEL24014Did },
|
||||||
|
{ SEALEVELVid, SEALEVEL24021Did },
|
||||||
|
{ SEALEVELVid, SEALEVEL24022Did },
|
||||||
|
{ SEALEVELVid, SEALEVEL24023Did },
|
||||||
|
{ SEALEVELVid, SEALEVEL24024Did },
|
||||||
|
{ SEALEVELVid, SEALEVEL24031Did },
|
||||||
|
{ SEALEVELVid, SEALEVEL24032Did },
|
||||||
|
{ SEALEVELVid, SEALEVEL24033Did },
|
||||||
|
{ SEALEVELVid, SEALEVEL24034Did },
|
||||||
|
{ SEALEVELVid, SEALEVEL28011Did },
|
||||||
|
{ SEALEVELVid, SEALEVEL28012Did },
|
||||||
|
{ SEALEVELVid, SEALEVEL28013Did },
|
||||||
|
{ SEALEVELVid, SEALEVEL28014Did },
|
||||||
|
{ SEALEVELVid, SEALEVEL28015Did },
|
||||||
|
{ SEALEVELVid, SEALEVEL28016Did },
|
||||||
|
{ SEALEVELVid, SEALEVEL28017Did },
|
||||||
|
{ SEALEVELVid, SEALEVEL28018Did },
|
||||||
|
{ SEALEVELVid, SEALEVEL28021Did },
|
||||||
|
{ SEALEVELVid, SEALEVEL28022Did },
|
||||||
|
{ SEALEVELVid, SEALEVEL28023Did },
|
||||||
|
{ SEALEVELVid, SEALEVEL28024Did },
|
||||||
|
{ SEALEVELVid, SEALEVEL28025Did },
|
||||||
|
{ SEALEVELVid, SEALEVEL28026Did },
|
||||||
|
{ SEALEVELVid, SEALEVEL28027Did },
|
||||||
|
{ SEALEVELVid, SEALEVEL28028Did },
|
||||||
|
{ SEALEVELVid, SEALEVEL28031Did },
|
||||||
|
{ SEALEVELVid, SEALEVEL28032Did },
|
||||||
|
{ SEALEVELVid, SEALEVEL28033Did },
|
||||||
|
{ SEALEVELVid, SEALEVEL28034Did },
|
||||||
|
{ SEALEVELVid, SEALEVEL28035Did },
|
||||||
|
{ SEALEVELVid, SEALEVEL28036Did },
|
||||||
|
{ SEALEVELVid, SEALEVEL28037Did },
|
||||||
|
{ SEALEVELVid, SEALEVEL28038Did },
|
||||||
|
{ IDTECHVid, IDTECHIDT1221UDid },
|
||||||
|
{ OCTVid, OCTUS101Did },
|
||||||
|
{ FTVid, FTHETIRA1Did }, /* special quirk div = 240 baud = B38400 rtscts = 1 */
|
||||||
|
{ FTVid, FTUSBUIRTDid }, /* special quirk div = 77, baud = B38400 */
|
||||||
|
{ FTVid, PROTEGOSPECIAL1 },
|
||||||
|
{ FTVid, PROTEGOR2X0 },
|
||||||
|
{ FTVid, PROTEGOSPECIAL3 },
|
||||||
|
{ FTVid, PROTEGOSPECIAL4 },
|
||||||
|
{ FTVid, FTGUDEADSE808Did },
|
||||||
|
{ FTVid, FTGUDEADSE809Did },
|
||||||
|
{ FTVid, FTGUDEADSE80ADid },
|
||||||
|
{ FTVid, FTGUDEADSE80BDid },
|
||||||
|
{ FTVid, FTGUDEADSE80CDid },
|
||||||
|
{ FTVid, FTGUDEADSE80DDid },
|
||||||
|
{ FTVid, FTGUDEADSE80EDid },
|
||||||
|
{ FTVid, FTGUDEADSE80FDid },
|
||||||
|
{ FTVid, FTGUDEADSE888Did },
|
||||||
|
{ FTVid, FTGUDEADSE889Did },
|
||||||
|
{ FTVid, FTGUDEADSE88ADid },
|
||||||
|
{ FTVid, FTGUDEADSE88BDid },
|
||||||
|
{ FTVid, FTGUDEADSE88CDid },
|
||||||
|
{ FTVid, FTGUDEADSE88DDid },
|
||||||
|
{ FTVid, FTGUDEADSE88EDid },
|
||||||
|
{ FTVid, FTGUDEADSE88FDid },
|
||||||
|
{ FTVid, FTELVUO100Did },
|
||||||
|
{ FTVid, FTELVUM100Did },
|
||||||
|
{ FTVid, FTELVUR100Did },
|
||||||
|
{ FTVid, FTELVALC8500Did },
|
||||||
|
{ FTVid, FTPYRAMIDDid },
|
||||||
|
{ FTVid, FTELVFHZ1000PCDid },
|
||||||
|
{ FTVid, FTELVCLI7000Did },
|
||||||
|
{ FTVid, FTELVPPS7330Did },
|
||||||
|
{ FTVid, FTELVTFM100Did },
|
||||||
|
{ FTVid, FTELVUDF77Did },
|
||||||
|
{ FTVid, FTELVUIO88Did },
|
||||||
|
{ FTVid, FTELVUAD8Did },
|
||||||
|
{ FTVid, FTELVUDA7Did },
|
||||||
|
{ FTVid, FTELVUSI2Did },
|
||||||
|
{ FTVid, FTELVT1100Did },
|
||||||
|
{ FTVid, FTELVPCD200Did },
|
||||||
|
{ FTVid, FTELVULA200Did },
|
||||||
|
{ FTVid, FTELVCSI8Did },
|
||||||
|
{ FTVid, FTELVEM1000DLDid },
|
||||||
|
{ FTVid, FTELVPCK100Did },
|
||||||
|
{ FTVid, FTELVRFP500Did },
|
||||||
|
{ FTVid, FTELVFS20SIGDid },
|
||||||
|
{ FTVid, FTELVWS300PCDid },
|
||||||
|
{ FTVid, FTELVFHZ1300PCDid },
|
||||||
|
{ FTVid, FTELVWS500Did },
|
||||||
|
{ FTVid, LINXSDMUSBQSSDid },
|
||||||
|
{ FTVid, LINXMASTERDEVEL2Did },
|
||||||
|
{ FTVid, LINXFUTURE0Did },
|
||||||
|
{ FTVid, LINXFUTURE1Did },
|
||||||
|
{ FTVid, LINXFUTURE2Did },
|
||||||
|
{ FTVid, FTCCSICDU200Did },
|
||||||
|
{ FTVid, FTCCSICDU401Did },
|
||||||
|
{ FTVid, INSIDEACCESSO },
|
||||||
|
{ INTREDidVid, INTREDidVALUECANDid },
|
||||||
|
{ INTREDidVid, INTREDidNEOVIDid },
|
||||||
|
{ FALCOMVid, FALCOMTWISTDid },
|
||||||
|
{ FALCOMVid, FALCOMSAMBADid },
|
||||||
|
{ FTVid, FTSUUNTOSPORTSDid },
|
||||||
|
{ FTVid, FTRMCANVIEWDid },
|
||||||
|
{ BANDBVid, BANDBUSOTL4Did },
|
||||||
|
{ BANDBVid, BANDBUSTL4Did },
|
||||||
|
{ BANDBVid, BANDBUSO9ML2Did },
|
||||||
|
{ FTVid, EVERECOPROCDSDid },
|
||||||
|
{ FTVid, FT4NGALAXYDE0Did },
|
||||||
|
{ FTVid, FT4NGALAXYDE1Did },
|
||||||
|
{ FTVid, FT4NGALAXYDE2Did },
|
||||||
|
{ FTVid, XSENSCONVERTER0Did },
|
||||||
|
{ FTVid, XSENSCONVERTER1Did },
|
||||||
|
{ FTVid, XSENSCONVERTER2Did },
|
||||||
|
{ FTVid, XSENSCONVERTER3Did },
|
||||||
|
{ FTVid, XSENSCONVERTER4Did },
|
||||||
|
{ FTVid, XSENSCONVERTER5Did },
|
||||||
|
{ FTVid, XSENSCONVERTER6Did },
|
||||||
|
{ FTVid, XSENSCONVERTER7Did },
|
||||||
|
{ MOBILITYVid, MOBILITYUSBSERIALDid },
|
||||||
|
{ FTVid, FTACTIVEROBOTSDid },
|
||||||
|
{ FTVid, FTMHAMKWDid },
|
||||||
|
{ FTVid, FTMHAMYSDid },
|
||||||
|
{ FTVid, FTMHAMY6Did },
|
||||||
|
{ FTVid, FTMHAMY8Did },
|
||||||
|
{ FTVid, FTMHAMICDid },
|
||||||
|
{ FTVid, FTMHAMDB9Did },
|
||||||
|
{ FTVid, FTMHAMRS232Did },
|
||||||
|
{ FTVid, FTMHAMY9Did },
|
||||||
|
{ FTVid, FTTERATRONIKVCPDid },
|
||||||
|
{ FTVid, FTTERATRONIKD2XXDid },
|
||||||
|
{ EVOLUTIONVid, EVOLUTIONER1Did },
|
||||||
|
{ FTVid, FTARTEMISDid },
|
||||||
|
{ FTVid, FTATIKATK16Did },
|
||||||
|
{ FTVid, FTATIKATK16CDid },
|
||||||
|
{ FTVid, FTATIKATK16HRDid },
|
||||||
|
{ FTVid, FTATIKATK16HRCDid },
|
||||||
|
{ KOBILVid, KOBILCONVB1Did },
|
||||||
|
{ KOBILVid, KOBILCONVKAANDid },
|
||||||
|
{ POSIFLEXVid, POSIFLEXPP7000Did },
|
||||||
|
{ FTVid, FTTTUSBDid },
|
||||||
|
{ FTVid, FTECLOCOM1WIREDid },
|
||||||
|
{ FTVid, FTWESTREXMODEL777Did },
|
||||||
|
{ FTVid, FTWESTREXMODEL8900FDid },
|
||||||
|
{ FTVid, FTPCDJDAC2Did },
|
||||||
|
{ FTVid, FTRRCIRKITSLOCOBUFFERDid },
|
||||||
|
{ FTVid, FTASKRDR400Did },
|
||||||
|
{ ICOMID1Vid, ICOMID1Did },
|
||||||
|
{ PAPOUCHVid, PAPOUCHTMUDid },
|
||||||
|
{ FTVid, FTACGHFDUALDid },
|
||||||
|
{ FT8U232AMDid, FT4232HDid },
|
||||||
|
{ 0, 0 },
|
||||||
|
};
|
||||||
|
|
||||||
|
enum {
|
||||||
|
Packsz = 64, /* default size */
|
||||||
|
Maxpacksz = 512,
|
||||||
|
Bufsiz = 4 * 1024,
|
||||||
|
};
|
||||||
|
|
||||||
|
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 int
|
||||||
|
ftmodemctl(Serialport *p, int set)
|
||||||
|
{
|
||||||
|
if(set == 0){
|
||||||
|
p->mctl = 0;
|
||||||
|
ftdiwrite(p, 0, 0, FTSETMODEMCTRL);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
p->mctl = 1;
|
||||||
|
ftdiwrite(p, 0, FTRTSCTSHS, FTSETFLOWCTRL);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static ushort
|
||||||
|
ft232ambaudbase2div(int baud, int base)
|
||||||
|
{
|
||||||
|
int divisor3;
|
||||||
|
ushort divisor;
|
||||||
|
|
||||||
|
divisor3 = (base / 2) / baud;
|
||||||
|
if((divisor3 & 7) == 7)
|
||||||
|
divisor3++; /* round x.7/8 up to x+1 */
|
||||||
|
divisor = divisor3 >> 3;
|
||||||
|
divisor3 &= 7;
|
||||||
|
|
||||||
|
if(divisor3 == 1)
|
||||||
|
divisor |= 0xc000; /* 0.125 */
|
||||||
|
else if(divisor3 >= 4)
|
||||||
|
divisor |= 0x4000; /* 0.5 */
|
||||||
|
else if(divisor3 != 0)
|
||||||
|
divisor |= 0x8000; /* 0.25 */
|
||||||
|
if( divisor == 1)
|
||||||
|
divisor = 0; /* special case for maximum baud rate */
|
||||||
|
return divisor;
|
||||||
|
}
|
||||||
|
|
||||||
|
enum{
|
||||||
|
ClockNew = 48000000,
|
||||||
|
ClockOld = 12000000 / 16,
|
||||||
|
HetiraDiv = 240,
|
||||||
|
UirtDiv = 77,
|
||||||
|
};
|
||||||
|
|
||||||
|
static ushort
|
||||||
|
ft232ambaud2div(int baud)
|
||||||
|
{
|
||||||
|
return ft232ambaudbase2div(baud, ClockNew);
|
||||||
|
}
|
||||||
|
|
||||||
|
static ulong divfrac[8] = { 0, 3, 2, 4, 1, 5, 6, 7};
|
||||||
|
|
||||||
|
static ulong
|
||||||
|
ft232bmbaudbase2div(int baud, int base)
|
||||||
|
{
|
||||||
|
int divisor3;
|
||||||
|
u32int divisor;
|
||||||
|
|
||||||
|
divisor3 = (base / 2) / baud;
|
||||||
|
divisor = divisor3 >> 3 | divfrac[divisor3 & 7] << 14;
|
||||||
|
|
||||||
|
/* Deal with special cases for highest baud rates. */
|
||||||
|
if( divisor == 1)
|
||||||
|
divisor = 0; /* 1.0 */
|
||||||
|
else if( divisor == 0x4001)
|
||||||
|
divisor = 1; /* 1.5 */
|
||||||
|
return divisor;
|
||||||
|
}
|
||||||
|
|
||||||
|
static ulong
|
||||||
|
ft232bmbaud2div (int baud)
|
||||||
|
{
|
||||||
|
return ft232bmbaudbase2div (baud, ClockNew);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
customdiv(Serial *ser)
|
||||||
|
{
|
||||||
|
if(ser->dev->usb->vid == FTVid && ser->dev->usb->did == FTHETIRA1Did)
|
||||||
|
return HetiraDiv;
|
||||||
|
else if(ser->dev->usb->vid == FTVid && ser->dev->usb->did == FTUSBUIRTDid)
|
||||||
|
return UirtDiv;
|
||||||
|
|
||||||
|
fprint(2, "serial: weird custom divisor\n");
|
||||||
|
return 0; /* shouldn't happen, break as much as I can */
|
||||||
|
}
|
||||||
|
|
||||||
|
static ulong
|
||||||
|
ftbaudcalcdiv(Serial *ser, int baud)
|
||||||
|
{
|
||||||
|
int cusdiv;
|
||||||
|
ulong divval;
|
||||||
|
|
||||||
|
if(baud == 38400 && (cusdiv = customdiv(ser)) != 0)
|
||||||
|
baud = ser->baudbase / cusdiv;
|
||||||
|
|
||||||
|
if(baud == 0)
|
||||||
|
baud = 9600;
|
||||||
|
|
||||||
|
switch(ser->type) {
|
||||||
|
case SIO:
|
||||||
|
switch(baud) {
|
||||||
|
case 300:
|
||||||
|
divval = FTb300;
|
||||||
|
break;
|
||||||
|
case 600:
|
||||||
|
divval = FTb600;
|
||||||
|
break;
|
||||||
|
case 1200:
|
||||||
|
divval = FTb1200;
|
||||||
|
break;
|
||||||
|
case 2400:
|
||||||
|
divval = FTb2400;
|
||||||
|
break;
|
||||||
|
case 4800:
|
||||||
|
divval = FTb4800;
|
||||||
|
break;
|
||||||
|
case 9600:
|
||||||
|
divval = FTb9600;
|
||||||
|
break;
|
||||||
|
case 19200:
|
||||||
|
divval = FTb19200;
|
||||||
|
break;
|
||||||
|
case 38400:
|
||||||
|
divval = FTb38400;
|
||||||
|
break;
|
||||||
|
case 57600:
|
||||||
|
divval = FTb57600;
|
||||||
|
break;
|
||||||
|
case 115200:
|
||||||
|
divval = FTb115200;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
divval = FTb9600;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case FT8U232AM:
|
||||||
|
if(baud <= 3000000)
|
||||||
|
divval = ft232ambaud2div(baud);
|
||||||
|
else
|
||||||
|
divval = ft232ambaud2div(9600);
|
||||||
|
break;
|
||||||
|
case FT232BM:
|
||||||
|
case FT2232C:
|
||||||
|
case FTKINDR:
|
||||||
|
case FT2232H:
|
||||||
|
case FT4232H:
|
||||||
|
if(baud <= 3000000)
|
||||||
|
divval = ft232bmbaud2div(baud);
|
||||||
|
else
|
||||||
|
divval = ft232bmbaud2div(9600);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
divval = ft232bmbaud2div(9600);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return divval;
|
||||||
|
}
|
||||||
|
|
||||||
|
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
|
||||||
|
hasjtag(Usbdev *udev)
|
||||||
|
{
|
||||||
|
/* no string, for now, by default we detect no jtag */
|
||||||
|
if(udev->product != nil && cistrstr(udev->product, "jtag") != nil)
|
||||||
|
return 1;
|
||||||
|
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;
|
||||||
|
|
||||||
|
dsprint (2, "serial: detected type: %#x\n", ser->type);
|
||||||
|
}
|
||||||
|
|
||||||
|
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
|
||||||
|
ftuseinhdr(Serialport *p, uchar *b)
|
||||||
|
{
|
||||||
|
if(b[0] & FTICTS)
|
||||||
|
p->cts = 1;
|
||||||
|
else
|
||||||
|
p->cts = 0;
|
||||||
|
if(b[0] & FTIDSR)
|
||||||
|
p->dsr = 1;
|
||||||
|
else
|
||||||
|
p->dsr = 0;
|
||||||
|
if(b[0] & FTIRI)
|
||||||
|
p->ring = 1;
|
||||||
|
else
|
||||||
|
p->ring = 0;
|
||||||
|
if(b[0] & FTIRLSD)
|
||||||
|
p->rlsd = 1;
|
||||||
|
else
|
||||||
|
p->rlsd = 0;
|
||||||
|
|
||||||
|
if(b[1] & FTIOE)
|
||||||
|
p->novererr++;
|
||||||
|
if(b[1] & FTIPE)
|
||||||
|
p->nparityerr++;
|
||||||
|
if(b[1] & FTIFE)
|
||||||
|
p->nframeerr++;
|
||||||
|
if(b[1] & FTIBI)
|
||||||
|
p->nbreakerr++;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
ftsetouthdr(Serialport *p, uchar *b, int len)
|
||||||
|
{
|
||||||
|
if(p->s->outhdrsz != 0)
|
||||||
|
b[0] = FTOPORT | (FTOLENMSK & len);
|
||||||
|
return p->s->outhdrsz;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
wait4data(Serialport *p, uchar *data, int count)
|
||||||
|
{
|
||||||
|
int d;
|
||||||
|
Serial *ser;
|
||||||
|
|
||||||
|
ser = p->s;
|
||||||
|
|
||||||
|
qunlock(ser);
|
||||||
|
d = sendul(p->w4data, 1);
|
||||||
|
qlock(ser);
|
||||||
|
if(d <= 0)
|
||||||
|
return -1;
|
||||||
|
if(p->ndata >= count)
|
||||||
|
p->ndata -= count;
|
||||||
|
else{
|
||||||
|
count = p->ndata;
|
||||||
|
p->ndata = 0;
|
||||||
|
}
|
||||||
|
assert(count >= 0);
|
||||||
|
assert(p->ndata >= 0);
|
||||||
|
memmove(data, p->data, count);
|
||||||
|
if(p->ndata != 0)
|
||||||
|
memmove(p->data, p->data+count, p->ndata);
|
||||||
|
|
||||||
|
recvul(p->gotdata);
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
wait4write(Serialport *p, uchar *data, int count)
|
||||||
|
{
|
||||||
|
int off, fd;
|
||||||
|
uchar *b;
|
||||||
|
Serial *ser;
|
||||||
|
|
||||||
|
ser = p->s;
|
||||||
|
|
||||||
|
b = emallocz(count+ser->outhdrsz, 1);
|
||||||
|
off = ftsetouthdr(p, b, count);
|
||||||
|
memmove(b+off, data, count);
|
||||||
|
|
||||||
|
fd = p->epout->dfd;
|
||||||
|
qunlock(ser);
|
||||||
|
count = write(fd, b, count+off);
|
||||||
|
qlock(ser);
|
||||||
|
free(b);
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
typedef struct Packser Packser;
|
||||||
|
struct Packser{
|
||||||
|
int nb;
|
||||||
|
uchar b[Bufsiz];
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef struct Areader Areader;
|
||||||
|
struct Areader{
|
||||||
|
Serialport *p;
|
||||||
|
Channel *c;
|
||||||
|
};
|
||||||
|
|
||||||
|
static void
|
||||||
|
shutdownchan(Channel *c)
|
||||||
|
{
|
||||||
|
Packser *bp;
|
||||||
|
|
||||||
|
while((bp=nbrecvp(c)) != nil)
|
||||||
|
free(bp);
|
||||||
|
chanfree(c);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
cpdata(Serial *ser, Serialport *port, uchar *out, uchar *in, int sz)
|
||||||
|
{
|
||||||
|
int i, ncp, ntotcp, pksz;
|
||||||
|
|
||||||
|
pksz = ser->maxrtrans;
|
||||||
|
ntotcp = 0;
|
||||||
|
|
||||||
|
for(i = 0; i < sz; i+= pksz){
|
||||||
|
ftuseinhdr(port, in + i);
|
||||||
|
if(sz - i > pksz)
|
||||||
|
ncp = pksz - ser->inhdrsz;
|
||||||
|
else
|
||||||
|
ncp = sz - i - ser->inhdrsz;
|
||||||
|
memmove(out, in + i + ser->inhdrsz, ncp);
|
||||||
|
out += ncp;
|
||||||
|
ntotcp += ncp;
|
||||||
|
}
|
||||||
|
return ntotcp;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
epreader(void *u)
|
||||||
|
{
|
||||||
|
int dfd, rcount, cl, ntries, recov;
|
||||||
|
char err[40];
|
||||||
|
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;
|
||||||
|
do {
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
} while(rcount >= 0 || (rcount < 0 && strstr(err, "timed out") != 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);
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
ftreset(Serial *ser, Serialport *p)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
if(p != nil){
|
||||||
|
ftdiwrite(p, FTRESETCTLVAL, 0, FTRESET);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
p = ser->p;
|
||||||
|
for(i = 0; i < Maxifc; i++)
|
||||||
|
if(p[i].s != nil)
|
||||||
|
ftdiwrite(&p[i], FTRESETCTLVAL, 0, FTRESET);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
/* 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
ftsetbreak(Serialport *p, int val)
|
||||||
|
{
|
||||||
|
return ftdiwrite(p, (val != 0? FTSETBREAK: 0), 0, FTSETDATA);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
ftclearpipes(Serialport *p)
|
||||||
|
{
|
||||||
|
/* maybe can be done in one... */
|
||||||
|
ftdiwrite(p, FTRESETCTLVALPURGETX, 0, FTRESET);
|
||||||
|
ftdiwrite(p, FTRESETCTLVALPURGERX, 0, FTRESET);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
setctlline(Serialport *p, uchar val)
|
||||||
|
{
|
||||||
|
return ftdiwrite(p, val | (val << 8), 0, FTSETMODEMCTRL);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
updatectlst(Serialport *p, int val)
|
||||||
|
{
|
||||||
|
if(p->rts)
|
||||||
|
p->ctlstate |= val;
|
||||||
|
else
|
||||||
|
p->ctlstate &= ~val;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
setctl(Serialport *p)
|
||||||
|
{
|
||||||
|
int res;
|
||||||
|
Serial *ser;
|
||||||
|
|
||||||
|
ser = p->s;
|
||||||
|
|
||||||
|
if(ser->dev->usb->vid == FTVid && ser->dev->usb->did == FTHETIRA1Did){
|
||||||
|
fprint(2, "serial: cannot set lines for this device\n");
|
||||||
|
updatectlst(p, CtlRTS|CtlDTR);
|
||||||
|
p->rts = p->dtr = 1;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* NB: you can not set DTR and RTS with one control message */
|
||||||
|
updatectlst(p, CtlRTS);
|
||||||
|
res = setctlline(p, (CtlRTS<<8)|p->ctlstate);
|
||||||
|
if(res < 0)
|
||||||
|
return res;
|
||||||
|
|
||||||
|
updatectlst(p, CtlDTR);
|
||||||
|
res = setctlline(p, (CtlDTR<<8)|p->ctlstate);
|
||||||
|
if(res < 0)
|
||||||
|
return res;
|
||||||
|
|
||||||
|
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
|
||||||
|
ftseteps(Serialport *p)
|
||||||
|
{
|
||||||
|
char *s;
|
||||||
|
Serial *ser;
|
||||||
|
|
||||||
|
ser = p->s;
|
||||||
|
|
||||||
|
s = smprint("maxpkt %d", ser->maxrtrans);
|
||||||
|
devctl(p->epin, s);
|
||||||
|
free(s);
|
||||||
|
|
||||||
|
s = smprint("maxpkt %d", ser->maxwtrans);
|
||||||
|
devctl(p->epout, s);
|
||||||
|
free(s);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
Serialops ftops = {
|
||||||
|
.init = ftinit,
|
||||||
|
.seteps = ftseteps,
|
||||||
|
.setparam = ftsetparam,
|
||||||
|
.clearpipes = ftclearpipes,
|
||||||
|
.reset = ftreset,
|
||||||
|
.sendlines = ftsendlines,
|
||||||
|
.modemctl = ftmodemctl,
|
||||||
|
.setbreak = ftsetbreak,
|
||||||
|
.wait4data = wait4data,
|
||||||
|
.wait4write = wait4write,
|
||||||
|
};
|
632
sys/src/cmd/nusb/serial/ftdi.h
Normal file
632
sys/src/cmd/nusb/serial/ftdi.h
Normal file
|
@ -0,0 +1,632 @@
|
||||||
|
enum {
|
||||||
|
/* used by devices which don't provide their own Vid */
|
||||||
|
FTVid = 0x0403,
|
||||||
|
|
||||||
|
FTSheevaVid = 0x9E88,
|
||||||
|
FTSheevaDid = 0x9E8F,
|
||||||
|
FTOpenRDUltDid = 0x9E90,
|
||||||
|
|
||||||
|
FTSIODid = 0x8372, /* Product Id SIO appl'n of 8U100AX */
|
||||||
|
FT8U232AMDid = 0x6001, /* Similar device to SIO above */
|
||||||
|
FT8U232AMALTDid = 0x6006, /* FT's alternate Did for above*/
|
||||||
|
FT8U2232CDid = 0x6010, /* Dual channel device */
|
||||||
|
FTRELAISDid = 0xFA10, /* Relais device */
|
||||||
|
|
||||||
|
/* NF reader */
|
||||||
|
FTNFRICVid = 0x0DCD,
|
||||||
|
FTNFRICDid = 0x0001,
|
||||||
|
|
||||||
|
FTACTZWAVEDid = 0xF2D0, /* www.irtrans.de device */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* ACT Solutions HomePro ZWave interface
|
||||||
|
* http://www.act-solutions.com/HomePro.htm)
|
||||||
|
*/
|
||||||
|
FTIRTRANSDid = 0xFC60,
|
||||||
|
|
||||||
|
/*
|
||||||
|
* www.thoughttechnology.com/ TT-USB
|
||||||
|
*/
|
||||||
|
FTTTUSBDid = 0xFF20,
|
||||||
|
|
||||||
|
/* iPlus device */
|
||||||
|
FTIPLUSDid = 0xD070,
|
||||||
|
|
||||||
|
/* www.crystalfontz.com devices */
|
||||||
|
FTXF632Did = 0xFC08, /* 632: 16x2 Character Display */
|
||||||
|
FTXF634Did = 0xFC09, /* 634: 20x4 Character Display */
|
||||||
|
FTXF547Did = 0xFC0A, /* 547: Two line Display */
|
||||||
|
FTXF633Did = 0xFC0B, /* 633: 16x2 Character Display with Keys */
|
||||||
|
FTXF631Did = 0xFC0C, /* 631: 20x2 Character Display */
|
||||||
|
FTXF635Did = 0xFC0D, /* 635: 20x4 Character Display */
|
||||||
|
FTXF640Did = 0xFC0E, /* 640: Two line Display */
|
||||||
|
FTXF642Did = 0xFC0F, /* 642: Two line Display */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Video Networks Limited / Homechoice in the UK
|
||||||
|
* use an ftdi-based device for their 1Mb broadband
|
||||||
|
*/
|
||||||
|
FTVNHCPCUSBDDid = 0xfe38,
|
||||||
|
|
||||||
|
/*
|
||||||
|
* PCDJ use ftdi based dj-controllers
|
||||||
|
* DAC-2 device http://www.pcdjhardware.com/DAC2.asp
|
||||||
|
*/
|
||||||
|
FTPCDJDAC2Did = 0xFA88,
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Matrix Orbital LCD displays,
|
||||||
|
* which are the FT232BM (similar to the 8U232AM)
|
||||||
|
*/
|
||||||
|
FTMTXORB0Did = 0xFA00,
|
||||||
|
FTMTXORB1Did = 0xFA01,
|
||||||
|
FTMTXORB2Did = 0xFA02,
|
||||||
|
FTMTXORB3Did = 0xFA03,
|
||||||
|
FTMTXORB4Did = 0xFA04,
|
||||||
|
FTMTXORB5Did = 0xFA05,
|
||||||
|
FTMTXORB6Did = 0xFA06,
|
||||||
|
|
||||||
|
/* Interbiometrics USB I/O Board */
|
||||||
|
INTERBIOMVid = 0x1209,
|
||||||
|
INTERBIOMIOBRDDid = 0x1002,
|
||||||
|
INTERBIOMMINIIOBRDDid = 0x1006,
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The following are the values for the Perle Systems
|
||||||
|
* UltraPort USB serial converters
|
||||||
|
*/
|
||||||
|
FTPERLEULTRAPORTDid = 0xF0C0,
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Sealevel SeaLINK+ adapters.
|
||||||
|
*/
|
||||||
|
|
||||||
|
SEALEVELVid = 0x0c52,
|
||||||
|
|
||||||
|
SEALEVEL2101Did = 0x2101, /* SeaLINK+232 (2101/2105) */
|
||||||
|
SEALEVEL2102Did = 0x2102, /* SeaLINK+485 (2102) */
|
||||||
|
SEALEVEL2103Did = 0x2103, /* SeaLINK+232I (2103) */
|
||||||
|
SEALEVEL2104Did = 0x2104, /* SeaLINK+485I (2104) */
|
||||||
|
SEALEVEL22011Did = 0x2211, /* SeaPORT+2/232 (2201) Port 1 */
|
||||||
|
SEALEVEL22012Did = 0x2221, /* SeaPORT+2/232 (2201) Port 2 */
|
||||||
|
SEALEVEL22021Did = 0x2212, /* SeaPORT+2/485 (2202) Port 1 */
|
||||||
|
SEALEVEL22022Did = 0x2222, /* SeaPORT+2/485 (2202) Port 2 */
|
||||||
|
SEALEVEL22031Did = 0x2213, /* SeaPORT+2 (2203) Port 1 */
|
||||||
|
SEALEVEL22032Did = 0x2223, /* SeaPORT+2 (2203) Port 2 */
|
||||||
|
SEALEVEL24011Did = 0x2411, /* SeaPORT+4/232 (2401) Port 1 */
|
||||||
|
SEALEVEL24012Did = 0x2421, /* SeaPORT+4/232 (2401) Port 2 */
|
||||||
|
SEALEVEL24013Did = 0x2431, /* SeaPORT+4/232 (2401) Port 3 */
|
||||||
|
SEALEVEL24014Did = 0x2441, /* SeaPORT+4/232 (2401) Port 4 */
|
||||||
|
SEALEVEL24021Did = 0x2412, /* SeaPORT+4/485 (2402) Port 1 */
|
||||||
|
SEALEVEL24022Did = 0x2422, /* SeaPORT+4/485 (2402) Port 2 */
|
||||||
|
SEALEVEL24023Did = 0x2432, /* SeaPORT+4/485 (2402) Port 3 */
|
||||||
|
SEALEVEL24024Did = 0x2442, /* SeaPORT+4/485 (2402) Port 4 */
|
||||||
|
SEALEVEL24031Did = 0x2413, /* SeaPORT+4 (2403) Port 1 */
|
||||||
|
SEALEVEL24032Did = 0x2423, /* SeaPORT+4 (2403) Port 2 */
|
||||||
|
SEALEVEL24033Did = 0x2433, /* SeaPORT+4 (2403) Port 3 */
|
||||||
|
SEALEVEL24034Did = 0x2443, /* SeaPORT+4 (2403) Port 4 */
|
||||||
|
SEALEVEL28011Did = 0x2811, /* SeaLINK+8/232 (2801) Port 1 */
|
||||||
|
SEALEVEL28012Did = 0x2821, /* SeaLINK+8/232 (2801) Port 2 */
|
||||||
|
SEALEVEL28013Did = 0x2831, /* SeaLINK+8/232 (2801) Port 3 */
|
||||||
|
SEALEVEL28014Did = 0x2841, /* SeaLINK+8/232 (2801) Port 4 */
|
||||||
|
SEALEVEL28015Did = 0x2851, /* SeaLINK+8/232 (2801) Port 5 */
|
||||||
|
SEALEVEL28016Did = 0x2861, /* SeaLINK+8/232 (2801) Port 6 */
|
||||||
|
SEALEVEL28017Did = 0x2871, /* SeaLINK+8/232 (2801) Port 7 */
|
||||||
|
SEALEVEL28018Did = 0x2881, /* SeaLINK+8/232 (2801) Port 8 */
|
||||||
|
SEALEVEL28021Did = 0x2812, /* SeaLINK+8/485 (2802) Port 1 */
|
||||||
|
SEALEVEL28022Did = 0x2822, /* SeaLINK+8/485 (2802) Port 2 */
|
||||||
|
SEALEVEL28023Did = 0x2832, /* SeaLINK+8/485 (2802) Port 3 */
|
||||||
|
SEALEVEL28024Did = 0x2842, /* SeaLINK+8/485 (2802) Port 4 */
|
||||||
|
SEALEVEL28025Did = 0x2852, /* SeaLINK+8/485 (2802) Port 5 */
|
||||||
|
SEALEVEL28026Did = 0x2862, /* SeaLINK+8/485 (2802) Port 6 */
|
||||||
|
SEALEVEL28027Did = 0x2872, /* SeaLINK+8/485 (2802) Port 7 */
|
||||||
|
SEALEVEL28028Did = 0x2882, /* SeaLINK+8/485 (2802) Port 8 */
|
||||||
|
SEALEVEL28031Did = 0x2813, /* SeaLINK+8 (2803) Port 1 */
|
||||||
|
SEALEVEL28032Did = 0x2823, /* SeaLINK+8 (2803) Port 2 */
|
||||||
|
SEALEVEL28033Did = 0x2833, /* SeaLINK+8 (2803) Port 3 */
|
||||||
|
SEALEVEL28034Did = 0x2843, /* SeaLINK+8 (2803) Port 4 */
|
||||||
|
SEALEVEL28035Did = 0x2853, /* SeaLINK+8 (2803) Port 5 */
|
||||||
|
SEALEVEL28036Did = 0x2863, /* SeaLINK+8 (2803) Port 6 */
|
||||||
|
SEALEVEL28037Did = 0x2873, /* SeaLINK+8 (2803) Port 7 */
|
||||||
|
SEALEVEL28038Did = 0x2883, /* SeaLINK+8 (2803) Port 8 */
|
||||||
|
|
||||||
|
/* KOBIL Vendor ID chipcard terminals */
|
||||||
|
KOBILVid = 0x0d46,
|
||||||
|
KOBILCONVB1Did = 0x2020, /* KOBIL Konverter for B1 */
|
||||||
|
KOBILCONVKAANDid = 0x2021, /* KOBILKonverter for KAAN */
|
||||||
|
|
||||||
|
/* Icom ID-1 digital transceiver */
|
||||||
|
ICOMID1Vid = 0x0C26,
|
||||||
|
ICOMID1Did = 0x0004,
|
||||||
|
|
||||||
|
FTASKRDR400Did = 0xC991, /* ASK RDR 400 series card reader */
|
||||||
|
FTDSS20Did = 0xFC82, /* DSS-20 Sync Station for Sony Ericsson P800 */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Home Electronics (www.home-electro.com) USB gadgets
|
||||||
|
*/
|
||||||
|
FTHETIRA1Did = 0xFA78, /* Tira-1 IR transceiver */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* An infrared receiver and transmitter using the 8U232AM chip
|
||||||
|
* http://www.usbuirt.com
|
||||||
|
*/
|
||||||
|
FTUSBUIRTDid = 0xF850,
|
||||||
|
|
||||||
|
FTELVUR100Did = 0xFB58, /* USB-RS232-Umsetzer (UR 100) */
|
||||||
|
FTELVUM100Did = 0xFB5A, /* USB-Modul UM 100 */
|
||||||
|
FTELVUO100Did = 0xFB5B, /* USB-Modul UO 100 */
|
||||||
|
FTELVALC8500Did = 0xF06E, /* ALC 8500 Expert */
|
||||||
|
FTELVCLI7000Did = 0xFB59, /* Computer-Light-Interface */
|
||||||
|
FTELVPPS7330Did = 0xFB5C, /* Processor-Power-Supply (PPS 7330) */
|
||||||
|
FTELVTFM100Did = 0xFB5D, /* Temperartur-Feuchte Messgeraet (TFM 100) */
|
||||||
|
FTELVUDF77Did = 0xFB5E, /* USB DCF Funkurh (UDF 77) */
|
||||||
|
FTELVUIO88Did = 0xFB5F, /* USB-I/O Interface (UIO 88) */
|
||||||
|
FTELVUAD8Did = 0xF068, /* USB-AD-Wandler (UAD 8) */
|
||||||
|
FTELVUDA7Did = 0xF069, /* USB-DA-Wandler (UDA 7) */
|
||||||
|
FTELVUSI2Did = 0xF06A, /* USB-Schrittmotoren-Interface (USI 2) */
|
||||||
|
FTELVT1100Did = 0xF06B, /* Thermometer (T 1100) */
|
||||||
|
FTELVPCD200Did = 0xF06C, /* PC-Datenlogger (PCD 200) */
|
||||||
|
FTELVULA200Did = 0xF06D, /* USB-LCD-Ansteuerung (ULA 200) */
|
||||||
|
FTELVFHZ1000PCDid= 0xF06F, /* FHZ 1000 PC */
|
||||||
|
FTELVCSI8Did = 0xE0F0, /* Computer-Schalt-Interface (CSI 8) */
|
||||||
|
FTELVEM1000DLDid= 0xE0F1, /* PC-Datenlogger fuer Energiemonitor (EM 1000 DL) */
|
||||||
|
FTELVPCK100Did = 0xE0F2, /* PC-Kabeltester (PCK 100) */
|
||||||
|
FTELVRFP500Did = 0xE0F3, /* HF-Leistungsmesser (RFP 500) */
|
||||||
|
FTELVFS20SIGDid = 0xE0F4, /* Signalgeber (FS 20 SIG) */
|
||||||
|
FTELVWS300PCDid = 0xE0F6, /* PC-Wetterstation (WS 300 PC) */
|
||||||
|
FTELVFHZ1300PCDid= 0xE0E8, /* FHZ 1300 PC */
|
||||||
|
FTELVWS500Did = 0xE0E9, /* PC-Wetterstation (WS 500) */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Definitions for ID TECH (http://www.idt-net.com) devices
|
||||||
|
*/
|
||||||
|
IDTECHVid = 0x0ACD, /* ID TECH Vendor ID */
|
||||||
|
IDTECHIDT1221UDid= 0x0300, /* IDT1221U USB to RS-232 */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Definitions for Omnidirectional Control Technology, Inc. devices
|
||||||
|
*/
|
||||||
|
OCTVid = 0x0B39, /* OCT vendor ID */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Note: OCT US101 is also rebadged as Dick Smith Electronics
|
||||||
|
* (NZ) XH6381, Dick Smith Electronics (Aus) XH6451, and SIIG
|
||||||
|
* Inc. model US2308 hardware version 1.
|
||||||
|
*/
|
||||||
|
OCTUS101Did = 0x0421, /* OCT US101 USB to RS-232 */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* infrared receiver for access control with IR tags
|
||||||
|
*/
|
||||||
|
FTPIEGROUPDid = 0xF208,
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Definitions for Artemis astronomical USB based cameras
|
||||||
|
* http://www.artemisccd.co.uk/
|
||||||
|
*/
|
||||||
|
|
||||||
|
FTARTEMISDid = 0xDF28, /* All Artemis Cameras */
|
||||||
|
|
||||||
|
FTATIKATK16Did = 0xDF30, /* ATIK ATK-16 Grayscale Camera */
|
||||||
|
FTATIKATK16CDid = 0xDF32, /* ATIK ATK-16C Colour Camera */
|
||||||
|
FTATIKATK16HRDid= 0xDF31, /* ATIK ATK-16HR Grayscale */
|
||||||
|
FTATIKATK16HRCDid= 0xDF33, /* ATIK ATK-16HRC Colour Camera */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Protego products
|
||||||
|
*/
|
||||||
|
PROTEGOSPECIAL1 = 0xFC70, /* special/unknown device */
|
||||||
|
PROTEGOR2X0 = 0xFC71, /* R200-USB TRNG unit (R210, R220, and R230) */
|
||||||
|
PROTEGOSPECIAL3 = 0xFC72, /* special/unknown device */
|
||||||
|
PROTEGOSPECIAL4 = 0xFC73, /* special/unknown device */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Gude Analog- und Digitalsysteme GmbH
|
||||||
|
*/
|
||||||
|
FTGUDEADSE808Did = 0xE808,
|
||||||
|
FTGUDEADSE809Did = 0xE809,
|
||||||
|
FTGUDEADSE80ADid = 0xE80A,
|
||||||
|
FTGUDEADSE80BDid = 0xE80B,
|
||||||
|
FTGUDEADSE80CDid = 0xE80C,
|
||||||
|
FTGUDEADSE80DDid = 0xE80D,
|
||||||
|
FTGUDEADSE80EDid = 0xE80E,
|
||||||
|
FTGUDEADSE80FDid = 0xE80F,
|
||||||
|
FTGUDEADSE888Did = 0xE888, /* Expert ISDN Control USB */
|
||||||
|
FTGUDEADSE889Did = 0xE889, /* USB RS-232 OptoBridge */
|
||||||
|
FTGUDEADSE88ADid = 0xE88A,
|
||||||
|
FTGUDEADSE88BDid = 0xE88B,
|
||||||
|
FTGUDEADSE88CDid = 0xE88C,
|
||||||
|
FTGUDEADSE88DDid = 0xE88D,
|
||||||
|
FTGUDEADSE88EDid = 0xE88E,
|
||||||
|
FTGUDEADSE88FDid = 0xE88F,
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Linx Technologies
|
||||||
|
*/
|
||||||
|
LINXSDMUSBQSSDid= 0xF448, /* Linx SDM-USB-QS-S */
|
||||||
|
LINXMASTERDEVEL2Did= 0xF449, /* Linx Master Development.0 */
|
||||||
|
LINXFUTURE0Did = 0xF44A, /* Linx future device */
|
||||||
|
LINXFUTURE1Did = 0xF44B, /* Linx future device */
|
||||||
|
LINXFUTURE2Did = 0xF44C, /* Linx future device */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* CCS Inc. ICDU/ICDU40 - the FT232BM used in a in-circuit-debugger
|
||||||
|
* unit for PIC16's/PIC18's
|
||||||
|
*/
|
||||||
|
FTCCSICDU200Did = 0xF9D0,
|
||||||
|
FTCCSICDU401Did = 0xF9D1,
|
||||||
|
|
||||||
|
/* Inside Accesso contactless reader (http://www.insidefr.com) */
|
||||||
|
INSIDEACCESSO = 0xFAD0,
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Intrepid Control Systems (http://www.intrepidcs.com/)
|
||||||
|
* ValueCAN and NeoVI
|
||||||
|
*/
|
||||||
|
INTREDidVid = 0x093C,
|
||||||
|
INTREDidVALUECANDid= 0x0601,
|
||||||
|
INTREDidNEOVIDid= 0x0701,
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Falcom Wireless Communications GmbH
|
||||||
|
*/
|
||||||
|
FALCOMVid = 0x0F94,
|
||||||
|
FALCOMTWISTDid = 0x0001, /* Falcom Twist USB GPRS modem */
|
||||||
|
FALCOMSAMBADid = 0x0005, /* Falcom Samba USB GPRS modem */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* SUUNTO
|
||||||
|
*/
|
||||||
|
FTSUUNTOSPORTSDid= 0xF680, /* Suunto Sports instrument */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* B&B Electronics
|
||||||
|
*/
|
||||||
|
BANDBVid = 0x0856, /* B&B Electronics Vendor ID */
|
||||||
|
BANDBUSOTL4Did = 0xAC01, /* USOTL4 Isolated RS-485 */
|
||||||
|
BANDBUSTL4Did = 0xAC02, /* USTL4 RS-485 Converter */
|
||||||
|
BANDBUSO9ML2Did = 0xAC03, /* USO9ML2 Isolated RS-232 */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* RM Michaelides CANview USB (http://www.rmcan.com)
|
||||||
|
* CAN fieldbus interface adapter
|
||||||
|
*/
|
||||||
|
FTRMCANVIEWDid = 0xfd60,
|
||||||
|
|
||||||
|
/*
|
||||||
|
* EVER Eco Pro UPS (http://www.ever.com.pl/)
|
||||||
|
*/
|
||||||
|
EVERECOPROCDSDid = 0xe520, /* RS-232 converter */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 4N-GALAXY.DE PIDs for CAN-USB, USB-RS232, USB-RS422, USB-RS485,
|
||||||
|
* USB-TTY activ, USB-TTY passiv. Some PIDs are used by several devices
|
||||||
|
*/
|
||||||
|
FT4NGALAXYDE0Did = 0x8372,
|
||||||
|
FT4NGALAXYDE1Did = 0xF3C0,
|
||||||
|
FT4NGALAXYDE2Did = 0xF3C1,
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Mobility Electronics products.
|
||||||
|
*/
|
||||||
|
MOBILITYVid = 0x1342,
|
||||||
|
MOBILITYUSBSERIALDid= 0x0202, /* EasiDock USB 200 serial */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* microHAM product IDs (http://www.microham.com)
|
||||||
|
*/
|
||||||
|
FTMHAMKWDid = 0xEEE8, /* USB-KW interface */
|
||||||
|
FTMHAMYSDid = 0xEEE9, /* USB-YS interface */
|
||||||
|
FTMHAMY6Did = 0xEEEA, /* USB-Y6 interface */
|
||||||
|
FTMHAMY8Did = 0xEEEB, /* USB-Y8 interface */
|
||||||
|
FTMHAMICDid = 0xEEEC, /* USB-IC interface */
|
||||||
|
FTMHAMDB9Did = 0xEEED, /* USB-DB9 interface */
|
||||||
|
FTMHAMRS232Did = 0xEEEE, /* USB-RS232 interface */
|
||||||
|
FTMHAMY9Did = 0xEEEF, /* USB-Y9 interface */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Active Robots product ids.
|
||||||
|
*/
|
||||||
|
FTACTIVEROBOTSDid = 0xE548, /* USB comms board */
|
||||||
|
XSENSCONVERTER0Did = 0xD388,
|
||||||
|
XSENSCONVERTER1Did = 0xD389,
|
||||||
|
XSENSCONVERTER2Did = 0xD38A,
|
||||||
|
XSENSCONVERTER3Did = 0xD38B,
|
||||||
|
XSENSCONVERTER4Did = 0xD38C,
|
||||||
|
XSENSCONVERTER5Did = 0xD38D,
|
||||||
|
XSENSCONVERTER6Did = 0xD38E,
|
||||||
|
XSENSCONVERTER7Did = 0xD38F,
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Xsens Technologies BV products (http://www.xsens.com).
|
||||||
|
*/
|
||||||
|
FTTERATRONIKVCPDid = 0xEC88, /* Teratronik device */
|
||||||
|
FTTERATRONIKD2XXDid = 0xEC89, /* Teratronik device */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Evolution Robotics products (http://www.evolution.com/).
|
||||||
|
*/
|
||||||
|
EVOLUTIONVid = 0xDEEE,
|
||||||
|
EVOLUTIONER1Did = 0x0300, /* ER1 Control Module */
|
||||||
|
|
||||||
|
/* Pyramid Computer GmbH */
|
||||||
|
FTPYRAMIDDid = 0xE6C8, /* Pyramid Appliance Display */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Posiflex inc retail equipment (http://www.posiflex.com.tw)
|
||||||
|
*/
|
||||||
|
POSIFLEXVid = 0x0d3a,
|
||||||
|
POSIFLEXPP7000Did= 0x0300, /* PP-7000II thermal printer */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Westrex International devices
|
||||||
|
*/
|
||||||
|
FTWESTREXMODEL777Did = 0xDC00, /* Model 777 */
|
||||||
|
FTWESTREXMODEL8900FDid = 0xDC01, /* Model 8900F */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* RR-CirKits LocoBuffer USB (http://www.rr-cirkits.com)
|
||||||
|
*/
|
||||||
|
FTRRCIRKITSLOCOBUFFERDid= 0xc7d0, /* LocoBuffer USB */
|
||||||
|
FTECLOCOM1WIREDid = 0xEA90, /* COM to 1-Wire USB */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Papouch products (http://www.papouch.com/)
|
||||||
|
*/
|
||||||
|
PAPOUCHVid = 0x5050,
|
||||||
|
PAPOUCHTMUDid = 0x0400, /* TMU USB Thermometer */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* ACG Identification Technologies GmbH products http://www.acg.de/
|
||||||
|
*/
|
||||||
|
FTACGHFDUALDid = 0xDD20, /* HF Dual ISO Reader (RFID) */
|
||||||
|
/*
|
||||||
|
* new high speed devices
|
||||||
|
*/
|
||||||
|
FT4232HDid = 0x6011, /* FTDI FT4232H based device */
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Commands */
|
||||||
|
enum {
|
||||||
|
FTRESET = 0, /* Reset the port */
|
||||||
|
FTSETMODEMCTRL, /* Set the modem control register */
|
||||||
|
FTSETFLOWCTRL, /* Set flow control register */
|
||||||
|
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 bit mode */
|
||||||
|
FTGETPINS, /* Read pins state */
|
||||||
|
FTGETE2READ = 0x90, /* Read address from 128-byte I2C EEPROM */
|
||||||
|
FTSETE2WRITE, /* Write to address on 128-byte I2C EEPROM */
|
||||||
|
FTSETE2ERASE, /* Erase address on 128-byte I2C EEPROM */
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Port Identifier Table, index for interfaces */
|
||||||
|
enum {
|
||||||
|
PITDEFAULT = 0, /* SIOA */
|
||||||
|
PITA, /* SIOA jtag if there is one */
|
||||||
|
};
|
||||||
|
|
||||||
|
enum {
|
||||||
|
Rftdireq = 1<<6, /* bit for type of request */
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Commands Data size
|
||||||
|
* Sets have wLength = 0
|
||||||
|
* Gets have wValue = 0
|
||||||
|
*/
|
||||||
|
enum {
|
||||||
|
FTMODEMSTATUSSZ = 1,
|
||||||
|
FTLATENCYTIMERSZ= 1,
|
||||||
|
FTPINSSZ = 1,
|
||||||
|
FTE2READSZ = 2,
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* bRequest: FTGETE2READ
|
||||||
|
* wIndex: Address of word to read
|
||||||
|
* Data: Will return a word (2 bytes) of data from E2Address
|
||||||
|
* Results put in the I2C 128 byte EEPROM string eeprom+(2*index)
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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
|
||||||
|
* wValue: Ctl Val
|
||||||
|
* wIndex: Port
|
||||||
|
*/
|
||||||
|
enum {
|
||||||
|
FTRESETCTLVAL = 0,
|
||||||
|
FTRESETCTLVALPURGERX = 1,
|
||||||
|
FTRESETCTLVALPURGETX = 2,
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* BmRequestType: SET
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* chip type */
|
||||||
|
enum {
|
||||||
|
SIO = 1,
|
||||||
|
FT8U232AM = 2,
|
||||||
|
FT232BM = 3,
|
||||||
|
FT2232C = 4,
|
||||||
|
FTKINDR = 5,
|
||||||
|
FT2232H = 6,
|
||||||
|
FT4232H = 7,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum {
|
||||||
|
FTb300 = 0,
|
||||||
|
FTb600 = 1,
|
||||||
|
FTb1200 = 2,
|
||||||
|
FTb2400 = 3,
|
||||||
|
FTb4800 = 4,
|
||||||
|
FTb9600 = 5,
|
||||||
|
FTb19200 = 6,
|
||||||
|
FTb38400 = 7,
|
||||||
|
FTb57600 = 8,
|
||||||
|
FTb115200 = 9,
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* bRequest: FTSETDATA
|
||||||
|
* wValue: Data characteristics
|
||||||
|
* bits 0-7 number of data bits
|
||||||
|
* wIndex: Port
|
||||||
|
*/
|
||||||
|
enum {
|
||||||
|
FTSETDATAParNONE = 0 << 8,
|
||||||
|
FTSETDATAParODD = 1 << 8,
|
||||||
|
FTSETDATAParEVEN = 2 << 8,
|
||||||
|
FTSETDATAParMARK = 3 << 8,
|
||||||
|
FTSETDATAParSPACE = 4 << 8,
|
||||||
|
FTSETDATASTOPBITS1 = 0 << 11,
|
||||||
|
FTSETDATASTOPBITS15 = 1 << 11,
|
||||||
|
FTSETDATASTOPBITS2 = 2 << 11,
|
||||||
|
FTSETBREAK = 1 << 14,
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* bRequest: FTSETMODEMCTRL
|
||||||
|
* wValue: ControlValue (see below)
|
||||||
|
* wIndex: Port
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* bRequest: FTSETFLOWCTRL
|
||||||
|
* wValue: Xoff/Xon
|
||||||
|
* wIndex: Protocol/Port - hIndex is protocol; lIndex is port
|
||||||
|
*/
|
||||||
|
enum {
|
||||||
|
FTDISABLEFLOWCTRL= 0,
|
||||||
|
FTRTSCTSHS = 1 << 8,
|
||||||
|
FTDTRDSRHS = 2 << 8,
|
||||||
|
FTXONXOFFHS = 4 << 8,
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* bRequest: FTGETLATENCYTIMER
|
||||||
|
* wIndex: Port
|
||||||
|
* wLength: 0
|
||||||
|
* Data: latency (on return)
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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 bit-bang mode */
|
||||||
|
|
||||||
|
BIGBMNORMAL = 1, /* normal bit-bang mode */
|
||||||
|
BIGBMSPI = 2, /* spi bit-bang mode */
|
||||||
|
|
||||||
|
BMABM = 1<<8, /* async mode */
|
||||||
|
BMMPSSE = 2<<8,
|
||||||
|
BMSYNCBB = 4<<8, /* sync bit-bang -- 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 1-255)
|
||||||
|
* 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
|
||||||
|
* wIndex: Port
|
||||||
|
* wLength: 1
|
||||||
|
* Data: Status
|
||||||
|
*/
|
||||||
|
enum {
|
||||||
|
FTCTSMASK = 0x10,
|
||||||
|
FTDSRMASK = 0x20,
|
||||||
|
FTRIMASK = 0x40,
|
||||||
|
FTRLSDMASK = 0x80,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum {
|
||||||
|
/* byte 0 of in data hdr */
|
||||||
|
FTICTS = 1 << 4,
|
||||||
|
FTIDSR = 1 << 5,
|
||||||
|
FTIRI = 1 << 6,
|
||||||
|
FTIRLSD = 1 << 7, /* receive line signal detect */
|
||||||
|
|
||||||
|
/* byte 1 of in data hdr */
|
||||||
|
FTIDR = 1<<0, /* data ready */
|
||||||
|
FTIOE = 1<<1, /* overrun error */
|
||||||
|
FTIPE = 1<<2, /* parity error */
|
||||||
|
FTIFE = 1<<3, /* framing error */
|
||||||
|
FTIBI = 1<<4, /* break interrupt */
|
||||||
|
FTITHRE = 1<<5, /* xmitter holding register */
|
||||||
|
FTITEMT = 1<<6, /* xmitter empty */
|
||||||
|
FTIFIFO = 1<<7, /* error in rcv fifo */
|
||||||
|
|
||||||
|
/* byte 0 of out data hdr len does not include byte 0 */
|
||||||
|
FTOLENMSK= 0x3F,
|
||||||
|
FTOPORT = 0x80, /* must be set */
|
||||||
|
};
|
||||||
|
|
||||||
|
extern Serialops ftops;
|
||||||
|
|
||||||
|
int ftmatch(Serial *ser, char *info);
|
23
sys/src/cmd/nusb/serial/mkfile
Normal file
23
sys/src/cmd/nusb/serial/mkfile
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
</$objtype/mkfile
|
||||||
|
|
||||||
|
TARG=serial
|
||||||
|
OFILES=ftdi.$O serial.$O prolific.$O ucons.$O
|
||||||
|
HFILES=\
|
||||||
|
../lib/usb.h\
|
||||||
|
ftdi.h\
|
||||||
|
prolific.h\
|
||||||
|
serial.h\
|
||||||
|
ucons.h\
|
||||||
|
|
||||||
|
LIB=../lib/usb.a$O
|
||||||
|
|
||||||
|
BIN=/$objtype/bin/nusb
|
||||||
|
|
||||||
|
UPDATE=\
|
||||||
|
mkfile\
|
||||||
|
$HFILES\
|
||||||
|
${OFILES:%.$O=%.c}\
|
||||||
|
|
||||||
|
</sys/src/cmd/mkone
|
||||||
|
|
||||||
|
CFLAGS=-I../lib $CFLAGS
|
439
sys/src/cmd/nusb/serial/prolific.c
Normal file
439
sys/src/cmd/nusb/serial/prolific.c
Normal file
|
@ -0,0 +1,439 @@
|
||||||
|
#include <u.h>
|
||||||
|
#include <libc.h>
|
||||||
|
#include <thread.h>
|
||||||
|
#include <fcall.h>
|
||||||
|
#include <9p.h>
|
||||||
|
#include "usb.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\n", 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; i<bufsz; i++)
|
||||||
|
print("buf[%d]=%#ux ", i, buf[i]);
|
||||||
|
print("\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
vendorread(Serialport *p, int val, int index, uchar *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
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* BUG: I could probably read Dcr0 and set only the bits */
|
||||||
|
static int
|
||||||
|
plmodemctl(Serialport *p, int set)
|
||||||
|
{
|
||||||
|
Serial *ser;
|
||||||
|
|
||||||
|
ser = p->s;
|
||||||
|
|
||||||
|
if(set == 0){
|
||||||
|
p->mctl = 0;
|
||||||
|
vendorwrite(p, Dcr0Idx|DcrSet, Dcr0Init);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
p->mctl = 1;
|
||||||
|
if(ser->type == TypeHX)
|
||||||
|
vendorwrite(p, Dcr0Idx|DcrSet, Dcr0Init|Dcr0HwFcX);
|
||||||
|
else
|
||||||
|
vendorwrite(p, Dcr0Idx|DcrSet, Dcr0Init|Dcr0HwFcH);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
plgetparam(Serialport *p)
|
||||||
|
{
|
||||||
|
uchar 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
plsetparam(Serialport *p)
|
||||||
|
{
|
||||||
|
uchar 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
|
||||||
|
revid(ulong devno)
|
||||||
|
{
|
||||||
|
switch(devno){
|
||||||
|
case RevH:
|
||||||
|
return TypeH;
|
||||||
|
case RevX:
|
||||||
|
case RevHX:
|
||||||
|
case Rev1:
|
||||||
|
return TypeHX;
|
||||||
|
default:
|
||||||
|
return TypeUnk;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* linux driver says the release id is not always right */
|
||||||
|
static int
|
||||||
|
heuristicid(ulong csp, ulong maxpkt)
|
||||||
|
{
|
||||||
|
if(Class(csp) == 0x02)
|
||||||
|
return TypeH;
|
||||||
|
else if(maxpkt == 0x40)
|
||||||
|
return TypeHX;
|
||||||
|
else if(Class(csp) == 0x00 || Class(csp) == 0xFF)
|
||||||
|
return TypeH;
|
||||||
|
else{
|
||||||
|
fprint(2, "serial: chip unknown, setting to HX version\n");
|
||||||
|
return TypeHX;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
plinit(Serialport *p)
|
||||||
|
{
|
||||||
|
char *st;
|
||||||
|
uchar *buf;
|
||||||
|
ulong 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
|
||||||
|
plsetbreak(Serialport *p, int val)
|
||||||
|
{
|
||||||
|
Serial *ser;
|
||||||
|
|
||||||
|
ser = p->s;
|
||||||
|
return usbcmd(ser->dev, Rh2d | Rclass | Riface,
|
||||||
|
(val != 0? BreakOn: BreakOff), val, 0, nil, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
plclearpipes(Serialport *p)
|
||||||
|
{
|
||||||
|
Serial *ser;
|
||||||
|
|
||||||
|
ser = p->s;
|
||||||
|
|
||||||
|
if(ser->type == TypeHX){
|
||||||
|
vendorwrite(p, PipeDSRst, 0);
|
||||||
|
vendorwrite(p, PipeUSRst, 0);
|
||||||
|
}else{
|
||||||
|
if(unstall(ser->dev, p->epout, Eout) < 0)
|
||||||
|
dprint(2, "disk: unstall epout: %r\n");
|
||||||
|
if(unstall(ser->dev, p->epin, Ein) < 0)
|
||||||
|
dprint(2, "disk: unstall epin: %r\n");
|
||||||
|
if(unstall(ser->dev, p->epintr, Ein) < 0)
|
||||||
|
dprint(2, "disk: unstall epintr: %r\n");
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
setctlline(Serialport *p, uchar val)
|
||||||
|
{
|
||||||
|
Serial *ser;
|
||||||
|
|
||||||
|
ser = p->s;
|
||||||
|
return usbcmd(ser->dev, Rh2d | Rclass | Riface, SetCtlReq,
|
||||||
|
val, 0, nil, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
composectl(Serialport *p)
|
||||||
|
{
|
||||||
|
if(p->rts)
|
||||||
|
p->ctlstate |= CtlRTS;
|
||||||
|
else
|
||||||
|
p->ctlstate &= ~CtlRTS;
|
||||||
|
if(p->dtr)
|
||||||
|
p->ctlstate |= CtlDTR;
|
||||||
|
else
|
||||||
|
p->ctlstate &= ~CtlDTR;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
plsendlines(Serialport *p)
|
||||||
|
{
|
||||||
|
int res;
|
||||||
|
|
||||||
|
dsprint(2, "serial: sendlines: %#2.2x\n", p->ctlstate);
|
||||||
|
composectl(p);
|
||||||
|
res = setctlline(p, p->ctlstate);
|
||||||
|
dsprint(2, "serial: sendlines res: %d\n", res);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
plreadstatus(Serialport *p)
|
||||||
|
{
|
||||||
|
int nr, dfd;
|
||||||
|
char err[40];
|
||||||
|
uchar 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
statusreader(void *u)
|
||||||
|
{
|
||||||
|
Serialport *p;
|
||||||
|
Serial *ser;
|
||||||
|
|
||||||
|
p = u;
|
||||||
|
ser = p->s;
|
||||||
|
threadsetname("statusreaderproc");
|
||||||
|
while(plreadstatus(p) >= 0)
|
||||||
|
;
|
||||||
|
fprint(2, "serial: statusreader exiting\n");
|
||||||
|
closedev(ser->dev);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Maximum number of bytes transferred per frame
|
||||||
|
* The output buffer size cannot be increased due to the size encoding
|
||||||
|
*/
|
||||||
|
|
||||||
|
static int
|
||||||
|
plseteps(Serialport *p)
|
||||||
|
{
|
||||||
|
devctl(p->epin, "maxpkt 256");
|
||||||
|
devctl(p->epout, "maxpkt 256");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
Serialops plops = {
|
||||||
|
.init = plinit,
|
||||||
|
.getparam = plgetparam,
|
||||||
|
.setparam = plsetparam,
|
||||||
|
.clearpipes = plclearpipes,
|
||||||
|
.sendlines = plsendlines,
|
||||||
|
.modemctl = plmodemctl,
|
||||||
|
.setbreak = plsetbreak,
|
||||||
|
.seteps = plseteps,
|
||||||
|
};
|
178
sys/src/cmd/nusb/serial/prolific.h
Normal file
178
sys/src/cmd/nusb/serial/prolific.h
Normal file
|
@ -0,0 +1,178 @@
|
||||||
|
enum {
|
||||||
|
/* flavours of the device */
|
||||||
|
TypeH,
|
||||||
|
TypeHX,
|
||||||
|
TypeUnk,
|
||||||
|
|
||||||
|
RevH = 0x0202,
|
||||||
|
RevX = 0x0300,
|
||||||
|
RevHX = 0x0400,
|
||||||
|
Rev1 = 0x0001,
|
||||||
|
|
||||||
|
/* usbcmd parameters */
|
||||||
|
SetLineReq = 0x20,
|
||||||
|
|
||||||
|
SetCtlReq = 0x22,
|
||||||
|
|
||||||
|
BreakReq = 0x23,
|
||||||
|
BreakOn = 0xffff,
|
||||||
|
BreakOff = 0x0000,
|
||||||
|
|
||||||
|
GetLineReq = 0x21,
|
||||||
|
|
||||||
|
VendorWriteReq = 0x01, /* BUG: is this a standard request? */
|
||||||
|
VendorReadReq = 0x01,
|
||||||
|
|
||||||
|
ParamReqSz = 7,
|
||||||
|
VendorReqSz = 10,
|
||||||
|
|
||||||
|
/* status read from interrupt endpoint */
|
||||||
|
DcdStatus = 0x01,
|
||||||
|
DsrStatus = 0x02,
|
||||||
|
BreakerrStatus = 0x04,
|
||||||
|
RingStatus = 0x08,
|
||||||
|
FrerrStatus = 0x10,
|
||||||
|
ParerrStatus = 0x20,
|
||||||
|
OvererrStatus = 0x40,
|
||||||
|
CtsStatus = 0x80,
|
||||||
|
|
||||||
|
DcrGet = 0x80,
|
||||||
|
DcrSet = 0x00,
|
||||||
|
|
||||||
|
Dcr0Idx = 0x00,
|
||||||
|
|
||||||
|
Dcr0Init = 0x0001,
|
||||||
|
Dcr0HwFcH = 0x0040,
|
||||||
|
Dcr0HwFcX = 0x0060,
|
||||||
|
|
||||||
|
Dcr1Idx = 0x01,
|
||||||
|
|
||||||
|
Dcr1Init = 0x0000,
|
||||||
|
Dcr1InitH = 0x0080,
|
||||||
|
Dcr1InitX = 0x0000,
|
||||||
|
|
||||||
|
Dcr2Idx = 0x02,
|
||||||
|
|
||||||
|
Dcr2InitH = 0x0024,
|
||||||
|
Dcr2InitX = 0x0044,
|
||||||
|
|
||||||
|
PipeDSRst = 0x08,
|
||||||
|
PipeUSRst = 0x09,
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
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);
|
876
sys/src/cmd/nusb/serial/serial.c
Normal file
876
sys/src/cmd/nusb/serial/serial.c
Normal file
|
@ -0,0 +1,876 @@
|
||||||
|
/*
|
||||||
|
* This part takes care of locking except for initialization and
|
||||||
|
* other threads created by the hw dep. drivers.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <u.h>
|
||||||
|
#include <libc.h>
|
||||||
|
#include <ctype.h>
|
||||||
|
#include <thread.h>
|
||||||
|
#include <fcall.h>
|
||||||
|
#include <9p.h>
|
||||||
|
#include "usb.h"
|
||||||
|
#include "serial.h"
|
||||||
|
#include "prolific.h"
|
||||||
|
#include "ucons.h"
|
||||||
|
#include "ftdi.h"
|
||||||
|
|
||||||
|
int serialdebug;
|
||||||
|
static int sdebug;
|
||||||
|
|
||||||
|
Serialport **ports;
|
||||||
|
int nports;
|
||||||
|
|
||||||
|
static void
|
||||||
|
serialfatal(Serial *ser)
|
||||||
|
{
|
||||||
|
Serialport *p;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
dsprint(2, "serial: fatal error, detaching\n");
|
||||||
|
devctl(ser->dev, "detach");
|
||||||
|
|
||||||
|
for(i = 0; i < ser->nifcs; i++){
|
||||||
|
p = &ser->p[i];
|
||||||
|
if(p->w4data != nil)
|
||||||
|
chanclose(p->w4data);
|
||||||
|
if(p->gotdata != nil)
|
||||||
|
chanclose(p->gotdata);
|
||||||
|
if(p->readc)
|
||||||
|
chanclose(p->readc);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* I sleep with the lock... only way to drain in general */
|
||||||
|
static void
|
||||||
|
serialdrain(Serialport *p)
|
||||||
|
{
|
||||||
|
Serial *ser;
|
||||||
|
uint baud, pipesize;
|
||||||
|
|
||||||
|
ser = p->s;
|
||||||
|
baud = p->baud;
|
||||||
|
|
||||||
|
if(p->baud == ~0)
|
||||||
|
return;
|
||||||
|
if(ser->maxwtrans < 256)
|
||||||
|
pipesize = 256;
|
||||||
|
else
|
||||||
|
pipesize = ser->maxwtrans;
|
||||||
|
/* wait for the at least 256-byte pipe to clear */
|
||||||
|
sleep(10 + pipesize/((1 + baud)*1000));
|
||||||
|
if(ser->clearpipes != nil)
|
||||||
|
ser->clearpipes(p);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
serialreset(Serial *ser)
|
||||||
|
{
|
||||||
|
Serialport *p;
|
||||||
|
int i, res;
|
||||||
|
|
||||||
|
res = 0;
|
||||||
|
/* cmd for reset */
|
||||||
|
for(i = 0; i < ser->nifcs; i++){
|
||||||
|
p = &ser->p[i];
|
||||||
|
serialdrain(p);
|
||||||
|
}
|
||||||
|
if(ser->reset != nil)
|
||||||
|
res = ser->reset(ser, nil);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* call this if something goes wrong, must be qlocked */
|
||||||
|
int
|
||||||
|
serialrecover(Serial *ser, Serialport *p, Dev *ep, char *err)
|
||||||
|
{
|
||||||
|
if(p != nil)
|
||||||
|
dprint(2, "serial[%d], %s: %s, level %d\n", p->interfc,
|
||||||
|
p->name, err, ser->recover);
|
||||||
|
else
|
||||||
|
dprint(2, "serial[%s], global error, level %d\n",
|
||||||
|
ser->p[0].name, ser->recover);
|
||||||
|
ser->recover++;
|
||||||
|
if(strstr(err, "detached") != nil)
|
||||||
|
return -1;
|
||||||
|
if(ser->recover < 3){
|
||||||
|
if(p != nil){
|
||||||
|
if(ep != nil){
|
||||||
|
if(ep == p->epintr)
|
||||||
|
unstall(ser->dev, p->epintr, Ein);
|
||||||
|
if(ep == p->epin)
|
||||||
|
unstall(ser->dev, p->epin, Ein);
|
||||||
|
if(ep == p->epout)
|
||||||
|
unstall(ser->dev, p->epout, Eout);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(p->epintr != nil)
|
||||||
|
unstall(ser->dev, p->epintr, Ein);
|
||||||
|
if(p->epin != nil)
|
||||||
|
unstall(ser->dev, p->epin, Ein);
|
||||||
|
if(p->epout != nil)
|
||||||
|
unstall(ser->dev, p->epout, Eout);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if(ser->recover > 4 && ser->recover < 8)
|
||||||
|
serialfatal(ser);
|
||||||
|
if(ser->recover > 8){
|
||||||
|
ser->reset(ser, p);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if(serialreset(ser) < 0)
|
||||||
|
return -1;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
serialctl(Serialport *p, char *cmd)
|
||||||
|
{
|
||||||
|
Serial *ser;
|
||||||
|
int c, i, n, nf, nop, nw, par, drain, set, lines;
|
||||||
|
char *f[16];
|
||||||
|
uchar x;
|
||||||
|
|
||||||
|
ser = p->s;
|
||||||
|
drain = set = lines = 0;
|
||||||
|
nf = tokenize(cmd, f, nelem(f));
|
||||||
|
for(i = 0; i < nf; i++){
|
||||||
|
if(strncmp(f[i], "break", 5) == 0){
|
||||||
|
if(ser->setbreak != nil)
|
||||||
|
ser->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++;
|
||||||
|
ser->setbreak(p, 1);
|
||||||
|
sleep(n);
|
||||||
|
ser->setbreak(p, 0);
|
||||||
|
break;
|
||||||
|
case 'l':
|
||||||
|
drain++;
|
||||||
|
p->bits = n;
|
||||||
|
set++;
|
||||||
|
break;
|
||||||
|
case 'm':
|
||||||
|
drain++;
|
||||||
|
if(ser->modemctl != nil)
|
||||||
|
ser->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][1];
|
||||||
|
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;
|
||||||
|
if(ser->wait4write != nil)
|
||||||
|
nw = ser->wait4write(p, &x, 1);
|
||||||
|
else
|
||||||
|
nw = write(p->epout->dfd, &x, 1);
|
||||||
|
if(nw != 1){
|
||||||
|
serialrecover(ser, p, p->epout, "");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
* don't print. the condition is harmless and the print
|
||||||
|
* splatters all over the display.
|
||||||
|
*/
|
||||||
|
USED(nop);
|
||||||
|
if (0 && nop)
|
||||||
|
fprint(2, "serial: %c, unsupported nop ctl\n", c);
|
||||||
|
}
|
||||||
|
if(drain)
|
||||||
|
serialdrain(p);
|
||||||
|
if(lines && !set){
|
||||||
|
if(ser->sendlines != nil && ser->sendlines(p) < 0)
|
||||||
|
return -1;
|
||||||
|
} else if(set){
|
||||||
|
if(ser->setparam != nil && ser->setparam(p) < 0)
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
ser->recover = 0;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
char *pformat = "noems";
|
||||||
|
|
||||||
|
char *
|
||||||
|
serdumpst(Serialport *p, char *buf, int bufsz)
|
||||||
|
{
|
||||||
|
char *e, *s;
|
||||||
|
Serial *ser;
|
||||||
|
|
||||||
|
ser = p->s;
|
||||||
|
|
||||||
|
e = buf + bufsz;
|
||||||
|
s = seprint(buf, e, "b%d ", p->baud);
|
||||||
|
s = seprint(s, e, "c%d ", p->dcd); /* unimplemented */
|
||||||
|
s = seprint(s, e, "d%d ", p->dtr);
|
||||||
|
s = seprint(s, e, "e%d ", p->dsr); /* unimplemented */
|
||||||
|
s = seprint(s, e, "l%d ", p->bits);
|
||||||
|
s = seprint(s, e, "m%d ", p->mctl);
|
||||||
|
if(p->parity >= 0 || p->parity < strlen(pformat))
|
||||||
|
s = seprint(s, e, "p%c ", pformat[p->parity]);
|
||||||
|
else
|
||||||
|
s = seprint(s, e, "p%c ", '?');
|
||||||
|
s = seprint(s, e, "r%d ", p->rts);
|
||||||
|
s = seprint(s, e, "s%d ", p->stop);
|
||||||
|
s = seprint(s, e, "i%d ", p->fifo);
|
||||||
|
s = seprint(s, e, "\ndev(%d) ", 0);
|
||||||
|
s = seprint(s, e, "type(%d) ", ser->type);
|
||||||
|
s = seprint(s, e, "framing(%d) ", p->nframeerr);
|
||||||
|
s = seprint(s, e, "overruns(%d) ", p->novererr);
|
||||||
|
s = seprint(s, e, "berr(%d) ", p->nbreakerr);
|
||||||
|
s = seprint(s, e, " serr(%d)\n", p->nparityerr);
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
serinit(Serialport *p)
|
||||||
|
{
|
||||||
|
int res;
|
||||||
|
res = 0;
|
||||||
|
Serial *ser;
|
||||||
|
|
||||||
|
ser = p->s;
|
||||||
|
|
||||||
|
if(ser->init != nil)
|
||||||
|
res = ser->init(p);
|
||||||
|
if(ser->getparam != nil)
|
||||||
|
ser->getparam(p);
|
||||||
|
p->nframeerr = p->nparityerr = p->nbreakerr = p->novererr = 0;
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
dattach(Req *req)
|
||||||
|
{
|
||||||
|
req->fid->qid = (Qid) {0, 0, QTDIR};
|
||||||
|
req->ofcall.qid = req->fid->qid;
|
||||||
|
respond(req, nil);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
dirgen(int n, Dir *d, void *)
|
||||||
|
{
|
||||||
|
if(n >= nports * 2)
|
||||||
|
return -1;
|
||||||
|
d->qid.path = n + 1;
|
||||||
|
d->qid.vers = 0;
|
||||||
|
if(n >= 0)
|
||||||
|
d->qid.type = 0;
|
||||||
|
else
|
||||||
|
d->qid.type = QTDIR;
|
||||||
|
d->uid = strdup("usb");
|
||||||
|
d->gid = strdup(d->uid);
|
||||||
|
d->muid = strdup(d->uid);
|
||||||
|
if(n >= 0){
|
||||||
|
d->name = smprint((n & 1) ? "%sctl" : "%s", ports[n/2]->name);
|
||||||
|
d->mode = ((n & 1) ? 0664 : 0660);
|
||||||
|
}else{
|
||||||
|
d->name = strdup("");
|
||||||
|
d->mode = 0555 | QTDIR;
|
||||||
|
}
|
||||||
|
d->atime = d->mtime = time(0);
|
||||||
|
d->length = 0;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static char *
|
||||||
|
dwalk(Fid *fid, char *name, Qid *qidp)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
int len;
|
||||||
|
Qid qid;
|
||||||
|
char *p;
|
||||||
|
|
||||||
|
qid = fid->qid;
|
||||||
|
if((qid.type & QTDIR) == 0){
|
||||||
|
return "walk in non-directory";
|
||||||
|
}
|
||||||
|
|
||||||
|
if(strcmp(name, "..") == 0){
|
||||||
|
fid->qid.path = 0;
|
||||||
|
fid->qid.vers = 0;
|
||||||
|
fid->qid.type = QTDIR;
|
||||||
|
*qidp = fid->qid;
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
|
||||||
|
for(i = 0; i < nports; i++)
|
||||||
|
if(strncmp(name, ports[i]->name, len = strlen(ports[i]->name)) == 0){
|
||||||
|
p = name + len;
|
||||||
|
if(*p == 0)
|
||||||
|
fid->qid.path = 2 * i + 1;
|
||||||
|
else if(strcmp(p, "ctl") == 0)
|
||||||
|
fid->qid.path = 2 * i + 2;
|
||||||
|
else
|
||||||
|
continue;
|
||||||
|
fid->qid.vers = 0;
|
||||||
|
fid->qid.type = 0;
|
||||||
|
*qidp = fid->qid;
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
return "does not exist";
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
dstat(Req *req)
|
||||||
|
{
|
||||||
|
if(dirgen(req->fid->qid.path - 1, &req->d, nil) < 0)
|
||||||
|
respond(req, "the front fell off");
|
||||||
|
else
|
||||||
|
respond(req, nil);
|
||||||
|
}
|
||||||
|
|
||||||
|
enum {
|
||||||
|
Serbufsize = 255,
|
||||||
|
};
|
||||||
|
|
||||||
|
static void
|
||||||
|
readproc(void *aux)
|
||||||
|
{
|
||||||
|
int dfd;
|
||||||
|
Req *req;
|
||||||
|
long count, rcount;
|
||||||
|
void *data;
|
||||||
|
Serial *ser;
|
||||||
|
Serialport *p;
|
||||||
|
static int errrun, good;
|
||||||
|
char err[Serbufsize];
|
||||||
|
|
||||||
|
p = aux;
|
||||||
|
ser = p->s;
|
||||||
|
for(;;){
|
||||||
|
qlock(&p->readq);
|
||||||
|
while(p->readfirst == nil)
|
||||||
|
rsleep(&p->readrend);
|
||||||
|
req = p->readfirst;
|
||||||
|
p->readfirst = req->aux;
|
||||||
|
if(p->readlast == req)
|
||||||
|
p->readlast = nil;
|
||||||
|
req->aux = nil;
|
||||||
|
qunlock(&p->readq);
|
||||||
|
|
||||||
|
count = req->ifcall.count;
|
||||||
|
data = req->ofcall.data;
|
||||||
|
qlock(ser);
|
||||||
|
if(count > ser->maxread)
|
||||||
|
count = ser->maxread;
|
||||||
|
dsprint(2, "serial: reading from data\n");
|
||||||
|
do {
|
||||||
|
err[0] = 0;
|
||||||
|
dfd = p->epin->dfd;
|
||||||
|
if(usbdebug >= 3)
|
||||||
|
dsprint(2, "serial: reading: %ld\n", count);
|
||||||
|
|
||||||
|
assert(count > 0);
|
||||||
|
if(ser->wait4data != nil)
|
||||||
|
rcount = ser->wait4data(p, data, count);
|
||||||
|
else{
|
||||||
|
qunlock(ser);
|
||||||
|
rcount = read(dfd, data, count);
|
||||||
|
qlock(ser);
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
* if we encounter a long run of continuous read
|
||||||
|
* errors, do something drastic so that our caller
|
||||||
|
* doesn't just spin its wheels forever.
|
||||||
|
*/
|
||||||
|
if(rcount < 0) {
|
||||||
|
snprint(err, Serbufsize, "%r");
|
||||||
|
++errrun;
|
||||||
|
sleep(20);
|
||||||
|
if (good > 0 && errrun > 10000) {
|
||||||
|
/* the line has been dropped; give up */
|
||||||
|
qunlock(ser);
|
||||||
|
fprint(2, "%s: line %s is gone: %r\n",
|
||||||
|
argv0, p->name);
|
||||||
|
threadexitsall("serial line gone");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
errrun = 0;
|
||||||
|
good++;
|
||||||
|
}
|
||||||
|
if(usbdebug >= 3)
|
||||||
|
dsprint(2, "serial: read: %s %ld\n", err, rcount);
|
||||||
|
} while(rcount < 0 && strstr(err, "timed out") != nil);
|
||||||
|
|
||||||
|
dsprint(2, "serial: read from bulk %ld, %10.10s\n", rcount, err);
|
||||||
|
if(rcount < 0){
|
||||||
|
dsprint(2, "serial: need to recover, data read %ld %r\n",
|
||||||
|
count);
|
||||||
|
serialrecover(ser, p, p->epin, err);
|
||||||
|
}
|
||||||
|
dsprint(2, "serial: read from bulk %ld\n", rcount);
|
||||||
|
if(rcount >= 0){
|
||||||
|
req->ofcall.count = rcount;
|
||||||
|
respond(req, nil);
|
||||||
|
} else
|
||||||
|
responderror(req);
|
||||||
|
qunlock(ser);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
dread(Req *req)
|
||||||
|
{
|
||||||
|
char *e; /* change */
|
||||||
|
Qid q;
|
||||||
|
Serial *ser;
|
||||||
|
vlong offset;
|
||||||
|
Serialport *p;
|
||||||
|
static char buf[Serbufsize];
|
||||||
|
|
||||||
|
q = req->fid->qid;
|
||||||
|
|
||||||
|
if(q.path == 0){
|
||||||
|
dirread9p(req, dirgen, nil);
|
||||||
|
respond(req, nil);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
p = ports[(q.path - 1) / 2];
|
||||||
|
ser = p->s;
|
||||||
|
offset = req->ifcall.offset;
|
||||||
|
|
||||||
|
memset(buf, 0, sizeof buf);
|
||||||
|
qlock(ser);
|
||||||
|
switch((long)((q.path - 1) % 2)){
|
||||||
|
case 0:
|
||||||
|
qlock(&p->readq);
|
||||||
|
if(p->readfirst == nil)
|
||||||
|
p->readfirst = req;
|
||||||
|
else
|
||||||
|
p->readlast->aux = req;
|
||||||
|
p->readlast = req;
|
||||||
|
rwakeup(&p->readrend);
|
||||||
|
qunlock(&p->readq);
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
if(offset == 0) {
|
||||||
|
if(!p->isjtag){
|
||||||
|
e = serdumpst(p, buf, Serbufsize);
|
||||||
|
readbuf(req, buf, e - buf);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
respond(req, nil);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
qunlock(ser);
|
||||||
|
}
|
||||||
|
|
||||||
|
static long
|
||||||
|
altwrite(Serialport *p, uchar *buf, long count)
|
||||||
|
{
|
||||||
|
int nw, dfd;
|
||||||
|
char err[128];
|
||||||
|
Serial *ser;
|
||||||
|
|
||||||
|
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);
|
||||||
|
else{
|
||||||
|
dfd = p->epout->dfd;
|
||||||
|
qunlock(ser);
|
||||||
|
nw = write(dfd, buf, count);
|
||||||
|
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){
|
||||||
|
dsprint(2, "serial: need to recover, status in write %d %r\n",
|
||||||
|
nw);
|
||||||
|
snprint(err, sizeof err, "%r");
|
||||||
|
serialrecover(p->s, p, p->epout, err);
|
||||||
|
}
|
||||||
|
return nw;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
dwrite(Req *req)
|
||||||
|
{
|
||||||
|
ulong path;
|
||||||
|
char *cmd;
|
||||||
|
Serial *ser;
|
||||||
|
long count;
|
||||||
|
void *buf;
|
||||||
|
Serialport *p;
|
||||||
|
|
||||||
|
path = req->fid->qid.path;
|
||||||
|
p = ports[(path-1)/2];
|
||||||
|
ser = p->s;
|
||||||
|
count = req->ifcall.count;
|
||||||
|
buf = req->ifcall.data;
|
||||||
|
|
||||||
|
qlock(ser);
|
||||||
|
switch((long)((path-1)%2)){
|
||||||
|
case 0:
|
||||||
|
count = altwrite(p, (uchar *)buf, count);
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
if(p->isjtag)
|
||||||
|
break;
|
||||||
|
cmd = emallocz(count+1, 1);
|
||||||
|
memmove(cmd, buf, count);
|
||||||
|
cmd[count] = 0;
|
||||||
|
if(serialctl(p, cmd) < 0){
|
||||||
|
qunlock(ser);
|
||||||
|
free(cmd);
|
||||||
|
respond(req, "bad control request");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
free(cmd);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if(count >= 0)
|
||||||
|
ser->recover = 0;
|
||||||
|
else
|
||||||
|
serialrecover(ser, p, p->epout, "writing");
|
||||||
|
qunlock(ser);
|
||||||
|
if(count >= 0){
|
||||||
|
req->ofcall.count = count;
|
||||||
|
respond(req, nil);
|
||||||
|
} else
|
||||||
|
responderror(req);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
openeps(Serialport *p, int epin, int epout, int epintr)
|
||||||
|
{
|
||||||
|
Serial *ser;
|
||||||
|
|
||||||
|
ser = p->s;
|
||||||
|
p->epin = openep(ser->dev, epin);
|
||||||
|
if(p->epin == nil){
|
||||||
|
fprint(2, "serial: openep %d: %r\n", epin);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
p->epout = openep(ser->dev, epout);
|
||||||
|
if(p->epout == nil){
|
||||||
|
fprint(2, "serial: openep %d: %r\n", epout);
|
||||||
|
closedev(p->epin);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!p->isjtag){
|
||||||
|
devctl(p->epin, "timeout 1000");
|
||||||
|
devctl(p->epout, "timeout 1000");
|
||||||
|
}
|
||||||
|
|
||||||
|
if(ser->hasepintr){
|
||||||
|
p->epintr = openep(ser->dev, epintr);
|
||||||
|
if(p->epintr == nil){
|
||||||
|
fprint(2, "serial: openep %d: %r\n", epintr);
|
||||||
|
closedev(p->epin);
|
||||||
|
closedev(p->epout);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
opendevdata(p->epintr, OREAD);
|
||||||
|
devctl(p->epintr, "timeout 1000");
|
||||||
|
}
|
||||||
|
|
||||||
|
if(ser->seteps!= nil)
|
||||||
|
ser->seteps(p);
|
||||||
|
opendevdata(p->epin, OREAD);
|
||||||
|
opendevdata(p->epout, OWRITE);
|
||||||
|
if(p->epin->dfd < 0 ||p->epout->dfd < 0 ||
|
||||||
|
(ser->hasepintr && p->epintr->dfd < 0)){
|
||||||
|
fprint(2, "serial: open i/o ep data: %r\n");
|
||||||
|
closedev(p->epin);
|
||||||
|
closedev(p->epout);
|
||||||
|
if(ser->hasepintr)
|
||||||
|
closedev(p->epintr);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
findendpoints(Serial *ser, int ifc)
|
||||||
|
{
|
||||||
|
int i, epin, epout, epintr;
|
||||||
|
Ep *ep, **eps;
|
||||||
|
|
||||||
|
epintr = epin = epout = -1;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* interfc 0 means start from the start which is equiv to
|
||||||
|
* iterate through endpoints probably, could be done better
|
||||||
|
*/
|
||||||
|
eps = ser->dev->usb->conf[0]->iface[ifc]->ep;
|
||||||
|
|
||||||
|
for(i = 0; i < Nep; i++){
|
||||||
|
if((ep = eps[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[%d]: ep ids: in %d out %d intr %d\n", ifc, epin, epout, epintr);
|
||||||
|
if(epin == -1 || epout == -1 || (ser->hasepintr && epintr == -1))
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
if(openeps(&ser->p[ifc], epin, epout, epintr) < 0)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
dprint(2, "serial: ep in %s out %s\n", ser->p[ifc].epin->dir, ser->p[ifc].epout->dir);
|
||||||
|
if(ser->hasepintr)
|
||||||
|
dprint(2, "serial: ep intr %s\n", ser->p[ifc].epintr->dir);
|
||||||
|
|
||||||
|
if(usbdebug > 1 || serialdebug > 2){
|
||||||
|
devctl(ser->p[ifc].epin, "debug 1");
|
||||||
|
devctl(ser->p[ifc].epout, "debug 1");
|
||||||
|
if(ser->hasepintr)
|
||||||
|
devctl(ser->p[ifc].epintr, "debug 1");
|
||||||
|
devctl(ser->dev, "debug 1");
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* keep in sync with main.c */
|
||||||
|
static void
|
||||||
|
usage(void)
|
||||||
|
{
|
||||||
|
fprint(2, "usage: usb/serial [-dD] [-m mtpt] [-s srv] devid\n");
|
||||||
|
threadexitsall("usage");
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
serdevfree(void *a)
|
||||||
|
{
|
||||||
|
Serial *ser = a;
|
||||||
|
Serialport *p;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
if(ser == nil)
|
||||||
|
return;
|
||||||
|
|
||||||
|
for(i = 0; i < ser->nifcs; i++){
|
||||||
|
p = &ser->p[i];
|
||||||
|
|
||||||
|
if(ser->hasepintr)
|
||||||
|
closedev(p->epintr);
|
||||||
|
closedev(p->epin);
|
||||||
|
closedev(p->epout);
|
||||||
|
p->epintr = p->epin = p->epout = nil;
|
||||||
|
if(p->w4data != nil)
|
||||||
|
chanfree(p->w4data);
|
||||||
|
if(p->gotdata != nil)
|
||||||
|
chanfree(p->gotdata);
|
||||||
|
if(p->readc)
|
||||||
|
chanfree(p->readc);
|
||||||
|
|
||||||
|
}
|
||||||
|
free(ser);
|
||||||
|
}
|
||||||
|
|
||||||
|
static Srv serialfs = {
|
||||||
|
.attach = dattach,
|
||||||
|
.walk1 = dwalk,
|
||||||
|
.read = dread,
|
||||||
|
.write= dwrite,
|
||||||
|
.stat = dstat,
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
static void
|
||||||
|
serialfsend(void)
|
||||||
|
{
|
||||||
|
if(p->w4data != nil)
|
||||||
|
chanclose(p->w4data);
|
||||||
|
if(p->gotdata != nil)
|
||||||
|
chanclose(p->gotdata);
|
||||||
|
if(p->readc)
|
||||||
|
chanclose(p->readc);
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
void
|
||||||
|
threadmain(int argc, char* argv[])
|
||||||
|
{
|
||||||
|
Serial *ser;
|
||||||
|
Dev *dev;
|
||||||
|
char buf[50];
|
||||||
|
int i, devid;
|
||||||
|
Serialport *p;
|
||||||
|
|
||||||
|
ARGBEGIN{
|
||||||
|
case 'd':
|
||||||
|
serialdebug++;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
usage();
|
||||||
|
}ARGEND
|
||||||
|
if(argc != 1)
|
||||||
|
usage();
|
||||||
|
devid = atoi(*argv);
|
||||||
|
dev = getdev(devid);
|
||||||
|
if(dev == nil)
|
||||||
|
sysfatal("getdev: %r");
|
||||||
|
|
||||||
|
ser = dev->aux = emallocz(sizeof(Serial), 1);
|
||||||
|
ser->maxrtrans = ser->maxwtrans = sizeof ser->p[0].data;
|
||||||
|
ser->maxread = ser->maxwrite = sizeof ser->p[0].data;
|
||||||
|
ser->dev = dev;
|
||||||
|
dev->free = serdevfree;
|
||||||
|
ser->jtag = -1;
|
||||||
|
ser->nifcs = 1;
|
||||||
|
|
||||||
|
snprint(buf, sizeof buf, "vid %#06x did %#06x",
|
||||||
|
dev->usb->vid, dev->usb->did);
|
||||||
|
if(plmatch(buf) == 0){
|
||||||
|
ser->hasepintr = 1;
|
||||||
|
ser->Serialops = plops;
|
||||||
|
} else if(uconsmatch(buf) == 0)
|
||||||
|
ser->Serialops = uconsops;
|
||||||
|
else if(ftmatch(ser, buf) == 0)
|
||||||
|
ser->Serialops = ftops;
|
||||||
|
else {
|
||||||
|
sysfatal("no serial devices found");
|
||||||
|
}
|
||||||
|
for(i = 0; i < ser->nifcs; i++){
|
||||||
|
p = &ser->p[i];
|
||||||
|
p->interfc = i;
|
||||||
|
p->s = ser;
|
||||||
|
if(i == ser->jtag){
|
||||||
|
p->isjtag++;
|
||||||
|
}
|
||||||
|
if(findendpoints(ser, i) < 0)
|
||||||
|
sysfatal("no endpoints found for ifc %d", i);
|
||||||
|
p->w4data = chancreate(sizeof(ulong), 0);
|
||||||
|
p->gotdata = chancreate(sizeof(ulong), 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
qlock(ser);
|
||||||
|
serialreset(ser);
|
||||||
|
for(i = 0; i < ser->nifcs; i++){
|
||||||
|
p = &ser->p[i];
|
||||||
|
dprint(2, "serial: valid interface, calling serinit\n");
|
||||||
|
if(serinit(p) < 0){
|
||||||
|
sysfatal("wserinit: %r");
|
||||||
|
}
|
||||||
|
|
||||||
|
dsprint(2, "serial: adding interface %d, %p\n", p->interfc, p);
|
||||||
|
if(p->isjtag){
|
||||||
|
snprint(p->name, sizeof p->name, "jtag");
|
||||||
|
dsprint(2, "serial: JTAG interface %d %p\n", i, p);
|
||||||
|
snprint(p->name, sizeof p->name, "jtag%d.%d", devid, i);
|
||||||
|
} else {
|
||||||
|
snprint(p->name, sizeof p->name, "eiaU");
|
||||||
|
if(i == 0)
|
||||||
|
snprint(p->name, sizeof p->name, "eiaU%d", devid);
|
||||||
|
else
|
||||||
|
snprint(p->name, sizeof p->name, "eiaU%d.%d", devid, i);
|
||||||
|
}
|
||||||
|
fprint(2, "%s...", p->name);
|
||||||
|
incref(dev);
|
||||||
|
p->readrend.l = &p->readq;
|
||||||
|
p->readpid = proccreate(readproc, p, mainstacksize);
|
||||||
|
ports = realloc(ports, (nports + 1) * sizeof(Serialport*));
|
||||||
|
ports[nports++] = p;
|
||||||
|
}
|
||||||
|
|
||||||
|
qunlock(ser);
|
||||||
|
if(nports > 0){
|
||||||
|
snprint(buf, sizeof buf, "serial-%d", devid);
|
||||||
|
threadpostsharesrv(&serialfs, nil, "usb", buf);
|
||||||
|
}
|
||||||
|
}
|
130
sys/src/cmd/nusb/serial/serial.h
Normal file
130
sys/src/cmd/nusb/serial/serial.h
Normal file
|
@ -0,0 +1,130 @@
|
||||||
|
typedef struct Serial Serial;
|
||||||
|
typedef struct Serialops Serialops;
|
||||||
|
typedef struct Serialport Serialport;
|
||||||
|
|
||||||
|
struct Serialops {
|
||||||
|
int (*seteps)(Serialport*);
|
||||||
|
int (*init)(Serialport*);
|
||||||
|
int (*getparam)(Serialport*);
|
||||||
|
int (*setparam)(Serialport*);
|
||||||
|
int (*clearpipes)(Serialport*);
|
||||||
|
int (*reset)(Serial*, Serialport*);
|
||||||
|
int (*sendlines)(Serialport*);
|
||||||
|
int (*modemctl)(Serialport*, int);
|
||||||
|
int (*setbreak)(Serialport*, int);
|
||||||
|
int (*readstatus)(Serialport*);
|
||||||
|
int (*wait4data)(Serialport*, uchar *, int);
|
||||||
|
int (*wait4write)(Serialport*, uchar *, int);
|
||||||
|
};
|
||||||
|
|
||||||
|
enum {
|
||||||
|
DataBufSz = 8*1024,
|
||||||
|
Maxifc = 16,
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
struct Serialport {
|
||||||
|
char name[32];
|
||||||
|
Serial *s; /* device we belong to */
|
||||||
|
int isjtag;
|
||||||
|
|
||||||
|
Dev *epintr; /* may not exist */
|
||||||
|
|
||||||
|
Dev *epin;
|
||||||
|
Dev *epout;
|
||||||
|
|
||||||
|
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;
|
||||||
|
int rlsd;
|
||||||
|
|
||||||
|
vlong timer;
|
||||||
|
int blocked; /* for sw flow ctl. BUG: not implemented yet */
|
||||||
|
int nbreakerr;
|
||||||
|
int ring;
|
||||||
|
int nframeerr;
|
||||||
|
int nparityerr;
|
||||||
|
int novererr;
|
||||||
|
int enabled;
|
||||||
|
|
||||||
|
int interfc; /* interfc on the device for ftdi */
|
||||||
|
|
||||||
|
Channel *w4data;
|
||||||
|
Channel *gotdata;
|
||||||
|
Channel *readc; /* to uncouple reads, only used in ftdi... */
|
||||||
|
int ndata;
|
||||||
|
uchar data[DataBufSz];
|
||||||
|
|
||||||
|
QLock readq;
|
||||||
|
Req *readfirst, *readlast; /* read request queue */
|
||||||
|
int readpid;
|
||||||
|
Rendez readrend;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Serial {
|
||||||
|
QLock;
|
||||||
|
Dev *dev; /* usb device*/
|
||||||
|
|
||||||
|
int type; /* serial model subtype */
|
||||||
|
int recover; /* # of non-fatal recovery tries */
|
||||||
|
Serialops;
|
||||||
|
|
||||||
|
int hasepintr;
|
||||||
|
|
||||||
|
int jtag; /* index of jtag interface, -1 none */
|
||||||
|
int nifcs; /* # of serial interfaces, including JTAG */
|
||||||
|
Serialport p[Maxifc];
|
||||||
|
int maxrtrans;
|
||||||
|
int maxwtrans;
|
||||||
|
|
||||||
|
int maxread;
|
||||||
|
int maxwrite;
|
||||||
|
|
||||||
|
int inhdrsz;
|
||||||
|
int outhdrsz;
|
||||||
|
int baudbase; /* for special baud base settings, see ftdi */
|
||||||
|
};
|
||||||
|
|
||||||
|
enum {
|
||||||
|
/* soft flow control chars */
|
||||||
|
CTLS = 023,
|
||||||
|
CTLQ = 021,
|
||||||
|
CtlDTR = 1,
|
||||||
|
CtlRTS = 2,
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* !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, Serialport *p, Dev *ep, char *err);
|
||||||
|
int serialreset(Serial *ser);
|
||||||
|
char *serdumpst(Serialport *p, char *buf, int bufsz);
|
48
sys/src/cmd/nusb/serial/ucons.c
Normal file
48
sys/src/cmd/nusb/serial/ucons.c
Normal file
|
@ -0,0 +1,48 @@
|
||||||
|
#include <u.h>
|
||||||
|
#include <libc.h>
|
||||||
|
#include <thread.h>
|
||||||
|
#include <fcall.h>
|
||||||
|
#include <9p.h>
|
||||||
|
#include "usb.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\n", buf, info);
|
||||||
|
if(strstr(info, buf) != nil)
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
ucseteps(Serialport *p)
|
||||||
|
{
|
||||||
|
Serial *ser;
|
||||||
|
|
||||||
|
ser = p->s;
|
||||||
|
|
||||||
|
p->baud = ~0; /* not real port */
|
||||||
|
ser->maxrtrans = ser->maxwtrans = 8;
|
||||||
|
devctl(p->epin, "maxpkt 8");
|
||||||
|
devctl(p->epout, "maxpkt 8");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* all nops */
|
||||||
|
Serialops uconsops = {
|
||||||
|
.seteps = ucseteps,
|
||||||
|
};
|
9
sys/src/cmd/nusb/serial/ucons.h
Normal file
9
sys/src/cmd/nusb/serial/ucons.h
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
|
||||||
|
|
||||||
|
enum {
|
||||||
|
Net20DCVid = 0x0525, /* Ajays usb debug cable */
|
||||||
|
Net20DCDid = 0x127a,
|
||||||
|
};
|
||||||
|
|
||||||
|
int uconsmatch(char *info);
|
||||||
|
extern Serialops uconsops;
|
Loading…
Add table
Add a link
Reference in a new issue