xref: /plan9-contrib/sys/src/9k/386/uarti8250.c (revision 45e6af3b6d7025ef7184352bb3f6852edd8de07e)
19ef1f84bSDavid du Colombier #include "u.h"
29ef1f84bSDavid du Colombier #include "../port/lib.h"
39ef1f84bSDavid du Colombier #include "mem.h"
49ef1f84bSDavid du Colombier #include "dat.h"
59ef1f84bSDavid du Colombier #include "fns.h"
6277b6efdSDavid du Colombier #include "../port/error.h"
79ef1f84bSDavid du Colombier 
89ef1f84bSDavid du Colombier /*
99ef1f84bSDavid du Colombier  * 8250 UART and compatibles.
109ef1f84bSDavid du Colombier  */
119ef1f84bSDavid du Colombier enum {
129ef1f84bSDavid du Colombier 	Uart0		= 0x3F8,	/* COM1 */
139ef1f84bSDavid du Colombier 	Uart0IRQ	= 4,
149ef1f84bSDavid du Colombier 	Uart1		= 0x2F8,	/* COM2 */
159ef1f84bSDavid du Colombier 	Uart1IRQ	= 3,
169ef1f84bSDavid du Colombier 
179ef1f84bSDavid du Colombier 	UartFREQ	= 1843200,
189ef1f84bSDavid du Colombier };
199ef1f84bSDavid du Colombier 
209ef1f84bSDavid du Colombier enum {					/* registers */
219ef1f84bSDavid du Colombier 	Rbr		= 0,		/* Receiver Buffer (RO) */
229ef1f84bSDavid du Colombier 	Thr		= 0,		/* Transmitter Holding (WO) */
239ef1f84bSDavid du Colombier 	Ier		= 1,		/* Interrupt Enable */
249ef1f84bSDavid du Colombier 	Iir		= 2,		/* Interrupt Identification (RO) */
259ef1f84bSDavid du Colombier 	Fcr		= 2,		/* FIFO Control (WO) */
269ef1f84bSDavid du Colombier 	Lcr		= 3,		/* Line Control */
279ef1f84bSDavid du Colombier 	Mcr		= 4,		/* Modem Control */
289ef1f84bSDavid du Colombier 	Lsr		= 5,		/* Line Status */
299ef1f84bSDavid du Colombier 	Msr		= 6,		/* Modem Status */
309ef1f84bSDavid du Colombier 	Scr		= 7,		/* Scratch Pad */
319ef1f84bSDavid du Colombier 	Dll		= 0,		/* Divisor Latch LSB */
329ef1f84bSDavid du Colombier 	Dlm		= 1,		/* Divisor Latch MSB */
339ef1f84bSDavid du Colombier };
349ef1f84bSDavid du Colombier 
359ef1f84bSDavid du Colombier enum {					/* Ier */
369ef1f84bSDavid du Colombier 	Erda		= 0x01,		/* Enable Received Data Available */
379ef1f84bSDavid du Colombier 	Ethre		= 0x02,		/* Enable Thr Empty */
389ef1f84bSDavid du Colombier 	Erls		= 0x04,		/* Enable Receiver Line Status */
399ef1f84bSDavid du Colombier 	Ems		= 0x08,		/* Enable Modem Status */
409ef1f84bSDavid du Colombier };
419ef1f84bSDavid du Colombier 
429ef1f84bSDavid du Colombier enum {					/* Iir */
439ef1f84bSDavid du Colombier 	Ims		= 0x00,		/* Ms interrupt */
449ef1f84bSDavid du Colombier 	Ip		= 0x01,		/* Interrupt Pending (not) */
459ef1f84bSDavid du Colombier 	Ithre		= 0x02,		/* Thr Empty */
469ef1f84bSDavid du Colombier 	Irda		= 0x04,		/* Received Data Available */
479ef1f84bSDavid du Colombier 	Irls		= 0x06,		/* Receiver Line Status */
489ef1f84bSDavid du Colombier 	Ictoi		= 0x0C,		/* Character Time-out Indication */
499ef1f84bSDavid du Colombier 	IirMASK		= 0x3F,
509ef1f84bSDavid du Colombier 	Ifena		= 0xC0,		/* FIFOs enabled */
519ef1f84bSDavid du Colombier };
529ef1f84bSDavid du Colombier 
539ef1f84bSDavid du Colombier enum {					/* Fcr */
549ef1f84bSDavid du Colombier 	FIFOena		= 0x01,		/* FIFO enable */
559ef1f84bSDavid du Colombier 	FIFOrclr	= 0x02,		/* clear Rx FIFO */
569ef1f84bSDavid du Colombier 	FIFOtclr	= 0x04,		/* clear Tx FIFO */
579ef1f84bSDavid du Colombier 	FIFO1		= 0x00,		/* Rx FIFO trigger level 1 byte */
589ef1f84bSDavid du Colombier 	FIFO4		= 0x40,		/*	4 bytes */
599ef1f84bSDavid du Colombier 	FIFO8		= 0x80,		/*	8 bytes */
609ef1f84bSDavid du Colombier 	FIFO14		= 0xC0,		/*	14 bytes */
619ef1f84bSDavid du Colombier };
629ef1f84bSDavid du Colombier 
639ef1f84bSDavid du Colombier enum {					/* Lcr */
649ef1f84bSDavid du Colombier 	Wls5		= 0x00,		/* Word Length Select 5 bits/byte */
659ef1f84bSDavid du Colombier 	Wls6		= 0x01,		/*	6 bits/byte */
669ef1f84bSDavid du Colombier 	Wls7		= 0x02,		/*	7 bits/byte */
679ef1f84bSDavid du Colombier 	Wls8		= 0x03,		/*	8 bits/byte */
689ef1f84bSDavid du Colombier 	WlsMASK		= 0x03,
699ef1f84bSDavid du Colombier 	Stb		= 0x04,		/* 2 stop bits */
709ef1f84bSDavid du Colombier 	Pen		= 0x08,		/* Parity Enable */
719ef1f84bSDavid du Colombier 	Eps		= 0x10,		/* Even Parity Select */
729ef1f84bSDavid du Colombier 	Stp		= 0x20,		/* Stick Parity */
739ef1f84bSDavid du Colombier 	Brk		= 0x40,		/* Break */
749ef1f84bSDavid du Colombier 	Dlab		= 0x80,		/* Divisor Latch Access Bit */
759ef1f84bSDavid du Colombier };
769ef1f84bSDavid du Colombier 
779ef1f84bSDavid du Colombier enum {					/* Mcr */
789ef1f84bSDavid du Colombier 	Dtr		= 0x01,		/* Data Terminal Ready */
799ef1f84bSDavid du Colombier 	Rts		= 0x02,		/* Ready To Send */
809ef1f84bSDavid du Colombier 	Out1		= 0x04,		/* no longer in use */
819ef1f84bSDavid du Colombier 	Ie		= 0x08,		/* IRQ Enable */
829ef1f84bSDavid du Colombier 	Dm		= 0x10,		/* Diagnostic Mode loopback */
839ef1f84bSDavid du Colombier };
849ef1f84bSDavid du Colombier 
859ef1f84bSDavid du Colombier enum {					/* Lsr */
869ef1f84bSDavid du Colombier 	Dr		= 0x01,		/* Data Ready */
879ef1f84bSDavid du Colombier 	Oe		= 0x02,		/* Overrun Error */
889ef1f84bSDavid du Colombier 	Pe		= 0x04,		/* Parity Error */
899ef1f84bSDavid du Colombier 	Fe		= 0x08,		/* Framing Error */
909ef1f84bSDavid du Colombier 	Bi		= 0x10,		/* Break Interrupt */
919ef1f84bSDavid du Colombier 	Thre		= 0x20,		/* Thr Empty */
929ef1f84bSDavid du Colombier 	Temt		= 0x40,		/* Tramsmitter Empty */
939ef1f84bSDavid du Colombier 	FIFOerr		= 0x80,		/* error in receiver FIFO */
949ef1f84bSDavid du Colombier };
959ef1f84bSDavid du Colombier 
969ef1f84bSDavid du Colombier enum {					/* Msr */
979ef1f84bSDavid du Colombier 	Dcts		= 0x01,		/* Delta Cts */
989ef1f84bSDavid du Colombier 	Ddsr		= 0x02,		/* Delta Dsr */
999ef1f84bSDavid du Colombier 	Teri		= 0x04,		/* Trailing Edge of Ri */
1009ef1f84bSDavid du Colombier 	Ddcd		= 0x08,		/* Delta Dcd */
1019ef1f84bSDavid du Colombier 	Cts		= 0x10,		/* Clear To Send */
1029ef1f84bSDavid du Colombier 	Dsr		= 0x20,		/* Data Set Ready */
1039ef1f84bSDavid du Colombier 	Ri		= 0x40,		/* Ring Indicator */
1049ef1f84bSDavid du Colombier 	Dcd		= 0x80,		/* Data Set Ready */
1059ef1f84bSDavid du Colombier };
1069ef1f84bSDavid du Colombier 
1079ef1f84bSDavid du Colombier typedef struct Ctlr {
1089ef1f84bSDavid du Colombier 	int	io;
1099ef1f84bSDavid du Colombier 	int	irq;
1109ef1f84bSDavid du Colombier 	int	tbdf;
1119ef1f84bSDavid du Colombier 	int	iena;
1129ef1f84bSDavid du Colombier 	void*	vector;
1139ef1f84bSDavid du Colombier 	int	poll;
1149ef1f84bSDavid du Colombier 
1159ef1f84bSDavid du Colombier 	uchar	sticky[8];
1169ef1f84bSDavid du Colombier 
1179ef1f84bSDavid du Colombier 	Lock;
1189ef1f84bSDavid du Colombier 	int	hasfifo;
1199ef1f84bSDavid du Colombier 	int	checkfifo;
1209ef1f84bSDavid du Colombier 	int	fena;
1219ef1f84bSDavid du Colombier } Ctlr;
1229ef1f84bSDavid du Colombier 
1239ef1f84bSDavid du Colombier extern PhysUart i8250physuart;
1249ef1f84bSDavid du Colombier 
1259ef1f84bSDavid du Colombier static Ctlr i8250ctlr[2] = {
1269ef1f84bSDavid du Colombier {	.io	= Uart0,
1279ef1f84bSDavid du Colombier 	.irq	= Uart0IRQ,
1289ef1f84bSDavid du Colombier 	.tbdf	= -1,
1299ef1f84bSDavid du Colombier 	.poll	= 0, },
1309ef1f84bSDavid du Colombier 
1319ef1f84bSDavid du Colombier {	.io	= Uart1,
1329ef1f84bSDavid du Colombier 	.irq	= Uart1IRQ,
1339ef1f84bSDavid du Colombier 	.tbdf	= -1,
1349ef1f84bSDavid du Colombier 	.poll	= 0, },
1359ef1f84bSDavid du Colombier };
1369ef1f84bSDavid du Colombier 
1379ef1f84bSDavid du Colombier static Uart i8250uart[2] = {
1389ef1f84bSDavid du Colombier {	.regs	= &i8250ctlr[0],
1399ef1f84bSDavid du Colombier 	.name	= "COM1",
1409ef1f84bSDavid du Colombier 	.freq	= UartFREQ,
1419ef1f84bSDavid du Colombier 	.phys	= &i8250physuart,
1429ef1f84bSDavid du Colombier 	.special= 0,
1439ef1f84bSDavid du Colombier 	.next	= &i8250uart[1], },
1449ef1f84bSDavid du Colombier 
1459ef1f84bSDavid du Colombier {	.regs	= &i8250ctlr[1],
1469ef1f84bSDavid du Colombier 	.name	= "COM2",
1479ef1f84bSDavid du Colombier 	.freq	= UartFREQ,
1489ef1f84bSDavid du Colombier 	.phys	= &i8250physuart,
1499ef1f84bSDavid du Colombier 	.special= 0,
1509ef1f84bSDavid du Colombier 	.next	= nil, },
1519ef1f84bSDavid du Colombier };
1529ef1f84bSDavid du Colombier 
1539ef1f84bSDavid du Colombier #define csr8r(c, r)	inb((c)->io+(r))
1549ef1f84bSDavid du Colombier #define csr8w(c, r, v)	outb((c)->io+(r), (c)->sticky[(r)]|(v))
1559ef1f84bSDavid du Colombier #define csr8o(c, r, v)	outb((c)->io+(r), (v))
1569ef1f84bSDavid du Colombier 
1579ef1f84bSDavid du Colombier static long
i8250status(Uart * uart,void * buf,long n,long offset)1589ef1f84bSDavid du Colombier i8250status(Uart* uart, void* buf, long n, long offset)
1599ef1f84bSDavid du Colombier {
1609ef1f84bSDavid du Colombier 	char *p;
1619ef1f84bSDavid du Colombier 	Ctlr *ctlr;
1629ef1f84bSDavid du Colombier 	uchar ier, lcr, mcr, msr;
1639ef1f84bSDavid du Colombier 
1649ef1f84bSDavid du Colombier 	p = malloc(READSTR);
165277b6efdSDavid du Colombier 	if(p == nil)
166277b6efdSDavid du Colombier 		error(Enomem);
167277b6efdSDavid du Colombier 	ctlr = uart->regs;
1689ef1f84bSDavid du Colombier 	mcr = ctlr->sticky[Mcr];
1699ef1f84bSDavid du Colombier 	msr = csr8r(ctlr, Msr);
1709ef1f84bSDavid du Colombier 	ier = ctlr->sticky[Ier];
1719ef1f84bSDavid du Colombier 	lcr = ctlr->sticky[Lcr];
1729ef1f84bSDavid du Colombier 	snprint(p, READSTR,
1739ef1f84bSDavid du Colombier 		"b%d c%d d%d e%d l%d m%d p%c r%d s%d i%d\n"
1749ef1f84bSDavid du Colombier 		"dev(%d) type(%d) framing(%d) overruns(%d) "
1759ef1f84bSDavid du Colombier 		"berr(%d) serr(%d)%s%s%s%s\n",
1769ef1f84bSDavid du Colombier 
1779ef1f84bSDavid du Colombier 		uart->baud,
1789ef1f84bSDavid du Colombier 		uart->hup_dcd,
1799ef1f84bSDavid du Colombier 		(msr & Dsr) != 0,
1809ef1f84bSDavid du Colombier 		uart->hup_dsr,
1819ef1f84bSDavid du Colombier 		(lcr & WlsMASK) + 5,
1829ef1f84bSDavid du Colombier 		(ier & Ems) != 0,
1839ef1f84bSDavid du Colombier 		(lcr & Pen) ? ((lcr & Eps) ? 'e': 'o'): 'n',
1849ef1f84bSDavid du Colombier 		(mcr & Rts) != 0,
1859ef1f84bSDavid du Colombier 		(lcr & Stb) ? 2: 1,
1869ef1f84bSDavid du Colombier 		ctlr->fena,
1879ef1f84bSDavid du Colombier 
1889ef1f84bSDavid du Colombier 		uart->dev,
1899ef1f84bSDavid du Colombier 		uart->type,
1909ef1f84bSDavid du Colombier 		uart->ferr,
1919ef1f84bSDavid du Colombier 		uart->oerr,
1929ef1f84bSDavid du Colombier 		uart->berr,
1939ef1f84bSDavid du Colombier 		uart->serr,
1949ef1f84bSDavid du Colombier 		(msr & Cts) ? " cts": "",
1959ef1f84bSDavid du Colombier 		(msr & Dsr) ? " dsr": "",
1969ef1f84bSDavid du Colombier 		(msr & Dcd) ? " dcd": "",
1979ef1f84bSDavid du Colombier 		(msr & Ri) ? " ring": ""
1989ef1f84bSDavid du Colombier 	);
1999ef1f84bSDavid du Colombier 	n = readstr(offset, buf, n, p);
2009ef1f84bSDavid du Colombier 	free(p);
2019ef1f84bSDavid du Colombier 
2029ef1f84bSDavid du Colombier 	return n;
2039ef1f84bSDavid du Colombier }
2049ef1f84bSDavid du Colombier 
2059ef1f84bSDavid du Colombier static void
i8250fifo(Uart * uart,int level)2069ef1f84bSDavid du Colombier i8250fifo(Uart* uart, int level)
2079ef1f84bSDavid du Colombier {
2089ef1f84bSDavid du Colombier 	Ctlr *ctlr;
2099ef1f84bSDavid du Colombier 
2109ef1f84bSDavid du Colombier 	ctlr = uart->regs;
2119ef1f84bSDavid du Colombier 	if(ctlr->hasfifo == 0)
2129ef1f84bSDavid du Colombier 		return;
2139ef1f84bSDavid du Colombier 
2149ef1f84bSDavid du Colombier 	/*
2159ef1f84bSDavid du Colombier 	 * Changing the FIFOena bit in Fcr flushes data
2169ef1f84bSDavid du Colombier 	 * from both receive and transmit FIFOs; there's
2179ef1f84bSDavid du Colombier 	 * no easy way to guarantee not losing data on
2189ef1f84bSDavid du Colombier 	 * the receive side, but it's possible to wait until
2199ef1f84bSDavid du Colombier 	 * the transmitter is really empty.
2209ef1f84bSDavid du Colombier 	 */
2219ef1f84bSDavid du Colombier 	ilock(ctlr);
2229ef1f84bSDavid du Colombier 	while(!(csr8r(ctlr, Lsr) & Temt))
2239ef1f84bSDavid du Colombier 		;
2249ef1f84bSDavid du Colombier 
2259ef1f84bSDavid du Colombier 	/*
2269ef1f84bSDavid du Colombier 	 * Set the trigger level, default is the max.
2279ef1f84bSDavid du Colombier 	 * value.
2289ef1f84bSDavid du Colombier 	 * Some UARTs require FIFOena to be set before
2299ef1f84bSDavid du Colombier 	 * other bits can take effect, so set it twice.
2309ef1f84bSDavid du Colombier 	 */
2319ef1f84bSDavid du Colombier 	ctlr->fena = level;
2329ef1f84bSDavid du Colombier 	switch(level){
2339ef1f84bSDavid du Colombier 	case 0:
2349ef1f84bSDavid du Colombier 		break;
2359ef1f84bSDavid du Colombier 	case 1:
2369ef1f84bSDavid du Colombier 		level = FIFO1|FIFOena;
2379ef1f84bSDavid du Colombier 		break;
2389ef1f84bSDavid du Colombier 	case 4:
2399ef1f84bSDavid du Colombier 		level = FIFO4|FIFOena;
2409ef1f84bSDavid du Colombier 		break;
2419ef1f84bSDavid du Colombier 	case 8:
2429ef1f84bSDavid du Colombier 		level = FIFO8|FIFOena;
2439ef1f84bSDavid du Colombier 		break;
2449ef1f84bSDavid du Colombier 	default:
2459ef1f84bSDavid du Colombier 		level = FIFO14|FIFOena;
2469ef1f84bSDavid du Colombier 		break;
2479ef1f84bSDavid du Colombier 	}
2489ef1f84bSDavid du Colombier 	csr8w(ctlr, Fcr, level);
2499ef1f84bSDavid du Colombier 	csr8w(ctlr, Fcr, level);
2509ef1f84bSDavid du Colombier 	iunlock(ctlr);
2519ef1f84bSDavid du Colombier }
2529ef1f84bSDavid du Colombier 
2539ef1f84bSDavid du Colombier static void
i8250dtr(Uart * uart,int on)2549ef1f84bSDavid du Colombier i8250dtr(Uart* uart, int on)
2559ef1f84bSDavid du Colombier {
2569ef1f84bSDavid du Colombier 	Ctlr *ctlr;
2579ef1f84bSDavid du Colombier 
2589ef1f84bSDavid du Colombier 	/*
2599ef1f84bSDavid du Colombier 	 * Toggle DTR.
2609ef1f84bSDavid du Colombier 	 */
2619ef1f84bSDavid du Colombier 	ctlr = uart->regs;
2629ef1f84bSDavid du Colombier 	if(on)
2639ef1f84bSDavid du Colombier 		ctlr->sticky[Mcr] |= Dtr;
2649ef1f84bSDavid du Colombier 	else
2659ef1f84bSDavid du Colombier 		ctlr->sticky[Mcr] &= ~Dtr;
2669ef1f84bSDavid du Colombier 	csr8w(ctlr, Mcr, 0);
2679ef1f84bSDavid du Colombier }
2689ef1f84bSDavid du Colombier 
2699ef1f84bSDavid du Colombier static void
i8250rts(Uart * uart,int on)2709ef1f84bSDavid du Colombier i8250rts(Uart* uart, int on)
2719ef1f84bSDavid du Colombier {
2729ef1f84bSDavid du Colombier 	Ctlr *ctlr;
2739ef1f84bSDavid du Colombier 
2749ef1f84bSDavid du Colombier 	/*
2759ef1f84bSDavid du Colombier 	 * Toggle RTS.
2769ef1f84bSDavid du Colombier 	 */
2779ef1f84bSDavid du Colombier 	ctlr = uart->regs;
2789ef1f84bSDavid du Colombier 	if(on)
2799ef1f84bSDavid du Colombier 		ctlr->sticky[Mcr] |= Rts;
2809ef1f84bSDavid du Colombier 	else
2819ef1f84bSDavid du Colombier 		ctlr->sticky[Mcr] &= ~Rts;
2829ef1f84bSDavid du Colombier 	csr8w(ctlr, Mcr, 0);
2839ef1f84bSDavid du Colombier }
2849ef1f84bSDavid du Colombier 
2859ef1f84bSDavid du Colombier static void
i8250modemctl(Uart * uart,int on)2869ef1f84bSDavid du Colombier i8250modemctl(Uart* uart, int on)
2879ef1f84bSDavid du Colombier {
2889ef1f84bSDavid du Colombier 	Ctlr *ctlr;
2899ef1f84bSDavid du Colombier 
2909ef1f84bSDavid du Colombier 	ctlr = uart->regs;
2919ef1f84bSDavid du Colombier 	ilock(&uart->tlock);
2929ef1f84bSDavid du Colombier 	if(on){
2939ef1f84bSDavid du Colombier 		ctlr->sticky[Ier] |= Ems;
2949ef1f84bSDavid du Colombier 		csr8w(ctlr, Ier, ctlr->sticky[Ier]);
2959ef1f84bSDavid du Colombier 		uart->modem = 1;
2969ef1f84bSDavid du Colombier 		uart->cts = csr8r(ctlr, Msr) & Cts;
2979ef1f84bSDavid du Colombier 	}
2989ef1f84bSDavid du Colombier 	else{
2999ef1f84bSDavid du Colombier 		ctlr->sticky[Ier] &= ~Ems;
3009ef1f84bSDavid du Colombier 		csr8w(ctlr, Ier, ctlr->sticky[Ier]);
3019ef1f84bSDavid du Colombier 		uart->modem = 0;
3029ef1f84bSDavid du Colombier 		uart->cts = 1;
3039ef1f84bSDavid du Colombier 	}
3049ef1f84bSDavid du Colombier 	iunlock(&uart->tlock);
3059ef1f84bSDavid du Colombier 
3069ef1f84bSDavid du Colombier 	/* modem needs fifo */
3079ef1f84bSDavid du Colombier 	(*uart->phys->fifo)(uart, on);
3089ef1f84bSDavid du Colombier }
3099ef1f84bSDavid du Colombier 
3109ef1f84bSDavid du Colombier static int
i8250parity(Uart * uart,int parity)3119ef1f84bSDavid du Colombier i8250parity(Uart* uart, int parity)
3129ef1f84bSDavid du Colombier {
3139ef1f84bSDavid du Colombier 	int lcr;
3149ef1f84bSDavid du Colombier 	Ctlr *ctlr;
3159ef1f84bSDavid du Colombier 
3169ef1f84bSDavid du Colombier 	ctlr = uart->regs;
3179ef1f84bSDavid du Colombier 	lcr = ctlr->sticky[Lcr] & ~(Eps|Pen);
3189ef1f84bSDavid du Colombier 
3199ef1f84bSDavid du Colombier 	switch(parity){
3209ef1f84bSDavid du Colombier 	case 'e':
3219ef1f84bSDavid du Colombier 		lcr |= Eps|Pen;
3229ef1f84bSDavid du Colombier 		break;
3239ef1f84bSDavid du Colombier 	case 'o':
3249ef1f84bSDavid du Colombier 		lcr |= Pen;
3259ef1f84bSDavid du Colombier 		break;
3269ef1f84bSDavid du Colombier 	case 'n':
3279ef1f84bSDavid du Colombier 		break;
3289ef1f84bSDavid du Colombier 	default:
3299ef1f84bSDavid du Colombier 		return -1;
3309ef1f84bSDavid du Colombier 	}
3319ef1f84bSDavid du Colombier 	ctlr->sticky[Lcr] = lcr;
3329ef1f84bSDavid du Colombier 	csr8w(ctlr, Lcr, 0);
3339ef1f84bSDavid du Colombier 
3349ef1f84bSDavid du Colombier 	uart->parity = parity;
3359ef1f84bSDavid du Colombier 
3369ef1f84bSDavid du Colombier 	return 0;
3379ef1f84bSDavid du Colombier }
3389ef1f84bSDavid du Colombier 
3399ef1f84bSDavid du Colombier static int
i8250stop(Uart * uart,int stop)3409ef1f84bSDavid du Colombier i8250stop(Uart* uart, int stop)
3419ef1f84bSDavid du Colombier {
3429ef1f84bSDavid du Colombier 	int lcr;
3439ef1f84bSDavid du Colombier 	Ctlr *ctlr;
3449ef1f84bSDavid du Colombier 
3459ef1f84bSDavid du Colombier 	ctlr = uart->regs;
3469ef1f84bSDavid du Colombier 	lcr = ctlr->sticky[Lcr] & ~Stb;
3479ef1f84bSDavid du Colombier 
3489ef1f84bSDavid du Colombier 	switch(stop){
3499ef1f84bSDavid du Colombier 	case 1:
3509ef1f84bSDavid du Colombier 		break;
3519ef1f84bSDavid du Colombier 	case 2:
3529ef1f84bSDavid du Colombier 		lcr |= Stb;
3539ef1f84bSDavid du Colombier 		break;
3549ef1f84bSDavid du Colombier 	default:
3559ef1f84bSDavid du Colombier 		return -1;
3569ef1f84bSDavid du Colombier 	}
3579ef1f84bSDavid du Colombier 	ctlr->sticky[Lcr] = lcr;
3589ef1f84bSDavid du Colombier 	csr8w(ctlr, Lcr, 0);
3599ef1f84bSDavid du Colombier 
3609ef1f84bSDavid du Colombier 	uart->stop = stop;
3619ef1f84bSDavid du Colombier 
3629ef1f84bSDavid du Colombier 	return 0;
3639ef1f84bSDavid du Colombier }
3649ef1f84bSDavid du Colombier 
3659ef1f84bSDavid du Colombier static int
i8250bits(Uart * uart,int bits)3669ef1f84bSDavid du Colombier i8250bits(Uart* uart, int bits)
3679ef1f84bSDavid du Colombier {
3689ef1f84bSDavid du Colombier 	int lcr;
3699ef1f84bSDavid du Colombier 	Ctlr *ctlr;
3709ef1f84bSDavid du Colombier 
3719ef1f84bSDavid du Colombier 	ctlr = uart->regs;
3729ef1f84bSDavid du Colombier 	lcr = ctlr->sticky[Lcr] & ~WlsMASK;
3739ef1f84bSDavid du Colombier 
3749ef1f84bSDavid du Colombier 	switch(bits){
3759ef1f84bSDavid du Colombier 	case 5:
3769ef1f84bSDavid du Colombier 		lcr |= Wls5;
3779ef1f84bSDavid du Colombier 		break;
3789ef1f84bSDavid du Colombier 	case 6:
3799ef1f84bSDavid du Colombier 		lcr |= Wls6;
3809ef1f84bSDavid du Colombier 		break;
3819ef1f84bSDavid du Colombier 	case 7:
3829ef1f84bSDavid du Colombier 		lcr |= Wls7;
3839ef1f84bSDavid du Colombier 		break;
3849ef1f84bSDavid du Colombier 	case 8:
3859ef1f84bSDavid du Colombier 		lcr |= Wls8;
3869ef1f84bSDavid du Colombier 		break;
3879ef1f84bSDavid du Colombier 	default:
3889ef1f84bSDavid du Colombier 		return -1;
3899ef1f84bSDavid du Colombier 	}
3909ef1f84bSDavid du Colombier 	ctlr->sticky[Lcr] = lcr;
3919ef1f84bSDavid du Colombier 	csr8w(ctlr, Lcr, 0);
3929ef1f84bSDavid du Colombier 
3939ef1f84bSDavid du Colombier 	uart->bits = bits;
3949ef1f84bSDavid du Colombier 
3959ef1f84bSDavid du Colombier 	return 0;
3969ef1f84bSDavid du Colombier }
3979ef1f84bSDavid du Colombier 
3989ef1f84bSDavid du Colombier static int
i8250baud(Uart * uart,int baud)3999ef1f84bSDavid du Colombier i8250baud(Uart* uart, int baud)
4009ef1f84bSDavid du Colombier {
4019ef1f84bSDavid du Colombier 	ulong bgc;
4029ef1f84bSDavid du Colombier 	Ctlr *ctlr;
4039ef1f84bSDavid du Colombier 
4049ef1f84bSDavid du Colombier 	/*
4059ef1f84bSDavid du Colombier 	 * Set the Baud rate by calculating and setting the Baud rate
4069ef1f84bSDavid du Colombier 	 * Generator Constant. This will work with fairly non-standard
4079ef1f84bSDavid du Colombier 	 * Baud rates.
4089ef1f84bSDavid du Colombier 	 */
4099ef1f84bSDavid du Colombier 	if(uart->freq == 0 || baud <= 0)
4109ef1f84bSDavid du Colombier 		return -1;
4119ef1f84bSDavid du Colombier 	bgc = (uart->freq+8*baud-1)/(16*baud);
4129ef1f84bSDavid du Colombier 
4139ef1f84bSDavid du Colombier 	ctlr = uart->regs;
4149ef1f84bSDavid du Colombier 	csr8w(ctlr, Lcr, Dlab);
4159ef1f84bSDavid du Colombier 	csr8o(ctlr, Dlm, bgc>>8);
4169ef1f84bSDavid du Colombier 	csr8o(ctlr, Dll, bgc);
4179ef1f84bSDavid du Colombier 	csr8w(ctlr, Lcr, 0);
4189ef1f84bSDavid du Colombier 
4199ef1f84bSDavid du Colombier 	uart->baud = baud;
4209ef1f84bSDavid du Colombier 
4219ef1f84bSDavid du Colombier 	return 0;
4229ef1f84bSDavid du Colombier }
4239ef1f84bSDavid du Colombier 
4249ef1f84bSDavid du Colombier static void
i8250break(Uart * uart,int ms)4259ef1f84bSDavid du Colombier i8250break(Uart* uart, int ms)
4269ef1f84bSDavid du Colombier {
4279ef1f84bSDavid du Colombier 	Ctlr *ctlr;
4289ef1f84bSDavid du Colombier 
4299ef1f84bSDavid du Colombier 	/*
4309ef1f84bSDavid du Colombier 	 * Send a break.
4319ef1f84bSDavid du Colombier 	 */
4329ef1f84bSDavid du Colombier 	if(ms <= 0)
4339ef1f84bSDavid du Colombier 		ms = 200;
4349ef1f84bSDavid du Colombier 
4359ef1f84bSDavid du Colombier 	ctlr = uart->regs;
4369ef1f84bSDavid du Colombier 	csr8w(ctlr, Lcr, Brk);
4379ef1f84bSDavid du Colombier 	tsleep(&up->sleep, return0, 0, ms);
4389ef1f84bSDavid du Colombier 	csr8w(ctlr, Lcr, 0);
4399ef1f84bSDavid du Colombier }
4409ef1f84bSDavid du Colombier 
4419ef1f84bSDavid du Colombier static void
i8250kick(Uart * uart)4429ef1f84bSDavid du Colombier i8250kick(Uart* uart)
4439ef1f84bSDavid du Colombier {
4449ef1f84bSDavid du Colombier 	int i;
4459ef1f84bSDavid du Colombier 	Ctlr *ctlr;
4469ef1f84bSDavid du Colombier 
4479ef1f84bSDavid du Colombier 	if(uart->cts == 0 || uart->blocked)
4489ef1f84bSDavid du Colombier 		return;
4499ef1f84bSDavid du Colombier 
4509ef1f84bSDavid du Colombier 	/*
4519ef1f84bSDavid du Colombier 	 *  128 here is an arbitrary limit to make sure
4529ef1f84bSDavid du Colombier 	 *  we don't stay in this loop too long.  If the
4539ef1f84bSDavid du Colombier 	 *  chip's output queue is longer than 128, too
4549ef1f84bSDavid du Colombier 	 *  bad -- presotto
4559ef1f84bSDavid du Colombier 	 */
4569ef1f84bSDavid du Colombier 	ctlr = uart->regs;
4579ef1f84bSDavid du Colombier 	for(i = 0; i < 128; i++){
4589ef1f84bSDavid du Colombier 		if(!(csr8r(ctlr, Lsr) & Thre))
4599ef1f84bSDavid du Colombier 			break;
4609ef1f84bSDavid du Colombier 		if(uart->op >= uart->oe && uartstageoutput(uart) == 0)
4619ef1f84bSDavid du Colombier 			break;
4629ef1f84bSDavid du Colombier 		csr8o(ctlr, Thr, *(uart->op++));
4639ef1f84bSDavid du Colombier 	}
4649ef1f84bSDavid du Colombier }
4659ef1f84bSDavid du Colombier 
4669ef1f84bSDavid du Colombier static void
i8250interrupt(Ureg *,void * arg)4679ef1f84bSDavid du Colombier i8250interrupt(Ureg*, void* arg)
4689ef1f84bSDavid du Colombier {
4699ef1f84bSDavid du Colombier 	Ctlr *ctlr;
4709ef1f84bSDavid du Colombier 	Uart *uart;
4719ef1f84bSDavid du Colombier 	int iir, lsr, old, r;
4729ef1f84bSDavid du Colombier 
4739ef1f84bSDavid du Colombier 	uart = arg;
4749ef1f84bSDavid du Colombier 
4759ef1f84bSDavid du Colombier 	ctlr = uart->regs;
4769ef1f84bSDavid du Colombier 	for(iir = csr8r(ctlr, Iir); !(iir & Ip); iir = csr8r(ctlr, Iir)){
4779ef1f84bSDavid du Colombier 		switch(iir & IirMASK){
4789ef1f84bSDavid du Colombier 		case Ims:		/* Ms interrupt */
4799ef1f84bSDavid du Colombier 			r = csr8r(ctlr, Msr);
4809ef1f84bSDavid du Colombier 			if(r & Dcts){
4819ef1f84bSDavid du Colombier 				ilock(&uart->tlock);
4829ef1f84bSDavid du Colombier 				old = uart->cts;
4839ef1f84bSDavid du Colombier 				uart->cts = r & Cts;
4849ef1f84bSDavid du Colombier 				if(old == 0 && uart->cts)
4859ef1f84bSDavid du Colombier 					uart->ctsbackoff = 2;
4869ef1f84bSDavid du Colombier 				iunlock(&uart->tlock);
4879ef1f84bSDavid du Colombier 			}
4889ef1f84bSDavid du Colombier 		 	if(r & Ddsr){
4899ef1f84bSDavid du Colombier 				old = r & Dsr;
4909ef1f84bSDavid du Colombier 				if(uart->hup_dsr && uart->dsr && !old)
4919ef1f84bSDavid du Colombier 					uart->dohup = 1;
4929ef1f84bSDavid du Colombier 				uart->dsr = old;
4939ef1f84bSDavid du Colombier 			}
4949ef1f84bSDavid du Colombier 		 	if(r & Ddcd){
4959ef1f84bSDavid du Colombier 				old = r & Dcd;
4969ef1f84bSDavid du Colombier 				if(uart->hup_dcd && uart->dcd && !old)
4979ef1f84bSDavid du Colombier 					uart->dohup = 1;
4989ef1f84bSDavid du Colombier 				uart->dcd = old;
4999ef1f84bSDavid du Colombier 			}
5009ef1f84bSDavid du Colombier 			break;
5019ef1f84bSDavid du Colombier 		case Ithre:		/* Thr Empty */
5029ef1f84bSDavid du Colombier 			uartkick(uart);
5039ef1f84bSDavid du Colombier 			break;
5049ef1f84bSDavid du Colombier 		case Irda:		/* Received Data Available */
5059ef1f84bSDavid du Colombier 		case Irls:		/* Receiver Line Status */
5069ef1f84bSDavid du Colombier 		case Ictoi:		/* Character Time-out Indication */
5079ef1f84bSDavid du Colombier 			/*
5089ef1f84bSDavid du Colombier 			 * Consume any received data.
5099ef1f84bSDavid du Colombier 			 * If the received byte came in with a break,
5109ef1f84bSDavid du Colombier 			 * parity or framing error, throw it away;
5119ef1f84bSDavid du Colombier 			 * overrun is an indication that something has
5129ef1f84bSDavid du Colombier 			 * already been tossed.
5139ef1f84bSDavid du Colombier 			 */
5149ef1f84bSDavid du Colombier 			while((lsr = csr8r(ctlr, Lsr)) & Dr){
5159ef1f84bSDavid du Colombier 				if(lsr & (FIFOerr|Oe))
5169ef1f84bSDavid du Colombier 					uart->oerr++;
5179ef1f84bSDavid du Colombier 				if(lsr & Pe)
5189ef1f84bSDavid du Colombier 					uart->perr++;
5199ef1f84bSDavid du Colombier 				if(lsr & Fe)
5209ef1f84bSDavid du Colombier 					uart->ferr++;
5219ef1f84bSDavid du Colombier 				r = csr8r(ctlr, Rbr);
5229ef1f84bSDavid du Colombier 				if(!(lsr & (Bi|Fe|Pe)))
5239ef1f84bSDavid du Colombier 					uartrecv(uart, r);
5249ef1f84bSDavid du Colombier 			}
5259ef1f84bSDavid du Colombier 			break;
5269ef1f84bSDavid du Colombier 
5279ef1f84bSDavid du Colombier 		default:
5289ef1f84bSDavid du Colombier 			iprint("weird uart interrupt %#2.2ux\n", iir);
5299ef1f84bSDavid du Colombier 			break;
5309ef1f84bSDavid du Colombier 		}
5319ef1f84bSDavid du Colombier 	}
5329ef1f84bSDavid du Colombier }
5339ef1f84bSDavid du Colombier 
5349ef1f84bSDavid du Colombier static void
i8250disable(Uart * uart)5359ef1f84bSDavid du Colombier i8250disable(Uart* uart)
5369ef1f84bSDavid du Colombier {
5379ef1f84bSDavid du Colombier 	Ctlr *ctlr;
5389ef1f84bSDavid du Colombier 
5399ef1f84bSDavid du Colombier 	/*
5409ef1f84bSDavid du Colombier 	 * Turn off DTR and RTS, disable interrupts and fifos.
5419ef1f84bSDavid du Colombier 	 */
5429ef1f84bSDavid du Colombier 	(*uart->phys->dtr)(uart, 0);
5439ef1f84bSDavid du Colombier 	(*uart->phys->rts)(uart, 0);
5449ef1f84bSDavid du Colombier 	(*uart->phys->fifo)(uart, 0);
5459ef1f84bSDavid du Colombier 
5469ef1f84bSDavid du Colombier 	ctlr = uart->regs;
5479ef1f84bSDavid du Colombier 	ctlr->sticky[Ier] = 0;
5489ef1f84bSDavid du Colombier 	csr8w(ctlr, Ier, ctlr->sticky[Ier]);
5499ef1f84bSDavid du Colombier 
5509ef1f84bSDavid du Colombier 	if(ctlr->iena != 0){
5519ef1f84bSDavid du Colombier 		if(intrdisable(ctlr->vector) == 0)
5529ef1f84bSDavid du Colombier 			ctlr->iena = 0;
5539ef1f84bSDavid du Colombier 	}
5549ef1f84bSDavid du Colombier }
5559ef1f84bSDavid du Colombier 
5569ef1f84bSDavid du Colombier static void
i8250enable(Uart * uart,int ie)5579ef1f84bSDavid du Colombier i8250enable(Uart* uart, int ie)
5589ef1f84bSDavid du Colombier {
5599ef1f84bSDavid du Colombier 	Ctlr *ctlr;
5609ef1f84bSDavid du Colombier 
5619ef1f84bSDavid du Colombier 	ctlr = uart->regs;
5629ef1f84bSDavid du Colombier 
5639ef1f84bSDavid du Colombier 	/*
5649ef1f84bSDavid du Colombier 	 * Check if there is a FIFO.
5659ef1f84bSDavid du Colombier 	 * Changing the FIFOena bit in Fcr flushes data
5669ef1f84bSDavid du Colombier 	 * from both receive and transmit FIFOs; there's
5679ef1f84bSDavid du Colombier 	 * no easy way to guarantee not losing data on
5689ef1f84bSDavid du Colombier 	 * the receive side, but it's possible to wait until
5699ef1f84bSDavid du Colombier 	 * the transmitter is really empty.
5709ef1f84bSDavid du Colombier 	 * Also, reading the Iir outwith i8250interrupt()
5719ef1f84bSDavid du Colombier 	 * can be dangerous, but this should only happen
572277b6efdSDavid du Colombier 	 * once before interrupts are enabled.
5739ef1f84bSDavid du Colombier 	 */
5749ef1f84bSDavid du Colombier 	ilock(ctlr);
5759ef1f84bSDavid du Colombier 	if(!ctlr->checkfifo){
5769ef1f84bSDavid du Colombier 		/*
5779ef1f84bSDavid du Colombier 		 * Wait until the transmitter is really empty.
5789ef1f84bSDavid du Colombier 		 */
5799ef1f84bSDavid du Colombier 		while(!(csr8r(ctlr, Lsr) & Temt))
5809ef1f84bSDavid du Colombier 			;
5819ef1f84bSDavid du Colombier 		csr8w(ctlr, Fcr, FIFOena);
5829ef1f84bSDavid du Colombier 		if(csr8r(ctlr, Iir) & Ifena)
5839ef1f84bSDavid du Colombier 			ctlr->hasfifo = 1;
5849ef1f84bSDavid du Colombier 		csr8w(ctlr, Fcr, 0);
5859ef1f84bSDavid du Colombier 		ctlr->checkfifo = 1;
5869ef1f84bSDavid du Colombier 	}
5879ef1f84bSDavid du Colombier 	iunlock(ctlr);
5889ef1f84bSDavid du Colombier 
5899ef1f84bSDavid du Colombier 	/*
5909ef1f84bSDavid du Colombier 	 * Enable interrupts and turn on DTR and RTS.
5919ef1f84bSDavid du Colombier 	 * Be careful if this is called to set up a polled serial line
5929ef1f84bSDavid du Colombier 	 * early on not to try to enable interrupts as interrupt-
5939ef1f84bSDavid du Colombier 	 * -enabling mechanisms might not be set up yet.
5949ef1f84bSDavid du Colombier 	 */
5959ef1f84bSDavid du Colombier 	if(ie){
5969ef1f84bSDavid du Colombier 		if(ctlr->iena == 0 && !ctlr->poll){
5979ef1f84bSDavid du Colombier 			ctlr->vector = intrenable(ctlr->irq, i8250interrupt, uart, ctlr->tbdf, uart->name);
5989ef1f84bSDavid du Colombier 			ctlr->iena = 1;
5999ef1f84bSDavid du Colombier 		}
6009ef1f84bSDavid du Colombier 		ctlr->sticky[Ier] = Ethre|Erda;
6019ef1f84bSDavid du Colombier 		ctlr->sticky[Mcr] |= Ie;
6029ef1f84bSDavid du Colombier 	}
6039ef1f84bSDavid du Colombier 	else{
6049ef1f84bSDavid du Colombier 		ctlr->sticky[Ier] = 0;
6059ef1f84bSDavid du Colombier 		ctlr->sticky[Mcr] = 0;
6069ef1f84bSDavid du Colombier 	}
6079ef1f84bSDavid du Colombier 	csr8w(ctlr, Ier, ctlr->sticky[Ier]);
6089ef1f84bSDavid du Colombier 	csr8w(ctlr, Mcr, ctlr->sticky[Mcr]);
6099ef1f84bSDavid du Colombier 
6109ef1f84bSDavid du Colombier 	(*uart->phys->dtr)(uart, 1);
6119ef1f84bSDavid du Colombier 	(*uart->phys->rts)(uart, 1);
6129ef1f84bSDavid du Colombier 
6139ef1f84bSDavid du Colombier 	/*
6149ef1f84bSDavid du Colombier 	 * During startup, the i8259 interrupt controller is reset.
6159ef1f84bSDavid du Colombier 	 * This may result in a lost interrupt from the i8250 uart.
6169ef1f84bSDavid du Colombier 	 * The i8250 thinks the interrupt is still outstanding and does not
6179ef1f84bSDavid du Colombier 	 * generate any further interrupts. The workaround is to call the
6189ef1f84bSDavid du Colombier 	 * interrupt handler to clear any pending interrupt events.
6199ef1f84bSDavid du Colombier 	 * Note: this must be done after setting Ier.
6209ef1f84bSDavid du Colombier 	 */
6219ef1f84bSDavid du Colombier 	if(ie)
6229ef1f84bSDavid du Colombier 		i8250interrupt(nil, uart);
6239ef1f84bSDavid du Colombier }
6249ef1f84bSDavid du Colombier 
6259ef1f84bSDavid du Colombier void*
i8250alloc(int io,int irq,int tbdf)6269ef1f84bSDavid du Colombier i8250alloc(int io, int irq, int tbdf)
6279ef1f84bSDavid du Colombier {
6289ef1f84bSDavid du Colombier 	Ctlr *ctlr;
6299ef1f84bSDavid du Colombier 
6309ef1f84bSDavid du Colombier 	if((ctlr = malloc(sizeof(Ctlr))) != nil){
6319ef1f84bSDavid du Colombier 		ctlr->io = io;
6329ef1f84bSDavid du Colombier 		ctlr->irq = irq;
6339ef1f84bSDavid du Colombier 		ctlr->tbdf = tbdf;
6349ef1f84bSDavid du Colombier 	}
6359ef1f84bSDavid du Colombier 
6369ef1f84bSDavid du Colombier 	return ctlr;
6379ef1f84bSDavid du Colombier }
6389ef1f84bSDavid du Colombier 
6399ef1f84bSDavid du Colombier static Uart*
i8250pnp(void)6409ef1f84bSDavid du Colombier i8250pnp(void)
6419ef1f84bSDavid du Colombier {
6429ef1f84bSDavid du Colombier 	int i;
6439ef1f84bSDavid du Colombier 	Ctlr *ctlr;
6449ef1f84bSDavid du Colombier 	Uart *head, *uart;
6459ef1f84bSDavid du Colombier 
6469ef1f84bSDavid du Colombier 	head = i8250uart;
6479ef1f84bSDavid du Colombier 	for(i = 0; i < nelem(i8250uart); i++){
6489ef1f84bSDavid du Colombier 		/*
6499ef1f84bSDavid du Colombier 		 * Does it exist?
6509ef1f84bSDavid du Colombier 		 * Should be able to write/read the Scratch Pad
6519ef1f84bSDavid du Colombier 		 * and reserve the I/O space.
6529ef1f84bSDavid du Colombier 		 */
6539ef1f84bSDavid du Colombier 		uart = &i8250uart[i];
6549ef1f84bSDavid du Colombier 		ctlr = uart->regs;
6559ef1f84bSDavid du Colombier 		csr8o(ctlr, Scr, 0x55);
6569ef1f84bSDavid du Colombier 		if(csr8r(ctlr, Scr) == 0x55)
6579ef1f84bSDavid du Colombier 			continue;
6589ef1f84bSDavid du Colombier 		if(ioalloc(ctlr->io, 8, 0, uart->name) < 0)
6599ef1f84bSDavid du Colombier 			continue;
6609ef1f84bSDavid du Colombier 		if(uart == head)
6619ef1f84bSDavid du Colombier 			head = uart->next;
6629ef1f84bSDavid du Colombier 		else
6639ef1f84bSDavid du Colombier 			(uart-1)->next = uart->next;
6649ef1f84bSDavid du Colombier 	}
6659ef1f84bSDavid du Colombier 
6669ef1f84bSDavid du Colombier 	return head;
6679ef1f84bSDavid du Colombier }
6689ef1f84bSDavid du Colombier 
6699ef1f84bSDavid du Colombier static int
i8250getc(Uart * uart)6709ef1f84bSDavid du Colombier i8250getc(Uart* uart)
6719ef1f84bSDavid du Colombier {
6729ef1f84bSDavid du Colombier 	Ctlr *ctlr;
6739ef1f84bSDavid du Colombier 
6749ef1f84bSDavid du Colombier 	ctlr = uart->regs;
6759ef1f84bSDavid du Colombier 	while(!(csr8r(ctlr, Lsr) & Dr))
6769ef1f84bSDavid du Colombier 		delay(1);
6779ef1f84bSDavid du Colombier 	return csr8r(ctlr, Rbr);
6789ef1f84bSDavid du Colombier }
6799ef1f84bSDavid du Colombier 
6809ef1f84bSDavid du Colombier static void
i8250putc(Uart * uart,int c)6819ef1f84bSDavid du Colombier i8250putc(Uart* uart, int c)
6829ef1f84bSDavid du Colombier {
6839ef1f84bSDavid du Colombier 	int i;
6849ef1f84bSDavid du Colombier 	Ctlr *ctlr;
6859ef1f84bSDavid du Colombier 
6869ef1f84bSDavid du Colombier 	ctlr = uart->regs;
6879ef1f84bSDavid du Colombier 	for(i = 0; !(csr8r(ctlr, Lsr) & Thre) && i < 128; i++)
6889ef1f84bSDavid du Colombier 		delay(1);
6899ef1f84bSDavid du Colombier 	csr8o(ctlr, Thr, c);
6909ef1f84bSDavid du Colombier 	for(i = 0; !(csr8r(ctlr, Lsr) & Thre) && i < 128; i++)
6919ef1f84bSDavid du Colombier 		delay(1);
6929ef1f84bSDavid du Colombier }
6939ef1f84bSDavid du Colombier 
6949ef1f84bSDavid du Colombier static void
i8250poll(Uart * uart)6959ef1f84bSDavid du Colombier i8250poll(Uart* uart)
6969ef1f84bSDavid du Colombier {
6979ef1f84bSDavid du Colombier 	Ctlr *ctlr;
6989ef1f84bSDavid du Colombier 
6999ef1f84bSDavid du Colombier 	/*
7009ef1f84bSDavid du Colombier 	 * If PhysUart has a non-nil .poll member, this
7019ef1f84bSDavid du Colombier 	 * routine will be called from the uartclock timer.
7029ef1f84bSDavid du Colombier 	 * If the Ctlr .poll member is non-zero, when the
7039ef1f84bSDavid du Colombier 	 * Uart is enabled interrupts will not be enabled
7049ef1f84bSDavid du Colombier 	 * and the result is polled input and output.
7059ef1f84bSDavid du Colombier 	 * Not very useful here, but ports to new hardware
7069ef1f84bSDavid du Colombier 	 * or simulators can use this to get serial I/O
7079ef1f84bSDavid du Colombier 	 * without setting up the interrupt mechanism.
7089ef1f84bSDavid du Colombier 	 */
7099ef1f84bSDavid du Colombier 	ctlr = uart->regs;
7109ef1f84bSDavid du Colombier 	if(ctlr->iena || !ctlr->poll)
7119ef1f84bSDavid du Colombier 		return;
7129ef1f84bSDavid du Colombier 	i8250interrupt(nil, uart);
7139ef1f84bSDavid du Colombier }
7149ef1f84bSDavid du Colombier 
7159ef1f84bSDavid du Colombier PhysUart i8250physuart = {
7169ef1f84bSDavid du Colombier 	.name		= "i8250",
7179ef1f84bSDavid du Colombier 	.pnp		= i8250pnp,
7189ef1f84bSDavid du Colombier 	.enable		= i8250enable,
7199ef1f84bSDavid du Colombier 	.disable	= i8250disable,
7209ef1f84bSDavid du Colombier 	.kick		= i8250kick,
7219ef1f84bSDavid du Colombier 	.dobreak	= i8250break,
7229ef1f84bSDavid du Colombier 	.baud		= i8250baud,
7239ef1f84bSDavid du Colombier 	.bits		= i8250bits,
7249ef1f84bSDavid du Colombier 	.stop		= i8250stop,
7259ef1f84bSDavid du Colombier 	.parity		= i8250parity,
7269ef1f84bSDavid du Colombier 	.modemctl	= i8250modemctl,
7279ef1f84bSDavid du Colombier 	.rts		= i8250rts,
7289ef1f84bSDavid du Colombier 	.dtr		= i8250dtr,
7299ef1f84bSDavid du Colombier 	.status		= i8250status,
7309ef1f84bSDavid du Colombier 	.fifo		= i8250fifo,
7319ef1f84bSDavid du Colombier 	.getc		= i8250getc,
7329ef1f84bSDavid du Colombier 	.putc		= i8250putc,
7339ef1f84bSDavid du Colombier 	.poll		= i8250poll,
7349ef1f84bSDavid du Colombier };
7359ef1f84bSDavid du Colombier 
7369ef1f84bSDavid du Colombier Uart*
i8250console(char * cfg)7379ef1f84bSDavid du Colombier i8250console(char* cfg)
7389ef1f84bSDavid du Colombier {
7399ef1f84bSDavid du Colombier 	int i;
7409ef1f84bSDavid du Colombier 	Uart *uart;
7419ef1f84bSDavid du Colombier 	Ctlr *ctlr;
7429ef1f84bSDavid du Colombier 	char *cmd, *p;
7439ef1f84bSDavid du Colombier 	ISAConf isa;
7449ef1f84bSDavid du Colombier 
7459ef1f84bSDavid du Colombier 	/*
7469ef1f84bSDavid du Colombier 	 * Before i8250pnp() is run can only set the console
7479ef1f84bSDavid du Colombier 	 * to 0 or 1 because those are the only uart structs which
7489ef1f84bSDavid du Colombier 	 * will be the same before and after that.
7499ef1f84bSDavid du Colombier 	 */
7509ef1f84bSDavid du Colombier 	if((p = getconf("console")) == nil && (p = cfg) == nil)
7519ef1f84bSDavid du Colombier 		return nil;
7529ef1f84bSDavid du Colombier 	i = strtoul(p, &cmd, 0);
7539ef1f84bSDavid du Colombier 	if(p == cmd)
7549ef1f84bSDavid du Colombier 		return nil;
7559ef1f84bSDavid du Colombier //WTF? Something to do with the PCIe-only machine?
7569ef1f84bSDavid du Colombier 	if((uart = uartconsole(i, cmd)) != nil){
7579ef1f84bSDavid du Colombier 		consuart = uart;
7589ef1f84bSDavid du Colombier 		return uart;
7599ef1f84bSDavid du Colombier 	}
7609ef1f84bSDavid du Colombier 	switch(i){
7619ef1f84bSDavid du Colombier 	default:
7629ef1f84bSDavid du Colombier 		return nil;
7639ef1f84bSDavid du Colombier 	case 0:
7649ef1f84bSDavid du Colombier 		uart = &i8250uart[0];
7659ef1f84bSDavid du Colombier 		break;
7669ef1f84bSDavid du Colombier 	case 1:
7679ef1f84bSDavid du Colombier 		uart = &i8250uart[1];
7689ef1f84bSDavid du Colombier 		break;
7699ef1f84bSDavid du Colombier 	}
7709ef1f84bSDavid du Colombier 
7719ef1f84bSDavid du Colombier //Madness. Something to do with the PCIe-only machine?
7729ef1f84bSDavid du Colombier 	memset(&isa, 0, sizeof(isa));
7739ef1f84bSDavid du Colombier 	ctlr = uart->regs;
7749ef1f84bSDavid du Colombier 	if(isaconfig("eia", i, &isa) != 0){
7759ef1f84bSDavid du Colombier 		if(isa.port != 0)
7769ef1f84bSDavid du Colombier 			ctlr->io = isa.port;
7779ef1f84bSDavid du Colombier 		if(isa.irq != 0)
7789ef1f84bSDavid du Colombier 			ctlr->irq = isa.irq;
7799ef1f84bSDavid du Colombier 		if(isa.freq != 0)
7809ef1f84bSDavid du Colombier 			uart->freq = isa.freq;
7819ef1f84bSDavid du Colombier 	}
7829ef1f84bSDavid du Colombier 
7839ef1f84bSDavid du Colombier 	/*
7849ef1f84bSDavid du Colombier 	 * Does it exist?
7859ef1f84bSDavid du Colombier 	 * Should be able to write/read
7869ef1f84bSDavid du Colombier 	 * the Scratch Pad.
7879ef1f84bSDavid du Colombier 	 */
7889ef1f84bSDavid du Colombier //	ctlr = uart->regs;
7899ef1f84bSDavid du Colombier //	csr8o(ctlr, Scr, 0x55);
7909ef1f84bSDavid du Colombier //	if(csr8r(ctlr, Scr) != 0x55)
7919ef1f84bSDavid du Colombier //		return nil;
7929ef1f84bSDavid du Colombier 
793277b6efdSDavid du Colombier 	if(!uart->enabled)
7949ef1f84bSDavid du Colombier 		(*uart->phys->enable)(uart, 0);
7959ef1f84bSDavid du Colombier 	uartctl(uart, "b9600 l8 pn s1 i1");
7969ef1f84bSDavid du Colombier 	if(*cmd != '\0')
7979ef1f84bSDavid du Colombier 		uartctl(uart, cmd);
7989ef1f84bSDavid du Colombier 
7999ef1f84bSDavid du Colombier 	consuart = uart;
8009ef1f84bSDavid du Colombier 	uart->console = 1;
8019ef1f84bSDavid du Colombier 
8029ef1f84bSDavid du Colombier 	return uart;
8039ef1f84bSDavid du Colombier }
804*45e6af3bSDavid du Colombier 
805*45e6af3bSDavid du Colombier void
i8250mouse(char * which,int (* putc)(Queue *,int),int setb1200)806*45e6af3bSDavid du Colombier i8250mouse(char* which, int (*putc)(Queue*, int), int setb1200)
807*45e6af3bSDavid du Colombier {
808*45e6af3bSDavid du Colombier 	char *p;
809*45e6af3bSDavid du Colombier 	int port;
810*45e6af3bSDavid du Colombier 
811*45e6af3bSDavid du Colombier 	port = strtol(which, &p, 0);
812*45e6af3bSDavid du Colombier 	if(p == which || port < 0 || port > 1)
813*45e6af3bSDavid du Colombier 		error(Ebadarg);
814*45e6af3bSDavid du Colombier 	uartmouse(&i8250uart[port], putc, setb1200);
815*45e6af3bSDavid du Colombier }
816*45e6af3bSDavid du Colombier 
817*45e6af3bSDavid du Colombier void
i8250setmouseputc(char * which,int (* putc)(Queue *,int))818*45e6af3bSDavid du Colombier i8250setmouseputc(char* which, int (*putc)(Queue*, int))
819*45e6af3bSDavid du Colombier {
820*45e6af3bSDavid du Colombier 	char *p;
821*45e6af3bSDavid du Colombier 	int port;
822*45e6af3bSDavid du Colombier 
823*45e6af3bSDavid du Colombier 	port = strtol(which, &p, 0);
824*45e6af3bSDavid du Colombier 	if(p == which || port < 0 || port > 1)
825*45e6af3bSDavid du Colombier 		error(Ebadarg);
826*45e6af3bSDavid du Colombier 	uartsetmouseputc(&i8250uart[port], putc);
827*45e6af3bSDavid du Colombier }
828