180e9508eSDavid du Colombier /* Future Technology Devices International serial ports */ 280e9508eSDavid du Colombier #include <u.h> 380e9508eSDavid du Colombier #include <libc.h> 480e9508eSDavid du Colombier #include <thread.h> 580e9508eSDavid du Colombier #include "usb.h" 680e9508eSDavid du Colombier #include "usbfs.h" 780e9508eSDavid du Colombier #include "serial.h" 880e9508eSDavid du Colombier #include "ftdi.h" 980e9508eSDavid du Colombier 1080e9508eSDavid du Colombier /* 1180e9508eSDavid du Colombier * BUG: This keeps growing, there has to be a better way, but without 1280e9508eSDavid du Colombier * devices to try it... We can probably simply look for FTDI in the 1380e9508eSDavid du Colombier * string, or use regular expressions somehow. 1480e9508eSDavid du Colombier */ 1580e9508eSDavid du Colombier Cinfo ftinfo[] = { 1680e9508eSDavid du Colombier { FTVid, FTACTZWAVEDid }, 1780e9508eSDavid du Colombier { FTSheevaVid, FTSheevaDid }, 183e5d0078SDavid du Colombier { FTVid, FTOpenRDUltDid}, 1980e9508eSDavid du Colombier { FTVid, FTIRTRANSDid }, 2080e9508eSDavid du Colombier { FTVid, FTIPLUSDid }, 2180e9508eSDavid du Colombier { FTVid, FTSIODid }, 2280e9508eSDavid du Colombier { FTVid, FT8U232AMDid }, 2380e9508eSDavid du Colombier { FTVid, FT8U232AMALTDid }, 2480e9508eSDavid du Colombier { FTVid, FT8U2232CDid }, 2580e9508eSDavid du Colombier { FTVid, FTRELAISDid }, 2680e9508eSDavid du Colombier { INTERBIOMVid, INTERBIOMIOBRDDid }, 2780e9508eSDavid du Colombier { INTERBIOMVid, INTERBIOMMINIIOBRDDid }, 2880e9508eSDavid du Colombier { FTVid, FTXF632Did }, 2980e9508eSDavid du Colombier { FTVid, FTXF634Did }, 3080e9508eSDavid du Colombier { FTVid, FTXF547Did }, 3180e9508eSDavid du Colombier { FTVid, FTXF633Did }, 3280e9508eSDavid du Colombier { FTVid, FTXF631Did }, 3380e9508eSDavid du Colombier { FTVid, FTXF635Did }, 3480e9508eSDavid du Colombier { FTVid, FTXF640Did }, 3580e9508eSDavid du Colombier { FTVid, FTXF642Did }, 3680e9508eSDavid du Colombier { FTVid, FTDSS20Did }, 3780e9508eSDavid du Colombier { FTNFRICVid, FTNFRICDid }, 3880e9508eSDavid du Colombier { FTVid, FTVNHCPCUSBDDid }, 3980e9508eSDavid du Colombier { FTVid, FTMTXORB0Did }, 4080e9508eSDavid du Colombier { FTVid, FTMTXORB1Did }, 4180e9508eSDavid du Colombier { FTVid, FTMTXORB2Did }, 4280e9508eSDavid du Colombier { FTVid, FTMTXORB3Did }, 4380e9508eSDavid du Colombier { FTVid, FTMTXORB4Did }, 4480e9508eSDavid du Colombier { FTVid, FTMTXORB5Did }, 4580e9508eSDavid du Colombier { FTVid, FTMTXORB6Did }, 4680e9508eSDavid du Colombier { FTVid, FTPERLEULTRAPORTDid }, 4780e9508eSDavid du Colombier { FTVid, FTPIEGROUPDid }, 4880e9508eSDavid du Colombier { SEALEVELVid, SEALEVEL2101Did }, 4980e9508eSDavid du Colombier { SEALEVELVid, SEALEVEL2102Did }, 5080e9508eSDavid du Colombier { SEALEVELVid, SEALEVEL2103Did }, 5180e9508eSDavid du Colombier { SEALEVELVid, SEALEVEL2104Did }, 5280e9508eSDavid du Colombier { SEALEVELVid, SEALEVEL22011Did }, 5380e9508eSDavid du Colombier { SEALEVELVid, SEALEVEL22012Did }, 5480e9508eSDavid du Colombier { SEALEVELVid, SEALEVEL22021Did }, 5580e9508eSDavid du Colombier { SEALEVELVid, SEALEVEL22022Did }, 5680e9508eSDavid du Colombier { SEALEVELVid, SEALEVEL22031Did }, 5780e9508eSDavid du Colombier { SEALEVELVid, SEALEVEL22032Did }, 5880e9508eSDavid du Colombier { SEALEVELVid, SEALEVEL24011Did }, 5980e9508eSDavid du Colombier { SEALEVELVid, SEALEVEL24012Did }, 6080e9508eSDavid du Colombier { SEALEVELVid, SEALEVEL24013Did }, 6180e9508eSDavid du Colombier { SEALEVELVid, SEALEVEL24014Did }, 6280e9508eSDavid du Colombier { SEALEVELVid, SEALEVEL24021Did }, 6380e9508eSDavid du Colombier { SEALEVELVid, SEALEVEL24022Did }, 6480e9508eSDavid du Colombier { SEALEVELVid, SEALEVEL24023Did }, 6580e9508eSDavid du Colombier { SEALEVELVid, SEALEVEL24024Did }, 6680e9508eSDavid du Colombier { SEALEVELVid, SEALEVEL24031Did }, 6780e9508eSDavid du Colombier { SEALEVELVid, SEALEVEL24032Did }, 6880e9508eSDavid du Colombier { SEALEVELVid, SEALEVEL24033Did }, 6980e9508eSDavid du Colombier { SEALEVELVid, SEALEVEL24034Did }, 7080e9508eSDavid du Colombier { SEALEVELVid, SEALEVEL28011Did }, 7180e9508eSDavid du Colombier { SEALEVELVid, SEALEVEL28012Did }, 7280e9508eSDavid du Colombier { SEALEVELVid, SEALEVEL28013Did }, 7380e9508eSDavid du Colombier { SEALEVELVid, SEALEVEL28014Did }, 7480e9508eSDavid du Colombier { SEALEVELVid, SEALEVEL28015Did }, 7580e9508eSDavid du Colombier { SEALEVELVid, SEALEVEL28016Did }, 7680e9508eSDavid du Colombier { SEALEVELVid, SEALEVEL28017Did }, 7780e9508eSDavid du Colombier { SEALEVELVid, SEALEVEL28018Did }, 7880e9508eSDavid du Colombier { SEALEVELVid, SEALEVEL28021Did }, 7980e9508eSDavid du Colombier { SEALEVELVid, SEALEVEL28022Did }, 8080e9508eSDavid du Colombier { SEALEVELVid, SEALEVEL28023Did }, 8180e9508eSDavid du Colombier { SEALEVELVid, SEALEVEL28024Did }, 8280e9508eSDavid du Colombier { SEALEVELVid, SEALEVEL28025Did }, 8380e9508eSDavid du Colombier { SEALEVELVid, SEALEVEL28026Did }, 8480e9508eSDavid du Colombier { SEALEVELVid, SEALEVEL28027Did }, 8580e9508eSDavid du Colombier { SEALEVELVid, SEALEVEL28028Did }, 8680e9508eSDavid du Colombier { SEALEVELVid, SEALEVEL28031Did }, 8780e9508eSDavid du Colombier { SEALEVELVid, SEALEVEL28032Did }, 8880e9508eSDavid du Colombier { SEALEVELVid, SEALEVEL28033Did }, 8980e9508eSDavid du Colombier { SEALEVELVid, SEALEVEL28034Did }, 9080e9508eSDavid du Colombier { SEALEVELVid, SEALEVEL28035Did }, 9180e9508eSDavid du Colombier { SEALEVELVid, SEALEVEL28036Did }, 9280e9508eSDavid du Colombier { SEALEVELVid, SEALEVEL28037Did }, 9380e9508eSDavid du Colombier { SEALEVELVid, SEALEVEL28038Did }, 9480e9508eSDavid du Colombier { IDTECHVid, IDTECHIDT1221UDid }, 9580e9508eSDavid du Colombier { OCTVid, OCTUS101Did }, 9680e9508eSDavid du Colombier { FTVid, FTHETIRA1Did }, /* special quirk div = 240 baud = B38400 rtscts = 1 */ 9780e9508eSDavid du Colombier { FTVid, FTUSBUIRTDid }, /* special quirk div = 77, baud = B38400 */ 9880e9508eSDavid du Colombier { FTVid, PROTEGOSPECIAL1 }, 9980e9508eSDavid du Colombier { FTVid, PROTEGOR2X0 }, 10080e9508eSDavid du Colombier { FTVid, PROTEGOSPECIAL3 }, 10180e9508eSDavid du Colombier { FTVid, PROTEGOSPECIAL4 }, 10280e9508eSDavid du Colombier { FTVid, FTGUDEADSE808Did }, 10380e9508eSDavid du Colombier { FTVid, FTGUDEADSE809Did }, 10480e9508eSDavid du Colombier { FTVid, FTGUDEADSE80ADid }, 10580e9508eSDavid du Colombier { FTVid, FTGUDEADSE80BDid }, 10680e9508eSDavid du Colombier { FTVid, FTGUDEADSE80CDid }, 10780e9508eSDavid du Colombier { FTVid, FTGUDEADSE80DDid }, 10880e9508eSDavid du Colombier { FTVid, FTGUDEADSE80EDid }, 10980e9508eSDavid du Colombier { FTVid, FTGUDEADSE80FDid }, 11080e9508eSDavid du Colombier { FTVid, FTGUDEADSE888Did }, 11180e9508eSDavid du Colombier { FTVid, FTGUDEADSE889Did }, 11280e9508eSDavid du Colombier { FTVid, FTGUDEADSE88ADid }, 11380e9508eSDavid du Colombier { FTVid, FTGUDEADSE88BDid }, 11480e9508eSDavid du Colombier { FTVid, FTGUDEADSE88CDid }, 11580e9508eSDavid du Colombier { FTVid, FTGUDEADSE88DDid }, 11680e9508eSDavid du Colombier { FTVid, FTGUDEADSE88EDid }, 11780e9508eSDavid du Colombier { FTVid, FTGUDEADSE88FDid }, 11880e9508eSDavid du Colombier { FTVid, FTELVUO100Did }, 11980e9508eSDavid du Colombier { FTVid, FTELVUM100Did }, 12080e9508eSDavid du Colombier { FTVid, FTELVUR100Did }, 12180e9508eSDavid du Colombier { FTVid, FTELVALC8500Did }, 12280e9508eSDavid du Colombier { FTVid, FTPYRAMIDDid }, 12380e9508eSDavid du Colombier { FTVid, FTELVFHZ1000PCDid }, 12480e9508eSDavid du Colombier { FTVid, FTELVCLI7000Did }, 12580e9508eSDavid du Colombier { FTVid, FTELVPPS7330Did }, 12680e9508eSDavid du Colombier { FTVid, FTELVTFM100Did }, 12780e9508eSDavid du Colombier { FTVid, FTELVUDF77Did }, 12880e9508eSDavid du Colombier { FTVid, FTELVUIO88Did }, 12980e9508eSDavid du Colombier { FTVid, FTELVUAD8Did }, 13080e9508eSDavid du Colombier { FTVid, FTELVUDA7Did }, 13180e9508eSDavid du Colombier { FTVid, FTELVUSI2Did }, 13280e9508eSDavid du Colombier { FTVid, FTELVT1100Did }, 13380e9508eSDavid du Colombier { FTVid, FTELVPCD200Did }, 13480e9508eSDavid du Colombier { FTVid, FTELVULA200Did }, 13580e9508eSDavid du Colombier { FTVid, FTELVCSI8Did }, 13680e9508eSDavid du Colombier { FTVid, FTELVEM1000DLDid }, 13780e9508eSDavid du Colombier { FTVid, FTELVPCK100Did }, 13880e9508eSDavid du Colombier { FTVid, FTELVRFP500Did }, 13980e9508eSDavid du Colombier { FTVid, FTELVFS20SIGDid }, 14080e9508eSDavid du Colombier { FTVid, FTELVWS300PCDid }, 14180e9508eSDavid du Colombier { FTVid, FTELVFHZ1300PCDid }, 14280e9508eSDavid du Colombier { FTVid, FTELVWS500Did }, 14380e9508eSDavid du Colombier { FTVid, LINXSDMUSBQSSDid }, 14480e9508eSDavid du Colombier { FTVid, LINXMASTERDEVEL2Did }, 14580e9508eSDavid du Colombier { FTVid, LINXFUTURE0Did }, 14680e9508eSDavid du Colombier { FTVid, LINXFUTURE1Did }, 14780e9508eSDavid du Colombier { FTVid, LINXFUTURE2Did }, 14880e9508eSDavid du Colombier { FTVid, FTCCSICDU200Did }, 14980e9508eSDavid du Colombier { FTVid, FTCCSICDU401Did }, 15080e9508eSDavid du Colombier { FTVid, INSIDEACCESSO }, 15180e9508eSDavid du Colombier { INTREDidVid, INTREDidVALUECANDid }, 15280e9508eSDavid du Colombier { INTREDidVid, INTREDidNEOVIDid }, 15380e9508eSDavid du Colombier { FALCOMVid, FALCOMTWISTDid }, 15480e9508eSDavid du Colombier { FALCOMVid, FALCOMSAMBADid }, 15580e9508eSDavid du Colombier { FTVid, FTSUUNTOSPORTSDid }, 15680e9508eSDavid du Colombier { FTVid, FTRMCANVIEWDid }, 15780e9508eSDavid du Colombier { BANDBVid, BANDBUSOTL4Did }, 15880e9508eSDavid du Colombier { BANDBVid, BANDBUSTL4Did }, 15980e9508eSDavid du Colombier { BANDBVid, BANDBUSO9ML2Did }, 16080e9508eSDavid du Colombier { FTVid, EVERECOPROCDSDid }, 16180e9508eSDavid du Colombier { FTVid, FT4NGALAXYDE0Did }, 16280e9508eSDavid du Colombier { FTVid, FT4NGALAXYDE1Did }, 16380e9508eSDavid du Colombier { FTVid, FT4NGALAXYDE2Did }, 16480e9508eSDavid du Colombier { FTVid, XSENSCONVERTER0Did }, 16580e9508eSDavid du Colombier { FTVid, XSENSCONVERTER1Did }, 16680e9508eSDavid du Colombier { FTVid, XSENSCONVERTER2Did }, 16780e9508eSDavid du Colombier { FTVid, XSENSCONVERTER3Did }, 16880e9508eSDavid du Colombier { FTVid, XSENSCONVERTER4Did }, 16980e9508eSDavid du Colombier { FTVid, XSENSCONVERTER5Did }, 17080e9508eSDavid du Colombier { FTVid, XSENSCONVERTER6Did }, 17180e9508eSDavid du Colombier { FTVid, XSENSCONVERTER7Did }, 17280e9508eSDavid du Colombier { MOBILITYVid, MOBILITYUSBSERIALDid }, 17380e9508eSDavid du Colombier { FTVid, FTACTIVEROBOTSDid }, 17480e9508eSDavid du Colombier { FTVid, FTMHAMKWDid }, 17580e9508eSDavid du Colombier { FTVid, FTMHAMYSDid }, 17680e9508eSDavid du Colombier { FTVid, FTMHAMY6Did }, 17780e9508eSDavid du Colombier { FTVid, FTMHAMY8Did }, 17880e9508eSDavid du Colombier { FTVid, FTMHAMICDid }, 17980e9508eSDavid du Colombier { FTVid, FTMHAMDB9Did }, 18080e9508eSDavid du Colombier { FTVid, FTMHAMRS232Did }, 18180e9508eSDavid du Colombier { FTVid, FTMHAMY9Did }, 18280e9508eSDavid du Colombier { FTVid, FTTERATRONIKVCPDid }, 18380e9508eSDavid du Colombier { FTVid, FTTERATRONIKD2XXDid }, 18480e9508eSDavid du Colombier { EVOLUTIONVid, EVOLUTIONER1Did }, 18580e9508eSDavid du Colombier { FTVid, FTARTEMISDid }, 18680e9508eSDavid du Colombier { FTVid, FTATIKATK16Did }, 18780e9508eSDavid du Colombier { FTVid, FTATIKATK16CDid }, 18880e9508eSDavid du Colombier { FTVid, FTATIKATK16HRDid }, 18980e9508eSDavid du Colombier { FTVid, FTATIKATK16HRCDid }, 19080e9508eSDavid du Colombier { KOBILVid, KOBILCONVB1Did }, 19180e9508eSDavid du Colombier { KOBILVid, KOBILCONVKAANDid }, 19280e9508eSDavid du Colombier { POSIFLEXVid, POSIFLEXPP7000Did }, 19380e9508eSDavid du Colombier { FTVid, FTTTUSBDid }, 19480e9508eSDavid du Colombier { FTVid, FTECLOCOM1WIREDid }, 19580e9508eSDavid du Colombier { FTVid, FTWESTREXMODEL777Did }, 19680e9508eSDavid du Colombier { FTVid, FTWESTREXMODEL8900FDid }, 19780e9508eSDavid du Colombier { FTVid, FTPCDJDAC2Did }, 19880e9508eSDavid du Colombier { FTVid, FTRRCIRKITSLOCOBUFFERDid }, 19980e9508eSDavid du Colombier { FTVid, FTASKRDR400Did }, 20080e9508eSDavid du Colombier { ICOMID1Vid, ICOMID1Did }, 20180e9508eSDavid du Colombier { PAPOUCHVid, PAPOUCHTMUDid }, 20280e9508eSDavid du Colombier { FTVid, FTACGHFDUALDid }, 203d5789509SDavid du Colombier { FT8U232AMDid, FT4232HDid }, 20480e9508eSDavid du Colombier { 0, 0 }, 20580e9508eSDavid du Colombier }; 20680e9508eSDavid du Colombier 20780e9508eSDavid du Colombier enum { 208d5789509SDavid du Colombier Packsz = 64, /* default size */ 209d5789509SDavid du Colombier Maxpacksz = 512, 210d5789509SDavid du Colombier Bufsiz = 4 * 1024, 21180e9508eSDavid du Colombier }; 21280e9508eSDavid du Colombier 21380e9508eSDavid du Colombier static int 214*d584e620SDavid du Colombier ftdiread(Serialport *p, int index, int req, uchar *buf, int len) 21580e9508eSDavid du Colombier { 21680e9508eSDavid du Colombier int res; 217d5789509SDavid du Colombier Serial *ser; 218d5789509SDavid du Colombier 219d5789509SDavid du Colombier ser = p->s; 22080e9508eSDavid du Colombier 22180e9508eSDavid du Colombier if(req != FTGETE2READ) 222d5789509SDavid du Colombier index |= p->interfc + 1; 223*d584e620SDavid du Colombier dsprint(2, "serial: ftdiread %#p [%d] req: %#x val: %#x idx:%d buf:%p len:%d\n", 224*d584e620SDavid du Colombier p, p->interfc, req, 0, index, buf, len); 225*d584e620SDavid du Colombier res = usbcmd(ser->dev, Rd2h | Rftdireq | Rdev, req, 0, index, buf, len); 22680e9508eSDavid du Colombier dsprint(2, "serial: ftdiread res:%d\n", res); 22780e9508eSDavid du Colombier return res; 22880e9508eSDavid du Colombier } 22980e9508eSDavid du Colombier 23080e9508eSDavid du Colombier static int 231d5789509SDavid du Colombier ftdiwrite(Serialport *p, int val, int index, int req) 23280e9508eSDavid du Colombier { 23380e9508eSDavid du Colombier int res; 234d5789509SDavid du Colombier Serial *ser; 23580e9508eSDavid du Colombier 236d5789509SDavid du Colombier ser = p->s; 237d5789509SDavid du Colombier 238*d584e620SDavid du Colombier if(req != FTGETE2READ || req != FTSETE2ERASE || req != FTSETBAUDRATE) 239d5789509SDavid du Colombier index |= p->interfc + 1; 240d5789509SDavid du Colombier dsprint(2, "serial: ftdiwrite %#p [%d] req: %#x val: %#x idx:%d\n", 241d5789509SDavid du Colombier p, p->interfc, req, val, index); 24280e9508eSDavid du Colombier res = usbcmd(ser->dev, Rh2d | Rftdireq | Rdev, req, val, index, nil, 0); 24380e9508eSDavid du Colombier dsprint(2, "serial: ftdiwrite res:%d\n", res); 24480e9508eSDavid du Colombier return res; 24580e9508eSDavid du Colombier } 24680e9508eSDavid du Colombier 24780e9508eSDavid du Colombier static int 248d5789509SDavid du Colombier ftmodemctl(Serialport *p, int set) 24980e9508eSDavid du Colombier { 25080e9508eSDavid du Colombier if(set == 0){ 251d5789509SDavid du Colombier p->mctl = 0; 252d5789509SDavid du Colombier ftdiwrite(p, 0, 0, FTSETMODEMCTRL); 25380e9508eSDavid du Colombier return 0; 25480e9508eSDavid du Colombier } 255d5789509SDavid du Colombier p->mctl = 1; 256d5789509SDavid du Colombier ftdiwrite(p, 0, FTRTSCTSHS, FTSETFLOWCTRL); 25780e9508eSDavid du Colombier return 0; 25880e9508eSDavid du Colombier } 25980e9508eSDavid du Colombier 26080e9508eSDavid du Colombier static ushort 26180e9508eSDavid du Colombier ft232ambaudbase2div(int baud, int base) 26280e9508eSDavid du Colombier { 26380e9508eSDavid du Colombier int divisor3; 26480e9508eSDavid du Colombier ushort divisor; 26580e9508eSDavid du Colombier 26680e9508eSDavid du Colombier divisor3 = (base / 2) / baud; 26780e9508eSDavid du Colombier if((divisor3 & 7) == 7) 26880e9508eSDavid du Colombier divisor3++; /* round x.7/8 up to x+1 */ 26980e9508eSDavid du Colombier divisor = divisor3 >> 3; 27080e9508eSDavid du Colombier divisor3 &= 7; 27180e9508eSDavid du Colombier 27280e9508eSDavid du Colombier if(divisor3 == 1) 27380e9508eSDavid du Colombier divisor |= 0xc000; /* 0.125 */ 27480e9508eSDavid du Colombier else if(divisor3 >= 4) 27580e9508eSDavid du Colombier divisor |= 0x4000; /* 0.5 */ 27680e9508eSDavid du Colombier else if(divisor3 != 0) 27780e9508eSDavid du Colombier divisor |= 0x8000; /* 0.25 */ 27880e9508eSDavid du Colombier if( divisor == 1) 27980e9508eSDavid du Colombier divisor = 0; /* special case for maximum baud rate */ 28080e9508eSDavid du Colombier return divisor; 28180e9508eSDavid du Colombier } 28280e9508eSDavid du Colombier 28380e9508eSDavid du Colombier enum{ 28480e9508eSDavid du Colombier ClockNew = 48000000, 28580e9508eSDavid du Colombier ClockOld = 12000000 / 16, 28680e9508eSDavid du Colombier HetiraDiv = 240, 28780e9508eSDavid du Colombier UirtDiv = 77, 28880e9508eSDavid du Colombier }; 28980e9508eSDavid du Colombier 29080e9508eSDavid du Colombier static ushort 29180e9508eSDavid du Colombier ft232ambaud2div(int baud) 29280e9508eSDavid du Colombier { 29380e9508eSDavid du Colombier return ft232ambaudbase2div(baud, ClockNew); 29480e9508eSDavid du Colombier } 29580e9508eSDavid du Colombier 29680e9508eSDavid du Colombier static ulong divfrac[8] = { 0, 3, 2, 4, 1, 5, 6, 7}; 29780e9508eSDavid du Colombier 29880e9508eSDavid du Colombier static ulong 29980e9508eSDavid du Colombier ft232bmbaudbase2div(int baud, int base) 30080e9508eSDavid du Colombier { 30180e9508eSDavid du Colombier int divisor3; 30280e9508eSDavid du Colombier u32int divisor; 30380e9508eSDavid du Colombier 30480e9508eSDavid du Colombier divisor3 = (base / 2) / baud; 30580e9508eSDavid du Colombier divisor = divisor3 >> 3 | divfrac[divisor3 & 7] << 14; 30680e9508eSDavid du Colombier 30780e9508eSDavid du Colombier /* Deal with special cases for highest baud rates. */ 30880e9508eSDavid du Colombier if( divisor == 1) 30980e9508eSDavid du Colombier divisor = 0; /* 1.0 */ 31080e9508eSDavid du Colombier else if( divisor == 0x4001) 31180e9508eSDavid du Colombier divisor = 1; /* 1.5 */ 31280e9508eSDavid du Colombier return divisor; 31380e9508eSDavid du Colombier } 31480e9508eSDavid du Colombier 31580e9508eSDavid du Colombier static ulong 31680e9508eSDavid du Colombier ft232bmbaud2div (int baud) 31780e9508eSDavid du Colombier { 31880e9508eSDavid du Colombier return ft232bmbaudbase2div (baud, ClockNew); 31980e9508eSDavid du Colombier } 32080e9508eSDavid du Colombier 32180e9508eSDavid du Colombier static int 32280e9508eSDavid du Colombier customdiv(Serial *ser) 32380e9508eSDavid du Colombier { 32480e9508eSDavid du Colombier if(ser->dev->usb->vid == FTVid && ser->dev->usb->did == FTHETIRA1Did) 32580e9508eSDavid du Colombier return HetiraDiv; 32680e9508eSDavid du Colombier else if(ser->dev->usb->vid == FTVid && ser->dev->usb->did == FTUSBUIRTDid) 32780e9508eSDavid du Colombier return UirtDiv; 32880e9508eSDavid du Colombier 32980e9508eSDavid du Colombier fprint(2, "serial: weird custom divisor\n"); 33080e9508eSDavid du Colombier return 0; /* shouldn't happen, break as much as I can */ 33180e9508eSDavid du Colombier } 33280e9508eSDavid du Colombier 33380e9508eSDavid du Colombier static ulong 33480e9508eSDavid du Colombier ftbaudcalcdiv(Serial *ser, int baud) 33580e9508eSDavid du Colombier { 33680e9508eSDavid du Colombier int cusdiv; 33780e9508eSDavid du Colombier ulong divval; 33880e9508eSDavid du Colombier 33980e9508eSDavid du Colombier if(baud == 38400 && (cusdiv = customdiv(ser)) != 0) 34080e9508eSDavid du Colombier baud = ser->baudbase / cusdiv; 34180e9508eSDavid du Colombier 34280e9508eSDavid du Colombier if(baud == 0) 34380e9508eSDavid du Colombier baud = 9600; 34480e9508eSDavid du Colombier 34580e9508eSDavid du Colombier switch(ser->type) { 34680e9508eSDavid du Colombier case SIO: 34780e9508eSDavid du Colombier switch(baud) { 34880e9508eSDavid du Colombier case 300: 34980e9508eSDavid du Colombier divval = FTb300; 35080e9508eSDavid du Colombier break; 35180e9508eSDavid du Colombier case 600: 35280e9508eSDavid du Colombier divval = FTb600; 35380e9508eSDavid du Colombier break; 35480e9508eSDavid du Colombier case 1200: 35580e9508eSDavid du Colombier divval = FTb1200; 35680e9508eSDavid du Colombier break; 35780e9508eSDavid du Colombier case 2400: 35880e9508eSDavid du Colombier divval = FTb2400; 35980e9508eSDavid du Colombier break; 36080e9508eSDavid du Colombier case 4800: 36180e9508eSDavid du Colombier divval = FTb4800; 36280e9508eSDavid du Colombier break; 36380e9508eSDavid du Colombier case 9600: 36480e9508eSDavid du Colombier divval = FTb9600; 36580e9508eSDavid du Colombier break; 36680e9508eSDavid du Colombier case 19200: 36780e9508eSDavid du Colombier divval = FTb19200; 36880e9508eSDavid du Colombier break; 36980e9508eSDavid du Colombier case 38400: 37080e9508eSDavid du Colombier divval = FTb38400; 37180e9508eSDavid du Colombier break; 37280e9508eSDavid du Colombier case 57600: 37380e9508eSDavid du Colombier divval = FTb57600; 37480e9508eSDavid du Colombier break; 37580e9508eSDavid du Colombier case 115200: 37680e9508eSDavid du Colombier divval = FTb115200; 37780e9508eSDavid du Colombier break; 37880e9508eSDavid du Colombier default: 37980e9508eSDavid du Colombier divval = FTb9600; 38080e9508eSDavid du Colombier break; 38180e9508eSDavid du Colombier } 38280e9508eSDavid du Colombier break; 38380e9508eSDavid du Colombier case FT8U232AM: 38480e9508eSDavid du Colombier if(baud <= 3000000) 38580e9508eSDavid du Colombier divval = ft232ambaud2div(baud); 38680e9508eSDavid du Colombier else 38780e9508eSDavid du Colombier divval = ft232ambaud2div(9600); 38880e9508eSDavid du Colombier break; 38980e9508eSDavid du Colombier case FT232BM: 39080e9508eSDavid du Colombier case FT2232C: 391d5789509SDavid du Colombier case FTKINDR: 392d5789509SDavid du Colombier case FT2232H: 393d5789509SDavid du Colombier case FT4232H: 39480e9508eSDavid du Colombier if(baud <= 3000000) 39580e9508eSDavid du Colombier divval = ft232bmbaud2div(baud); 39680e9508eSDavid du Colombier else 39780e9508eSDavid du Colombier divval = ft232bmbaud2div(9600); 39880e9508eSDavid du Colombier break; 39980e9508eSDavid du Colombier default: 40080e9508eSDavid du Colombier divval = ft232bmbaud2div(9600); 40180e9508eSDavid du Colombier break; 40280e9508eSDavid du Colombier } 40380e9508eSDavid du Colombier return divval; 40480e9508eSDavid du Colombier } 40580e9508eSDavid du Colombier 40680e9508eSDavid du Colombier static int 407d5789509SDavid du Colombier ftsetparam(Serialport *p) 40880e9508eSDavid du Colombier { 40980e9508eSDavid du Colombier int res; 41080e9508eSDavid du Colombier ushort val; 41180e9508eSDavid du Colombier ulong bauddiv; 41280e9508eSDavid du Colombier 41380e9508eSDavid du Colombier val = 0; 414d5789509SDavid du Colombier if(p->stop == 1) 41580e9508eSDavid du Colombier val |= FTSETDATASTOPBITS1; 416d5789509SDavid du Colombier else if(p->stop == 2) 41780e9508eSDavid du Colombier val |= FTSETDATASTOPBITS2; 418d5789509SDavid du Colombier else if(p->stop == 15) 41980e9508eSDavid du Colombier val |= FTSETDATASTOPBITS15; 420d5789509SDavid du Colombier switch(p->parity){ 42180e9508eSDavid du Colombier case 0: 42280e9508eSDavid du Colombier val |= FTSETDATAParNONE; 42380e9508eSDavid du Colombier break; 42480e9508eSDavid du Colombier case 1: 42580e9508eSDavid du Colombier val |= FTSETDATAParODD; 42680e9508eSDavid du Colombier break; 42780e9508eSDavid du Colombier case 2: 42880e9508eSDavid du Colombier val |= FTSETDATAParEVEN; 42980e9508eSDavid du Colombier break; 43080e9508eSDavid du Colombier case 3: 43180e9508eSDavid du Colombier val |= FTSETDATAParMARK; 43280e9508eSDavid du Colombier break; 43380e9508eSDavid du Colombier case 4: 43480e9508eSDavid du Colombier val |= FTSETDATAParSPACE; 43580e9508eSDavid du Colombier break; 43680e9508eSDavid du Colombier }; 43780e9508eSDavid du Colombier 43880e9508eSDavid du Colombier dsprint(2, "serial: setparam\n"); 43980e9508eSDavid du Colombier 440d5789509SDavid du Colombier res = ftdiwrite(p, val, 0, FTSETDATA); 44180e9508eSDavid du Colombier if(res < 0) 44280e9508eSDavid du Colombier return res; 44380e9508eSDavid du Colombier 444d5789509SDavid du Colombier res = ftmodemctl(p, p->mctl); 44580e9508eSDavid du Colombier if(res < 0) 44680e9508eSDavid du Colombier return res; 44780e9508eSDavid du Colombier 448d5789509SDavid du Colombier bauddiv = ftbaudcalcdiv(p->s, p->baud); 449*d584e620SDavid du Colombier res = ftdiwrite(p, bauddiv, (bauddiv>>16) & 1, FTSETBAUDRATE); 45080e9508eSDavid du Colombier 45180e9508eSDavid du Colombier dsprint(2, "serial: setparam res: %d\n", res); 45280e9508eSDavid du Colombier return res; 45380e9508eSDavid du Colombier } 45480e9508eSDavid du Colombier 45580e9508eSDavid du Colombier /* ser locked */ 45680e9508eSDavid du Colombier static void 45780e9508eSDavid du Colombier ftgettype(Serial *ser) 45880e9508eSDavid du Colombier { 459d5789509SDavid du Colombier int i, outhdrsz, dno, pksz; 46080e9508eSDavid du Colombier ulong baudbase; 46180e9508eSDavid du Colombier Conf *cnf; 46280e9508eSDavid du Colombier 463d5789509SDavid du Colombier pksz = Packsz; 46480e9508eSDavid du Colombier /* Assume it is not the original SIO device for now. */ 46580e9508eSDavid du Colombier baudbase = ClockNew / 2; 46680e9508eSDavid du Colombier outhdrsz = 0; 46780e9508eSDavid du Colombier dno = ser->dev->usb->dno; 46880e9508eSDavid du Colombier cnf = ser->dev->usb->conf[0]; 469d5789509SDavid du Colombier ser->nifcs = 0; 47080e9508eSDavid du Colombier for(i = 0; i < Niface; i++) 47180e9508eSDavid du Colombier if(cnf->iface[i] != nil) 472d5789509SDavid du Colombier ser->nifcs++; 473d5789509SDavid du Colombier if(ser->nifcs > 1) { 47480e9508eSDavid du Colombier /* 475d5789509SDavid du Colombier * Multiple interfaces. default assume FT2232C, 47680e9508eSDavid du Colombier */ 477d5789509SDavid du Colombier if(dno == 0x500) 478d5789509SDavid du Colombier ser->type = FT2232C; 479d5789509SDavid du Colombier else if(dno == 0x600) 480d5789509SDavid du Colombier ser->type = FTKINDR; 481d5789509SDavid du Colombier else if(dno == 0x700){ 482d5789509SDavid du Colombier ser->type = FT2232H; 483d5789509SDavid du Colombier pksz = Maxpacksz; 484d5789509SDavid du Colombier } else if(dno == 0x800){ 485d5789509SDavid du Colombier ser->type = FT4232H; 486d5789509SDavid du Colombier pksz = Maxpacksz; 487d5789509SDavid du Colombier } else 488d5789509SDavid du Colombier ser->type = FT2232C; 489d5789509SDavid du Colombier 490d5789509SDavid du Colombier ser->jtag = 0; 49180e9508eSDavid du Colombier 49280e9508eSDavid du Colombier /* 49380e9508eSDavid du Colombier * BM-type devices have a bug where dno gets set 49480e9508eSDavid du Colombier * to 0x200 when serial is 0. 49580e9508eSDavid du Colombier */ 49680e9508eSDavid du Colombier if(dno < 0x500) 497d5789509SDavid du Colombier fprint(2, "serial: warning: dno %d too low for " 498d5789509SDavid du Colombier "multi-interface device\n", dno); 49980e9508eSDavid du Colombier } else if(dno < 0x200) { 50080e9508eSDavid du Colombier /* Old device. Assume it is the original SIO. */ 50180e9508eSDavid du Colombier ser->type = SIO; 50280e9508eSDavid du Colombier baudbase = ClockOld/16; 50380e9508eSDavid du Colombier outhdrsz = 1; 50480e9508eSDavid du Colombier } else if(dno < 0x400) 50580e9508eSDavid du Colombier /* 50680e9508eSDavid du Colombier * Assume its an FT8U232AM (or FT8U245AM) 50780e9508eSDavid du Colombier * (It might be a BM because of the iSerialNumber bug, 50880e9508eSDavid du Colombier * but it will still work as an AM device.) 50980e9508eSDavid du Colombier */ 51080e9508eSDavid du Colombier ser->type = FT8U232AM; 51180e9508eSDavid du Colombier else /* Assume it is an FT232BM (or FT245BM) */ 51280e9508eSDavid du Colombier ser->type = FT232BM; 51380e9508eSDavid du Colombier 514d5789509SDavid du Colombier ser->maxrtrans = ser->maxwtrans = pksz; 51580e9508eSDavid du Colombier ser->baudbase = baudbase; 51680e9508eSDavid du Colombier ser->outhdrsz = outhdrsz; 51780e9508eSDavid du Colombier ser->inhdrsz = 2; 518d5789509SDavid du Colombier 51980e9508eSDavid du Colombier dsprint (2, "serial: detected type: %#x\n", ser->type); 52080e9508eSDavid du Colombier } 52180e9508eSDavid du Colombier 52280e9508eSDavid du Colombier int 52380e9508eSDavid du Colombier ftmatch(Serial *ser, char *info) 52480e9508eSDavid du Colombier { 52580e9508eSDavid du Colombier Cinfo *ip; 52680e9508eSDavid du Colombier char buf[50]; 52780e9508eSDavid du Colombier 52880e9508eSDavid du Colombier for(ip = ftinfo; ip->vid != 0; ip++){ 52980e9508eSDavid du Colombier snprint(buf, sizeof buf, "vid %#06x did %#06x", ip->vid, ip->did); 53080e9508eSDavid du Colombier dsprint(2, "serial: %s %s\n", buf, info); 53180e9508eSDavid du Colombier if(strstr(info, buf) != nil){ 53280e9508eSDavid du Colombier if(ser != nil){ 53380e9508eSDavid du Colombier qlock(ser); 53480e9508eSDavid du Colombier ftgettype(ser); 53580e9508eSDavid du Colombier qunlock(ser); 53680e9508eSDavid du Colombier } 53780e9508eSDavid du Colombier return 0; 53880e9508eSDavid du Colombier } 53980e9508eSDavid du Colombier } 54080e9508eSDavid du Colombier return -1; 54180e9508eSDavid du Colombier } 54280e9508eSDavid du Colombier 54380e9508eSDavid du Colombier static int 544d5789509SDavid du Colombier ftuseinhdr(Serialport *p, uchar *b) 54580e9508eSDavid du Colombier { 54680e9508eSDavid du Colombier if(b[0] & FTICTS) 547d5789509SDavid du Colombier p->cts = 1; 54880e9508eSDavid du Colombier else 549d5789509SDavid du Colombier p->cts = 0; 55080e9508eSDavid du Colombier if(b[0] & FTIDSR) 551d5789509SDavid du Colombier p->dsr = 1; 55280e9508eSDavid du Colombier else 553d5789509SDavid du Colombier p->dsr = 0; 55480e9508eSDavid du Colombier if(b[0] & FTIRI) 555d5789509SDavid du Colombier p->ring = 1; 55680e9508eSDavid du Colombier else 557d5789509SDavid du Colombier p->ring = 0; 55880e9508eSDavid du Colombier if(b[0] & FTIRLSD) 559d5789509SDavid du Colombier p->rlsd = 1; 56080e9508eSDavid du Colombier else 561d5789509SDavid du Colombier p->rlsd = 0; 56280e9508eSDavid du Colombier 56380e9508eSDavid du Colombier if(b[1] & FTIOE) 564d5789509SDavid du Colombier p->novererr++; 56580e9508eSDavid du Colombier if(b[1] & FTIPE) 566d5789509SDavid du Colombier p->nparityerr++; 56780e9508eSDavid du Colombier if(b[1] & FTIFE) 568d5789509SDavid du Colombier p->nframeerr++; 56980e9508eSDavid du Colombier if(b[1] & FTIBI) 570d5789509SDavid du Colombier p->nbreakerr++; 57180e9508eSDavid du Colombier return 0; 57280e9508eSDavid du Colombier } 57380e9508eSDavid du Colombier 57480e9508eSDavid du Colombier static int 575d5789509SDavid du Colombier ftsetouthdr(Serialport *p, uchar *b, int len) 57680e9508eSDavid du Colombier { 577d5789509SDavid du Colombier if(p->s->outhdrsz != 0) 57880e9508eSDavid du Colombier b[0] = FTOPORT | (FTOLENMSK & len); 579d5789509SDavid du Colombier return p->s->outhdrsz; 58080e9508eSDavid du Colombier } 58180e9508eSDavid du Colombier 58280e9508eSDavid du Colombier static int 583d5789509SDavid du Colombier wait4data(Serialport *p, uchar *data, int count) 58480e9508eSDavid du Colombier { 585d5789509SDavid du Colombier int d; 586d5789509SDavid du Colombier Serial *ser; 587d5789509SDavid du Colombier 588d5789509SDavid du Colombier ser = p->s; 589d5789509SDavid du Colombier 59080e9508eSDavid du Colombier qunlock(ser); 591d5789509SDavid du Colombier d = sendul(p->w4data, 1); 592ed868a7cSDavid du Colombier qlock(ser); 593d5789509SDavid du Colombier if(d <= 0) 594d5789509SDavid du Colombier return -1; 595d5789509SDavid du Colombier if(p->ndata >= count) 596d5789509SDavid du Colombier p->ndata -= count; 59780e9508eSDavid du Colombier else{ 598d5789509SDavid du Colombier count = p->ndata; 599d5789509SDavid du Colombier p->ndata = 0; 60080e9508eSDavid du Colombier } 601ecc2a7c8SDavid du Colombier assert(count >= 0); 602d5789509SDavid du Colombier assert(p->ndata >= 0); 603d5789509SDavid du Colombier memmove(data, p->data, count); 604d5789509SDavid du Colombier if(p->ndata != 0) 605d5789509SDavid du Colombier memmove(p->data, p->data+count, p->ndata); 60680e9508eSDavid du Colombier 607d5789509SDavid du Colombier recvul(p->gotdata); 60880e9508eSDavid du Colombier return count; 60980e9508eSDavid du Colombier } 61080e9508eSDavid du Colombier 61180e9508eSDavid du Colombier static int 612d5789509SDavid du Colombier wait4write(Serialport *p, uchar *data, int count) 61380e9508eSDavid du Colombier { 61480e9508eSDavid du Colombier int off, fd; 61580e9508eSDavid du Colombier uchar *b; 616d5789509SDavid du Colombier Serial *ser; 61780e9508eSDavid du Colombier 618d5789509SDavid du Colombier ser = p->s; 61980e9508eSDavid du Colombier 62080e9508eSDavid du Colombier b = emallocz(count+ser->outhdrsz, 1); 621d5789509SDavid du Colombier off = ftsetouthdr(p, b, count); 62280e9508eSDavid du Colombier memmove(b+off, data, count); 62380e9508eSDavid du Colombier 624d5789509SDavid du Colombier fd = p->epout->dfd; 62580e9508eSDavid du Colombier qunlock(ser); 62680e9508eSDavid du Colombier count = write(fd, b, count+off); 62780e9508eSDavid du Colombier qlock(ser); 62880e9508eSDavid du Colombier free(b); 62980e9508eSDavid du Colombier return count; 63080e9508eSDavid du Colombier } 63180e9508eSDavid du Colombier 63280e9508eSDavid du Colombier typedef struct Packser Packser; 63380e9508eSDavid du Colombier struct Packser{ 63480e9508eSDavid du Colombier int nb; 635d5789509SDavid du Colombier uchar b[Bufsiz]; 63680e9508eSDavid du Colombier }; 63780e9508eSDavid du Colombier 63880e9508eSDavid du Colombier typedef struct Areader Areader; 63980e9508eSDavid du Colombier struct Areader{ 640d5789509SDavid du Colombier Serialport *p; 64180e9508eSDavid du Colombier Channel *c; 64280e9508eSDavid du Colombier }; 64380e9508eSDavid du Colombier 64480e9508eSDavid du Colombier static void 645d5789509SDavid du Colombier shutdownchan(Channel *c) 646d5789509SDavid du Colombier { 647d5789509SDavid du Colombier Packser *bp; 648d5789509SDavid du Colombier 649d5789509SDavid du Colombier while((bp=nbrecvp(c)) != nil) 650d5789509SDavid du Colombier free(bp); 651d5789509SDavid du Colombier chanfree(c); 652d5789509SDavid du Colombier } 653d5789509SDavid du Colombier 654d5789509SDavid du Colombier int 655d5789509SDavid du Colombier cpdata(Serial *ser, Serialport *port, uchar *out, uchar *in, int sz) 656d5789509SDavid du Colombier { 657d5789509SDavid du Colombier int i, ncp, ntotcp, pksz; 658d5789509SDavid du Colombier 659d5789509SDavid du Colombier pksz = ser->maxrtrans; 660d5789509SDavid du Colombier ntotcp = 0; 661d5789509SDavid du Colombier 662d5789509SDavid du Colombier for(i = 0; i < sz; i+= pksz){ 663d5789509SDavid du Colombier ftuseinhdr(port, in + i); 664d5789509SDavid du Colombier if(sz - i > pksz) 665d5789509SDavid du Colombier ncp = pksz - ser->inhdrsz; 666d5789509SDavid du Colombier else 667d5789509SDavid du Colombier ncp = sz - i - ser->inhdrsz; 668d5789509SDavid du Colombier memmove(out, in + i + ser->inhdrsz, ncp); 669d5789509SDavid du Colombier out += ncp; 670d5789509SDavid du Colombier ntotcp += ncp; 671d5789509SDavid du Colombier } 672d5789509SDavid du Colombier return ntotcp; 673d5789509SDavid du Colombier } 674d5789509SDavid du Colombier 675d5789509SDavid du Colombier static void 67680e9508eSDavid du Colombier epreader(void *u) 67780e9508eSDavid du Colombier { 678d5789509SDavid du Colombier int dfd, rcount, cl; 67980e9508eSDavid du Colombier char err[40]; 68080e9508eSDavid du Colombier Areader *a; 68180e9508eSDavid du Colombier Channel *c; 682d5789509SDavid du Colombier Packser *pk; 68380e9508eSDavid du Colombier Serial *ser; 684d5789509SDavid du Colombier Serialport *p; 68580e9508eSDavid du Colombier 68680e9508eSDavid du Colombier threadsetname("epreader proc"); 68780e9508eSDavid du Colombier a = u; 688d5789509SDavid du Colombier p = a->p; 689d5789509SDavid du Colombier ser = p->s; 69080e9508eSDavid du Colombier c = a->c; 69180e9508eSDavid du Colombier free(a); 69280e9508eSDavid du Colombier 69380e9508eSDavid du Colombier qlock(ser); 694d5789509SDavid du Colombier dfd = p->epin->dfd; 69580e9508eSDavid du Colombier qunlock(ser); 69680e9508eSDavid du Colombier 697d5789509SDavid du Colombier pk = nil; 69880e9508eSDavid du Colombier do { 699d5789509SDavid du Colombier if (pk == nil) 700d5789509SDavid du Colombier pk = emallocz(sizeof(Packser), 1); 701d5789509SDavid du Colombier rcount = read(dfd, pk->b, sizeof pk->b); 70280e9508eSDavid du Colombier if(serialdebug > 5) 703d5789509SDavid du Colombier dsprint(2, "%d %#ux%#ux ", rcount, p->data[0], 704d5789509SDavid du Colombier p->data[1]); 705d5789509SDavid du Colombier if(rcount < 0) 70680e9508eSDavid du Colombier break; 707d5789509SDavid du Colombier if(rcount == 0) 708d5789509SDavid du Colombier continue; 70980e9508eSDavid du Colombier if(rcount >= ser->inhdrsz){ 710d5789509SDavid du Colombier rcount = cpdata(ser, p, pk->b, pk->b, rcount); 71180e9508eSDavid du Colombier if(rcount != 0){ 712d5789509SDavid du Colombier pk->nb = rcount; 713d5789509SDavid du Colombier cl = sendp(c, pk); 714d5789509SDavid du Colombier if(cl < 0){ 715d5789509SDavid du Colombier /* 716d5789509SDavid du Colombier * if it was a time-out, I don't want 717d5789509SDavid du Colombier * to give back an error. 718d5789509SDavid du Colombier */ 719d5789509SDavid du Colombier rcount = 0; 720d5789509SDavid du Colombier break; 72180e9508eSDavid du Colombier } 722d5789509SDavid du Colombier }else 723d5789509SDavid du Colombier free(pk); 724d5789509SDavid du Colombier pk = nil; 72580e9508eSDavid du Colombier } 72680e9508eSDavid du Colombier } while(rcount >= 0 || (rcount < 0 && strstr(err, "timed out") != nil)); 72780e9508eSDavid du Colombier 72880e9508eSDavid du Colombier if(rcount < 0) 729d5789509SDavid du Colombier fprint(2, "%s: error reading %s: %r\n", argv0, p->fs.name); 730d5789509SDavid du Colombier free(pk); 731d5789509SDavid du Colombier nbsendp(c, nil); 732d5789509SDavid du Colombier if(p->w4data != nil) 733d5789509SDavid du Colombier chanclose(p->w4data); 734d5789509SDavid du Colombier if(p->gotdata != nil) 735d5789509SDavid du Colombier chanclose(p->gotdata); 736d5789509SDavid du Colombier devctl(ser->dev, "detach"); 73780e9508eSDavid du Colombier closedev(ser->dev); 738d5789509SDavid du Colombier usbfsdel(&p->fs); 73980e9508eSDavid du Colombier } 74080e9508eSDavid du Colombier 74180e9508eSDavid du Colombier static void 74280e9508eSDavid du Colombier statusreader(void *u) 74380e9508eSDavid du Colombier { 74480e9508eSDavid du Colombier Areader *a; 74580e9508eSDavid du Colombier Channel *c; 746d5789509SDavid du Colombier Packser *pk; 747d5789509SDavid du Colombier Serialport *p; 74880e9508eSDavid du Colombier Serial *ser; 749d5789509SDavid du Colombier int cl; 75080e9508eSDavid du Colombier 751d5789509SDavid du Colombier p = u; 752d5789509SDavid du Colombier ser = p->s; 75380e9508eSDavid du Colombier threadsetname("statusreader thread"); 75480e9508eSDavid du Colombier /* big buffering, fewer bytes lost */ 75580e9508eSDavid du Colombier c = chancreate(sizeof(Packser *), 128); 75680e9508eSDavid du Colombier a = emallocz(sizeof(Areader), 1); 757d5789509SDavid du Colombier a->p = p; 75880e9508eSDavid du Colombier a->c = c; 75980e9508eSDavid du Colombier incref(ser->dev); 76080e9508eSDavid du Colombier proccreate(epreader, a, 16*1024); 76180e9508eSDavid du Colombier 762d5789509SDavid du Colombier while((pk = recvp(c)) != nil){ 763d5789509SDavid du Colombier memmove(p->data, pk->b, pk->nb); 764d5789509SDavid du Colombier p->ndata = pk->nb; 765d5789509SDavid du Colombier free(pk); 766*d584e620SDavid du Colombier dsprint(2, "serial %p: status reader %d \n", p, p->ndata); 76780e9508eSDavid du Colombier /* consume it all */ 768d5789509SDavid du Colombier while(p->ndata != 0){ 769*d584e620SDavid du Colombier dsprint(2, "serial %p: status reader to consume: %d\n", 770*d584e620SDavid du Colombier p, p->ndata); 771d5789509SDavid du Colombier cl = recvul(p->w4data); 772d5789509SDavid du Colombier if(cl < 0) 773d5789509SDavid du Colombier break; 774d5789509SDavid du Colombier cl = sendul(p->gotdata, 1); 775d5789509SDavid du Colombier if(cl < 0) 776d5789509SDavid du Colombier break; 77780e9508eSDavid du Colombier } 77880e9508eSDavid du Colombier } 779d5789509SDavid du Colombier 780d5789509SDavid du Colombier shutdownchan(c); 781d5789509SDavid du Colombier devctl(ser->dev, "detach"); 78280e9508eSDavid du Colombier closedev(ser->dev); 783d5789509SDavid du Colombier usbfsdel(&p->fs); 78480e9508eSDavid du Colombier } 78580e9508eSDavid du Colombier 78680e9508eSDavid du Colombier static int 78780e9508eSDavid du Colombier ftreset(Serial *ser) 78880e9508eSDavid du Colombier { 789d5789509SDavid du Colombier Serialport *p; 790d5789509SDavid du Colombier int i; 791d5789509SDavid du Colombier 792d5789509SDavid du Colombier p = ser->p; 793d5789509SDavid du Colombier for(i = 0; i < Maxifc; i++) 794*d584e620SDavid du Colombier if(p[i].s != nil) 795d5789509SDavid du Colombier ftdiwrite(&p[i], FTRESETCTLVAL, 0, FTRESET); 79680e9508eSDavid du Colombier return 0; 79780e9508eSDavid du Colombier } 79880e9508eSDavid du Colombier 79980e9508eSDavid du Colombier static int 800d5789509SDavid du Colombier ftinit(Serialport *p) 80180e9508eSDavid du Colombier { 802d5789509SDavid du Colombier Serial *ser; 803*d584e620SDavid du Colombier uint timerval; 804*d584e620SDavid du Colombier int res; 80580e9508eSDavid du Colombier 806d5789509SDavid du Colombier ser = p->s; 807*d584e620SDavid du Colombier if(p->isjtag){ 808*d584e620SDavid du Colombier res = ftdiwrite(p, FTSETFLOWCTRL, 0, FTDISABLEFLOWCTRL); 809*d584e620SDavid du Colombier if(res < 0) 810*d584e620SDavid du Colombier return -1; 811*d584e620SDavid du Colombier res = ftdiread(p, FTSETLATENCYTIMER, 0, (uchar *)&timerval, 812*d584e620SDavid du Colombier FTLATENCYTIMERSZ); 813*d584e620SDavid du Colombier if(res < 0) 814*d584e620SDavid du Colombier return -1; 815*d584e620SDavid du Colombier dsprint(2, "serial: jtag latency timer is %d\n", timerval); 816*d584e620SDavid du Colombier timerval = 2; 817*d584e620SDavid du Colombier ftdiwrite(p, FTLATENCYDEFAULT, 0, FTSETLATENCYTIMER); 818*d584e620SDavid du Colombier res = ftdiread(p, FTSETLATENCYTIMER, 0, (uchar *)&timerval, 819*d584e620SDavid du Colombier FTLATENCYTIMERSZ); 820*d584e620SDavid du Colombier if(res < 0) 821*d584e620SDavid du Colombier return -1; 822*d584e620SDavid du Colombier 823*d584e620SDavid du Colombier dsprint(2, "serial: jtag latency timer set to %d\n", timerval); 824*d584e620SDavid du Colombier /* may be unnecessary */ 825*d584e620SDavid du Colombier devctl(p->epin, "timeout 5000"); 826*d584e620SDavid du Colombier devctl(p->epout, "timeout 5000"); 827*d584e620SDavid du Colombier /* 0xb is the mask for lines. plug dependant? */ 828*d584e620SDavid du Colombier ftdiwrite(p, BMMPSSE|0x0b, 0, FTSETBITMODE); 829*d584e620SDavid du Colombier } 83080e9508eSDavid du Colombier incref(ser->dev); 831d5789509SDavid du Colombier threadcreate(statusreader, p, 8*1024); 83280e9508eSDavid du Colombier return 0; 83380e9508eSDavid du Colombier } 83480e9508eSDavid du Colombier 83580e9508eSDavid du Colombier static int 836d5789509SDavid du Colombier ftsetbreak(Serialport *p, int val) 83780e9508eSDavid du Colombier { 838d5789509SDavid du Colombier return ftdiwrite(p, (val != 0? FTSETBREAK: 0), 0, FTSETDATA); 83980e9508eSDavid du Colombier } 84080e9508eSDavid du Colombier 84180e9508eSDavid du Colombier static int 842d5789509SDavid du Colombier ftclearpipes(Serialport *p) 84380e9508eSDavid du Colombier { 84480e9508eSDavid du Colombier /* maybe can be done in one... */ 845d5789509SDavid du Colombier ftdiwrite(p, FTRESETCTLVALPURGETX, 0, FTRESET); 846d5789509SDavid du Colombier ftdiwrite(p, FTRESETCTLVALPURGERX, 0, FTRESET); 84780e9508eSDavid du Colombier return 0; 84880e9508eSDavid du Colombier } 84980e9508eSDavid du Colombier 85080e9508eSDavid du Colombier static int 851d5789509SDavid du Colombier setctlline(Serialport *p, uchar val) 85280e9508eSDavid du Colombier { 853d5789509SDavid du Colombier return ftdiwrite(p, val | (val << 8), 0, FTSETMODEMCTRL); 85480e9508eSDavid du Colombier } 85580e9508eSDavid du Colombier 85680e9508eSDavid du Colombier static void 857d5789509SDavid du Colombier updatectlst(Serialport *p, int val) 85880e9508eSDavid du Colombier { 859d5789509SDavid du Colombier if(p->rts) 860d5789509SDavid du Colombier p->ctlstate |= val; 86180e9508eSDavid du Colombier else 862d5789509SDavid du Colombier p->ctlstate &= ~val; 86380e9508eSDavid du Colombier } 86480e9508eSDavid du Colombier 86580e9508eSDavid du Colombier static int 866d5789509SDavid du Colombier setctl(Serialport *p) 86780e9508eSDavid du Colombier { 86880e9508eSDavid du Colombier int res; 869d5789509SDavid du Colombier Serial *ser; 870d5789509SDavid du Colombier 871d5789509SDavid du Colombier ser = p->s; 87280e9508eSDavid du Colombier 87380e9508eSDavid du Colombier if(ser->dev->usb->vid == FTVid && ser->dev->usb->did == FTHETIRA1Did){ 87480e9508eSDavid du Colombier fprint(2, "serial: cannot set lines for this device\n"); 875d5789509SDavid du Colombier updatectlst(p, CtlRTS|CtlDTR); 876d5789509SDavid du Colombier p->rts = p->dtr = 1; 87780e9508eSDavid du Colombier return -1; 87880e9508eSDavid du Colombier } 87980e9508eSDavid du Colombier 88080e9508eSDavid du Colombier /* NB: you can not set DTR and RTS with one control message */ 881d5789509SDavid du Colombier updatectlst(p, CtlRTS); 882d5789509SDavid du Colombier res = setctlline(p, (CtlRTS<<8)|p->ctlstate); 88380e9508eSDavid du Colombier if(res < 0) 88480e9508eSDavid du Colombier return res; 88580e9508eSDavid du Colombier 886d5789509SDavid du Colombier updatectlst(p, CtlDTR); 887d5789509SDavid du Colombier res = setctlline(p, (CtlDTR<<8)|p->ctlstate); 88880e9508eSDavid du Colombier if(res < 0) 88980e9508eSDavid du Colombier return res; 89080e9508eSDavid du Colombier 89180e9508eSDavid du Colombier return 0; 89280e9508eSDavid du Colombier } 89380e9508eSDavid du Colombier 89480e9508eSDavid du Colombier static int 895d5789509SDavid du Colombier ftsendlines(Serialport *p) 89680e9508eSDavid du Colombier { 89780e9508eSDavid du Colombier int res; 89880e9508eSDavid du Colombier 899d5789509SDavid du Colombier dsprint(2, "serial: sendlines: %#2.2x\n", p->ctlstate); 900d5789509SDavid du Colombier res = setctl(p); 90180e9508eSDavid du Colombier dsprint(2, "serial: sendlines res: %d\n", res); 90280e9508eSDavid du Colombier return 0; 90380e9508eSDavid du Colombier } 90480e9508eSDavid du Colombier 90580e9508eSDavid du Colombier static int 906d5789509SDavid du Colombier ftseteps(Serialport *p) 90780e9508eSDavid du Colombier { 90880e9508eSDavid du Colombier char *s; 909d5789509SDavid du Colombier Serial *ser; 91080e9508eSDavid du Colombier 911d5789509SDavid du Colombier ser = p->s; 912d5789509SDavid du Colombier 913d5789509SDavid du Colombier s = smprint("maxpkt %d", ser->maxrtrans); 914d5789509SDavid du Colombier devctl(p->epin, s); 915d5789509SDavid du Colombier free(s); 916d5789509SDavid du Colombier 917d5789509SDavid du Colombier s = smprint("maxpkt %d", ser->maxwtrans); 918d5789509SDavid du Colombier devctl(p->epout, s); 91980e9508eSDavid du Colombier free(s); 92080e9508eSDavid du Colombier return 0; 92180e9508eSDavid du Colombier } 92280e9508eSDavid du Colombier 92380e9508eSDavid du Colombier Serialops ftops = { 92480e9508eSDavid du Colombier .init = ftinit, 92580e9508eSDavid du Colombier .seteps = ftseteps, 92680e9508eSDavid du Colombier .setparam = ftsetparam, 92780e9508eSDavid du Colombier .clearpipes = ftclearpipes, 92880e9508eSDavid du Colombier .reset = ftreset, 92980e9508eSDavid du Colombier .sendlines = ftsendlines, 93080e9508eSDavid du Colombier .modemctl = ftmodemctl, 93180e9508eSDavid du Colombier .setbreak = ftsetbreak, 93280e9508eSDavid du Colombier .wait4data = wait4data, 93380e9508eSDavid du Colombier .wait4write = wait4write, 93480e9508eSDavid du Colombier }; 935