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 default: 363 return false; 364 } 365 366 return false; 367 } 368 369 370 bool 371 SerialDevice::IsInterruptPending() 372 { 373 TRACE(("IsInterruptPending()\n")); 374 375 // because reading the IIR acknowledges some IRQ conditions, 376 // the next time we'll read we'll miss the IRQ condition 377 // so we just cache the value for the real handler 378 fCachedIIR = ReadReg8(IIR); 379 380 bool pending = (fCachedIIR & IIR_PENDING) == 0; 381 382 if (pending) { 383 // temporarily mask the IRQ 384 // else VirtualBox triggers one per every written byte it seems 385 // not sure it's required on real hardware 386 WriteReg8(IER, fCachedIER & ~(IER_RLS | IER_MS | IER_RDA | IER_THRE)); 387 388 atomic_add(&fPendingDPC, 1); 389 } 390 391 return pending; // 0 means yes 392 } 393 394 395 int32 396 SerialDevice::InterruptHandler() 397 { 398 int32 ret = B_UNHANDLED_INTERRUPT; 399 //XXX: what should we do here ? (certainly not use a mutex !) 400 401 uint8 iir, lsr, msr; 402 uint8 buffer[64]; 403 int tries = 8; // avoid busy looping 404 TRACE(("InterruptHandler()\n")); 405 406 // start with the first (cached) irq condition 407 iir = fCachedIIR; 408 while ((iir & IIR_PENDING) == 0) { // 0 means yes 409 status_t status; 410 size_t bytesLeft; 411 size_t readable = 0; 412 size_t fifoavail = 1; 413 size_t i; 414 415 //DEBUG 416 // for (int count = 0; ReadReg8(LSR) & LSR_DR; count++) 417 // gTTYModule->ttyin(&fTTY, &fRover, ReadReg8(RBR)); 418 419 switch (iir & (IIR_IMASK | IIR_TO)) { 420 case IIR_THRE: 421 TRACE(("IIR_THRE\n")); 422 // check how much fifo we can use 423 //XXX: move to Init() ? 424 if ((iir & IIR_FMASK) == IIR_FMASK) 425 fifoavail = 16; 426 if (iir & IIR_F64EN) 427 fifoavail = 64; 428 // we're not open... just discard the data 429 if (!IsOpen()) 430 break; 431 gTTYModule->tty_control(fDeviceTTYCookie, FIONREAD, &readable, 432 sizeof(readable)); 433 TRACE("%s: FIONREAD: %d\n", __FUNCTION__, readable); 434 435 if (readable == 0) { 436 release_sem_etc(fDoneWrite, 1, B_DO_NOT_RESCHEDULE); 437 // mask it until there's data again 438 fCachedIER &= ~IER_THRE; 439 break; 440 } 441 442 bytesLeft = MIN(fifoavail, sizeof(buffer)); 443 bytesLeft = MIN(bytesLeft, readable); 444 TRACE("%s: left %d\n", __FUNCTION__, bytesLeft); 445 status = gTTYModule->tty_read(fDeviceTTYCookie, buffer, &bytesLeft); 446 TRACE("%s: tty_read: %d\n", __FUNCTION__, bytesLeft); 447 if (status != B_OK) { 448 dprintf(DRIVER_NAME ": irq: tty_read: %s\n", strerror(status)); 449 break; 450 } 451 452 for (i = 0; i < bytesLeft; i++) { 453 WriteReg8(THB, buffer[i]); 454 } 455 456 break; 457 case IIR_TO: 458 case IIR_TO | IIR_RDA: 459 // timeout: FALLTHROUGH 460 case IIR_RDA: 461 TRACE(("IIR_TO/RDA\n")); 462 // while data is ready... and we have room for it, get it 463 bytesLeft = sizeof(buffer); 464 for (i = 0; i < bytesLeft && (ReadReg8(LSR) & LSR_DR); i++) { 465 buffer[i] = ReadReg8(RBR); 466 } 467 // we're not open... just discard the data 468 if (!IsOpen()) 469 break; 470 // we shouldn't block here but it's < 256 bytes anyway 471 status = gTTYModule->tty_write(fDeviceTTYCookie, buffer, &i); 472 if (status != B_OK) { 473 dprintf(DRIVER_NAME ": irq: tty_write: %s\n", strerror(status)); 474 break; 475 } 476 break; 477 case IIR_RLS: 478 TRACE(("IIR_RLS\n")); 479 // ack 480 lsr = ReadReg8(LSR); 481 //XXX: handle this somehow 482 break; 483 case IIR_MS: 484 TRACE(("IIR_MS\n")); 485 // modem signals changed 486 msr = ReadReg8(MSR); 487 if (!IsOpen()) 488 break; 489 if (msr & MSR_DDCD) 490 SignalControlLineState(TTYHWDCD, msr & MSR_DCD); 491 if (msr & MSR_DCTS) 492 SignalControlLineState(TTYHWCTS, msr & MSR_CTS); 493 if (msr & MSR_DDSR) 494 SignalControlLineState(TTYHWDSR, msr & MSR_DSR); 495 if (msr & MSR_TERI) 496 SignalControlLineState(TTYHWRI, msr & MSR_RI); 497 break; 498 default: 499 TRACE(("IIR_?\n")); 500 // something happened 501 break; 502 } 503 ret = B_HANDLED_INTERRUPT; 504 TRACE(("IRQ:h\n")); 505 506 // enough for now 507 if (tries-- == 0) 508 break; 509 510 // check the next IRQ condition 511 iir = ReadReg8(IIR); 512 } 513 514 atomic_add(&fPendingDPC, -1); 515 516 // unmask IRQ 517 WriteReg8(IER, fCachedIER); 518 519 TRACE_FUNCRET("< IRQ:%d\n", ret); 520 return ret; 521 } 522 523 524 status_t 525 SerialDevice::Open(uint32 flags) 526 { 527 status_t status = B_OK; 528 529 if (fDeviceOpen) 530 return B_BUSY; 531 532 if (fDeviceRemoved) 533 return B_DEV_NOT_READY; 534 535 fMasterTTY = gTTYModule->tty_create(pc_serial_service, true); 536 if (fMasterTTY == NULL) { 537 TRACE_ALWAYS("open: failed to init master tty\n"); 538 return B_NO_MEMORY; 539 } 540 541 fSlaveTTY = gTTYModule->tty_create(pc_serial_service, false); 542 if (fSlaveTTY == NULL) { 543 TRACE_ALWAYS("open: failed to init slave tty\n"); 544 gTTYModule->tty_destroy(fMasterTTY); 545 return B_NO_MEMORY; 546 } 547 548 fSystemTTYCookie = gTTYModule->tty_create_cookie(fMasterTTY, fSlaveTTY, 549 O_RDWR); 550 if (fSystemTTYCookie == NULL) { 551 TRACE_ALWAYS("open: failed to init system tty cookie\n"); 552 gTTYModule->tty_destroy(fMasterTTY); 553 gTTYModule->tty_destroy(fSlaveTTY); 554 return B_NO_MEMORY; 555 } 556 557 fDeviceTTYCookie = gTTYModule->tty_create_cookie(fSlaveTTY, fMasterTTY, 558 O_RDWR); 559 if (fDeviceTTYCookie == NULL) { 560 TRACE_ALWAYS("open: failed to init device tty cookie\n"); 561 gTTYModule->tty_destroy_cookie(fSystemTTYCookie); 562 gTTYModule->tty_destroy(fMasterTTY); 563 gTTYModule->tty_destroy(fSlaveTTY); 564 return B_NO_MEMORY; 565 } 566 567 ResetDevice(); 568 569 //XXX: we shouldn't have to do this! 570 bool en = true; 571 Service(fMasterTTY, TTYENABLE, &en, sizeof(en)); 572 573 if (status < B_OK) { 574 TRACE_ALWAYS("open: failed to open tty\n"); 575 return status; 576 } 577 578 // set our config (will propagate to the slave config as well in SetModes() 579 gTTYModule->tty_control(fSystemTTYCookie, TCSETA, &fTTYConfig, 580 sizeof(termios)); 581 582 #if 0 583 fDeviceThread = spawn_kernel_thread(_DeviceThread, "usb_serial device thread", 584 B_NORMAL_PRIORITY, this); 585 586 if (fDeviceThread < B_OK) { 587 TRACE_ALWAYS("open: failed to spawn kernel thread\n"); 588 return fDeviceThread; 589 } 590 591 resume_thread(fDeviceThread); 592 593 fControlOut = CLS_LINE_DTR | CLS_LINE_RTS; 594 SetControlLineState(fControlOut); 595 596 status = gUSBModule->queue_interrupt(fControlPipe, fInterruptBuffer, 597 fInterruptBufferSize, InterruptCallbackFunction, this); 598 if (status < B_OK) 599 TRACE_ALWAYS("failed to queue initial interrupt\n"); 600 601 #endif 602 fDeviceOpen = true; 603 return B_OK; 604 } 605 606 607 status_t 608 SerialDevice::Read(char *buffer, size_t *numBytes) 609 { 610 if (fDeviceRemoved) { 611 *numBytes = 0; 612 return B_DEV_NOT_READY; 613 } 614 615 status_t status; 616 617 status = gTTYModule->tty_read(fSystemTTYCookie, buffer, numBytes); 618 619 return status; 620 } 621 622 623 status_t 624 SerialDevice::Write(const char *buffer, size_t *numBytes) 625 { 626 TRACE("%s(,&%d)\n", __FUNCTION__, *numBytes); 627 if (fDeviceRemoved) { 628 *numBytes = 0; 629 return B_DEV_NOT_READY; 630 } 631 632 status_t status; 633 size_t bytesLeft = *numBytes; 634 *numBytes = 0; 635 636 while (bytesLeft > 0) { 637 size_t length = MIN(bytesLeft, 256); 638 // TODO: This is an ugly hack; We use a small buffer size so that 639 // we don't overrun the tty line buffer and cause it to block. While 640 // that isn't a problem, we shouldn't just hardcode the value here. 641 642 TRACE("%s: tty_write(,&%d)\n", __FUNCTION__, length); 643 status = gTTYModule->tty_write(fSystemTTYCookie, buffer, 644 &length); 645 if (status != B_OK) { 646 TRACE_ALWAYS("failed to write to tty: %s\n", strerror(status)); 647 return status; 648 } 649 650 buffer += length; 651 *numBytes += length; 652 bytesLeft -= length; 653 654 // XXX: WTF: this ought to be done by the tty module calling service_func! 655 // enable irqs 656 Service(fMasterTTY, TTYOSTART, NULL, 0); 657 } 658 659 status = acquire_sem_etc(fDoneWrite, 1, B_CAN_INTERRUPT, 0); 660 if (status != B_OK) { 661 TRACE_ALWAYS("write: failed to get write done sem " 662 "0x%08x\n", status); 663 return status; 664 } 665 666 667 if (*numBytes > 0) 668 return B_OK; 669 670 return B_ERROR; 671 } 672 673 674 status_t 675 SerialDevice::Control(uint32 op, void *arg, size_t length) 676 { 677 status_t status = B_OK; 678 679 if (fDeviceRemoved) 680 return B_DEV_NOT_READY; 681 682 status = gTTYModule->tty_control(fSystemTTYCookie, op, arg, length); 683 684 return status; 685 } 686 687 688 status_t 689 SerialDevice::Select(uint8 event, uint32 ref, selectsync *sync) 690 { 691 if (fDeviceRemoved) 692 return B_DEV_NOT_READY; 693 694 return gTTYModule->tty_select(fSystemTTYCookie, event, ref, sync); 695 } 696 697 698 status_t 699 SerialDevice::DeSelect(uint8 event, selectsync *sync) 700 { 701 if (fDeviceRemoved) 702 return B_DEV_NOT_READY; 703 704 return gTTYModule->tty_deselect(fSystemTTYCookie, event, sync); 705 } 706 707 708 status_t 709 SerialDevice::Close() 710 { 711 status_t status = B_OK; 712 713 OnClose(); 714 715 if (!fDeviceRemoved) { 716 #if 0 717 gUSBModule->cancel_queued_transfers(fReadPipe); 718 gUSBModule->cancel_queued_transfers(fWritePipe); 719 gUSBModule->cancel_queued_transfers(fControlPipe); 720 #endif 721 } 722 723 fDeviceOpen = false; 724 725 gTTYModule->tty_close_cookie(fSystemTTYCookie); 726 gTTYModule->tty_close_cookie(fDeviceTTYCookie); 727 728 //XXX: we shouldn't have to do this! 729 bool en = false; 730 Service(fMasterTTY, TTYENABLE, &en, sizeof(en)); 731 732 return status; 733 } 734 735 736 status_t 737 SerialDevice::Free() 738 { 739 status_t status = B_OK; 740 741 // wait until currently executing DPC is done. In case another one 742 // is run beyond this point it will just bail out on !IsOpen(). 743 //while (atomic_get(&fPendingDPC)) 744 // snooze(1000); 745 746 gTTYModule->tty_destroy_cookie(fSystemTTYCookie); 747 gTTYModule->tty_destroy_cookie(fDeviceTTYCookie); 748 fSystemTTYCookie = fDeviceTTYCookie = NULL; 749 750 gTTYModule->tty_destroy(fMasterTTY); 751 gTTYModule->tty_destroy(fSlaveTTY); 752 fMasterTTY = fSlaveTTY = NULL; 753 754 return status; 755 } 756 757 758 void 759 SerialDevice::Removed() 760 { 761 if (fDeviceRemoved) 762 return; 763 764 // notifies us that the device was removed 765 fDeviceRemoved = true; 766 767 // we need to ensure that we do not use the device anymore 768 fStopDeviceThread = true; 769 fInputStopped = false; 770 #if 0 771 gUSBModule->cancel_queued_transfers(fReadPipe); 772 gUSBModule->cancel_queued_transfers(fWritePipe); 773 gUSBModule->cancel_queued_transfers(fControlPipe); 774 #endif 775 776 int32 result = B_OK; 777 wait_for_thread(fDeviceThread, &result); 778 fDeviceThread = -1; 779 } 780 781 782 status_t 783 SerialDevice::AddDevice(const serial_config_descriptor *config) 784 { 785 // default implementation - does nothing 786 return B_ERROR; 787 } 788 789 790 status_t 791 SerialDevice::ResetDevice() 792 { 793 // default implementation - does nothing 794 return B_OK; 795 } 796 797 798 #if 0 799 status_t 800 SerialDevice::SetLineCoding(usb_serial_line_coding *coding) 801 { 802 // default implementation - does nothing 803 return B_OK; 804 } 805 #endif 806 807 status_t 808 SerialDevice::SignalControlLineState(int line, bool enable) 809 { 810 gTTYModule->tty_hardware_signal(fSystemTTYCookie, line, enable); 811 812 return B_OK; 813 } 814 815 816 void 817 SerialDevice::OnRead(char **buffer, size_t *numBytes) 818 { 819 // default implementation - does nothing 820 } 821 822 823 void 824 SerialDevice::OnWrite(const char *buffer, size_t *numBytes, size_t *packetBytes) 825 { 826 // default implementation - does nothing 827 } 828 829 830 void 831 SerialDevice::OnClose() 832 { 833 // default implementation - does nothing 834 } 835 836 837 int32 838 SerialDevice::_DeviceThread(void *data) 839 { 840 #if 0 841 SerialDevice *device = (SerialDevice *)data; 842 843 while (!device->fStopDeviceThread) { 844 status_t status = gUSBModule->queue_bulk(device->fReadPipe, 845 device->fReadBuffer, device->fReadBufferSize, 846 device->ReadCallbackFunction, data); 847 if (status < B_OK) { 848 TRACE_ALWAYS("device thread: queueing failed with error: 0x%08x\n", status); 849 break; 850 } 851 852 status = acquire_sem_etc(device->fDoneRead, 1, B_CAN_INTERRUPT, 0); 853 if (status < B_OK) { 854 TRACE_ALWAYS("device thread: failed to get read done sem 0x%08x\n", status); 855 break; 856 } 857 858 if (device->fStatusRead != B_OK) { 859 TRACE("device thread: device status error 0x%08x\n", 860 device->fStatusRead); 861 if (gUSBModule->clear_feature(device->fReadPipe, 862 USB_FEATURE_ENDPOINT_HALT) != B_OK) { 863 TRACE_ALWAYS("device thread: failed to clear halt feature\n"); 864 break; 865 } 866 } 867 868 char *buffer = device->fReadBuffer; 869 size_t readLength = device->fActualLengthRead; 870 device->OnRead(&buffer, &readLength); 871 if (readLength == 0) 872 continue; 873 874 ddrover *ddr = gTTYModule->ddrstart(NULL); 875 if (!ddr) { 876 TRACE_ALWAYS("device thread: ddrstart problem\n"); 877 return B_NO_MEMORY; 878 } 879 880 while (device->fInputStopped) 881 snooze(100); 882 883 gTTYModule->ttyilock(&device->fTTY, ddr, true); 884 for (size_t i = 0; i < readLength; i++) 885 gTTYModule->ttyin(&device->fTTY, ddr, buffer[i]); 886 887 gTTYModule->ttyilock(&device->fTTY, ddr, false); 888 gTTYModule->ddrdone(ddr); 889 } 890 891 #endif 892 return B_OK; 893 } 894 895 896 status_t 897 SerialDevice::_WriteToDevice() 898 { 899 char *buffer = &fWriteBuffer[fWriteBufferIn]; 900 size_t bytesLeft = DEF_BUFFER_SIZE - atomic_get(&fWriteBufferAvail); 901 bytesLeft = MIN(bytesLeft, DEF_BUFFER_SIZE - fWriteBufferIn); 902 TRACE("%s: in %d left %d\n", __FUNCTION__, fWriteBufferIn, bytesLeft); 903 status_t status = gTTYModule->tty_read(fDeviceTTYCookie, buffer, 904 &bytesLeft); 905 TRACE("%s: tty_read: %d\n", __FUNCTION__, bytesLeft); 906 if (status != B_OK) { 907 TRACE_ALWAYS("write to device: failed to read from TTY: %s\n", 908 strerror(status)); 909 return status; 910 } 911 fWriteBufferIn += bytesLeft; 912 fWriteBufferIn %= DEF_BUFFER_SIZE; 913 atomic_add(&fWriteBufferAvail, bytesLeft); 914 915 // XXX: WTF: this ought to be done by the tty module calling service_func! 916 // enable irqs 917 Service(fMasterTTY, TTYOSTART, NULL, 0); 918 919 status = acquire_sem_etc(fWriteBufferSem, 1, B_CAN_INTERRUPT, 0); 920 if (status != B_OK) { 921 TRACE_ALWAYS("write to device: failed to acquire sem: %s\n", 922 strerror(status)); 923 return status; 924 } 925 return B_OK; 926 } 927 928 929 void 930 SerialDevice::ReadCallbackFunction(void *cookie, int32 status, void *data, 931 uint32 actualLength) 932 { 933 TRACE_FUNCALLS("read callback: cookie: 0x%08x status: 0x%08x data: 0x%08x len: %lu\n", 934 cookie, status, data, actualLength); 935 936 SerialDevice *device = (SerialDevice *)cookie; 937 device->fActualLengthRead = actualLength; 938 device->fStatusRead = status; 939 release_sem_etc(device->fDoneRead, 1, B_DO_NOT_RESCHEDULE); 940 } 941 942 943 void 944 SerialDevice::WriteCallbackFunction(void *cookie, int32 status, void *data, 945 uint32 actualLength) 946 { 947 TRACE_FUNCALLS("write callback: cookie: 0x%08x status: 0x%08x data: 0x%08x len: %lu\n", 948 cookie, status, data, actualLength); 949 950 SerialDevice *device = (SerialDevice *)cookie; 951 device->fActualLengthWrite = actualLength; 952 device->fStatusWrite = status; 953 release_sem_etc(device->fDoneWrite, 1, B_DO_NOT_RESCHEDULE); 954 } 955 956 957 void 958 SerialDevice::InterruptCallbackFunction(void *cookie, int32 status, 959 void *data, uint32 actualLength) 960 { 961 TRACE_FUNCALLS("interrupt callback: cookie: 0x%08x status: 0x%08x data: 0x%08x len: %lu\n", 962 cookie, status, data, actualLength); 963 964 SerialDevice *device = (SerialDevice *)cookie; 965 device->fActualLengthInterrupt = actualLength; 966 device->fStatusInterrupt = status; 967 968 // ToDo: maybe handle those somehow? 969 970 if (status == B_OK && !device->fDeviceRemoved) { 971 #if 0 972 status = gUSBModule->queue_interrupt(device->fControlPipe, 973 device->fInterruptBuffer, device->fInterruptBufferSize, 974 device->InterruptCallbackFunction, device); 975 #endif 976 } 977 } 978 979 980 981 #if 0 982 SerialDevice * 983 SerialDevice::MakeDevice(usb_device device, uint16 vendorID, 984 uint16 productID) 985 { 986 const char *description = NULL; 987 988 switch (vendorID) { 989 case VENDOR_IODATA: 990 case VENDOR_ATEN: 991 case VENDOR_TDK: 992 case VENDOR_RATOC: 993 case VENDOR_PROLIFIC: 994 case VENDOR_ELECOM: 995 case VENDOR_SOURCENEXT: 996 case VENDOR_HAL: 997 { 998 switch (productID) { 999 case PRODUCT_PROLIFIC_RSAQ2: description = "PL2303 Serial adapter (IODATA USB-RSAQ2)"; break; 1000 case PRODUCT_IODATA_USBRSAQ: description = "I/O Data USB serial adapter USB-RSAQ1"; break; 1001 case PRODUCT_ATEN_UC232A: description = "Aten Serial adapter"; break; 1002 case PRODUCT_TDK_UHA6400: description = "TDK USB-PHS Adapter UHA6400"; break; 1003 case PRODUCT_RATOC_REXUSB60: description = "Ratoc USB serial adapter REX-USB60"; break; 1004 case PRODUCT_PROLIFIC_PL2303: description = "PL2303 Serial adapter (ATEN/IOGEAR UC232A)"; break; 1005 case PRODUCT_ELECOM_UCSGT: description = "Elecom UC-SGT"; break; 1006 case PRODUCT_SOURCENEXT_KEIKAI8: description = "SOURCENEXT KeikaiDenwa 8"; break; 1007 case PRODUCT_SOURCENEXT_KEIKAI8_CHG: description = "SOURCENEXT KeikaiDenwa 8 with charger"; break; 1008 case PRODUCT_HAL_IMR001: description = "HAL Corporation Crossam2+USB"; break; 1009 } 1010 1011 if (!description) 1012 break; 1013 1014 return new(std::nothrow) ProlificDevice(device, vendorID, productID, description); 1015 } 1016 1017 case VENDOR_FTDI: 1018 { 1019 switch (productID) { 1020 case PRODUCT_FTDI_8U100AX: description = "FTDI 8U100AX serial converter"; break; 1021 case PRODUCT_FTDI_8U232AM: description = "FTDI 8U232AM serial converter"; break; 1022 } 1023 1024 if (!description) 1025 break; 1026 1027 return new(std::nothrow) FTDIDevice(device, vendorID, productID, description); 1028 } 1029 1030 case VENDOR_PALM: 1031 case VENDOR_KLSI: 1032 { 1033 switch (productID) { 1034 case PRODUCT_PALM_CONNECT: description = "PalmConnect RS232"; break; 1035 case PRODUCT_KLSI_KL5KUSB105D: description = "KLSI KL5KUSB105D"; break; 1036 } 1037 1038 if (!description) 1039 break; 1040 1041 return new(std::nothrow) KLSIDevice(device, vendorID, productID, description); 1042 } 1043 } 1044 1045 return new(std::nothrow) ACMDevice(device, vendorID, productID, "CDC ACM compatible device"); 1046 } 1047 #endif 1048 1049 1050 uint8 1051 SerialDevice::ReadReg8(int reg) 1052 { 1053 uint8 ret; 1054 switch (fBus) { 1055 case B_ISA_BUS: 1056 ret = gISAModule->read_io_8(IOBase() + reg); 1057 break; 1058 case B_PCI_BUS: 1059 ret = gPCIModule->read_io_8(IOBase() + reg); 1060 break; 1061 default: 1062 TRACE_ALWAYS("%s: unknown bus!\n", __FUNCTION__); 1063 ret = 0; 1064 //XXX:pcmcia ? 1065 } 1066 TRACE/*_ALWAYS*/("RR8(%d) = %d [%02x]\n", reg, ret, ret); 1067 //spin(1000); 1068 return ret; 1069 } 1070 1071 void 1072 SerialDevice::WriteReg8(int reg, uint8 value) 1073 { 1074 // TRACE_ALWAYS("WR8(0x%04x+%d, %d [0x%x])\n", IOBase(), reg, value, value); 1075 TRACE/*_ALWAYS*/("WR8(%d, %d [0x%x])\n", reg, value, value); 1076 switch (fBus) { 1077 case B_ISA_BUS: 1078 gISAModule->write_io_8(IOBase() + reg, value); 1079 break; 1080 case B_PCI_BUS: 1081 gPCIModule->write_io_8(IOBase() + reg, value); 1082 break; 1083 default: 1084 TRACE_ALWAYS("%s: unknown bus!\n", __FUNCTION__); 1085 //XXX:pcmcia ? 1086 } 1087 //spin(10000); 1088 } 1089 1090 1091 void 1092 SerialDevice::OrReg8(int reg, uint8 value) 1093 { 1094 WriteReg8(reg, ReadReg8(reg) | value); 1095 } 1096 1097 1098 void 1099 SerialDevice::AndReg8(int reg, uint8 value) 1100 { 1101 WriteReg8(reg, ReadReg8(reg) & value); 1102 } 1103 1104 1105 void 1106 SerialDevice::MaskReg8(int reg, uint8 value) 1107 { 1108 WriteReg8(reg, ReadReg8(reg) & ~value); 1109 } 1110