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 status_t status = B_OK; 291 292 if (fDeviceOpen) 293 return B_BUSY; 294 295 if (fDeviceRemoved) 296 return B_DEV_NOT_READY; 297 298 status = gTTYModule->tty_create(usb_serial_service, NULL, &fMasterTTY); 299 if (status != B_OK) { 300 TRACE_ALWAYS("open: failed to init master tty\n"); 301 return status; 302 } 303 304 status = gTTYModule->tty_create(usb_serial_service, fMasterTTY, &fSlaveTTY); 305 if (status != B_OK) { 306 TRACE_ALWAYS("open: failed to init slave tty\n"); 307 gTTYModule->tty_destroy(fMasterTTY); 308 return status; 309 } 310 311 status = gTTYModule->tty_create_cookie(fMasterTTY, fSlaveTTY, O_RDWR, &fSystemTTYCookie); 312 if (status != B_OK) { 313 TRACE_ALWAYS("open: failed to init system tty cookie\n"); 314 gTTYModule->tty_destroy(fMasterTTY); 315 gTTYModule->tty_destroy(fSlaveTTY); 316 return status; 317 } 318 319 status = gTTYModule->tty_create_cookie(fSlaveTTY, fMasterTTY, O_RDWR, &fDeviceTTYCookie); 320 if (status != B_OK) { 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 status; 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 = gUSBModule->queue_interrupt(fControlPipe, fInterruptBuffer, fInterruptBufferSize, 346 _InterruptCallbackFunction, 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 // WinChipHead Serial Device 782 for (uint32 i = 0; i < sizeof(kWCHDevices) 783 / sizeof(kWCHDevices[0]); i++) { 784 if (vendorID == kWCHDevices[i].vendorID 785 && productID == kWCHDevices[i].productID) { 786 return new(std::nothrow) WCHDevice(device, vendorID, productID, 787 kWCHDevices[i].deviceName); 788 } 789 } 790 791 // Option Serial Device 792 for (uint32 i = 0; i < sizeof(kOptionDevices) 793 / sizeof(kOptionDevices[0]); i++) { 794 if (vendorID == kOptionDevices[i].vendorID 795 && productID == kOptionDevices[i].productID) { 796 return new(std::nothrow) OptionDevice(device, vendorID, productID, 797 kOptionDevices[i].deviceName); 798 } 799 } 800 801 // Otherwise, return standard ACM device 802 return new(std::nothrow) ACMDevice(device, vendorID, productID, 803 "CDC ACM compatible device"); 804 } 805