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 }, 1880e9508eSDavid du Colombier { FTVid, FTIRTRANSDid }, 1980e9508eSDavid du Colombier { FTVid, FTIPLUSDid }, 2080e9508eSDavid du Colombier { FTVid, FTSIODid }, 2180e9508eSDavid du Colombier { FTVid, FT8U232AMDid }, 2280e9508eSDavid du Colombier { FTVid, FT8U232AMALTDid }, 2380e9508eSDavid du Colombier { FTVid, FT8U2232CDid }, 2480e9508eSDavid du Colombier { FTVid, FTRELAISDid }, 2580e9508eSDavid du Colombier { INTERBIOMVid, INTERBIOMIOBRDDid }, 2680e9508eSDavid du Colombier { INTERBIOMVid, INTERBIOMMINIIOBRDDid }, 2780e9508eSDavid du Colombier { FTVid, FTXF632Did }, 2880e9508eSDavid du Colombier { FTVid, FTXF634Did }, 2980e9508eSDavid du Colombier { FTVid, FTXF547Did }, 3080e9508eSDavid du Colombier { FTVid, FTXF633Did }, 3180e9508eSDavid du Colombier { FTVid, FTXF631Did }, 3280e9508eSDavid du Colombier { FTVid, FTXF635Did }, 3380e9508eSDavid du Colombier { FTVid, FTXF640Did }, 3480e9508eSDavid du Colombier { FTVid, FTXF642Did }, 3580e9508eSDavid du Colombier { FTVid, FTDSS20Did }, 3680e9508eSDavid du Colombier { FTNFRICVid, FTNFRICDid }, 3780e9508eSDavid du Colombier { FTVid, FTVNHCPCUSBDDid }, 3880e9508eSDavid du Colombier { FTVid, FTMTXORB0Did }, 3980e9508eSDavid du Colombier { FTVid, FTMTXORB1Did }, 4080e9508eSDavid du Colombier { FTVid, FTMTXORB2Did }, 4180e9508eSDavid du Colombier { FTVid, FTMTXORB3Did }, 4280e9508eSDavid du Colombier { FTVid, FTMTXORB4Did }, 4380e9508eSDavid du Colombier { FTVid, FTMTXORB5Did }, 4480e9508eSDavid du Colombier { FTVid, FTMTXORB6Did }, 4580e9508eSDavid du Colombier { FTVid, FTPERLEULTRAPORTDid }, 4680e9508eSDavid du Colombier { FTVid, FTPIEGROUPDid }, 4780e9508eSDavid du Colombier { SEALEVELVid, SEALEVEL2101Did }, 4880e9508eSDavid du Colombier { SEALEVELVid, SEALEVEL2102Did }, 4980e9508eSDavid du Colombier { SEALEVELVid, SEALEVEL2103Did }, 5080e9508eSDavid du Colombier { SEALEVELVid, SEALEVEL2104Did }, 5180e9508eSDavid du Colombier { SEALEVELVid, SEALEVEL22011Did }, 5280e9508eSDavid du Colombier { SEALEVELVid, SEALEVEL22012Did }, 5380e9508eSDavid du Colombier { SEALEVELVid, SEALEVEL22021Did }, 5480e9508eSDavid du Colombier { SEALEVELVid, SEALEVEL22022Did }, 5580e9508eSDavid du Colombier { SEALEVELVid, SEALEVEL22031Did }, 5680e9508eSDavid du Colombier { SEALEVELVid, SEALEVEL22032Did }, 5780e9508eSDavid du Colombier { SEALEVELVid, SEALEVEL24011Did }, 5880e9508eSDavid du Colombier { SEALEVELVid, SEALEVEL24012Did }, 5980e9508eSDavid du Colombier { SEALEVELVid, SEALEVEL24013Did }, 6080e9508eSDavid du Colombier { SEALEVELVid, SEALEVEL24014Did }, 6180e9508eSDavid du Colombier { SEALEVELVid, SEALEVEL24021Did }, 6280e9508eSDavid du Colombier { SEALEVELVid, SEALEVEL24022Did }, 6380e9508eSDavid du Colombier { SEALEVELVid, SEALEVEL24023Did }, 6480e9508eSDavid du Colombier { SEALEVELVid, SEALEVEL24024Did }, 6580e9508eSDavid du Colombier { SEALEVELVid, SEALEVEL24031Did }, 6680e9508eSDavid du Colombier { SEALEVELVid, SEALEVEL24032Did }, 6780e9508eSDavid du Colombier { SEALEVELVid, SEALEVEL24033Did }, 6880e9508eSDavid du Colombier { SEALEVELVid, SEALEVEL24034Did }, 6980e9508eSDavid du Colombier { SEALEVELVid, SEALEVEL28011Did }, 7080e9508eSDavid du Colombier { SEALEVELVid, SEALEVEL28012Did }, 7180e9508eSDavid du Colombier { SEALEVELVid, SEALEVEL28013Did }, 7280e9508eSDavid du Colombier { SEALEVELVid, SEALEVEL28014Did }, 7380e9508eSDavid du Colombier { SEALEVELVid, SEALEVEL28015Did }, 7480e9508eSDavid du Colombier { SEALEVELVid, SEALEVEL28016Did }, 7580e9508eSDavid du Colombier { SEALEVELVid, SEALEVEL28017Did }, 7680e9508eSDavid du Colombier { SEALEVELVid, SEALEVEL28018Did }, 7780e9508eSDavid du Colombier { SEALEVELVid, SEALEVEL28021Did }, 7880e9508eSDavid du Colombier { SEALEVELVid, SEALEVEL28022Did }, 7980e9508eSDavid du Colombier { SEALEVELVid, SEALEVEL28023Did }, 8080e9508eSDavid du Colombier { SEALEVELVid, SEALEVEL28024Did }, 8180e9508eSDavid du Colombier { SEALEVELVid, SEALEVEL28025Did }, 8280e9508eSDavid du Colombier { SEALEVELVid, SEALEVEL28026Did }, 8380e9508eSDavid du Colombier { SEALEVELVid, SEALEVEL28027Did }, 8480e9508eSDavid du Colombier { SEALEVELVid, SEALEVEL28028Did }, 8580e9508eSDavid du Colombier { SEALEVELVid, SEALEVEL28031Did }, 8680e9508eSDavid du Colombier { SEALEVELVid, SEALEVEL28032Did }, 8780e9508eSDavid du Colombier { SEALEVELVid, SEALEVEL28033Did }, 8880e9508eSDavid du Colombier { SEALEVELVid, SEALEVEL28034Did }, 8980e9508eSDavid du Colombier { SEALEVELVid, SEALEVEL28035Did }, 9080e9508eSDavid du Colombier { SEALEVELVid, SEALEVEL28036Did }, 9180e9508eSDavid du Colombier { SEALEVELVid, SEALEVEL28037Did }, 9280e9508eSDavid du Colombier { SEALEVELVid, SEALEVEL28038Did }, 9380e9508eSDavid du Colombier { IDTECHVid, IDTECHIDT1221UDid }, 9480e9508eSDavid du Colombier { OCTVid, OCTUS101Did }, 9580e9508eSDavid du Colombier { FTVid, FTHETIRA1Did }, /* special quirk div = 240 baud = B38400 rtscts = 1 */ 9680e9508eSDavid du Colombier { FTVid, FTUSBUIRTDid }, /* special quirk div = 77, baud = B38400 */ 9780e9508eSDavid du Colombier { FTVid, PROTEGOSPECIAL1 }, 9880e9508eSDavid du Colombier { FTVid, PROTEGOR2X0 }, 9980e9508eSDavid du Colombier { FTVid, PROTEGOSPECIAL3 }, 10080e9508eSDavid du Colombier { FTVid, PROTEGOSPECIAL4 }, 10180e9508eSDavid du Colombier { FTVid, FTGUDEADSE808Did }, 10280e9508eSDavid du Colombier { FTVid, FTGUDEADSE809Did }, 10380e9508eSDavid du Colombier { FTVid, FTGUDEADSE80ADid }, 10480e9508eSDavid du Colombier { FTVid, FTGUDEADSE80BDid }, 10580e9508eSDavid du Colombier { FTVid, FTGUDEADSE80CDid }, 10680e9508eSDavid du Colombier { FTVid, FTGUDEADSE80DDid }, 10780e9508eSDavid du Colombier { FTVid, FTGUDEADSE80EDid }, 10880e9508eSDavid du Colombier { FTVid, FTGUDEADSE80FDid }, 10980e9508eSDavid du Colombier { FTVid, FTGUDEADSE888Did }, 11080e9508eSDavid du Colombier { FTVid, FTGUDEADSE889Did }, 11180e9508eSDavid du Colombier { FTVid, FTGUDEADSE88ADid }, 11280e9508eSDavid du Colombier { FTVid, FTGUDEADSE88BDid }, 11380e9508eSDavid du Colombier { FTVid, FTGUDEADSE88CDid }, 11480e9508eSDavid du Colombier { FTVid, FTGUDEADSE88DDid }, 11580e9508eSDavid du Colombier { FTVid, FTGUDEADSE88EDid }, 11680e9508eSDavid du Colombier { FTVid, FTGUDEADSE88FDid }, 11780e9508eSDavid du Colombier { FTVid, FTELVUO100Did }, 11880e9508eSDavid du Colombier { FTVid, FTELVUM100Did }, 11980e9508eSDavid du Colombier { FTVid, FTELVUR100Did }, 12080e9508eSDavid du Colombier { FTVid, FTELVALC8500Did }, 12180e9508eSDavid du Colombier { FTVid, FTPYRAMIDDid }, 12280e9508eSDavid du Colombier { FTVid, FTELVFHZ1000PCDid }, 12380e9508eSDavid du Colombier { FTVid, FTELVCLI7000Did }, 12480e9508eSDavid du Colombier { FTVid, FTELVPPS7330Did }, 12580e9508eSDavid du Colombier { FTVid, FTELVTFM100Did }, 12680e9508eSDavid du Colombier { FTVid, FTELVUDF77Did }, 12780e9508eSDavid du Colombier { FTVid, FTELVUIO88Did }, 12880e9508eSDavid du Colombier { FTVid, FTELVUAD8Did }, 12980e9508eSDavid du Colombier { FTVid, FTELVUDA7Did }, 13080e9508eSDavid du Colombier { FTVid, FTELVUSI2Did }, 13180e9508eSDavid du Colombier { FTVid, FTELVT1100Did }, 13280e9508eSDavid du Colombier { FTVid, FTELVPCD200Did }, 13380e9508eSDavid du Colombier { FTVid, FTELVULA200Did }, 13480e9508eSDavid du Colombier { FTVid, FTELVCSI8Did }, 13580e9508eSDavid du Colombier { FTVid, FTELVEM1000DLDid }, 13680e9508eSDavid du Colombier { FTVid, FTELVPCK100Did }, 13780e9508eSDavid du Colombier { FTVid, FTELVRFP500Did }, 13880e9508eSDavid du Colombier { FTVid, FTELVFS20SIGDid }, 13980e9508eSDavid du Colombier { FTVid, FTELVWS300PCDid }, 14080e9508eSDavid du Colombier { FTVid, FTELVFHZ1300PCDid }, 14180e9508eSDavid du Colombier { FTVid, FTELVWS500Did }, 14280e9508eSDavid du Colombier { FTVid, LINXSDMUSBQSSDid }, 14380e9508eSDavid du Colombier { FTVid, LINXMASTERDEVEL2Did }, 14480e9508eSDavid du Colombier { FTVid, LINXFUTURE0Did }, 14580e9508eSDavid du Colombier { FTVid, LINXFUTURE1Did }, 14680e9508eSDavid du Colombier { FTVid, LINXFUTURE2Did }, 14780e9508eSDavid du Colombier { FTVid, FTCCSICDU200Did }, 14880e9508eSDavid du Colombier { FTVid, FTCCSICDU401Did }, 14980e9508eSDavid du Colombier { FTVid, INSIDEACCESSO }, 15080e9508eSDavid du Colombier { INTREDidVid, INTREDidVALUECANDid }, 15180e9508eSDavid du Colombier { INTREDidVid, INTREDidNEOVIDid }, 15280e9508eSDavid du Colombier { FALCOMVid, FALCOMTWISTDid }, 15380e9508eSDavid du Colombier { FALCOMVid, FALCOMSAMBADid }, 15480e9508eSDavid du Colombier { FTVid, FTSUUNTOSPORTSDid }, 15580e9508eSDavid du Colombier { FTVid, FTRMCANVIEWDid }, 15680e9508eSDavid du Colombier { BANDBVid, BANDBUSOTL4Did }, 15780e9508eSDavid du Colombier { BANDBVid, BANDBUSTL4Did }, 15880e9508eSDavid du Colombier { BANDBVid, BANDBUSO9ML2Did }, 15980e9508eSDavid du Colombier { FTVid, EVERECOPROCDSDid }, 16080e9508eSDavid du Colombier { FTVid, FT4NGALAXYDE0Did }, 16180e9508eSDavid du Colombier { FTVid, FT4NGALAXYDE1Did }, 16280e9508eSDavid du Colombier { FTVid, FT4NGALAXYDE2Did }, 16380e9508eSDavid du Colombier { FTVid, XSENSCONVERTER0Did }, 16480e9508eSDavid du Colombier { FTVid, XSENSCONVERTER1Did }, 16580e9508eSDavid du Colombier { FTVid, XSENSCONVERTER2Did }, 16680e9508eSDavid du Colombier { FTVid, XSENSCONVERTER3Did }, 16780e9508eSDavid du Colombier { FTVid, XSENSCONVERTER4Did }, 16880e9508eSDavid du Colombier { FTVid, XSENSCONVERTER5Did }, 16980e9508eSDavid du Colombier { FTVid, XSENSCONVERTER6Did }, 17080e9508eSDavid du Colombier { FTVid, XSENSCONVERTER7Did }, 17180e9508eSDavid du Colombier { MOBILITYVid, MOBILITYUSBSERIALDid }, 17280e9508eSDavid du Colombier { FTVid, FTACTIVEROBOTSDid }, 17380e9508eSDavid du Colombier { FTVid, FTMHAMKWDid }, 17480e9508eSDavid du Colombier { FTVid, FTMHAMYSDid }, 17580e9508eSDavid du Colombier { FTVid, FTMHAMY6Did }, 17680e9508eSDavid du Colombier { FTVid, FTMHAMY8Did }, 17780e9508eSDavid du Colombier { FTVid, FTMHAMICDid }, 17880e9508eSDavid du Colombier { FTVid, FTMHAMDB9Did }, 17980e9508eSDavid du Colombier { FTVid, FTMHAMRS232Did }, 18080e9508eSDavid du Colombier { FTVid, FTMHAMY9Did }, 18180e9508eSDavid du Colombier { FTVid, FTTERATRONIKVCPDid }, 18280e9508eSDavid du Colombier { FTVid, FTTERATRONIKD2XXDid }, 18380e9508eSDavid du Colombier { EVOLUTIONVid, EVOLUTIONER1Did }, 18480e9508eSDavid du Colombier { FTVid, FTARTEMISDid }, 18580e9508eSDavid du Colombier { FTVid, FTATIKATK16Did }, 18680e9508eSDavid du Colombier { FTVid, FTATIKATK16CDid }, 18780e9508eSDavid du Colombier { FTVid, FTATIKATK16HRDid }, 18880e9508eSDavid du Colombier { FTVid, FTATIKATK16HRCDid }, 18980e9508eSDavid du Colombier { KOBILVid, KOBILCONVB1Did }, 19080e9508eSDavid du Colombier { KOBILVid, KOBILCONVKAANDid }, 19180e9508eSDavid du Colombier { POSIFLEXVid, POSIFLEXPP7000Did }, 19280e9508eSDavid du Colombier { FTVid, FTTTUSBDid }, 19380e9508eSDavid du Colombier { FTVid, FTECLOCOM1WIREDid }, 19480e9508eSDavid du Colombier { FTVid, FTWESTREXMODEL777Did }, 19580e9508eSDavid du Colombier { FTVid, FTWESTREXMODEL8900FDid }, 19680e9508eSDavid du Colombier { FTVid, FTPCDJDAC2Did }, 19780e9508eSDavid du Colombier { FTVid, FTRRCIRKITSLOCOBUFFERDid }, 19880e9508eSDavid du Colombier { FTVid, FTASKRDR400Did }, 19980e9508eSDavid du Colombier { ICOMID1Vid, ICOMID1Did }, 20080e9508eSDavid du Colombier { PAPOUCHVid, PAPOUCHTMUDid }, 20180e9508eSDavid du Colombier { FTVid, FTACGHFDUALDid }, 202d5789509SDavid du Colombier { FT8U232AMDid, FT4232HDid }, 20380e9508eSDavid du Colombier { 0, 0 }, 20480e9508eSDavid du Colombier }; 20580e9508eSDavid du Colombier 20680e9508eSDavid du Colombier enum { 207d5789509SDavid du Colombier Packsz = 64, /* default size */ 208d5789509SDavid du Colombier Maxpacksz = 512, 209d5789509SDavid du Colombier Bufsiz = 4 * 1024, 21080e9508eSDavid du Colombier }; 21180e9508eSDavid du Colombier 21280e9508eSDavid du Colombier static int 213d5789509SDavid du Colombier ftdiread(Serialport *p, int val, int index, int req, uchar *buf) 21480e9508eSDavid du Colombier { 21580e9508eSDavid du Colombier int res; 216d5789509SDavid du Colombier Serial *ser; 217d5789509SDavid du Colombier 218d5789509SDavid du Colombier ser = p->s; 21980e9508eSDavid du Colombier 22080e9508eSDavid du Colombier if(req != FTGETE2READ) 221d5789509SDavid du Colombier index |= p->interfc + 1; 222d5789509SDavid du Colombier dsprint(2, "serial: ftdiread %#p [%d] req: %#x val: %#x idx:%d buf:%p\n", 223d5789509SDavid du Colombier p, p->interfc, req, val, index, buf); 22480e9508eSDavid du Colombier res = usbcmd(ser->dev, Rd2h | Rftdireq | Rdev, req, val, index, buf, 1); 22580e9508eSDavid du Colombier dsprint(2, "serial: ftdiread res:%d\n", res); 22680e9508eSDavid du Colombier return res; 22780e9508eSDavid du Colombier } 22880e9508eSDavid du Colombier 22980e9508eSDavid du Colombier static int 230d5789509SDavid du Colombier ftdiwrite(Serialport *p, int val, int index, int req) 23180e9508eSDavid du Colombier { 23280e9508eSDavid du Colombier int res; 233d5789509SDavid du Colombier Serial *ser; 23480e9508eSDavid du Colombier 235d5789509SDavid du Colombier ser = p->s; 236d5789509SDavid du Colombier 237d5789509SDavid du Colombier index |= p->interfc + 1; 238d5789509SDavid du Colombier dsprint(2, "serial: ftdiwrite %#p [%d] req: %#x val: %#x idx:%d\n", 239d5789509SDavid du Colombier p, p->interfc, req, val, index); 24080e9508eSDavid du Colombier res = usbcmd(ser->dev, Rh2d | Rftdireq | Rdev, req, val, index, nil, 0); 24180e9508eSDavid du Colombier dsprint(2, "serial: ftdiwrite res:%d\n", res); 24280e9508eSDavid du Colombier return res; 24380e9508eSDavid du Colombier } 24480e9508eSDavid du Colombier 24580e9508eSDavid du Colombier static int 246d5789509SDavid du Colombier ftmodemctl(Serialport *p, int set) 24780e9508eSDavid du Colombier { 24880e9508eSDavid du Colombier if(set == 0){ 249d5789509SDavid du Colombier p->mctl = 0; 250d5789509SDavid du Colombier ftdiwrite(p, 0, 0, FTSETMODEMCTRL); 25180e9508eSDavid du Colombier return 0; 25280e9508eSDavid du Colombier } 253d5789509SDavid du Colombier p->mctl = 1; 254d5789509SDavid du Colombier ftdiwrite(p, 0, FTRTSCTSHS, FTSETFLOWCTRL); 25580e9508eSDavid du Colombier return 0; 25680e9508eSDavid du Colombier } 25780e9508eSDavid du Colombier 25880e9508eSDavid du Colombier static ushort 25980e9508eSDavid du Colombier ft232ambaudbase2div(int baud, int base) 26080e9508eSDavid du Colombier { 26180e9508eSDavid du Colombier int divisor3; 26280e9508eSDavid du Colombier ushort divisor; 26380e9508eSDavid du Colombier 26480e9508eSDavid du Colombier divisor3 = (base / 2) / baud; 26580e9508eSDavid du Colombier if((divisor3 & 7) == 7) 26680e9508eSDavid du Colombier divisor3++; /* round x.7/8 up to x+1 */ 26780e9508eSDavid du Colombier divisor = divisor3 >> 3; 26880e9508eSDavid du Colombier divisor3 &= 7; 26980e9508eSDavid du Colombier 27080e9508eSDavid du Colombier if(divisor3 == 1) 27180e9508eSDavid du Colombier divisor |= 0xc000; /* 0.125 */ 27280e9508eSDavid du Colombier else if(divisor3 >= 4) 27380e9508eSDavid du Colombier divisor |= 0x4000; /* 0.5 */ 27480e9508eSDavid du Colombier else if(divisor3 != 0) 27580e9508eSDavid du Colombier divisor |= 0x8000; /* 0.25 */ 27680e9508eSDavid du Colombier if( divisor == 1) 27780e9508eSDavid du Colombier divisor = 0; /* special case for maximum baud rate */ 27880e9508eSDavid du Colombier return divisor; 27980e9508eSDavid du Colombier } 28080e9508eSDavid du Colombier 28180e9508eSDavid du Colombier enum{ 28280e9508eSDavid du Colombier ClockNew = 48000000, 28380e9508eSDavid du Colombier ClockOld = 12000000 / 16, 28480e9508eSDavid du Colombier HetiraDiv = 240, 28580e9508eSDavid du Colombier UirtDiv = 77, 28680e9508eSDavid du Colombier }; 28780e9508eSDavid du Colombier 28880e9508eSDavid du Colombier static ushort 28980e9508eSDavid du Colombier ft232ambaud2div(int baud) 29080e9508eSDavid du Colombier { 29180e9508eSDavid du Colombier return ft232ambaudbase2div(baud, ClockNew); 29280e9508eSDavid du Colombier } 29380e9508eSDavid du Colombier 29480e9508eSDavid du Colombier static ulong divfrac[8] = { 0, 3, 2, 4, 1, 5, 6, 7}; 29580e9508eSDavid du Colombier 29680e9508eSDavid du Colombier static ulong 29780e9508eSDavid du Colombier ft232bmbaudbase2div(int baud, int base) 29880e9508eSDavid du Colombier { 29980e9508eSDavid du Colombier int divisor3; 30080e9508eSDavid du Colombier u32int divisor; 30180e9508eSDavid du Colombier 30280e9508eSDavid du Colombier divisor3 = (base / 2) / baud; 30380e9508eSDavid du Colombier divisor = divisor3 >> 3 | divfrac[divisor3 & 7] << 14; 30480e9508eSDavid du Colombier 30580e9508eSDavid du Colombier /* Deal with special cases for highest baud rates. */ 30680e9508eSDavid du Colombier if( divisor == 1) 30780e9508eSDavid du Colombier divisor = 0; /* 1.0 */ 30880e9508eSDavid du Colombier else if( divisor == 0x4001) 30980e9508eSDavid du Colombier divisor = 1; /* 1.5 */ 31080e9508eSDavid du Colombier return divisor; 31180e9508eSDavid du Colombier } 31280e9508eSDavid du Colombier 31380e9508eSDavid du Colombier static ulong 31480e9508eSDavid du Colombier ft232bmbaud2div (int baud) 31580e9508eSDavid du Colombier { 31680e9508eSDavid du Colombier return ft232bmbaudbase2div (baud, ClockNew); 31780e9508eSDavid du Colombier } 31880e9508eSDavid du Colombier 31980e9508eSDavid du Colombier static int 32080e9508eSDavid du Colombier customdiv(Serial *ser) 32180e9508eSDavid du Colombier { 32280e9508eSDavid du Colombier if(ser->dev->usb->vid == FTVid && ser->dev->usb->did == FTHETIRA1Did) 32380e9508eSDavid du Colombier return HetiraDiv; 32480e9508eSDavid du Colombier else if(ser->dev->usb->vid == FTVid && ser->dev->usb->did == FTUSBUIRTDid) 32580e9508eSDavid du Colombier return UirtDiv; 32680e9508eSDavid du Colombier 32780e9508eSDavid du Colombier fprint(2, "serial: weird custom divisor\n"); 32880e9508eSDavid du Colombier return 0; /* shouldn't happen, break as much as I can */ 32980e9508eSDavid du Colombier } 33080e9508eSDavid du Colombier 33180e9508eSDavid du Colombier static ulong 33280e9508eSDavid du Colombier ftbaudcalcdiv(Serial *ser, int baud) 33380e9508eSDavid du Colombier { 33480e9508eSDavid du Colombier int cusdiv; 33580e9508eSDavid du Colombier ulong divval; 33680e9508eSDavid du Colombier 33780e9508eSDavid du Colombier if(baud == 38400 && (cusdiv = customdiv(ser)) != 0) 33880e9508eSDavid du Colombier baud = ser->baudbase / cusdiv; 33980e9508eSDavid du Colombier 34080e9508eSDavid du Colombier if(baud == 0) 34180e9508eSDavid du Colombier baud = 9600; 34280e9508eSDavid du Colombier 34380e9508eSDavid du Colombier switch(ser->type) { 34480e9508eSDavid du Colombier case SIO: 34580e9508eSDavid du Colombier switch(baud) { 34680e9508eSDavid du Colombier case 300: 34780e9508eSDavid du Colombier divval = FTb300; 34880e9508eSDavid du Colombier break; 34980e9508eSDavid du Colombier case 600: 35080e9508eSDavid du Colombier divval = FTb600; 35180e9508eSDavid du Colombier break; 35280e9508eSDavid du Colombier case 1200: 35380e9508eSDavid du Colombier divval = FTb1200; 35480e9508eSDavid du Colombier break; 35580e9508eSDavid du Colombier case 2400: 35680e9508eSDavid du Colombier divval = FTb2400; 35780e9508eSDavid du Colombier break; 35880e9508eSDavid du Colombier case 4800: 35980e9508eSDavid du Colombier divval = FTb4800; 36080e9508eSDavid du Colombier break; 36180e9508eSDavid du Colombier case 9600: 36280e9508eSDavid du Colombier divval = FTb9600; 36380e9508eSDavid du Colombier break; 36480e9508eSDavid du Colombier case 19200: 36580e9508eSDavid du Colombier divval = FTb19200; 36680e9508eSDavid du Colombier break; 36780e9508eSDavid du Colombier case 38400: 36880e9508eSDavid du Colombier divval = FTb38400; 36980e9508eSDavid du Colombier break; 37080e9508eSDavid du Colombier case 57600: 37180e9508eSDavid du Colombier divval = FTb57600; 37280e9508eSDavid du Colombier break; 37380e9508eSDavid du Colombier case 115200: 37480e9508eSDavid du Colombier divval = FTb115200; 37580e9508eSDavid du Colombier break; 37680e9508eSDavid du Colombier default: 37780e9508eSDavid du Colombier divval = FTb9600; 37880e9508eSDavid du Colombier break; 37980e9508eSDavid du Colombier } 38080e9508eSDavid du Colombier break; 38180e9508eSDavid du Colombier case FT8U232AM: 38280e9508eSDavid du Colombier if(baud <= 3000000) 38380e9508eSDavid du Colombier divval = ft232ambaud2div(baud); 38480e9508eSDavid du Colombier else 38580e9508eSDavid du Colombier divval = ft232ambaud2div(9600); 38680e9508eSDavid du Colombier break; 38780e9508eSDavid du Colombier case FT232BM: 38880e9508eSDavid du Colombier case FT2232C: 389d5789509SDavid du Colombier case FTKINDR: 390d5789509SDavid du Colombier case FT2232H: 391d5789509SDavid du Colombier case FT4232H: 39280e9508eSDavid du Colombier if(baud <= 3000000) 39380e9508eSDavid du Colombier divval = ft232bmbaud2div(baud); 39480e9508eSDavid du Colombier else 39580e9508eSDavid du Colombier divval = ft232bmbaud2div(9600); 39680e9508eSDavid du Colombier break; 39780e9508eSDavid du Colombier default: 39880e9508eSDavid du Colombier divval = ft232bmbaud2div(9600); 39980e9508eSDavid du Colombier break; 40080e9508eSDavid du Colombier } 40180e9508eSDavid du Colombier return divval; 40280e9508eSDavid du Colombier } 40380e9508eSDavid du Colombier 40480e9508eSDavid du Colombier static int 405d5789509SDavid du Colombier ftsetparam(Serialport *p) 40680e9508eSDavid du Colombier { 40780e9508eSDavid du Colombier int res; 40880e9508eSDavid du Colombier ushort val; 40980e9508eSDavid du Colombier ulong bauddiv; 41080e9508eSDavid du Colombier 41180e9508eSDavid du Colombier val = 0; 412d5789509SDavid du Colombier if(p->stop == 1) 41380e9508eSDavid du Colombier val |= FTSETDATASTOPBITS1; 414d5789509SDavid du Colombier else if(p->stop == 2) 41580e9508eSDavid du Colombier val |= FTSETDATASTOPBITS2; 416d5789509SDavid du Colombier else if(p->stop == 15) 41780e9508eSDavid du Colombier val |= FTSETDATASTOPBITS15; 418d5789509SDavid du Colombier switch(p->parity){ 41980e9508eSDavid du Colombier case 0: 42080e9508eSDavid du Colombier val |= FTSETDATAParNONE; 42180e9508eSDavid du Colombier break; 42280e9508eSDavid du Colombier case 1: 42380e9508eSDavid du Colombier val |= FTSETDATAParODD; 42480e9508eSDavid du Colombier break; 42580e9508eSDavid du Colombier case 2: 42680e9508eSDavid du Colombier val |= FTSETDATAParEVEN; 42780e9508eSDavid du Colombier break; 42880e9508eSDavid du Colombier case 3: 42980e9508eSDavid du Colombier val |= FTSETDATAParMARK; 43080e9508eSDavid du Colombier break; 43180e9508eSDavid du Colombier case 4: 43280e9508eSDavid du Colombier val |= FTSETDATAParSPACE; 43380e9508eSDavid du Colombier break; 43480e9508eSDavid du Colombier }; 43580e9508eSDavid du Colombier 43680e9508eSDavid du Colombier dsprint(2, "serial: setparam\n"); 43780e9508eSDavid du Colombier 438d5789509SDavid du Colombier res = ftdiwrite(p, val, 0, FTSETDATA); 43980e9508eSDavid du Colombier if(res < 0) 44080e9508eSDavid du Colombier return res; 44180e9508eSDavid du Colombier 442d5789509SDavid du Colombier res = ftmodemctl(p, p->mctl); 44380e9508eSDavid du Colombier if(res < 0) 44480e9508eSDavid du Colombier return res; 44580e9508eSDavid du Colombier 446d5789509SDavid du Colombier bauddiv = ftbaudcalcdiv(p->s, p->baud); 447d5789509SDavid du Colombier res = ftdiwrite(p, bauddiv, (bauddiv>>16) & 1, FTSETBaudRate); 44880e9508eSDavid du Colombier 44980e9508eSDavid du Colombier dsprint(2, "serial: setparam res: %d\n", res); 45080e9508eSDavid du Colombier return res; 45180e9508eSDavid du Colombier } 45280e9508eSDavid du Colombier 45380e9508eSDavid du Colombier /* ser locked */ 45480e9508eSDavid du Colombier static void 45580e9508eSDavid du Colombier ftgettype(Serial *ser) 45680e9508eSDavid du Colombier { 457d5789509SDavid du Colombier int i, outhdrsz, dno, pksz; 45880e9508eSDavid du Colombier ulong baudbase; 45980e9508eSDavid du Colombier Conf *cnf; 46080e9508eSDavid du Colombier 461d5789509SDavid du Colombier pksz = Packsz; 46280e9508eSDavid du Colombier /* Assume it is not the original SIO device for now. */ 46380e9508eSDavid du Colombier baudbase = ClockNew / 2; 46480e9508eSDavid du Colombier outhdrsz = 0; 46580e9508eSDavid du Colombier dno = ser->dev->usb->dno; 46680e9508eSDavid du Colombier cnf = ser->dev->usb->conf[0]; 467d5789509SDavid du Colombier ser->nifcs = 0; 46880e9508eSDavid du Colombier for(i = 0; i < Niface; i++) 46980e9508eSDavid du Colombier if(cnf->iface[i] != nil) 470d5789509SDavid du Colombier ser->nifcs++; 471d5789509SDavid du Colombier if(ser->nifcs > 1) { 47280e9508eSDavid du Colombier /* 473d5789509SDavid du Colombier * Multiple interfaces. default assume FT2232C, 47480e9508eSDavid du Colombier */ 475d5789509SDavid du Colombier if(dno == 0x500) 476d5789509SDavid du Colombier ser->type = FT2232C; 477d5789509SDavid du Colombier else if(dno == 0x600) 478d5789509SDavid du Colombier ser->type = FTKINDR; 479d5789509SDavid du Colombier else if(dno == 0x700){ 480d5789509SDavid du Colombier ser->type = FT2232H; 481d5789509SDavid du Colombier pksz = Maxpacksz; 482d5789509SDavid du Colombier } else if(dno == 0x800){ 483d5789509SDavid du Colombier ser->type = FT4232H; 484d5789509SDavid du Colombier pksz = Maxpacksz; 485d5789509SDavid du Colombier } else 486d5789509SDavid du Colombier ser->type = FT2232C; 487d5789509SDavid du Colombier 488d5789509SDavid du Colombier ser->jtag = 0; 48980e9508eSDavid du Colombier 49080e9508eSDavid du Colombier /* 49180e9508eSDavid du Colombier * BM-type devices have a bug where dno gets set 49280e9508eSDavid du Colombier * to 0x200 when serial is 0. 49380e9508eSDavid du Colombier */ 49480e9508eSDavid du Colombier if(dno < 0x500) 495d5789509SDavid du Colombier fprint(2, "serial: warning: dno %d too low for " 496d5789509SDavid du Colombier "multi-interface device\n", dno); 49780e9508eSDavid du Colombier } else if(dno < 0x200) { 49880e9508eSDavid du Colombier /* Old device. Assume it is the original SIO. */ 49980e9508eSDavid du Colombier ser->type = SIO; 50080e9508eSDavid du Colombier baudbase = ClockOld/16; 50180e9508eSDavid du Colombier outhdrsz = 1; 50280e9508eSDavid du Colombier } else if(dno < 0x400) 50380e9508eSDavid du Colombier /* 50480e9508eSDavid du Colombier * Assume its an FT8U232AM (or FT8U245AM) 50580e9508eSDavid du Colombier * (It might be a BM because of the iSerialNumber bug, 50680e9508eSDavid du Colombier * but it will still work as an AM device.) 50780e9508eSDavid du Colombier */ 50880e9508eSDavid du Colombier ser->type = FT8U232AM; 50980e9508eSDavid du Colombier else /* Assume it is an FT232BM (or FT245BM) */ 51080e9508eSDavid du Colombier ser->type = FT232BM; 51180e9508eSDavid du Colombier 512d5789509SDavid du Colombier ser->maxrtrans = ser->maxwtrans = pksz; 51380e9508eSDavid du Colombier ser->baudbase = baudbase; 51480e9508eSDavid du Colombier ser->outhdrsz = outhdrsz; 51580e9508eSDavid du Colombier ser->inhdrsz = 2; 516d5789509SDavid du Colombier 51780e9508eSDavid du Colombier dsprint (2, "serial: detected type: %#x\n", ser->type); 51880e9508eSDavid du Colombier } 51980e9508eSDavid du Colombier 52080e9508eSDavid du Colombier int 52180e9508eSDavid du Colombier ftmatch(Serial *ser, char *info) 52280e9508eSDavid du Colombier { 52380e9508eSDavid du Colombier Cinfo *ip; 52480e9508eSDavid du Colombier char buf[50]; 52580e9508eSDavid du Colombier 52680e9508eSDavid du Colombier for(ip = ftinfo; ip->vid != 0; ip++){ 52780e9508eSDavid du Colombier snprint(buf, sizeof buf, "vid %#06x did %#06x", ip->vid, ip->did); 52880e9508eSDavid du Colombier dsprint(2, "serial: %s %s\n", buf, info); 52980e9508eSDavid du Colombier if(strstr(info, buf) != nil){ 53080e9508eSDavid du Colombier if(ser != nil){ 53180e9508eSDavid du Colombier qlock(ser); 53280e9508eSDavid du Colombier ftgettype(ser); 53380e9508eSDavid du Colombier qunlock(ser); 53480e9508eSDavid du Colombier } 53580e9508eSDavid du Colombier return 0; 53680e9508eSDavid du Colombier } 53780e9508eSDavid du Colombier } 53880e9508eSDavid du Colombier return -1; 53980e9508eSDavid du Colombier } 54080e9508eSDavid du Colombier 54180e9508eSDavid du Colombier static int 542d5789509SDavid du Colombier ftuseinhdr(Serialport *p, uchar *b) 54380e9508eSDavid du Colombier { 54480e9508eSDavid du Colombier if(b[0] & FTICTS) 545d5789509SDavid du Colombier p->cts = 1; 54680e9508eSDavid du Colombier else 547d5789509SDavid du Colombier p->cts = 0; 54880e9508eSDavid du Colombier if(b[0] & FTIDSR) 549d5789509SDavid du Colombier p->dsr = 1; 55080e9508eSDavid du Colombier else 551d5789509SDavid du Colombier p->dsr = 0; 55280e9508eSDavid du Colombier if(b[0] & FTIRI) 553d5789509SDavid du Colombier p->ring = 1; 55480e9508eSDavid du Colombier else 555d5789509SDavid du Colombier p->ring = 0; 55680e9508eSDavid du Colombier if(b[0] & FTIRLSD) 557d5789509SDavid du Colombier p->rlsd = 1; 55880e9508eSDavid du Colombier else 559d5789509SDavid du Colombier p->rlsd = 0; 56080e9508eSDavid du Colombier 56180e9508eSDavid du Colombier if(b[1] & FTIOE) 562d5789509SDavid du Colombier p->novererr++; 56380e9508eSDavid du Colombier if(b[1] & FTIPE) 564d5789509SDavid du Colombier p->nparityerr++; 56580e9508eSDavid du Colombier if(b[1] & FTIFE) 566d5789509SDavid du Colombier p->nframeerr++; 56780e9508eSDavid du Colombier if(b[1] & FTIBI) 568d5789509SDavid du Colombier p->nbreakerr++; 56980e9508eSDavid du Colombier return 0; 57080e9508eSDavid du Colombier } 57180e9508eSDavid du Colombier 57280e9508eSDavid du Colombier static int 573d5789509SDavid du Colombier ftsetouthdr(Serialport *p, uchar *b, int len) 57480e9508eSDavid du Colombier { 575d5789509SDavid du Colombier if(p->s->outhdrsz != 0) 57680e9508eSDavid du Colombier b[0] = FTOPORT | (FTOLENMSK & len); 577d5789509SDavid du Colombier return p->s->outhdrsz; 57880e9508eSDavid du Colombier } 57980e9508eSDavid du Colombier 58080e9508eSDavid du Colombier static int 581d5789509SDavid du Colombier wait4data(Serialport *p, uchar *data, int count) 58280e9508eSDavid du Colombier { 583d5789509SDavid du Colombier int d; 584d5789509SDavid du Colombier Serial *ser; 585d5789509SDavid du Colombier 586d5789509SDavid du Colombier ser = p->s; 587d5789509SDavid du Colombier 58880e9508eSDavid du Colombier qunlock(ser); 589d5789509SDavid du Colombier d = sendul(p->w4data, 1); 590*ed868a7cSDavid du Colombier qlock(ser); 591d5789509SDavid du Colombier if(d <= 0) 592d5789509SDavid du Colombier return -1; 593d5789509SDavid du Colombier if(p->ndata >= count) 594d5789509SDavid du Colombier p->ndata -= count; 59580e9508eSDavid du Colombier else{ 596d5789509SDavid du Colombier count = p->ndata; 597d5789509SDavid du Colombier p->ndata = 0; 59880e9508eSDavid du Colombier } 599ecc2a7c8SDavid du Colombier assert(count >= 0); 600d5789509SDavid du Colombier assert(p->ndata >= 0); 601d5789509SDavid du Colombier memmove(data, p->data, count); 602d5789509SDavid du Colombier if(p->ndata != 0) 603d5789509SDavid du Colombier memmove(p->data, p->data+count, p->ndata); 60480e9508eSDavid du Colombier 605d5789509SDavid du Colombier recvul(p->gotdata); 60680e9508eSDavid du Colombier return count; 60780e9508eSDavid du Colombier } 60880e9508eSDavid du Colombier 60980e9508eSDavid du Colombier static int 610d5789509SDavid du Colombier wait4write(Serialport *p, uchar *data, int count) 61180e9508eSDavid du Colombier { 61280e9508eSDavid du Colombier int off, fd; 61380e9508eSDavid du Colombier uchar *b; 614d5789509SDavid du Colombier Serial *ser; 61580e9508eSDavid du Colombier 616d5789509SDavid du Colombier ser = p->s; 61780e9508eSDavid du Colombier 61880e9508eSDavid du Colombier b = emallocz(count+ser->outhdrsz, 1); 619d5789509SDavid du Colombier off = ftsetouthdr(p, b, count); 62080e9508eSDavid du Colombier memmove(b+off, data, count); 62180e9508eSDavid du Colombier 622d5789509SDavid du Colombier fd = p->epout->dfd; 62380e9508eSDavid du Colombier qunlock(ser); 62480e9508eSDavid du Colombier count = write(fd, b, count+off); 62580e9508eSDavid du Colombier qlock(ser); 62680e9508eSDavid du Colombier free(b); 62780e9508eSDavid du Colombier return count; 62880e9508eSDavid du Colombier } 62980e9508eSDavid du Colombier 63080e9508eSDavid du Colombier typedef struct Packser Packser; 63180e9508eSDavid du Colombier struct Packser{ 63280e9508eSDavid du Colombier int nb; 633d5789509SDavid du Colombier uchar b[Bufsiz]; 63480e9508eSDavid du Colombier }; 63580e9508eSDavid du Colombier 63680e9508eSDavid du Colombier typedef struct Areader Areader; 63780e9508eSDavid du Colombier struct Areader{ 638d5789509SDavid du Colombier Serialport *p; 63980e9508eSDavid du Colombier Channel *c; 64080e9508eSDavid du Colombier }; 64180e9508eSDavid du Colombier 64280e9508eSDavid du Colombier static void 643d5789509SDavid du Colombier shutdownchan(Channel *c) 644d5789509SDavid du Colombier { 645d5789509SDavid du Colombier Packser *bp; 646d5789509SDavid du Colombier 647d5789509SDavid du Colombier while((bp=nbrecvp(c)) != nil) 648d5789509SDavid du Colombier free(bp); 649d5789509SDavid du Colombier chanfree(c); 650d5789509SDavid du Colombier } 651d5789509SDavid du Colombier 652d5789509SDavid du Colombier int 653d5789509SDavid du Colombier cpdata(Serial *ser, Serialport *port, uchar *out, uchar *in, int sz) 654d5789509SDavid du Colombier { 655d5789509SDavid du Colombier int i, ncp, ntotcp, pksz; 656d5789509SDavid du Colombier 657d5789509SDavid du Colombier pksz = ser->maxrtrans; 658d5789509SDavid du Colombier ntotcp = 0; 659d5789509SDavid du Colombier 660d5789509SDavid du Colombier for(i = 0; i < sz; i+= pksz){ 661d5789509SDavid du Colombier ftuseinhdr(port, in + i); 662d5789509SDavid du Colombier if(sz - i > pksz) 663d5789509SDavid du Colombier ncp = pksz - ser->inhdrsz; 664d5789509SDavid du Colombier else 665d5789509SDavid du Colombier ncp = sz - i - ser->inhdrsz; 666d5789509SDavid du Colombier memmove(out, in + i + ser->inhdrsz, ncp); 667d5789509SDavid du Colombier out += ncp; 668d5789509SDavid du Colombier ntotcp += ncp; 669d5789509SDavid du Colombier } 670d5789509SDavid du Colombier return ntotcp; 671d5789509SDavid du Colombier } 672d5789509SDavid du Colombier 673d5789509SDavid du Colombier static void 67480e9508eSDavid du Colombier epreader(void *u) 67580e9508eSDavid du Colombier { 676d5789509SDavid du Colombier int dfd, rcount, cl; 67780e9508eSDavid du Colombier char err[40]; 67880e9508eSDavid du Colombier Areader *a; 67980e9508eSDavid du Colombier Channel *c; 680d5789509SDavid du Colombier Packser *pk; 68180e9508eSDavid du Colombier Serial *ser; 682d5789509SDavid du Colombier Serialport *p; 68380e9508eSDavid du Colombier 68480e9508eSDavid du Colombier threadsetname("epreader proc"); 68580e9508eSDavid du Colombier a = u; 686d5789509SDavid du Colombier p = a->p; 687d5789509SDavid du Colombier ser = p->s; 68880e9508eSDavid du Colombier c = a->c; 68980e9508eSDavid du Colombier free(a); 69080e9508eSDavid du Colombier 69180e9508eSDavid du Colombier qlock(ser); 692d5789509SDavid du Colombier dfd = p->epin->dfd; 69380e9508eSDavid du Colombier qunlock(ser); 69480e9508eSDavid du Colombier 695d5789509SDavid du Colombier pk = nil; 69680e9508eSDavid du Colombier do { 697d5789509SDavid du Colombier if (pk == nil) 698d5789509SDavid du Colombier pk = emallocz(sizeof(Packser), 1); 699d5789509SDavid du Colombier rcount = read(dfd, pk->b, sizeof pk->b); 70080e9508eSDavid du Colombier if(serialdebug > 5) 701d5789509SDavid du Colombier dsprint(2, "%d %#ux%#ux ", rcount, p->data[0], 702d5789509SDavid du Colombier p->data[1]); 703d5789509SDavid du Colombier if(rcount < 0) 70480e9508eSDavid du Colombier break; 705d5789509SDavid du Colombier if(rcount == 0) 706d5789509SDavid du Colombier continue; 70780e9508eSDavid du Colombier if(rcount >= ser->inhdrsz){ 708d5789509SDavid du Colombier rcount = cpdata(ser, p, pk->b, pk->b, rcount); 70980e9508eSDavid du Colombier if(rcount != 0){ 710d5789509SDavid du Colombier pk->nb = rcount; 711d5789509SDavid du Colombier cl = sendp(c, pk); 712d5789509SDavid du Colombier if(cl < 0){ 713d5789509SDavid du Colombier /* 714d5789509SDavid du Colombier * if it was a time-out, I don't want 715d5789509SDavid du Colombier * to give back an error. 716d5789509SDavid du Colombier */ 717d5789509SDavid du Colombier rcount = 0; 718d5789509SDavid du Colombier break; 71980e9508eSDavid du Colombier } 720d5789509SDavid du Colombier }else 721d5789509SDavid du Colombier free(pk); 722d5789509SDavid du Colombier pk = nil; 72380e9508eSDavid du Colombier } 72480e9508eSDavid du Colombier } while(rcount >= 0 || (rcount < 0 && strstr(err, "timed out") != nil)); 72580e9508eSDavid du Colombier 72680e9508eSDavid du Colombier if(rcount < 0) 727d5789509SDavid du Colombier fprint(2, "%s: error reading %s: %r\n", argv0, p->fs.name); 728d5789509SDavid du Colombier free(pk); 729d5789509SDavid du Colombier nbsendp(c, nil); 730d5789509SDavid du Colombier if(p->w4data != nil) 731d5789509SDavid du Colombier chanclose(p->w4data); 732d5789509SDavid du Colombier if(p->gotdata != nil) 733d5789509SDavid du Colombier chanclose(p->gotdata); 734d5789509SDavid du Colombier devctl(ser->dev, "detach"); 73580e9508eSDavid du Colombier closedev(ser->dev); 736d5789509SDavid du Colombier usbfsdel(&p->fs); 73780e9508eSDavid du Colombier } 73880e9508eSDavid du Colombier 73980e9508eSDavid du Colombier static void 74080e9508eSDavid du Colombier statusreader(void *u) 74180e9508eSDavid du Colombier { 74280e9508eSDavid du Colombier Areader *a; 74380e9508eSDavid du Colombier Channel *c; 744d5789509SDavid du Colombier Packser *pk; 745d5789509SDavid du Colombier Serialport *p; 74680e9508eSDavid du Colombier Serial *ser; 747d5789509SDavid du Colombier int cl; 74880e9508eSDavid du Colombier 749d5789509SDavid du Colombier p = u; 750d5789509SDavid du Colombier ser = p->s; 75180e9508eSDavid du Colombier threadsetname("statusreader thread"); 75280e9508eSDavid du Colombier /* big buffering, fewer bytes lost */ 75380e9508eSDavid du Colombier c = chancreate(sizeof(Packser *), 128); 75480e9508eSDavid du Colombier a = emallocz(sizeof(Areader), 1); 755d5789509SDavid du Colombier a->p = p; 75680e9508eSDavid du Colombier a->c = c; 75780e9508eSDavid du Colombier incref(ser->dev); 75880e9508eSDavid du Colombier proccreate(epreader, a, 16*1024); 75980e9508eSDavid du Colombier 760d5789509SDavid du Colombier while((pk = recvp(c)) != nil){ 761d5789509SDavid du Colombier memmove(p->data, pk->b, pk->nb); 762d5789509SDavid du Colombier p->ndata = pk->nb; 763d5789509SDavid du Colombier free(pk); 764d5789509SDavid du Colombier dsprint(2, "serial: status reader %d \n", p->ndata); 76580e9508eSDavid du Colombier /* consume it all */ 766d5789509SDavid du Colombier while(p->ndata != 0){ 76780e9508eSDavid du Colombier dsprint(2, "serial: status reader to consume: %d\n", 768d5789509SDavid du Colombier p->ndata); 769d5789509SDavid du Colombier cl = recvul(p->w4data); 770d5789509SDavid du Colombier if(cl < 0) 771d5789509SDavid du Colombier break; 772d5789509SDavid du Colombier cl = sendul(p->gotdata, 1); 773d5789509SDavid du Colombier if(cl < 0) 774d5789509SDavid du Colombier break; 77580e9508eSDavid du Colombier } 77680e9508eSDavid du Colombier } 777d5789509SDavid du Colombier 778d5789509SDavid du Colombier shutdownchan(c); 779d5789509SDavid du Colombier devctl(ser->dev, "detach"); 78080e9508eSDavid du Colombier closedev(ser->dev); 781d5789509SDavid du Colombier usbfsdel(&p->fs); 78280e9508eSDavid du Colombier } 78380e9508eSDavid du Colombier 78480e9508eSDavid du Colombier static int 78580e9508eSDavid du Colombier ftreset(Serial *ser) 78680e9508eSDavid du Colombier { 787d5789509SDavid du Colombier Serialport *p; 788d5789509SDavid du Colombier int i; 789d5789509SDavid du Colombier 790d5789509SDavid du Colombier p = ser->p; 791d5789509SDavid du Colombier for(i = 0; i < Maxifc; i++) 792d5789509SDavid du Colombier if(!p[i].isjtag && p[i].s != nil) 793d5789509SDavid du Colombier ftdiwrite(&p[i], FTRESETCTLVAL, 0, FTRESET); 79480e9508eSDavid du Colombier return 0; 79580e9508eSDavid du Colombier } 79680e9508eSDavid du Colombier 79780e9508eSDavid du Colombier static int 798d5789509SDavid du Colombier ftinit(Serialport *p) 79980e9508eSDavid du Colombier { 800d5789509SDavid du Colombier Serial *ser; 80180e9508eSDavid du Colombier 802d5789509SDavid du Colombier ser = p->s; 80380e9508eSDavid du Colombier incref(ser->dev); 804d5789509SDavid du Colombier threadcreate(statusreader, p, 8*1024); 80580e9508eSDavid du Colombier return 0; 80680e9508eSDavid du Colombier } 80780e9508eSDavid du Colombier 80880e9508eSDavid du Colombier static int 809d5789509SDavid du Colombier ftsetbreak(Serialport *p, int val) 81080e9508eSDavid du Colombier { 811d5789509SDavid du Colombier return ftdiwrite(p, (val != 0? FTSETBREAK: 0), 0, FTSETDATA); 81280e9508eSDavid du Colombier } 81380e9508eSDavid du Colombier 81480e9508eSDavid du Colombier static int 815d5789509SDavid du Colombier ftclearpipes(Serialport *p) 81680e9508eSDavid du Colombier { 81780e9508eSDavid du Colombier /* maybe can be done in one... */ 818d5789509SDavid du Colombier ftdiwrite(p, FTRESETCTLVALPURGETX, 0, FTRESET); 819d5789509SDavid du Colombier ftdiwrite(p, FTRESETCTLVALPURGERX, 0, FTRESET); 82080e9508eSDavid du Colombier return 0; 82180e9508eSDavid du Colombier } 82280e9508eSDavid du Colombier 82380e9508eSDavid du Colombier static int 824d5789509SDavid du Colombier setctlline(Serialport *p, uchar val) 82580e9508eSDavid du Colombier { 826d5789509SDavid du Colombier return ftdiwrite(p, val | (val << 8), 0, FTSETMODEMCTRL); 82780e9508eSDavid du Colombier } 82880e9508eSDavid du Colombier 82980e9508eSDavid du Colombier static void 830d5789509SDavid du Colombier updatectlst(Serialport *p, int val) 83180e9508eSDavid du Colombier { 832d5789509SDavid du Colombier if(p->rts) 833d5789509SDavid du Colombier p->ctlstate |= val; 83480e9508eSDavid du Colombier else 835d5789509SDavid du Colombier p->ctlstate &= ~val; 83680e9508eSDavid du Colombier } 83780e9508eSDavid du Colombier 83880e9508eSDavid du Colombier static int 839d5789509SDavid du Colombier setctl(Serialport *p) 84080e9508eSDavid du Colombier { 84180e9508eSDavid du Colombier int res; 842d5789509SDavid du Colombier Serial *ser; 843d5789509SDavid du Colombier 844d5789509SDavid du Colombier ser = p->s; 84580e9508eSDavid du Colombier 84680e9508eSDavid du Colombier if(ser->dev->usb->vid == FTVid && ser->dev->usb->did == FTHETIRA1Did){ 84780e9508eSDavid du Colombier fprint(2, "serial: cannot set lines for this device\n"); 848d5789509SDavid du Colombier updatectlst(p, CtlRTS|CtlDTR); 849d5789509SDavid du Colombier p->rts = p->dtr = 1; 85080e9508eSDavid du Colombier return -1; 85180e9508eSDavid du Colombier } 85280e9508eSDavid du Colombier 85380e9508eSDavid du Colombier /* NB: you can not set DTR and RTS with one control message */ 854d5789509SDavid du Colombier updatectlst(p, CtlRTS); 855d5789509SDavid du Colombier res = setctlline(p, (CtlRTS<<8)|p->ctlstate); 85680e9508eSDavid du Colombier if(res < 0) 85780e9508eSDavid du Colombier return res; 85880e9508eSDavid du Colombier 859d5789509SDavid du Colombier updatectlst(p, CtlDTR); 860d5789509SDavid du Colombier res = setctlline(p, (CtlDTR<<8)|p->ctlstate); 86180e9508eSDavid du Colombier if(res < 0) 86280e9508eSDavid du Colombier return res; 86380e9508eSDavid du Colombier 86480e9508eSDavid du Colombier return 0; 86580e9508eSDavid du Colombier } 86680e9508eSDavid du Colombier 86780e9508eSDavid du Colombier static int 868d5789509SDavid du Colombier ftsendlines(Serialport *p) 86980e9508eSDavid du Colombier { 87080e9508eSDavid du Colombier int res; 87180e9508eSDavid du Colombier 872d5789509SDavid du Colombier dsprint(2, "serial: sendlines: %#2.2x\n", p->ctlstate); 873d5789509SDavid du Colombier res = setctl(p); 87480e9508eSDavid du Colombier dsprint(2, "serial: sendlines res: %d\n", res); 87580e9508eSDavid du Colombier return 0; 87680e9508eSDavid du Colombier } 87780e9508eSDavid du Colombier 87880e9508eSDavid du Colombier static int 879d5789509SDavid du Colombier ftseteps(Serialport *p) 88080e9508eSDavid du Colombier { 88180e9508eSDavid du Colombier char *s; 882d5789509SDavid du Colombier Serial *ser; 88380e9508eSDavid du Colombier 884d5789509SDavid du Colombier ser = p->s; 885d5789509SDavid du Colombier 886d5789509SDavid du Colombier s = smprint("maxpkt %d", ser->maxrtrans); 887d5789509SDavid du Colombier devctl(p->epin, s); 888d5789509SDavid du Colombier free(s); 889d5789509SDavid du Colombier 890d5789509SDavid du Colombier s = smprint("maxpkt %d", ser->maxwtrans); 891d5789509SDavid du Colombier devctl(p->epout, s); 89280e9508eSDavid du Colombier free(s); 89380e9508eSDavid du Colombier return 0; 89480e9508eSDavid du Colombier } 89580e9508eSDavid du Colombier 89680e9508eSDavid du Colombier Serialops ftops = { 89780e9508eSDavid du Colombier .init = ftinit, 89880e9508eSDavid du Colombier .seteps = ftseteps, 89980e9508eSDavid du Colombier .setparam = ftsetparam, 90080e9508eSDavid du Colombier .clearpipes = ftclearpipes, 90180e9508eSDavid du Colombier .reset = ftreset, 90280e9508eSDavid du Colombier .sendlines = ftsendlines, 90380e9508eSDavid du Colombier .modemctl = ftmodemctl, 90480e9508eSDavid du Colombier .setbreak = ftsetbreak, 90580e9508eSDavid du Colombier .wait4data = wait4data, 90680e9508eSDavid du Colombier .wait4write = wait4write, 90780e9508eSDavid du Colombier }; 908