xref: /openbsd-src/sys/arch/i386/stand/libsa/bioscons.c (revision 517bfc4a0a64e0dedebb4cb53688095b93790ca7)
1*517bfc4aSbeck /*	$OpenBSD: bioscons.c,v 1.36 2016/05/27 05:37:51 beck Exp $	*/
280d96289Smickey 
380d96289Smickey /*
4857b0937Smickey  * Copyright (c) 1997-1999 Michael Shalayeff
580d96289Smickey  * All rights reserved.
680d96289Smickey  *
780d96289Smickey  * Redistribution and use in source and binary forms, with or without
880d96289Smickey  * modification, are permitted provided that the following conditions
980d96289Smickey  * are met:
1080d96289Smickey  * 1. Redistributions of source code must retain the above copyright
1180d96289Smickey  *    notice, this list of conditions and the following disclaimer.
1280d96289Smickey  * 2. Redistributions in binary form must reproduce the above copyright
1380d96289Smickey  *    notice, this list of conditions and the following disclaimer in the
1480d96289Smickey  *    documentation and/or other materials provided with the distribution.
1580d96289Smickey  *
1680d96289Smickey  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17857b0937Smickey  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18857b0937Smickey  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19857b0937Smickey  * IN NO EVENT SHALL THE AUTHOR OR HIS RELATIVES BE LIABLE FOR ANY DIRECT,
20857b0937Smickey  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21857b0937Smickey  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
22857b0937Smickey  * SERVICES; LOSS OF MIND, USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23857b0937Smickey  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
24857b0937Smickey  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
25857b0937Smickey  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
26857b0937Smickey  * THE POSSIBILITY OF SUCH DAMAGE.
2780d96289Smickey  */
2880d96289Smickey 
2980d96289Smickey #include <sys/types.h>
3080d96289Smickey #include <machine/biosvar.h>
3180d96289Smickey #include <machine/pio.h>
3280d96289Smickey #include <dev/isa/isareg.h>
3380d96289Smickey #include <dev/ic/mc146818reg.h>
34e20327dbSflipk #include <dev/ic/comreg.h>
35e20327dbSflipk #include <dev/ic/ns16450reg.h>
364da2c3beSmickey /* #include <i386/isa/nvram.h> */
3780d96289Smickey #include <dev/cons.h>
38c657d8f4Sniklas #include <lib/libsa/stand.h>
399f2d58dfSderaadt #include "debug.h"
40599546b3Sderaadt #include "biosdev.h"
4180d96289Smickey 
42c657d8f4Sniklas /* XXX cannot trust NVRAM on this.  Maybe later we make a real probe.  */
43c657d8f4Sniklas #if 0
4480d96289Smickey #define PRESENT_MASK (NVRAM_EQUIPMENT_KBD|NVRAM_EQUIPMENT_DISPLAY)
45c657d8f4Sniklas #else
46c657d8f4Sniklas #define PRESENT_MASK 0
47c657d8f4Sniklas #endif
4880d96289Smickey 
4980d96289Smickey void
pc_probe(struct consdev * cn)50599546b3Sderaadt pc_probe(struct consdev *cn)
5180d96289Smickey {
52713cf266Sjsing 	cn->cn_pri = CN_MIDPRI;
539f2d58dfSderaadt 	cn->cn_dev = makedev(12, 0);
544b52c9a5Sderaadt 	printf(" pc%d", minor(cn->cn_dev));
559f2d58dfSderaadt 
569f2d58dfSderaadt #if 0
5780d96289Smickey 	outb(IO_RTC, NVRAM_EQUIPMENT);
5880d96289Smickey 	if ((inb(IO_RTC+1) & PRESENT_MASK) == PRESENT_MASK) {
59713cf266Sjsing 		cn->cn_pri = CN_MIDPRI;
6080d96289Smickey 		/* XXX from i386/conf.c */
6180d96289Smickey 		cn->cn_dev = makedev(12, 0);
624b52c9a5Sderaadt 		printf(" pc%d", minor(cn->cn_dev));
6380d96289Smickey 	}
649f2d58dfSderaadt #endif
6580d96289Smickey }
6680d96289Smickey 
6780d96289Smickey void
pc_init(struct consdev * cn)68599546b3Sderaadt pc_init(struct consdev *cn)
6980d96289Smickey {
7080d96289Smickey }
7180d96289Smickey 
7280d96289Smickey int
pc_getc(dev_t dev)73599546b3Sderaadt pc_getc(dev_t dev)
7480d96289Smickey {
75a9d53ef8Smickey 	register int rv;
76b9eba8b7Smickey 
77b9eba8b7Smickey 	if (dev & 0x80) {
782df76cc2Sguenther 		__asm volatile(DOINT(0x16) "; setnz %b0" : "=a" (rv) :
793f8949d5Smickey 		    "0" (0x100) : "%ecx", "%edx", "cc" );
805a927cd4Smickey 		return (rv & 0xff);
81b9eba8b7Smickey 	}
8280d96289Smickey 
83657ad163Stom 	/*
84657ad163Stom 	 * Wait for a character to actually become available.  Appears to
85657ad163Stom 	 * be necessary on (at least) the Intel Mac Mini.
86657ad163Stom 	 */
87657ad163Stom 	do {
882df76cc2Sguenther 		__asm volatile(DOINT(0x16) "; setnz %b0" : "=a" (rv) :
89657ad163Stom 		    "0" (0x100) : "%ecx", "%edx", "cc" );
90657ad163Stom 	} while ((rv & 0xff) == 0);
91657ad163Stom 
922df76cc2Sguenther 	__asm volatile(DOINT(0x16) : "=a" (rv) : "0" (0x000) :
936ba77b25Saaron 	    "%ecx", "%edx", "cc" );
9461acb34aStom 
955a927cd4Smickey 	return (rv & 0xff);
9680d96289Smickey }
9780d96289Smickey 
987f20cbb1Stom int
pc_getshifts(dev_t dev)997f20cbb1Stom pc_getshifts(dev_t dev)
1007f20cbb1Stom {
1017f20cbb1Stom 	register int rv;
1027f20cbb1Stom 
1032df76cc2Sguenther 	__asm volatile(DOINT(0x16) : "=a" (rv) : "0" (0x200) :
1047f20cbb1Stom 	    "%ecx", "%edx", "cc" );
1057f20cbb1Stom 
1067f20cbb1Stom 	return (rv & 0xff);
1077f20cbb1Stom }
1087f20cbb1Stom 
10980d96289Smickey void
pc_putc(dev_t dev,int c)110599546b3Sderaadt pc_putc(dev_t dev, int c)
11180d96289Smickey {
1122df76cc2Sguenther 	__asm volatile(DOINT(0x10) : : "a" (c | 0xe00), "b" (1) :
113c657d8f4Sniklas 	    "%ecx", "%edx", "cc" );
11480d96289Smickey }
11580d96289Smickey 
1169f2d58dfSderaadt const int comports[4] = { 0x3f8, 0x2f8, 0x3e8, 0x2e8 };
1173abee3e7Smickey 
11880d96289Smickey void
com_probe(struct consdev * cn)119599546b3Sderaadt com_probe(struct consdev *cn)
12080d96289Smickey {
12180d96289Smickey 	register int i, n;
122c657d8f4Sniklas 
123c657d8f4Sniklas 	/* get equip. (9-11 # of coms) */
1242df76cc2Sguenther 	__asm volatile(DOINT(0x11) : "=a" (n) : : "%ecx", "%edx", "cc");
12580d96289Smickey 	n >>= 9;
12680d96289Smickey 	n &= 7;
12780d96289Smickey 	for (i = 0; i < n; i++)
1284b52c9a5Sderaadt 		printf(" com%d", i);
129be66b246Skettenis 
130713cf266Sjsing 	cn->cn_pri = CN_LOWPRI;
131c657d8f4Sniklas 	/* XXX from i386/conf.c */
132c657d8f4Sniklas 	cn->cn_dev = makedev(8, 0);
133c657d8f4Sniklas }
13480d96289Smickey 
1353490245dSdlg int com_speed = -1;
136a1e303c3Skettenis int com_addr = -1;
1373490245dSdlg 
13880d96289Smickey void
com_init(struct consdev * cn)139599546b3Sderaadt com_init(struct consdev *cn)
14080d96289Smickey {
141a1e303c3Skettenis 	int port = (com_addr == -1) ? comports[minor(cn->cn_dev)] : com_addr;
142*517bfc4aSbeck 	time_t tt = getsecs() + 1;
143*517bfc4aSbeck 	u_long i = 1;
144c657d8f4Sniklas 
1453490245dSdlg 	outb(port + com_ier, 0);
1463490245dSdlg 	if (com_speed == -1)
1473490245dSdlg 		comspeed(cn->cn_dev, 9600); /* default speed is 9600 baud */
1483490245dSdlg 	outb(port + com_mcr, MCR_DTR | MCR_RTS);
1493490245dSdlg 	outb(port + com_fifo, FIFO_ENABLE | FIFO_RCV_RST | FIFO_XMT_RST |
1503490245dSdlg 	    FIFO_TRIGGER_1);
151*517bfc4aSbeck 	(void) inb(port + com_iir);
152*517bfc4aSbeck 
153*517bfc4aSbeck 	/* A few ms delay for the chip, using the getsecs() API */
154*517bfc4aSbeck 	while (!(i++ % 1000) && getsecs() < tt)
155*517bfc4aSbeck 		;
1563490245dSdlg 
1573490245dSdlg 	/* drain the input buffer */
1583490245dSdlg 	while (inb(port + com_lsr) & LSR_RXRDY)
1593490245dSdlg 		(void)inb(port + com_data);
16080d96289Smickey }
16180d96289Smickey 
16280d96289Smickey int
com_getc(dev_t dev)163599546b3Sderaadt com_getc(dev_t dev)
16480d96289Smickey {
165a1e303c3Skettenis 	int port = (com_addr == -1) ? comports[minor(dev & 0x7f)] : com_addr;
16680d96289Smickey 
1673490245dSdlg 	if (dev & 0x80)
1683490245dSdlg 		return (inb(port + com_lsr) & LSR_RXRDY);
16980d96289Smickey 
1703490245dSdlg 	while ((inb(port + com_lsr) & LSR_RXRDY) == 0)
1713490245dSdlg 		;
17280d96289Smickey 
1733490245dSdlg 	return (inb(port + com_data) & 0xff);
17480d96289Smickey }
17580d96289Smickey 
17681a5a260Smickey /* call with sp == 0 to query the current speed */
17781a5a260Smickey int
comspeed(dev_t dev,int sp)178599546b3Sderaadt comspeed(dev_t dev, int sp)
179e20327dbSflipk {
180a1e303c3Skettenis 	int port = (com_addr == -1) ? comports[minor(dev)] : com_addr;
18181a5a260Smickey 	int i, newsp;
18281a5a260Smickey 	int err;
183e20327dbSflipk 
18481a5a260Smickey 	if (sp <= 0)
18581a5a260Smickey 		return com_speed;
18681a5a260Smickey 	/* valid baud rate? */
187bf899d08Smickey 	if (115200 < sp || sp < 75)
188e20327dbSflipk 		return -1;
18981a5a260Smickey 
190f35eef81Sweingart 	/*
191f35eef81Sweingart 	 * Accepted speeds:
192f35eef81Sweingart 	 *   75 150 300 600 1200 2400 4800 9600 19200 38400 76800 and
193f35eef81Sweingart 	 *   14400 28800 57600 115200
194f35eef81Sweingart 	 */
195f35eef81Sweingart 	for (i = sp; i != 75 && i != 14400; i >>= 1)
19681a5a260Smickey 		if (i & 1)
197e20327dbSflipk 			return -1;
19881a5a260Smickey 
19981a5a260Smickey /* ripped screaming from dev/ic/com.c */
20081a5a260Smickey #define divrnd(n, q)    (((n)*2/(q)+1)/2)       /* divide and round off */
20181a5a260Smickey 	newsp = divrnd((COM_FREQ / 16), sp);
20281a5a260Smickey 	if (newsp <= 0)
20381a5a260Smickey 		return -1;
20481a5a260Smickey 	err = divrnd((COM_FREQ / 16) * 1000, sp * newsp) - 1000;
205e20327dbSflipk 	if (err < 0)
206e20327dbSflipk 		err = -err;
207e20327dbSflipk 	if (err > COM_TOLERANCE)
208e20327dbSflipk 		return -1;
2090677d144Sespie #undef  divrnd
210e20327dbSflipk 
2113490245dSdlg 	if (com_speed != -1 && cn_tab && cn_tab->cn_dev == dev &&
2123490245dSdlg 	    com_speed != sp) {
2131c8d9fcfSderaadt 		printf("com%d: changing speed to %d baud in 5 seconds, "
2141c8d9fcfSderaadt 		    "change your terminal to match!\n\a",
2151c8d9fcfSderaadt 		    minor(dev), sp);
2163abee3e7Smickey 		sleep(5);
217e20327dbSflipk 	}
21881a5a260Smickey 
219a1e303c3Skettenis 	outb(port + com_cfcr, LCR_DLAB);
220a1e303c3Skettenis 	outb(port + com_dlbl, newsp);
221a1e303c3Skettenis 	outb(port + com_dlbh, newsp>>8);
222a1e303c3Skettenis 	outb(port + com_cfcr, LCR_8BITS);
2233490245dSdlg 	if (com_speed != -1)
2241c8d9fcfSderaadt 		printf("\ncom%d: %d baud\n", minor(dev), sp);
22581a5a260Smickey 
22681a5a260Smickey 	newsp = com_speed;
22781a5a260Smickey 	com_speed = sp;
22881a5a260Smickey 	return newsp;
229e20327dbSflipk }
230e20327dbSflipk 
23180d96289Smickey void
com_putc(dev_t dev,int c)232599546b3Sderaadt com_putc(dev_t dev, int c)
23380d96289Smickey {
234a1e303c3Skettenis 	int port = (com_addr == -1) ? comports[minor(dev)] : com_addr;
235c657d8f4Sniklas 
2363490245dSdlg 	while ((inb(port + com_lsr) & LSR_TXRDY) == 0)
2373490245dSdlg 		;
238096e4ceeSmickey 
2393490245dSdlg 	outb(port + com_data, c);
24080d96289Smickey }
241