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