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