]> git.lizzy.rs Git - plan9front.git/blob - sys/src/cmd/nusb/serial/ftdi.c
add nusb/cam
[plan9front.git] / sys / src / cmd / nusb / serial / ftdi.c
1 /* Future Technology Devices International serial ports */
2 #include <u.h>
3 #include <libc.h>
4 #include <thread.h>
5 #include <fcall.h>
6 #include <9p.h>
7 #include "usb.h"
8 #include "serial.h"
9
10 enum {
11         /* used by devices which don't provide their own Vid */
12         FTVid           = 0x0403,
13
14         FTSheevaVid     = 0x9E88,
15         FTSheevaDid     = 0x9E8F,
16         FTOpenRDUltDid  = 0x9E90,
17
18         FTSIODid        = 0x8372,       /* Product Id SIO appl'n of 8U100AX */
19         FT8U232AMDid    = 0x6001,       /* Similar device to SIO above */
20         FT8U232AMALTDid = 0x6006,       /* FT's alternate Did for above*/
21         FT8U2232CDid    = 0x6010,       /* Dual channel device */
22         FTRELAISDid     = 0xFA10,       /* Relais device */
23
24         /* NF reader */
25         FTNFRICVid      = 0x0DCD,
26         FTNFRICDid      = 0x0001,
27
28         FTACTZWAVEDid   = 0xF2D0,               /* www.irtrans.de device */
29
30         /*
31          * ACT Solutions HomePro ZWave interface
32          * http://www.act-solutions.com/HomePro.htm)
33          */
34         FTIRTRANSDid    = 0xFC60,
35
36         /*
37          * www.thoughttechnology.com/ TT-USB
38          */
39         FTTTUSBDid      = 0xFF20,
40
41         /* iPlus device */
42         FTIPLUSDid      = 0xD070,
43
44         /* www.crystalfontz.com devices */
45         FTXF632Did = 0xFC08,    /* 632: 16x2 Character Display */
46         FTXF634Did = 0xFC09,    /* 634: 20x4 Character Display */
47         FTXF547Did = 0xFC0A,    /* 547: Two line Display */
48         FTXF633Did = 0xFC0B,    /* 633: 16x2 Character Display with Keys */
49         FTXF631Did = 0xFC0C,    /* 631: 20x2 Character Display */
50         FTXF635Did = 0xFC0D,    /* 635: 20x4 Character Display */
51         FTXF640Did = 0xFC0E,    /* 640: Two line Display */
52         FTXF642Did = 0xFC0F,    /* 642: Two line Display */
53
54         /*
55          * Video Networks Limited / Homechoice in the UK
56          * use an ftdi-based device for their 1Mb broadband
57          */
58         FTVNHCPCUSBDDid = 0xfe38,
59
60         /*
61          * PCDJ use ftdi based dj-controllers
62          * DAC-2 device http://www.pcdjhardware.com/DAC2.asp
63          */
64         FTPCDJDAC2Did = 0xFA88,
65
66         /*
67          * Matrix Orbital LCD displays,
68          * which are the FT232BM (similar to the 8U232AM)
69          */
70         FTMTXORB0Did = 0xFA00,
71         FTMTXORB1Did = 0xFA01,
72         FTMTXORB2Did = 0xFA02,
73         FTMTXORB3Did = 0xFA03,
74         FTMTXORB4Did = 0xFA04,
75         FTMTXORB5Did = 0xFA05,
76         FTMTXORB6Did = 0xFA06,
77
78         /* Interbiometrics USB I/O Board */
79         INTERBIOMVid            = 0x1209,
80         INTERBIOMIOBRDDid       = 0x1002,
81         INTERBIOMMINIIOBRDDid   = 0x1006,
82
83         /*
84          * The following are the values for the Perle Systems
85          * UltraPort USB serial converters
86          */
87         FTPERLEULTRAPORTDid = 0xF0C0,
88
89         /*
90          * Sealevel SeaLINK+ adapters.
91          */
92
93         SEALEVELVid = 0x0c52,
94
95         SEALEVEL2101Did = 0x2101,       /* SeaLINK+232 (2101/2105) */
96         SEALEVEL2102Did = 0x2102,       /* SeaLINK+485 (2102) */
97         SEALEVEL2103Did = 0x2103,       /* SeaLINK+232I (2103) */
98         SEALEVEL2104Did = 0x2104,       /* SeaLINK+485I (2104) */
99         SEALEVEL22011Did = 0x2211,      /* SeaPORT+2/232 (2201) Port 1 */
100         SEALEVEL22012Did = 0x2221,      /* SeaPORT+2/232 (2201) Port 2 */
101         SEALEVEL22021Did = 0x2212,      /* SeaPORT+2/485 (2202) Port 1 */
102         SEALEVEL22022Did = 0x2222,      /* SeaPORT+2/485 (2202) Port 2 */
103         SEALEVEL22031Did = 0x2213,      /* SeaPORT+2 (2203) Port 1 */
104         SEALEVEL22032Did = 0x2223,      /* SeaPORT+2 (2203) Port 2 */
105         SEALEVEL24011Did = 0x2411,      /* SeaPORT+4/232 (2401) Port 1 */
106         SEALEVEL24012Did = 0x2421,      /* SeaPORT+4/232 (2401) Port 2 */
107         SEALEVEL24013Did = 0x2431,      /* SeaPORT+4/232 (2401) Port 3 */
108         SEALEVEL24014Did = 0x2441,      /* SeaPORT+4/232 (2401) Port 4 */
109         SEALEVEL24021Did = 0x2412,      /* SeaPORT+4/485 (2402) Port 1 */
110         SEALEVEL24022Did = 0x2422,      /* SeaPORT+4/485 (2402) Port 2 */
111         SEALEVEL24023Did = 0x2432,      /* SeaPORT+4/485 (2402) Port 3 */
112         SEALEVEL24024Did = 0x2442,      /* SeaPORT+4/485 (2402) Port 4 */
113         SEALEVEL24031Did = 0x2413,      /* SeaPORT+4 (2403) Port 1 */
114         SEALEVEL24032Did = 0x2423,      /* SeaPORT+4 (2403) Port 2 */
115         SEALEVEL24033Did = 0x2433,      /* SeaPORT+4 (2403) Port 3 */
116         SEALEVEL24034Did = 0x2443,      /* SeaPORT+4 (2403) Port 4 */
117         SEALEVEL28011Did = 0x2811,      /* SeaLINK+8/232 (2801) Port 1 */
118         SEALEVEL28012Did = 0x2821,      /* SeaLINK+8/232 (2801) Port 2 */
119         SEALEVEL28013Did = 0x2831,      /* SeaLINK+8/232 (2801) Port 3 */
120         SEALEVEL28014Did = 0x2841,      /* SeaLINK+8/232 (2801) Port 4 */
121         SEALEVEL28015Did = 0x2851,      /* SeaLINK+8/232 (2801) Port 5 */
122         SEALEVEL28016Did = 0x2861,      /* SeaLINK+8/232 (2801) Port 6 */
123         SEALEVEL28017Did = 0x2871,      /* SeaLINK+8/232 (2801) Port 7 */
124         SEALEVEL28018Did = 0x2881,      /* SeaLINK+8/232 (2801) Port 8 */
125         SEALEVEL28021Did = 0x2812,      /* SeaLINK+8/485 (2802) Port 1 */
126         SEALEVEL28022Did = 0x2822,      /* SeaLINK+8/485 (2802) Port 2 */
127         SEALEVEL28023Did = 0x2832,      /* SeaLINK+8/485 (2802) Port 3 */
128         SEALEVEL28024Did = 0x2842,      /* SeaLINK+8/485 (2802) Port 4 */
129         SEALEVEL28025Did = 0x2852,      /* SeaLINK+8/485 (2802) Port 5 */
130         SEALEVEL28026Did = 0x2862,      /* SeaLINK+8/485 (2802) Port 6 */
131         SEALEVEL28027Did = 0x2872,      /* SeaLINK+8/485 (2802) Port 7 */
132         SEALEVEL28028Did = 0x2882,      /* SeaLINK+8/485 (2802) Port 8 */
133         SEALEVEL28031Did = 0x2813,      /* SeaLINK+8 (2803) Port 1 */
134         SEALEVEL28032Did = 0x2823,      /* SeaLINK+8 (2803) Port 2 */
135         SEALEVEL28033Did = 0x2833,      /* SeaLINK+8 (2803) Port 3 */
136         SEALEVEL28034Did = 0x2843,      /* SeaLINK+8 (2803) Port 4 */
137         SEALEVEL28035Did = 0x2853,      /* SeaLINK+8 (2803) Port 5 */
138         SEALEVEL28036Did = 0x2863,      /* SeaLINK+8 (2803) Port 6 */
139         SEALEVEL28037Did = 0x2873,      /* SeaLINK+8 (2803) Port 7 */
140         SEALEVEL28038Did = 0x2883,      /* SeaLINK+8 (2803) Port 8 */
141
142         /* KOBIL Vendor ID chipcard terminals */
143         KOBILVid        = 0x0d46,
144         KOBILCONVB1Did  = 0x2020,       /* KOBIL Konverter for B1 */
145         KOBILCONVKAANDid = 0x2021,      /* KOBILKonverter for KAAN */
146
147         /* Icom ID-1 digital transceiver */
148         ICOMID1Vid      = 0x0C26,
149         ICOMID1Did      = 0x0004,
150
151         FTASKRDR400Did  = 0xC991,       /* ASK RDR 400 series card reader */
152         FTDSS20Did      = 0xFC82,       /* DSS-20 Sync Station for Sony Ericsson P800 */
153
154         /*
155          * Home Electronics (www.home-electro.com) USB gadgets
156          */
157         FTHETIRA1Did    = 0xFA78,       /* Tira-1 IR transceiver */
158
159         /*
160          * An infrared receiver and transmitter using the 8U232AM chip
161          * http://www.usbuirt.com
162          */
163         FTUSBUIRTDid    = 0xF850,
164
165         FTELVUR100Did   = 0xFB58,       /* USB-RS232-Umsetzer (UR 100) */
166         FTELVUM100Did   = 0xFB5A,       /* USB-Modul UM 100 */
167         FTELVUO100Did   = 0xFB5B,       /* USB-Modul UO 100 */
168         FTELVALC8500Did = 0xF06E,       /* ALC 8500 Expert */
169         FTELVCLI7000Did = 0xFB59,       /* Computer-Light-Interface */
170         FTELVPPS7330Did = 0xFB5C,       /* Processor-Power-Supply (PPS 7330) */
171         FTELVTFM100Did  = 0xFB5D,       /* Temperartur-Feuchte Messgeraet (TFM 100) */
172         FTELVUDF77Did   = 0xFB5E,       /* USB DCF Funkurh (UDF 77) */
173         FTELVUIO88Did   = 0xFB5F,       /* USB-I/O Interface (UIO 88) */
174         FTELVUAD8Did    = 0xF068,       /* USB-AD-Wandler (UAD 8) */
175         FTELVUDA7Did    = 0xF069,       /* USB-DA-Wandler (UDA 7) */
176         FTELVUSI2Did    = 0xF06A,       /* USB-Schrittmotoren-Interface (USI 2) */
177         FTELVT1100Did   = 0xF06B,       /* Thermometer (T 1100) */
178         FTELVPCD200Did  = 0xF06C,       /* PC-Datenlogger (PCD 200) */
179         FTELVULA200Did  = 0xF06D,       /* USB-LCD-Ansteuerung (ULA 200) */
180         FTELVFHZ1000PCDid= 0xF06F,      /* FHZ 1000 PC */
181         FTELVCSI8Did    = 0xE0F0,       /* Computer-Schalt-Interface (CSI 8) */
182         FTELVEM1000DLDid= 0xE0F1,       /* PC-Datenlogger fuer Energiemonitor (EM 1000 DL) */
183         FTELVPCK100Did  = 0xE0F2,       /* PC-Kabeltester (PCK 100) */
184         FTELVRFP500Did  = 0xE0F3,       /* HF-Leistungsmesser (RFP 500) */
185         FTELVFS20SIGDid = 0xE0F4,       /* Signalgeber (FS 20 SIG) */
186         FTELVWS300PCDid = 0xE0F6,       /* PC-Wetterstation (WS 300 PC) */
187         FTELVFHZ1300PCDid= 0xE0E8,      /* FHZ 1300 PC */
188         FTELVWS500Did   = 0xE0E9,       /* PC-Wetterstation (WS 500) */
189
190         /*
191          * Definitions for ID TECH (http://www.idt-net.com) devices
192          */
193         IDTECHVid       = 0x0ACD,       /* ID TECH Vendor ID */
194         IDTECHIDT1221UDid= 0x0300,      /* IDT1221U USB to RS-232 */
195
196         /*
197          * Definitions for Omnidirectional Control Technology, Inc. devices
198          */
199         OCTVid          = 0x0B39,       /* OCT vendor ID */
200
201         /*
202          * Note: OCT US101 is also rebadged as Dick Smith Electronics
203          * (NZ) XH6381, Dick Smith Electronics (Aus) XH6451, and SIIG
204          * Inc. model US2308 hardware version 1.
205          */
206         OCTUS101Did     = 0x0421,       /* OCT US101 USB to RS-232 */
207
208         /*
209          *      infrared receiver for access control with IR tags
210          */
211         FTPIEGROUPDid   = 0xF208,
212
213         /*
214          * Definitions for Artemis astronomical USB based cameras
215          * http://www.artemisccd.co.uk/
216          */
217
218         FTARTEMISDid    = 0xDF28,       /* All Artemis Cameras */
219
220         FTATIKATK16Did  = 0xDF30,       /* ATIK ATK-16 Grayscale Camera */
221         FTATIKATK16CDid = 0xDF32,       /* ATIK ATK-16C Colour Camera */
222         FTATIKATK16HRDid= 0xDF31,       /* ATIK ATK-16HR Grayscale */
223         FTATIKATK16HRCDid= 0xDF33,      /* ATIK ATK-16HRC Colour Camera */
224
225         /*
226          * Protego products
227          */
228         PROTEGOSPECIAL1 = 0xFC70,       /* special/unknown device */
229         PROTEGOR2X0     = 0xFC71,       /* R200-USB TRNG unit (R210, R220, and R230) */
230         PROTEGOSPECIAL3 = 0xFC72,       /* special/unknown device */
231         PROTEGOSPECIAL4 = 0xFC73,       /* special/unknown device */
232
233         /*
234          * Gude Analog- und Digitalsysteme GmbH
235          */
236         FTGUDEADSE808Did = 0xE808,
237         FTGUDEADSE809Did = 0xE809,
238         FTGUDEADSE80ADid = 0xE80A,
239         FTGUDEADSE80BDid = 0xE80B,
240         FTGUDEADSE80CDid = 0xE80C,
241         FTGUDEADSE80DDid = 0xE80D,
242         FTGUDEADSE80EDid = 0xE80E,
243         FTGUDEADSE80FDid = 0xE80F,
244         FTGUDEADSE888Did = 0xE888,      /* Expert ISDN Control USB */
245         FTGUDEADSE889Did = 0xE889,      /* USB RS-232 OptoBridge */
246         FTGUDEADSE88ADid = 0xE88A,
247         FTGUDEADSE88BDid = 0xE88B,
248         FTGUDEADSE88CDid = 0xE88C,
249         FTGUDEADSE88DDid = 0xE88D,
250         FTGUDEADSE88EDid = 0xE88E,
251         FTGUDEADSE88FDid = 0xE88F,
252
253         /*
254          * Linx Technologies
255          */
256         LINXSDMUSBQSSDid= 0xF448,       /* Linx SDM-USB-QS-S */
257         LINXMASTERDEVEL2Did= 0xF449,    /* Linx Master Development.0 */
258         LINXFUTURE0Did  = 0xF44A,       /* Linx future device */
259         LINXFUTURE1Did  = 0xF44B,       /* Linx future device */
260         LINXFUTURE2Did  = 0xF44C,       /* Linx future device */
261
262         /*
263          * CCS Inc. ICDU/ICDU40 - the FT232BM used in a in-circuit-debugger
264          * unit for PIC16's/PIC18's
265          */
266         FTCCSICDU200Did = 0xF9D0,
267         FTCCSICDU401Did = 0xF9D1,
268
269         /* Inside Accesso contactless reader (http://www.insidefr.com) */
270         INSIDEACCESSO   = 0xFAD0,
271
272         /*
273          * Intrepid Control Systems (http://www.intrepidcs.com/)
274          * ValueCAN and NeoVI
275          */
276         INTREDidVid     = 0x093C,
277         INTREDidVALUECANDid= 0x0601,
278         INTREDidNEOVIDid= 0x0701,
279
280         /*
281          * Falcom Wireless Communications GmbH
282          */
283         FALCOMVid       = 0x0F94,
284         FALCOMTWISTDid  = 0x0001,       /* Falcom Twist USB GPRS modem */
285         FALCOMSAMBADid  = 0x0005,       /* Falcom Samba USB GPRS modem */
286
287         /*
288          * SUUNTO
289          */
290         FTSUUNTOSPORTSDid= 0xF680,      /* Suunto Sports instrument */
291
292         /*
293          * B&B Electronics
294          */
295         BANDBVid        = 0x0856,       /* B&B Electronics Vendor ID */
296         BANDBUSOTL4Did  = 0xAC01,       /* USOTL4 Isolated RS-485 */
297         BANDBUSTL4Did   = 0xAC02,       /* USTL4 RS-485 Converter */
298         BANDBUSO9ML2Did = 0xAC03,       /* USO9ML2 Isolated RS-232 */
299
300         /*
301          * RM Michaelides CANview USB (http://www.rmcan.com)
302          * CAN fieldbus interface adapter
303          */
304         FTRMCANVIEWDid  = 0xfd60,
305
306         /*
307          * EVER Eco Pro UPS (http://www.ever.com.pl/)
308          */
309         EVERECOPROCDSDid = 0xe520,      /* RS-232 converter */
310
311         /*
312          * 4N-GALAXY.DE PIDs for CAN-USB, USB-RS232, USB-RS422, USB-RS485,
313          * USB-TTY activ, USB-TTY passiv. Some PIDs are used by several devices
314          */
315         FT4NGALAXYDE0Did = 0x8372,
316         FT4NGALAXYDE1Did = 0xF3C0,
317         FT4NGALAXYDE2Did = 0xF3C1,
318
319         /*
320          * Mobility Electronics products.
321          */
322         MOBILITYVid     = 0x1342,
323         MOBILITYUSBSERIALDid= 0x0202,   /* EasiDock USB 200 serial */
324
325         /*
326          * microHAM product IDs (http://www.microham.com)
327          */
328         FTMHAMKWDid     = 0xEEE8,       /* USB-KW interface */
329         FTMHAMYSDid     = 0xEEE9,       /* USB-YS interface */
330         FTMHAMY6Did     = 0xEEEA,       /* USB-Y6 interface */
331         FTMHAMY8Did     = 0xEEEB,       /* USB-Y8 interface */
332         FTMHAMICDid     = 0xEEEC,       /* USB-IC interface */
333         FTMHAMDB9Did    = 0xEEED,       /* USB-DB9 interface */
334         FTMHAMRS232Did  = 0xEEEE,       /* USB-RS232 interface */
335         FTMHAMY9Did     = 0xEEEF,       /* USB-Y9 interface */
336
337         /*
338          * Active Robots product ids.
339          */
340         FTACTIVEROBOTSDid       = 0xE548,       /* USB comms board */
341         XSENSCONVERTER0Did      = 0xD388,
342         XSENSCONVERTER1Did      = 0xD389,
343         XSENSCONVERTER2Did      = 0xD38A,
344         XSENSCONVERTER3Did      = 0xD38B,
345         XSENSCONVERTER4Did      = 0xD38C,
346         XSENSCONVERTER5Did      = 0xD38D,
347         XSENSCONVERTER6Did      = 0xD38E,
348         XSENSCONVERTER7Did      = 0xD38F,
349
350         /*
351          * Xsens Technologies BV products (http://www.xsens.com).
352          */
353         FTTERATRONIKVCPDid      = 0xEC88,       /* Teratronik device */
354         FTTERATRONIKD2XXDid     = 0xEC89,       /* Teratronik device */
355
356         /*
357          * Evolution Robotics products (http://www.evolution.com/).
358          */
359         EVOLUTIONVid    = 0xDEEE,
360         EVOLUTIONER1Did = 0x0300,               /* ER1 Control Module */
361
362         /* Pyramid Computer GmbH */
363         FTPYRAMIDDid    = 0xE6C8,               /* Pyramid Appliance Display */
364
365         /*
366          * Posiflex inc retail equipment (http://www.posiflex.com.tw)
367          */
368         POSIFLEXVid     = 0x0d3a,
369         POSIFLEXPP7000Did= 0x0300,              /* PP-7000II thermal printer */
370
371         /*
372          * Westrex International devices
373          */
374         FTWESTREXMODEL777Did    = 0xDC00,       /* Model 777 */
375         FTWESTREXMODEL8900FDid  = 0xDC01,       /* Model 8900F */
376
377         /*
378          * RR-CirKits LocoBuffer USB (http://www.rr-cirkits.com)
379          */
380         FTRRCIRKITSLOCOBUFFERDid= 0xc7d0,       /* LocoBuffer USB */
381         FTECLOCOM1WIREDid       = 0xEA90,       /* COM to 1-Wire USB */
382
383         /*
384          * Papouch products (http://www.papouch.com/)
385          */
386         PAPOUCHVid      = 0x5050,
387         PAPOUCHTMUDid   = 0x0400,               /* TMU USB Thermometer */
388
389         /*
390          * ACG Identification Technologies GmbH products http://www.acg.de/
391          */
392         FTACGHFDUALDid  = 0xDD20,               /* HF Dual ISO Reader (RFID) */
393         /*
394          * new high speed devices
395          */
396         FT4232HDid      = 0x6011,               /* FTDI FT4232H based device */
397
398         /*
399          * Amontec JTAGkey (http://www.amontec.com/)
400          */
401         AMONKEYDid      = 0xCFF8,
402 };
403
404 /* Commands */
405 enum {
406         FTRESET         = 0,            /* Reset the port */
407         FTSETMODEMCTRL,                 /* Set the modem control register */
408         FTSETFLOWCTRL,                  /* Set flow control register */
409         FTSETBAUDRATE,                  /* Set baud rate */
410         FTSETDATA,                      /* Set the parameters, parity */
411         FTGETMODEMSTATUS,               /* Retrieve current value of modem ctl */
412         FTSETEVENTCHAR,                 /* Set the event character */
413         FTSETERRORCHAR,                 /* Set the error character */
414         FTUNKNOWN,
415         FTSETLATENCYTIMER,              /* Set the latency timer */
416         FTGETLATENCYTIMER,              /* Get the latency timer */
417         FTSETBITMODE,                   /* Set bit mode */
418         FTGETPINS,                      /* Read pins state */
419         FTGETE2READ     = 0x90,         /* Read address from 128-byte I2C EEPROM */
420         FTSETE2WRITE,                   /* Write to address on 128-byte I2C EEPROM */
421         FTSETE2ERASE,                   /* Erase address on 128-byte I2C EEPROM */
422 };
423
424 /* Port Identifier Table, index for interfaces */
425 enum {
426         PITDEFAULT = 0,         /* SIOA */
427         PITA,                   /* SIOA jtag if there is one */
428 };
429
430 enum {
431         Rftdireq = 1<<6,                /* bit for type of request */
432 };
433
434 /*
435  * Commands Data size
436  * Sets have wLength = 0
437  * Gets have wValue = 0
438  */
439 enum {
440         FTMODEMSTATUSSZ = 1,
441         FTLATENCYTIMERSZ= 1,
442         FTPINSSZ        = 1,
443         FTE2READSZ      = 2,
444 };
445
446 /*
447  * bRequest: FTGETE2READ
448  * wIndex: Address of word to read
449  * Data: Will return a word (2 bytes) of data from E2Address
450  * Results put in the I2C 128 byte EEPROM string eeprom+(2*index)
451  */
452
453 /*
454  * bRequest: FTSETE2WRITE
455  * wIndex: Address of word to read
456  * wValue: Value of the word
457  * Data: Will return a word (2 bytes) of data from E2Address
458  */
459
460 /*
461  * bRequest: FTSETE2ERASE
462  * Erases the EEPROM
463  * wIndex: 0
464  */
465
466 /*
467  * bRequest: FTRESET
468  * wValue: Ctl Val
469  * wIndex: Port
470  */
471 enum {
472         FTRESETCTLVAL           = 0,
473         FTRESETCTLVALPURGERX    = 1,
474         FTRESETCTLVALPURGETX    = 2,
475 };
476
477 /*
478  * BmRequestType: SET
479  * bRequest: FTSETBAUDRATE
480  * wValue: BaudDivisor value - see below
481  * Bits 15 to 0 of the 17-bit divisor are placed in the request value.
482  * Bit 16 is placed in bit 0 of the request index.
483  */
484
485 /* chip type */
486 enum {
487         SIO             = 1,
488         FT8U232AM       = 2,
489         FT232BM         = 3,
490         FT2232C         = 4,
491         FTKINDR         = 5,
492         FT2232H         = 6,
493         FT4232H         = 7,
494 };
495
496 enum {
497          FTb300         = 0,
498          FTb600         = 1,
499          FTb1200        = 2,
500          FTb2400        = 3,
501          FTb4800        = 4,
502          FTb9600        = 5,
503          FTb19200       = 6,
504          FTb38400       = 7,
505          FTb57600       = 8,
506          FTb115200      = 9,
507 };
508
509 /*
510  * bRequest: FTSETDATA
511  * wValue: Data characteristics
512  *      bits 0-7 number of data bits
513  * wIndex: Port
514  */
515 enum {
516         FTSETDATAParNONE        = 0 << 8,
517         FTSETDATAParODD         = 1 << 8,
518         FTSETDATAParEVEN        = 2 << 8,
519         FTSETDATAParMARK        = 3 << 8,
520         FTSETDATAParSPACE       = 4 << 8,
521         FTSETDATASTOPBITS1      = 0 << 11,
522         FTSETDATASTOPBITS15     = 1 << 11,
523         FTSETDATASTOPBITS2      = 2 << 11,
524         FTSETBREAK              = 1 << 14,
525 };
526
527 /*
528  * bRequest: FTSETMODEMCTRL
529  * wValue: ControlValue (see below)
530  * wIndex: Port
531  */
532
533 /*
534  * bRequest: FTSETFLOWCTRL
535  * wValue: Xoff/Xon
536  * wIndex: Protocol/Port - hIndex is protocol; lIndex is port
537  */
538 enum {
539         FTDISABLEFLOWCTRL= 0,
540         FTRTSCTSHS      = 1 << 8,
541         FTDTRDSRHS      = 2 << 8,
542         FTXONXOFFHS     = 4 << 8,
543 };
544
545 /*
546  * bRequest: FTGETLATENCYTIMER
547  * wIndex: Port
548  * wLength: 0
549  * Data: latency (on return)
550  */
551
552 /*
553  * bRequest: FTSETBITMODE
554  * wIndex: Port
555  * either it is big bang mode, in which case
556  * wValue: 1 byte L is the big bang mode BIG*
557  *      or BM is
558  * wValue: 1 byte bitbang mode H, 1 byte bitmask for lines L
559  */
560 enum {
561         BMSERIAL        = 0,            /* reset, turn off bit-bang mode */
562
563         BIGBMNORMAL     = 1,            /* normal bit-bang mode */
564         BIGBMSPI        = 2,            /* spi bit-bang mode */
565
566         BMABM           = 1<<8,         /* async mode */
567         BMMPSSE         = 2<<8,
568         BMSYNCBB        = 4<<8,         /* sync bit-bang -- 2232x and R-type */
569         BMMCU           = 8<<8,         /* MCU Host Bus -- 2232x */
570         BMOPTO          = 0x10<<8,      /* opto-isolated<<8, 2232x */
571         BMCBUS          = 0x20<<8,      /* CBUS pins of R-type chips */
572         BMSYNCFF        = 0x40<<8,      /* Single Channel Sync FIFO, 2232H only */
573 };
574
575 /*
576  * bRequest: FTSETLATENCYTIMER
577  * wValue: Latency (milliseconds 1-255)
578  * wIndex: Port
579  */
580 enum {
581         FTLATENCYDEFAULT = 2,
582 };
583
584 /*
585  * BmRequestType: SET
586  * bRequest: FTSETEVENTCHAR
587  * wValue: EventChar
588  * wIndex: Port
589  * 0-7 lower bits event char
590  * 8 enable
591  */
592 enum {
593         FTEVCHARENAB = 1<<8,
594 };
595
596 /*
597  * BmRequestType: SET
598  * bRequest: FTSETERRORCHAR
599  * wValue: Error Char
600  * wIndex: Port
601  * 0-7 lower bits event char
602  * 8 enable
603  */
604 enum {
605         FTERRCHARENAB = 1<<8,
606 };
607 /*
608  * BmRequestType: GET
609  * bRequest: FTGETMODEMSTATUS
610  * wIndex: Port
611  * wLength: 1
612  * Data: Status
613  */
614 enum {
615         FTCTSMASK       = 0x10,
616         FTDSRMASK       = 0x20,
617         FTRIMASK        = 0x40,
618         FTRLSDMASK      = 0x80,
619 };
620
621 enum {
622         /* byte 0 of in data hdr */
623         FTICTS  = 1 << 4,
624         FTIDSR  = 1 << 5,
625         FTIRI   = 1 << 6,
626         FTIRLSD = 1 << 7,       /* receive line signal detect */
627
628         /* byte 1 of in data hdr */
629         FTIDR   = 1<<0,         /* data ready */
630         FTIOE   = 1<<1,         /* overrun error */
631         FTIPE   = 1<<2,         /* parity error */
632         FTIFE   = 1<<3,         /* framing error */
633         FTIBI   = 1<<4,         /* break interrupt */
634         FTITHRE = 1<<5,         /* xmitter holding register */
635         FTITEMT = 1<<6,         /* xmitter empty */
636         FTIFIFO = 1<<7,         /* error in rcv fifo */
637
638         /* byte 0 of out data hdr len does not include byte 0 */
639         FTOLENMSK= 0x3F,
640         FTOPORT = 0x80,         /* must be set */
641 };
642
643 /*
644  * BUG: This keeps growing, there has to be a better way, but without
645  * devices to try it...  We can probably simply look for FTDI in the
646  * string, or use regular expressions somehow.
647  */
648 Cinfo ftinfo[] = {
649         { FTVid, FTACTZWAVEDid },
650         { FTSheevaVid, FTSheevaDid },
651         { FTVid, FTOpenRDUltDid},
652         { FTVid, FTIRTRANSDid },
653         { FTVid, FTIPLUSDid },
654         { FTVid, FTSIODid },
655         { FTVid, FT8U232AMDid },
656         { FTVid, FT8U232AMALTDid },
657         { FTVid, FT8U2232CDid },
658         { FTVid, FTRELAISDid },
659         { INTERBIOMVid, INTERBIOMIOBRDDid },
660         { INTERBIOMVid, INTERBIOMMINIIOBRDDid },
661         { FTVid, FTXF632Did },
662         { FTVid, FTXF634Did },
663         { FTVid, FTXF547Did },
664         { FTVid, FTXF633Did },
665         { FTVid, FTXF631Did },
666         { FTVid, FTXF635Did },
667         { FTVid, FTXF640Did },
668         { FTVid, FTXF642Did },
669         { FTVid, FTDSS20Did },
670         { FTNFRICVid, FTNFRICDid },
671         { FTVid, FTVNHCPCUSBDDid },
672         { FTVid, FTMTXORB0Did },
673         { FTVid, FTMTXORB1Did },
674         { FTVid, FTMTXORB2Did },
675         { FTVid, FTMTXORB3Did },
676         { FTVid, FTMTXORB4Did },
677         { FTVid, FTMTXORB5Did },
678         { FTVid, FTMTXORB6Did },
679         { FTVid, FTPERLEULTRAPORTDid },
680         { FTVid, FTPIEGROUPDid },
681         { SEALEVELVid, SEALEVEL2101Did },
682         { SEALEVELVid, SEALEVEL2102Did },
683         { SEALEVELVid, SEALEVEL2103Did },
684         { SEALEVELVid, SEALEVEL2104Did },
685         { SEALEVELVid, SEALEVEL22011Did },
686         { SEALEVELVid, SEALEVEL22012Did },
687         { SEALEVELVid, SEALEVEL22021Did },
688         { SEALEVELVid, SEALEVEL22022Did },
689         { SEALEVELVid, SEALEVEL22031Did },
690         { SEALEVELVid, SEALEVEL22032Did },
691         { SEALEVELVid, SEALEVEL24011Did },
692         { SEALEVELVid, SEALEVEL24012Did },
693         { SEALEVELVid, SEALEVEL24013Did },
694         { SEALEVELVid, SEALEVEL24014Did },
695         { SEALEVELVid, SEALEVEL24021Did },
696         { SEALEVELVid, SEALEVEL24022Did },
697         { SEALEVELVid, SEALEVEL24023Did },
698         { SEALEVELVid, SEALEVEL24024Did },
699         { SEALEVELVid, SEALEVEL24031Did },
700         { SEALEVELVid, SEALEVEL24032Did },
701         { SEALEVELVid, SEALEVEL24033Did },
702         { SEALEVELVid, SEALEVEL24034Did },
703         { SEALEVELVid, SEALEVEL28011Did },
704         { SEALEVELVid, SEALEVEL28012Did },
705         { SEALEVELVid, SEALEVEL28013Did },
706         { SEALEVELVid, SEALEVEL28014Did },
707         { SEALEVELVid, SEALEVEL28015Did },
708         { SEALEVELVid, SEALEVEL28016Did },
709         { SEALEVELVid, SEALEVEL28017Did },
710         { SEALEVELVid, SEALEVEL28018Did },
711         { SEALEVELVid, SEALEVEL28021Did },
712         { SEALEVELVid, SEALEVEL28022Did },
713         { SEALEVELVid, SEALEVEL28023Did },
714         { SEALEVELVid, SEALEVEL28024Did },
715         { SEALEVELVid, SEALEVEL28025Did },
716         { SEALEVELVid, SEALEVEL28026Did },
717         { SEALEVELVid, SEALEVEL28027Did },
718         { SEALEVELVid, SEALEVEL28028Did },
719         { SEALEVELVid, SEALEVEL28031Did },
720         { SEALEVELVid, SEALEVEL28032Did },
721         { SEALEVELVid, SEALEVEL28033Did },
722         { SEALEVELVid, SEALEVEL28034Did },
723         { SEALEVELVid, SEALEVEL28035Did },
724         { SEALEVELVid, SEALEVEL28036Did },
725         { SEALEVELVid, SEALEVEL28037Did },
726         { SEALEVELVid, SEALEVEL28038Did },
727         { IDTECHVid, IDTECHIDT1221UDid },
728         { OCTVid, OCTUS101Did },
729         { FTVid, FTHETIRA1Did }, /* special quirk div = 240 baud = B38400 rtscts = 1 */
730         { FTVid, FTUSBUIRTDid }, /* special quirk div = 77, baud = B38400 */
731         { FTVid, PROTEGOSPECIAL1 },
732         { FTVid, PROTEGOR2X0 },
733         { FTVid, PROTEGOSPECIAL3 },
734         { FTVid, PROTEGOSPECIAL4 },
735         { FTVid, FTGUDEADSE808Did },
736         { FTVid, FTGUDEADSE809Did },
737         { FTVid, FTGUDEADSE80ADid },
738         { FTVid, FTGUDEADSE80BDid },
739         { FTVid, FTGUDEADSE80CDid },
740         { FTVid, FTGUDEADSE80DDid },
741         { FTVid, FTGUDEADSE80EDid },
742         { FTVid, FTGUDEADSE80FDid },
743         { FTVid, FTGUDEADSE888Did },
744         { FTVid, FTGUDEADSE889Did },
745         { FTVid, FTGUDEADSE88ADid },
746         { FTVid, FTGUDEADSE88BDid },
747         { FTVid, FTGUDEADSE88CDid },
748         { FTVid, FTGUDEADSE88DDid },
749         { FTVid, FTGUDEADSE88EDid },
750         { FTVid, FTGUDEADSE88FDid },
751         { FTVid, FTELVUO100Did },
752         { FTVid, FTELVUM100Did },
753         { FTVid, FTELVUR100Did },
754         { FTVid, FTELVALC8500Did },
755         { FTVid, FTPYRAMIDDid },
756         { FTVid, FTELVFHZ1000PCDid },
757         { FTVid, FTELVCLI7000Did },
758         { FTVid, FTELVPPS7330Did },
759         { FTVid, FTELVTFM100Did },
760         { FTVid, FTELVUDF77Did },
761         { FTVid, FTELVUIO88Did },
762         { FTVid, FTELVUAD8Did },
763         { FTVid, FTELVUDA7Did },
764         { FTVid, FTELVUSI2Did },
765         { FTVid, FTELVT1100Did },
766         { FTVid, FTELVPCD200Did },
767         { FTVid, FTELVULA200Did },
768         { FTVid, FTELVCSI8Did },
769         { FTVid, FTELVEM1000DLDid },
770         { FTVid, FTELVPCK100Did },
771         { FTVid, FTELVRFP500Did },
772         { FTVid, FTELVFS20SIGDid },
773         { FTVid, FTELVWS300PCDid },
774         { FTVid, FTELVFHZ1300PCDid },
775         { FTVid, FTELVWS500Did },
776         { FTVid, LINXSDMUSBQSSDid },
777         { FTVid, LINXMASTERDEVEL2Did },
778         { FTVid, LINXFUTURE0Did },
779         { FTVid, LINXFUTURE1Did },
780         { FTVid, LINXFUTURE2Did },
781         { FTVid, FTCCSICDU200Did },
782         { FTVid, FTCCSICDU401Did },
783         { FTVid, INSIDEACCESSO },
784         { INTREDidVid, INTREDidVALUECANDid },
785         { INTREDidVid, INTREDidNEOVIDid },
786         { FALCOMVid, FALCOMTWISTDid },
787         { FALCOMVid, FALCOMSAMBADid },
788         { FTVid, FTSUUNTOSPORTSDid },
789         { FTVid, FTRMCANVIEWDid },
790         { BANDBVid, BANDBUSOTL4Did },
791         { BANDBVid, BANDBUSTL4Did },
792         { BANDBVid, BANDBUSO9ML2Did },
793         { FTVid, EVERECOPROCDSDid },
794         { FTVid, FT4NGALAXYDE0Did },
795         { FTVid, FT4NGALAXYDE1Did },
796         { FTVid, FT4NGALAXYDE2Did },
797         { FTVid, XSENSCONVERTER0Did },
798         { FTVid, XSENSCONVERTER1Did },
799         { FTVid, XSENSCONVERTER2Did },
800         { FTVid, XSENSCONVERTER3Did },
801         { FTVid, XSENSCONVERTER4Did },
802         { FTVid, XSENSCONVERTER5Did },
803         { FTVid, XSENSCONVERTER6Did },
804         { FTVid, XSENSCONVERTER7Did },
805         { MOBILITYVid, MOBILITYUSBSERIALDid },
806         { FTVid, FTACTIVEROBOTSDid },
807         { FTVid, FTMHAMKWDid },
808         { FTVid, FTMHAMYSDid },
809         { FTVid, FTMHAMY6Did },
810         { FTVid, FTMHAMY8Did },
811         { FTVid, FTMHAMICDid },
812         { FTVid, FTMHAMDB9Did },
813         { FTVid, FTMHAMRS232Did },
814         { FTVid, FTMHAMY9Did },
815         { FTVid, FTTERATRONIKVCPDid },
816         { FTVid, FTTERATRONIKD2XXDid },
817         { EVOLUTIONVid, EVOLUTIONER1Did },
818         { FTVid, FTARTEMISDid },
819         { FTVid, FTATIKATK16Did },
820         { FTVid, FTATIKATK16CDid },
821         { FTVid, FTATIKATK16HRDid },
822         { FTVid, FTATIKATK16HRCDid },
823         { KOBILVid, KOBILCONVB1Did },
824         { KOBILVid, KOBILCONVKAANDid },
825         { POSIFLEXVid, POSIFLEXPP7000Did },
826         { FTVid, FTTTUSBDid },
827         { FTVid, FTECLOCOM1WIREDid },
828         { FTVid, FTWESTREXMODEL777Did },
829         { FTVid, FTWESTREXMODEL8900FDid },
830         { FTVid, FTPCDJDAC2Did },
831         { FTVid, FTRRCIRKITSLOCOBUFFERDid },
832         { FTVid, FTASKRDR400Did },
833         { ICOMID1Vid, ICOMID1Did },
834         { PAPOUCHVid, PAPOUCHTMUDid },
835         { FTVid, FTACGHFDUALDid },
836         { FT8U232AMDid, FT4232HDid },
837         { FTVid, AMONKEYDid },
838         { 0,    0 },
839 };
840
841 static Serialops ftops;
842
843 enum {
844         Packsz          = 64,           /* default size */
845         Maxpacksz       = 512,
846         Bufsiz          = 4 * 1024,
847 };
848
849 static int
850 ftdiread(Serialport *p, int index, int req, uchar *buf, int len)
851 {
852         int res;
853         Serial *ser;
854
855         ser = p->s;
856
857         if(req != FTGETE2READ)
858                 index |= p->interfc + 1;
859         dsprint(2, "serial: ftdiread %#p [%d] req: %#x val: %#x idx:%d buf:%p len:%d\n",
860                 p, p->interfc, req, 0, index, buf, len);
861         res = usbcmd(ser->dev, Rd2h | Rftdireq | Rdev, req, 0, index, buf, len);
862         dsprint(2, "serial: ftdiread res:%d\n", res);
863         return res;
864 }
865
866 static int
867 ftdiwrite(Serialport *p, int val, int index, int req)
868 {
869         int res;
870         Serial *ser;
871
872         ser = p->s;
873
874         if(req != FTGETE2READ || req != FTSETE2ERASE || req != FTSETBAUDRATE)
875                 index |= p->interfc + 1;
876         dsprint(2, "serial: ftdiwrite %#p [%d] req: %#x val: %#x idx:%d\n",
877                 p, p->interfc, req, val, index);
878         res = usbcmd(ser->dev, Rh2d | Rftdireq | Rdev, req, val, index, nil, 0);
879         dsprint(2, "serial: ftdiwrite res:%d\n", res);
880         return res;
881 }
882
883 static int
884 ftmodemctl(Serialport *p, int set)
885 {
886         if(set == 0){
887                 p->mctl = 0;
888                 ftdiwrite(p, 0, 0, FTSETMODEMCTRL);
889                 return 0;
890         }
891         p->mctl = 1;
892         ftdiwrite(p, 0, FTRTSCTSHS, FTSETFLOWCTRL);
893         return 0;
894 }
895
896 static ushort
897 ft232ambaudbase2div(int baud, int base)
898 {
899         int divisor3;
900         ushort divisor;
901
902         divisor3 = (base / 2) / baud;
903         if((divisor3 & 7) == 7)
904                 divisor3++;                     /* round x.7/8 up to x+1 */
905         divisor = divisor3 >> 3;
906         divisor3 &= 7;
907
908         if(divisor3 == 1)
909                 divisor |= 0xc000;              /*      0.125 */
910         else if(divisor3 >= 4)
911                 divisor |= 0x4000;              /*      0.5     */
912         else if(divisor3 != 0)
913                 divisor |= 0x8000;              /*      0.25    */
914         if( divisor == 1)
915                 divisor = 0;            /* special case for maximum baud rate */
916         return divisor;
917 }
918
919 enum{
920         ClockNew        = 48000000,
921         ClockOld        = 12000000 / 16,
922         HetiraDiv       = 240,
923         UirtDiv         = 77,
924 };
925
926 static ushort
927 ft232ambaud2div(int baud)
928 {
929         return ft232ambaudbase2div(baud, ClockNew);
930 }
931
932 static ulong divfrac[8] = { 0, 3, 2, 4, 1, 5, 6, 7};
933
934 static ulong
935 ft232bmbaudbase2div(int baud, int base)
936 {
937         int divisor3;
938         u32int divisor;
939
940         divisor3 = (base / 2) / baud;
941         divisor = divisor3 >> 3 | divfrac[divisor3 & 7] << 14;
942
943         /* Deal with special cases for highest baud rates. */
944         if( divisor == 1)
945                 divisor = 0;                    /* 1.0 */
946         else if( divisor == 0x4001)
947                 divisor = 1;                    /* 1.5 */
948         return divisor;
949 }
950
951 static ulong
952 ft232bmbaud2div (int baud)
953 {
954         return ft232bmbaudbase2div (baud, ClockNew);
955 }
956
957 static int
958 customdiv(Serial *ser)
959 {
960         if(ser->dev->usb->vid == FTVid && ser->dev->usb->did == FTHETIRA1Did)
961                 return HetiraDiv;
962         else if(ser->dev->usb->vid == FTVid && ser->dev->usb->did == FTUSBUIRTDid)
963                 return UirtDiv;
964
965         fprint(2, "serial: weird custom divisor\n");
966         return 0;               /* shouldn't happen, break as much as I can */
967 }
968
969 static ulong
970 ftbaudcalcdiv(Serial *ser, int baud)
971 {
972         int cusdiv;
973         ulong divval;
974
975         if(baud == 38400 && (cusdiv = customdiv(ser)) != 0)
976                 baud = ser->baudbase / cusdiv;
977
978         if(baud == 0)
979                 baud = 9600;
980
981         switch(ser->type) {
982         case SIO:
983                 switch(baud) {
984                 case 300:
985                         divval = FTb300;
986                         break;
987                 case 600:
988                         divval = FTb600;
989                         break;
990                 case 1200:
991                         divval = FTb1200;
992                         break;
993                 case 2400:
994                         divval = FTb2400;
995                         break;
996                 case 4800:
997                         divval = FTb4800;
998                         break;
999                 case 9600:
1000                         divval = FTb9600;
1001                         break;
1002                 case 19200:
1003                         divval = FTb19200;
1004                         break;
1005                 case 38400:
1006                         divval = FTb38400;
1007                         break;
1008                 case 57600:
1009                         divval = FTb57600;
1010                         break;
1011                 case 115200:
1012                         divval = FTb115200;
1013                         break;
1014                 default:
1015                         divval = FTb9600;
1016                         break;
1017                 }
1018                 break;
1019         case FT8U232AM:
1020                 if(baud <= 3000000)
1021                         divval = ft232ambaud2div(baud);
1022                 else
1023                         divval = ft232ambaud2div(9600);
1024                 break;
1025         case FT232BM:
1026         case FT2232C:
1027         case FTKINDR:
1028         case FT2232H:
1029         case FT4232H:
1030                 if(baud <= 3000000)
1031                         divval = ft232bmbaud2div(baud);
1032                 else
1033                         divval = ft232bmbaud2div(9600);
1034                 break;
1035         default:
1036                 divval = ft232bmbaud2div(9600);
1037                 break;
1038         }
1039         return divval;
1040 }
1041
1042 static int
1043 ftsetparam(Serialport *p)
1044 {
1045         int res;
1046         ushort val;
1047         ulong bauddiv;
1048
1049         val = 0;
1050         if(p->stop == 1)
1051                 val |= FTSETDATASTOPBITS1;
1052         else if(p->stop == 2)
1053                 val |= FTSETDATASTOPBITS2;
1054         else if(p->stop == 15)
1055                 val |= FTSETDATASTOPBITS15;
1056         switch(p->parity){
1057         case 0:
1058                 val |= FTSETDATAParNONE;
1059                 break;
1060         case 1:
1061                 val |= FTSETDATAParODD;
1062                 break;
1063         case 2:
1064                 val |= FTSETDATAParEVEN;
1065                 break;
1066         case 3:
1067                 val |= FTSETDATAParMARK;
1068                 break;
1069         case 4:
1070                 val |= FTSETDATAParSPACE;
1071                 break;
1072         };
1073
1074         dsprint(2, "serial: setparam\n");
1075
1076         res = ftdiwrite(p, val, 0, FTSETDATA);
1077         if(res < 0)
1078                 return res;
1079
1080         res = ftmodemctl(p, p->mctl);
1081         if(res < 0)
1082                 return res;
1083
1084         bauddiv = ftbaudcalcdiv(p->s, p->baud);
1085         res = ftdiwrite(p, bauddiv, (bauddiv>>16) & 1, FTSETBAUDRATE);
1086
1087         dsprint(2, "serial: setparam res: %d\n", res);
1088         return res;
1089 }
1090
1091 static int
1092 hasjtag(Usbdev *udev)
1093 {
1094         /* no string, for now, by default we detect no jtag */
1095         if(udev->product != nil && cistrstr(udev->product, "jtag") != nil)
1096                 return 1;
1097         /* blank aijuboard has jtag for initial bringup */
1098         if(udev->csp == 0xffffff)
1099                 return 1;
1100         return 0;
1101 }
1102
1103 /* ser locked */
1104 static void
1105 ftgettype(Serial *ser)
1106 {
1107         int i, outhdrsz, dno, pksz;
1108         ulong baudbase;
1109         Conf *cnf;
1110
1111         pksz = Packsz;
1112         /* Assume it is not the original SIO device for now. */
1113         baudbase = ClockNew / 2;
1114         outhdrsz = 0;
1115         dno = ser->dev->usb->dno;
1116         cnf = ser->dev->usb->conf[0];
1117         ser->nifcs = 0;
1118         for(i = 0; i < Niface; i++)
1119                 if(cnf->iface[i] != nil)
1120                         ser->nifcs++;
1121         if(ser->nifcs > 1) {
1122                 /*
1123                  * Multiple interfaces.  default assume FT2232C,
1124                  */
1125                 if(dno == 0x500)
1126                         ser->type = FT2232C;
1127                 else if(dno == 0x600)
1128                         ser->type = FTKINDR;
1129                 else if(dno == 0x700){
1130                         ser->type = FT2232H;
1131                         pksz = Maxpacksz;
1132                 } else if(dno == 0x800){
1133                         ser->type = FT4232H;
1134                         pksz = Maxpacksz;
1135                 } else
1136                         ser->type = FT2232C;
1137
1138                 if(hasjtag(ser->dev->usb))
1139                         ser->jtag = 0;
1140
1141                 /*
1142                  * BM-type devices have a bug where dno gets set
1143                  * to 0x200 when serial is 0.
1144                  */
1145                 if(dno < 0x500)
1146                         fprint(2, "serial: warning: dno %d too low for "
1147                                 "multi-interface device\n", dno);
1148         } else if(dno < 0x200) {
1149                 /* Old device.  Assume it is the original SIO. */
1150                 ser->type = SIO;
1151                 baudbase = ClockOld/16;
1152                 outhdrsz = 1;
1153         } else if(dno < 0x400)
1154                 /*
1155                  * Assume its an FT8U232AM (or FT8U245AM)
1156                  * (It might be a BM because of the iSerialNumber bug,
1157                  * but it will still work as an AM device.)
1158                  */
1159                 ser->type = FT8U232AM;
1160         else                    /* Assume it is an FT232BM (or FT245BM) */
1161                 ser->type = FT232BM;
1162
1163         ser->maxrtrans = ser->maxwtrans = pksz;
1164         ser->baudbase = baudbase;
1165         ser->outhdrsz = outhdrsz;
1166         ser->inhdrsz = 2;
1167         ser->Serialops = ftops;
1168
1169         dsprint (2, "serial: detected type: %#x\n", ser->type);
1170 }
1171
1172 int
1173 ftprobe(Serial *ser)
1174 {
1175         Usbdev *ud = ser->dev->usb;
1176
1177         if(matchid(ftinfo, ud->vid, ud->did) == nil)
1178                 return -1;
1179         ftgettype(ser);
1180         return 0;
1181 }
1182
1183 static int
1184 ftuseinhdr(Serialport *p, uchar *b)
1185 {
1186         if(b[0] & FTICTS)
1187                 p->cts = 1;
1188         else
1189                 p->cts = 0;
1190         if(b[0] & FTIDSR)
1191                 p->dsr = 1;
1192         else
1193                 p->dsr = 0;
1194         if(b[0] & FTIRI)
1195                 p->ring = 1;
1196         else
1197                 p->ring = 0;
1198         if(b[0] & FTIRLSD)
1199                 p->rlsd = 1;
1200         else
1201                 p->rlsd = 0;
1202
1203         if(b[1] & FTIOE)
1204                 p->novererr++;
1205         if(b[1] & FTIPE)
1206                 p->nparityerr++;
1207         if(b[1] & FTIFE)
1208                 p->nframeerr++;
1209         if(b[1] & FTIBI)
1210                 p->nbreakerr++;
1211         return 0;
1212 }
1213
1214 static int
1215 ftsetouthdr(Serialport *p, uchar *b, int len)
1216 {
1217         if(p->s->outhdrsz != 0)
1218                 b[0] = FTOPORT | (FTOLENMSK & len);
1219         return p->s->outhdrsz;
1220 }
1221
1222 static int
1223 wait4data(Serialport *p, uchar *data, int count)
1224 {
1225         int d;
1226         Serial *ser;
1227
1228         ser = p->s;
1229
1230         qunlock(ser);
1231         d = sendul(p->w4data, 1);
1232         qlock(ser);
1233         if(d <= 0)
1234                 return -1;
1235         if(p->ndata >= count)
1236                 p->ndata -= count;
1237         else{
1238                 count = p->ndata;
1239                 p->ndata = 0;
1240         }
1241         memmove(data, p->data, count);
1242         if(p->ndata != 0)
1243                 memmove(p->data, p->data+count, p->ndata);
1244         recvul(p->gotdata);
1245         return count;
1246 }
1247
1248 static int
1249 wait4write(Serialport *p, uchar *data, int count)
1250 {
1251         int off, fd;
1252         uchar *b;
1253         Serial *ser;
1254
1255         ser = p->s;
1256
1257         b = emallocz(count+ser->outhdrsz, 1);
1258         off = ftsetouthdr(p, b, count);
1259         memmove(b+off, data, count);
1260
1261         fd = p->epout->dfd;
1262         qunlock(ser);
1263         count = write(fd, b, count+off);
1264         qlock(ser);
1265         free(b);
1266         return count;
1267 }
1268
1269 typedef struct Packser Packser;
1270 struct Packser{
1271         int     nb;
1272         uchar   b[Bufsiz];
1273 };
1274
1275 typedef struct Areader Areader;
1276 struct Areader{
1277         Serialport      *p;
1278         Channel *c;
1279 };
1280
1281 static void
1282 shutdownchan(Channel *c)
1283 {
1284         Packser *bp;
1285
1286         while((bp=nbrecvp(c)) != nil)
1287                 free(bp);
1288         chanfree(c);
1289 }
1290
1291 int
1292 cpdata(Serial *ser, Serialport *port, uchar *out, uchar *in, int sz)
1293 {
1294         int i, ncp, ntotcp, pksz;
1295
1296         pksz = ser->maxrtrans;
1297         ntotcp = 0;
1298
1299         for(i = 0; i < sz; i+= pksz){
1300                 ftuseinhdr(port, in + i);
1301                 if(sz - i > pksz)
1302                         ncp = pksz - ser->inhdrsz;
1303                 else
1304                         ncp = sz - i - ser->inhdrsz;
1305                 memmove(out, in + i + ser->inhdrsz, ncp);
1306                 out += ncp;
1307                 ntotcp += ncp;
1308         }
1309         return ntotcp;
1310 }
1311
1312 static void
1313 epreader(void *u)
1314 {
1315         int dfd, rcount, cl, ntries, recov;
1316         Areader *a;
1317         Channel *c;
1318         Packser *pk;
1319         Serial *ser;
1320         Serialport *p;
1321
1322         threadsetname("epreader proc");
1323         a = u;
1324         p = a->p;
1325         ser = p->s;
1326         c = a->c;
1327         free(a);
1328
1329         qlock(ser);     /* this makes the reader wait end of initialization too */
1330         dfd = p->epin->dfd;
1331         qunlock(ser);
1332
1333         ntries = 0;
1334         pk = nil;
1335         for(;;) {
1336                 if (pk == nil)
1337                         pk = emallocz(sizeof(Packser), 1);
1338 Eagain:
1339                 rcount = read(dfd, pk->b, sizeof pk->b);
1340                 if(serialdebug > 5)
1341                         dsprint(2, "%d %#ux%#ux ", rcount, p->data[0],
1342                                 p->data[1]);
1343
1344                 if(rcount < 0){
1345                         if(ntries++ > 100)
1346                                 break;
1347                         qlock(ser);
1348                         recov = serialrecover(ser, p, nil, "epreader: bulkin error");
1349                         qunlock(ser);
1350                         if(recov >= 0)
1351                                 goto Eagain;
1352                 }
1353                 if(rcount == 0)
1354                         continue;
1355                 if(rcount >= ser->inhdrsz){
1356                         rcount = cpdata(ser, p, pk->b, pk->b, rcount);
1357                         if(rcount != 0){
1358                                 pk->nb = rcount;
1359                                 cl = sendp(c, pk);
1360                                 if(cl < 0){
1361                                         /*
1362                                          * if it was a time-out, I don't want
1363                                          * to give back an error.
1364                                          */
1365                                         rcount = 0;
1366                                         break;
1367                                 }
1368                         }else
1369                                 free(pk);
1370                         qlock(ser);
1371                         ser->recover = 0;
1372                         qunlock(ser);
1373                         ntries = 0;
1374                         pk = nil;
1375                 }
1376         }
1377
1378         if(rcount < 0)
1379                 fprint(2, "%s: error reading %s: %r\n", argv0, p->name);
1380         free(pk);
1381         nbsendp(c, nil);
1382         if(p->w4data != nil)
1383                 chanclose(p->w4data);
1384         if(p->gotdata != nil)
1385                 chanclose(p->gotdata);
1386         devctl(ser->dev, "detach");
1387         closedev(ser->dev);
1388 }
1389
1390 static void
1391 statusreader(void *u)
1392 {
1393         Areader *a;
1394         Channel *c;
1395         Packser *pk;
1396         Serialport *p;
1397         Serial *ser;
1398         int cl;
1399
1400         p = u;
1401         ser = p->s;
1402         threadsetname("statusreader thread");
1403         /* big buffering, fewer bytes lost */
1404         c = chancreate(sizeof(Packser *), 128);
1405         a = emallocz(sizeof(Areader), 1);
1406         a->p = p;
1407         a->c = c;
1408         incref(ser->dev);
1409         proccreate(epreader, a, 16*1024);
1410
1411         while((pk = recvp(c)) != nil){
1412                 memmove(p->data, pk->b, pk->nb);
1413                 p->ndata = pk->nb;
1414                 free(pk);
1415                 /* consume it all */
1416                 while(p->ndata != 0){
1417                         cl = recvul(p->w4data);
1418                         if(cl < 0)
1419                                 break;
1420                         cl = sendul(p->gotdata, 1);
1421                         if(cl < 0)
1422                                 break;
1423                 }
1424         }
1425
1426         shutdownchan(c);
1427         devctl(ser->dev, "detach");
1428         closedev(ser->dev);
1429 }
1430
1431 static int
1432 ftreset(Serial *ser, Serialport *p)
1433 {
1434         int i;
1435
1436         if(p != nil){
1437                 ftdiwrite(p, FTRESETCTLVAL, 0, FTRESET);
1438                 return 0;
1439         }
1440         p = ser->p;
1441         for(i = 0; i < Maxifc; i++)
1442                 if(p[i].s != nil)
1443                         ftdiwrite(&p[i], FTRESETCTLVAL, 0, FTRESET);
1444         return 0;
1445 }
1446
1447 static int
1448 ftinit(Serialport *p)
1449 {
1450         Serial *ser;
1451         uint timerval;
1452         int res;
1453
1454         ser = p->s;
1455         if(p->isjtag){
1456                 res = ftdiwrite(p, FTSETFLOWCTRL, 0, FTDISABLEFLOWCTRL);
1457                 if(res < 0)
1458                         return -1;
1459                 res = ftdiread(p, FTSETLATENCYTIMER, 0, (uchar *)&timerval,
1460                         FTLATENCYTIMERSZ);
1461                 if(res < 0)
1462                         return -1;
1463                 dsprint(2, "serial: jtag latency timer is %d\n", timerval);
1464                 timerval = 2;
1465                 ftdiwrite(p, FTLATENCYDEFAULT, 0, FTSETLATENCYTIMER);
1466                 res = ftdiread(p, FTSETLATENCYTIMER, 0, (uchar *)&timerval,
1467                         FTLATENCYTIMERSZ);
1468                 if(res < 0)
1469                         return -1;
1470
1471                 dsprint(2, "serial: jtag latency timer set to %d\n", timerval);
1472                 /* 0xb is the mask for lines. plug dependant? */
1473                 ftdiwrite(p, BMMPSSE|0x0b, 0, FTSETBITMODE);
1474         }
1475         incref(ser->dev);
1476         proccreate(statusreader, p, 8*1024);
1477         return 0;
1478 }
1479
1480 static int
1481 ftsetbreak(Serialport *p, int val)
1482 {
1483         return ftdiwrite(p, (val != 0? FTSETBREAK: 0), 0, FTSETDATA);
1484 }
1485
1486 static int
1487 ftclearpipes(Serialport *p)
1488 {
1489         /* maybe can be done in one... */
1490         ftdiwrite(p, FTRESETCTLVALPURGETX, 0, FTRESET);
1491         ftdiwrite(p, FTRESETCTLVALPURGERX, 0, FTRESET);
1492         return 0;
1493 }
1494
1495 static int
1496 setctlline(Serialport *p, uchar val)
1497 {
1498         return ftdiwrite(p, val | (val << 8), 0, FTSETMODEMCTRL);
1499 }
1500
1501 static void
1502 updatectlst(Serialport *p, int val)
1503 {
1504         if(p->rts)
1505                 p->ctlstate |= val;
1506         else
1507                 p->ctlstate &= ~val;
1508 }
1509
1510 static int
1511 setctl(Serialport *p)
1512 {
1513         int res;
1514         Serial *ser;
1515
1516         ser = p->s;
1517
1518         if(ser->dev->usb->vid == FTVid && ser->dev->usb->did ==  FTHETIRA1Did){
1519                 fprint(2, "serial: cannot set lines for this device\n");
1520                 updatectlst(p, CtlRTS|CtlDTR);
1521                 p->rts = p->dtr = 1;
1522                 return -1;
1523         }
1524
1525         /* NB: you can not set DTR and RTS with one control message */
1526         updatectlst(p, CtlRTS);
1527         res = setctlline(p, (CtlRTS<<8)|p->ctlstate);
1528         if(res < 0)
1529                 return res;
1530
1531         updatectlst(p, CtlDTR);
1532         res = setctlline(p, (CtlDTR<<8)|p->ctlstate);
1533         if(res < 0)
1534                 return res;
1535
1536         return 0;
1537 }
1538
1539 static int
1540 ftsendlines(Serialport *p)
1541 {
1542         int res;
1543
1544         dsprint(2, "serial: sendlines: %#2.2x\n", p->ctlstate);
1545         res = setctl(p);
1546         dsprint(2, "serial: sendlines res: %d\n", res);
1547         return 0;
1548 }
1549
1550 static int
1551 ftseteps(Serialport *p)
1552 {
1553         char *s;
1554         Serial *ser;
1555
1556         ser = p->s;
1557
1558         s = smprint("maxpkt %d", ser->maxrtrans);
1559         devctl(p->epin, s);
1560         free(s);
1561
1562         s = smprint("maxpkt %d", ser->maxwtrans);
1563         devctl(p->epout, s);
1564         free(s);
1565         return 0;
1566 }
1567
1568 static Serialops ftops = {
1569         .init           = ftinit,
1570         .seteps         = ftseteps,
1571         .setparam       = ftsetparam,
1572         .clearpipes     = ftclearpipes,
1573         .reset          = ftreset,
1574         .sendlines      = ftsendlines,
1575         .modemctl       = ftmodemctl,
1576         .setbreak       = ftsetbreak,
1577         .wait4data      = wait4data,
1578         .wait4write     = wait4write,
1579 };