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