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