Subversion Repositories planix.SVN

Rev

Rev 2 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 - 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
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
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
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
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
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
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
317
ft232bmbaud2div (int baud)
318
{
319
	return ft232bmbaudbase2div (baud, ClockNew);
320
}
321
 
322
static int
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
864
ftsetbreak(Serialport *p, int val)
865
{
866
	return ftdiwrite(p, (val != 0? FTSETBREAK: 0), 0, FTSETDATA);
867
}
868
 
869
static int
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
879
setctlline(Serialport *p, uchar val)
880
{
881
	return ftdiwrite(p, val | (val << 8), 0, FTSETMODEMCTRL);
882
}
883
 
884
static void
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
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
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
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
};