xref: /plan9-contrib/sys/src/9/pc/uarti8250.c (revision 3d8d68dd17293a991eef0262bb22083c92b38140)
19a747e4fSDavid du Colombier #include "u.h"
29a747e4fSDavid du Colombier #include "../port/lib.h"
39a747e4fSDavid du Colombier #include "mem.h"
49a747e4fSDavid du Colombier #include "dat.h"
59a747e4fSDavid du Colombier #include "fns.h"
69a747e4fSDavid du Colombier #include "io.h"
79a747e4fSDavid du Colombier #include "../port/error.h"
89a747e4fSDavid du Colombier 
99a747e4fSDavid du Colombier /*
109a747e4fSDavid du Colombier  * 8250 UART and compatibles.
119a747e4fSDavid du Colombier  */
129a747e4fSDavid du Colombier enum {
139a747e4fSDavid du Colombier 	Uart0		= 0x3F8,	/* COM1 */
149a747e4fSDavid du Colombier 	Uart0IRQ	= 4,
159a747e4fSDavid du Colombier 	Uart1		= 0x2F8,	/* COM2 */
169a747e4fSDavid du Colombier 	Uart1IRQ	= 3,
179a747e4fSDavid du Colombier 
189a747e4fSDavid du Colombier 	UartFREQ	= 1843200,
199a747e4fSDavid du Colombier };
209a747e4fSDavid du Colombier 
219a747e4fSDavid du Colombier enum {					/* I/O ports */
229a747e4fSDavid du Colombier 	Rbr		= 0,		/* Receiver Buffer (RO) */
239a747e4fSDavid du Colombier 	Thr		= 0,		/* Transmitter Holding (WO) */
249a747e4fSDavid du Colombier 	Ier		= 1,		/* Interrupt Enable */
259a747e4fSDavid du Colombier 	Iir		= 2,		/* Interrupt Identification (RO) */
269a747e4fSDavid du Colombier 	Fcr		= 2,		/* FIFO Control (WO) */
279a747e4fSDavid du Colombier 	Lcr		= 3,		/* Line Control */
289a747e4fSDavid du Colombier 	Mcr		= 4,		/* Modem Control */
299a747e4fSDavid du Colombier 	Lsr		= 5,		/* Line Status */
309a747e4fSDavid du Colombier 	Msr		= 6,		/* Modem Status */
319a747e4fSDavid du Colombier 	Scr		= 7,		/* Scratch Pad */
329a747e4fSDavid du Colombier 	Dll		= 0,		/* Divisor Latch LSB */
339a747e4fSDavid du Colombier 	Dlm		= 1,		/* Divisor Latch MSB */
349a747e4fSDavid du Colombier };
359a747e4fSDavid du Colombier 
369a747e4fSDavid du Colombier enum {					/* Ier */
379a747e4fSDavid du Colombier 	Erda		= 0x01,		/* Enable Received Data Available */
389a747e4fSDavid du Colombier 	Ethre		= 0x02,		/* Enable Thr Empty */
399a747e4fSDavid du Colombier 	Erls		= 0x04,		/* Enable Receiver Line Status */
409a747e4fSDavid du Colombier 	Ems		= 0x08,		/* Enable Modem Status */
419a747e4fSDavid du Colombier };
429a747e4fSDavid du Colombier 
439a747e4fSDavid du Colombier enum {					/* Iir */
449a747e4fSDavid du Colombier 	Ims		= 0x00,		/* Ms interrupt */
459a747e4fSDavid du Colombier 	Ip		= 0x01,		/* Interrupt Pending (not) */
469a747e4fSDavid du Colombier 	Ithre		= 0x02,		/* Thr Empty */
479a747e4fSDavid du Colombier 	Irda		= 0x04,		/* Received Data Available */
489a747e4fSDavid du Colombier 	Irls		= 0x06,		/* Receiver Line Status */
499a747e4fSDavid du Colombier 	Ictoi		= 0x0C,		/* Character Time-out Indication */
509a747e4fSDavid du Colombier 	IirMASK		= 0x3F,
51e288d156SDavid du Colombier 	Ifena		= 0xC0,		/* FIFOs enabled */
529a747e4fSDavid du Colombier };
539a747e4fSDavid du Colombier 
549a747e4fSDavid du Colombier enum {					/* Fcr */
559a747e4fSDavid du Colombier 	FIFOena		= 0x01,		/* FIFO enable */
569a747e4fSDavid du Colombier 	FIFOrclr	= 0x02,		/* clear Rx FIFO */
579a747e4fSDavid du Colombier 	FIFOtclr	= 0x04,		/* clear Tx FIFO */
589a747e4fSDavid du Colombier 	FIFO1		= 0x00,		/* Rx FIFO trigger level 1 byte */
599a747e4fSDavid du Colombier 	FIFO4		= 0x40,		/*	4 bytes */
609a747e4fSDavid du Colombier 	FIFO8		= 0x80,		/*	8 bytes */
619a747e4fSDavid du Colombier 	FIFO14		= 0xC0,		/*	14 bytes */
629a747e4fSDavid du Colombier };
639a747e4fSDavid du Colombier 
649a747e4fSDavid du Colombier enum {					/* Lcr */
659a747e4fSDavid du Colombier 	Wls5		= 0x00,		/* Word Length Select 5 bits/byte */
669a747e4fSDavid du Colombier 	Wls6		= 0x01,		/*	6 bits/byte */
679a747e4fSDavid du Colombier 	Wls7		= 0x02,		/*	7 bits/byte */
689a747e4fSDavid du Colombier 	Wls8		= 0x03,		/*	8 bits/byte */
699a747e4fSDavid du Colombier 	WlsMASK		= 0x03,
709a747e4fSDavid du Colombier 	Stb		= 0x04,		/* 2 stop bits */
719a747e4fSDavid du Colombier 	Pen		= 0x08,		/* Parity Enable */
729a747e4fSDavid du Colombier 	Eps		= 0x10,		/* Even Parity Select */
739a747e4fSDavid du Colombier 	Stp		= 0x20,		/* Stick Parity */
749a747e4fSDavid du Colombier 	Brk		= 0x40,		/* Break */
759a747e4fSDavid du Colombier 	Dlab		= 0x80,		/* Divisor Latch Access Bit */
769a747e4fSDavid du Colombier };
779a747e4fSDavid du Colombier 
789a747e4fSDavid du Colombier enum {					/* Mcr */
799a747e4fSDavid du Colombier 	Dtr		= 0x01,		/* Data Terminal Ready */
809a747e4fSDavid du Colombier 	Rts		= 0x02,		/* Ready To Send */
819a747e4fSDavid du Colombier 	Out1		= 0x04,		/* no longer in use */
829a747e4fSDavid du Colombier 	Ie		= 0x08,		/* IRQ Enable */
839a747e4fSDavid du Colombier 	Dm		= 0x10,		/* Diagnostic Mode loopback */
849a747e4fSDavid du Colombier };
859a747e4fSDavid du Colombier 
869a747e4fSDavid du Colombier enum {					/* Lsr */
879a747e4fSDavid du Colombier 	Dr		= 0x01,		/* Data Ready */
889a747e4fSDavid du Colombier 	Oe		= 0x02,		/* Overrun Error */
899a747e4fSDavid du Colombier 	Pe		= 0x04,		/* Parity Error */
909a747e4fSDavid du Colombier 	Fe		= 0x08,		/* Framing Error */
919a747e4fSDavid du Colombier 	Bi		= 0x10,		/* Break Interrupt */
929a747e4fSDavid du Colombier 	Thre		= 0x20,		/* Thr Empty */
939a747e4fSDavid du Colombier 	Temt		= 0x40,		/* Tramsmitter Empty */
949a747e4fSDavid du Colombier 	FIFOerr		= 0x80,		/* error in receiver FIFO */
959a747e4fSDavid du Colombier };
969a747e4fSDavid du Colombier 
979a747e4fSDavid du Colombier enum {					/* Msr */
989a747e4fSDavid du Colombier 	Dcts		= 0x01,		/* Delta Cts */
999a747e4fSDavid du Colombier 	Ddsr		= 0x02,		/* Delta Dsr */
1009a747e4fSDavid du Colombier 	Teri		= 0x04,		/* Trailing Edge of Ri */
1019a747e4fSDavid du Colombier 	Ddcd		= 0x08,		/* Delta Dcd */
1029a747e4fSDavid du Colombier 	Cts		= 0x10,		/* Clear To Send */
1039a747e4fSDavid du Colombier 	Dsr		= 0x20,		/* Data Set Ready */
1049a747e4fSDavid du Colombier 	Ri		= 0x40,		/* Ring Indicator */
1059a747e4fSDavid du Colombier 	Dcd		= 0x80,		/* Data Set Ready */
1069a747e4fSDavid du Colombier };
1079a747e4fSDavid du Colombier 
1089a747e4fSDavid du Colombier typedef struct Ctlr {
1099a747e4fSDavid du Colombier 	int	io;
1109a747e4fSDavid du Colombier 	int	irq;
1119a747e4fSDavid du Colombier 	int	tbdf;
1129a747e4fSDavid du Colombier 	int	iena;
1139a747e4fSDavid du Colombier 
1149a747e4fSDavid du Colombier 	uchar	sticky[8];
1159a747e4fSDavid du Colombier 
1169a747e4fSDavid du Colombier 	Lock;
117e288d156SDavid du Colombier 	int	hasfifo;
118e288d156SDavid du Colombier 	int	checkfifo;
1199a747e4fSDavid du Colombier 	int	fena;
1209a747e4fSDavid du Colombier } Ctlr;
1219a747e4fSDavid du Colombier 
1229a747e4fSDavid du Colombier extern PhysUart i8250physuart;
1239a747e4fSDavid du Colombier 
1249a747e4fSDavid du Colombier static Ctlr i8250ctlr[2] = {
1259a747e4fSDavid du Colombier {	.io	= Uart0,
1269a747e4fSDavid du Colombier 	.irq	= Uart0IRQ,
1279a747e4fSDavid du Colombier 	.tbdf	= BUSUNKNOWN, },
1289a747e4fSDavid du Colombier 
1299a747e4fSDavid du Colombier {	.io	= Uart1,
1309a747e4fSDavid du Colombier 	.irq	= Uart1IRQ,
1319a747e4fSDavid du Colombier 	.tbdf	= BUSUNKNOWN, },
1329a747e4fSDavid du Colombier };
1339a747e4fSDavid du Colombier 
1349a747e4fSDavid du Colombier static Uart i8250uart[2] = {
1359a747e4fSDavid du Colombier {	.regs	= &i8250ctlr[0],
1369a747e4fSDavid du Colombier 	.name	= "COM1",
1379a747e4fSDavid du Colombier 	.freq	= UartFREQ,
1389a747e4fSDavid du Colombier 	.phys	= &i8250physuart,
1399a747e4fSDavid du Colombier 	.special= 0,
1409a747e4fSDavid du Colombier 	.next	= &i8250uart[1], },
1419a747e4fSDavid du Colombier 
1429a747e4fSDavid du Colombier {	.regs	= &i8250ctlr[1],
1439a747e4fSDavid du Colombier 	.name	= "COM2",
1449a747e4fSDavid du Colombier 	.freq	= UartFREQ,
1459a747e4fSDavid du Colombier 	.phys	= &i8250physuart,
1469a747e4fSDavid du Colombier 	.special= 0,
1479a747e4fSDavid du Colombier 	.next	= nil, },
1489a747e4fSDavid du Colombier };
1499a747e4fSDavid du Colombier 
1509a747e4fSDavid du Colombier #define csr8r(c, r)	inb((c)->io+(r))
1519a747e4fSDavid du Colombier #define csr8w(c, r, v)	outb((c)->io+(r), (c)->sticky[(r)]|(v))
1529a747e4fSDavid du Colombier 
1539a747e4fSDavid du Colombier static long
i8250status(Uart * uart,void * buf,long n,long offset)1549a747e4fSDavid du Colombier i8250status(Uart* uart, void* buf, long n, long offset)
1559a747e4fSDavid du Colombier {
1569a747e4fSDavid du Colombier 	char *p;
1579a747e4fSDavid du Colombier 	Ctlr *ctlr;
1589a747e4fSDavid du Colombier 	uchar ier, lcr, mcr, msr;
1599a747e4fSDavid du Colombier 
1609a747e4fSDavid du Colombier 	p = malloc(READSTR);
161aa72973aSDavid du Colombier 	if(p == nil)
162aa72973aSDavid du Colombier 		error(Enomem);
163aa72973aSDavid du Colombier 	ctlr = uart->regs;
1649a747e4fSDavid du Colombier 	mcr = ctlr->sticky[Mcr];
1659a747e4fSDavid du Colombier 	msr = csr8r(ctlr, Msr);
1669a747e4fSDavid du Colombier 	ier = ctlr->sticky[Ier];
1679a747e4fSDavid du Colombier 	lcr = ctlr->sticky[Lcr];
1689a747e4fSDavid du Colombier 	snprint(p, READSTR,
1695243b8d1SDavid du Colombier 		"b%d c%d d%d e%d l%d m%d p%c r%d s%d i%d\n"
1705243b8d1SDavid du Colombier 		"dev(%d) type(%d) framing(%d) overruns(%d) "
1715243b8d1SDavid du Colombier 		"berr(%d) serr(%d)%s%s%s%s\n",
1729a747e4fSDavid du Colombier 
1739a747e4fSDavid du Colombier 		uart->baud,
1749a747e4fSDavid du Colombier 		uart->hup_dcd,
1759a747e4fSDavid du Colombier 		(msr & Dsr) != 0,
1769a747e4fSDavid du Colombier 		uart->hup_dsr,
1779a747e4fSDavid du Colombier 		(lcr & WlsMASK) + 5,
1789a747e4fSDavid du Colombier 		(ier & Ems) != 0,
1799a747e4fSDavid du Colombier 		(lcr & Pen) ? ((lcr & Eps) ? 'e': 'o'): 'n',
1809a747e4fSDavid du Colombier 		(mcr & Rts) != 0,
1819a747e4fSDavid du Colombier 		(lcr & Stb) ? 2: 1,
1829a747e4fSDavid du Colombier 		ctlr->fena,
1839a747e4fSDavid du Colombier 
1849a747e4fSDavid du Colombier 		uart->dev,
1859a747e4fSDavid du Colombier 		uart->type,
1869a747e4fSDavid du Colombier 		uart->ferr,
1879a747e4fSDavid du Colombier 		uart->oerr,
1885243b8d1SDavid du Colombier 		uart->berr,
1895243b8d1SDavid du Colombier 		uart->serr,
1909a747e4fSDavid du Colombier 		(msr & Cts) ? " cts": "",
1919a747e4fSDavid du Colombier 		(msr & Dsr) ? " dsr": "",
1929a747e4fSDavid du Colombier 		(msr & Dcd) ? " dcd": "",
1939a747e4fSDavid du Colombier 		(msr & Ri) ? " ring": ""
1949a747e4fSDavid du Colombier 	);
1959a747e4fSDavid du Colombier 	n = readstr(offset, buf, n, p);
1969a747e4fSDavid du Colombier 	free(p);
1979a747e4fSDavid du Colombier 
1989a747e4fSDavid du Colombier 	return n;
1999a747e4fSDavid du Colombier }
2009a747e4fSDavid du Colombier 
2019a747e4fSDavid du Colombier static void
i8250fifo(Uart * uart,int level)202e288d156SDavid du Colombier i8250fifo(Uart* uart, int level)
2039a747e4fSDavid du Colombier {
2049a747e4fSDavid du Colombier 	Ctlr *ctlr;
2059a747e4fSDavid du Colombier 
2069a747e4fSDavid du Colombier 	ctlr = uart->regs;
207e288d156SDavid du Colombier 	if(ctlr->hasfifo == 0)
208e288d156SDavid du Colombier 		return;
2099a747e4fSDavid du Colombier 
210e288d156SDavid du Colombier 	/*
211e288d156SDavid du Colombier 	 * Changing the FIFOena bit in Fcr flushes data
212e288d156SDavid du Colombier 	 * from both receive and transmit FIFOs; there's
213e288d156SDavid du Colombier 	 * no easy way to guarantee not losing data on
214e288d156SDavid du Colombier 	 * the receive side, but it's possible to wait until
215e288d156SDavid du Colombier 	 * the transmitter is really empty.
216e288d156SDavid du Colombier 	 */
2179a747e4fSDavid du Colombier 	ilock(ctlr);
218e288d156SDavid du Colombier 	while(!(csr8r(ctlr, Lsr) & Temt))
219e288d156SDavid du Colombier 		;
2209a747e4fSDavid du Colombier 
221e288d156SDavid du Colombier 	/*
222e288d156SDavid du Colombier 	 * Set the trigger level, default is the max.
223e288d156SDavid du Colombier 	 * value.
224e288d156SDavid du Colombier 	 * Some UARTs require FIFOena to be set before
225e288d156SDavid du Colombier 	 * other bits can take effect, so set it twice.
226e288d156SDavid du Colombier 	 */
227e288d156SDavid du Colombier 	ctlr->fena = level;
228e288d156SDavid du Colombier 	switch(level){
229e288d156SDavid du Colombier 	case 0:
230e288d156SDavid du Colombier 		break;
231e288d156SDavid du Colombier 	case 1:
232e288d156SDavid du Colombier 		level = FIFO1|FIFOena;
233e288d156SDavid du Colombier 		break;
234e288d156SDavid du Colombier 	case 4:
235e288d156SDavid du Colombier 		level = FIFO4|FIFOena;
236e288d156SDavid du Colombier 		break;
237e288d156SDavid du Colombier 	case 8:
238e288d156SDavid du Colombier 		level = FIFO8|FIFOena;
239e288d156SDavid du Colombier 		break;
240e288d156SDavid du Colombier 	default:
241e288d156SDavid du Colombier 		level = FIFO14|FIFOena;
242e288d156SDavid du Colombier 		break;
2439a747e4fSDavid du Colombier 	}
244e288d156SDavid du Colombier 	csr8w(ctlr, Fcr, level);
245e288d156SDavid du Colombier 	csr8w(ctlr, Fcr, level);
2469a747e4fSDavid du Colombier 	iunlock(ctlr);
2479a747e4fSDavid du Colombier }
2489a747e4fSDavid du Colombier 
2499a747e4fSDavid du Colombier static void
i8250dtr(Uart * uart,int on)2509a747e4fSDavid du Colombier i8250dtr(Uart* uart, int on)
2519a747e4fSDavid du Colombier {
2529a747e4fSDavid du Colombier 	Ctlr *ctlr;
2539a747e4fSDavid du Colombier 
2549a747e4fSDavid du Colombier 	/*
2559a747e4fSDavid du Colombier 	 * Toggle DTR.
2569a747e4fSDavid du Colombier 	 */
2579a747e4fSDavid du Colombier 	ctlr = uart->regs;
2589a747e4fSDavid du Colombier 	if(on)
2599a747e4fSDavid du Colombier 		ctlr->sticky[Mcr] |= Dtr;
2609a747e4fSDavid du Colombier 	else
2619a747e4fSDavid du Colombier 		ctlr->sticky[Mcr] &= ~Dtr;
2629a747e4fSDavid du Colombier 	csr8w(ctlr, Mcr, 0);
2639a747e4fSDavid du Colombier }
2649a747e4fSDavid du Colombier 
2659a747e4fSDavid du Colombier static void
i8250rts(Uart * uart,int on)2669a747e4fSDavid du Colombier i8250rts(Uart* uart, int on)
2679a747e4fSDavid du Colombier {
2689a747e4fSDavid du Colombier 	Ctlr *ctlr;
2699a747e4fSDavid du Colombier 
2709a747e4fSDavid du Colombier 	/*
2719a747e4fSDavid du Colombier 	 * Toggle RTS.
2729a747e4fSDavid du Colombier 	 */
2739a747e4fSDavid du Colombier 	ctlr = uart->regs;
2749a747e4fSDavid du Colombier 	if(on)
2759a747e4fSDavid du Colombier 		ctlr->sticky[Mcr] |= Rts;
2769a747e4fSDavid du Colombier 	else
2779a747e4fSDavid du Colombier 		ctlr->sticky[Mcr] &= ~Rts;
2789a747e4fSDavid du Colombier 	csr8w(ctlr, Mcr, 0);
2799a747e4fSDavid du Colombier }
2809a747e4fSDavid du Colombier 
2819a747e4fSDavid du Colombier static void
i8250modemctl(Uart * uart,int on)2829a747e4fSDavid du Colombier i8250modemctl(Uart* uart, int on)
2839a747e4fSDavid du Colombier {
2849a747e4fSDavid du Colombier 	Ctlr *ctlr;
2859a747e4fSDavid du Colombier 
2869a747e4fSDavid du Colombier 	ctlr = uart->regs;
2879a747e4fSDavid du Colombier 	ilock(&uart->tlock);
2889a747e4fSDavid du Colombier 	if(on){
2899a747e4fSDavid du Colombier 		ctlr->sticky[Ier] |= Ems;
2909a747e4fSDavid du Colombier 		csr8w(ctlr, Ier, ctlr->sticky[Ier]);
2919a747e4fSDavid du Colombier 		uart->modem = 1;
2929a747e4fSDavid du Colombier 		uart->cts = csr8r(ctlr, Msr) & Cts;
2939a747e4fSDavid du Colombier 	}
2949a747e4fSDavid du Colombier 	else{
2959a747e4fSDavid du Colombier 		ctlr->sticky[Ier] &= ~Ems;
2969a747e4fSDavid du Colombier 		csr8w(ctlr, Ier, ctlr->sticky[Ier]);
2979a747e4fSDavid du Colombier 		uart->modem = 0;
2989a747e4fSDavid du Colombier 		uart->cts = 1;
2999a747e4fSDavid du Colombier 	}
3009a747e4fSDavid du Colombier 	iunlock(&uart->tlock);
3019a747e4fSDavid du Colombier 
3029a747e4fSDavid du Colombier 	/* modem needs fifo */
3039a747e4fSDavid du Colombier 	(*uart->phys->fifo)(uart, on);
3049a747e4fSDavid du Colombier }
3059a747e4fSDavid du Colombier 
3069a747e4fSDavid du Colombier static int
i8250parity(Uart * uart,int parity)3079a747e4fSDavid du Colombier i8250parity(Uart* uart, int parity)
3089a747e4fSDavid du Colombier {
3099a747e4fSDavid du Colombier 	int lcr;
3109a747e4fSDavid du Colombier 	Ctlr *ctlr;
3119a747e4fSDavid du Colombier 
3129a747e4fSDavid du Colombier 	ctlr = uart->regs;
3139a747e4fSDavid du Colombier 	lcr = ctlr->sticky[Lcr] & ~(Eps|Pen);
3149a747e4fSDavid du Colombier 
3159a747e4fSDavid du Colombier 	switch(parity){
3169a747e4fSDavid du Colombier 	case 'e':
3179a747e4fSDavid du Colombier 		lcr |= Eps|Pen;
3189a747e4fSDavid du Colombier 		break;
3199a747e4fSDavid du Colombier 	case 'o':
3209a747e4fSDavid du Colombier 		lcr |= Pen;
3219a747e4fSDavid du Colombier 		break;
3229a747e4fSDavid du Colombier 	case 'n':
3239a747e4fSDavid du Colombier 		break;
3245243b8d1SDavid du Colombier 	default:
3255243b8d1SDavid du Colombier 		return -1;
3269a747e4fSDavid du Colombier 	}
3279a747e4fSDavid du Colombier 	ctlr->sticky[Lcr] = lcr;
3289a747e4fSDavid du Colombier 	csr8w(ctlr, Lcr, 0);
3299a747e4fSDavid du Colombier 
3309a747e4fSDavid du Colombier 	uart->parity = parity;
3319a747e4fSDavid du Colombier 
3329a747e4fSDavid du Colombier 	return 0;
3339a747e4fSDavid du Colombier }
3349a747e4fSDavid du Colombier 
3359a747e4fSDavid du Colombier static int
i8250stop(Uart * uart,int stop)3369a747e4fSDavid du Colombier i8250stop(Uart* uart, int stop)
3379a747e4fSDavid du Colombier {
3389a747e4fSDavid du Colombier 	int lcr;
3399a747e4fSDavid du Colombier 	Ctlr *ctlr;
3409a747e4fSDavid du Colombier 
3419a747e4fSDavid du Colombier 	ctlr = uart->regs;
3429a747e4fSDavid du Colombier 	lcr = ctlr->sticky[Lcr] & ~Stb;
3439a747e4fSDavid du Colombier 
3449a747e4fSDavid du Colombier 	switch(stop){
3459a747e4fSDavid du Colombier 	case 1:
3469a747e4fSDavid du Colombier 		break;
3479a747e4fSDavid du Colombier 	case 2:
3489a747e4fSDavid du Colombier 		lcr |= Stb;
3499a747e4fSDavid du Colombier 		break;
3509a747e4fSDavid du Colombier 	default:
3519a747e4fSDavid du Colombier 		return -1;
3529a747e4fSDavid du Colombier 	}
3539a747e4fSDavid du Colombier 	ctlr->sticky[Lcr] = lcr;
3549a747e4fSDavid du Colombier 	csr8w(ctlr, Lcr, 0);
3559a747e4fSDavid du Colombier 
3569a747e4fSDavid du Colombier 	uart->stop = stop;
3579a747e4fSDavid du Colombier 
3589a747e4fSDavid du Colombier 	return 0;
3599a747e4fSDavid du Colombier }
3609a747e4fSDavid du Colombier 
3619a747e4fSDavid du Colombier static int
i8250bits(Uart * uart,int bits)3629a747e4fSDavid du Colombier i8250bits(Uart* uart, int bits)
3639a747e4fSDavid du Colombier {
3649a747e4fSDavid du Colombier 	int lcr;
3659a747e4fSDavid du Colombier 	Ctlr *ctlr;
3669a747e4fSDavid du Colombier 
3679a747e4fSDavid du Colombier 	ctlr = uart->regs;
3689a747e4fSDavid du Colombier 	lcr = ctlr->sticky[Lcr] & ~WlsMASK;
3699a747e4fSDavid du Colombier 
3709a747e4fSDavid du Colombier 	switch(bits){
3719a747e4fSDavid du Colombier 	case 5:
3729a747e4fSDavid du Colombier 		lcr |= Wls5;
3739a747e4fSDavid du Colombier 		break;
3749a747e4fSDavid du Colombier 	case 6:
3759a747e4fSDavid du Colombier 		lcr |= Wls6;
3769a747e4fSDavid du Colombier 		break;
3779a747e4fSDavid du Colombier 	case 7:
3789a747e4fSDavid du Colombier 		lcr |= Wls7;
3799a747e4fSDavid du Colombier 		break;
3809a747e4fSDavid du Colombier 	case 8:
3819a747e4fSDavid du Colombier 		lcr |= Wls8;
3829a747e4fSDavid du Colombier 		break;
3839a747e4fSDavid du Colombier 	default:
3849a747e4fSDavid du Colombier 		return -1;
3859a747e4fSDavid du Colombier 	}
3869a747e4fSDavid du Colombier 	ctlr->sticky[Lcr] = lcr;
3879a747e4fSDavid du Colombier 	csr8w(ctlr, Lcr, 0);
3889a747e4fSDavid du Colombier 
3899a747e4fSDavid du Colombier 	uart->bits = bits;
3909a747e4fSDavid du Colombier 
3919a747e4fSDavid du Colombier 	return 0;
3929a747e4fSDavid du Colombier }
3939a747e4fSDavid du Colombier 
3949a747e4fSDavid du Colombier static int
i8250baud(Uart * uart,int baud)3959a747e4fSDavid du Colombier i8250baud(Uart* uart, int baud)
3969a747e4fSDavid du Colombier {
3979a747e4fSDavid du Colombier 	ulong bgc;
3989a747e4fSDavid du Colombier 	Ctlr *ctlr;
3999a747e4fSDavid du Colombier 
4009a747e4fSDavid du Colombier 	/*
4019a747e4fSDavid du Colombier 	 * Set the Baud rate by calculating and setting the Baud rate
4029a747e4fSDavid du Colombier 	 * Generator Constant. This will work with fairly non-standard
4039a747e4fSDavid du Colombier 	 * Baud rates.
4049a747e4fSDavid du Colombier 	 */
4059a747e4fSDavid du Colombier 	if(uart->freq == 0 || baud <= 0)
4069a747e4fSDavid du Colombier 		return -1;
4079a747e4fSDavid du Colombier 	bgc = (uart->freq+8*baud-1)/(16*baud);
4089a747e4fSDavid du Colombier 
4099a747e4fSDavid du Colombier 	ctlr = uart->regs;
4109a747e4fSDavid du Colombier 	csr8w(ctlr, Lcr, Dlab);
4119a747e4fSDavid du Colombier 	outb(ctlr->io+Dlm, bgc>>8);
4129a747e4fSDavid du Colombier 	outb(ctlr->io+Dll, bgc);
4139a747e4fSDavid du Colombier 	csr8w(ctlr, Lcr, 0);
4149a747e4fSDavid du Colombier 
4159a747e4fSDavid du Colombier 	uart->baud = baud;
4169a747e4fSDavid du Colombier 
4179a747e4fSDavid du Colombier 	return 0;
4189a747e4fSDavid du Colombier }
4199a747e4fSDavid du Colombier 
4209a747e4fSDavid du Colombier static void
i8250break(Uart * uart,int ms)4219a747e4fSDavid du Colombier i8250break(Uart* uart, int ms)
4229a747e4fSDavid du Colombier {
4239a747e4fSDavid du Colombier 	Ctlr *ctlr;
4249a747e4fSDavid du Colombier 
4259a747e4fSDavid du Colombier 	/*
4269a747e4fSDavid du Colombier 	 * Send a break.
4279a747e4fSDavid du Colombier 	 */
4285243b8d1SDavid du Colombier 	if(ms <= 0)
4299a747e4fSDavid du Colombier 		ms = 200;
4309a747e4fSDavid du Colombier 
4319a747e4fSDavid du Colombier 	ctlr = uart->regs;
4329a747e4fSDavid du Colombier 	csr8w(ctlr, Lcr, Brk);
4339a747e4fSDavid du Colombier 	tsleep(&up->sleep, return0, 0, ms);
4349a747e4fSDavid du Colombier 	csr8w(ctlr, Lcr, 0);
4359a747e4fSDavid du Colombier }
4369a747e4fSDavid du Colombier 
4379a747e4fSDavid du Colombier static void
i8250kick(Uart * uart)4389a747e4fSDavid du Colombier i8250kick(Uart* uart)
4399a747e4fSDavid du Colombier {
4409a747e4fSDavid du Colombier 	int i;
4419a747e4fSDavid du Colombier 	Ctlr *ctlr;
4429a747e4fSDavid du Colombier 
4439a747e4fSDavid du Colombier 	if(uart->cts == 0 || uart->blocked)
4449a747e4fSDavid du Colombier 		return;
4459a747e4fSDavid du Colombier 
4469a747e4fSDavid du Colombier 	/*
4479a747e4fSDavid du Colombier 	 *  128 here is an arbitrary limit to make sure
4489a747e4fSDavid du Colombier 	 *  we don't stay in this loop too long.  If the
4499a747e4fSDavid du Colombier 	 *  chip's output queue is longer than 128, too
4509a747e4fSDavid du Colombier 	 *  bad -- presotto
4519a747e4fSDavid du Colombier 	 */
4529a747e4fSDavid du Colombier 	ctlr = uart->regs;
4539a747e4fSDavid du Colombier 	for(i = 0; i < 128; i++){
4549a747e4fSDavid du Colombier 		if(!(csr8r(ctlr, Lsr) & Thre))
4559a747e4fSDavid du Colombier 			break;
4569a747e4fSDavid du Colombier 		if(uart->op >= uart->oe && uartstageoutput(uart) == 0)
4579a747e4fSDavid du Colombier 			break;
4589a747e4fSDavid du Colombier 		outb(ctlr->io+Thr, *(uart->op++));
4599a747e4fSDavid du Colombier 	}
4609a747e4fSDavid du Colombier }
4619a747e4fSDavid du Colombier 
4629a747e4fSDavid du Colombier static void
i8250interrupt(Ureg *,void * arg)4639a747e4fSDavid du Colombier i8250interrupt(Ureg*, void* arg)
4649a747e4fSDavid du Colombier {
4659a747e4fSDavid du Colombier 	Ctlr *ctlr;
4669a747e4fSDavid du Colombier 	Uart *uart;
4679a747e4fSDavid du Colombier 	int iir, lsr, old, r;
4689a747e4fSDavid du Colombier 
4699a747e4fSDavid du Colombier 	uart = arg;
4709a747e4fSDavid du Colombier 
4719a747e4fSDavid du Colombier 	ctlr = uart->regs;
4729a747e4fSDavid du Colombier 	for(iir = csr8r(ctlr, Iir); !(iir & Ip); iir = csr8r(ctlr, Iir)){
4739a747e4fSDavid du Colombier 		switch(iir & IirMASK){
4749a747e4fSDavid du Colombier 		case Ims:		/* Ms interrupt */
4759a747e4fSDavid du Colombier 			r = csr8r(ctlr, Msr);
4769a747e4fSDavid du Colombier 			if(r & Dcts){
4779a747e4fSDavid du Colombier 				ilock(&uart->tlock);
4789a747e4fSDavid du Colombier 				old = uart->cts;
4799a747e4fSDavid du Colombier 				uart->cts = r & Cts;
4809a747e4fSDavid du Colombier 				if(old == 0 && uart->cts)
4819a747e4fSDavid du Colombier 					uart->ctsbackoff = 2;
4829a747e4fSDavid du Colombier 				iunlock(&uart->tlock);
4839a747e4fSDavid du Colombier 			}
4849a747e4fSDavid du Colombier 		 	if(r & Ddsr){
4859a747e4fSDavid du Colombier 				old = r & Dsr;
4869a747e4fSDavid du Colombier 				if(uart->hup_dsr && uart->dsr && !old)
4879a747e4fSDavid du Colombier 					uart->dohup = 1;
4889a747e4fSDavid du Colombier 				uart->dsr = old;
4899a747e4fSDavid du Colombier 			}
4909a747e4fSDavid du Colombier 		 	if(r & Ddcd){
4919a747e4fSDavid du Colombier 				old = r & Dcd;
4929a747e4fSDavid du Colombier 				if(uart->hup_dcd && uart->dcd && !old)
4939a747e4fSDavid du Colombier 					uart->dohup = 1;
4949a747e4fSDavid du Colombier 				uart->dcd = old;
4959a747e4fSDavid du Colombier 			}
4969a747e4fSDavid du Colombier 			break;
4979a747e4fSDavid du Colombier 		case Ithre:		/* Thr Empty */
4989a747e4fSDavid du Colombier 			uartkick(uart);
4999a747e4fSDavid du Colombier 			break;
5009a747e4fSDavid du Colombier 		case Irda:		/* Received Data Available */
501b5630d1bSDavid du Colombier 		case Irls:		/* Receiver Line Status */
5029a747e4fSDavid du Colombier 		case Ictoi:		/* Character Time-out Indication */
5039a747e4fSDavid du Colombier 			/*
5049a747e4fSDavid du Colombier 			 * Consume any received data.
5059a747e4fSDavid du Colombier 			 * If the received byte came in with a break,
5069a747e4fSDavid du Colombier 			 * parity or framing error, throw it away;
5079a747e4fSDavid du Colombier 			 * overrun is an indication that something has
5089a747e4fSDavid du Colombier 			 * already been tossed.
5099a747e4fSDavid du Colombier 			 */
5109a747e4fSDavid du Colombier 			while((lsr = csr8r(ctlr, Lsr)) & Dr){
5115243b8d1SDavid du Colombier 				if(lsr & (FIFOerr|Oe))
5129a747e4fSDavid du Colombier 					uart->oerr++;
5139a747e4fSDavid du Colombier 				if(lsr & Pe)
5149a747e4fSDavid du Colombier 					uart->perr++;
5159a747e4fSDavid du Colombier 				if(lsr & Fe)
5169a747e4fSDavid du Colombier 					uart->ferr++;
5179a747e4fSDavid du Colombier 				r = csr8r(ctlr, Rbr);
5189a747e4fSDavid du Colombier 				if(!(lsr & (Bi|Fe|Pe)))
5199a747e4fSDavid du Colombier 					uartrecv(uart, r);
5209a747e4fSDavid du Colombier 			}
5219a747e4fSDavid du Colombier 			break;
5229a747e4fSDavid du Colombier 
5239a747e4fSDavid du Colombier 		default:
5249a747e4fSDavid du Colombier 			iprint("weird uart interrupt 0x%2.2uX\n", iir);
5259a747e4fSDavid du Colombier 			break;
5269a747e4fSDavid du Colombier 		}
5279a747e4fSDavid du Colombier 	}
5289a747e4fSDavid du Colombier }
5299a747e4fSDavid du Colombier 
5309a747e4fSDavid du Colombier static void
i8250disable(Uart * uart)5319a747e4fSDavid du Colombier i8250disable(Uart* uart)
5329a747e4fSDavid du Colombier {
5339a747e4fSDavid du Colombier 	Ctlr *ctlr;
5349a747e4fSDavid du Colombier 
5359a747e4fSDavid du Colombier 	/*
5369a747e4fSDavid du Colombier  	 * Turn off DTR and RTS, disable interrupts and fifos.
5379a747e4fSDavid du Colombier 	 */
5389a747e4fSDavid du Colombier 	(*uart->phys->dtr)(uart, 0);
5399a747e4fSDavid du Colombier 	(*uart->phys->rts)(uart, 0);
5409a747e4fSDavid du Colombier 	(*uart->phys->fifo)(uart, 0);
5419a747e4fSDavid du Colombier 
5429a747e4fSDavid du Colombier 	ctlr = uart->regs;
5439a747e4fSDavid du Colombier 	ctlr->sticky[Ier] = 0;
5449a747e4fSDavid du Colombier 	csr8w(ctlr, Ier, ctlr->sticky[Ier]);
5459a747e4fSDavid du Colombier 
5469a747e4fSDavid du Colombier 	if(ctlr->iena != 0){
54707a38badSDavid du Colombier 		if(intrdisable(ctlr->irq, i8250interrupt, uart, ctlr->tbdf, uart->name) == 0)
5489a747e4fSDavid du Colombier 			ctlr->iena = 0;
5499a747e4fSDavid du Colombier 	}
5509a747e4fSDavid du Colombier }
5519a747e4fSDavid du Colombier 
5529a747e4fSDavid du Colombier static void
i8250enable(Uart * uart,int ie)5539a747e4fSDavid du Colombier i8250enable(Uart* uart, int ie)
5549a747e4fSDavid du Colombier {
5559a747e4fSDavid du Colombier 	Ctlr *ctlr;
5569a747e4fSDavid du Colombier 
557e288d156SDavid du Colombier 	ctlr = uart->regs;
558e288d156SDavid du Colombier 
559e288d156SDavid du Colombier 	/*
560e288d156SDavid du Colombier 	 * Check if there is a FIFO.
561e288d156SDavid du Colombier 	 * Changing the FIFOena bit in Fcr flushes data
562e288d156SDavid du Colombier 	 * from both receive and transmit FIFOs; there's
563e288d156SDavid du Colombier 	 * no easy way to guarantee not losing data on
564e288d156SDavid du Colombier 	 * the receive side, but it's possible to wait until
565e288d156SDavid du Colombier 	 * the transmitter is really empty.
566e288d156SDavid du Colombier 	 * Also, reading the Iir outwith i8250interrupt()
567e288d156SDavid du Colombier 	 * can be dangerous, but this should only happen
568e29d4813SDavid du Colombier 	 * once before interrupts are enabled.
569e288d156SDavid du Colombier 	 */
570e288d156SDavid du Colombier 	ilock(ctlr);
571e288d156SDavid du Colombier 	if(!ctlr->checkfifo){
572e288d156SDavid du Colombier 		/*
573e288d156SDavid du Colombier 		 * Wait until the transmitter is really empty.
574e288d156SDavid du Colombier 		 */
575e288d156SDavid du Colombier 		while(!(csr8r(ctlr, Lsr) & Temt))
576e288d156SDavid du Colombier 			;
577e288d156SDavid du Colombier 		csr8w(ctlr, Fcr, FIFOena);
578e288d156SDavid du Colombier 		if(csr8r(ctlr, Iir) & Ifena)
579e288d156SDavid du Colombier 			ctlr->hasfifo = 1;
580e288d156SDavid du Colombier 		csr8w(ctlr, Fcr, 0);
581e288d156SDavid du Colombier 		ctlr->checkfifo = 1;
582e288d156SDavid du Colombier 	}
583e288d156SDavid du Colombier 	iunlock(ctlr);
584e288d156SDavid du Colombier 
5859a747e4fSDavid du Colombier 	/*
5869a747e4fSDavid du Colombier  	 * Enable interrupts and turn on DTR and RTS.
5879a747e4fSDavid du Colombier 	 * Be careful if this is called to set up a polled serial line
5889a747e4fSDavid du Colombier 	 * early on not to try to enable interrupts as interrupt-
5899a747e4fSDavid du Colombier 	 * -enabling mechanisms might not be set up yet.
5909a747e4fSDavid du Colombier 	 */
5919a747e4fSDavid du Colombier 	if(ie){
5929a747e4fSDavid du Colombier 		if(ctlr->iena == 0){
5939a747e4fSDavid du Colombier 			intrenable(ctlr->irq, i8250interrupt, uart, ctlr->tbdf, uart->name);
5949a747e4fSDavid du Colombier 			ctlr->iena = 1;
5959a747e4fSDavid du Colombier 		}
5969a747e4fSDavid du Colombier 		ctlr->sticky[Ier] = Ethre|Erda;
5979a747e4fSDavid du Colombier 		ctlr->sticky[Mcr] |= Ie;
5989a747e4fSDavid du Colombier 	}
5999a747e4fSDavid du Colombier 	else{
6009a747e4fSDavid du Colombier 		ctlr->sticky[Ier] = 0;
6019a747e4fSDavid du Colombier 		ctlr->sticky[Mcr] = 0;
6029a747e4fSDavid du Colombier 	}
6039a747e4fSDavid du Colombier 	csr8w(ctlr, Ier, ctlr->sticky[Ier]);
6049a747e4fSDavid du Colombier 	csr8w(ctlr, Mcr, ctlr->sticky[Mcr]);
6059a747e4fSDavid du Colombier 
6069a747e4fSDavid du Colombier 	(*uart->phys->dtr)(uart, 1);
6079a747e4fSDavid du Colombier 	(*uart->phys->rts)(uart, 1);
6089a747e4fSDavid du Colombier 
6099a747e4fSDavid du Colombier 	/*
610b7b24591SDavid du Colombier 	 * During startup, the i8259 interrupt controller is reset.
6119a747e4fSDavid du Colombier 	 * This may result in a lost interrupt from the i8250 uart.
6129a747e4fSDavid du Colombier 	 * The i8250 thinks the interrupt is still outstanding and does not
613b7b24591SDavid du Colombier 	 * generate any further interrupts. The workaround is to call the
614b7b24591SDavid du Colombier 	 * interrupt handler to clear any pending interrupt events.
615b7b24591SDavid du Colombier 	 * Note: this must be done after setting Ier.
6169a747e4fSDavid du Colombier 	 */
6179a747e4fSDavid du Colombier 	if(ie)
6189a747e4fSDavid du Colombier 		i8250interrupt(nil, uart);
6199a747e4fSDavid du Colombier }
6209a747e4fSDavid du Colombier 
6219a747e4fSDavid du Colombier void*
i8250alloc(int io,int irq,int tbdf)6229a747e4fSDavid du Colombier i8250alloc(int io, int irq, int tbdf)
6239a747e4fSDavid du Colombier {
6249a747e4fSDavid du Colombier 	Ctlr *ctlr;
6259a747e4fSDavid du Colombier 
6269a747e4fSDavid du Colombier 	if((ctlr = malloc(sizeof(Ctlr))) != nil){
6279a747e4fSDavid du Colombier 		ctlr->io = io;
6289a747e4fSDavid du Colombier 		ctlr->irq = irq;
6299a747e4fSDavid du Colombier 		ctlr->tbdf = tbdf;
6309a747e4fSDavid du Colombier 	}
6319a747e4fSDavid du Colombier 
6329a747e4fSDavid du Colombier 	return ctlr;
6339a747e4fSDavid du Colombier }
6349a747e4fSDavid du Colombier 
6359a747e4fSDavid du Colombier static Uart*
i8250pnp(void)6369a747e4fSDavid du Colombier i8250pnp(void)
6379a747e4fSDavid du Colombier {
6389a747e4fSDavid du Colombier 	return i8250uart;
6399a747e4fSDavid du Colombier }
6409a747e4fSDavid du Colombier 
6419a747e4fSDavid du Colombier static int
i8250getc(Uart * uart)6429a747e4fSDavid du Colombier i8250getc(Uart *uart)
6439a747e4fSDavid du Colombier {
6449a747e4fSDavid du Colombier 	Ctlr *ctlr;
6459a747e4fSDavid du Colombier 
6469a747e4fSDavid du Colombier 	ctlr = uart->regs;
6479a747e4fSDavid du Colombier 	while(!(csr8r(ctlr, Lsr)&Dr))
6489a747e4fSDavid du Colombier 		delay(1);
6499a747e4fSDavid du Colombier 	return csr8r(ctlr, Rbr);
6509a747e4fSDavid du Colombier }
6519a747e4fSDavid du Colombier 
6529a747e4fSDavid du Colombier static void
i8250putc(Uart * uart,int c)6539a747e4fSDavid du Colombier i8250putc(Uart *uart, int c)
6549a747e4fSDavid du Colombier {
6559a747e4fSDavid du Colombier 	int i;
6569a747e4fSDavid du Colombier 	Ctlr *ctlr;
6579a747e4fSDavid du Colombier 
6589a747e4fSDavid du Colombier 	ctlr = uart->regs;
6599a747e4fSDavid du Colombier 	for(i = 0; !(csr8r(ctlr, Lsr)&Thre) && i < 128; i++)
6609a747e4fSDavid du Colombier 		delay(1);
6619a747e4fSDavid du Colombier 	outb(ctlr->io+Thr, c);
6629a747e4fSDavid du Colombier 	for(i = 0; !(csr8r(ctlr, Lsr)&Thre) && i < 128; i++)
6639a747e4fSDavid du Colombier 		delay(1);
6649a747e4fSDavid du Colombier }
6659a747e4fSDavid du Colombier 
6669a747e4fSDavid du Colombier PhysUart i8250physuart = {
6679a747e4fSDavid du Colombier 	.name		= "i8250",
6689a747e4fSDavid du Colombier 	.pnp		= i8250pnp,
6699a747e4fSDavid du Colombier 	.enable		= i8250enable,
6709a747e4fSDavid du Colombier 	.disable	= i8250disable,
6719a747e4fSDavid du Colombier 	.kick		= i8250kick,
6729a747e4fSDavid du Colombier 	.dobreak	= i8250break,
6739a747e4fSDavid du Colombier 	.baud		= i8250baud,
6749a747e4fSDavid du Colombier 	.bits		= i8250bits,
6759a747e4fSDavid du Colombier 	.stop		= i8250stop,
6769a747e4fSDavid du Colombier 	.parity		= i8250parity,
6779a747e4fSDavid du Colombier 	.modemctl	= i8250modemctl,
6789a747e4fSDavid du Colombier 	.rts		= i8250rts,
6799a747e4fSDavid du Colombier 	.dtr		= i8250dtr,
6809a747e4fSDavid du Colombier 	.status		= i8250status,
6819a747e4fSDavid du Colombier 	.fifo		= i8250fifo,
6829a747e4fSDavid du Colombier 	.getc		= i8250getc,
6839a747e4fSDavid du Colombier 	.putc		= i8250putc,
6849a747e4fSDavid du Colombier };
6859a747e4fSDavid du Colombier 
6869a747e4fSDavid du Colombier void
i8250config(char * p)687*3d8d68ddSDavid du Colombier i8250config(char *p)
6889a747e4fSDavid du Colombier {
6899a747e4fSDavid du Colombier 	Uart *uart;
6909a747e4fSDavid du Colombier 	int n;
691*3d8d68ddSDavid du Colombier 	char *cmd;
6929a747e4fSDavid du Colombier 
693*3d8d68ddSDavid du Colombier 	if(p == nil)
6949a747e4fSDavid du Colombier 		return;
6959a747e4fSDavid du Colombier 	n = strtoul(p, &cmd, 0);
6969a747e4fSDavid du Colombier 	if(p == cmd)
6979a747e4fSDavid du Colombier 		return;
6989a747e4fSDavid du Colombier 	switch(n){
6999a747e4fSDavid du Colombier 	default:
7009a747e4fSDavid du Colombier 		return;
7019a747e4fSDavid du Colombier 	case 0:
7029a747e4fSDavid du Colombier 		uart = &i8250uart[0];
7039a747e4fSDavid du Colombier 		break;
7049a747e4fSDavid du Colombier 	case 1:
7059a747e4fSDavid du Colombier 		uart = &i8250uart[1];
7069a747e4fSDavid du Colombier 		break;
7079a747e4fSDavid du Colombier 	}
7089a747e4fSDavid du Colombier 
709*3d8d68ddSDavid du Colombier 	if(!uart->enabled)
710e288d156SDavid du Colombier 		(*uart->phys->enable)(uart, 0);
7119a747e4fSDavid du Colombier 	uartctl(uart, "b9600 l8 pn s1");
7129a747e4fSDavid du Colombier 	if(*cmd != '\0')
7139a747e4fSDavid du Colombier 		uartctl(uart, cmd);
7149a747e4fSDavid du Colombier 
7159a747e4fSDavid du Colombier 	consuart = uart;
7169a747e4fSDavid du Colombier 	uart->console = 1;
7179a747e4fSDavid du Colombier }
718b7b24591SDavid du Colombier 
719b7b24591SDavid du Colombier void
i8250console(void)720*3d8d68ddSDavid du Colombier i8250console(void)
721*3d8d68ddSDavid du Colombier {
722*3d8d68ddSDavid du Colombier 	i8250config(getconf("console"));
723*3d8d68ddSDavid du Colombier }
724*3d8d68ddSDavid du Colombier 
725*3d8d68ddSDavid du Colombier void
i8250mouse(char * which,int (* putc)(Queue *,int),int setb1200)726b7b24591SDavid du Colombier i8250mouse(char* which, int (*putc)(Queue*, int), int setb1200)
727b7b24591SDavid du Colombier {
728b7b24591SDavid du Colombier 	char *p;
729b7b24591SDavid du Colombier 	int port;
730b7b24591SDavid du Colombier 
731b7b24591SDavid du Colombier 	port = strtol(which, &p, 0);
732b7b24591SDavid du Colombier 	if(p == which || port < 0 || port > 1)
733b7b24591SDavid du Colombier 		error(Ebadarg);
734b7b24591SDavid du Colombier 	uartmouse(&i8250uart[port], putc, setb1200);
735b7b24591SDavid du Colombier }
736aa46331bSDavid du Colombier 
737aa46331bSDavid du Colombier void
i8250setmouseputc(char * which,int (* putc)(Queue *,int))738aa46331bSDavid du Colombier i8250setmouseputc(char* which, int (*putc)(Queue*, int))
739aa46331bSDavid du Colombier {
740aa46331bSDavid du Colombier 	char *p;
741aa46331bSDavid du Colombier 	int port;
742aa46331bSDavid du Colombier 
743aa46331bSDavid du Colombier 	port = strtol(which, &p, 0);
744aa46331bSDavid du Colombier 	if(p == which || port < 0 || port > 1)
745aa46331bSDavid du Colombier 		error(Ebadarg);
746aa46331bSDavid du Colombier 	uartsetmouseputc(&i8250uart[port], putc);
747aa46331bSDavid du Colombier 
748aa46331bSDavid du Colombier }
749