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
15SerialDevice::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
57SerialDevice::~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
74status_t
75SerialDevice::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__
98void
99SerialDevice::SetModes()
100{
101	struct termios tios;
102	memcpy(&tios, &fTTY.t, sizeof(struct termios));
103	SetModes(&tios);
104}
105#endif /* __BEOS__ */
106
107
108void
109SerialDevice::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
238bool
239SerialDevice::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
356bool
357SerialDevice::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
458int32
459SerialDevice::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
554status_t
555SerialDevice::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
638status_t
639SerialDevice::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
678status_t
679SerialDevice::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
764status_t
765SerialDevice::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
791status_t
792SerialDevice::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
816status_t
817SerialDevice::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
841status_t
842SerialDevice::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
873status_t
874SerialDevice::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
892void
893SerialDevice::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
919status_t
920SerialDevice::AddDevice(const serial_config_descriptor *config)
921{
922	// default implementation - does nothing
923	return B_ERROR;
924}
925
926
927status_t
928SerialDevice::ResetDevice()
929{
930	// default implementation - does nothing
931	return B_OK;
932}
933
934
935#if 0
936status_t
937SerialDevice::SetLineCoding(usb_serial_line_coding *coding)
938{
939	// default implementation - does nothing
940	return B_OK;
941}
942#endif
943
944status_t
945SerialDevice::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
957void
958SerialDevice::OnRead(char **buffer, size_t *numBytes)
959{
960	// default implementation - does nothing
961}
962
963
964void
965SerialDevice::OnWrite(const char *buffer, size_t *numBytes, size_t *packetBytes)
966{
967	// default implementation - does nothing
968}
969
970
971void
972SerialDevice::OnClose()
973{
974	// default implementation - does nothing
975}
976
977
978int32
979SerialDevice::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
1037void
1038SerialDevice::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
1051void
1052SerialDevice::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
1065void
1066SerialDevice::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
1090SerialDevice *
1091SerialDevice::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
1158uint8
1159SerialDevice::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
1179void
1180SerialDevice::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
1199void
1200SerialDevice::OrReg8(int reg, uint8 value)
1201{
1202	WriteReg8(reg, ReadReg8(reg) | value);
1203}
1204
1205
1206void
1207SerialDevice::AndReg8(int reg, uint8 value)
1208{
1209	WriteReg8(reg, ReadReg8(reg) & value);
1210}
1211
1212
1213void
1214SerialDevice::MaskReg8(int reg, uint8 value)
1215{
1216	WriteReg8(reg, ReadReg8(reg) & ~value);
1217}
1218