1 /* 2 * Copyright (c) 2007-2008 by Michael Lotz 3 * Heavily based on the original usb_serial driver which is: 4 * 5 * Copyright (c) 2003 by Siarzhuk Zharski <imker@gmx.li> 6 * Distributed under the terms of the MIT License. 7 */ 8 #include "SerialDevice.h" 9 #include "USB3.h" 10 11 #include "ACM.h" 12 #include "FTDI.h" 13 #include "KLSI.h" 14 #include "Prolific.h" 15 16 SerialDevice::SerialDevice(usb_device device, uint16 vendorID, 17 uint16 productID, const char *description) 18 : fDevice(device), 19 fVendorID(vendorID), 20 fProductID(productID), 21 fDescription(description), 22 fControlPipe(0), 23 fReadPipe(0), 24 fWritePipe(0), 25 fBufferArea(-1), 26 fReadBuffer(NULL), 27 fReadBufferSize(0), 28 fWriteBuffer(NULL), 29 fWriteBufferSize(0), 30 fInterruptBuffer(NULL), 31 fInterruptBufferSize(0), 32 fDoneRead(-1), 33 fDoneWrite(-1), 34 fControlOut(0), 35 fInputStopped(false), 36 fDeviceThread(-1), 37 fStopDeviceThread(false) 38 { 39 memset(&fTTYFile, 0, sizeof(ttyfile)); 40 memset(&fTTY, 0, sizeof(tty)); 41 } 42 43 44 SerialDevice::~SerialDevice() 45 { 46 fStopDeviceThread = true; 47 gUSBModule->cancel_queued_transfers(fReadPipe); 48 gUSBModule->cancel_queued_transfers(fWritePipe); 49 gUSBModule->cancel_queued_transfers(fControlPipe); 50 51 if (fDoneRead >= B_OK) 52 delete_sem(fDoneRead); 53 if (fDoneWrite >= B_OK) 54 delete_sem(fDoneWrite); 55 56 int32 result = B_OK; 57 wait_for_thread(fDeviceThread, &result); 58 59 if (fBufferArea >= B_OK) 60 delete_area(fBufferArea); 61 62 benaphore_destroy(&fReadLock); 63 benaphore_destroy(&fWriteLock); 64 } 65 66 67 status_t 68 SerialDevice::Init() 69 { 70 fDoneRead = create_sem(0, "usb_serial:done_read"); 71 fDoneWrite = create_sem(0, "usb_serial:done_write"); 72 benaphore_init(&fReadLock, "usb_serial:read_lock"); 73 benaphore_init(&fWriteLock, "usb_serial:write_lock"); 74 75 fReadBufferSize = fWriteBufferSize = ROUNDUP(DEF_BUFFER_SIZE, 16); 76 fInterruptBufferSize = 16; 77 78 size_t totalBuffers = fReadBufferSize + fWriteBufferSize + fInterruptBufferSize; 79 fBufferArea = create_area("usb_serial:buffers_area", (void **)&fReadBuffer, 80 B_ANY_KERNEL_ADDRESS, ROUNDUP(totalBuffers, B_PAGE_SIZE), B_CONTIGUOUS, 81 B_READ_AREA | B_WRITE_AREA); 82 83 fWriteBuffer = fReadBuffer + fReadBufferSize; 84 fInterruptBuffer = fWriteBuffer + fWriteBufferSize; 85 return B_OK; 86 } 87 88 89 void 90 SerialDevice::SetControlPipe(usb_pipe handle) 91 { 92 fControlPipe = handle; 93 } 94 95 96 void 97 SerialDevice::SetReadPipe(usb_pipe handle) 98 { 99 fReadPipe = handle; 100 } 101 102 103 void 104 SerialDevice::SetWritePipe(usb_pipe handle) 105 { 106 fWritePipe = handle; 107 } 108 109 110 void 111 SerialDevice::SetModes() 112 { 113 struct termios tios; 114 memcpy(&tios, &fTTY.t, sizeof(struct termios)); 115 uint16 newControl = fControlOut; 116 TRACE_FUNCRES(trace_termios, &tios); 117 118 static uint32 baudRates[] = { 119 0x00000000, //B0 120 0x00000032, //B50 121 0x0000004B, //B75 122 0x0000006E, //B110 123 0x00000086, //B134 124 0x00000096, //B150 125 0x000000C8, //B200 126 0x0000012C, //B300 127 0x00000258, //B600 128 0x000004B0, //B1200 129 0x00000708, //B1800 130 0x00000960, //B2400 131 0x000012C0, //B4800 132 0x00002580, //B9600 133 0x00004B00, //B19200 134 0x00009600, //B38400 135 0x0000E100, //B57600 136 0x0001C200, //B115200 137 0x00038400, //B230400 138 0x00070800, //460800 139 0x000E1000, //921600 140 }; 141 142 uint32 baudCount = sizeof(baudRates) / sizeof(baudRates[0]); 143 uint32 baudIndex = tios.c_cflag & CBAUD; 144 if (baudIndex > baudCount) 145 baudIndex = baudCount - 1; 146 147 usb_serial_line_coding lineCoding; 148 lineCoding.speed = baudRates[baudIndex]; 149 lineCoding.stopbits = (tios.c_cflag & CSTOPB) ? LC_STOP_BIT_2 : LC_STOP_BIT_1; 150 151 if (tios.c_cflag & PARENB) { 152 lineCoding.parity = LC_PARITY_EVEN; 153 if (tios.c_cflag & PARODD) 154 lineCoding.parity = LC_PARITY_ODD; 155 } else 156 lineCoding.parity = LC_PARITY_NONE; 157 158 lineCoding.databits = (tios.c_cflag & CS8) ? 8 : 7; 159 160 if (lineCoding.speed == 0) { 161 newControl &= 0xfffffffe; 162 lineCoding.speed = fLineCoding.speed; 163 } else 164 newControl = CLS_LINE_DTR; 165 166 if (fControlOut != newControl) { 167 fControlOut = newControl; 168 TRACE("newctrl send to modem: 0x%08x\n", newControl); 169 SetControlLineState(newControl); 170 } 171 172 if (memcmp(&lineCoding, &fLineCoding, sizeof(usb_serial_line_coding)) != 0) { 173 fLineCoding.speed = lineCoding.speed; 174 fLineCoding.stopbits = lineCoding.stopbits; 175 fLineCoding.databits = lineCoding.databits; 176 fLineCoding.parity = lineCoding.parity; 177 TRACE("send to modem: speed %d sb: 0x%08x db: 0x%08x parity: 0x%08x\n", 178 fLineCoding.speed, fLineCoding.stopbits, fLineCoding.databits, 179 fLineCoding.parity); 180 SetLineCoding(&fLineCoding); 181 } 182 } 183 184 185 bool 186 SerialDevice::Service(struct tty *ptty, struct ddrover *ddr, uint flags) 187 { 188 if (&fTTY != ptty) 189 return false; 190 191 if (flags <= TTYGETSIGNALS) { 192 switch (flags) { 193 case TTYENABLE: 194 TRACE("TTYENABLE\n"); 195 gTTYModule->ttyhwsignal(ptty, ddr, TTYHWDCD, false); 196 gTTYModule->ttyhwsignal(ptty, ddr, TTYHWCTS, true); 197 fControlOut = CLS_LINE_DTR | CLS_LINE_RTS; 198 SetControlLineState(fControlOut); 199 break; 200 201 case TTYDISABLE: 202 TRACE("TTYDISABLE\n"); 203 gTTYModule->ttyhwsignal(ptty, ddr, TTYHWDCD, false); 204 fControlOut = 0x0; 205 SetControlLineState(fControlOut); 206 break; 207 208 case TTYISTOP: 209 TRACE("TTYISTOP\n"); 210 fInputStopped = true; 211 gTTYModule->ttyhwsignal(ptty, ddr, TTYHWCTS, false); 212 break; 213 214 case TTYIRESUME: 215 TRACE("TTYIRESUME\n"); 216 gTTYModule->ttyhwsignal(ptty, ddr, TTYHWCTS, true); 217 fInputStopped = false; 218 break; 219 220 case TTYGETSIGNALS: 221 TRACE("TTYGETSIGNALS\n"); 222 gTTYModule->ttyhwsignal(ptty, ddr, TTYHWDCD, true); 223 gTTYModule->ttyhwsignal(ptty, ddr, TTYHWCTS, true); 224 gTTYModule->ttyhwsignal(ptty, ddr, TTYHWDSR, false); 225 gTTYModule->ttyhwsignal(ptty, ddr, TTYHWRI, false); 226 break; 227 228 case TTYSETMODES: 229 TRACE("TTYSETMODES\n"); 230 SetModes(); 231 break; 232 233 case TTYOSTART: 234 case TTYOSYNC: 235 case TTYSETBREAK: 236 case TTYCLRBREAK: 237 case TTYSETDTR: 238 case TTYCLRDTR: 239 TRACE("TTY other\n"); 240 break; 241 } 242 243 return true; 244 } 245 246 return false; 247 } 248 249 250 status_t 251 SerialDevice::Open(uint32 flags) 252 { 253 gTTYModule->ttyinit(&fTTY, true); 254 fTTYFile.tty = &fTTY; 255 fTTYFile.flags = flags; 256 ResetDevice(); 257 258 struct ddrover *ddr = gTTYModule->ddrstart(NULL); 259 if (!ddr) 260 return B_NO_MEMORY; 261 262 gTTYModule->ddacquire(ddr, &gSerialDomain); 263 status_t status = gTTYModule->ttyopen(&fTTYFile, ddr, usb_serial_service); 264 gTTYModule->ddrdone(ddr); 265 266 if (status < B_OK) { 267 TRACE_ALWAYS("open: failed to open tty\n"); 268 return status; 269 } 270 271 fDeviceThread = spawn_kernel_thread(DeviceThread, "usb_serial device thread", 272 B_NORMAL_PRIORITY, this); 273 274 if (fDeviceThread < B_OK) { 275 TRACE_ALWAYS("open: failed to spawn kernel thread\n"); 276 return fDeviceThread; 277 } 278 279 resume_thread(fDeviceThread); 280 281 fControlOut = CLS_LINE_DTR | CLS_LINE_RTS; 282 SetControlLineState(fControlOut); 283 284 status = gUSBModule->queue_interrupt(fControlPipe, fInterruptBuffer, 285 fInterruptBufferSize, InterruptCallbackFunction, this); 286 if (status < B_OK) 287 TRACE_ALWAYS("failed to queue initial interrupt\n"); 288 return status; 289 } 290 291 292 status_t 293 SerialDevice::Read(char *buffer, size_t *numBytes) 294 { 295 struct ddrover *ddr = gTTYModule->ddrstart(NULL); 296 if (!ddr) { 297 *numBytes = 0; 298 return B_NO_MEMORY; 299 } 300 301 status_t status = benaphore_lock(&fReadLock); 302 if (status != B_OK) { 303 TRACE_ALWAYS("read: failed to get read lock\n"); 304 *numBytes = 0; 305 return status; 306 } 307 308 status = gTTYModule->ttyread(&fTTYFile, ddr, buffer, numBytes); 309 gTTYModule->ddrdone(ddr); 310 311 benaphore_unlock(&fReadLock); 312 return status; 313 } 314 315 316 status_t 317 SerialDevice::Write(const char *buffer, size_t *numBytes) 318 { 319 size_t bytesLeft = *numBytes; 320 *numBytes = 0; 321 322 status_t status = benaphore_lock(&fWriteLock); 323 if (status != B_OK) { 324 TRACE_ALWAYS("write: failed to get write lock\n"); 325 return status; 326 } 327 328 while (bytesLeft > 0) { 329 size_t length = MIN(bytesLeft, fWriteBufferSize); 330 OnWrite(buffer, &length); 331 332 status = gUSBModule->queue_bulk(fWritePipe, fWriteBuffer, 333 length, WriteCallbackFunction, this); 334 if (status < B_OK) { 335 TRACE_ALWAYS("write: queueing failed with status 0x%08x\n", status); 336 break; 337 } 338 339 status = acquire_sem_etc(fDoneWrite, 1, B_CAN_INTERRUPT, 0); 340 if (status < B_OK) { 341 TRACE_ALWAYS("write: failed to get write done sem 0x%08x\n", status); 342 break; 343 } 344 345 if (fStatusWrite != B_OK) { 346 TRACE("write: device status error 0x%08x\n", fStatusWrite); 347 status = gUSBModule->clear_feature(fWritePipe, 348 USB_FEATURE_ENDPOINT_HALT); 349 if (status < B_OK) { 350 TRACE_ALWAYS("write: failed to clear device halt\n"); 351 status = B_ERROR; 352 break; 353 } 354 continue; 355 } 356 357 buffer += fActualLengthWrite; 358 *numBytes += fActualLengthWrite; 359 bytesLeft -= fActualLengthWrite; 360 } 361 362 benaphore_unlock(&fWriteLock); 363 return status; 364 } 365 366 367 status_t 368 SerialDevice::Control(uint32 op, void *arg, size_t length) 369 { 370 struct ddrover *ddr = gTTYModule->ddrstart(NULL); 371 if (!ddr) 372 return B_NO_MEMORY; 373 374 status_t status = gTTYModule->ttycontrol(&fTTYFile, ddr, op, arg, length); 375 gTTYModule->ddrdone(ddr); 376 return status; 377 } 378 379 380 status_t 381 SerialDevice::Select(uint8 event, uint32 ref, selectsync *sync) 382 { 383 struct ddrover *ddr = gTTYModule->ddrstart(NULL); 384 if (!ddr) 385 return B_NO_MEMORY; 386 387 status_t status = gTTYModule->ttyselect(&fTTYFile, ddr, event, ref, sync); 388 gTTYModule->ddrdone(ddr); 389 return status; 390 } 391 392 393 status_t 394 SerialDevice::DeSelect(uint8 event, selectsync *sync) 395 { 396 struct ddrover *ddr = gTTYModule->ddrstart(NULL); 397 if (!ddr) 398 return B_NO_MEMORY; 399 400 status_t status = gTTYModule->ttydeselect(&fTTYFile, ddr, event, sync); 401 gTTYModule->ddrdone(ddr); 402 return status; 403 } 404 405 406 status_t 407 SerialDevice::Close() 408 { 409 OnClose(); 410 411 gUSBModule->cancel_queued_transfers(fReadPipe); 412 gUSBModule->cancel_queued_transfers(fWritePipe); 413 gUSBModule->cancel_queued_transfers(fControlPipe); 414 415 struct ddrover *ddr = gTTYModule->ddrstart(NULL); 416 if (!ddr) 417 return B_NO_MEMORY; 418 419 status_t status = gTTYModule->ttyclose(&fTTYFile, ddr); 420 gTTYModule->ddrdone(ddr); 421 return status; 422 } 423 424 425 status_t 426 SerialDevice::Free() 427 { 428 struct ddrover *ddr = gTTYModule->ddrstart(NULL); 429 if (!ddr) 430 return B_NO_MEMORY; 431 432 status_t status = gTTYModule->ttyfree(&fTTYFile, ddr); 433 gTTYModule->ddrdone(ddr); 434 return status; 435 } 436 437 438 status_t 439 SerialDevice::AddDevice(const usb_configuration_info *config) 440 { 441 // default implementation - does nothing 442 return B_ERROR; 443 } 444 445 446 status_t 447 SerialDevice::ResetDevice() 448 { 449 // default implementation - does nothing 450 return B_OK; 451 } 452 453 454 status_t 455 SerialDevice::SetLineCoding(usb_serial_line_coding *coding) 456 { 457 // default implementation - does nothing 458 return B_OK; 459 } 460 461 462 status_t 463 SerialDevice::SetControlLineState(uint16 state) 464 { 465 // default implementation - does nothing 466 return B_OK; 467 } 468 469 470 void 471 SerialDevice::OnRead(char **buffer, size_t *numBytes) 472 { 473 // default implementation - does nothing 474 } 475 476 477 void 478 SerialDevice::OnWrite(const char *buffer, size_t *numBytes) 479 { 480 // default implementation - does nothing 481 } 482 483 484 void 485 SerialDevice::OnClose() 486 { 487 // default implementation - does nothing 488 } 489 490 491 int32 492 SerialDevice::DeviceThread(void *data) 493 { 494 SerialDevice *device = (SerialDevice *)data; 495 496 while (!device->fStopDeviceThread) { 497 status_t status = gUSBModule->queue_bulk(device->fReadPipe, 498 device->fReadBuffer, device->fReadBufferSize, 499 device->ReadCallbackFunction, data); 500 if (status < B_OK) { 501 TRACE_ALWAYS("device thread: queueing failed with error: 0x%08x\n", status); 502 break; 503 } 504 505 status = acquire_sem_etc(device->fDoneRead, 1, B_CAN_INTERRUPT, 0); 506 if (status < B_OK) { 507 TRACE_ALWAYS("device thread: failed to get read done sem 0x%08x\n", status); 508 break; 509 } 510 511 if (device->fStatusRead != B_OK) { 512 TRACE("device thread: device status error 0x%08x\n", 513 device->fStatusRead); 514 if (gUSBModule->clear_feature(device->fReadPipe, 515 USB_FEATURE_ENDPOINT_HALT) != B_OK) { 516 TRACE_ALWAYS("device thread: failed to clear halt feature\n"); 517 break; 518 } 519 } 520 521 char *buffer = device->fReadBuffer; 522 size_t readLength = device->fActualLengthRead; 523 device->OnRead(&buffer, &readLength); 524 if (readLength == 0) 525 continue; 526 527 ddrover *ddr = gTTYModule->ddrstart(NULL); 528 if (!ddr) { 529 TRACE_ALWAYS("device thread: ddrstart problem\n"); 530 return B_NO_MEMORY; 531 } 532 533 while (device->fInputStopped) 534 snooze(100); 535 536 gTTYModule->ttyilock(&device->fTTY, ddr, true); 537 for (size_t i = 0; i < readLength; i++) 538 gTTYModule->ttyin(&device->fTTY, ddr, buffer[i]); 539 540 gTTYModule->ttyilock(&device->fTTY, ddr, false); 541 gTTYModule->ddrdone(ddr); 542 } 543 544 return B_OK; 545 } 546 547 548 void 549 SerialDevice::ReadCallbackFunction(void *cookie, int32 status, void *data, 550 uint32 actualLength) 551 { 552 TRACE_FUNCALLS("read callback: cookie: 0x%08x status: 0x%08x data: 0x%08x len: %lu\n", 553 cookie, status, data, actualLength); 554 555 SerialDevice *device = (SerialDevice *)cookie; 556 device->fActualLengthRead = actualLength; 557 device->fStatusRead = status; 558 release_sem_etc(device->fDoneRead, 1, B_DO_NOT_RESCHEDULE); 559 } 560 561 562 void 563 SerialDevice::WriteCallbackFunction(void *cookie, int32 status, void *data, 564 uint32 actualLength) 565 { 566 TRACE_FUNCALLS("write callback: cookie: 0x%08x status: 0x%08x data: 0x%08x len: %lu\n", 567 cookie, status, data, actualLength); 568 569 SerialDevice *device = (SerialDevice *)cookie; 570 device->fActualLengthWrite = actualLength; 571 device->fStatusWrite = status; 572 release_sem_etc(device->fDoneWrite, 1, B_DO_NOT_RESCHEDULE); 573 } 574 575 576 void 577 SerialDevice::InterruptCallbackFunction(void *cookie, int32 status, 578 void *data, uint32 actualLength) 579 { 580 TRACE_FUNCALLS("interrupt callback: cookie: 0x%08x status: 0x%08x data: 0x%08x len: %lu\n", 581 cookie, status, data, actualLength); 582 583 SerialDevice *device = (SerialDevice *)cookie; 584 device->fActualLengthInterrupt = actualLength; 585 device->fStatusInterrupt = status; 586 587 // ToDo: maybe handle those somehow? 588 589 if (status == B_OK) { 590 status = gUSBModule->queue_interrupt(device->fControlPipe, 591 device->fInterruptBuffer, device->fInterruptBufferSize, 592 device->InterruptCallbackFunction, device); 593 } 594 } 595 596 597 598 SerialDevice * 599 SerialDevice::MakeDevice(usb_device device, uint16 vendorID, 600 uint16 productID) 601 { 602 const char *description = NULL; 603 604 switch (vendorID) { 605 case VENDOR_IODATA: 606 case VENDOR_ATEN: 607 case VENDOR_TDK: 608 case VENDOR_RATOC: 609 case VENDOR_PROLIFIC: 610 case VENDOR_ELECOM: 611 case VENDOR_SOURCENEXT: 612 case VENDOR_HAL: 613 { 614 switch (productID) { 615 case PRODUCT_PROLIFIC_RSAQ2: description = "PL2303 Serial adapter (IODATA USB-RSAQ2)"; break; 616 case PRODUCT_IODATA_USBRSAQ: description = "I/O Data USB serial adapter USB-RSAQ1"; break; 617 case PRODUCT_ATEN_UC232A: description = "Aten Serial adapter"; break; 618 case PRODUCT_TDK_UHA6400: description = "TDK USB-PHS Adapter UHA6400"; break; 619 case PRODUCT_RATOC_REXUSB60: description = "Ratoc USB serial adapter REX-USB60"; break; 620 case PRODUCT_PROLIFIC_PL2303: description = "PL2303 Serial adapter (ATEN/IOGEAR UC232A)"; break; 621 case PRODUCT_ELECOM_UCSGT: description = "Elecom UC-SGT"; break; 622 case PRODUCT_SOURCENEXT_KEIKAI8: description = "SOURCENEXT KeikaiDenwa 8"; break; 623 case PRODUCT_SOURCENEXT_KEIKAI8_CHG: description = "SOURCENEXT KeikaiDenwa 8 with charger"; break; 624 case PRODUCT_HAL_IMR001: description = "HAL Corporation Crossam2+USB"; break; 625 } 626 627 if (!description) 628 break; 629 630 return new ProlificDevice(device, vendorID, productID, description); 631 } 632 633 case VENDOR_FTDI: 634 { 635 switch (productID) { 636 case PRODUCT_FTDI_8U100AX: description = "FTDI 8U100AX serial converter"; break; 637 case PRODUCT_FTDI_8U232AM: description = "FTDI 8U232AM serial converter"; break; 638 } 639 640 if (!description) 641 break; 642 643 return new FTDIDevice(device, vendorID, productID, description); 644 } 645 646 case VENDOR_PALM: 647 case VENDOR_KLSI: 648 { 649 switch (productID) { 650 case PRODUCT_PALM_CONNECT: description = "PalmConnect RS232"; break; 651 case PRODUCT_KLSI_KL5KUSB105D: description = "KLSI KL5KUSB105D"; break; 652 } 653 654 if (!description) 655 break; 656 657 return new KLSIDevice(device, vendorID, productID, description); 658 } 659 } 660 661 return new ACMDevice(device, vendorID, productID, "CDC ACM compatible device"); 662 } 663