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_READ_AREA | B_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 (tty != fMasterTTY) 216 return false; 217 218 switch (op) { 219 case TTYENABLE: 220 { 221 bool enable = *(bool *)buffer; 222 TRACE("TTYENABLE: %sable\n", enable ? "en" : "dis"); 223 224 gTTYModule->tty_hardware_signal(fSystemTTYCookie, TTYHWDCD, enable); 225 gTTYModule->tty_hardware_signal(fSystemTTYCookie, TTYHWCTS, enable); 226 227 fControlOut = enable ? USB_CDC_CONTROL_SIGNAL_STATE_DTR 228 | USB_CDC_CONTROL_SIGNAL_STATE_RTS : 0; 229 SetControlLineState(fControlOut); 230 return true; 231 } 232 233 case TTYISTOP: 234 fInputStopped = *(bool *)buffer; 235 TRACE("TTYISTOP: %sstopped\n", fInputStopped ? "" : "not "); 236 gTTYModule->tty_hardware_signal(fSystemTTYCookie, TTYHWCTS, 237 !fInputStopped); 238 return true; 239 240 case TTYGETSIGNALS: 241 TRACE("TTYGETSIGNALS\n"); 242 gTTYModule->tty_hardware_signal(fSystemTTYCookie, TTYHWDCD, 243 (fControlOut & (USB_CDC_CONTROL_SIGNAL_STATE_DTR 244 | USB_CDC_CONTROL_SIGNAL_STATE_RTS)) != 0); 245 gTTYModule->tty_hardware_signal(fSystemTTYCookie, TTYHWCTS, 246 !fInputStopped); 247 gTTYModule->tty_hardware_signal(fSystemTTYCookie, TTYHWDSR, false); 248 gTTYModule->tty_hardware_signal(fSystemTTYCookie, TTYHWRI, false); 249 return true; 250 251 case TTYSETMODES: 252 TRACE("TTYSETMODES\n"); 253 SetModes((struct termios *)buffer); 254 return true; 255 256 case TTYSETDTR: 257 case TTYSETRTS: 258 { 259 bool set = *(bool *)buffer; 260 uint8 bit = op == TTYSETDTR ? USB_CDC_CONTROL_SIGNAL_STATE_DTR 261 : USB_CDC_CONTROL_SIGNAL_STATE_RTS; 262 if (set) 263 fControlOut |= bit; 264 else 265 fControlOut &= ~bit; 266 267 SetControlLineState(fControlOut); 268 return true; 269 } 270 271 case TTYOSTART: 272 case TTYOSYNC: 273 case TTYSETBREAK: 274 TRACE("TTY other\n"); 275 return true; 276 } 277 278 return false; 279 } 280 281 282 status_t 283 SerialDevice::Open(uint32 flags) 284 { 285 if (fDeviceOpen) 286 return B_BUSY; 287 288 if (fDeviceRemoved) 289 return B_DEV_NOT_READY; 290 291 fMasterTTY = gTTYModule->tty_create(usb_serial_service, true); 292 if (fMasterTTY == NULL) { 293 TRACE_ALWAYS("open: failed to init master tty\n"); 294 return B_NO_MEMORY; 295 } 296 297 fSlaveTTY = gTTYModule->tty_create(usb_serial_service, false); 298 if (fSlaveTTY == NULL) { 299 TRACE_ALWAYS("open: failed to init slave tty\n"); 300 gTTYModule->tty_destroy(fMasterTTY); 301 return B_NO_MEMORY; 302 } 303 304 fSystemTTYCookie = gTTYModule->tty_create_cookie(fMasterTTY, fSlaveTTY, 305 O_RDWR); 306 if (fSystemTTYCookie == NULL) { 307 TRACE_ALWAYS("open: failed to init system tty cookie\n"); 308 gTTYModule->tty_destroy(fMasterTTY); 309 gTTYModule->tty_destroy(fSlaveTTY); 310 return B_NO_MEMORY; 311 } 312 313 fDeviceTTYCookie = gTTYModule->tty_create_cookie(fSlaveTTY, fMasterTTY, 314 O_RDWR); 315 if (fDeviceTTYCookie == NULL) { 316 TRACE_ALWAYS("open: failed to init device tty cookie\n"); 317 gTTYModule->tty_destroy_cookie(fSystemTTYCookie); 318 gTTYModule->tty_destroy(fMasterTTY); 319 gTTYModule->tty_destroy(fSlaveTTY); 320 return B_NO_MEMORY; 321 } 322 323 ResetDevice(); 324 325 fStopThreads = false; 326 327 fInputThread = spawn_kernel_thread(_InputThread, 328 "usb_serial input thread", B_NORMAL_PRIORITY, this); 329 if (fInputThread < 0) { 330 TRACE_ALWAYS("open: failed to spawn input thread\n"); 331 return fInputThread; 332 } 333 334 resume_thread(fInputThread); 335 336 fControlOut = USB_CDC_CONTROL_SIGNAL_STATE_DTR 337 | USB_CDC_CONTROL_SIGNAL_STATE_RTS; 338 SetControlLineState(fControlOut); 339 340 status_t status = gUSBModule->queue_interrupt(fControlPipe, 341 fInterruptBuffer, fInterruptBufferSize, _InterruptCallbackFunction, 342 this); 343 if (status < B_OK) 344 TRACE_ALWAYS("failed to queue initial interrupt\n"); 345 346 // set our config (will propagate to the slave config as well in SetModes() 347 gTTYModule->tty_control(fSystemTTYCookie, TCSETA, &fTTYConfig, 348 sizeof(termios)); 349 350 fDeviceOpen = true; 351 return B_OK; 352 } 353 354 355 status_t 356 SerialDevice::Read(char *buffer, size_t *numBytes) 357 { 358 if (fDeviceRemoved) { 359 *numBytes = 0; 360 return B_DEV_NOT_READY; 361 } 362 363 return gTTYModule->tty_read(fSystemTTYCookie, buffer, numBytes); 364 } 365 366 367 status_t 368 SerialDevice::Write(const char *buffer, size_t *numBytes) 369 { 370 if (fDeviceRemoved) { 371 *numBytes = 0; 372 return B_DEV_NOT_READY; 373 } 374 375 size_t bytesLeft = *numBytes; 376 *numBytes = 0; 377 378 while (bytesLeft > 0) { 379 size_t length = MIN(bytesLeft, 256); 380 // TODO: This is an ugly hack; We use a small buffer size so that 381 // we don't overrun the tty line buffer and cause it to block. While 382 // that isn't a problem, we shouldn't just hardcode the value here. 383 384 status_t result = gTTYModule->tty_write(fSystemTTYCookie, buffer, 385 &length); 386 if (result != B_OK) { 387 TRACE_ALWAYS("failed to write to tty: %s\n", strerror(result)); 388 return result; 389 } 390 391 buffer += length; 392 *numBytes += length; 393 bytesLeft -= length; 394 395 while (true) { 396 // Write to the device as long as there's anything in the tty buffer 397 int readable = 0; 398 gTTYModule->tty_control(fDeviceTTYCookie, FIONREAD, &readable, 399 sizeof(readable)); 400 if (readable == 0) 401 break; 402 403 result = _WriteToDevice(); 404 if (result != B_OK) { 405 TRACE_ALWAYS("failed to write to device: %s\n", 406 strerror(result)); 407 return result; 408 } 409 } 410 } 411 412 if (*numBytes > 0) 413 return B_OK; 414 415 return B_ERROR; 416 } 417 418 419 status_t 420 SerialDevice::Control(uint32 op, void *arg, size_t length) 421 { 422 if (fDeviceRemoved) 423 return B_DEV_NOT_READY; 424 425 return gTTYModule->tty_control(fSystemTTYCookie, op, arg, length); 426 } 427 428 429 status_t 430 SerialDevice::Select(uint8 event, uint32 ref, selectsync *sync) 431 { 432 if (fDeviceRemoved) 433 return B_DEV_NOT_READY; 434 435 return gTTYModule->tty_select(fSystemTTYCookie, event, ref, sync); 436 } 437 438 439 status_t 440 SerialDevice::DeSelect(uint8 event, selectsync *sync) 441 { 442 if (fDeviceRemoved) 443 return B_DEV_NOT_READY; 444 445 return gTTYModule->tty_deselect(fSystemTTYCookie, event, sync); 446 } 447 448 449 status_t 450 SerialDevice::Close() 451 { 452 OnClose(); 453 454 fStopThreads = true; 455 fInputStopped = false; 456 457 if (!fDeviceRemoved) { 458 gUSBModule->cancel_queued_transfers(fReadPipe); 459 gUSBModule->cancel_queued_transfers(fWritePipe); 460 gUSBModule->cancel_queued_transfers(fControlPipe); 461 } 462 463 gTTYModule->tty_close_cookie(fSystemTTYCookie); 464 gTTYModule->tty_close_cookie(fDeviceTTYCookie); 465 466 int32 result = B_OK; 467 wait_for_thread(fInputThread, &result); 468 fInputThread = -1; 469 470 gTTYModule->tty_destroy_cookie(fSystemTTYCookie); 471 gTTYModule->tty_destroy_cookie(fDeviceTTYCookie); 472 473 gTTYModule->tty_destroy(fMasterTTY); 474 gTTYModule->tty_destroy(fSlaveTTY); 475 476 fDeviceOpen = false; 477 return B_OK; 478 } 479 480 481 status_t 482 SerialDevice::Free() 483 { 484 return B_OK; 485 } 486 487 488 void 489 SerialDevice::Removed() 490 { 491 if (fDeviceRemoved) 492 return; 493 494 // notifies us that the device was removed 495 fDeviceRemoved = true; 496 497 // we need to ensure that we do not use the device anymore 498 fStopThreads = true; 499 fInputStopped = false; 500 gUSBModule->cancel_queued_transfers(fReadPipe); 501 gUSBModule->cancel_queued_transfers(fWritePipe); 502 gUSBModule->cancel_queued_transfers(fControlPipe); 503 } 504 505 506 status_t 507 SerialDevice::AddDevice(const usb_configuration_info *config) 508 { 509 // default implementation - does nothing 510 return B_ERROR; 511 } 512 513 514 status_t 515 SerialDevice::ResetDevice() 516 { 517 // default implementation - does nothing 518 return B_OK; 519 } 520 521 522 status_t 523 SerialDevice::SetLineCoding(usb_cdc_line_coding *coding) 524 { 525 // default implementation - does nothing 526 return B_NOT_SUPPORTED; 527 } 528 529 530 status_t 531 SerialDevice::SetControlLineState(uint16 state) 532 { 533 // default implementation - does nothing 534 return B_NOT_SUPPORTED; 535 } 536 537 538 status_t 539 SerialDevice::SetHardwareFlowControl(bool enable) 540 { 541 // default implementation - does nothing 542 return B_NOT_SUPPORTED; 543 } 544 545 546 void 547 SerialDevice::OnRead(char **buffer, size_t *numBytes) 548 { 549 // default implementation - does nothing 550 } 551 552 553 void 554 SerialDevice::OnWrite(const char *buffer, size_t *numBytes, size_t *packetBytes) 555 { 556 memcpy(fWriteBuffer, buffer, *numBytes); 557 } 558 559 560 void 561 SerialDevice::OnClose() 562 { 563 // default implementation - does nothing 564 } 565 566 567 int32 568 SerialDevice::_InputThread(void *data) 569 { 570 SerialDevice *device = (SerialDevice *)data; 571 572 while (!device->fStopThreads) { 573 status_t status = gUSBModule->queue_bulk(device->fReadPipe, 574 device->fReadBuffer, device->fReadBufferSize, 575 device->_ReadCallbackFunction, data); 576 if (status < B_OK) { 577 TRACE_ALWAYS("input thread: queueing failed with error: 0x%08x\n", 578 status); 579 return status; 580 } 581 582 status = acquire_sem_etc(device->fDoneRead, 1, B_CAN_INTERRUPT, 0); 583 if (status < B_OK) { 584 TRACE_ALWAYS("input thread: failed to get read done sem 0x%08x\n", 585 status); 586 return status; 587 } 588 589 if (device->fStatusRead != B_OK) { 590 TRACE("input thread: device status error 0x%08x\n", 591 device->fStatusRead); 592 if (device->fStatusRead == B_DEV_STALLED 593 && gUSBModule->clear_feature(device->fReadPipe, 594 USB_FEATURE_ENDPOINT_HALT) != B_OK) { 595 TRACE_ALWAYS("input thread: failed to clear halt feature\n"); 596 return B_ERROR; 597 } 598 599 continue; 600 } 601 602 char *buffer = device->fReadBuffer; 603 size_t readLength = device->fActualLengthRead; 604 device->OnRead(&buffer, &readLength); 605 if (readLength == 0) 606 continue; 607 608 while (device->fInputStopped) 609 snooze(100); 610 611 status = gTTYModule->tty_write(device->fDeviceTTYCookie, buffer, 612 &readLength); 613 if (status != B_OK) { 614 TRACE_ALWAYS("input thread: failed to write into TTY\n"); 615 return status; 616 } 617 } 618 619 return B_OK; 620 } 621 622 623 status_t 624 SerialDevice::_WriteToDevice() 625 { 626 char *buffer = fOutputBuffer; 627 size_t bytesLeft = fOutputBufferSize; 628 status_t status = gTTYModule->tty_read(fDeviceTTYCookie, buffer, 629 &bytesLeft); 630 if (status != B_OK) { 631 TRACE_ALWAYS("write to device: failed to read from TTY: %s\n", 632 strerror(status)); 633 return status; 634 } 635 636 while (!fDeviceRemoved && bytesLeft > 0) { 637 size_t length = MIN(bytesLeft, fWriteBufferSize); 638 size_t packetLength = length; 639 OnWrite(buffer, &length, &packetLength); 640 641 status = gUSBModule->queue_bulk(fWritePipe, fWriteBuffer, packetLength, 642 _WriteCallbackFunction, this); 643 if (status != B_OK) { 644 TRACE_ALWAYS("write to device: queueing failed with status " 645 "0x%08x\n", status); 646 return status; 647 } 648 649 status = acquire_sem_etc(fDoneWrite, 1, B_CAN_INTERRUPT, 0); 650 if (status != B_OK) { 651 TRACE_ALWAYS("write to device: failed to get write done sem " 652 "0x%08x\n", status); 653 return status; 654 } 655 656 if (fStatusWrite != B_OK) { 657 TRACE("write to device: device status error 0x%08x\n", 658 fStatusWrite); 659 if (fStatusWrite == B_DEV_STALLED) { 660 status = gUSBModule->clear_feature(fWritePipe, 661 USB_FEATURE_ENDPOINT_HALT); 662 if (status != B_OK) { 663 TRACE_ALWAYS("write to device: failed to clear device " 664 "halt\n"); 665 return B_ERROR; 666 } 667 } 668 669 continue; 670 } 671 672 buffer += length; 673 bytesLeft -= length; 674 } 675 676 return B_OK; 677 } 678 679 680 void 681 SerialDevice::_ReadCallbackFunction(void *cookie, status_t status, void *data, 682 size_t actualLength) 683 { 684 TRACE_FUNCALLS("read callback: cookie: 0x%08x status: 0x%08x data: 0x%08x " 685 "length: %lu\n", cookie, status, data, actualLength); 686 687 SerialDevice *device = (SerialDevice *)cookie; 688 device->fActualLengthRead = actualLength; 689 device->fStatusRead = status; 690 release_sem_etc(device->fDoneRead, 1, B_DO_NOT_RESCHEDULE); 691 } 692 693 694 void 695 SerialDevice::_WriteCallbackFunction(void *cookie, status_t status, void *data, 696 size_t actualLength) 697 { 698 TRACE_FUNCALLS("write callback: cookie: 0x%08x status: 0x%08x data: 0x%08x " 699 "length: %lu\n", cookie, status, data, actualLength); 700 701 SerialDevice *device = (SerialDevice *)cookie; 702 device->fActualLengthWrite = actualLength; 703 device->fStatusWrite = status; 704 release_sem_etc(device->fDoneWrite, 1, B_DO_NOT_RESCHEDULE); 705 } 706 707 708 void 709 SerialDevice::_InterruptCallbackFunction(void *cookie, status_t status, 710 void *data, size_t actualLength) 711 { 712 TRACE_FUNCALLS("interrupt callback: cookie: 0x%08x status: 0x%08x data: " 713 "0x%08x len: %lu\n", cookie, status, data, actualLength); 714 715 SerialDevice *device = (SerialDevice *)cookie; 716 device->fActualLengthInterrupt = actualLength; 717 device->fStatusInterrupt = status; 718 719 // ToDo: maybe handle those somehow? 720 721 if (status == B_OK && !device->fDeviceRemoved) { 722 status = gUSBModule->queue_interrupt(device->fControlPipe, 723 device->fInterruptBuffer, device->fInterruptBufferSize, 724 device->_InterruptCallbackFunction, device); 725 } 726 } 727 728 729 SerialDevice * 730 SerialDevice::MakeDevice(usb_device device, uint16 vendorID, 731 uint16 productID) 732 { 733 // FTDI Serial Device 734 for (uint32 i = 0; i < sizeof(kFTDIDevices) 735 / sizeof(kFTDIDevices[0]); i++) { 736 if (vendorID == kFTDIDevices[i].vendorID 737 && productID == kFTDIDevices[i].productID) { 738 return new(std::nothrow) FTDIDevice(device, vendorID, productID, 739 kFTDIDevices[i].deviceName); 740 } 741 } 742 743 // KLSI Serial Device 744 for (uint32 i = 0; i < sizeof(kKLSIDevices) 745 / sizeof(kKLSIDevices[0]); i++) { 746 if (vendorID == kKLSIDevices[i].vendorID 747 && productID == kKLSIDevices[i].productID) { 748 return new(std::nothrow) KLSIDevice(device, vendorID, productID, 749 kKLSIDevices[i].deviceName); 750 } 751 } 752 753 // Prolific Serial Device 754 for (uint32 i = 0; i < sizeof(kProlificDevices) 755 / sizeof(kProlificDevices[0]); i++) { 756 if (vendorID == kProlificDevices[i].vendorID 757 && productID == kProlificDevices[i].productID) { 758 return new(std::nothrow) ProlificDevice(device, vendorID, productID, 759 kProlificDevices[i].deviceName); 760 } 761 } 762 763 // Silicon Serial Device 764 for (uint32 i = 0; i < sizeof(kSiliconDevices) 765 / sizeof(kSiliconDevices[0]); i++) { 766 if (vendorID == kSiliconDevices[i].vendorID 767 && productID == kSiliconDevices[i].productID) { 768 return new(std::nothrow) SiliconDevice(device, vendorID, productID, 769 kSiliconDevices[i].deviceName); 770 } 771 } 772 773 // Option Serial Device 774 for (uint32 i = 0; i < sizeof(kOptionDevices) 775 / sizeof(kOptionDevices[0]); i++) { 776 if (vendorID == kOptionDevices[i].vendorID 777 && productID == kOptionDevices[i].productID) { 778 return new(std::nothrow) OptionDevice(device, vendorID, productID, 779 kOptionDevices[i].deviceName); 780 } 781 } 782 783 // Otherwise, return standard ACM device 784 return new(std::nothrow) ACMDevice(device, vendorID, productID, 785 "CDC ACM compatible device"); 786 } 787