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