xref: /plan9/sys/src/cmd/usb/serial/ftdi.c (revision 6bbfed0d85c6d7248503ef0614d0f1e40438b735)
1 /* Future Technology Devices International serial ports */
2 #include <u.h>
3 #include <libc.h>
4 #include <thread.h>
5 #include "usb.h"
6 #include "usbfs.h"
7 #include "serial.h"
8 #include "ftdi.h"
9 
10 /*
11  * BUG: This keeps growing, there has to be a better way, but without
12  * devices to try it...  We can probably simply look for FTDI in the
13  * string, or use regular expressions somehow.
14  */
15 Cinfo ftinfo[] = {
16 	{ FTVid, FTACTZWAVEDid },
17 	{ FTSheevaVid, FTSheevaDid },
18 	{ FTVid, FTOpenRDUltDid},
19 	{ FTVid, FTIRTRANSDid },
20 	{ FTVid, FTIPLUSDid },
21 	{ FTVid, FTSIODid },
22 	{ FTVid, FT8U232AMDid },
23 	{ FTVid, FT8U232AMALTDid },
24 	{ FTVid, FT8U2232CDid },
25 	{ FTVid, FTRELAISDid },
26 	{ INTERBIOMVid, INTERBIOMIOBRDDid },
27 	{ INTERBIOMVid, INTERBIOMMINIIOBRDDid },
28 	{ FTVid, FTXF632Did },
29 	{ FTVid, FTXF634Did },
30 	{ FTVid, FTXF547Did },
31 	{ FTVid, FTXF633Did },
32 	{ FTVid, FTXF631Did },
33 	{ FTVid, FTXF635Did },
34 	{ FTVid, FTXF640Did },
35 	{ FTVid, FTXF642Did },
36 	{ FTVid, FTDSS20Did },
37 	{ FTNFRICVid, FTNFRICDid },
38 	{ FTVid, FTVNHCPCUSBDDid },
39 	{ FTVid, FTMTXORB0Did },
40 	{ FTVid, FTMTXORB1Did },
41 	{ FTVid, FTMTXORB2Did },
42 	{ FTVid, FTMTXORB3Did },
43 	{ FTVid, FTMTXORB4Did },
44 	{ FTVid, FTMTXORB5Did },
45 	{ FTVid, FTMTXORB6Did },
46 	{ FTVid, FTPERLEULTRAPORTDid },
47 	{ FTVid, FTPIEGROUPDid },
48 	{ SEALEVELVid, SEALEVEL2101Did },
49 	{ SEALEVELVid, SEALEVEL2102Did },
50 	{ SEALEVELVid, SEALEVEL2103Did },
51 	{ SEALEVELVid, SEALEVEL2104Did },
52 	{ SEALEVELVid, SEALEVEL22011Did },
53 	{ SEALEVELVid, SEALEVEL22012Did },
54 	{ SEALEVELVid, SEALEVEL22021Did },
55 	{ SEALEVELVid, SEALEVEL22022Did },
56 	{ SEALEVELVid, SEALEVEL22031Did },
57 	{ SEALEVELVid, SEALEVEL22032Did },
58 	{ SEALEVELVid, SEALEVEL24011Did },
59 	{ SEALEVELVid, SEALEVEL24012Did },
60 	{ SEALEVELVid, SEALEVEL24013Did },
61 	{ SEALEVELVid, SEALEVEL24014Did },
62 	{ SEALEVELVid, SEALEVEL24021Did },
63 	{ SEALEVELVid, SEALEVEL24022Did },
64 	{ SEALEVELVid, SEALEVEL24023Did },
65 	{ SEALEVELVid, SEALEVEL24024Did },
66 	{ SEALEVELVid, SEALEVEL24031Did },
67 	{ SEALEVELVid, SEALEVEL24032Did },
68 	{ SEALEVELVid, SEALEVEL24033Did },
69 	{ SEALEVELVid, SEALEVEL24034Did },
70 	{ SEALEVELVid, SEALEVEL28011Did },
71 	{ SEALEVELVid, SEALEVEL28012Did },
72 	{ SEALEVELVid, SEALEVEL28013Did },
73 	{ SEALEVELVid, SEALEVEL28014Did },
74 	{ SEALEVELVid, SEALEVEL28015Did },
75 	{ SEALEVELVid, SEALEVEL28016Did },
76 	{ SEALEVELVid, SEALEVEL28017Did },
77 	{ SEALEVELVid, SEALEVEL28018Did },
78 	{ SEALEVELVid, SEALEVEL28021Did },
79 	{ SEALEVELVid, SEALEVEL28022Did },
80 	{ SEALEVELVid, SEALEVEL28023Did },
81 	{ SEALEVELVid, SEALEVEL28024Did },
82 	{ SEALEVELVid, SEALEVEL28025Did },
83 	{ SEALEVELVid, SEALEVEL28026Did },
84 	{ SEALEVELVid, SEALEVEL28027Did },
85 	{ SEALEVELVid, SEALEVEL28028Did },
86 	{ SEALEVELVid, SEALEVEL28031Did },
87 	{ SEALEVELVid, SEALEVEL28032Did },
88 	{ SEALEVELVid, SEALEVEL28033Did },
89 	{ SEALEVELVid, SEALEVEL28034Did },
90 	{ SEALEVELVid, SEALEVEL28035Did },
91 	{ SEALEVELVid, SEALEVEL28036Did },
92 	{ SEALEVELVid, SEALEVEL28037Did },
93 	{ SEALEVELVid, SEALEVEL28038Did },
94 	{ IDTECHVid, IDTECHIDT1221UDid },
95 	{ OCTVid, OCTUS101Did },
96 	{ FTVid, FTHETIRA1Did }, /* special quirk div = 240 baud = B38400 rtscts = 1 */
97 	{ FTVid, FTUSBUIRTDid }, /* special quirk div = 77, baud = B38400 */
98 	{ FTVid, PROTEGOSPECIAL1 },
99 	{ FTVid, PROTEGOR2X0 },
100 	{ FTVid, PROTEGOSPECIAL3 },
101 	{ FTVid, PROTEGOSPECIAL4 },
102 	{ FTVid, FTGUDEADSE808Did },
103 	{ FTVid, FTGUDEADSE809Did },
104 	{ FTVid, FTGUDEADSE80ADid },
105 	{ FTVid, FTGUDEADSE80BDid },
106 	{ FTVid, FTGUDEADSE80CDid },
107 	{ FTVid, FTGUDEADSE80DDid },
108 	{ FTVid, FTGUDEADSE80EDid },
109 	{ FTVid, FTGUDEADSE80FDid },
110 	{ FTVid, FTGUDEADSE888Did },
111 	{ FTVid, FTGUDEADSE889Did },
112 	{ FTVid, FTGUDEADSE88ADid },
113 	{ FTVid, FTGUDEADSE88BDid },
114 	{ FTVid, FTGUDEADSE88CDid },
115 	{ FTVid, FTGUDEADSE88DDid },
116 	{ FTVid, FTGUDEADSE88EDid },
117 	{ FTVid, FTGUDEADSE88FDid },
118 	{ FTVid, FTELVUO100Did },
119 	{ FTVid, FTELVUM100Did },
120 	{ FTVid, FTELVUR100Did },
121 	{ FTVid, FTELVALC8500Did },
122 	{ FTVid, FTPYRAMIDDid },
123 	{ FTVid, FTELVFHZ1000PCDid },
124 	{ FTVid, FTELVCLI7000Did },
125 	{ FTVid, FTELVPPS7330Did },
126 	{ FTVid, FTELVTFM100Did },
127 	{ FTVid, FTELVUDF77Did },
128 	{ FTVid, FTELVUIO88Did },
129 	{ FTVid, FTELVUAD8Did },
130 	{ FTVid, FTELVUDA7Did },
131 	{ FTVid, FTELVUSI2Did },
132 	{ FTVid, FTELVT1100Did },
133 	{ FTVid, FTELVPCD200Did },
134 	{ FTVid, FTELVULA200Did },
135 	{ FTVid, FTELVCSI8Did },
136 	{ FTVid, FTELVEM1000DLDid },
137 	{ FTVid, FTELVPCK100Did },
138 	{ FTVid, FTELVRFP500Did },
139 	{ FTVid, FTELVFS20SIGDid },
140 	{ FTVid, FTELVWS300PCDid },
141 	{ FTVid, FTELVFHZ1300PCDid },
142 	{ FTVid, FTELVWS500Did },
143 	{ FTVid, LINXSDMUSBQSSDid },
144 	{ FTVid, LINXMASTERDEVEL2Did },
145 	{ FTVid, LINXFUTURE0Did },
146 	{ FTVid, LINXFUTURE1Did },
147 	{ FTVid, LINXFUTURE2Did },
148 	{ FTVid, FTCCSICDU200Did },
149 	{ FTVid, FTCCSICDU401Did },
150 	{ FTVid, INSIDEACCESSO },
151 	{ INTREDidVid, INTREDidVALUECANDid },
152 	{ INTREDidVid, INTREDidNEOVIDid },
153 	{ FALCOMVid, FALCOMTWISTDid },
154 	{ FALCOMVid, FALCOMSAMBADid },
155 	{ FTVid, FTSUUNTOSPORTSDid },
156 	{ FTVid, FTRMCANVIEWDid },
157 	{ BANDBVid, BANDBUSOTL4Did },
158 	{ BANDBVid, BANDBUSTL4Did },
159 	{ BANDBVid, BANDBUSO9ML2Did },
160 	{ FTVid, EVERECOPROCDSDid },
161 	{ FTVid, FT4NGALAXYDE0Did },
162 	{ FTVid, FT4NGALAXYDE1Did },
163 	{ FTVid, FT4NGALAXYDE2Did },
164 	{ FTVid, XSENSCONVERTER0Did },
165 	{ FTVid, XSENSCONVERTER1Did },
166 	{ FTVid, XSENSCONVERTER2Did },
167 	{ FTVid, XSENSCONVERTER3Did },
168 	{ FTVid, XSENSCONVERTER4Did },
169 	{ FTVid, XSENSCONVERTER5Did },
170 	{ FTVid, XSENSCONVERTER6Did },
171 	{ FTVid, XSENSCONVERTER7Did },
172 	{ MOBILITYVid, MOBILITYUSBSERIALDid },
173 	{ FTVid, FTACTIVEROBOTSDid },
174 	{ FTVid, FTMHAMKWDid },
175 	{ FTVid, FTMHAMYSDid },
176 	{ FTVid, FTMHAMY6Did },
177 	{ FTVid, FTMHAMY8Did },
178 	{ FTVid, FTMHAMICDid },
179 	{ FTVid, FTMHAMDB9Did },
180 	{ FTVid, FTMHAMRS232Did },
181 	{ FTVid, FTMHAMY9Did },
182 	{ FTVid, FTTERATRONIKVCPDid },
183 	{ FTVid, FTTERATRONIKD2XXDid },
184 	{ EVOLUTIONVid, EVOLUTIONER1Did },
185 	{ FTVid, FTARTEMISDid },
186 	{ FTVid, FTATIKATK16Did },
187 	{ FTVid, FTATIKATK16CDid },
188 	{ FTVid, FTATIKATK16HRDid },
189 	{ FTVid, FTATIKATK16HRCDid },
190 	{ KOBILVid, KOBILCONVB1Did },
191 	{ KOBILVid, KOBILCONVKAANDid },
192 	{ POSIFLEXVid, POSIFLEXPP7000Did },
193 	{ FTVid, FTTTUSBDid },
194 	{ FTVid, FTECLOCOM1WIREDid },
195 	{ FTVid, FTWESTREXMODEL777Did },
196 	{ FTVid, FTWESTREXMODEL8900FDid },
197 	{ FTVid, FTPCDJDAC2Did },
198 	{ FTVid, FTRRCIRKITSLOCOBUFFERDid },
199 	{ FTVid, FTASKRDR400Did },
200 	{ ICOMID1Vid, ICOMID1Did },
201 	{ PAPOUCHVid, PAPOUCHTMUDid },
202 	{ FTVid, FTACGHFDUALDid },
203 	{ FT8U232AMDid, FT4232HDid },
204 	{ FTVid, AMONKEYDid },
205 	{ 0,	0 },
206 };
207 
208 enum {
209 	Packsz		= 64,		/* default size */
210 	Maxpacksz	= 512,
211 	Bufsiz		= 4 * 1024,
212 };
213 
214 static int
ftdiread(Serialport * p,int index,int req,uchar * buf,int len)215 ftdiread(Serialport *p, int index, int req, uchar *buf, int len)
216 {
217 	int res;
218 	Serial *ser;
219 
220 	ser = p->s;
221 
222 	if(req != FTGETE2READ)
223 		index |= p->interfc + 1;
224 	dsprint(2, "serial: ftdiread %#p [%d] req: %#x val: %#x idx:%d buf:%p len:%d\n",
225 		p, p->interfc, req, 0, index, buf, len);
226 	res = usbcmd(ser->dev,  Rd2h | Rftdireq | Rdev, req, 0, index, buf, len);
227 	dsprint(2, "serial: ftdiread res:%d\n", res);
228 	return res;
229 }
230 
231 static int
ftdiwrite(Serialport * p,int val,int index,int req)232 ftdiwrite(Serialport *p, int val, int index, int req)
233 {
234 	int res;
235 	Serial *ser;
236 
237 	ser = p->s;
238 
239 	if(req != FTGETE2READ || req != FTSETE2ERASE || req != FTSETBAUDRATE)
240 		index |= p->interfc + 1;
241 	dsprint(2, "serial: ftdiwrite %#p [%d] req: %#x val: %#x idx:%d\n",
242 		p, p->interfc, req, val, index);
243 	res = usbcmd(ser->dev, Rh2d | Rftdireq | Rdev, req, val, index, nil, 0);
244 	dsprint(2, "serial: ftdiwrite res:%d\n", res);
245 	return res;
246 }
247 
248 static int
ftmodemctl(Serialport * p,int set)249 ftmodemctl(Serialport *p, int set)
250 {
251 	if(set == 0){
252 		p->mctl = 0;
253 		ftdiwrite(p, 0, 0, FTSETMODEMCTRL);
254 		return 0;
255 	}
256 	p->mctl = 1;
257 	ftdiwrite(p, 0, FTRTSCTSHS, FTSETFLOWCTRL);
258 	return 0;
259 }
260 
261 static ushort
ft232ambaudbase2div(int baud,int base)262 ft232ambaudbase2div(int baud, int base)
263 {
264 	int divisor3;
265 	ushort divisor;
266 
267 	divisor3 = (base / 2) / baud;
268 	if((divisor3 & 7) == 7)
269 		divisor3++;			/* round x.7/8 up to x+1 */
270 	divisor = divisor3 >> 3;
271 	divisor3 &= 7;
272 
273 	if(divisor3 == 1)
274 		divisor |= 0xc000;		/*	0.125 */
275 	else if(divisor3 >= 4)
276 		divisor |= 0x4000;		/*	0.5	*/
277 	else if(divisor3 != 0)
278 		divisor |= 0x8000;		/*	0.25	*/
279 	if( divisor == 1)
280 		divisor = 0;		/* special case for maximum baud rate */
281 	return divisor;
282 }
283 
284 enum{
285 	ClockNew	= 48000000,
286 	ClockOld	= 12000000 / 16,
287 	HetiraDiv	= 240,
288 	UirtDiv		= 77,
289 };
290 
291 static ushort
ft232ambaud2div(int baud)292 ft232ambaud2div(int baud)
293 {
294 	return ft232ambaudbase2div(baud, ClockNew);
295 }
296 
297 static ulong divfrac[8] = { 0, 3, 2, 4, 1, 5, 6, 7};
298 
299 static ulong
ft232bmbaudbase2div(int baud,int base)300 ft232bmbaudbase2div(int baud, int base)
301 {
302 	int divisor3;
303 	u32int divisor;
304 
305 	divisor3 = (base / 2) / baud;
306 	divisor = divisor3 >> 3 | divfrac[divisor3 & 7] << 14;
307 
308 	/* Deal with special cases for highest baud rates. */
309 	if( divisor == 1)
310 		divisor = 0;			/* 1.0 */
311 	else if( divisor == 0x4001)
312 		divisor = 1;			/* 1.5 */
313 	return divisor;
314 }
315 
316 static ulong
ft232bmbaud2div(int baud)317 ft232bmbaud2div (int baud)
318 {
319 	return ft232bmbaudbase2div (baud, ClockNew);
320 }
321 
322 static int
customdiv(Serial * ser)323 customdiv(Serial *ser)
324 {
325 	if(ser->dev->usb->vid == FTVid && ser->dev->usb->did == FTHETIRA1Did)
326 		return HetiraDiv;
327 	else if(ser->dev->usb->vid == FTVid && ser->dev->usb->did == FTUSBUIRTDid)
328 		return UirtDiv;
329 
330 	fprint(2, "serial: weird custom divisor\n");
331 	return 0;		/* shouldn't happen, break as much as I can */
332 }
333 
334 static ulong
ftbaudcalcdiv(Serial * ser,int baud)335 ftbaudcalcdiv(Serial *ser, int baud)
336 {
337 	int cusdiv;
338 	ulong divval;
339 
340 	if(baud == 38400 && (cusdiv = customdiv(ser)) != 0)
341 		baud = ser->baudbase / cusdiv;
342 
343 	if(baud == 0)
344 		baud = 9600;
345 
346 	switch(ser->type) {
347 	case SIO:
348 		switch(baud) {
349 		case 300:
350 			divval = FTb300;
351 			break;
352 		case 600:
353 			divval = FTb600;
354 			break;
355 		case 1200:
356 			divval = FTb1200;
357 			break;
358 		case 2400:
359 			divval = FTb2400;
360 			break;
361 		case 4800:
362 			divval = FTb4800;
363 			break;
364 		case 9600:
365 			divval = FTb9600;
366 			break;
367 		case 19200:
368 			divval = FTb19200;
369 			break;
370 		case 38400:
371 			divval = FTb38400;
372 			break;
373 		case 57600:
374 			divval = FTb57600;
375 			break;
376 		case 115200:
377 			divval = FTb115200;
378 			break;
379 		default:
380 			divval = FTb9600;
381 			break;
382 		}
383 		break;
384 	case FT8U232AM:
385 		if(baud <= 3000000)
386 			divval = ft232ambaud2div(baud);
387 		else
388 			divval = ft232ambaud2div(9600);
389 		break;
390 	case FT232BM:
391 	case FT2232C:
392 	case FTKINDR:
393 	case FT2232H:
394 	case FT4232H:
395 		if(baud <= 3000000)
396 			divval = ft232bmbaud2div(baud);
397 		else
398 			divval = ft232bmbaud2div(9600);
399 		break;
400 	default:
401 		divval = ft232bmbaud2div(9600);
402 		break;
403 	}
404 	return divval;
405 }
406 
407 static int
ftsetparam(Serialport * p)408 ftsetparam(Serialport *p)
409 {
410 	int res;
411 	ushort val;
412 	ulong bauddiv;
413 
414 	val = 0;
415 	if(p->stop == 1)
416 		val |= FTSETDATASTOPBITS1;
417 	else if(p->stop == 2)
418 		val |= FTSETDATASTOPBITS2;
419 	else if(p->stop == 15)
420 		val |= FTSETDATASTOPBITS15;
421 	switch(p->parity){
422 	case 0:
423 		val |= FTSETDATAParNONE;
424 		break;
425 	case 1:
426 		val |= FTSETDATAParODD;
427 		break;
428 	case 2:
429 		val |= FTSETDATAParEVEN;
430 		break;
431 	case 3:
432 		val |= FTSETDATAParMARK;
433 		break;
434 	case 4:
435 		val |= FTSETDATAParSPACE;
436 		break;
437 	};
438 
439 	dsprint(2, "serial: setparam\n");
440 
441 	res = ftdiwrite(p, val, 0, FTSETDATA);
442 	if(res < 0)
443 		return res;
444 
445 	res = ftmodemctl(p, p->mctl);
446 	if(res < 0)
447 		return res;
448 
449 	bauddiv = ftbaudcalcdiv(p->s, p->baud);
450 	res = ftdiwrite(p, bauddiv, (bauddiv>>16) & 1, FTSETBAUDRATE);
451 
452 	dsprint(2, "serial: setparam res: %d\n", res);
453 	return res;
454 }
455 
456 static int
hasjtag(Usbdev * udev)457 hasjtag(Usbdev *udev)
458 {
459 	/* no string, for now, by default we detect no jtag */
460 	if(udev->product != nil && cistrstr(udev->product, "jtag") != nil)
461 		return 1;
462 	return 0;
463 }
464 
465 /* ser locked */
466 static void
ftgettype(Serial * ser)467 ftgettype(Serial *ser)
468 {
469 	int i, outhdrsz, dno, pksz;
470 	ulong baudbase;
471 	Conf *cnf;
472 
473 	pksz = Packsz;
474 	/* Assume it is not the original SIO device for now. */
475 	baudbase = ClockNew / 2;
476 	outhdrsz = 0;
477 	dno = ser->dev->usb->dno;
478 	cnf = ser->dev->usb->conf[0];
479 	ser->nifcs = 0;
480 	for(i = 0; i < Niface; i++)
481 		if(cnf->iface[i] != nil)
482 			ser->nifcs++;
483 	if(ser->nifcs > 1) {
484 		/*
485 		 * Multiple interfaces.  default assume FT2232C,
486 		 */
487 		if(dno == 0x500)
488 			ser->type = FT2232C;
489 		else if(dno == 0x600)
490 			ser->type = FTKINDR;
491 		else if(dno == 0x700){
492 			ser->type = FT2232H;
493 			pksz = Maxpacksz;
494 		} else if(dno == 0x800){
495 			ser->type = FT4232H;
496 			pksz = Maxpacksz;
497 		} else
498 			ser->type = FT2232C;
499 
500 		if(hasjtag(ser->dev->usb))
501 			ser->jtag = 0;
502 
503 		/*
504 		 * BM-type devices have a bug where dno gets set
505 		 * to 0x200 when serial is 0.
506 		 */
507 		if(dno < 0x500)
508 			fprint(2, "serial: warning: dno %d too low for "
509 				"multi-interface device\n", dno);
510 	} else if(dno < 0x200) {
511 		/* Old device.  Assume it is the original SIO. */
512 		ser->type = SIO;
513 		baudbase = ClockOld/16;
514 		outhdrsz = 1;
515 	} else if(dno < 0x400)
516 		/*
517 		 * Assume its an FT8U232AM (or FT8U245AM)
518 		 * (It might be a BM because of the iSerialNumber bug,
519 		 * but it will still work as an AM device.)
520 		 */
521 		ser->type = FT8U232AM;
522 	else			/* Assume it is an FT232BM (or FT245BM) */
523 		ser->type = FT232BM;
524 
525 	ser->maxrtrans = ser->maxwtrans = pksz;
526 	ser->baudbase = baudbase;
527 	ser->outhdrsz = outhdrsz;
528 	ser->inhdrsz = 2;
529 
530 	dsprint (2, "serial: detected type: %#x\n", ser->type);
531 }
532 
533 int
ftmatch(Serial * ser,char * info)534 ftmatch(Serial *ser, char *info)
535 {
536 	Cinfo *ip;
537 	char buf[50];
538 
539 	for(ip = ftinfo; ip->vid != 0; ip++){
540 		snprint(buf, sizeof buf, "vid %#06x did %#06x", ip->vid, ip->did);
541 		dsprint(2, "serial: %s %s\n", buf, info);
542 		if(strstr(info, buf) != nil){
543 			if(ser != nil){
544 				qlock(ser);
545 				ftgettype(ser);
546 				qunlock(ser);
547 			}
548 			return 0;
549 		}
550 	}
551 	return -1;
552 }
553 
554 static int
ftuseinhdr(Serialport * p,uchar * b)555 ftuseinhdr(Serialport *p, uchar *b)
556 {
557 	if(b[0] & FTICTS)
558 		p->cts = 1;
559 	else
560 		p->cts = 0;
561 	if(b[0] & FTIDSR)
562 		p->dsr = 1;
563 	else
564 		p->dsr = 0;
565 	if(b[0] & FTIRI)
566 		p->ring = 1;
567 	else
568 		p->ring = 0;
569 	if(b[0] & FTIRLSD)
570 		p->rlsd = 1;
571 	else
572 		p->rlsd = 0;
573 
574 	if(b[1] & FTIOE)
575 		p->novererr++;
576 	if(b[1] & FTIPE)
577 		p->nparityerr++;
578 	if(b[1] & FTIFE)
579 		p->nframeerr++;
580 	if(b[1] & FTIBI)
581 		p->nbreakerr++;
582 	return 0;
583 }
584 
585 static int
ftsetouthdr(Serialport * p,uchar * b,int len)586 ftsetouthdr(Serialport *p, uchar *b, int len)
587 {
588 	if(p->s->outhdrsz != 0)
589 		b[0] = FTOPORT | (FTOLENMSK & len);
590 	return p->s->outhdrsz;
591 }
592 
593 static int
wait4data(Serialport * p,uchar * data,int count)594 wait4data(Serialport *p, uchar *data, int count)
595 {
596 	int d;
597 	Serial *ser;
598 
599 	ser = p->s;
600 
601 	qunlock(ser);
602 	d = sendul(p->w4data, 1);
603 	qlock(ser);
604 	if(d <= 0)
605 		return -1;
606 	if(p->ndata >= count)
607 		p->ndata -= count;
608 	else{
609 		count = p->ndata;
610 		p->ndata = 0;
611 	}
612 	assert(count >= 0);
613 	assert(p->ndata >= 0);
614 	memmove(data, p->data, count);
615 	if(p->ndata != 0)
616 		memmove(p->data, p->data+count, p->ndata);
617 
618 	recvul(p->gotdata);
619 	return count;
620 }
621 
622 static int
wait4write(Serialport * p,uchar * data,int count)623 wait4write(Serialport *p, uchar *data, int count)
624 {
625 	int off, fd;
626 	uchar *b;
627 	Serial *ser;
628 
629 	ser = p->s;
630 
631 	b = emallocz(count+ser->outhdrsz, 1);
632 	off = ftsetouthdr(p, b, count);
633 	memmove(b+off, data, count);
634 
635 	fd = p->epout->dfd;
636 	qunlock(ser);
637 	count = write(fd, b, count+off);
638 	qlock(ser);
639 	free(b);
640 	return count;
641 }
642 
643 typedef struct Packser Packser;
644 struct Packser{
645 	int	nb;
646 	uchar	b[Bufsiz];
647 };
648 
649 typedef struct Areader Areader;
650 struct Areader{
651 	Serialport	*p;
652 	Channel	*c;
653 };
654 
655 static void
shutdownchan(Channel * c)656 shutdownchan(Channel *c)
657 {
658 	Packser *bp;
659 
660 	while((bp=nbrecvp(c)) != nil)
661 		free(bp);
662 	chanfree(c);
663 }
664 
665 int
cpdata(Serial * ser,Serialport * port,uchar * out,uchar * in,int sz)666 cpdata(Serial *ser, Serialport *port, uchar *out, uchar *in, int sz)
667 {
668 	int i, ncp, ntotcp, pksz;
669 
670 	pksz = ser->maxrtrans;
671 	ntotcp = 0;
672 
673 	for(i = 0; i < sz; i+= pksz){
674 		ftuseinhdr(port, in + i);
675 		if(sz - i > pksz)
676 			ncp = pksz - ser->inhdrsz;
677 		else
678 			ncp = sz - i - ser->inhdrsz;
679 		memmove(out, in + i + ser->inhdrsz, ncp);
680 		out += ncp;
681 		ntotcp += ncp;
682 	}
683 	return ntotcp;
684 }
685 
686 static void
epreader(void * u)687 epreader(void *u)
688 {
689 	int dfd, rcount, cl, ntries, recov;
690 	char err[40];
691 	Areader *a;
692 	Channel *c;
693 	Packser *pk;
694 	Serial *ser;
695 	Serialport *p;
696 
697 	threadsetname("epreader proc");
698 	a = u;
699 	p = a->p;
700 	ser = p->s;
701 	c = a->c;
702 	free(a);
703 
704 	qlock(ser);	/* this makes the reader wait end of initialization too */
705 	dfd = p->epin->dfd;
706 	qunlock(ser);
707 
708 	ntries = 0;
709 	pk = nil;
710 	do {
711 		if (pk == nil)
712 			pk = emallocz(sizeof(Packser), 1);
713 Eagain:
714 		rcount = read(dfd, pk->b, sizeof pk->b);
715 		if(serialdebug > 5)
716 			dsprint(2, "%d %#ux%#ux ", rcount, p->data[0],
717 				p->data[1]);
718 
719 		if(rcount < 0){
720 			if(ntries++ > 100)
721 				break;
722 			qlock(ser);
723 			recov = serialrecover(ser, p, nil, "epreader: bulkin error");
724 			qunlock(ser);
725 			if(recov >= 0)
726 				goto Eagain;
727 		}
728 		if(rcount == 0)
729 			continue;
730 		if(rcount >= ser->inhdrsz){
731 			rcount = cpdata(ser, p, pk->b, pk->b, rcount);
732 			if(rcount != 0){
733 				pk->nb = rcount;
734 				cl = sendp(c, pk);
735 				if(cl < 0){
736 					/*
737 					 * if it was a time-out, I don't want
738 					 * to give back an error.
739 					 */
740 					rcount = 0;
741 					break;
742 				}
743 			}else
744 				free(pk);
745 			qlock(ser);
746 			ser->recover = 0;
747 			qunlock(ser);
748 			ntries = 0;
749 			pk = nil;
750 		}
751 	} while(rcount >= 0 || (rcount < 0 && strstr(err, "timed out") != nil));
752 
753 	if(rcount < 0)
754 		fprint(2, "%s: error reading %s: %r\n", argv0, p->fs.name);
755 	free(pk);
756 	nbsendp(c, nil);
757 	if(p->w4data != nil)
758 		chanclose(p->w4data);
759 	if(p->gotdata != nil)
760 		chanclose(p->gotdata);
761 	devctl(ser->dev, "detach");
762 	closedev(ser->dev);
763 	usbfsdel(&p->fs);
764 }
765 
766 static void
statusreader(void * u)767 statusreader(void *u)
768 {
769 	Areader *a;
770 	Channel *c;
771 	Packser *pk;
772 	Serialport *p;
773 	Serial *ser;
774 	int cl;
775 
776 	p = u;
777 	ser = p->s;
778 	threadsetname("statusreader thread");
779 	/* big buffering, fewer bytes lost */
780 	c = chancreate(sizeof(Packser *), 128);
781 	a = emallocz(sizeof(Areader), 1);
782 	a->p = p;
783 	a->c = c;
784 	incref(ser->dev);
785 	proccreate(epreader, a, 16*1024);
786 
787 	while((pk = recvp(c)) != nil){
788 		memmove(p->data, pk->b, pk->nb);
789 		p->ndata = pk->nb;
790 		free(pk);
791 		dsprint(2, "serial %p: status reader %d \n", p, p->ndata);
792 		/* consume it all */
793 		while(p->ndata != 0){
794 			dsprint(2, "serial %p: status reader to consume: %d\n",
795 				p, p->ndata);
796 			cl = recvul(p->w4data);
797 			if(cl  < 0)
798 				break;
799 			cl = sendul(p->gotdata, 1);
800 			if(cl  < 0)
801 				break;
802 		}
803 	}
804 
805 	shutdownchan(c);
806 	devctl(ser->dev, "detach");
807 	closedev(ser->dev);
808 	usbfsdel(&p->fs);
809 }
810 
811 static int
ftreset(Serial * ser,Serialport * p)812 ftreset(Serial *ser, Serialport *p)
813 {
814 	int i;
815 
816 	if(p != nil){
817 		ftdiwrite(p, FTRESETCTLVAL, 0, FTRESET);
818 		return 0;
819 	}
820 	p = ser->p;
821 	for(i = 0; i < Maxifc; i++)
822 		if(p[i].s != nil)
823 			ftdiwrite(&p[i], FTRESETCTLVAL, 0, FTRESET);
824 	return 0;
825 }
826 
827 static int
ftinit(Serialport * p)828 ftinit(Serialport *p)
829 {
830 	Serial *ser;
831 	uint timerval;
832 	int res;
833 
834 	ser = p->s;
835 	if(p->isjtag){
836 		res = ftdiwrite(p, FTSETFLOWCTRL, 0, FTDISABLEFLOWCTRL);
837 		if(res < 0)
838 			return -1;
839 		res = ftdiread(p, FTSETLATENCYTIMER, 0, (uchar *)&timerval,
840 			FTLATENCYTIMERSZ);
841 		if(res < 0)
842 			return -1;
843 		dsprint(2, "serial: jtag latency timer is %d\n", timerval);
844 		timerval = 2;
845 		ftdiwrite(p, FTLATENCYDEFAULT, 0, FTSETLATENCYTIMER);
846 		res = ftdiread(p, FTSETLATENCYTIMER, 0, (uchar *)&timerval,
847 			FTLATENCYTIMERSZ);
848 		if(res < 0)
849 			return -1;
850 
851 		dsprint(2, "serial: jtag latency timer set to %d\n", timerval);
852 		/* may be unnecessary */
853 		devctl(p->epin,  "timeout 5000");
854 		devctl(p->epout, "timeout 5000");
855 		/* 0xb is the mask for lines. plug dependant? */
856 		ftdiwrite(p, BMMPSSE|0x0b, 0, FTSETBITMODE);
857 	}
858 	incref(ser->dev);
859 	threadcreate(statusreader, p, 8*1024);
860 	return 0;
861 }
862 
863 static int
ftsetbreak(Serialport * p,int val)864 ftsetbreak(Serialport *p, int val)
865 {
866 	return ftdiwrite(p, (val != 0? FTSETBREAK: 0), 0, FTSETDATA);
867 }
868 
869 static int
ftclearpipes(Serialport * p)870 ftclearpipes(Serialport *p)
871 {
872 	/* maybe can be done in one... */
873 	ftdiwrite(p, FTRESETCTLVALPURGETX, 0, FTRESET);
874 	ftdiwrite(p, FTRESETCTLVALPURGERX, 0, FTRESET);
875 	return 0;
876 }
877 
878 static int
setctlline(Serialport * p,uchar val)879 setctlline(Serialport *p, uchar val)
880 {
881 	return ftdiwrite(p, val | (val << 8), 0, FTSETMODEMCTRL);
882 }
883 
884 static void
updatectlst(Serialport * p,int val)885 updatectlst(Serialport *p, int val)
886 {
887 	if(p->rts)
888 		p->ctlstate |= val;
889 	else
890 		p->ctlstate &= ~val;
891 }
892 
893 static int
setctl(Serialport * p)894 setctl(Serialport *p)
895 {
896 	int res;
897 	Serial *ser;
898 
899 	ser = p->s;
900 
901 	if(ser->dev->usb->vid == FTVid && ser->dev->usb->did ==  FTHETIRA1Did){
902 		fprint(2, "serial: cannot set lines for this device\n");
903 		updatectlst(p, CtlRTS|CtlDTR);
904 		p->rts = p->dtr = 1;
905 		return -1;
906 	}
907 
908 	/* NB: you can not set DTR and RTS with one control message */
909 	updatectlst(p, CtlRTS);
910 	res = setctlline(p, (CtlRTS<<8)|p->ctlstate);
911 	if(res < 0)
912 		return res;
913 
914 	updatectlst(p, CtlDTR);
915 	res = setctlline(p, (CtlDTR<<8)|p->ctlstate);
916 	if(res < 0)
917 		return res;
918 
919 	return 0;
920 }
921 
922 static int
ftsendlines(Serialport * p)923 ftsendlines(Serialport *p)
924 {
925 	int res;
926 
927 	dsprint(2, "serial: sendlines: %#2.2x\n", p->ctlstate);
928 	res = setctl(p);
929 	dsprint(2, "serial: sendlines res: %d\n", res);
930 	return 0;
931 }
932 
933 static int
ftseteps(Serialport * p)934 ftseteps(Serialport *p)
935 {
936 	char *s;
937 	Serial *ser;
938 
939 	ser = p->s;
940 
941 	s = smprint("maxpkt %d", ser->maxrtrans);
942 	devctl(p->epin, s);
943 	free(s);
944 
945 	s = smprint("maxpkt %d", ser->maxwtrans);
946 	devctl(p->epout, s);
947 	free(s);
948 	return 0;
949 }
950 
951 Serialops ftops = {
952 	.init		= ftinit,
953 	.seteps		= ftseteps,
954 	.setparam	= ftsetparam,
955 	.clearpipes	= ftclearpipes,
956 	.reset		= ftreset,
957 	.sendlines	= ftsendlines,
958 	.modemctl	= ftmodemctl,
959 	.setbreak	= ftsetbreak,
960 	.wait4data	= wait4data,
961 	.wait4write	= wait4write,
962 };
963