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 * Authors: 9 * Alexander von Gluck IV, kallisti5@unixzen.com 10 */ 11 12 13 #include <new> 14 15 #include "SerialDevice.h" 16 #include "USB3.h" 17 18 #include "ACM.h" 19 #include "FTDI.h" 20 #include "KLSI.h" 21 #include "Option.h" 22 #include "Prolific.h" 23 #include "Silicon.h" 24 #include "WinChipHead.h" 25 26 #include <sys/ioctl.h> 27 28 29 SerialDevice::SerialDevice(usb_device device, uint16 vendorID, 30 uint16 productID, const char *description) 31 : fDevice(device), 32 fVendorID(vendorID), 33 fProductID(productID), 34 fDescription(description), 35 fDeviceOpen(false), 36 fDeviceRemoved(false), 37 fControlPipe(0), 38 fReadPipe(0), 39 fWritePipe(0), 40 fBufferArea(-1), 41 fReadBuffer(NULL), 42 fReadBufferSize(ROUNDUP(DEF_BUFFER_SIZE, 16)), 43 fOutputBuffer(NULL), 44 fOutputBufferSize(ROUNDUP(DEF_BUFFER_SIZE, 16)), 45 fWriteBuffer(NULL), 46 fWriteBufferSize(ROUNDUP(DEF_BUFFER_SIZE, 16)), 47 fInterruptBuffer(NULL), 48 fInterruptBufferSize(16), 49 fDoneRead(-1), 50 fDoneWrite(-1), 51 fControlOut(0), 52 fInputStopped(false), 53 fMasterTTY(NULL), 54 fSlaveTTY(NULL), 55 fSystemTTYCookie(NULL), 56 fDeviceTTYCookie(NULL), 57 fInputThread(-1), 58 fStopThreads(false) 59 { 60 memset(&fTTYConfig, 0, sizeof(termios)); 61 fTTYConfig.c_cflag = B9600 | CS8 | CREAD; 62 } 63 64 65 SerialDevice::~SerialDevice() 66 { 67 Removed(); 68 69 if (fDoneRead >= 0) 70 delete_sem(fDoneRead); 71 if (fDoneWrite >= 0) 72 delete_sem(fDoneWrite); 73 74 if (fBufferArea >= 0) 75 delete_area(fBufferArea); 76 } 77 78 79 status_t 80 SerialDevice::Init() 81 { 82 fDoneRead = create_sem(0, "usb_serial:done_read"); 83 if (fDoneRead < 0) 84 return fDoneRead; 85 86 fDoneWrite = create_sem(0, "usb_serial:done_write"); 87 if (fDoneWrite < 0) 88 return fDoneWrite; 89 90 size_t totalBuffers = fReadBufferSize + fOutputBufferSize + fWriteBufferSize 91 + fInterruptBufferSize; 92 fBufferArea = create_area("usb_serial:buffers_area", (void **)&fReadBuffer, 93 B_ANY_KERNEL_ADDRESS, ROUNDUP(totalBuffers, B_PAGE_SIZE), B_CONTIGUOUS, 94 B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA); 95 if (fBufferArea < 0) 96 return fBufferArea; 97 98 fOutputBuffer = fReadBuffer + fReadBufferSize; 99 fWriteBuffer = fOutputBuffer + fOutputBufferSize; 100 fInterruptBuffer = fWriteBuffer + fWriteBufferSize; 101 return B_OK; 102 } 103 104 105 void 106 SerialDevice::SetControlPipe(usb_pipe handle) 107 { 108 fControlPipe = handle; 109 } 110 111 112 void 113 SerialDevice::SetReadPipe(usb_pipe handle) 114 { 115 fReadPipe = handle; 116 } 117 118 119 void 120 SerialDevice::SetWritePipe(usb_pipe handle) 121 { 122 fWritePipe = handle; 123 } 124 125 126 inline int32 127 baud_index_to_speed(int index) 128 { 129 switch (index) { 130 case B0: return 0; 131 case B50: return 50; 132 case B75: return 75; 133 case B110: return 110; 134 case B134: return 134; 135 case B150: return 150; 136 case B200: return 200; 137 case B300: return 300; 138 case B600: return 600; 139 case B1200: return 1200; 140 case B1800: return 1800; 141 case B2400: return 2400; 142 case B4800: return 4800; 143 case B9600: return 9600; 144 case B19200: return 19200; 145 case B31250: return 31250; 146 case B38400: return 38400; 147 case B57600: return 57600; 148 case B115200: return 115200; 149 case B230400: return 230400; 150 } 151 152 TRACE_ALWAYS("invalid baud index %d\n", index); 153 return -1; 154 } 155 156 157 void 158 SerialDevice::SetModes(struct termios *tios) 159 { 160 TRACE_FUNCRES(trace_termios, tios); 161 162 uint8 baud = tios->c_cflag & CBAUD; 163 int32 speed = baud_index_to_speed(baud); 164 if (speed < 0) { 165 baud = CBAUD; 166 speed = tios->c_ospeed; 167 } 168 169 // update our master config in full 170 memcpy(&fTTYConfig, tios, sizeof(termios)); 171 fTTYConfig.c_cflag &= ~CBAUD; 172 fTTYConfig.c_cflag |= baud; 173 174 // only apply the relevant parts to the device side 175 termios config; 176 memset(&config, 0, sizeof(termios)); 177 config.c_cflag = tios->c_cflag; 178 config.c_cflag &= ~CBAUD; 179 config.c_cflag |= baud; 180 181 // update the termios of the device side 182 gTTYModule->tty_control(fDeviceTTYCookie, TCSETA, &config, sizeof(termios)); 183 184 SetHardwareFlowControl((tios->c_cflag & CRTSCTS) != 0); 185 186 usb_cdc_line_coding lineCoding; 187 lineCoding.speed = speed; 188 lineCoding.stopbits = (tios->c_cflag & CSTOPB) 189 ? USB_CDC_LINE_CODING_2_STOPBITS : USB_CDC_LINE_CODING_1_STOPBIT; 190 191 if (tios->c_cflag & PARENB) { 192 lineCoding.parity = USB_CDC_LINE_CODING_EVEN_PARITY; 193 if (tios->c_cflag & PARODD) 194 lineCoding.parity = USB_CDC_LINE_CODING_ODD_PARITY; 195 } else 196 lineCoding.parity = USB_CDC_LINE_CODING_NO_PARITY; 197 198 lineCoding.databits = (tios->c_cflag & CS8) ? 8 : 7; 199 200 if (memcmp(&lineCoding, &fLineCoding, sizeof(usb_cdc_line_coding)) != 0) { 201 fLineCoding.speed = lineCoding.speed; 202 fLineCoding.stopbits = lineCoding.stopbits; 203 fLineCoding.databits = lineCoding.databits; 204 fLineCoding.parity = lineCoding.parity; 205 TRACE("send to modem: speed %d sb: 0x%08x db: 0x%08x parity: 0x%08x\n", 206 fLineCoding.speed, fLineCoding.stopbits, fLineCoding.databits, 207 fLineCoding.parity); 208 SetLineCoding(&fLineCoding); 209 } 210 } 211 212 213 bool 214 SerialDevice::Service(struct tty *tty, uint32 op, void *buffer, size_t length) 215 { 216 if (!fDeviceOpen) 217 return false; 218 219 if (tty != fMasterTTY) 220 return false; 221 222 switch (op) { 223 case TTYENABLE: 224 { 225 bool enable = *(bool *)buffer; 226 TRACE("TTYENABLE: %sable\n", enable ? "en" : "dis"); 227 228 gTTYModule->tty_hardware_signal(fSystemTTYCookie, TTYHWDCD, enable); 229 gTTYModule->tty_hardware_signal(fSystemTTYCookie, TTYHWCTS, enable); 230 231 fControlOut = enable ? USB_CDC_CONTROL_SIGNAL_STATE_DTR 232 | USB_CDC_CONTROL_SIGNAL_STATE_RTS : 0; 233 SetControlLineState(fControlOut); 234 return true; 235 } 236 237 case TTYISTOP: 238 fInputStopped = *(bool *)buffer; 239 TRACE("TTYISTOP: %sstopped\n", fInputStopped ? "" : "not "); 240 gTTYModule->tty_hardware_signal(fSystemTTYCookie, TTYHWCTS, 241 !fInputStopped); 242 return true; 243 244 case TTYGETSIGNALS: 245 TRACE("TTYGETSIGNALS\n"); 246 gTTYModule->tty_hardware_signal(fSystemTTYCookie, TTYHWDCD, 247 (fControlOut & (USB_CDC_CONTROL_SIGNAL_STATE_DTR 248 | USB_CDC_CONTROL_SIGNAL_STATE_RTS)) != 0); 249 gTTYModule->tty_hardware_signal(fSystemTTYCookie, TTYHWCTS, 250 !fInputStopped); 251 gTTYModule->tty_hardware_signal(fSystemTTYCookie, TTYHWDSR, false); 252 gTTYModule->tty_hardware_signal(fSystemTTYCookie, TTYHWRI, false); 253 return true; 254 255 case TTYSETMODES: 256 TRACE("TTYSETMODES\n"); 257 SetModes((struct termios *)buffer); 258 return true; 259 260 case TTYSETDTR: 261 case TTYSETRTS: 262 { 263 bool set = *(bool *)buffer; 264 uint8 bit = op == TTYSETDTR ? USB_CDC_CONTROL_SIGNAL_STATE_DTR 265 : USB_CDC_CONTROL_SIGNAL_STATE_RTS; 266 if (set) 267 fControlOut |= bit; 268 else 269 fControlOut &= ~bit; 270 271 SetControlLineState(fControlOut); 272 return true; 273 } 274 275 case TTYOSTART: 276 case TTYOSYNC: 277 case TTYSETBREAK: 278 case TTYFLUSH: 279 TRACE("TTY other\n"); 280 return true; 281 } 282 283 return false; 284 } 285 286 287 status_t 288 SerialDevice::Open(uint32 flags) 289 { 290 if (fDeviceOpen) 291 return B_BUSY; 292 293 if (fDeviceRemoved) 294 return B_DEV_NOT_READY; 295 296 fMasterTTY = gTTYModule->tty_create(usb_serial_service, NULL); 297 if (fMasterTTY == NULL) { 298 TRACE_ALWAYS("open: failed to init master tty\n"); 299 return B_NO_MEMORY; 300 } 301 302 fSlaveTTY = gTTYModule->tty_create(usb_serial_service, fMasterTTY); 303 if (fSlaveTTY == NULL) { 304 TRACE_ALWAYS("open: failed to init slave tty\n"); 305 gTTYModule->tty_destroy(fMasterTTY); 306 return B_NO_MEMORY; 307 } 308 309 fSystemTTYCookie = gTTYModule->tty_create_cookie(fMasterTTY, fSlaveTTY, 310 O_RDWR); 311 if (fSystemTTYCookie == NULL) { 312 TRACE_ALWAYS("open: failed to init system tty cookie\n"); 313 gTTYModule->tty_destroy(fMasterTTY); 314 gTTYModule->tty_destroy(fSlaveTTY); 315 return B_NO_MEMORY; 316 } 317 318 fDeviceTTYCookie = gTTYModule->tty_create_cookie(fSlaveTTY, fMasterTTY, 319 O_RDWR); 320 if (fDeviceTTYCookie == NULL) { 321 TRACE_ALWAYS("open: failed to init device tty cookie\n"); 322 gTTYModule->tty_destroy_cookie(fSystemTTYCookie); 323 gTTYModule->tty_destroy(fMasterTTY); 324 gTTYModule->tty_destroy(fSlaveTTY); 325 return B_NO_MEMORY; 326 } 327 328 ResetDevice(); 329 330 fStopThreads = false; 331 332 fInputThread = spawn_kernel_thread(_InputThread, 333 "usb_serial input thread", B_NORMAL_PRIORITY, this); 334 if (fInputThread < 0) { 335 TRACE_ALWAYS("open: failed to spawn input thread\n"); 336 return fInputThread; 337 } 338 339 resume_thread(fInputThread); 340 341 fControlOut = USB_CDC_CONTROL_SIGNAL_STATE_DTR 342 | USB_CDC_CONTROL_SIGNAL_STATE_RTS; 343 SetControlLineState(fControlOut); 344 345 status_t status = gUSBModule->queue_interrupt(fControlPipe, 346 fInterruptBuffer, fInterruptBufferSize, _InterruptCallbackFunction, 347 this); 348 if (status < B_OK) 349 TRACE_ALWAYS("failed to queue initial interrupt\n"); 350 351 // set our config (will propagate to the slave config as well in SetModes() 352 gTTYModule->tty_control(fSystemTTYCookie, TCSETA, &fTTYConfig, 353 sizeof(termios)); 354 355 fDeviceOpen = true; 356 return B_OK; 357 } 358 359 360 status_t 361 SerialDevice::Read(char *buffer, size_t *numBytes) 362 { 363 if (fDeviceRemoved) { 364 *numBytes = 0; 365 return B_DEV_NOT_READY; 366 } 367 368 return gTTYModule->tty_read(fSystemTTYCookie, buffer, numBytes); 369 } 370 371 372 status_t 373 SerialDevice::Write(const char *buffer, size_t *numBytes) 374 { 375 if (fDeviceRemoved) { 376 *numBytes = 0; 377 return B_DEV_NOT_READY; 378 } 379 380 size_t bytesLeft = *numBytes; 381 *numBytes = 0; 382 383 while (bytesLeft > 0) { 384 size_t length = MIN(bytesLeft, 256); 385 // TODO: This is an ugly hack; We use a small buffer size so that 386 // we don't overrun the tty line buffer and cause it to block. While 387 // that isn't a problem, we shouldn't just hardcode the value here. 388 389 status_t result = gTTYModule->tty_write(fSystemTTYCookie, buffer, 390 &length); 391 if (result != B_OK) { 392 TRACE_ALWAYS("failed to write to tty: %s\n", strerror(result)); 393 return result; 394 } 395 396 buffer += length; 397 *numBytes += length; 398 bytesLeft -= length; 399 400 while (true) { 401 // Write to the device as long as there's anything in the tty buffer 402 int readable = 0; 403 gTTYModule->tty_control(fDeviceTTYCookie, FIONREAD, &readable, 404 sizeof(readable)); 405 if (readable == 0) 406 break; 407 408 result = _WriteToDevice(); 409 if (result != B_OK) { 410 TRACE_ALWAYS("failed to write to device: %s\n", 411 strerror(result)); 412 return result; 413 } 414 } 415 } 416 417 if (*numBytes > 0) 418 return B_OK; 419 420 return B_ERROR; 421 } 422 423 424 status_t 425 SerialDevice::Control(uint32 op, void *arg, size_t length) 426 { 427 if (fDeviceRemoved) 428 return B_DEV_NOT_READY; 429 430 return gTTYModule->tty_control(fSystemTTYCookie, op, arg, length); 431 } 432 433 434 status_t 435 SerialDevice::Select(uint8 event, uint32 ref, selectsync *sync) 436 { 437 if (fDeviceRemoved) 438 return B_DEV_NOT_READY; 439 440 return gTTYModule->tty_select(fSystemTTYCookie, event, ref, sync); 441 } 442 443 444 status_t 445 SerialDevice::DeSelect(uint8 event, selectsync *sync) 446 { 447 if (fDeviceRemoved) 448 return B_DEV_NOT_READY; 449 450 return gTTYModule->tty_deselect(fSystemTTYCookie, event, sync); 451 } 452 453 454 status_t 455 SerialDevice::Close() 456 { 457 OnClose(); 458 459 fStopThreads = true; 460 fInputStopped = false; 461 fDeviceOpen = false; 462 463 if (!fDeviceRemoved) { 464 gUSBModule->cancel_queued_transfers(fReadPipe); 465 gUSBModule->cancel_queued_transfers(fWritePipe); 466 gUSBModule->cancel_queued_transfers(fControlPipe); 467 } 468 469 gTTYModule->tty_close_cookie(fSystemTTYCookie); 470 gTTYModule->tty_close_cookie(fDeviceTTYCookie); 471 472 int32 result = B_OK; 473 wait_for_thread(fInputThread, &result); 474 fInputThread = -1; 475 476 gTTYModule->tty_destroy_cookie(fSystemTTYCookie); 477 gTTYModule->tty_destroy_cookie(fDeviceTTYCookie); 478 479 gTTYModule->tty_destroy(fMasterTTY); 480 gTTYModule->tty_destroy(fSlaveTTY); 481 482 fMasterTTY = NULL; 483 fSlaveTTY = NULL; 484 fSystemTTYCookie = NULL; 485 fDeviceTTYCookie = NULL; 486 return B_OK; 487 } 488 489 490 status_t 491 SerialDevice::Free() 492 { 493 return B_OK; 494 } 495 496 497 void 498 SerialDevice::Removed() 499 { 500 if (fDeviceRemoved) 501 return; 502 503 // notifies us that the device was removed 504 fDeviceRemoved = true; 505 506 // we need to ensure that we do not use the device anymore 507 fStopThreads = true; 508 fInputStopped = false; 509 gUSBModule->cancel_queued_transfers(fReadPipe); 510 gUSBModule->cancel_queued_transfers(fWritePipe); 511 gUSBModule->cancel_queued_transfers(fControlPipe); 512 } 513 514 515 status_t 516 SerialDevice::AddDevice(const usb_configuration_info *config) 517 { 518 // default implementation - does nothing 519 return B_ERROR; 520 } 521 522 523 status_t 524 SerialDevice::ResetDevice() 525 { 526 // default implementation - does nothing 527 return B_OK; 528 } 529 530 531 status_t 532 SerialDevice::SetLineCoding(usb_cdc_line_coding *coding) 533 { 534 // default implementation - does nothing 535 return B_NOT_SUPPORTED; 536 } 537 538 539 status_t 540 SerialDevice::SetControlLineState(uint16 state) 541 { 542 // default implementation - does nothing 543 return B_NOT_SUPPORTED; 544 } 545 546 547 status_t 548 SerialDevice::SetHardwareFlowControl(bool enable) 549 { 550 // default implementation - does nothing 551 return B_NOT_SUPPORTED; 552 } 553 554 555 void 556 SerialDevice::OnRead(char **buffer, size_t *numBytes) 557 { 558 // default implementation - does nothing 559 } 560 561 562 void 563 SerialDevice::OnWrite(const char *buffer, size_t *numBytes, size_t *packetBytes) 564 { 565 memcpy(fWriteBuffer, buffer, *numBytes); 566 } 567 568 569 void 570 SerialDevice::OnClose() 571 { 572 // default implementation - does nothing 573 } 574 575 576 int32 577 SerialDevice::_InputThread(void *data) 578 { 579 SerialDevice *device = (SerialDevice *)data; 580 581 while (!device->fStopThreads) { 582 status_t status = gUSBModule->queue_bulk(device->fReadPipe, 583 device->fReadBuffer, device->fReadBufferSize, 584 device->_ReadCallbackFunction, data); 585 if (status < B_OK) { 586 TRACE_ALWAYS("input thread: queueing failed with error: 0x%08x\n", 587 status); 588 return status; 589 } 590 591 status = acquire_sem_etc(device->fDoneRead, 1, B_CAN_INTERRUPT, 0); 592 if (status < B_OK) { 593 TRACE_ALWAYS("input thread: failed to get read done sem 0x%08x\n", 594 status); 595 return status; 596 } 597 598 if (device->fStatusRead != B_OK) { 599 TRACE("input thread: device status error 0x%08x\n", 600 device->fStatusRead); 601 if (device->fStatusRead == B_DEV_STALLED 602 && gUSBModule->clear_feature(device->fReadPipe, 603 USB_FEATURE_ENDPOINT_HALT) != B_OK) { 604 TRACE_ALWAYS("input thread: failed to clear halt feature\n"); 605 return B_ERROR; 606 } 607 608 continue; 609 } 610 611 char *buffer = device->fReadBuffer; 612 size_t readLength = device->fActualLengthRead; 613 device->OnRead(&buffer, &readLength); 614 if (readLength == 0) 615 continue; 616 617 while (device->fInputStopped) 618 snooze(100); 619 620 status = gTTYModule->tty_write(device->fDeviceTTYCookie, buffer, 621 &readLength); 622 if (status != B_OK) { 623 TRACE_ALWAYS("input thread: failed to write into TTY\n"); 624 return status; 625 } 626 } 627 628 return B_OK; 629 } 630 631 632 status_t 633 SerialDevice::_WriteToDevice() 634 { 635 char *buffer = fOutputBuffer; 636 size_t bytesLeft = fOutputBufferSize; 637 status_t status = gTTYModule->tty_read(fDeviceTTYCookie, buffer, 638 &bytesLeft); 639 if (status != B_OK) { 640 TRACE_ALWAYS("write to device: failed to read from TTY: %s\n", 641 strerror(status)); 642 return status; 643 } 644 645 while (!fDeviceRemoved && bytesLeft > 0) { 646 size_t length = MIN(bytesLeft, fWriteBufferSize); 647 size_t packetLength = length; 648 OnWrite(buffer, &length, &packetLength); 649 650 status = gUSBModule->queue_bulk(fWritePipe, fWriteBuffer, packetLength, 651 _WriteCallbackFunction, this); 652 if (status != B_OK) { 653 TRACE_ALWAYS("write to device: queueing failed with status " 654 "0x%08x\n", status); 655 return status; 656 } 657 658 status = acquire_sem_etc(fDoneWrite, 1, B_CAN_INTERRUPT, 0); 659 if (status != B_OK) { 660 TRACE_ALWAYS("write to device: failed to get write done sem " 661 "0x%08x\n", status); 662 return status; 663 } 664 665 if (fStatusWrite != B_OK) { 666 TRACE("write to device: device status error 0x%08x\n", 667 fStatusWrite); 668 if (fStatusWrite == B_DEV_STALLED) { 669 status = gUSBModule->clear_feature(fWritePipe, 670 USB_FEATURE_ENDPOINT_HALT); 671 if (status != B_OK) { 672 TRACE_ALWAYS("write to device: failed to clear device " 673 "halt\n"); 674 return B_ERROR; 675 } 676 } 677 678 continue; 679 } 680 681 buffer += length; 682 bytesLeft -= length; 683 } 684 685 return B_OK; 686 } 687 688 689 void 690 SerialDevice::_ReadCallbackFunction(void *cookie, status_t status, void *data, 691 size_t actualLength) 692 { 693 TRACE_FUNCALLS("read callback: cookie: 0x%08x status: 0x%08x data: 0x%08x " 694 "length: %lu\n", cookie, status, data, actualLength); 695 696 SerialDevice *device = (SerialDevice *)cookie; 697 device->fActualLengthRead = actualLength; 698 device->fStatusRead = status; 699 release_sem_etc(device->fDoneRead, 1, B_DO_NOT_RESCHEDULE); 700 } 701 702 703 void 704 SerialDevice::_WriteCallbackFunction(void *cookie, status_t status, void *data, 705 size_t actualLength) 706 { 707 TRACE_FUNCALLS("write callback: cookie: 0x%08x status: 0x%08x data: 0x%08x " 708 "length: %lu\n", cookie, status, data, actualLength); 709 710 SerialDevice *device = (SerialDevice *)cookie; 711 device->fActualLengthWrite = actualLength; 712 device->fStatusWrite = status; 713 release_sem_etc(device->fDoneWrite, 1, B_DO_NOT_RESCHEDULE); 714 } 715 716 717 void 718 SerialDevice::_InterruptCallbackFunction(void *cookie, status_t status, 719 void *data, size_t actualLength) 720 { 721 TRACE_FUNCALLS("interrupt callback: cookie: 0x%08x status: 0x%08x data: " 722 "0x%08x len: %lu\n", cookie, status, data, actualLength); 723 724 SerialDevice *device = (SerialDevice *)cookie; 725 device->fActualLengthInterrupt = actualLength; 726 device->fStatusInterrupt = status; 727 728 // ToDo: maybe handle those somehow? 729 730 if (status == B_OK && !device->fDeviceRemoved) { 731 status = gUSBModule->queue_interrupt(device->fControlPipe, 732 device->fInterruptBuffer, device->fInterruptBufferSize, 733 device->_InterruptCallbackFunction, device); 734 } 735 } 736 737 738 SerialDevice * 739 SerialDevice::MakeDevice(usb_device device, uint16 vendorID, 740 uint16 productID) 741 { 742 // FTDI Serial Device 743 for (uint32 i = 0; i < sizeof(kFTDIDevices) 744 / sizeof(kFTDIDevices[0]); i++) { 745 if (vendorID == kFTDIDevices[i].vendorID 746 && productID == kFTDIDevices[i].productID) { 747 return new(std::nothrow) FTDIDevice(device, vendorID, productID, 748 kFTDIDevices[i].deviceName); 749 } 750 } 751 752 // KLSI Serial Device 753 for (uint32 i = 0; i < sizeof(kKLSIDevices) 754 / sizeof(kKLSIDevices[0]); i++) { 755 if (vendorID == kKLSIDevices[i].vendorID 756 && productID == kKLSIDevices[i].productID) { 757 return new(std::nothrow) KLSIDevice(device, vendorID, productID, 758 kKLSIDevices[i].deviceName); 759 } 760 } 761 762 // Prolific Serial Device 763 for (uint32 i = 0; i < sizeof(kProlificDevices) 764 / sizeof(kProlificDevices[0]); i++) { 765 if (vendorID == kProlificDevices[i].vendorID 766 && productID == kProlificDevices[i].productID) { 767 return new(std::nothrow) ProlificDevice(device, vendorID, productID, 768 kProlificDevices[i].deviceName); 769 } 770 } 771 772 // Silicon Serial Device 773 for (uint32 i = 0; i < sizeof(kSiliconDevices) 774 / sizeof(kSiliconDevices[0]); i++) { 775 if (vendorID == kSiliconDevices[i].vendorID 776 && productID == kSiliconDevices[i].productID) { 777 return new(std::nothrow) SiliconDevice(device, vendorID, productID, 778 kSiliconDevices[i].deviceName); 779 } 780 } 781 782 // WinChipHead Serial Device 783 for (uint32 i = 0; i < sizeof(kWCHDevices) 784 / sizeof(kWCHDevices[0]); i++) { 785 if (vendorID == kWCHDevices[i].vendorID 786 && productID == kWCHDevices[i].productID) { 787 return new(std::nothrow) WCHDevice(device, vendorID, productID, 788 kWCHDevices[i].deviceName); 789 } 790 } 791 792 // Option Serial Device 793 for (uint32 i = 0; i < sizeof(kOptionDevices) 794 / sizeof(kOptionDevices[0]); i++) { 795 if (vendorID == kOptionDevices[i].vendorID 796 && productID == kOptionDevices[i].productID) { 797 return new(std::nothrow) OptionDevice(device, vendorID, productID, 798 kOptionDevices[i].deviceName); 799 } 800 } 801 802 // Otherwise, return standard ACM device 803 return new(std::nothrow) ACMDevice(device, vendorID, productID, 804 "CDC ACM compatible device"); 805 } 806