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