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 #include <new> 9 10 #include "SerialDevice.h" 11 #include "USB3.h" 12 13 #include "ACM.h" 14 #include "FTDI.h" 15 #include "KLSI.h" 16 #include "Prolific.h" 17 #include "Silicon.h" 18 19 #include <sys/ioctl.h> 20 21 22 SerialDevice::SerialDevice(usb_device device, uint16 vendorID, 23 uint16 productID, const char *description) 24 : fDevice(device), 25 fVendorID(vendorID), 26 fProductID(productID), 27 fDescription(description), 28 fDeviceOpen(false), 29 fDeviceRemoved(false), 30 fControlPipe(0), 31 fReadPipe(0), 32 fWritePipe(0), 33 fBufferArea(-1), 34 fReadBuffer(NULL), 35 fReadBufferSize(ROUNDUP(DEF_BUFFER_SIZE, 16)), 36 fOutputBuffer(NULL), 37 fOutputBufferSize(ROUNDUP(DEF_BUFFER_SIZE, 16)), 38 fWriteBuffer(NULL), 39 fWriteBufferSize(ROUNDUP(DEF_BUFFER_SIZE, 16)), 40 fInterruptBuffer(NULL), 41 fInterruptBufferSize(16), 42 fDoneRead(-1), 43 fDoneWrite(-1), 44 fControlOut(0), 45 fInputStopped(false), 46 fMasterTTY(NULL), 47 fSlaveTTY(NULL), 48 fSystemTTYCookie(NULL), 49 fDeviceTTYCookie(NULL), 50 fInputThread(-1), 51 fStopThreads(false) 52 { 53 memset(&fTTYConfig, 0, sizeof(termios)); 54 fTTYConfig.c_cflag = B9600 | CS8 | CREAD; 55 } 56 57 58 SerialDevice::~SerialDevice() 59 { 60 Removed(); 61 62 if (fDoneRead >= 0) 63 delete_sem(fDoneRead); 64 if (fDoneWrite >= 0) 65 delete_sem(fDoneWrite); 66 67 if (fBufferArea >= 0) 68 delete_area(fBufferArea); 69 } 70 71 72 status_t 73 SerialDevice::Init() 74 { 75 fDoneRead = create_sem(0, "usb_serial:done_read"); 76 if (fDoneRead < 0) 77 return fDoneRead; 78 79 fDoneWrite = create_sem(0, "usb_serial:done_write"); 80 if (fDoneWrite < 0) 81 return fDoneWrite; 82 83 size_t totalBuffers = fReadBufferSize + fOutputBufferSize + fWriteBufferSize 84 + fInterruptBufferSize; 85 fBufferArea = create_area("usb_serial:buffers_area", (void **)&fReadBuffer, 86 B_ANY_KERNEL_ADDRESS, ROUNDUP(totalBuffers, B_PAGE_SIZE), B_CONTIGUOUS, 87 B_READ_AREA | B_WRITE_AREA); 88 if (fBufferArea < 0) 89 return fBufferArea; 90 91 fOutputBuffer = fReadBuffer + fReadBufferSize; 92 fWriteBuffer = fOutputBuffer + fOutputBufferSize; 93 fInterruptBuffer = fWriteBuffer + fWriteBufferSize; 94 return B_OK; 95 } 96 97 98 void 99 SerialDevice::SetControlPipe(usb_pipe handle) 100 { 101 fControlPipe = handle; 102 } 103 104 105 void 106 SerialDevice::SetReadPipe(usb_pipe handle) 107 { 108 fReadPipe = handle; 109 } 110 111 112 void 113 SerialDevice::SetWritePipe(usb_pipe handle) 114 { 115 fWritePipe = handle; 116 } 117 118 119 inline int32 120 baud_index_to_speed(int index) 121 { 122 switch (index) { 123 case B0: return 0; 124 case B50: return 50; 125 case B75: return 75; 126 case B110: return 110; 127 case B134: return 134; 128 case B150: return 150; 129 case B200: return 200; 130 case B300: return 300; 131 case B600: return 600; 132 case B1200: return 1200; 133 case B1800: return 1800; 134 case B2400: return 2400; 135 case B4800: return 4800; 136 case B9600: return 9600; 137 case B19200: return 19200; 138 case B31250: return 31250; 139 case B38400: return 38400; 140 case B57600: return 57600; 141 case B115200: return 115200; 142 case B230400: return 230400; 143 } 144 145 TRACE_ALWAYS("invalid baud index %d\n", index); 146 return -1; 147 } 148 149 150 void 151 SerialDevice::SetModes(struct termios *tios) 152 { 153 TRACE_FUNCRES(trace_termios, tios); 154 155 uint8 baud = tios->c_cflag & CBAUD; 156 int32 speed = baud_index_to_speed(baud); 157 if (speed < 0) { 158 baud = B19200; 159 speed = 19200; 160 } 161 162 // update our master config in full 163 memcpy(&fTTYConfig, tios, sizeof(termios)); 164 fTTYConfig.c_cflag &= ~CBAUD; 165 fTTYConfig.c_cflag |= baud; 166 167 // only apply the relevant parts to the device side 168 termios config; 169 memset(&config, 0, sizeof(termios)); 170 config.c_cflag = tios->c_cflag; 171 config.c_cflag &= ~CBAUD; 172 config.c_cflag |= baud; 173 174 // update the termios of the device side 175 gTTYModule->tty_control(fDeviceTTYCookie, TCSETA, &config, sizeof(termios)); 176 177 usb_cdc_line_coding lineCoding; 178 lineCoding.speed = speed; 179 lineCoding.stopbits = (tios->c_cflag & CSTOPB) 180 ? USB_CDC_LINE_CODING_2_STOPBITS : USB_CDC_LINE_CODING_1_STOPBIT; 181 182 if (tios->c_cflag & PARENB) { 183 lineCoding.parity = USB_CDC_LINE_CODING_EVEN_PARITY; 184 if (tios->c_cflag & PARODD) 185 lineCoding.parity = USB_CDC_LINE_CODING_ODD_PARITY; 186 } else 187 lineCoding.parity = USB_CDC_LINE_CODING_NO_PARITY; 188 189 lineCoding.databits = (tios->c_cflag & CS8) ? 8 : 7; 190 191 if (memcmp(&lineCoding, &fLineCoding, sizeof(usb_cdc_line_coding)) != 0) { 192 fLineCoding.speed = lineCoding.speed; 193 fLineCoding.stopbits = lineCoding.stopbits; 194 fLineCoding.databits = lineCoding.databits; 195 fLineCoding.parity = lineCoding.parity; 196 TRACE("send to modem: speed %d sb: 0x%08x db: 0x%08x parity: 0x%08x\n", 197 fLineCoding.speed, fLineCoding.stopbits, fLineCoding.databits, 198 fLineCoding.parity); 199 SetLineCoding(&fLineCoding); 200 } 201 } 202 203 204 bool 205 SerialDevice::Service(struct tty *tty, uint32 op, void *buffer, size_t length) 206 { 207 if (tty != fMasterTTY) 208 return false; 209 210 switch (op) { 211 case TTYENABLE: 212 { 213 bool enable = *(bool *)buffer; 214 TRACE("TTYENABLE: %sable\n", enable ? "en" : "dis"); 215 216 gTTYModule->tty_hardware_signal(fSystemTTYCookie, TTYHWDCD, enable); 217 gTTYModule->tty_hardware_signal(fSystemTTYCookie, TTYHWCTS, enable); 218 219 fControlOut = enable ? USB_CDC_CONTROL_SIGNAL_STATE_DTR 220 | USB_CDC_CONTROL_SIGNAL_STATE_RTS : 0; 221 SetControlLineState(fControlOut); 222 return true; 223 } 224 225 case TTYISTOP: 226 fInputStopped = *(bool *)buffer; 227 TRACE("TTYISTOP: %sstopped\n", fInputStopped ? "" : "not "); 228 gTTYModule->tty_hardware_signal(fSystemTTYCookie, TTYHWCTS, 229 !fInputStopped); 230 return true; 231 232 case TTYGETSIGNALS: 233 TRACE("TTYGETSIGNALS\n"); 234 gTTYModule->tty_hardware_signal(fSystemTTYCookie, TTYHWDCD, 235 (fControlOut & (USB_CDC_CONTROL_SIGNAL_STATE_DTR 236 | USB_CDC_CONTROL_SIGNAL_STATE_RTS)) != 0); 237 gTTYModule->tty_hardware_signal(fSystemTTYCookie, TTYHWCTS, 238 !fInputStopped); 239 gTTYModule->tty_hardware_signal(fSystemTTYCookie, TTYHWDSR, false); 240 gTTYModule->tty_hardware_signal(fSystemTTYCookie, TTYHWRI, false); 241 return true; 242 243 case TTYSETMODES: 244 TRACE("TTYSETMODES\n"); 245 SetModes((struct termios *)buffer); 246 return true; 247 248 case TTYSETDTR: 249 case TTYSETRTS: 250 { 251 bool set = *(bool *)buffer; 252 uint8 bit = op == TTYSETDTR ? USB_CDC_CONTROL_SIGNAL_STATE_DTR 253 : USB_CDC_CONTROL_SIGNAL_STATE_RTS; 254 if (set) 255 fControlOut |= bit; 256 else 257 fControlOut &= ~bit; 258 259 SetControlLineState(fControlOut); 260 return true; 261 } 262 263 case TTYOSTART: 264 case TTYOSYNC: 265 case TTYSETBREAK: 266 TRACE("TTY other\n"); 267 return true; 268 } 269 270 return false; 271 } 272 273 274 status_t 275 SerialDevice::Open(uint32 flags) 276 { 277 if (fDeviceOpen) 278 return B_BUSY; 279 280 if (fDeviceRemoved) 281 return B_DEV_NOT_READY; 282 283 fMasterTTY = gTTYModule->tty_create(usb_serial_service, true); 284 if (fMasterTTY == NULL) { 285 TRACE_ALWAYS("open: failed to init master tty\n"); 286 return B_NO_MEMORY; 287 } 288 289 fSlaveTTY = gTTYModule->tty_create(usb_serial_service, false); 290 if (fSlaveTTY == NULL) { 291 TRACE_ALWAYS("open: failed to init slave tty\n"); 292 gTTYModule->tty_destroy(fMasterTTY); 293 return B_NO_MEMORY; 294 } 295 296 fSystemTTYCookie = gTTYModule->tty_create_cookie(fMasterTTY, fSlaveTTY, 297 O_RDWR); 298 if (fSystemTTYCookie == NULL) { 299 TRACE_ALWAYS("open: failed to init system tty cookie\n"); 300 gTTYModule->tty_destroy(fMasterTTY); 301 gTTYModule->tty_destroy(fSlaveTTY); 302 return B_NO_MEMORY; 303 } 304 305 fDeviceTTYCookie = gTTYModule->tty_create_cookie(fSlaveTTY, fMasterTTY, 306 O_RDWR); 307 if (fDeviceTTYCookie == NULL) { 308 TRACE_ALWAYS("open: failed to init device tty cookie\n"); 309 gTTYModule->tty_destroy_cookie(fSystemTTYCookie); 310 gTTYModule->tty_destroy(fMasterTTY); 311 gTTYModule->tty_destroy(fSlaveTTY); 312 return B_NO_MEMORY; 313 } 314 315 ResetDevice(); 316 317 fStopThreads = false; 318 319 fInputThread = spawn_kernel_thread(_InputThread, 320 "usb_serial input thread", B_NORMAL_PRIORITY, this); 321 if (fInputThread < 0) { 322 TRACE_ALWAYS("open: failed to spawn input thread\n"); 323 return fInputThread; 324 } 325 326 resume_thread(fInputThread); 327 328 fControlOut = USB_CDC_CONTROL_SIGNAL_STATE_DTR 329 | USB_CDC_CONTROL_SIGNAL_STATE_RTS; 330 SetControlLineState(fControlOut); 331 332 status_t status = gUSBModule->queue_interrupt(fControlPipe, 333 fInterruptBuffer, fInterruptBufferSize, _InterruptCallbackFunction, 334 this); 335 if (status < B_OK) 336 TRACE_ALWAYS("failed to queue initial interrupt\n"); 337 338 // set our config (will propagate to the slave config as well in SetModes() 339 gTTYModule->tty_control(fSystemTTYCookie, TCSETA, &fTTYConfig, 340 sizeof(termios)); 341 342 fDeviceOpen = true; 343 return B_OK; 344 } 345 346 347 status_t 348 SerialDevice::Read(char *buffer, size_t *numBytes) 349 { 350 if (fDeviceRemoved) { 351 *numBytes = 0; 352 return B_DEV_NOT_READY; 353 } 354 355 return gTTYModule->tty_read(fSystemTTYCookie, buffer, numBytes); 356 } 357 358 359 status_t 360 SerialDevice::Write(const char *buffer, size_t *numBytes) 361 { 362 if (fDeviceRemoved) { 363 *numBytes = 0; 364 return B_DEV_NOT_READY; 365 } 366 367 size_t bytesLeft = *numBytes; 368 *numBytes = 0; 369 370 while (bytesLeft > 0) { 371 size_t length = MIN(bytesLeft, 256); 372 // TODO: This is an ugly hack; We use a small buffer size so that 373 // we don't overrun the tty line buffer and cause it to block. While 374 // that isn't a problem, we shouldn't just hardcode the value here. 375 376 status_t result = gTTYModule->tty_write(fSystemTTYCookie, buffer, 377 &length); 378 if (result != B_OK) { 379 TRACE_ALWAYS("failed to write to tty: %s\n", strerror(result)); 380 return result; 381 } 382 383 buffer += length; 384 *numBytes += length; 385 bytesLeft -= length; 386 387 while (true) { 388 // Write to the device as long as there's anything in the tty buffer 389 int readable = 0; 390 gTTYModule->tty_control(fDeviceTTYCookie, FIONREAD, &readable, 391 sizeof(readable)); 392 if (readable == 0) 393 break; 394 395 result = _WriteToDevice(); 396 if (result != B_OK) { 397 TRACE_ALWAYS("failed to write to device: %s\n", 398 strerror(result)); 399 return result; 400 } 401 } 402 } 403 404 if (*numBytes > 0) 405 return B_OK; 406 407 return B_ERROR; 408 } 409 410 411 status_t 412 SerialDevice::Control(uint32 op, void *arg, size_t length) 413 { 414 if (fDeviceRemoved) 415 return B_DEV_NOT_READY; 416 417 return gTTYModule->tty_control(fSystemTTYCookie, op, arg, length); 418 } 419 420 421 status_t 422 SerialDevice::Select(uint8 event, uint32 ref, selectsync *sync) 423 { 424 if (fDeviceRemoved) 425 return B_DEV_NOT_READY; 426 427 return gTTYModule->tty_select(fSystemTTYCookie, event, ref, sync); 428 } 429 430 431 status_t 432 SerialDevice::DeSelect(uint8 event, selectsync *sync) 433 { 434 if (fDeviceRemoved) 435 return B_DEV_NOT_READY; 436 437 return gTTYModule->tty_deselect(fSystemTTYCookie, event, sync); 438 } 439 440 441 status_t 442 SerialDevice::Close() 443 { 444 OnClose(); 445 446 fStopThreads = true; 447 fInputStopped = false; 448 449 if (!fDeviceRemoved) { 450 gUSBModule->cancel_queued_transfers(fReadPipe); 451 gUSBModule->cancel_queued_transfers(fWritePipe); 452 gUSBModule->cancel_queued_transfers(fControlPipe); 453 } 454 455 gTTYModule->tty_close_cookie(fSystemTTYCookie); 456 gTTYModule->tty_close_cookie(fDeviceTTYCookie); 457 458 int32 result = B_OK; 459 wait_for_thread(fInputThread, &result); 460 fInputThread = -1; 461 462 gTTYModule->tty_destroy_cookie(fSystemTTYCookie); 463 gTTYModule->tty_destroy_cookie(fDeviceTTYCookie); 464 465 gTTYModule->tty_destroy(fMasterTTY); 466 gTTYModule->tty_destroy(fSlaveTTY); 467 468 fDeviceOpen = false; 469 return B_OK; 470 } 471 472 473 status_t 474 SerialDevice::Free() 475 { 476 return B_OK; 477 } 478 479 480 void 481 SerialDevice::Removed() 482 { 483 if (fDeviceRemoved) 484 return; 485 486 // notifies us that the device was removed 487 fDeviceRemoved = true; 488 489 // we need to ensure that we do not use the device anymore 490 fStopThreads = true; 491 fInputStopped = false; 492 gUSBModule->cancel_queued_transfers(fReadPipe); 493 gUSBModule->cancel_queued_transfers(fWritePipe); 494 gUSBModule->cancel_queued_transfers(fControlPipe); 495 } 496 497 498 status_t 499 SerialDevice::AddDevice(const usb_configuration_info *config) 500 { 501 // default implementation - does nothing 502 return B_ERROR; 503 } 504 505 506 status_t 507 SerialDevice::ResetDevice() 508 { 509 // default implementation - does nothing 510 return B_OK; 511 } 512 513 514 status_t 515 SerialDevice::SetLineCoding(usb_cdc_line_coding *coding) 516 { 517 // default implementation - does nothing 518 return B_OK; 519 } 520 521 522 status_t 523 SerialDevice::SetControlLineState(uint16 state) 524 { 525 // default implementation - does nothing 526 return B_OK; 527 } 528 529 530 void 531 SerialDevice::OnRead(char **buffer, size_t *numBytes) 532 { 533 // default implementation - does nothing 534 } 535 536 537 void 538 SerialDevice::OnWrite(const char *buffer, size_t *numBytes, size_t *packetBytes) 539 { 540 memcpy(fWriteBuffer, buffer, *numBytes); 541 } 542 543 544 void 545 SerialDevice::OnClose() 546 { 547 // default implementation - does nothing 548 } 549 550 551 int32 552 SerialDevice::_InputThread(void *data) 553 { 554 SerialDevice *device = (SerialDevice *)data; 555 556 while (!device->fStopThreads) { 557 status_t status = gUSBModule->queue_bulk(device->fReadPipe, 558 device->fReadBuffer, device->fReadBufferSize, 559 device->_ReadCallbackFunction, data); 560 if (status < B_OK) { 561 TRACE_ALWAYS("input thread: queueing failed with error: 0x%08x\n", 562 status); 563 return status; 564 } 565 566 status = acquire_sem_etc(device->fDoneRead, 1, B_CAN_INTERRUPT, 0); 567 if (status < B_OK) { 568 TRACE_ALWAYS("input thread: failed to get read done sem 0x%08x\n", 569 status); 570 return status; 571 } 572 573 if (device->fStatusRead != B_OK) { 574 TRACE("input thread: device status error 0x%08x\n", 575 device->fStatusRead); 576 if (device->fStatusRead == B_DEV_STALLED 577 && gUSBModule->clear_feature(device->fReadPipe, 578 USB_FEATURE_ENDPOINT_HALT) != B_OK) { 579 TRACE_ALWAYS("input thread: failed to clear halt feature\n"); 580 return B_ERROR; 581 } 582 583 continue; 584 } 585 586 char *buffer = device->fReadBuffer; 587 size_t readLength = device->fActualLengthRead; 588 device->OnRead(&buffer, &readLength); 589 if (readLength == 0) 590 continue; 591 592 while (device->fInputStopped) 593 snooze(100); 594 595 status = gTTYModule->tty_write(device->fDeviceTTYCookie, buffer, 596 &readLength); 597 if (status != B_OK) { 598 TRACE_ALWAYS("input thread: failed to write into TTY\n"); 599 return status; 600 } 601 } 602 603 return B_OK; 604 } 605 606 607 status_t 608 SerialDevice::_WriteToDevice() 609 { 610 char *buffer = fOutputBuffer; 611 size_t bytesLeft = fOutputBufferSize; 612 status_t status = gTTYModule->tty_read(fDeviceTTYCookie, buffer, 613 &bytesLeft); 614 if (status != B_OK) { 615 TRACE_ALWAYS("write to device: failed to read from TTY: %s\n", 616 strerror(status)); 617 return status; 618 } 619 620 while (!fDeviceRemoved && bytesLeft > 0) { 621 size_t length = MIN(bytesLeft, fWriteBufferSize); 622 size_t packetLength = length; 623 OnWrite(buffer, &length, &packetLength); 624 625 status = gUSBModule->queue_bulk(fWritePipe, fWriteBuffer, packetLength, 626 _WriteCallbackFunction, this); 627 if (status != B_OK) { 628 TRACE_ALWAYS("write to device: queueing failed with status " 629 "0x%08x\n", status); 630 return status; 631 } 632 633 status = acquire_sem_etc(fDoneWrite, 1, B_CAN_INTERRUPT, 0); 634 if (status != B_OK) { 635 TRACE_ALWAYS("write to device: failed to get write done sem " 636 "0x%08x\n", status); 637 return status; 638 } 639 640 if (fStatusWrite != B_OK) { 641 TRACE("write to device: device status error 0x%08x\n", 642 fStatusWrite); 643 if (fStatusWrite == B_DEV_STALLED) { 644 status = gUSBModule->clear_feature(fWritePipe, 645 USB_FEATURE_ENDPOINT_HALT); 646 if (status != B_OK) { 647 TRACE_ALWAYS("write to device: failed to clear device " 648 "halt\n"); 649 return B_ERROR; 650 } 651 } 652 653 continue; 654 } 655 656 buffer += length; 657 bytesLeft -= length; 658 } 659 660 return B_OK; 661 } 662 663 664 void 665 SerialDevice::_ReadCallbackFunction(void *cookie, status_t status, void *data, 666 uint32 actualLength) 667 { 668 TRACE_FUNCALLS("read callback: cookie: 0x%08x status: 0x%08x data: 0x%08x " 669 "length: %lu\n", cookie, status, data, actualLength); 670 671 SerialDevice *device = (SerialDevice *)cookie; 672 device->fActualLengthRead = actualLength; 673 device->fStatusRead = status; 674 release_sem_etc(device->fDoneRead, 1, B_DO_NOT_RESCHEDULE); 675 } 676 677 678 void 679 SerialDevice::_WriteCallbackFunction(void *cookie, status_t status, void *data, 680 uint32 actualLength) 681 { 682 TRACE_FUNCALLS("write callback: cookie: 0x%08x status: 0x%08x data: 0x%08x " 683 "length: %lu\n", cookie, status, data, actualLength); 684 685 SerialDevice *device = (SerialDevice *)cookie; 686 device->fActualLengthWrite = actualLength; 687 device->fStatusWrite = status; 688 release_sem_etc(device->fDoneWrite, 1, B_DO_NOT_RESCHEDULE); 689 } 690 691 692 void 693 SerialDevice::_InterruptCallbackFunction(void *cookie, status_t status, 694 void *data, uint32 actualLength) 695 { 696 TRACE_FUNCALLS("interrupt callback: cookie: 0x%08x status: 0x%08x data: " 697 "0x%08x len: %lu\n", cookie, status, data, actualLength); 698 699 SerialDevice *device = (SerialDevice *)cookie; 700 device->fActualLengthInterrupt = actualLength; 701 device->fStatusInterrupt = status; 702 703 // ToDo: maybe handle those somehow? 704 705 if (status == B_OK && !device->fDeviceRemoved) { 706 status = gUSBModule->queue_interrupt(device->fControlPipe, 707 device->fInterruptBuffer, device->fInterruptBufferSize, 708 device->_InterruptCallbackFunction, device); 709 } 710 } 711 712 713 SerialDevice * 714 SerialDevice::MakeDevice(usb_device device, uint16 vendorID, 715 uint16 productID) 716 { 717 const char *description = NULL; 718 719 switch (vendorID) { 720 case VENDOR_IODATA: 721 case VENDOR_ATEN: 722 case VENDOR_TDK: 723 case VENDOR_RATOC: 724 case VENDOR_PROLIFIC: 725 case VENDOR_ELECOM: 726 case VENDOR_SOURCENEXT: 727 case VENDOR_HAL: 728 { 729 switch (productID) { 730 case PRODUCT_PROLIFIC_RSAQ2: 731 description = "PL2303 Serial adapter (IODATA USB-RSAQ2)"; 732 break; 733 case PRODUCT_IODATA_USBRSAQ: 734 description = "I/O Data USB serial adapter USB-RSAQ1"; 735 break; 736 case PRODUCT_ATEN_UC232A: 737 description = "Aten Serial adapter"; 738 break; 739 case PRODUCT_TDK_UHA6400: 740 description = "TDK USB-PHS Adapter UHA6400"; 741 break; 742 case PRODUCT_RATOC_REXUSB60: 743 description = "Ratoc USB serial adapter REX-USB60"; 744 break; 745 case PRODUCT_PROLIFIC_PL2303: 746 description = "PL2303 Serial adapter (ATEN/IOGEAR UC232A)"; 747 break; 748 case PRODUCT_ELECOM_UCSGT: 749 description = "Elecom UC-SGT"; 750 break; 751 case PRODUCT_SOURCENEXT_KEIKAI8: 752 description = "SOURCENEXT KeikaiDenwa 8"; 753 break; 754 case PRODUCT_SOURCENEXT_KEIKAI8_CHG: 755 description = "SOURCENEXT KeikaiDenwa 8 with charger"; 756 break; 757 case PRODUCT_HAL_IMR001: 758 description = "HAL Corporation Crossam2+USB"; 759 break; 760 } 761 762 if (description == NULL) 763 break; 764 765 return new(std::nothrow) ProlificDevice(device, vendorID, productID, 766 description); 767 } 768 769 case VENDOR_FTDI: 770 { 771 switch (productID) { 772 case PRODUCT_FTDI_8U100AX: 773 description = "FTDI 8U100AX serial converter"; 774 break; 775 case PRODUCT_FTDI_8U232AM: 776 description = "FTDI 8U232AM serial converter"; 777 break; 778 } 779 780 if (description == NULL) 781 break; 782 783 return new(std::nothrow) FTDIDevice(device, vendorID, productID, 784 description); 785 } 786 787 case VENDOR_PALM: 788 case VENDOR_KLSI: 789 { 790 switch (productID) { 791 case PRODUCT_PALM_CONNECT: 792 description = "PalmConnect RS232"; 793 break; 794 case PRODUCT_KLSI_KL5KUSB105D: 795 description = "KLSI KL5KUSB105D"; 796 break; 797 } 798 799 if (description == NULL) 800 break; 801 802 return new(std::nothrow) KLSIDevice(device, vendorID, productID, 803 description); 804 } 805 806 case VENDOR_RENESAS: 807 { 808 switch (productID) { 809 case 0x0053: 810 description = "Renesas RX610 RX-Stick"; 811 break; 812 } 813 814 if (description != NULL) 815 goto SILICON; 816 break; 817 } 818 case VENDOR_AKATOM: 819 { 820 switch (productID) { 821 case 0x066A: 822 description = "AKTAKOM ACE-1001"; 823 break; 824 } 825 826 if (description != NULL) 827 goto SILICON; 828 break; 829 } 830 case VENDOR_PIRELLI: 831 { 832 switch (productID) { 833 case 0xE000: 834 case 0xE003: 835 description = "Pirelli DP-L10 GSM Mobile"; 836 break; 837 } 838 839 if (description != NULL) 840 goto SILICON; 841 break; 842 } 843 case VENDOR_CYPHERLAB: 844 { 845 switch (productID) { 846 case 0x1000: 847 description = "Cipherlab CCD Barcode Scanner"; 848 break; 849 } 850 851 if (description != NULL) 852 goto SILICON; 853 break; 854 } 855 case VENDOR_GEMALTO: 856 { 857 switch (productID) { 858 case 0x5501: 859 description = "Gemalto contactless smartcard reader"; 860 break; 861 } 862 863 if (description != NULL) 864 goto SILICON; 865 break; 866 } 867 case VENDOR_DIGIANSWER: 868 { 869 switch (productID) { 870 case 0x000A: 871 description = "Digianswer ZigBee MAC device"; 872 break; 873 } 874 875 if (description != NULL) 876 goto SILICON; 877 break; 878 } 879 case VENDOR_MEI: 880 { 881 switch (productID) { 882 case 0x1100: 883 case 0x1101: 884 description = "MEI Acceptor"; 885 break; 886 } 887 888 if (description != NULL) 889 goto SILICON; 890 break; 891 } 892 case VENDOR_DYNASTREAM: 893 { 894 switch (productID) { 895 case 0x1003: 896 case 0x1004: 897 case 0x1006: 898 description = "Dynastream ANT development board"; 899 break; 900 } 901 902 if (description != NULL) 903 goto SILICON; 904 break; 905 } 906 case VENDOR_KNOCKOFF: 907 { 908 switch (productID) { 909 case 0xAA26: 910 description = "Knock-off DCU-11"; 911 break; 912 } 913 914 if (description != NULL) 915 goto SILICON; 916 break; 917 } 918 case VENDOR_SIEMENS: 919 { 920 switch (productID) { 921 case 0x10C5: 922 description = "Siemens MC60"; 923 break; 924 } 925 926 if (description != NULL) 927 goto SILICON; 928 break; 929 } 930 case VENDOR_NOKIA: 931 { 932 switch (productID) { 933 case 0xAC70: 934 description = "Nokia CA-42"; 935 break; 936 } 937 938 if (description != NULL) 939 goto SILICON; 940 break; 941 } 942 case VENDOR_SILICON: 943 { 944 switch (productID) { 945 case 0x0F91: 946 case 0x1101: 947 case 0x1601: 948 case 0x800A: 949 case 0x803B: 950 case 0x8044: 951 case 0x804E: 952 case 0x8053: 953 case 0x8054: 954 case 0x8066: 955 case 0x806F: 956 case 0x807A: 957 case 0x80CA: 958 case 0x80DD: 959 case 0x80F6: 960 case 0x8115: 961 case 0x813D: 962 case 0x813F: 963 case 0x814A: 964 case 0x814B: 965 case 0x8156: 966 case 0x815E: 967 case 0x818B: 968 case 0x819F: 969 case 0x81A6: 970 case 0x81AC: 971 case 0x81AD: 972 case 0x81C8: 973 case 0x81E2: 974 case 0x81E7: 975 case 0x81E8: 976 case 0x81F2: 977 case 0x8218: 978 case 0x822B: 979 case 0x826B: 980 case 0x8293: 981 case 0x82F9: 982 case 0x8341: 983 case 0x8382: 984 case 0x83A8: 985 case 0x83D8: 986 case 0x8411: 987 case 0x8418: 988 case 0x846E: 989 case 0x8477: 990 case 0x85EA: 991 case 0x85EB: 992 case 0x8664: 993 case 0x8665: 994 case 0xEA60: 995 case 0xEA61: 996 case 0xEA71: 997 case 0xF001: 998 case 0xF002: 999 case 0xF003: 1000 case 0xF004: 1001 description = "Silicon Labs CP210x USB UART converter"; 1002 break; 1003 } 1004 1005 if (description != NULL) 1006 goto SILICON; 1007 break; 1008 } 1009 case VENDOR_SILICON2: 1010 { 1011 switch (productID) { 1012 case 0xEA61: 1013 description = "Silicon Labs GPRS USB Modem"; 1014 break; 1015 } 1016 1017 if (description != NULL) 1018 goto SILICON; 1019 break; 1020 } 1021 case VENDOR_SILICON3: 1022 { 1023 switch (productID) { 1024 case 0xEA6A: 1025 description = "Silicon Labs GPRS USB Modem 100EU"; 1026 break; 1027 } 1028 1029 if (description != NULL) 1030 goto SILICON; 1031 break; 1032 } 1033 case VENDOR_BALTECH: 1034 { 1035 switch (productID) { 1036 case 0x9999: 1037 description = "Balteck card reader"; 1038 break; 1039 } 1040 1041 if (description != NULL) 1042 goto SILICON; 1043 break; 1044 } 1045 case VENDOR_OWEN: 1046 { 1047 switch (productID) { 1048 case 0x0004: 1049 description = "Owen AC4 USB-RS485 Converter"; 1050 break; 1051 } 1052 1053 if (description != NULL) 1054 goto SILICON; 1055 break; 1056 } 1057 case VENDOR_CLIPSAL: 1058 { 1059 switch (productID) { 1060 case 0x0303: 1061 description = "Clipsal 5500PCU C-Bus USB interface"; 1062 break; 1063 } 1064 1065 if (description != NULL) 1066 goto SILICON; 1067 break; 1068 } 1069 case VENDOR_JABLOTRON: 1070 { 1071 switch (productID) { 1072 case 0x0001: 1073 description = "Jablotron serial interface"; 1074 break; 1075 } 1076 1077 if (description != NULL) 1078 goto SILICON; 1079 break; 1080 } 1081 case VENDOR_WIENER: 1082 { 1083 switch (productID) { 1084 case 0x0010: 1085 case 0x0011: 1086 case 0x0012: 1087 case 0x0015: 1088 description = "W-IE-NE-R Plein & Baus GmbH device"; 1089 break; 1090 } 1091 1092 if (description != NULL) 1093 goto SILICON; 1094 break; 1095 } 1096 case VENDOR_WAVESENSE: 1097 { 1098 switch (productID) { 1099 case 0xAAAA: 1100 description = "Wavesense Jazz blood glucose meter"; 1101 break; 1102 } 1103 1104 if (description != NULL) 1105 goto SILICON; 1106 break; 1107 } 1108 case VENDOR_VAISALA: 1109 { 1110 switch (productID) { 1111 case 0x0200: 1112 description = "Vaisala USB instrument"; 1113 break; 1114 } 1115 1116 if (description != NULL) 1117 goto SILICON; 1118 break; 1119 } 1120 case VENDOR_ELV: 1121 { 1122 switch (productID) { 1123 case 0xE00F: 1124 description = "ELV USB I²C interface"; 1125 break; 1126 } 1127 1128 if (description != NULL) 1129 goto SILICON; 1130 break; 1131 } 1132 case VENDOR_WAGO: 1133 { 1134 switch (productID) { 1135 case 0x07A6: 1136 description = "WAGO 750-923 USB Service"; 1137 break; 1138 } 1139 1140 if (description != NULL) 1141 goto SILICON; 1142 break; 1143 } 1144 case VENDOR_DW700: 1145 { 1146 switch (productID) { 1147 case 0x9500: 1148 description = "DW700 GPS USB interface"; 1149 break; 1150 } 1151 1152 if (description != NULL) 1153 goto SILICON; 1154 break; 1155 } 1156 1157 SILICON: 1158 return new(std::nothrow) SiliconDevice(device, vendorID, productID, 1159 description); 1160 } 1161 1162 return new(std::nothrow) ACMDevice(device, vendorID, productID, 1163 "CDC ACM compatible device"); 1164 } 1165