1 /* 2 * Copyright 2009-2010, François Revol, <revol@free.fr>. 3 * Sponsored by TuneTracker Systems. 4 * Based on the Haiku usb_serial driver which is: 5 * 6 * Copyright (c) 2007-2008 by Michael Lotz 7 * Heavily based on the original usb_serial driver which is: 8 * 9 * Copyright (c) 2003 by Siarzhuk Zharski <imker@gmx.li> 10 * Distributed under the terms of the MIT License. 11 */ 12 #include "SerialDevice.h" 13 #include "UART.h" 14 15 #include <sys/ioctl.h> 16 17 SerialDevice::SerialDevice(const struct serial_support_descriptor *device, 18 uint32 ioBase, uint32 irq, const SerialDevice *master) 19 : /*fSupportDescriptor(device->descriptor), 20 fDevice(device), 21 fDescription(device->descriptor->name),*/ 22 fSupportDescriptor(device), 23 fDevice(NULL), 24 fDescription(device->name), 25 // 26 fDeviceOpen(false), 27 fDeviceRemoved(false), 28 fBus(device->bus), 29 fIOBase(ioBase), 30 fIRQ(irq), 31 fMaster(master), 32 fCachedIER(0x0), 33 fCachedIIR(0x1), 34 fPendingDPC(0), 35 fReadBufferAvail(0), 36 fReadBufferIn(0), 37 fReadBufferOut(0), 38 fReadBufferSem(-1), 39 fWriteBufferAvail(0), 40 fWriteBufferIn(0), 41 fWriteBufferOut(0), 42 fWriteBufferSem(-1), 43 fDoneRead(-1), 44 fDoneWrite(-1), 45 fControlOut(0), 46 fInputStopped(false), 47 fMasterTTY(NULL), 48 fSlaveTTY(NULL), 49 fSystemTTYCookie(NULL), 50 fDeviceTTYCookie(NULL), 51 fDeviceThread(-1), 52 fStopDeviceThread(false) 53 { 54 memset(&fTTYConfig, 0, sizeof(termios)); 55 fTTYConfig.c_cflag = B9600 | CS8 | CREAD; 56 memset(fReadBuffer, 'z', DEF_BUFFER_SIZE); 57 memset(fWriteBuffer, 'z', DEF_BUFFER_SIZE); 58 } 59 60 61 SerialDevice::~SerialDevice() 62 { 63 Removed(); 64 65 if (fDoneWrite >= B_OK) 66 delete_sem(fDoneWrite); 67 if (fReadBufferSem >= B_OK) 68 delete_sem(fReadBufferSem); 69 if (fWriteBufferSem >= B_OK) 70 delete_sem(fWriteBufferSem); 71 } 72 73 74 bool 75 SerialDevice::Probe() 76 { 77 uint8 msr; 78 msr = ReadReg8(MSR); 79 // just in case read twice to make sure the "delta" bits are 0 80 msr = ReadReg8(MSR); 81 // this should be enough to probe for the device for now 82 // we might want to check the scratch reg, and try identifying 83 // the model as in: 84 // http://en.wikibooks.org/wiki/Serial_Programming/8250_UART_Programming#Software_Identification_of_the_UART 85 return (msr != 0xff); 86 } 87 88 89 status_t 90 SerialDevice::Init() 91 { 92 fDoneWrite = create_sem(0, "pc_serial:done_write"); 93 fReadBufferSem = create_sem(0, "pc_serial:done_read"); 94 fWriteBufferSem = create_sem(0, "pc_serial:done_write"); 95 96 // disable IRQ 97 fCachedIER = 0; 98 WriteReg8(IER, fCachedIER); 99 100 // disable DLAB 101 WriteReg8(LCR, 0); 102 103 return B_OK; 104 } 105 106 107 void 108 SerialDevice::SetModes(struct termios *tios) 109 { 110 //TRACE_FUNCRES(trace_termios, tios); 111 spin(10000); 112 uint32 baudIndex = tios->c_cflag & CBAUD; 113 if (baudIndex > BLAST) 114 baudIndex = BLAST; 115 116 // update our master config in full 117 memcpy(&fTTYConfig, tios, sizeof(termios)); 118 fTTYConfig.c_cflag &= ~CBAUD; 119 fTTYConfig.c_cflag |= baudIndex; 120 121 // only apply the relevant parts to the device side 122 termios config; 123 memset(&config, 0, sizeof(termios)); 124 config.c_cflag = tios->c_cflag; 125 config.c_cflag &= ~CBAUD; 126 config.c_cflag |= baudIndex; 127 128 // update the termios of the device side 129 gTTYModule->tty_control(fDeviceTTYCookie, TCSETA, &config, sizeof(termios)); 130 131 uint8 lcr = 0; 132 uint16 divisor = SupportDescriptor()->bauds[baudIndex]; 133 134 switch (tios->c_cflag & CSIZE) { 135 #if CS5 != CS7 136 // in case someday... 137 case CS5: 138 lcr |= LCR_5BIT; 139 break; 140 case CS6: 141 lcr |= LCR_6BIT; 142 break; 143 #endif 144 case CS7: 145 lcr |= LCR_7BIT; 146 break; 147 case CS8: 148 default: 149 lcr |= LCR_8BIT; 150 break; 151 } 152 153 if (tios->c_cflag & CSTOPB) 154 lcr |= LCR_2STOP; 155 if (tios->c_cflag & PARENB) 156 lcr |= LCR_P_EN; 157 if ((tios->c_cflag & PARODD) == 0) 158 lcr |= LCR_P_EVEN; 159 160 if (baudIndex == B0) { 161 // disable 162 MaskReg8(MCR, MCR_DTR); 163 } else { 164 // set FCR now, 165 // 16650 and later chips have another reg at 2 when DLAB=1 166 uint8 fcr = FCR_ENABLE | FCR_RX_RST | FCR_TX_RST | FCR_F_8 | FCR_F64EN; 167 // enable fifo 168 //fcr = 0; 169 WriteReg8(FCR, fcr); 170 171 // unmask the divisor latch regs 172 WriteReg8(LCR, lcr | LCR_DLAB); 173 // set divisor 174 WriteReg8(DLLB, divisor & 0x00ff); 175 WriteReg8(DLHB, divisor >> 8); 176 //WriteReg8(2,0); 177 178 } 179 // set control lines, and disable divisor latch reg 180 WriteReg8(LCR, lcr); 181 182 183 #if 0 184 uint16 newControl = fControlOut; 185 186 static uint32 baudRates[] = { 187 0x00000000, //B0 188 0x00000032, //B50 189 0x0000004B, //B75 190 0x0000006E, //B110 191 0x00000086, //B134 192 0x00000096, //B150 193 0x000000C8, //B200 194 0x0000012C, //B300 195 0x00000258, //B600 196 0x000004B0, //B1200 197 0x00000708, //B1800 198 0x00000960, //B2400 199 0x000012C0, //B4800 200 0x00002580, //B9600 201 0x00004B00, //B19200 202 0x00009600, //B38400 203 0x0000E100, //B57600 204 0x0001C200, //B115200 205 0x00038400, //B230400 206 0x00070800, //460800 207 0x000E1000, //921600 208 }; 209 210 usb_serial_line_coding lineCoding; 211 lineCoding.speed = baudRates[baudIndex]; 212 lineCoding.stopbits = (tios->c_cflag & CSTOPB) ? LC_STOP_BIT_2 : LC_STOP_BIT_1; 213 214 if (tios->c_cflag & PARENB) { 215 lineCoding.parity = LC_PARITY_EVEN; 216 if (tios->c_cflag & PARODD) 217 lineCoding.parity = LC_PARITY_ODD; 218 } else 219 lineCoding.parity = LC_PARITY_NONE; 220 221 lineCoding.databits = (tios->c_cflag & CS8) ? 8 : 7; 222 223 if (lineCoding.speed == 0) { 224 newControl &= 0xfffffffe; 225 lineCoding.speed = fLineCoding.speed; 226 } else 227 newControl = CLS_LINE_DTR; 228 229 if (fControlOut != newControl) { 230 fControlOut = newControl; 231 TRACE("newctrl send to modem: 0x%08x\n", newControl); 232 SetControlLineState(newControl); 233 } 234 235 if (memcmp(&lineCoding, &fLineCoding, sizeof(usb_serial_line_coding)) != 0) { 236 fLineCoding.speed = lineCoding.speed; 237 fLineCoding.stopbits = lineCoding.stopbits; 238 fLineCoding.databits = lineCoding.databits; 239 fLineCoding.parity = lineCoding.parity; 240 TRACE("send to modem: speed %d sb: 0x%08x db: 0x%08x parity: 0x%08x\n", 241 fLineCoding.speed, fLineCoding.stopbits, fLineCoding.databits, 242 fLineCoding.parity); 243 SetLineCoding(&fLineCoding); 244 } 245 #endif 246 } 247 248 249 bool 250 SerialDevice::Service(struct tty *tty, uint32 op, void *buffer, size_t length) 251 { 252 uint8 msr; 253 status_t err; 254 255 TRACE("%s(,0x%08lx,,%d)\n", __FUNCTION__, op, length); 256 if (tty != fMasterTTY) 257 return false; 258 259 TRACE("%s(,0x%08lx,,%d)\n", __FUNCTION__, op, length); 260 261 switch (op) { 262 case TTYENABLE: 263 { 264 bool enable = *(bool *)buffer; 265 TRACE("TTYENABLE: %sable\n", enable ? "en" : "dis"); 266 267 if (enable) { 268 //XXX:must call SetModes(); 269 err = install_io_interrupt_handler(IRQ(), pc_serial_interrupt, this, 0); 270 TRACE("installing irq handler for %d: %s\n", IRQ(), strerror(err)); 271 } else { 272 // remove the handler 273 remove_io_interrupt_handler(IRQ(), pc_serial_interrupt, this); 274 // disable IRQ 275 fCachedIER = 0; 276 WriteReg8(IER, fCachedIER); 277 WriteReg8(MCR, 0); 278 } 279 280 msr = ReadReg8(MSR); 281 282 SignalControlLineState(TTYHWDCD, msr & MSR_DCD); 283 SignalControlLineState(TTYHWCTS, msr & MSR_CTS); 284 285 if (enable) { 286 // 287 WriteReg8(MCR, MCR_DTR | MCR_RTS | MCR_IRQ_EN /*| MCR_LOOP*//*XXXXXXX*/); 288 // enable irqs 289 fCachedIER = IER_RLS | IER_MS | IER_RDA; 290 WriteReg8(IER, fCachedIER); 291 //WriteReg8(IER, IER_RDA); 292 } 293 294 return true; 295 } 296 297 case TTYISTOP: 298 fInputStopped = *(bool *)buffer; 299 TRACE("TTYISTOP: %sstopped\n", fInputStopped ? "" : "not "); 300 301 if (fInputStopped) 302 MaskReg8(MCR, MCR_RTS); 303 else 304 OrReg8(MCR, MCR_RTS); 305 306 //gTTYModule->ttyhwsignal(ptty, ddr, TTYHWCTS, false); 307 //SignalControlLineState(TTYHWCTS, !fInputStopped); 308 //msr = ReadReg8(MSR); 309 //SignalControlLineState(TTYHWCTS, msr & MSR_CTS); 310 return true; 311 312 case TTYGETSIGNALS: 313 TRACE("TTYGETSIGNALS\n"); 314 msr = ReadReg8(MSR); 315 SignalControlLineState(TTYHWDCD, msr & MSR_DCD); 316 SignalControlLineState(TTYHWCTS, msr & MSR_CTS); 317 SignalControlLineState(TTYHWDSR, msr & MSR_DSR); 318 SignalControlLineState(TTYHWRI, msr & MSR_RI); 319 return true; 320 321 case TTYSETMODES: 322 TRACE("TTYSETMODES\n"); 323 SetModes((struct termios *)buffer); 324 //WriteReg8(IER, IER_RLS | IER_MS | IER_RDA); 325 return true; 326 327 case TTYSETDTR: 328 case TTYSETRTS: 329 { 330 bool set = *(bool *)buffer; 331 uint8 bit = op == TTYSETDTR ? MCR_DTR : MCR_RTS; 332 if (set) 333 OrReg8(MCR, bit); 334 else 335 MaskReg8(MCR, bit); 336 337 return true; 338 } 339 340 case TTYOSTART: 341 TRACE("TTYOSTART\n"); 342 // enable irqs 343 fCachedIER |= IER_THRE; 344 // XXX: toggle the bit to make VirtualBox happy !? 345 WriteReg8(IER, fCachedIER & ~IER_THRE); 346 WriteReg8(IER, fCachedIER); 347 return true; 348 case TTYOSYNC: 349 TRACE("TTYOSYNC\n"); 350 return (ReadReg8(LSR) & (LSR_THRE | LSR_TSRE)) == (LSR_THRE | LSR_TSRE); 351 return true; 352 case TTYSETBREAK: 353 { 354 bool set = *(bool *)buffer; 355 if (set) 356 OrReg8(MCR, LCR_BREAK); 357 else 358 MaskReg8(MCR, LCR_BREAK); 359 360 return true; 361 } 362 case TTYFLUSH: 363 { 364 int directions = *(int*)buffer; 365 uint8 mask = 0; 366 if (directions & TCIFLUSH) 367 mask |= FCR_RX_RST; 368 if (directions & TCOFLUSH) 369 mask |= FCR_TX_RST; 370 // These bits clear themselves when flushing is complete 371 OrReg8(FCR, mask); 372 373 return true; 374 } 375 default: 376 return false; 377 } 378 379 return false; 380 } 381 382 383 bool 384 SerialDevice::IsInterruptPending() 385 { 386 TRACE(("IsInterruptPending()\n")); 387 388 // because reading the IIR acknowledges some IRQ conditions, 389 // the next time we'll read we'll miss the IRQ condition 390 // so we just cache the value for the real handler 391 fCachedIIR = ReadReg8(IIR); 392 393 bool pending = (fCachedIIR & IIR_PENDING) == 0; 394 395 if (pending) { 396 // temporarily mask the IRQ 397 // else VirtualBox triggers one per every written byte it seems 398 // not sure it's required on real hardware 399 WriteReg8(IER, fCachedIER & ~(IER_RLS | IER_MS | IER_RDA | IER_THRE)); 400 401 atomic_add(&fPendingDPC, 1); 402 } 403 404 return pending; // 0 means yes 405 } 406 407 408 int32 409 SerialDevice::InterruptHandler() 410 { 411 int32 ret = B_UNHANDLED_INTERRUPT; 412 //XXX: what should we do here ? (certainly not use a mutex !) 413 414 uint8 iir, lsr, msr; 415 uint8 buffer[64]; 416 int tries = 8; // avoid busy looping 417 TRACE(("InterruptHandler()\n")); 418 419 // start with the first (cached) irq condition 420 iir = fCachedIIR; 421 while ((iir & IIR_PENDING) == 0) { // 0 means yes 422 status_t status; 423 size_t bytesLeft; 424 size_t readable = 0; 425 size_t fifoavail = 1; 426 size_t i; 427 428 //DEBUG 429 // for (int count = 0; ReadReg8(LSR) & LSR_DR; count++) 430 // gTTYModule->ttyin(&fTTY, &fRover, ReadReg8(RBR)); 431 432 switch (iir & (IIR_IMASK | IIR_TO)) { 433 case IIR_THRE: 434 TRACE(("IIR_THRE\n")); 435 // check how much fifo we can use 436 //XXX: move to Init() ? 437 if ((iir & IIR_FMASK) == IIR_FMASK) 438 fifoavail = 16; 439 if (iir & IIR_F64EN) 440 fifoavail = 64; 441 // we're not open... just discard the data 442 if (!IsOpen()) 443 break; 444 gTTYModule->tty_control(fDeviceTTYCookie, FIONREAD, &readable, 445 sizeof(readable)); 446 TRACE("%s: FIONREAD: %d\n", __FUNCTION__, readable); 447 448 if (readable == 0) { 449 release_sem_etc(fDoneWrite, 1, B_DO_NOT_RESCHEDULE); 450 // mask it until there's data again 451 fCachedIER &= ~IER_THRE; 452 break; 453 } 454 455 bytesLeft = MIN(fifoavail, sizeof(buffer)); 456 bytesLeft = MIN(bytesLeft, readable); 457 TRACE("%s: left %d\n", __FUNCTION__, bytesLeft); 458 status = gTTYModule->tty_read(fDeviceTTYCookie, buffer, &bytesLeft); 459 TRACE("%s: tty_read: %d\n", __FUNCTION__, bytesLeft); 460 if (status != B_OK) { 461 dprintf(DRIVER_NAME ": irq: tty_read: %s\n", strerror(status)); 462 break; 463 } 464 465 for (i = 0; i < bytesLeft; i++) { 466 WriteReg8(THB, buffer[i]); 467 } 468 469 break; 470 case IIR_TO: 471 case IIR_TO | IIR_RDA: 472 // timeout: FALLTHROUGH 473 case IIR_RDA: 474 TRACE(("IIR_TO/RDA\n")); 475 // while data is ready... and we have room for it, get it 476 bytesLeft = sizeof(buffer); 477 for (i = 0; i < bytesLeft && (ReadReg8(LSR) & LSR_DR); i++) { 478 buffer[i] = ReadReg8(RBR); 479 } 480 // we're not open... just discard the data 481 if (!IsOpen()) 482 break; 483 // we shouldn't block here but it's < 256 bytes anyway 484 status = gTTYModule->tty_write(fDeviceTTYCookie, buffer, &i); 485 if (status != B_OK) { 486 dprintf(DRIVER_NAME ": irq: tty_write: %s\n", strerror(status)); 487 break; 488 } 489 break; 490 case IIR_RLS: 491 TRACE(("IIR_RLS\n")); 492 // ack 493 lsr = ReadReg8(LSR); 494 //XXX: handle this somehow 495 break; 496 case IIR_MS: 497 TRACE(("IIR_MS\n")); 498 // modem signals changed 499 msr = ReadReg8(MSR); 500 if (!IsOpen()) 501 break; 502 if (msr & MSR_DDCD) 503 SignalControlLineState(TTYHWDCD, msr & MSR_DCD); 504 if (msr & MSR_DCTS) 505 SignalControlLineState(TTYHWCTS, msr & MSR_CTS); 506 if (msr & MSR_DDSR) 507 SignalControlLineState(TTYHWDSR, msr & MSR_DSR); 508 if (msr & MSR_TERI) 509 SignalControlLineState(TTYHWRI, msr & MSR_RI); 510 break; 511 default: 512 TRACE(("IIR_?\n")); 513 // something happened 514 break; 515 } 516 ret = B_HANDLED_INTERRUPT; 517 TRACE(("IRQ:h\n")); 518 519 // enough for now 520 if (tries-- == 0) 521 break; 522 523 // check the next IRQ condition 524 iir = ReadReg8(IIR); 525 } 526 527 atomic_add(&fPendingDPC, -1); 528 529 // unmask IRQ 530 WriteReg8(IER, fCachedIER); 531 532 TRACE_FUNCRET("< IRQ:%d\n", ret); 533 return ret; 534 } 535 536 537 status_t 538 SerialDevice::Open(uint32 flags) 539 { 540 status_t status = B_OK; 541 542 if (fDeviceOpen) 543 return B_BUSY; 544 545 if (fDeviceRemoved) 546 return B_DEV_NOT_READY; 547 548 status = gTTYModule->tty_create(pc_serial_service, NULL, &fMasterTTY); 549 if (status != B_OK) { 550 TRACE_ALWAYS("open: failed to init master tty\n"); 551 return status; 552 } 553 554 status = gTTYModule->tty_create(pc_serial_service, fMasterTTY, &fSlaveTTY); 555 if (status != B_OK) { 556 TRACE_ALWAYS("open: failed to init slave tty\n"); 557 gTTYModule->tty_destroy(fMasterTTY); 558 return status; 559 } 560 561 status = gTTYModule->tty_create_cookie(fMasterTTY, fSlaveTTY, O_RDWR, &fSystemTTYCookie); 562 if (status != B_OK) { 563 TRACE_ALWAYS("open: failed to init system tty cookie\n"); 564 gTTYModule->tty_destroy(fMasterTTY); 565 gTTYModule->tty_destroy(fSlaveTTY); 566 return status; 567 } 568 569 status = gTTYModule->tty_create_cookie(fSlaveTTY, fMasterTTY, O_RDWR, &fDeviceTTYCookie); 570 if (status != B_OK) { 571 TRACE_ALWAYS("open: failed to init device tty cookie\n"); 572 gTTYModule->tty_destroy_cookie(fSystemTTYCookie); 573 gTTYModule->tty_destroy(fMasterTTY); 574 gTTYModule->tty_destroy(fSlaveTTY); 575 return status; 576 } 577 578 ResetDevice(); 579 580 //XXX: we shouldn't have to do this! 581 bool en = true; 582 Service(fMasterTTY, TTYENABLE, &en, sizeof(en)); 583 584 if (status < B_OK) { 585 TRACE_ALWAYS("open: failed to open tty\n"); 586 return status; 587 } 588 589 // set our config (will propagate to the slave config as well in SetModes() 590 gTTYModule->tty_control(fSystemTTYCookie, TCSETA, &fTTYConfig, 591 sizeof(termios)); 592 593 #if 0 594 fDeviceThread = spawn_kernel_thread(_DeviceThread, "usb_serial device thread", 595 B_NORMAL_PRIORITY, this); 596 597 if (fDeviceThread < B_OK) { 598 TRACE_ALWAYS("open: failed to spawn kernel thread\n"); 599 return fDeviceThread; 600 } 601 602 resume_thread(fDeviceThread); 603 604 fControlOut = CLS_LINE_DTR | CLS_LINE_RTS; 605 SetControlLineState(fControlOut); 606 607 status = gUSBModule->queue_interrupt(fControlPipe, fInterruptBuffer, 608 fInterruptBufferSize, InterruptCallbackFunction, this); 609 if (status < B_OK) 610 TRACE_ALWAYS("failed to queue initial interrupt\n"); 611 612 #endif 613 fDeviceOpen = true; 614 return B_OK; 615 } 616 617 618 status_t 619 SerialDevice::Read(char *buffer, size_t *numBytes) 620 { 621 if (fDeviceRemoved) { 622 *numBytes = 0; 623 return B_DEV_NOT_READY; 624 } 625 626 status_t status; 627 628 status = gTTYModule->tty_read(fSystemTTYCookie, buffer, numBytes); 629 630 return status; 631 } 632 633 634 status_t 635 SerialDevice::Write(const char *buffer, size_t *numBytes) 636 { 637 TRACE("%s(,&%d)\n", __FUNCTION__, *numBytes); 638 if (fDeviceRemoved) { 639 *numBytes = 0; 640 return B_DEV_NOT_READY; 641 } 642 643 status_t status; 644 size_t bytesLeft = *numBytes; 645 *numBytes = 0; 646 647 while (bytesLeft > 0) { 648 size_t length = MIN(bytesLeft, 256); 649 // TODO: This is an ugly hack; We use a small buffer size so that 650 // we don't overrun the tty line buffer and cause it to block. While 651 // that isn't a problem, we shouldn't just hardcode the value here. 652 653 TRACE("%s: tty_write(,&%d)\n", __FUNCTION__, length); 654 status = gTTYModule->tty_write(fSystemTTYCookie, buffer, 655 &length); 656 if (status != B_OK) { 657 TRACE_ALWAYS("failed to write to tty: %s\n", strerror(status)); 658 return status; 659 } 660 661 buffer += length; 662 *numBytes += length; 663 bytesLeft -= length; 664 665 // XXX: WTF: this ought to be done by the tty module calling service_func! 666 // enable irqs 667 Service(fMasterTTY, TTYOSTART, NULL, 0); 668 } 669 670 status = acquire_sem_etc(fDoneWrite, 1, B_CAN_INTERRUPT, 0); 671 if (status != B_OK) { 672 TRACE_ALWAYS("write: failed to get write done sem " 673 "0x%08x\n", status); 674 return status; 675 } 676 677 678 if (*numBytes > 0) 679 return B_OK; 680 681 return B_ERROR; 682 } 683 684 685 status_t 686 SerialDevice::Control(uint32 op, void *arg, size_t length) 687 { 688 status_t status = B_OK; 689 690 if (fDeviceRemoved) 691 return B_DEV_NOT_READY; 692 693 status = gTTYModule->tty_control(fSystemTTYCookie, op, arg, length); 694 695 return status; 696 } 697 698 699 status_t 700 SerialDevice::Select(uint8 event, uint32 ref, selectsync *sync) 701 { 702 if (fDeviceRemoved) 703 return B_DEV_NOT_READY; 704 705 return gTTYModule->tty_select(fSystemTTYCookie, event, ref, sync); 706 } 707 708 709 status_t 710 SerialDevice::DeSelect(uint8 event, selectsync *sync) 711 { 712 if (fDeviceRemoved) 713 return B_DEV_NOT_READY; 714 715 return gTTYModule->tty_deselect(fSystemTTYCookie, event, sync); 716 } 717 718 719 status_t 720 SerialDevice::Close() 721 { 722 status_t status = B_OK; 723 724 OnClose(); 725 726 if (!fDeviceRemoved) { 727 #if 0 728 gUSBModule->cancel_queued_transfers(fReadPipe); 729 gUSBModule->cancel_queued_transfers(fWritePipe); 730 gUSBModule->cancel_queued_transfers(fControlPipe); 731 #endif 732 } 733 734 fDeviceOpen = false; 735 736 gTTYModule->tty_close_cookie(fSystemTTYCookie); 737 gTTYModule->tty_close_cookie(fDeviceTTYCookie); 738 739 //XXX: we shouldn't have to do this! 740 bool en = false; 741 Service(fMasterTTY, TTYENABLE, &en, sizeof(en)); 742 743 return status; 744 } 745 746 747 status_t 748 SerialDevice::Free() 749 { 750 status_t status = B_OK; 751 752 // wait until currently executing DPC is done. In case another one 753 // is run beyond this point it will just bail out on !IsOpen(). 754 //while (atomic_get(&fPendingDPC)) 755 // snooze(1000); 756 757 gTTYModule->tty_destroy_cookie(fSystemTTYCookie); 758 gTTYModule->tty_destroy_cookie(fDeviceTTYCookie); 759 fSystemTTYCookie = fDeviceTTYCookie = NULL; 760 761 gTTYModule->tty_destroy(fMasterTTY); 762 gTTYModule->tty_destroy(fSlaveTTY); 763 fMasterTTY = fSlaveTTY = NULL; 764 765 return status; 766 } 767 768 769 void 770 SerialDevice::Removed() 771 { 772 if (fDeviceRemoved) 773 return; 774 775 // notifies us that the device was removed 776 fDeviceRemoved = true; 777 778 // we need to ensure that we do not use the device anymore 779 fStopDeviceThread = true; 780 fInputStopped = false; 781 #if 0 782 gUSBModule->cancel_queued_transfers(fReadPipe); 783 gUSBModule->cancel_queued_transfers(fWritePipe); 784 gUSBModule->cancel_queued_transfers(fControlPipe); 785 #endif 786 787 int32 result = B_OK; 788 wait_for_thread(fDeviceThread, &result); 789 fDeviceThread = -1; 790 } 791 792 793 status_t 794 SerialDevice::AddDevice(const serial_config_descriptor *config) 795 { 796 // default implementation - does nothing 797 return B_ERROR; 798 } 799 800 801 status_t 802 SerialDevice::ResetDevice() 803 { 804 // default implementation - does nothing 805 return B_OK; 806 } 807 808 809 #if 0 810 status_t 811 SerialDevice::SetLineCoding(usb_serial_line_coding *coding) 812 { 813 // default implementation - does nothing 814 return B_OK; 815 } 816 #endif 817 818 status_t 819 SerialDevice::SignalControlLineState(int line, bool enable) 820 { 821 gTTYModule->tty_hardware_signal(fSystemTTYCookie, line, enable); 822 823 return B_OK; 824 } 825 826 827 void 828 SerialDevice::OnRead(char **buffer, size_t *numBytes) 829 { 830 // default implementation - does nothing 831 } 832 833 834 void 835 SerialDevice::OnWrite(const char *buffer, size_t *numBytes, size_t *packetBytes) 836 { 837 // default implementation - does nothing 838 } 839 840 841 void 842 SerialDevice::OnClose() 843 { 844 // default implementation - does nothing 845 } 846 847 848 int32 849 SerialDevice::_DeviceThread(void *data) 850 { 851 #if 0 852 SerialDevice *device = (SerialDevice *)data; 853 854 while (!device->fStopDeviceThread) { 855 status_t status = gUSBModule->queue_bulk(device->fReadPipe, 856 device->fReadBuffer, device->fReadBufferSize, 857 device->ReadCallbackFunction, data); 858 if (status < B_OK) { 859 TRACE_ALWAYS("device thread: queueing failed with error: 0x%08x\n", status); 860 break; 861 } 862 863 status = acquire_sem_etc(device->fDoneRead, 1, B_CAN_INTERRUPT, 0); 864 if (status < B_OK) { 865 TRACE_ALWAYS("device thread: failed to get read done sem 0x%08x\n", status); 866 break; 867 } 868 869 if (device->fStatusRead != B_OK) { 870 TRACE("device thread: device status error 0x%08x\n", 871 device->fStatusRead); 872 if (gUSBModule->clear_feature(device->fReadPipe, 873 USB_FEATURE_ENDPOINT_HALT) != B_OK) { 874 TRACE_ALWAYS("device thread: failed to clear halt feature\n"); 875 break; 876 } 877 } 878 879 char *buffer = device->fReadBuffer; 880 size_t readLength = device->fActualLengthRead; 881 device->OnRead(&buffer, &readLength); 882 if (readLength == 0) 883 continue; 884 885 ddrover *ddr = gTTYModule->ddrstart(NULL); 886 if (!ddr) { 887 TRACE_ALWAYS("device thread: ddrstart problem\n"); 888 return B_NO_MEMORY; 889 } 890 891 while (device->fInputStopped) 892 snooze(100); 893 894 gTTYModule->ttyilock(&device->fTTY, ddr, true); 895 for (size_t i = 0; i < readLength; i++) 896 gTTYModule->ttyin(&device->fTTY, ddr, buffer[i]); 897 898 gTTYModule->ttyilock(&device->fTTY, ddr, false); 899 gTTYModule->ddrdone(ddr); 900 } 901 902 #endif 903 return B_OK; 904 } 905 906 907 status_t 908 SerialDevice::_WriteToDevice() 909 { 910 char *buffer = &fWriteBuffer[fWriteBufferIn]; 911 size_t bytesLeft = DEF_BUFFER_SIZE - atomic_get(&fWriteBufferAvail); 912 bytesLeft = MIN(bytesLeft, DEF_BUFFER_SIZE - fWriteBufferIn); 913 TRACE("%s: in %d left %d\n", __FUNCTION__, fWriteBufferIn, bytesLeft); 914 status_t status = gTTYModule->tty_read(fDeviceTTYCookie, buffer, 915 &bytesLeft); 916 TRACE("%s: tty_read: %d\n", __FUNCTION__, bytesLeft); 917 if (status != B_OK) { 918 TRACE_ALWAYS("write to device: failed to read from TTY: %s\n", 919 strerror(status)); 920 return status; 921 } 922 fWriteBufferIn += bytesLeft; 923 fWriteBufferIn %= DEF_BUFFER_SIZE; 924 atomic_add(&fWriteBufferAvail, bytesLeft); 925 926 // XXX: WTF: this ought to be done by the tty module calling service_func! 927 // enable irqs 928 Service(fMasterTTY, TTYOSTART, NULL, 0); 929 930 status = acquire_sem_etc(fWriteBufferSem, 1, B_CAN_INTERRUPT, 0); 931 if (status != B_OK) { 932 TRACE_ALWAYS("write to device: failed to acquire sem: %s\n", 933 strerror(status)); 934 return status; 935 } 936 return B_OK; 937 } 938 939 940 void 941 SerialDevice::ReadCallbackFunction(void *cookie, int32 status, void *data, 942 uint32 actualLength) 943 { 944 TRACE_FUNCALLS("read callback: cookie: 0x%08x status: 0x%08x data: 0x%08x len: %lu\n", 945 cookie, status, data, actualLength); 946 947 SerialDevice *device = (SerialDevice *)cookie; 948 device->fActualLengthRead = actualLength; 949 device->fStatusRead = status; 950 release_sem_etc(device->fDoneRead, 1, B_DO_NOT_RESCHEDULE); 951 } 952 953 954 void 955 SerialDevice::WriteCallbackFunction(void *cookie, int32 status, void *data, 956 uint32 actualLength) 957 { 958 TRACE_FUNCALLS("write callback: cookie: 0x%08x status: 0x%08x data: 0x%08x len: %lu\n", 959 cookie, status, data, actualLength); 960 961 SerialDevice *device = (SerialDevice *)cookie; 962 device->fActualLengthWrite = actualLength; 963 device->fStatusWrite = status; 964 release_sem_etc(device->fDoneWrite, 1, B_DO_NOT_RESCHEDULE); 965 } 966 967 968 void 969 SerialDevice::InterruptCallbackFunction(void *cookie, int32 status, 970 void *data, uint32 actualLength) 971 { 972 TRACE_FUNCALLS("interrupt callback: cookie: 0x%08x status: 0x%08x data: 0x%08x len: %lu\n", 973 cookie, status, data, actualLength); 974 975 SerialDevice *device = (SerialDevice *)cookie; 976 device->fActualLengthInterrupt = actualLength; 977 device->fStatusInterrupt = status; 978 979 // ToDo: maybe handle those somehow? 980 981 if (status == B_OK && !device->fDeviceRemoved) { 982 #if 0 983 status = gUSBModule->queue_interrupt(device->fControlPipe, 984 device->fInterruptBuffer, device->fInterruptBufferSize, 985 device->InterruptCallbackFunction, device); 986 #endif 987 } 988 } 989 990 991 992 #if 0 993 SerialDevice * 994 SerialDevice::MakeDevice(usb_device device, uint16 vendorID, 995 uint16 productID) 996 { 997 const char *description = NULL; 998 999 switch (vendorID) { 1000 case VENDOR_IODATA: 1001 case VENDOR_ATEN: 1002 case VENDOR_TDK: 1003 case VENDOR_RATOC: 1004 case VENDOR_PROLIFIC: 1005 case VENDOR_ELECOM: 1006 case VENDOR_SOURCENEXT: 1007 case VENDOR_HAL: 1008 { 1009 switch (productID) { 1010 case PRODUCT_PROLIFIC_RSAQ2: description = "PL2303 Serial adapter (IODATA USB-RSAQ2)"; break; 1011 case PRODUCT_IODATA_USBRSAQ: description = "I/O Data USB serial adapter USB-RSAQ1"; break; 1012 case PRODUCT_ATEN_UC232A: description = "Aten Serial adapter"; break; 1013 case PRODUCT_TDK_UHA6400: description = "TDK USB-PHS Adapter UHA6400"; break; 1014 case PRODUCT_RATOC_REXUSB60: description = "Ratoc USB serial adapter REX-USB60"; break; 1015 case PRODUCT_PROLIFIC_PL2303: description = "PL2303 Serial adapter (ATEN/IOGEAR UC232A)"; break; 1016 case PRODUCT_ELECOM_UCSGT: description = "Elecom UC-SGT"; break; 1017 case PRODUCT_SOURCENEXT_KEIKAI8: description = "SOURCENEXT KeikaiDenwa 8"; break; 1018 case PRODUCT_SOURCENEXT_KEIKAI8_CHG: description = "SOURCENEXT KeikaiDenwa 8 with charger"; break; 1019 case PRODUCT_HAL_IMR001: description = "HAL Corporation Crossam2+USB"; break; 1020 } 1021 1022 if (!description) 1023 break; 1024 1025 return new(std::nothrow) ProlificDevice(device, vendorID, productID, description); 1026 } 1027 1028 case VENDOR_FTDI: 1029 { 1030 switch (productID) { 1031 case PRODUCT_FTDI_8U100AX: description = "FTDI 8U100AX serial converter"; break; 1032 case PRODUCT_FTDI_8U232AM: description = "FTDI 8U232AM serial converter"; break; 1033 } 1034 1035 if (!description) 1036 break; 1037 1038 return new(std::nothrow) FTDIDevice(device, vendorID, productID, description); 1039 } 1040 1041 case VENDOR_PALM: 1042 case VENDOR_KLSI: 1043 { 1044 switch (productID) { 1045 case PRODUCT_PALM_CONNECT: description = "PalmConnect RS232"; break; 1046 case PRODUCT_KLSI_KL5KUSB105D: description = "KLSI KL5KUSB105D"; break; 1047 } 1048 1049 if (!description) 1050 break; 1051 1052 return new(std::nothrow) KLSIDevice(device, vendorID, productID, description); 1053 } 1054 } 1055 1056 return new(std::nothrow) ACMDevice(device, vendorID, productID, "CDC ACM compatible device"); 1057 } 1058 #endif 1059 1060 1061 uint8 1062 SerialDevice::ReadReg8(int reg) 1063 { 1064 uint8 ret; 1065 switch (fBus) { 1066 case B_ISA_BUS: 1067 ret = gISAModule->read_io_8(IOBase() + reg); 1068 break; 1069 case B_PCI_BUS: 1070 ret = gPCIModule->read_io_8(IOBase() + reg); 1071 break; 1072 default: 1073 TRACE_ALWAYS("%s: unknown bus!\n", __FUNCTION__); 1074 ret = 0; 1075 //XXX:pcmcia ? 1076 } 1077 TRACE/*_ALWAYS*/("RR8(%d) = %d [%02x]\n", reg, ret, ret); 1078 //spin(1000); 1079 return ret; 1080 } 1081 1082 void 1083 SerialDevice::WriteReg8(int reg, uint8 value) 1084 { 1085 // TRACE_ALWAYS("WR8(0x%04x+%d, %d [0x%x])\n", IOBase(), reg, value, value); 1086 TRACE/*_ALWAYS*/("WR8(%d, %d [0x%x])\n", reg, value, value); 1087 switch (fBus) { 1088 case B_ISA_BUS: 1089 gISAModule->write_io_8(IOBase() + reg, value); 1090 break; 1091 case B_PCI_BUS: 1092 gPCIModule->write_io_8(IOBase() + reg, value); 1093 break; 1094 default: 1095 TRACE_ALWAYS("%s: unknown bus!\n", __FUNCTION__); 1096 //XXX:pcmcia ? 1097 } 1098 //spin(10000); 1099 } 1100 1101 1102 void 1103 SerialDevice::OrReg8(int reg, uint8 value) 1104 { 1105 WriteReg8(reg, ReadReg8(reg) | value); 1106 } 1107 1108 1109 void 1110 SerialDevice::AndReg8(int reg, uint8 value) 1111 { 1112 WriteReg8(reg, ReadReg8(reg) & value); 1113 } 1114 1115 1116 void 1117 SerialDevice::MaskReg8(int reg, uint8 value) 1118 { 1119 WriteReg8(reg, ReadReg8(reg) & ~value); 1120 } 1121