xref: /minix3/sys/arch/i386/stand/lib/gatea20.c (revision 58a2b0008e28f606a7f7f5faaeaba4faac57a1ea)
1*58a2b000SEvgeniy Ivanov /*	$NetBSD: gatea20.c,v 1.12 2009/08/23 12:31:05 jmcneill Exp $	*/
2*58a2b000SEvgeniy Ivanov 
3*58a2b000SEvgeniy Ivanov /* extracted from freebsd:sys/i386/boot/biosboot/io.c */
4*58a2b000SEvgeniy Ivanov 
5*58a2b000SEvgeniy Ivanov #include <sys/types.h>
6*58a2b000SEvgeniy Ivanov 
7*58a2b000SEvgeniy Ivanov #include <lib/libsa/stand.h>
8*58a2b000SEvgeniy Ivanov 
9*58a2b000SEvgeniy Ivanov #include "libi386.h"
10*58a2b000SEvgeniy Ivanov #include "biosmca.h"
11*58a2b000SEvgeniy Ivanov #include "cpufunc.h"
12*58a2b000SEvgeniy Ivanov 
13*58a2b000SEvgeniy Ivanov #define K_RDWR 		0x60		/* keyboard data & cmds (read/write) */
14*58a2b000SEvgeniy Ivanov #define K_STATUS 	0x64		/* keyboard status */
15*58a2b000SEvgeniy Ivanov #define K_CMD	 	0x64		/* keybd ctlr command (write-only) */
16*58a2b000SEvgeniy Ivanov 
17*58a2b000SEvgeniy Ivanov #define K_OBUF_FUL 	0x01		/* output buffer full */
18*58a2b000SEvgeniy Ivanov #define K_IBUF_FUL 	0x02		/* input buffer full */
19*58a2b000SEvgeniy Ivanov 
20*58a2b000SEvgeniy Ivanov #define KC_CMD_WIN	0xd0		/* read  output port */
21*58a2b000SEvgeniy Ivanov #define KC_CMD_WOUT	0xd1		/* write output port */
22*58a2b000SEvgeniy Ivanov #define KB_A20		0x9f		/* enable A20,
23*58a2b000SEvgeniy Ivanov 					   reset (!),
24*58a2b000SEvgeniy Ivanov 					   enable output buffer full interrupt
25*58a2b000SEvgeniy Ivanov 					   enable data line
26*58a2b000SEvgeniy Ivanov 					   disable clock line */
27*58a2b000SEvgeniy Ivanov 
28*58a2b000SEvgeniy Ivanov /*
29*58a2b000SEvgeniy Ivanov  * Gate A20 for high memory
30*58a2b000SEvgeniy Ivanov  */
31*58a2b000SEvgeniy Ivanov static unsigned char	x_20 = KB_A20;
32*58a2b000SEvgeniy Ivanov 
33*58a2b000SEvgeniy Ivanov void
gateA20(void)34*58a2b000SEvgeniy Ivanov gateA20(void)
35*58a2b000SEvgeniy Ivanov {
36*58a2b000SEvgeniy Ivanov 	int biosA20(void);
37*58a2b000SEvgeniy Ivanov 	u_long psl;
38*58a2b000SEvgeniy Ivanov 
39*58a2b000SEvgeniy Ivanov 	/*
40*58a2b000SEvgeniy Ivanov 	 * First, try asking the BIOS to enable A20.
41*58a2b000SEvgeniy Ivanov 	 *
42*58a2b000SEvgeniy Ivanov 	 * If that fails, try system configuration port 0x92 but only
43*58a2b000SEvgeniy Ivanov 	 * if known to be necessary.  Not all systems enable A20 via the
44*58a2b000SEvgeniy Ivanov 	 * keyboard controller, some don't have keyboard controllers,
45*58a2b000SEvgeniy Ivanov 	 * and playing with port 0x92 may cause some systems to break.
46*58a2b000SEvgeniy Ivanov 	 *
47*58a2b000SEvgeniy Ivanov 	 * Otherwise, use the traditional method (keyboard controller).
48*58a2b000SEvgeniy Ivanov 	 */
49*58a2b000SEvgeniy Ivanov 	if (!biosA20())
50*58a2b000SEvgeniy Ivanov 		return;
51*58a2b000SEvgeniy Ivanov 	psl = x86_read_psl();
52*58a2b000SEvgeniy Ivanov 	x86_disable_intr();
53*58a2b000SEvgeniy Ivanov 	if (
54*58a2b000SEvgeniy Ivanov #ifdef SUPPORT_PS2
55*58a2b000SEvgeniy Ivanov 	    biosmca_ps2model == 0xf82 ||
56*58a2b000SEvgeniy Ivanov #endif
57*58a2b000SEvgeniy Ivanov 	    (inb(K_STATUS) == 0xff && inb(K_RDWR) == 0xff)) {
58*58a2b000SEvgeniy Ivanov 		int data;
59*58a2b000SEvgeniy Ivanov 
60*58a2b000SEvgeniy Ivanov 		data = inb(0x92);
61*58a2b000SEvgeniy Ivanov 		outb(0x92, data | 0x2);
62*58a2b000SEvgeniy Ivanov 	} else {
63*58a2b000SEvgeniy Ivanov 		while (inb(K_STATUS) & K_IBUF_FUL);
64*58a2b000SEvgeniy Ivanov 
65*58a2b000SEvgeniy Ivanov 		while (inb(K_STATUS) & K_OBUF_FUL)
66*58a2b000SEvgeniy Ivanov 			(void)inb(K_RDWR);
67*58a2b000SEvgeniy Ivanov 
68*58a2b000SEvgeniy Ivanov 		outb(K_CMD, KC_CMD_WOUT);
69*58a2b000SEvgeniy Ivanov 
70*58a2b000SEvgeniy Ivanov 		while (inb(K_STATUS) & K_IBUF_FUL);
71*58a2b000SEvgeniy Ivanov 
72*58a2b000SEvgeniy Ivanov 		outb(K_RDWR, x_20);
73*58a2b000SEvgeniy Ivanov 
74*58a2b000SEvgeniy Ivanov 		while (inb(K_STATUS) & K_IBUF_FUL);
75*58a2b000SEvgeniy Ivanov 
76*58a2b000SEvgeniy Ivanov 		while (inb(K_STATUS) & K_OBUF_FUL)
77*58a2b000SEvgeniy Ivanov 			(void)inb(K_RDWR);
78*58a2b000SEvgeniy Ivanov 	}
79*58a2b000SEvgeniy Ivanov 	x86_write_psl(psl);
80*58a2b000SEvgeniy Ivanov }
81