xref: /haiku/src/add-ons/kernel/drivers/ports/pc_serial/SerialDevice.cpp (revision 893988af824e65e49e55f517b157db8386e8002b)
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 "SerialDevice.h"
9 #include "UART.h"
10 
11 SerialDevice::SerialDevice(const struct serial_support_descriptor *device,
12 	uint32 ioBase, uint32 irq, const SerialDevice *master)
13 	:	/*fSupportDescriptor(device->descriptor),
14 		fDevice(device),
15 		fDescription(device->descriptor->name),*/
16 		fSupportDescriptor(device),
17 		fDevice(NULL),
18 		fDescription(device->name),
19 		//
20 		fDeviceOpen(false),
21 		fDeviceRemoved(false),
22 		fBus(device->bus),
23 		fIOBase(ioBase),
24 		fIRQ(irq),
25 		fMaster(master),
26 		fBufferArea(-1),
27 		fReadBuffer(NULL),
28 		fReadBufferSize(ROUNDUP(DEF_BUFFER_SIZE, 16)),
29 		fWriteBuffer(NULL),
30 		fWriteBufferSize(ROUNDUP(DEF_BUFFER_SIZE, 16)),
31 		fInterruptBuffer(NULL),
32 		fInterruptBufferSize(16),
33 		fDoneRead(-1),
34 		fDoneWrite(-1),
35 		fControlOut(0),
36 		fInputStopped(false),
37 		fDeviceThread(-1),
38 		fStopDeviceThread(false)
39 {
40 	memset(&fTTYFile, 0, sizeof(ttyfile));
41 	memset(&fTTY, 0, sizeof(tty));
42 	memset(&fRover, 0, sizeof(ddrover));
43 }
44 
45 
46 SerialDevice::~SerialDevice()
47 {
48 	Removed();
49 
50 	if (fDoneRead >= B_OK)
51 		delete_sem(fDoneRead);
52 	if (fDoneWrite >= B_OK)
53 		delete_sem(fDoneWrite);
54 
55 	if (fBufferArea >= B_OK)
56 		delete_area(fBufferArea);
57 
58 	mutex_destroy(&fReadLock);
59 	mutex_destroy(&fWriteLock);
60 }
61 
62 
63 status_t
64 SerialDevice::Init()
65 {
66 	fDoneRead = create_sem(0, "usb_serial:done_read");
67 	fDoneWrite = create_sem(0, "usb_serial:done_write");
68 	mutex_init(&fReadLock, "usb_serial:read_lock");
69 	mutex_init(&fWriteLock, "usb_serial:write_lock");
70 
71 	size_t totalBuffers = fReadBufferSize + fWriteBufferSize + fInterruptBufferSize;
72 	fBufferArea = create_area("usb_serial:buffers_area", (void **)&fReadBuffer,
73 		B_ANY_KERNEL_ADDRESS, ROUNDUP(totalBuffers, B_PAGE_SIZE), B_CONTIGUOUS,
74 		B_READ_AREA | B_WRITE_AREA);
75 
76 	fWriteBuffer = fReadBuffer + fReadBufferSize;
77 	fInterruptBuffer = fWriteBuffer + fWriteBufferSize;
78 
79 	// disable DLAB
80 	WriteReg8(LCR, 0);
81 
82 	return B_OK;
83 }
84 
85 
86 void
87 SerialDevice::SetModes()
88 {
89 	struct termios tios;
90 	memcpy(&tios, &fTTY.t, sizeof(struct termios));
91 	//TRACE_FUNCRES(trace_termios, &tios);
92 	spin(10000);
93 	uint32 baudIndex = tios.c_cflag & CBAUD;
94 	if (baudIndex > BLAST)
95 		baudIndex = BLAST;
96 
97 	uint8 lcr = 0;
98 	uint16 divisor = SupportDescriptor()->bauds[baudIndex];
99 
100 	switch (tios.c_cflag & CSIZE) {
101 #if	CS5 != CS7
102 	// in case someday...
103 	case CS5:
104 		lcr |= LCR_5BIT;
105 		break;
106 	case CS6:
107 		lcr |= LCR_6BIT;
108 		break;
109 #endif
110 	case CS7:
111 		lcr |= LCR_7BIT;
112 		break;
113 	case CS8:
114 	default:
115 		lcr |= LCR_8BIT;
116 		break;
117 	}
118 
119 	if (tios.c_cflag & CSTOPB)
120 		lcr |= LCR_2STOP;
121 	if (tios.c_cflag & PARENB)
122 		lcr |= LCR_P_EN;
123 	if (tios.c_cflag & PARODD == 0)
124 		lcr |= LCR_P_EVEN;
125 
126 	if (baudIndex == B0) {
127 		// disable
128 		MaskReg8(MCR, MCR_DTR);
129 	} else {
130 		// set FCR now,
131 		// 16650 and later chips have another reg at 2 when DLAB=1
132 		uint8 fcr = FCR_ENABLE | FCR_RX_RST | FCR_TX_RST | FCR_F_8;
133 		// enable fifo
134 		//fcr = 0;
135 		WriteReg8(FCR, fcr);
136 
137 		// unmask the divisor latch regs
138 		WriteReg8(LCR, LCR_DLAB);
139 		// set divisor
140 		WriteReg8(DLLB, divisor & 0x00ff);
141 		WriteReg8(DLHB, divisor >> 8);
142 		//WriteReg8(2,0);
143 
144 	}
145 	// set control lines, and disable divisor latch reg
146 	WriteReg8(LCR, lcr);
147 
148 
149 #if 0
150 	uint16 newControl = fControlOut;
151 
152 	static uint32 baudRates[] = {
153 		0x00000000, //B0
154 		0x00000032, //B50
155 		0x0000004B, //B75
156 		0x0000006E, //B110
157 		0x00000086, //B134
158 		0x00000096, //B150
159 		0x000000C8, //B200
160 		0x0000012C, //B300
161 		0x00000258, //B600
162 		0x000004B0, //B1200
163 		0x00000708, //B1800
164 		0x00000960, //B2400
165 		0x000012C0, //B4800
166 		0x00002580, //B9600
167 		0x00004B00, //B19200
168 		0x00009600, //B38400
169 		0x0000E100, //B57600
170 		0x0001C200, //B115200
171 		0x00038400, //B230400
172 		0x00070800, //460800
173 		0x000E1000, //921600
174 	};
175 
176 	usb_serial_line_coding lineCoding;
177 	lineCoding.speed = baudRates[baudIndex];
178 	lineCoding.stopbits = (tios.c_cflag & CSTOPB) ? LC_STOP_BIT_2 : LC_STOP_BIT_1;
179 
180 	if (tios.c_cflag & PARENB) {
181 		lineCoding.parity = LC_PARITY_EVEN;
182 		if (tios.c_cflag & PARODD)
183 			lineCoding.parity = LC_PARITY_ODD;
184 	} else
185 		lineCoding.parity = LC_PARITY_NONE;
186 
187 	lineCoding.databits = (tios.c_cflag & CS8) ? 8 : 7;
188 
189 	if (lineCoding.speed == 0) {
190 		newControl &= 0xfffffffe;
191 		lineCoding.speed = fLineCoding.speed;
192 	} else
193 		newControl = CLS_LINE_DTR;
194 
195 	if (fControlOut != newControl) {
196 		fControlOut = newControl;
197 		TRACE("newctrl send to modem: 0x%08x\n", newControl);
198 		SetControlLineState(newControl);
199 	}
200 
201 	if (memcmp(&lineCoding, &fLineCoding, sizeof(usb_serial_line_coding)) != 0) {
202 		fLineCoding.speed = lineCoding.speed;
203 		fLineCoding.stopbits = lineCoding.stopbits;
204 		fLineCoding.databits = lineCoding.databits;
205 		fLineCoding.parity = lineCoding.parity;
206 		TRACE("send to modem: speed %d sb: 0x%08x db: 0x%08x parity: 0x%08x\n",
207 			fLineCoding.speed, fLineCoding.stopbits, fLineCoding.databits,
208 			fLineCoding.parity);
209 		SetLineCoding(&fLineCoding);
210 	}
211 #endif
212 }
213 
214 
215 bool
216 SerialDevice::Service(struct tty *ptty, struct ddrover *ddr, uint flags)
217 {
218 	uint8 msr;
219 	status_t err;
220 
221 	if (&fTTY != ptty)
222 		return false;
223 
224 	TRACE_ALWAYS("%s(,,0x%08lx)\n", __FUNCTION__, flags);
225 
226 	if (flags <= TTYGETSIGNALS) {
227 		switch (flags) {
228 			case TTYENABLE:
229 				TRACE("TTYENABLE\n");
230 
231 				SetModes();
232 				err = install_io_interrupt_handler(IRQ(), pc_serial_interrupt, this, 0);
233 				TRACE_ALWAYS("installing irq handler for %d: %s\n", IRQ(), strerror(err));
234 				msr = ReadReg8(MSR);
235 				gTTYModule->ttyhwsignal(ptty, ddr, TTYHWDCD, msr & MSR_DCD);
236 				gTTYModule->ttyhwsignal(ptty, ddr, TTYHWCTS, msr & MSR_CTS);
237 				//
238 				WriteReg8(MCR, MCR_DTR | MCR_RTS | MCR_IRQ_EN /*| MCR_LOOP*//*XXXXXXX*/);
239 				// enable irqs
240 				WriteReg8(IER, IER_RLS | IER_MS | IER_RDA);
241 				//WriteReg8(IER, IER_RDA);
242 				break;
243 
244 			case TTYDISABLE:
245 				TRACE("TTYDISABLE\n");
246 				// remove the handler
247 				remove_io_interrupt_handler(IRQ(), pc_serial_interrupt, this);
248 				// disable IRQ
249 				WriteReg8(IER, 0);
250 				WriteReg8(MCR, 0);
251 				msr = ReadReg8(MSR);
252 				gTTYModule->ttyhwsignal(ptty, ddr, TTYHWDCD, msr & MSR_DCD);
253 				break;
254 
255 			case TTYISTOP:
256 				TRACE("TTYISTOP\n");
257 				MaskReg8(MCR, MCR_RTS);
258 				//fInputStopped = true;
259 				//gTTYModule->ttyhwsignal(ptty, ddr, TTYHWCTS, false);
260 				break;
261 
262 			case TTYIRESUME:
263 				TRACE("TTYIRESUME\n");
264 				OrReg8(MCR, MCR_RTS);
265 				//gTTYModule->ttyhwsignal(ptty, ddr, TTYHWCTS, true);
266 				//fInputStopped = false;
267 				break;
268 
269 			case TTYGETSIGNALS:
270 				TRACE("TTYGETSIGNALS\n");
271 				msr = ReadReg8(MSR);
272 				gTTYModule->ttyhwsignal(ptty, ddr, TTYHWDCD, msr & MSR_DCD);
273 				gTTYModule->ttyhwsignal(ptty, ddr, TTYHWCTS, msr & MSR_CTS);
274 				gTTYModule->ttyhwsignal(ptty, ddr, TTYHWDSR, msr & MSR_DSR);
275 				gTTYModule->ttyhwsignal(ptty, ddr, TTYHWRI, msr & MSR_RI);
276 				break;
277 
278 			case TTYSETMODES:
279 				TRACE("TTYSETMODES\n");
280 				SetModes();
281 //WriteReg8(IER, IER_RLS | IER_MS | IER_RDA);
282 				break;
283 
284 			case TTYOSTART:
285 				TRACE("TTYOSTART\n");
286 				// enable irqs
287 				WriteReg8(IER, IER_RLS | IER_MS | IER_RDA | IER_THRE);
288 				break;
289 			case TTYOSYNC:
290 				TRACE("TTYOSYNC\n");
291 				return (ReadReg8(LSR) & (LSR_THRE | LSR_TSRE)) == (LSR_THRE | LSR_TSRE);
292 				break;
293 			case TTYSETBREAK:
294 				TRACE("TTYSETBREAK\n");
295 				OrReg8(LCR, LCR_BREAK);
296 				break;
297 			case TTYCLRBREAK:
298 				TRACE("TTYCLRBREAK\n");
299 				MaskReg8(LCR, LCR_BREAK);
300 				break;
301 			case TTYSETDTR:
302 				TRACE("TTYSETDTR\n");
303 				OrReg8(MCR, MCR_DTR);
304 				break;
305 			case TTYCLRDTR:
306 				TRACE("TTYCLRDTR\n");
307 				MaskReg8(MCR, MCR_DTR);
308 				break;
309 		}
310 
311 		return true;
312 	}
313 
314 	return false;
315 }
316 
317 
318 int32
319 SerialDevice::InterruptHandler()
320 {
321 	int32 ret = B_UNHANDLED_INTERRUPT;
322 	gTTYModule->ddrstart(&fRover);
323 	gTTYModule->ttyilock(&fTTY, &fRover, true);
324 
325 	uint8 iir, lsr, msr;
326 	int count;
327 
328 	while (((iir = ReadReg8(IIR)) & IIR_PENDING) == 0) { // 0 means yes
329 		int fifoavail = 1;
330 
331 		//DEBUG
332 //		for (count = 0; ReadReg8(LSR) & LSR_DR; count++)
333 //			gTTYModule->ttyin(&fTTY, &fRover, ReadReg8(RBR));
334 
335 		switch (iir & (IIR_IMASK | IIR_TO)) {
336 		case IIR_THRE:
337 			dprintf("IIR_THRE\n");
338 			// check how much fifo we can use
339 			//XXX: move to Init() ?
340 			if (iir & IIR_FMASK == IIR_FMASK)
341 				fifoavail = 16;
342 			if (iir & IIR_F64EN)
343 				fifoavail = 64;
344 			for (int i = 0; i < fifoavail; i++) {
345 				int chr = gTTYModule->ttyout(&fTTY, &fRover);
346 				if (chr < 0) {
347 					//WriteReg8(THB, (uint8)chr);
348 					break;
349 				}
350 				WriteReg8(THB, (uint8)chr);
351 			}
352 			break;
353 		case IIR_TO:
354 		case IIR_TO | IIR_RDA:
355 			// timeout: FALLTHROUGH
356 		case IIR_RDA:
357 			dprintf("IIR_TO/RDA\n");
358 			// while data is ready... get it
359 			while (ReadReg8(LSR) & LSR_DR)
360 				gTTYModule->ttyin(&fTTY, &fRover, ReadReg8(RBR));
361 			break;
362 		case IIR_RLS:
363 			dprintf("IIR_RLS\n");
364 			// ack
365 			lsr = ReadReg8(LSR);
366 			//XXX: handle this somehow
367 			break;
368 		case IIR_MS:
369 			dprintf("IIR_MS\n");
370 			// modem signals changed
371 			msr = ReadReg8(MSR);
372 			if (msr & MSR_DDCD)
373 				gTTYModule->ttyhwsignal(&fTTY, &fRover, TTYHWDCD, msr & MSR_DCD);
374 			if (msr & MSR_DCTS)
375 				gTTYModule->ttyhwsignal(&fTTY, &fRover, TTYHWCTS, msr & MSR_CTS);
376 			if (msr & MSR_DDSR)
377 				gTTYModule->ttyhwsignal(&fTTY, &fRover, TTYHWDSR, msr & MSR_DSR);
378 			if (msr & MSR_TERI)
379 				gTTYModule->ttyhwsignal(&fTTY, &fRover, TTYHWRI, msr & MSR_RI);
380 			break;
381 		default:
382 			dprintf("IIR_?\n");
383 			// something happened
384 			break;
385 		}
386 		ret = B_HANDLED_INTERRUPT;
387 		dprintf("IRQ:h\n");
388 	}
389 
390 
391 	gTTYModule->ttyilock(&fTTY, &fRover, false);
392 	gTTYModule->ddrdone(&fRover);
393 	dprintf("IRQ:r\n");
394 	return ret;
395 }
396 
397 
398 status_t
399 SerialDevice::Open(uint32 flags)
400 {
401 	if (fDeviceOpen)
402 		return B_BUSY;
403 
404 	if (fDeviceRemoved)
405 		return B_DEV_NOT_READY;
406 
407 	gTTYModule->ttyinit(&fTTY, false);
408 	fTTYFile.tty = &fTTY;
409 	fTTYFile.flags = flags;
410 	ResetDevice();
411 
412 	struct ddrover *ddr = gTTYModule->ddrstart(NULL);
413 	if (!ddr)
414 		return B_NO_MEMORY;
415 
416 	gTTYModule->ddacquire(ddr, &gSerialDomain);
417 	status_t status = gTTYModule->ttyopen(&fTTYFile, ddr, pc_serial_service);
418 	gTTYModule->ddrdone(ddr);
419 
420 	if (status < B_OK) {
421 		TRACE_ALWAYS("open: failed to open tty\n");
422 		return status;
423 	}
424 
425 #if 0
426 	fDeviceThread = spawn_kernel_thread(DeviceThread, "usb_serial device thread",
427 		B_NORMAL_PRIORITY, this);
428 
429 	if (fDeviceThread < B_OK) {
430 		TRACE_ALWAYS("open: failed to spawn kernel thread\n");
431 		return fDeviceThread;
432 	}
433 
434 	resume_thread(fDeviceThread);
435 
436 	fControlOut = CLS_LINE_DTR | CLS_LINE_RTS;
437 	SetControlLineState(fControlOut);
438 
439 	status = gUSBModule->queue_interrupt(fControlPipe, fInterruptBuffer,
440 		fInterruptBufferSize, InterruptCallbackFunction, this);
441 	if (status < B_OK)
442 		TRACE_ALWAYS("failed to queue initial interrupt\n");
443 
444 #endif
445 	fDeviceOpen = true;
446 	return B_OK;
447 }
448 
449 
450 status_t
451 SerialDevice::Read(char *buffer, size_t *numBytes)
452 {
453 	if (fDeviceRemoved) {
454 		*numBytes = 0;
455 		return B_DEV_NOT_READY;
456 	}
457 
458 	status_t status;
459 #if 0
460 	status_t status = mutex_lock(&fReadLock);
461 	if (status != B_OK) {
462 		TRACE_ALWAYS("read: failed to get read lock\n");
463 		*numBytes = 0;
464 		return status;
465 	}
466 #endif
467 
468 	struct ddrover *ddr = gTTYModule->ddrstart(NULL);
469 	if (!ddr) {
470 		*numBytes = 0;
471 #if 0
472 		mutex_unlock(&fReadLock);
473 #endif
474 		return B_NO_MEMORY;
475 	}
476 
477 	status = gTTYModule->ttyread(&fTTYFile, ddr, buffer, numBytes);
478 	gTTYModule->ddrdone(ddr);
479 
480 #if 0
481 	mutex_unlock(&fReadLock);
482 #endif
483 	return status;
484 }
485 
486 
487 status_t
488 SerialDevice::Write(const char *buffer, size_t *numBytes)
489 {
490 	size_t bytesLeft = *numBytes;
491 	//*numBytes = 0;
492 
493 	status_t status = EINVAL;
494 	struct ddrover *ddr = gTTYModule->ddrstart(NULL);
495 	if (!ddr) {
496 		*numBytes = 0;
497 		return B_ERROR;
498 	}
499 
500 	status = gTTYModule->ttywrite(&fTTYFile, ddr, buffer, numBytes);
501 	gTTYModule->ddrdone(ddr);
502 
503 #if 0
504 	status_t status = mutex_lock(&fWriteLock);
505 	if (status != B_OK) {
506 		TRACE_ALWAYS("write: failed to get write lock\n");
507 		return status;
508 	}
509 
510 	if (fDeviceRemoved) {
511 		mutex_unlock(&fWriteLock);
512 		return B_DEV_NOT_READY;
513 	}
514 
515 	while (bytesLeft > 0) {
516 		size_t length = MIN(bytesLeft, fWriteBufferSize);
517 		size_t packetLength = length;
518 		OnWrite(buffer, &length, &packetLength);
519 
520 		status = gUSBModule->queue_bulk(fWritePipe, fWriteBuffer,
521 			packetLength, WriteCallbackFunction, this);
522 		if (status < B_OK) {
523 			TRACE_ALWAYS("write: queueing failed with status 0x%08x\n", status);
524 			break;
525 		}
526 
527 		status = acquire_sem_etc(fDoneWrite, 1, B_CAN_INTERRUPT, 0);
528 		if (status < B_OK) {
529 			TRACE_ALWAYS("write: failed to get write done sem 0x%08x\n", status);
530 			break;
531 		}
532 
533 		if (fStatusWrite != B_OK) {
534 			TRACE("write: device status error 0x%08x\n", fStatusWrite);
535 			status = gUSBModule->clear_feature(fWritePipe,
536 				USB_FEATURE_ENDPOINT_HALT);
537 			if (status < B_OK) {
538 				TRACE_ALWAYS("write: failed to clear device halt\n");
539 				status = B_ERROR;
540 				break;
541 			}
542 			continue;
543 		}
544 
545 		buffer += length;
546 		*numBytes += length;
547 		bytesLeft -= length;
548 	}
549 
550 	mutex_unlock(&fWriteLock);
551 #endif
552 	return status;
553 }
554 
555 
556 status_t
557 SerialDevice::Control(uint32 op, void *arg, size_t length)
558 {
559 	if (fDeviceRemoved)
560 		return B_DEV_NOT_READY;
561 
562 	struct ddrover *ddr = gTTYModule->ddrstart(NULL);
563 	if (!ddr)
564 		return B_NO_MEMORY;
565 
566 	status_t status = gTTYModule->ttycontrol(&fTTYFile, ddr, op, arg, length);
567 	gTTYModule->ddrdone(ddr);
568 	return status;
569 }
570 
571 
572 status_t
573 SerialDevice::Select(uint8 event, uint32 ref, selectsync *sync)
574 {
575 	if (fDeviceRemoved)
576 		return B_DEV_NOT_READY;
577 
578 	struct ddrover *ddr = gTTYModule->ddrstart(NULL);
579 	if (!ddr)
580 		return B_NO_MEMORY;
581 
582 	status_t status = gTTYModule->ttyselect(&fTTYFile, ddr, event, ref, sync);
583 	gTTYModule->ddrdone(ddr);
584 	return status;
585 }
586 
587 
588 status_t
589 SerialDevice::DeSelect(uint8 event, selectsync *sync)
590 {
591 	if (fDeviceRemoved)
592 		return B_DEV_NOT_READY;
593 
594 	struct ddrover *ddr = gTTYModule->ddrstart(NULL);
595 	if (!ddr)
596 		return B_NO_MEMORY;
597 
598 	status_t status = gTTYModule->ttydeselect(&fTTYFile, ddr, event, sync);
599 	gTTYModule->ddrdone(ddr);
600 	return status;
601 }
602 
603 
604 status_t
605 SerialDevice::Close()
606 {
607 	OnClose();
608 
609 	if (!fDeviceRemoved) {
610 #if 0
611 		gUSBModule->cancel_queued_transfers(fReadPipe);
612 		gUSBModule->cancel_queued_transfers(fWritePipe);
613 		gUSBModule->cancel_queued_transfers(fControlPipe);
614 #endif
615 	}
616 
617 	struct ddrover *ddr = gTTYModule->ddrstart(NULL);
618 	if (!ddr)
619 		return B_NO_MEMORY;
620 
621 	status_t status = gTTYModule->ttyclose(&fTTYFile, ddr);
622 	gTTYModule->ddrdone(ddr);
623 
624 	fDeviceOpen = false;
625 	return status;
626 }
627 
628 
629 status_t
630 SerialDevice::Free()
631 {
632 	struct ddrover *ddr = gTTYModule->ddrstart(NULL);
633 	if (!ddr)
634 		return B_NO_MEMORY;
635 
636 	status_t status = gTTYModule->ttyfree(&fTTYFile, ddr);
637 	gTTYModule->ddrdone(ddr);
638 	return status;
639 }
640 
641 
642 void
643 SerialDevice::Removed()
644 {
645 	if (fDeviceRemoved)
646 		return;
647 
648 	// notifies us that the device was removed
649 	fDeviceRemoved = true;
650 
651 	// we need to ensure that we do not use the device anymore
652 	fStopDeviceThread = true;
653 	fInputStopped = false;
654 #if 0
655 	gUSBModule->cancel_queued_transfers(fReadPipe);
656 	gUSBModule->cancel_queued_transfers(fWritePipe);
657 	gUSBModule->cancel_queued_transfers(fControlPipe);
658 #endif
659 
660 	int32 result = B_OK;
661 	//wait_for_thread(fDeviceThread, &result);
662 	fDeviceThread = -1;
663 
664 	mutex_lock(&fWriteLock);
665 	mutex_unlock(&fWriteLock);
666 }
667 
668 
669 status_t
670 SerialDevice::AddDevice(const serial_config_descriptor *config)
671 {
672 	// default implementation - does nothing
673 	return B_ERROR;
674 }
675 
676 
677 status_t
678 SerialDevice::ResetDevice()
679 {
680 	// default implementation - does nothing
681 	return B_OK;
682 }
683 
684 
685 #if 0
686 status_t
687 SerialDevice::SetLineCoding(usb_serial_line_coding *coding)
688 {
689 	// default implementation - does nothing
690 	return B_OK;
691 }
692 #endif
693 
694 status_t
695 SerialDevice::SetControlLineState(uint16 state)
696 {
697 	// default implementation - does nothing
698 	return B_OK;
699 }
700 
701 
702 void
703 SerialDevice::OnRead(char **buffer, size_t *numBytes)
704 {
705 	// default implementation - does nothing
706 }
707 
708 
709 void
710 SerialDevice::OnWrite(const char *buffer, size_t *numBytes, size_t *packetBytes)
711 {
712 	// default implementation - does nothing
713 }
714 
715 
716 void
717 SerialDevice::OnClose()
718 {
719 	// default implementation - does nothing
720 }
721 
722 
723 int32
724 SerialDevice::DeviceThread(void *data)
725 {
726 	SerialDevice *device = (SerialDevice *)data;
727 #if 0
728 
729 	while (!device->fStopDeviceThread) {
730 		status_t status = gUSBModule->queue_bulk(device->fReadPipe,
731 			device->fReadBuffer, device->fReadBufferSize,
732 			device->ReadCallbackFunction, data);
733 		if (status < B_OK) {
734 			TRACE_ALWAYS("device thread: queueing failed with error: 0x%08x\n", status);
735 			break;
736 		}
737 
738 		status = acquire_sem_etc(device->fDoneRead, 1, B_CAN_INTERRUPT, 0);
739 		if (status < B_OK) {
740 			TRACE_ALWAYS("device thread: failed to get read done sem 0x%08x\n", status);
741 			break;
742 		}
743 
744 		if (device->fStatusRead != B_OK) {
745 			TRACE("device thread: device status error 0x%08x\n",
746 				device->fStatusRead);
747 			if (gUSBModule->clear_feature(device->fReadPipe,
748 				USB_FEATURE_ENDPOINT_HALT) != B_OK) {
749 				TRACE_ALWAYS("device thread: failed to clear halt feature\n");
750 				break;
751 			}
752 		}
753 
754 		char *buffer = device->fReadBuffer;
755 		size_t readLength = device->fActualLengthRead;
756 		device->OnRead(&buffer, &readLength);
757 		if (readLength == 0)
758 			continue;
759 
760 		ddrover *ddr = gTTYModule->ddrstart(NULL);
761 		if (!ddr) {
762 			TRACE_ALWAYS("device thread: ddrstart problem\n");
763 			return B_NO_MEMORY;
764 		}
765 
766 		while (device->fInputStopped)
767 			snooze(100);
768 
769 		gTTYModule->ttyilock(&device->fTTY, ddr, true);
770 		for (size_t i = 0; i < readLength; i++)
771 			gTTYModule->ttyin(&device->fTTY, ddr, buffer[i]);
772 
773 		gTTYModule->ttyilock(&device->fTTY, ddr, false);
774 		gTTYModule->ddrdone(ddr);
775 	}
776 
777 #endif
778 	return B_OK;
779 }
780 
781 
782 void
783 SerialDevice::ReadCallbackFunction(void *cookie, int32 status, void *data,
784 	uint32 actualLength)
785 {
786 	TRACE_FUNCALLS("read callback: cookie: 0x%08x status: 0x%08x data: 0x%08x len: %lu\n",
787 		cookie, status, data, actualLength);
788 
789 	SerialDevice *device = (SerialDevice *)cookie;
790 	device->fActualLengthRead = actualLength;
791 	device->fStatusRead = status;
792 	release_sem_etc(device->fDoneRead, 1, B_DO_NOT_RESCHEDULE);
793 }
794 
795 
796 void
797 SerialDevice::WriteCallbackFunction(void *cookie, int32 status, void *data,
798 	uint32 actualLength)
799 {
800 	TRACE_FUNCALLS("write callback: cookie: 0x%08x status: 0x%08x data: 0x%08x len: %lu\n",
801 		cookie, status, data, actualLength);
802 
803 	SerialDevice *device = (SerialDevice *)cookie;
804 	device->fActualLengthWrite = actualLength;
805 	device->fStatusWrite = status;
806 	release_sem_etc(device->fDoneWrite, 1, B_DO_NOT_RESCHEDULE);
807 }
808 
809 
810 void
811 SerialDevice::InterruptCallbackFunction(void *cookie, int32 status,
812 	void *data, uint32 actualLength)
813 {
814 	TRACE_FUNCALLS("interrupt callback: cookie: 0x%08x status: 0x%08x data: 0x%08x len: %lu\n",
815 		cookie, status, data, actualLength);
816 
817 	SerialDevice *device = (SerialDevice *)cookie;
818 	device->fActualLengthInterrupt = actualLength;
819 	device->fStatusInterrupt = status;
820 
821 	// ToDo: maybe handle those somehow?
822 
823 	if (status == B_OK && !device->fDeviceRemoved) {
824 #if 0
825 		status = gUSBModule->queue_interrupt(device->fControlPipe,
826 			device->fInterruptBuffer, device->fInterruptBufferSize,
827 			device->InterruptCallbackFunction, device);
828 #endif
829 	}
830 }
831 
832 
833 
834 #if 0
835 SerialDevice *
836 SerialDevice::MakeDevice(usb_device device, uint16 vendorID,
837 	uint16 productID)
838 {
839 	const char *description = NULL;
840 
841 	switch (vendorID) {
842 		case VENDOR_IODATA:
843 		case VENDOR_ATEN:
844 		case VENDOR_TDK:
845 		case VENDOR_RATOC:
846 		case VENDOR_PROLIFIC:
847 		case VENDOR_ELECOM:
848 		case VENDOR_SOURCENEXT:
849 		case VENDOR_HAL:
850 		{
851 			switch (productID) {
852 				case PRODUCT_PROLIFIC_RSAQ2: description = "PL2303 Serial adapter (IODATA USB-RSAQ2)"; break;
853 				case PRODUCT_IODATA_USBRSAQ: description = "I/O Data USB serial adapter USB-RSAQ1"; break;
854 				case PRODUCT_ATEN_UC232A: description = "Aten Serial adapter"; break;
855 				case PRODUCT_TDK_UHA6400: description = "TDK USB-PHS Adapter UHA6400"; break;
856 				case PRODUCT_RATOC_REXUSB60: description = "Ratoc USB serial adapter REX-USB60"; break;
857 				case PRODUCT_PROLIFIC_PL2303: description = "PL2303 Serial adapter (ATEN/IOGEAR UC232A)"; break;
858 				case PRODUCT_ELECOM_UCSGT: description = "Elecom UC-SGT"; break;
859 				case PRODUCT_SOURCENEXT_KEIKAI8: description = "SOURCENEXT KeikaiDenwa 8"; break;
860 				case PRODUCT_SOURCENEXT_KEIKAI8_CHG: description = "SOURCENEXT KeikaiDenwa 8 with charger"; break;
861 				case PRODUCT_HAL_IMR001: description = "HAL Corporation Crossam2+USB"; break;
862 			}
863 
864 			if (!description)
865 				break;
866 
867 			return new ProlificDevice(device, vendorID, productID, description);
868 		}
869 
870 		case VENDOR_FTDI:
871 		{
872 			switch (productID) {
873 				case PRODUCT_FTDI_8U100AX: description = "FTDI 8U100AX serial converter"; break;
874 				case PRODUCT_FTDI_8U232AM: description = "FTDI 8U232AM serial converter"; break;
875 			}
876 
877 			if (!description)
878 				break;
879 
880 			return new FTDIDevice(device, vendorID, productID, description);
881 		}
882 
883 		case VENDOR_PALM:
884 		case VENDOR_KLSI:
885 		{
886 			switch (productID) {
887 				case PRODUCT_PALM_CONNECT: description = "PalmConnect RS232"; break;
888 				case PRODUCT_KLSI_KL5KUSB105D: description = "KLSI KL5KUSB105D"; break;
889 			}
890 
891 			if (!description)
892 				break;
893 
894 			return new KLSIDevice(device, vendorID, productID, description);
895 		}
896 	}
897 
898 	return new ACMDevice(device, vendorID, productID, "CDC ACM compatible device");
899 }
900 #endif
901 
902 
903 uint8
904 SerialDevice::ReadReg8(int reg)
905 {
906 	uint8 ret;
907 	switch (fBus) {
908 	case B_ISA_BUS:
909 		ret = gISAModule->read_io_8(IOBase() + reg);
910 		break;
911 	case B_PCI_BUS:
912 		ret = gPCIModule->read_io_8(IOBase() + reg);
913 		break;
914 	default:
915 		TRACE_ALWAYS("%s: unknown bus!\n", __FUNCTION__);
916 		ret = 0;
917 	//XXX:pcmcia ?
918 	}
919 	TRACE_ALWAYS("RR8(%d) = %d [%02x]\n", reg, ret, ret);
920 	//spin(1000);
921 	return ret;
922 }
923 
924 void
925 SerialDevice::WriteReg8(int reg, uint8 value)
926 {
927 //	TRACE_ALWAYS("WR8(0x%04x+%d, %d [0x%x])\n", IOBase(), reg, value, value);
928 	TRACE_ALWAYS("WR8(%d, %d [0x%x])\n", reg, value, value);
929 	switch (fBus) {
930 	case B_ISA_BUS:
931 		gISAModule->write_io_8(IOBase() + reg, value);
932 		break;
933 	case B_PCI_BUS:
934 		gPCIModule->write_io_8(IOBase() + reg, value);
935 		break;
936 	default:
937 		TRACE_ALWAYS("%s: unknown bus!\n", __FUNCTION__);
938 	//XXX:pcmcia ?
939 	}
940 	//spin(10000);
941 }
942 
943 
944 void
945 SerialDevice::OrReg8(int reg, uint8 value)
946 {
947 	WriteReg8(reg, ReadReg8(reg) | value);
948 }
949 
950 
951 void
952 SerialDevice::AndReg8(int reg, uint8 value)
953 {
954 	WriteReg8(reg, ReadReg8(reg) & value);
955 }
956 
957 
958 void
959 SerialDevice::MaskReg8(int reg, uint8 value)
960 {
961 	WriteReg8(reg, ReadReg8(reg) & ~value);
962 }
963