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