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 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