diff options
Diffstat (limited to 'arch/x86/boot/a20.c')
-rw-r--r-- | arch/x86/boot/a20.c | 79 |
1 files changed, 40 insertions, 39 deletions
diff --git a/arch/x86/boot/a20.c b/arch/x86/boot/a20.c index 4063d630deff..7c19ce8c2442 100644 --- a/arch/x86/boot/a20.c +++ b/arch/x86/boot/a20.c | |||
@@ -2,6 +2,7 @@ | |||
2 | * | 2 | * |
3 | * Copyright (C) 1991, 1992 Linus Torvalds | 3 | * Copyright (C) 1991, 1992 Linus Torvalds |
4 | * Copyright 2007-2008 rPath, Inc. - All Rights Reserved | 4 | * Copyright 2007-2008 rPath, Inc. - All Rights Reserved |
5 | * Copyright 2009 Intel Corporation | ||
5 | * | 6 | * |
6 | * This file is part of the Linux kernel, and is made available under | 7 | * This file is part of the Linux kernel, and is made available under |
7 | * the terms of the GNU General Public License version 2. | 8 | * the terms of the GNU General Public License version 2. |
@@ -15,16 +16,23 @@ | |||
15 | #include "boot.h" | 16 | #include "boot.h" |
16 | 17 | ||
17 | #define MAX_8042_LOOPS 100000 | 18 | #define MAX_8042_LOOPS 100000 |
19 | #define MAX_8042_FF 32 | ||
18 | 20 | ||
19 | static int empty_8042(void) | 21 | static int empty_8042(void) |
20 | { | 22 | { |
21 | u8 status; | 23 | u8 status; |
22 | int loops = MAX_8042_LOOPS; | 24 | int loops = MAX_8042_LOOPS; |
25 | int ffs = MAX_8042_FF; | ||
23 | 26 | ||
24 | while (loops--) { | 27 | while (loops--) { |
25 | io_delay(); | 28 | io_delay(); |
26 | 29 | ||
27 | status = inb(0x64); | 30 | status = inb(0x64); |
31 | if (status == 0xff) { | ||
32 | /* FF is a plausible, but very unlikely status */ | ||
33 | if (!--ffs) | ||
34 | return -1; /* Assume no KBC present */ | ||
35 | } | ||
28 | if (status & 1) { | 36 | if (status & 1) { |
29 | /* Read and discard input data */ | 37 | /* Read and discard input data */ |
30 | io_delay(); | 38 | io_delay(); |
@@ -118,44 +126,37 @@ static void enable_a20_fast(void) | |||
118 | 126 | ||
119 | int enable_a20(void) | 127 | int enable_a20(void) |
120 | { | 128 | { |
121 | #if defined(CONFIG_X86_ELAN) | ||
122 | /* Elan croaks if we try to touch the KBC */ | ||
123 | enable_a20_fast(); | ||
124 | while (!a20_test_long()) | ||
125 | ; | ||
126 | return 0; | ||
127 | #elif defined(CONFIG_X86_VOYAGER) | ||
128 | /* On Voyager, a20_test() is unsafe? */ | ||
129 | enable_a20_kbc(); | ||
130 | return 0; | ||
131 | #else | ||
132 | int loops = A20_ENABLE_LOOPS; | 129 | int loops = A20_ENABLE_LOOPS; |
133 | while (loops--) { | 130 | int kbc_err; |
134 | /* First, check to see if A20 is already enabled | 131 | |
135 | (legacy free, etc.) */ | 132 | while (loops--) { |
136 | if (a20_test_short()) | 133 | /* First, check to see if A20 is already enabled |
137 | return 0; | 134 | (legacy free, etc.) */ |
138 | 135 | if (a20_test_short()) | |
139 | /* Next, try the BIOS (INT 0x15, AX=0x2401) */ | 136 | return 0; |
140 | enable_a20_bios(); | 137 | |
141 | if (a20_test_short()) | 138 | /* Next, try the BIOS (INT 0x15, AX=0x2401) */ |
142 | return 0; | 139 | enable_a20_bios(); |
143 | 140 | if (a20_test_short()) | |
144 | /* Try enabling A20 through the keyboard controller */ | 141 | return 0; |
145 | empty_8042(); | 142 | |
146 | if (a20_test_short()) | 143 | /* Try enabling A20 through the keyboard controller */ |
147 | return 0; /* BIOS worked, but with delayed reaction */ | 144 | kbc_err = empty_8042(); |
148 | 145 | ||
149 | enable_a20_kbc(); | 146 | if (a20_test_short()) |
150 | if (a20_test_long()) | 147 | return 0; /* BIOS worked, but with delayed reaction */ |
151 | return 0; | 148 | |
152 | 149 | if (!kbc_err) { | |
153 | /* Finally, try enabling the "fast A20 gate" */ | 150 | enable_a20_kbc(); |
154 | enable_a20_fast(); | 151 | if (a20_test_long()) |
155 | if (a20_test_long()) | 152 | return 0; |
156 | return 0; | 153 | } |
157 | } | 154 | |
158 | 155 | /* Finally, try enabling the "fast A20 gate" */ | |
159 | return -1; | 156 | enable_a20_fast(); |
160 | #endif | 157 | if (a20_test_long()) |
158 | return 0; | ||
159 | } | ||
160 | |||
161 | return -1; | ||
161 | } | 162 | } |