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