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