xref: /haiku/src/add-ons/kernel/drivers/ports/usb_serial/SerialDevice.cpp (revision b31cb92f29fe89eaca84d173d0f70d38bf0c6a3d)
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