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