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 fMasterTTY = gTTYModule->tty_create(pc_serial_service, NULL); 549 if (fMasterTTY == NULL) { 550 TRACE_ALWAYS("open: failed to init master tty\n"); 551 return B_NO_MEMORY; 552 } 553 554 fSlaveTTY = gTTYModule->tty_create(pc_serial_service, fMasterTTY); 555 if (fSlaveTTY == NULL) { 556 TRACE_ALWAYS("open: failed to init slave tty\n"); 557 gTTYModule->tty_destroy(fMasterTTY); 558 return B_NO_MEMORY; 559 } 560 561 fSystemTTYCookie = gTTYModule->tty_create_cookie(fMasterTTY, fSlaveTTY, 562 O_RDWR); 563 if (fSystemTTYCookie == NULL) { 564 TRACE_ALWAYS("open: failed to init system tty cookie\n"); 565 gTTYModule->tty_destroy(fMasterTTY); 566 gTTYModule->tty_destroy(fSlaveTTY); 567 return B_NO_MEMORY; 568 } 569 570 fDeviceTTYCookie = gTTYModule->tty_create_cookie(fSlaveTTY, fMasterTTY, 571 O_RDWR); 572 if (fDeviceTTYCookie == NULL) { 573 TRACE_ALWAYS("open: failed to init device tty cookie\n"); 574 gTTYModule->tty_destroy_cookie(fSystemTTYCookie); 575 gTTYModule->tty_destroy(fMasterTTY); 576 gTTYModule->tty_destroy(fSlaveTTY); 577 return B_NO_MEMORY; 578 } 579 580 ResetDevice(); 581 582 //XXX: we shouldn't have to do this! 583 bool en = true; 584 Service(fMasterTTY, TTYENABLE, &en, sizeof(en)); 585 586 if (status < B_OK) { 587 TRACE_ALWAYS("open: failed to open tty\n"); 588 return status; 589 } 590 591 // set our config (will propagate to the slave config as well in SetModes() 592 gTTYModule->tty_control(fSystemTTYCookie, TCSETA, &fTTYConfig, 593 sizeof(termios)); 594 595 #if 0 596 fDeviceThread = spawn_kernel_thread(_DeviceThread, "usb_serial device thread", 597 B_NORMAL_PRIORITY, this); 598 599 if (fDeviceThread < B_OK) { 600 TRACE_ALWAYS("open: failed to spawn kernel thread\n"); 601 return fDeviceThread; 602 } 603 604 resume_thread(fDeviceThread); 605 606 fControlOut = CLS_LINE_DTR | CLS_LINE_RTS; 607 SetControlLineState(fControlOut); 608 609 status = gUSBModule->queue_interrupt(fControlPipe, fInterruptBuffer, 610 fInterruptBufferSize, InterruptCallbackFunction, this); 611 if (status < B_OK) 612 TRACE_ALWAYS("failed to queue initial interrupt\n"); 613 614 #endif 615 fDeviceOpen = true; 616 return B_OK; 617 } 618 619 620 status_t 621 SerialDevice::Read(char *buffer, size_t *numBytes) 622 { 623 if (fDeviceRemoved) { 624 *numBytes = 0; 625 return B_DEV_NOT_READY; 626 } 627 628 status_t status; 629 630 status = gTTYModule->tty_read(fSystemTTYCookie, buffer, numBytes); 631 632 return status; 633 } 634 635 636 status_t 637 SerialDevice::Write(const char *buffer, size_t *numBytes) 638 { 639 TRACE("%s(,&%d)\n", __FUNCTION__, *numBytes); 640 if (fDeviceRemoved) { 641 *numBytes = 0; 642 return B_DEV_NOT_READY; 643 } 644 645 status_t status; 646 size_t bytesLeft = *numBytes; 647 *numBytes = 0; 648 649 while (bytesLeft > 0) { 650 size_t length = MIN(bytesLeft, 256); 651 // TODO: This is an ugly hack; We use a small buffer size so that 652 // we don't overrun the tty line buffer and cause it to block. While 653 // that isn't a problem, we shouldn't just hardcode the value here. 654 655 TRACE("%s: tty_write(,&%d)\n", __FUNCTION__, length); 656 status = gTTYModule->tty_write(fSystemTTYCookie, buffer, 657 &length); 658 if (status != B_OK) { 659 TRACE_ALWAYS("failed to write to tty: %s\n", strerror(status)); 660 return status; 661 } 662 663 buffer += length; 664 *numBytes += length; 665 bytesLeft -= length; 666 667 // XXX: WTF: this ought to be done by the tty module calling service_func! 668 // enable irqs 669 Service(fMasterTTY, TTYOSTART, NULL, 0); 670 } 671 672 status = acquire_sem_etc(fDoneWrite, 1, B_CAN_INTERRUPT, 0); 673 if (status != B_OK) { 674 TRACE_ALWAYS("write: failed to get write done sem " 675 "0x%08x\n", status); 676 return status; 677 } 678 679 680 if (*numBytes > 0) 681 return B_OK; 682 683 return B_ERROR; 684 } 685 686 687 status_t 688 SerialDevice::Control(uint32 op, void *arg, size_t length) 689 { 690 status_t status = B_OK; 691 692 if (fDeviceRemoved) 693 return B_DEV_NOT_READY; 694 695 status = gTTYModule->tty_control(fSystemTTYCookie, op, arg, length); 696 697 return status; 698 } 699 700 701 status_t 702 SerialDevice::Select(uint8 event, uint32 ref, selectsync *sync) 703 { 704 if (fDeviceRemoved) 705 return B_DEV_NOT_READY; 706 707 return gTTYModule->tty_select(fSystemTTYCookie, event, ref, sync); 708 } 709 710 711 status_t 712 SerialDevice::DeSelect(uint8 event, selectsync *sync) 713 { 714 if (fDeviceRemoved) 715 return B_DEV_NOT_READY; 716 717 return gTTYModule->tty_deselect(fSystemTTYCookie, event, sync); 718 } 719 720 721 status_t 722 SerialDevice::Close() 723 { 724 status_t status = B_OK; 725 726 OnClose(); 727 728 if (!fDeviceRemoved) { 729 #if 0 730 gUSBModule->cancel_queued_transfers(fReadPipe); 731 gUSBModule->cancel_queued_transfers(fWritePipe); 732 gUSBModule->cancel_queued_transfers(fControlPipe); 733 #endif 734 } 735 736 fDeviceOpen = false; 737 738 gTTYModule->tty_close_cookie(fSystemTTYCookie); 739 gTTYModule->tty_close_cookie(fDeviceTTYCookie); 740 741 //XXX: we shouldn't have to do this! 742 bool en = false; 743 Service(fMasterTTY, TTYENABLE, &en, sizeof(en)); 744 745 return status; 746 } 747 748 749 status_t 750 SerialDevice::Free() 751 { 752 status_t status = B_OK; 753 754 // wait until currently executing DPC is done. In case another one 755 // is run beyond this point it will just bail out on !IsOpen(). 756 //while (atomic_get(&fPendingDPC)) 757 // snooze(1000); 758 759 gTTYModule->tty_destroy_cookie(fSystemTTYCookie); 760 gTTYModule->tty_destroy_cookie(fDeviceTTYCookie); 761 fSystemTTYCookie = fDeviceTTYCookie = NULL; 762 763 gTTYModule->tty_destroy(fMasterTTY); 764 gTTYModule->tty_destroy(fSlaveTTY); 765 fMasterTTY = fSlaveTTY = NULL; 766 767 return status; 768 } 769 770 771 void 772 SerialDevice::Removed() 773 { 774 if (fDeviceRemoved) 775 return; 776 777 // notifies us that the device was removed 778 fDeviceRemoved = true; 779 780 // we need to ensure that we do not use the device anymore 781 fStopDeviceThread = true; 782 fInputStopped = false; 783 #if 0 784 gUSBModule->cancel_queued_transfers(fReadPipe); 785 gUSBModule->cancel_queued_transfers(fWritePipe); 786 gUSBModule->cancel_queued_transfers(fControlPipe); 787 #endif 788 789 int32 result = B_OK; 790 wait_for_thread(fDeviceThread, &result); 791 fDeviceThread = -1; 792 } 793 794 795 status_t 796 SerialDevice::AddDevice(const serial_config_descriptor *config) 797 { 798 // default implementation - does nothing 799 return B_ERROR; 800 } 801 802 803 status_t 804 SerialDevice::ResetDevice() 805 { 806 // default implementation - does nothing 807 return B_OK; 808 } 809 810 811 #if 0 812 status_t 813 SerialDevice::SetLineCoding(usb_serial_line_coding *coding) 814 { 815 // default implementation - does nothing 816 return B_OK; 817 } 818 #endif 819 820 status_t 821 SerialDevice::SignalControlLineState(int line, bool enable) 822 { 823 gTTYModule->tty_hardware_signal(fSystemTTYCookie, line, enable); 824 825 return B_OK; 826 } 827 828 829 void 830 SerialDevice::OnRead(char **buffer, size_t *numBytes) 831 { 832 // default implementation - does nothing 833 } 834 835 836 void 837 SerialDevice::OnWrite(const char *buffer, size_t *numBytes, size_t *packetBytes) 838 { 839 // default implementation - does nothing 840 } 841 842 843 void 844 SerialDevice::OnClose() 845 { 846 // default implementation - does nothing 847 } 848 849 850 int32 851 SerialDevice::_DeviceThread(void *data) 852 { 853 #if 0 854 SerialDevice *device = (SerialDevice *)data; 855 856 while (!device->fStopDeviceThread) { 857 status_t status = gUSBModule->queue_bulk(device->fReadPipe, 858 device->fReadBuffer, device->fReadBufferSize, 859 device->ReadCallbackFunction, data); 860 if (status < B_OK) { 861 TRACE_ALWAYS("device thread: queueing failed with error: 0x%08x\n", status); 862 break; 863 } 864 865 status = acquire_sem_etc(device->fDoneRead, 1, B_CAN_INTERRUPT, 0); 866 if (status < B_OK) { 867 TRACE_ALWAYS("device thread: failed to get read done sem 0x%08x\n", status); 868 break; 869 } 870 871 if (device->fStatusRead != B_OK) { 872 TRACE("device thread: device status error 0x%08x\n", 873 device->fStatusRead); 874 if (gUSBModule->clear_feature(device->fReadPipe, 875 USB_FEATURE_ENDPOINT_HALT) != B_OK) { 876 TRACE_ALWAYS("device thread: failed to clear halt feature\n"); 877 break; 878 } 879 } 880 881 char *buffer = device->fReadBuffer; 882 size_t readLength = device->fActualLengthRead; 883 device->OnRead(&buffer, &readLength); 884 if (readLength == 0) 885 continue; 886 887 ddrover *ddr = gTTYModule->ddrstart(NULL); 888 if (!ddr) { 889 TRACE_ALWAYS("device thread: ddrstart problem\n"); 890 return B_NO_MEMORY; 891 } 892 893 while (device->fInputStopped) 894 snooze(100); 895 896 gTTYModule->ttyilock(&device->fTTY, ddr, true); 897 for (size_t i = 0; i < readLength; i++) 898 gTTYModule->ttyin(&device->fTTY, ddr, buffer[i]); 899 900 gTTYModule->ttyilock(&device->fTTY, ddr, false); 901 gTTYModule->ddrdone(ddr); 902 } 903 904 #endif 905 return B_OK; 906 } 907 908 909 status_t 910 SerialDevice::_WriteToDevice() 911 { 912 char *buffer = &fWriteBuffer[fWriteBufferIn]; 913 size_t bytesLeft = DEF_BUFFER_SIZE - atomic_get(&fWriteBufferAvail); 914 bytesLeft = MIN(bytesLeft, DEF_BUFFER_SIZE - fWriteBufferIn); 915 TRACE("%s: in %d left %d\n", __FUNCTION__, fWriteBufferIn, bytesLeft); 916 status_t status = gTTYModule->tty_read(fDeviceTTYCookie, buffer, 917 &bytesLeft); 918 TRACE("%s: tty_read: %d\n", __FUNCTION__, bytesLeft); 919 if (status != B_OK) { 920 TRACE_ALWAYS("write to device: failed to read from TTY: %s\n", 921 strerror(status)); 922 return status; 923 } 924 fWriteBufferIn += bytesLeft; 925 fWriteBufferIn %= DEF_BUFFER_SIZE; 926 atomic_add(&fWriteBufferAvail, bytesLeft); 927 928 // XXX: WTF: this ought to be done by the tty module calling service_func! 929 // enable irqs 930 Service(fMasterTTY, TTYOSTART, NULL, 0); 931 932 status = acquire_sem_etc(fWriteBufferSem, 1, B_CAN_INTERRUPT, 0); 933 if (status != B_OK) { 934 TRACE_ALWAYS("write to device: failed to acquire sem: %s\n", 935 strerror(status)); 936 return status; 937 } 938 return B_OK; 939 } 940 941 942 void 943 SerialDevice::ReadCallbackFunction(void *cookie, int32 status, void *data, 944 uint32 actualLength) 945 { 946 TRACE_FUNCALLS("read callback: cookie: 0x%08x status: 0x%08x data: 0x%08x len: %lu\n", 947 cookie, status, data, actualLength); 948 949 SerialDevice *device = (SerialDevice *)cookie; 950 device->fActualLengthRead = actualLength; 951 device->fStatusRead = status; 952 release_sem_etc(device->fDoneRead, 1, B_DO_NOT_RESCHEDULE); 953 } 954 955 956 void 957 SerialDevice::WriteCallbackFunction(void *cookie, int32 status, void *data, 958 uint32 actualLength) 959 { 960 TRACE_FUNCALLS("write callback: cookie: 0x%08x status: 0x%08x data: 0x%08x len: %lu\n", 961 cookie, status, data, actualLength); 962 963 SerialDevice *device = (SerialDevice *)cookie; 964 device->fActualLengthWrite = actualLength; 965 device->fStatusWrite = status; 966 release_sem_etc(device->fDoneWrite, 1, B_DO_NOT_RESCHEDULE); 967 } 968 969 970 void 971 SerialDevice::InterruptCallbackFunction(void *cookie, int32 status, 972 void *data, uint32 actualLength) 973 { 974 TRACE_FUNCALLS("interrupt callback: cookie: 0x%08x status: 0x%08x data: 0x%08x len: %lu\n", 975 cookie, status, data, actualLength); 976 977 SerialDevice *device = (SerialDevice *)cookie; 978 device->fActualLengthInterrupt = actualLength; 979 device->fStatusInterrupt = status; 980 981 // ToDo: maybe handle those somehow? 982 983 if (status == B_OK && !device->fDeviceRemoved) { 984 #if 0 985 status = gUSBModule->queue_interrupt(device->fControlPipe, 986 device->fInterruptBuffer, device->fInterruptBufferSize, 987 device->InterruptCallbackFunction, device); 988 #endif 989 } 990 } 991 992 993 994 #if 0 995 SerialDevice * 996 SerialDevice::MakeDevice(usb_device device, uint16 vendorID, 997 uint16 productID) 998 { 999 const char *description = NULL; 1000 1001 switch (vendorID) { 1002 case VENDOR_IODATA: 1003 case VENDOR_ATEN: 1004 case VENDOR_TDK: 1005 case VENDOR_RATOC: 1006 case VENDOR_PROLIFIC: 1007 case VENDOR_ELECOM: 1008 case VENDOR_SOURCENEXT: 1009 case VENDOR_HAL: 1010 { 1011 switch (productID) { 1012 case PRODUCT_PROLIFIC_RSAQ2: description = "PL2303 Serial adapter (IODATA USB-RSAQ2)"; break; 1013 case PRODUCT_IODATA_USBRSAQ: description = "I/O Data USB serial adapter USB-RSAQ1"; break; 1014 case PRODUCT_ATEN_UC232A: description = "Aten Serial adapter"; break; 1015 case PRODUCT_TDK_UHA6400: description = "TDK USB-PHS Adapter UHA6400"; break; 1016 case PRODUCT_RATOC_REXUSB60: description = "Ratoc USB serial adapter REX-USB60"; break; 1017 case PRODUCT_PROLIFIC_PL2303: description = "PL2303 Serial adapter (ATEN/IOGEAR UC232A)"; break; 1018 case PRODUCT_ELECOM_UCSGT: description = "Elecom UC-SGT"; break; 1019 case PRODUCT_SOURCENEXT_KEIKAI8: description = "SOURCENEXT KeikaiDenwa 8"; break; 1020 case PRODUCT_SOURCENEXT_KEIKAI8_CHG: description = "SOURCENEXT KeikaiDenwa 8 with charger"; break; 1021 case PRODUCT_HAL_IMR001: description = "HAL Corporation Crossam2+USB"; break; 1022 } 1023 1024 if (!description) 1025 break; 1026 1027 return new(std::nothrow) ProlificDevice(device, vendorID, productID, description); 1028 } 1029 1030 case VENDOR_FTDI: 1031 { 1032 switch (productID) { 1033 case PRODUCT_FTDI_8U100AX: description = "FTDI 8U100AX serial converter"; break; 1034 case PRODUCT_FTDI_8U232AM: description = "FTDI 8U232AM serial converter"; break; 1035 } 1036 1037 if (!description) 1038 break; 1039 1040 return new(std::nothrow) FTDIDevice(device, vendorID, productID, description); 1041 } 1042 1043 case VENDOR_PALM: 1044 case VENDOR_KLSI: 1045 { 1046 switch (productID) { 1047 case PRODUCT_PALM_CONNECT: description = "PalmConnect RS232"; break; 1048 case PRODUCT_KLSI_KL5KUSB105D: description = "KLSI KL5KUSB105D"; break; 1049 } 1050 1051 if (!description) 1052 break; 1053 1054 return new(std::nothrow) KLSIDevice(device, vendorID, productID, description); 1055 } 1056 } 1057 1058 return new(std::nothrow) ACMDevice(device, vendorID, productID, "CDC ACM compatible device"); 1059 } 1060 #endif 1061 1062 1063 uint8 1064 SerialDevice::ReadReg8(int reg) 1065 { 1066 uint8 ret; 1067 switch (fBus) { 1068 case B_ISA_BUS: 1069 ret = gISAModule->read_io_8(IOBase() + reg); 1070 break; 1071 case B_PCI_BUS: 1072 ret = gPCIModule->read_io_8(IOBase() + reg); 1073 break; 1074 default: 1075 TRACE_ALWAYS("%s: unknown bus!\n", __FUNCTION__); 1076 ret = 0; 1077 //XXX:pcmcia ? 1078 } 1079 TRACE/*_ALWAYS*/("RR8(%d) = %d [%02x]\n", reg, ret, ret); 1080 //spin(1000); 1081 return ret; 1082 } 1083 1084 void 1085 SerialDevice::WriteReg8(int reg, uint8 value) 1086 { 1087 // TRACE_ALWAYS("WR8(0x%04x+%d, %d [0x%x])\n", IOBase(), reg, value, value); 1088 TRACE/*_ALWAYS*/("WR8(%d, %d [0x%x])\n", reg, value, value); 1089 switch (fBus) { 1090 case B_ISA_BUS: 1091 gISAModule->write_io_8(IOBase() + reg, value); 1092 break; 1093 case B_PCI_BUS: 1094 gPCIModule->write_io_8(IOBase() + reg, value); 1095 break; 1096 default: 1097 TRACE_ALWAYS("%s: unknown bus!\n", __FUNCTION__); 1098 //XXX:pcmcia ? 1099 } 1100 //spin(10000); 1101 } 1102 1103 1104 void 1105 SerialDevice::OrReg8(int reg, uint8 value) 1106 { 1107 WriteReg8(reg, ReadReg8(reg) | value); 1108 } 1109 1110 1111 void 1112 SerialDevice::AndReg8(int reg, uint8 value) 1113 { 1114 WriteReg8(reg, ReadReg8(reg) & value); 1115 } 1116 1117 1118 void 1119 SerialDevice::MaskReg8(int reg, uint8 value) 1120 { 1121 WriteReg8(reg, ReadReg8(reg) & ~value); 1122 } 1123