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, nleft, n;
626 uchar *b;
627 Serial *ser;
628
629 ser = p->s;
630
631 b = emallocz(ser->maxwtrans, 1);
632 fd = p->epout->dfd;
633 qunlock(ser);
634 for(nleft = count; nleft > 0; data += n, nleft -= n){
635 n = ser->maxwtrans - ser->outhdrsz;
636 if(n > nleft)
637 n = nleft;
638 off = ftsetouthdr(p, b, n);
639 memmove(b+off, data, n);
640 n = write(fd, b, n+off);
641 if(n <= 0)
642 break;
643 }
644 qlock(ser);
645 free(b);
646 return count - nleft;
647 }
648
649 typedef struct Packser Packser;
650 struct Packser{
651 int nb;
652 uchar b[Bufsiz];
653 };
654
655 typedef struct Areader Areader;
656 struct Areader{
657 Serialport *p;
658 Channel *c;
659 };
660
661 static void
shutdownchan(Channel * c)662 shutdownchan(Channel *c)
663 {
664 Packser *bp;
665
666 while((bp=nbrecvp(c)) != nil)
667 free(bp);
668 chanfree(c);
669 }
670
671 int
cpdata(Serial * ser,Serialport * port,uchar * out,uchar * in,int sz)672 cpdata(Serial *ser, Serialport *port, uchar *out, uchar *in, int sz)
673 {
674 int i, ncp, ntotcp, pksz;
675
676 pksz = ser->maxrtrans;
677 ntotcp = 0;
678
679 for(i = 0; i < sz; i+= pksz){
680 ftuseinhdr(port, in + i);
681 if(sz - i > pksz)
682 ncp = pksz - ser->inhdrsz;
683 else
684 ncp = sz - i - ser->inhdrsz;
685 memmove(out, in + i + ser->inhdrsz, ncp);
686 out += ncp;
687 ntotcp += ncp;
688 }
689 return ntotcp;
690 }
691
692 static void
epreader(void * u)693 epreader(void *u)
694 {
695 int dfd, rcount, cl, ntries, recov;
696 char err[40];
697 Areader *a;
698 Channel *c;
699 Packser *pk;
700 Serial *ser;
701 Serialport *p;
702
703 threadsetname("epreader proc");
704 a = u;
705 p = a->p;
706 ser = p->s;
707 c = a->c;
708 free(a);
709
710 qlock(ser); /* this makes the reader wait end of initialization too */
711 dfd = p->epin->dfd;
712 qunlock(ser);
713
714 ntries = 0;
715 pk = nil;
716 do {
717 if (pk == nil)
718 pk = emallocz(sizeof(Packser), 1);
719 Eagain:
720 rcount = read(dfd, pk->b, sizeof pk->b);
721 if(serialdebug > 5)
722 dsprint(2, "%d %#ux%#ux ", rcount, p->data[0],
723 p->data[1]);
724
725 if(rcount < 0){
726 if(ntries++ > 100)
727 break;
728 qlock(ser);
729 recov = serialrecover(ser, p, nil, "epreader: bulkin error");
730 qunlock(ser);
731 if(recov >= 0)
732 goto Eagain;
733 }
734 if(rcount == 0)
735 continue;
736 if(rcount >= ser->inhdrsz){
737 rcount = cpdata(ser, p, pk->b, pk->b, rcount);
738 if(rcount != 0){
739 pk->nb = rcount;
740 cl = sendp(c, pk);
741 if(cl < 0){
742 /*
743 * if it was a time-out, I don't want
744 * to give back an error.
745 */
746 rcount = 0;
747 break;
748 }
749 }else
750 free(pk);
751 qlock(ser);
752 ser->recover = 0;
753 qunlock(ser);
754 ntries = 0;
755 pk = nil;
756 }
757 } while(rcount >= 0 || (rcount < 0 && strstr(err, "timed out") != nil));
758
759 if(rcount < 0)
760 fprint(2, "%s: error reading %s: %r\n", argv0, p->fs.name);
761 free(pk);
762 nbsendp(c, nil);
763 if(p->w4data != nil)
764 chanclose(p->w4data);
765 if(p->gotdata != nil)
766 chanclose(p->gotdata);
767 devctl(ser->dev, "detach");
768 closedev(ser->dev);
769 usbfsdel(&p->fs);
770 }
771
772 static void
statusreader(void * u)773 statusreader(void *u)
774 {
775 Areader *a;
776 Channel *c;
777 Packser *pk;
778 Serialport *p;
779 Serial *ser;
780 int cl;
781
782 p = u;
783 ser = p->s;
784 threadsetname("statusreader thread");
785 /* big buffering, fewer bytes lost */
786 c = chancreate(sizeof(Packser *), 128);
787 a = emallocz(sizeof(Areader), 1);
788 a->p = p;
789 a->c = c;
790 incref(ser->dev);
791 proccreate(epreader, a, 16*1024);
792
793 while((pk = recvp(c)) != nil){
794 memmove(p->data, pk->b, pk->nb);
795 p->ndata = pk->nb;
796 free(pk);
797 dsprint(2, "serial %p: status reader %d \n", p, p->ndata);
798 /* consume it all */
799 while(p->ndata != 0){
800 dsprint(2, "serial %p: status reader to consume: %d\n",
801 p, p->ndata);
802 cl = recvul(p->w4data);
803 if(cl < 0)
804 break;
805 cl = sendul(p->gotdata, 1);
806 if(cl < 0)
807 break;
808 }
809 }
810
811 shutdownchan(c);
812 devctl(ser->dev, "detach");
813 closedev(ser->dev);
814 usbfsdel(&p->fs);
815 }
816
817 static int
ftreset(Serial * ser,Serialport * p)818 ftreset(Serial *ser, Serialport *p)
819 {
820 int i;
821
822 if(p != nil){
823 ftdiwrite(p, FTRESETCTLVAL, 0, FTRESET);
824 return 0;
825 }
826 p = ser->p;
827 for(i = 0; i < Maxifc; i++)
828 if(p[i].s != nil)
829 ftdiwrite(&p[i], FTRESETCTLVAL, 0, FTRESET);
830 return 0;
831 }
832
833 static int
ftinit(Serialport * p)834 ftinit(Serialport *p)
835 {
836 Serial *ser;
837 uint timerval;
838 int res;
839
840 ser = p->s;
841 if(p->isjtag){
842 res = ftdiwrite(p, FTSETFLOWCTRL, 0, FTDISABLEFLOWCTRL);
843 if(res < 0)
844 return -1;
845 res = ftdiread(p, FTSETLATENCYTIMER, 0, (uchar *)&timerval,
846 FTLATENCYTIMERSZ);
847 if(res < 0)
848 return -1;
849 dsprint(2, "serial: jtag latency timer is %d\n", timerval);
850 timerval = 2;
851 ftdiwrite(p, FTLATENCYDEFAULT, 0, FTSETLATENCYTIMER);
852 res = ftdiread(p, FTSETLATENCYTIMER, 0, (uchar *)&timerval,
853 FTLATENCYTIMERSZ);
854 if(res < 0)
855 return -1;
856
857 dsprint(2, "serial: jtag latency timer set to %d\n", timerval);
858 /* may be unnecessary */
859 devctl(p->epin, "timeout 5000");
860 devctl(p->epout, "timeout 5000");
861 /* 0xb is the mask for lines. plug dependant? */
862 ftdiwrite(p, BMMPSSE|0x0b, 0, FTSETBITMODE);
863 }
864 incref(ser->dev);
865 threadcreate(statusreader, p, 8*1024);
866 return 0;
867 }
868
869 static int
ftsetbreak(Serialport * p,int val)870 ftsetbreak(Serialport *p, int val)
871 {
872 return ftdiwrite(p, (val != 0? FTSETBREAK: 0), 0, FTSETDATA);
873 }
874
875 static int
ftclearpipes(Serialport * p)876 ftclearpipes(Serialport *p)
877 {
878 /* maybe can be done in one... */
879 ftdiwrite(p, FTRESETCTLVALPURGETX, 0, FTRESET);
880 ftdiwrite(p, FTRESETCTLVALPURGERX, 0, FTRESET);
881 return 0;
882 }
883
884 static int
setctlline(Serialport * p,uchar val)885 setctlline(Serialport *p, uchar val)
886 {
887 return ftdiwrite(p, val | (val << 8), 0, FTSETMODEMCTRL);
888 }
889
890 static void
updatectlst(Serialport * p,int val)891 updatectlst(Serialport *p, int val)
892 {
893 if(p->rts)
894 p->ctlstate |= val;
895 else
896 p->ctlstate &= ~val;
897 }
898
899 static int
setctl(Serialport * p)900 setctl(Serialport *p)
901 {
902 int res;
903 Serial *ser;
904
905 ser = p->s;
906
907 if(ser->dev->usb->vid == FTVid && ser->dev->usb->did == FTHETIRA1Did){
908 fprint(2, "serial: cannot set lines for this device\n");
909 updatectlst(p, CtlRTS|CtlDTR);
910 p->rts = p->dtr = 1;
911 return -1;
912 }
913
914 /* NB: you can not set DTR and RTS with one control message */
915 updatectlst(p, CtlRTS);
916 res = setctlline(p, (CtlRTS<<8)|p->ctlstate);
917 if(res < 0)
918 return res;
919
920 updatectlst(p, CtlDTR);
921 res = setctlline(p, (CtlDTR<<8)|p->ctlstate);
922 if(res < 0)
923 return res;
924
925 return 0;
926 }
927
928 static int
ftsendlines(Serialport * p)929 ftsendlines(Serialport *p)
930 {
931 int res;
932
933 dsprint(2, "serial: sendlines: %#2.2x\n", p->ctlstate);
934 res = setctl(p);
935 dsprint(2, "serial: sendlines res: %d\n", res);
936 return 0;
937 }
938
939 static int
ftseteps(Serialport * p)940 ftseteps(Serialport *p)
941 {
942 char *s;
943 Serial *ser;
944
945 ser = p->s;
946
947 s = smprint("maxpkt %d", ser->maxrtrans);
948 devctl(p->epin, s);
949 free(s);
950
951 s = smprint("maxpkt %d", ser->maxwtrans);
952 devctl(p->epout, s);
953 free(s);
954 return 0;
955 }
956
957 Serialops ftops = {
958 .init = ftinit,
959 .seteps = ftseteps,
960 .setparam = ftsetparam,
961 .clearpipes = ftclearpipes,
962 .reset = ftreset,
963 .sendlines = ftsendlines,
964 .modemctl = ftmodemctl,
965 .setbreak = ftsetbreak,
966 .wait4data = wait4data,
967 .wait4write = wait4write,
968 };
969