Wait for ACKs when setting the mode

This commit is contained in:
Vladimir 'phcoder' Serbinenko 2010-08-23 11:26:28 +02:00
parent b88904ca7f
commit 7ae3eb6232
2 changed files with 31 additions and 9 deletions

View file

@ -27,6 +27,8 @@
#define KEYBOARD_AT_TRANSLATE 0x40 #define KEYBOARD_AT_TRANSLATE 0x40
#define GRUB_AT_ACK 0xfa
#define KEYBOARD_ISMAKE(x) !((x) & 0x80) #define KEYBOARD_ISMAKE(x) !((x) & 0x80)
#define KEYBOARD_ISREADY(x) ((x) & 0x01) #define KEYBOARD_ISREADY(x) ((x) & 0x01)
#define KEYBOARD_SCANCODE(x) ((x) & 0x7f) #define KEYBOARD_SCANCODE(x) ((x) & 0x7f)

View file

@ -23,6 +23,7 @@
#include <grub/misc.h> #include <grub/misc.h>
#include <grub/term.h> #include <grub/term.h>
#include <grub/keyboard_layouts.h> #include <grub/keyboard_layouts.h>
#include <grub/time.h>
static short at_keyboard_status = 0; static short at_keyboard_status = 0;
static int e0_received = 0; static int e0_received = 0;
@ -225,19 +226,29 @@ grub_keyboard_controller_write (grub_uint8_t c)
} }
static int static int
write_mode (int mode) wait_ack (void)
{ {
grub_uint8_t ack; grub_uint8_t ack;
grub_uint64_t endtime = grub_get_time_ms () + 20;
do
{
ack = grub_inb (KEYBOARD_REG_DATA);
}
while (ack != GRUB_AT_ACK && grub_get_time_ms () < endtime);
grub_dprintf ("atkeyb", "Ack 0x%02x\n", ack);
return ack == GRUB_AT_ACK;
}
static int
write_mode (int mode)
{
keyboard_controller_wait_until_ready (); keyboard_controller_wait_until_ready ();
grub_outb (0xf0, KEYBOARD_REG_DATA); grub_outb (0xf0, KEYBOARD_REG_DATA);
keyboard_controller_wait_until_ready (); keyboard_controller_wait_until_ready ();
grub_outb (mode, KEYBOARD_REG_DATA); grub_outb (mode, KEYBOARD_REG_DATA);
keyboard_controller_wait_until_ready (); keyboard_controller_wait_until_ready ();
ack = grub_inb (KEYBOARD_REG_DATA);
if (ack != 0xfa)
return 0;
return 1; return wait_ack ();
} }
static int static int
@ -254,7 +265,7 @@ query_mode (void)
do do
ret = grub_inb (KEYBOARD_REG_DATA); ret = grub_inb (KEYBOARD_REG_DATA);
while (ret == 0xfa); while (ret == GRUB_AT_ACK);
/* QEMU translates the set even in no-translate mode. */ /* QEMU translates the set even in no-translate mode. */
if (ret == 0x43 || ret == 1) if (ret == 0x43 || ret == 1)
@ -275,6 +286,7 @@ set_scancodes (void)
knowledge. Assume XT. */ knowledge. Assume XT. */
if (!grub_keyboard_orig_set) if (!grub_keyboard_orig_set)
{ {
grub_dprintf ("atkeyb", "No sets support assumed\n");
current_set = 1; current_set = 1;
return; return;
} }
@ -284,11 +296,13 @@ set_scancodes (void)
write_mode (2); write_mode (2);
current_set = query_mode (); current_set = query_mode ();
grub_dprintf ("atkeyb", "returned set %d\n", current_set);
if (current_set == 2) if (current_set == 2)
return; return;
write_mode (1); write_mode (1);
current_set = query_mode (); current_set = query_mode ();
grub_dprintf ("atkeyb", "returned set %d\n", current_set);
if (current_set == 1) if (current_set == 1)
return; return;
grub_printf ("No supported scancode set found\n"); grub_printf ("No supported scancode set found\n");
@ -334,7 +348,7 @@ fetch_key (int *is_break)
} }
/* Setting LEDs may generate ACKs. */ /* Setting LEDs may generate ACKs. */
if (at_key == 0xfa) if (at_key == GRUB_AT_ACK)
return -1; return -1;
was_ext = e0_received; was_ext = e0_received;
@ -540,8 +554,14 @@ grub_keyboard_controller_init (struct grub_term_input *term __attribute__ ((unus
pending_key = -1; pending_key = -1;
at_keyboard_status = 0; at_keyboard_status = 0;
/* Drain input buffer. */ /* Drain input buffer. */
while (KEYBOARD_ISREADY (grub_inb (KEYBOARD_REG_STATUS))) while (1)
grub_inb (KEYBOARD_REG_DATA); {
keyboard_controller_wait_until_ready ();
if (! KEYBOARD_ISREADY (grub_inb (KEYBOARD_REG_STATUS)))
break;
keyboard_controller_wait_until_ready ();
grub_inb (KEYBOARD_REG_DATA);
}
grub_keyboard_controller_orig = grub_keyboard_controller_read (); grub_keyboard_controller_orig = grub_keyboard_controller_read ();
set_scancodes (); set_scancodes ();
keyboard_controller_led (led_status); keyboard_controller_led (led_status);