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
SerialDevice(usb_device device,uint16 vendorID,uint16 productID,const char * description)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
~SerialDevice()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
Init()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
SetControlPipe(usb_pipe handle)106 SerialDevice::SetControlPipe(usb_pipe handle)
107 {
108 fControlPipe = handle;
109 }
110
111
112 void
SetReadPipe(usb_pipe handle)113 SerialDevice::SetReadPipe(usb_pipe handle)
114 {
115 fReadPipe = handle;
116 }
117
118
119 void
SetWritePipe(usb_pipe handle)120 SerialDevice::SetWritePipe(usb_pipe handle)
121 {
122 fWritePipe = handle;
123 }
124
125
126 inline int32
baud_index_to_speed(int index)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
SetModes(struct termios * tios)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
Service(struct tty * tty,uint32 op,void * buffer,size_t length)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
Open(uint32 flags)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
Read(char * buffer,size_t * numBytes)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
Write(const char * buffer,size_t * numBytes)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
Control(uint32 op,void * arg,size_t length)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
Select(uint8 event,uint32 ref,selectsync * sync)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
DeSelect(uint8 event,selectsync * sync)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
Close()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
Free()490 SerialDevice::Free()
491 {
492 return B_OK;
493 }
494
495
496 void
Removed()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
AddDevice(const usb_configuration_info * config)515 SerialDevice::AddDevice(const usb_configuration_info *config)
516 {
517 // default implementation - does nothing
518 return B_ERROR;
519 }
520
521
522 status_t
ResetDevice()523 SerialDevice::ResetDevice()
524 {
525 // default implementation - does nothing
526 return B_OK;
527 }
528
529
530 status_t
SetLineCoding(usb_cdc_line_coding * coding)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
SetControlLineState(uint16 state)539 SerialDevice::SetControlLineState(uint16 state)
540 {
541 // default implementation - does nothing
542 return B_NOT_SUPPORTED;
543 }
544
545
546 status_t
SetHardwareFlowControl(bool enable)547 SerialDevice::SetHardwareFlowControl(bool enable)
548 {
549 // default implementation - does nothing
550 return B_NOT_SUPPORTED;
551 }
552
553
554 void
OnRead(char ** buffer,size_t * numBytes)555 SerialDevice::OnRead(char **buffer, size_t *numBytes)
556 {
557 // default implementation - does nothing
558 }
559
560
561 void
OnWrite(const char * buffer,size_t * numBytes,size_t * packetBytes)562 SerialDevice::OnWrite(const char *buffer, size_t *numBytes, size_t *packetBytes)
563 {
564 memcpy(fWriteBuffer, buffer, *numBytes);
565 }
566
567
568 void
OnClose()569 SerialDevice::OnClose()
570 {
571 // default implementation - does nothing
572 }
573
574
575 int32
_InputThread(void * data)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
_WriteToDevice()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
_ReadCallbackFunction(void * cookie,status_t status,void * data,size_t actualLength)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
_WriteCallbackFunction(void * cookie,status_t status,void * data,size_t actualLength)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
_InterruptCallbackFunction(void * cookie,status_t status,void * data,size_t actualLength)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 *
MakeDevice(usb_device device,uint16 vendorID,uint16 productID)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