diff --git a/src/device/keyboard_at.c b/src/device/keyboard_at.c index 581f55f30..92690db1f 100644 --- a/src/device/keyboard_at.c +++ b/src/device/keyboard_at.c @@ -57,9 +57,7 @@ #define STAT_IFULL 0x02 #define STAT_OFULL 0x01 -#define PS2_REFRESH_TIME (16 * TIMER_USEC) - -#define RESET_DELAY_TIME (100 * 10) /* 600ms */ +#define RESET_DELAY_TIME 1000 /* 100 ms */ #define CCB_UNUSED 0x80 #define CCB_TRANSLATE 0x40 @@ -74,49 +72,136 @@ #define MODE_MASK 0x6c #define KBC_TYPE_ISA 0x00 /* AT ISA-based chips */ -#define KBC_TYPE_PS2_NOREF 0x01 /* PS2 type, no refresh */ -#define KBC_TYPE_PS2_1 0x02 /* PS2 on PS/2, type 1 */ -#define KBC_TYPE_PS2_2 0x03 /* PS2 on PS/2, type 2 */ -#define KBC_TYPE_MASK 0x03 +#define KBC_TYPE_PS2_1 0x04 /* PS2 type, no refresh */ +/* This only differs in that translation is forced off. */ +#define KBC_TYPE_PS2_2 0x05 /* PS2 on PS/2, type 2 */ +#define KBC_TYPE_MASK 0x07 +#define KBC_FLAG_PS2 0x04 + +/* We need to redefine this: + Currently, we use bits 3-7 for vendor, we should instead use bits 4-7 + for vendor, 0-3 for revision/variant, and have a dev->ps2 flag controlling + controller mode, normally set according to the flags, but togglable on + AMIKey: + 0000 0000 0x00 IBM, AT + 0000 0001 0x01 MR + 0000 0010 0x02 Xi8088, clone of IBM PS/2 type 1 + 0001 0000 0x10 Olivetti + 0010 0000 0x20 Toshiba + 0011 0000 0x30 Quadtel + 0100 0000 0x40 Phoenix MultiKey/42 + 0101 0000 0x50 AMI KF + 0101 0001 0x51 AMI KH + 0101 0010 0x52 AMIKey + 0101 0011 0x53 AMIKey-2 + 0101 0100 0x54 JetKey (clone of AMI KF/AMIKey) + 0110 0000 0x60 Award + 0110 0001 0x61 Award 286 (has some AMI commands apparently) + 0111 0000 0x70 Siemens +*/ + +/* Standard IBM controller */ #define KBC_VEN_GENERIC 0x00 -#define KBC_VEN_AMI 0x04 +/* All commands are standard PS/2 */ #define KBC_VEN_IBM_MCA 0x08 -#define KBC_VEN_QUADTEL 0x0c -#define KBC_VEN_TOSHIBA 0x10 -#define KBC_VEN_XI8088 0x14 -#define KBC_VEN_IBM_PS1 0x18 -#define KBC_VEN_ACER 0x1c -#define KBC_VEN_INTEL_AMI 0x20 -#define KBC_VEN_OLIVETTI 0x24 -#define KBC_VEN_NCR 0x28 -#define KBC_VEN_SAMSUNG 0x2c -#define KBC_VEN_MASK 0x3c +/* Standard IBM commands, differs in input port bits */ +#define KBC_VEN_IBM_PS1 0x10 +/* Olivetti - proprietary commands and port 62h with switches + readout */ +#define KBC_VEN_OLIVETTI 0x20 +/* Toshiba T3100e - has a bunch of proprietary commands, also sets + IFULL on command AA */ +#define KBC_VEN_TOSHIBA 0x28 +/* Standard IBM commands, uses input port as a switches readout */ +#define KBC_VEN_NCR 0x30 +/* Xi8088 - standard IBM commands, has a turbo bit on port 61h, and the + polarity of the video type bit in the input port is inverted */ +#define KBC_VEN_XI8088 0x38 +/* QuadtelKey - currently guesswork */ +#define KBC_VEN_QUADTEL 0x40 +/* Phoenix MultiKey/42 - not yet implemented */ +#define KBC_VEN_PHOENIX 0x48 +/* Generic commands, XI8088-like input port handling of video type, + maybe we just need a flag for that? */ +#define KBC_VEN_ACER 0x50 +/* AMI KF/KH/AMIKey/AMIKey-2 */ +#define KBC_VEN_AMI 0xf0 +/* Standard AMI commands, differs in input port bits */ +#define KBC_VEN_INTEL_AMI 0xf8 +#define KBC_VEN_MASK 0xf8 + + +/* Flags should be fully 32-bit: + Bits 7- 0: Vendor and revision/variant; + Bits 15- 8: Input port mask; + Bits 23-16: Input port bits that are always on; + Bits 31-24: Flags: + Bit 0: Invert P1 video type bit polarity; + Bit 1: Is PS/2; + Bit 2: Translation forced always off. + + So for example, the IBM PS/2 type 1 controller flags would be: 00000010 00000000 11111111 00000000 = 0200ff00 . */ typedef struct { - uint8_t command, status, old_status, out, old_out, secr_phase, - mem_addr, input_port, output_port, old_output_port, - key_command, output_locked, ami_stat, want60, - wantirq, key_wantdata, refresh, first_write; + uint8_t status, ib, ob, p1, p2, old_p2, p2_locked, fast_a20_phase, + secr_phase, mem_index, ami_stat, ami_mode, + kbc_in, kbc_cmd, kbc_in_cmd, kbc_poll_phase, kbc_to_send, + kbc_send_pending, kbc_channel, kbc_stat_hi, kbc_wait_for_response, inhibit, + kbd_in, kbd_cmd, kbd_in_cmd, kbd_written, kbd_data, kbd_poll_phase, kbd_inhibit, + mouse_in, mouse_cmd, mouse_in_cmd, mouse_written, mouse_data, mouse_poll_phase, mouse_inhibit, + kbc_written[3], kbc_data[3]; - uint8_t mem[0x100]; + uint8_t mem_int[0x40], mem[0x240]; - int last_irq, old_last_irq, - reset_delay, - out_new, out_delayed; + uint16_t last_irq, kbc_phase, kbd_phase, mouse_phase; uint32_t flags; - pc_timer_t refresh_time, pulse_cb; + pc_timer_t pulse_cb, send_delay_timer; uint8_t (*write60_ven)(void *p, uint8_t val); uint8_t (*write64_ven)(void *p, uint8_t val); - - pc_timer_t send_delay_timer; } atkbd_t; +enum +{ + CHANNEL_KBC = 0, + CHANNEL_KBD, + CHANNEL_MOUSE +}; + +enum +{ + KBD_MAIN_LOOP = 0, + KBD_CMD_PROCESS +}; + +enum +{ + MOUSE_MAIN_LOOP_1 = 0, + MOUSE_CMD_PROCESS, + MOUSE_CMD_END, + MOUSE_MAIN_LOOP_2 +}; + +enum { + KBC_MAIN_LOOP = 0, + KBC_RESET = 1, + KBC_WAIT = 4, + KBC_WAIT_FOR_KBD, + KBC_WAIT_FOR_MOUSE, + KBC_WAIT_FOR_BOTH +}; + + +static void kbd_cmd_process(atkbd_t *dev); + +static void kbc_wait(atkbd_t *dev, uint8_t flags); + + /* bit 0 = repeat, bit 1 = makes break code? */ uint8_t keyboard_set3_flags[512]; uint8_t keyboard_set3_all_repeat; @@ -125,9 +210,9 @@ uint8_t keyboard_set3_all_break; /* Bits 0 - 1 = scan code set, bit 6 = translate or not. */ uint8_t keyboard_mode = 0x42; +uint8_t * ami_copr = (uint8_t *) "(C)1994 AMI"; + -static uint8_t key_ctrl_queue[16]; -static int key_ctrl_queue_start = 0, key_ctrl_queue_end = 0; static uint8_t key_queue[16]; static int key_queue_start = 0, key_queue_end = 0; uint8_t mouse_queue[16]; @@ -568,9 +653,27 @@ static const scancode scancode_set3[512] = { }; +#define UISTR_LEN 256 +static char kbd_str[UISTR_LEN]; /* UI output string */ static void add_data_kbd(uint16_t val); +extern void ui_sb_bugui(char *__str); + + +static void +kbd_status(const char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + vsprintf(kbd_str, fmt, ap); + ui_sb_bugui(kbd_str); + va_end(ap); +} + + +// #define ENABLE_KEYBOARD_AT_LOG 1 #ifdef ENABLE_KEYBOARD_AT_LOG int keyboard_at_do_log = ENABLE_KEYBOARD_AT_LOG; @@ -631,9 +734,6 @@ kbc_queue_reset(uint8_t channel) } else if (channel == 1) { key_queue_start = key_queue_end = 0; memset(key_queue, 0x00, sizeof(key_queue)); - } else { - key_ctrl_queue_start = key_ctrl_queue_end = 0; - memset(key_ctrl_queue, 0x00, sizeof(key_ctrl_queue)); } } @@ -641,15 +741,6 @@ kbc_queue_reset(uint8_t channel) static void kbc_queue_add(atkbd_t *dev, uint8_t val, uint8_t channel, uint8_t stat_hi) { - uint8_t kbc_ven = dev->flags & KBC_VEN_MASK; - - if ((kbc_ven == KBC_VEN_AMI) || ((dev->flags & KBC_TYPE_MASK) >= KBC_TYPE_PS2_NOREF)) - stat_hi |= ((dev->input_port & 0x80) ? 0x10 : 0x00); - else - stat_hi |= 0x10; - - dev->status = (dev->status & 0x0f) | stat_hi; - if (channel == 2) { kbd_log("ATkbc: mouse_queue[%02X] = %02X;\n", mouse_queue_end, val); mouse_queue[mouse_queue_end] = val; @@ -658,83 +749,1042 @@ kbc_queue_add(atkbd_t *dev, uint8_t val, uint8_t channel, uint8_t stat_hi) kbd_log("ATkbc: key_queue[%02X] = %02X;\n", key_queue_end, val); key_queue[key_queue_end] = val; key_queue_end = (key_queue_end + 1) & 0xf; - } else { - kbd_log("ATkbc: key_ctrl_queue[%02X] = %02X;\n", key_ctrl_queue_end, val); - key_ctrl_queue[key_ctrl_queue_end] = val; - key_ctrl_queue_end = (key_ctrl_queue_end + 1) & 0xf; - } -} - - -static void -add_to_kbc_queue_front(atkbd_t *dev, uint8_t val, uint8_t channel, uint8_t stat_hi) -{ - uint8_t kbc_ven = dev->flags & KBC_VEN_MASK; - - if ((kbc_ven == KBC_VEN_AMI) || ((dev->flags & KBC_TYPE_MASK) >= KBC_TYPE_PS2_NOREF)) - stat_hi |= ((dev->input_port & 0x80) ? 0x10 : 0x00); - else - stat_hi |= 0x10; - - kbd_log("ATkbc: Adding %02X to front...\n", val); - dev->wantirq = 0; - if (channel == 2) { - if (dev->mem[0] & 0x02) - picint(0x1000); - dev->last_irq = 0x1000; - } else { - if (dev->mem[0] & 0x01) - picint(2); - dev->last_irq = 2; - } - dev->out = val; - if (channel == 2) - dev->status = (dev->status & ~STAT_IFULL) | (STAT_OFULL | STAT_MFULL) | stat_hi; - else - dev->status = (dev->status & ~(STAT_IFULL | STAT_MFULL)) | STAT_OFULL | stat_hi; + } else + fatal("Adding %02X to invalid channel %02X\n", val, channel); } static void add_data_kbd_queue(atkbd_t *dev, int direct, uint8_t val) { - if ((!keyboard_scan && !direct) || (dev->reset_delay > 0) || (key_queue_end >= 16)) { - kbd_log("ATkbc: Unable to add to queue, conditions: %i, %i, %i\n", !keyboard_scan, (dev->reset_delay > 0), (key_queue_end >= 16)); + if ((!keyboard_scan && !direct) || (key_queue_end >= 16)) { + kbd_log("ATkbc: Unable to add to queue, conditions: %i, %i\n", !keyboard_scan, (key_queue_end >= 16)); return; } - kbd_log("ATkbc: key_queue[%02X] = %02X;\n", key_queue_end, val); + + kbd_log("ATkbc: key_queue[%02X] = %02X;\n", key_queue_end, val); kbc_queue_add(dev, val, 1, 0x00); kbd_last_scan_code = val; } - static void -add_data_kbd_direct(atkbd_t *dev, uint8_t val) +kbc_send(atkbd_t *dev, uint8_t val, uint8_t channel) { - int xt_mode = (keyboard_mode & 0x20) && ((dev->flags & KBC_TYPE_MASK) < KBC_TYPE_PS2_NOREF); - int translate = (keyboard_mode & 0x40); - uint8_t send; - - if (dev->reset_delay) - return; - - translate = translate || (keyboard_mode & 0x40) || xt_mode; - translate = translate || ((dev->flags & KBC_TYPE_MASK) == KBC_TYPE_PS2_2); - - if (translate) - send = nont_to_t[val]; - else - send = val; - - add_data_kbd_queue(dev, 1, send); + dev->kbc_written[channel] = 1; + dev->kbc_data[channel] = val; } static void -add_data_kbd_raw(atkbd_t *dev, uint8_t val) +kbd_send_to_host(atkbd_t *dev, uint8_t val) { - add_data_kbd_queue(dev, 1, val); + kbc_send(dev, val, CHANNEL_KBD); +} + + +static void +kbd_chip_reset(atkbd_t *dev) +{ + kbc_queue_reset(1); + dev->kbc_written[1] = 0x00; + kbd_last_scan_code = 0x00; + + /* Set scan code set to 2. */ + keyboard_mode = (keyboard_mode & 0xfc) | 0x02; + set_scancode_map(dev); + + dev->kbd_phase = 0; + dev->kbd_in = 0; +} + + +static void +kbd_command(atkbd_t *dev) +{ + uint8_t val = dev->kbd_data; + + if ((dev->kbd_phase > 0) && (dev->kbd_cmd == 0xff)) { + dev->kbd_phase++; + if (dev->kbd_phase == RESET_DELAY_TIME) { + kbd_send_to_host(dev, 0xaa); + dev->kbd_phase = 0; + dev->kbd_cmd = 0x00; + } + return; + } + + if (dev->kbd_phase == 2) { + dev->kbd_phase = 0; + + switch (dev->kbd_cmd) { + case 0xf2: + kbd_send_to_host(dev, 0x83); + break; + default: + fatal("Invalid command for phase 2: %02X\n", dev->kbd_cmd); + break; + } + + /* Keyboard command is now done. */ + if (dev->kbd_phase == 0) + dev->kbd_cmd = 0x00; + return; + } else if (dev->kbd_phase == 1) { + dev->kbd_phase = 0; + + switch (dev->kbd_cmd) { + case 0xf0: + kbd_log("Get scan code set: %02X\n", keyboard_mode & 3); + kbd_send_to_host(dev, keyboard_mode & 3); + break; + case 0xf2: + kbd_send_to_host(dev, 0xab); + dev->kbd_phase = 2; + break; + default: + fatal("Invalid command for phase 1: %02X\n", dev->kbd_cmd); + break; + } + + /* Keyboard command is now done. */ + if (dev->kbd_phase == 0) + dev->kbd_cmd = 0x00; + return; + } + + if (dev->kbd_in && (val < 0xed)) { + dev->kbd_in = 0; + dev->kbd_phase = 0; + + switch (dev->kbd_cmd) { + case 0xed: /* set/reset LEDs */ + kbd_log("ATkbd: set LEDs [%02x]\n", val); + kbd_send_to_host(dev, 0xfa); + break; + + case 0xf0: /* get/set scancode set */ + kbd_send_to_host(dev, 0xfa); + if (val == 0) + dev->kbd_phase = 1; + else { + if ((val <= 3) && (val != 1)) { + keyboard_mode &= 0xfc; + keyboard_mode |= (val & 3); + kbd_log("Scan code set now: %02X\n", val); + } + set_scancode_map(dev); + } + break; + + case 0xf3: /* set typematic rate/delay */ + kbd_send_to_host(dev, 0xfa); + break; + + default: + kbd_log("ATkbd: bad keyboard 0060 write %02X command %02X\n", val, dev->kbd_cmd); + kbd_send_to_host(dev, 0xfe); + break; + } + + /* Keyboard command is now done. */ + if (dev->kbd_phase == 0) + dev->kbd_cmd = 0x00; + } else { + /* No keyboard command in progress. */ + dev->kbd_in = 0; + dev->kbd_cmd = 0x00; + dev->kbd_phase = 0; + + switch (val) { + case 0x00: + kbd_log("ATkbd: command 00\n"); + kbd_send_to_host(dev, 0xfa); + break; + + case 0x05: /*??? - sent by NT 4.0*/ + kbd_log("ATkbd: command 05 (NT 4.0)\n"); + kbd_send_to_host(dev, 0xfe); + break; + + case 0xed: /* set/reset LEDs */ + kbd_log("ATkbd: set/reset leds\n"); + kbd_send_to_host(dev, 0xfa); + + dev->kbd_in = 1; + break; + + case 0xee: /* diagnostic echo */ + kbd_log("ATkbd: ECHO\n"); + kbd_send_to_host(dev, 0xee); + break; + + case 0xef: /* NOP (reserved for future use) */ + kbd_log("ATkbd: NOP\n"); + break; + + case 0xf0: /* get/set scan code set */ + kbd_log("ATkbd: scan code set\n"); + kbd_send_to_host(dev, 0xfa); + dev->kbd_in = 1; + break; + + case 0xf2: /* read ID */ + /* Fixed as translation will be done in add_data_kbd(). */ + kbd_log("ATkbd: read keyboard id\n"); + /* TODO: After keyboard type selection is implemented, make this + return the correct keyboard ID for the selected type. */ + kbd_send_to_host(dev, 0xfa); + dev->kbd_phase = 1; + break; + + case 0xf3: /* set typematic rate/delay */ + kbd_log("ATkbd: set typematic rate/delay\n"); + kbd_send_to_host(dev, 0xfa); + dev->kbd_in = 1; + break; + + case 0xf4: /* enable keyboard */ + kbd_log("ATkbd: enable keyboard\n"); + kbd_send_to_host(dev, 0xfa); + keyboard_scan = 1; + break; + + case 0xf5: /* set defaults and disable keyboard */ + case 0xf6: /* set defaults */ + kbd_log("ATkbd: set defaults%s\n", (val == 0xf6) ? "" : " and disable keyboard"); + keyboard_scan = (val == 0xf6); + kbd_log("val = %02X, keyboard_scan = %i, dev->mem[0x20] = %02X\n", + val, keyboard_scan, dev->mem[0x20]); + kbd_send_to_host(dev, 0xfa); + + keyboard_set3_all_break = 0; + keyboard_set3_all_repeat = 0; + memset(keyboard_set3_flags, 0, 512); + keyboard_mode = (keyboard_mode & 0xfc) | 0x02; + set_scancode_map(dev); + break; + + case 0xf7: /* set all keys to repeat */ + kbd_log("ATkbd: set all keys to repeat\n"); + kbd_send_to_host(dev, 0xfa); + keyboard_set3_all_break = 1; + break; + + case 0xf8: /* set all keys to give make/break codes */ + kbd_log("ATkbd: set all keys to give make/break codes\n"); + kbd_send_to_host(dev, 0xfa); + keyboard_set3_all_break = 1; + break; + + case 0xf9: /* set all keys to give make codes only */ + kbd_log("ATkbd: set all keys to give make codes only\n"); + kbd_send_to_host(dev, 0xfa); + keyboard_set3_all_break = 0; + break; + + case 0xfa: /* set all keys to repeat and give make/break codes */ + kbd_log("ATkbd: set all keys to repeat and give make/break codes\n"); + kbd_send_to_host(dev, 0xfa); + keyboard_set3_all_repeat = 1; + keyboard_set3_all_break = 1; + break; + + case 0xfe: /* resend last scan code */ + kbd_log("ATkbd: reset last scan code\n"); + kbd_send_to_host(dev, kbd_last_scan_code); + break; + + case 0xff: /* reset */ + kbd_log("ATkbd: kbd reset\n"); + kbd_chip_reset(dev); + kbd_send_to_host(dev, 0xfa); + dev->kbd_phase = 1; + break; + + default: + kbd_log("ATkbd: bad keyboard command %02X\n", val); + kbd_send_to_host(dev, 0xfe); + } + + /* If command needs data, remember command. */ + if ((dev->kbd_in == 1) || (dev->kbd_phase > 0)) + dev->kbd_cmd = val; + } +} + + +static void +kbd_do_command(atkbd_t *dev) +{ + kbd_command(dev); + if (dev->kbd_written) + dev->kbd_poll_phase = KBD_CMD_PROCESS; + else if ((dev->kbd_phase == 0) && !dev->kbd_in) { + dev->kbd_in_cmd = 0; + if (dev->kbd_data != 0xf5) + keyboard_scan = 1; + dev->kbd_poll_phase = KBD_MAIN_LOOP; + } else { + keyboard_scan = 0; + dev->kbd_in_cmd = 1; + dev->kbd_poll_phase = KBD_CMD_PROCESS; + } +} + + +static void +kbd_nack(atkbd_t *dev) +{ + kbd_send_to_host(dev, 0xfe); + dev->kbd_poll_phase = KBD_MAIN_LOOP; +} + + +static void +kbd_main_loop(atkbd_t *dev) +{ + uint8_t scan = !dev->kbd_inhibit && keyboard_scan; + + if (dev->kbd_written) { + dev->kbd_written = 0; + kbd_cmd_process(dev); + } else if (scan && (key_queue_start != key_queue_end)) { + /* Scan here. */ + kbd_log("ATkbd: Get %02X from FIFO\n", key_queue[key_queue_start]); + kbd_send_to_host(dev, key_queue[key_queue_start]); + key_queue_start = (key_queue_start + 1) & 0xf; + } +} + + +static void +kbd_cmd_process(atkbd_t *dev) +{ + uint8_t written = dev->kbd_written; + + /* We want data, nothing has been written yet, return. */ + if (dev->kbd_in && !dev->kbd_written) + return; + + dev->kbd_written = 0; + + if (!written && !keyboard_scan && dev->kbd_in_cmd && (dev->kbd_phase > 0)) { + kbd_log("ATkbd: Keyboard not written, not scanning, in command, and phase > 0\n"); + kbd_do_command(dev); + } else if (dev->kbd_data == 0xfe) { + kbd_log("ATkbd: Send last byte %02X\n", kbd_last_scan_code); + kbd_send_to_host(dev, kbd_last_scan_code); + dev->kbd_poll_phase = KBD_MAIN_LOOP; + } else if (dev->kbd_data == 0xee) { + kbd_log("ATkbd: Echo EE\n"); + kbd_send_to_host(dev, 0xee); + dev->kbd_poll_phase = KBD_MAIN_LOOP; + } else if (dev->kbd_data >= 0xed) { + kbd_log("ATkbd: Command %02X\n", dev->kbd_data); + if (!keyboard_scan && dev->kbd_in_cmd && (dev->kbd_cmd == 0xed)) { + kbd_log("ATkbd: Not scanning, in command, old command is ED\n"); + keyboard_scan = 1; + dev->kbd_in_cmd = 0; + } + kbd_do_command(dev); + } else { + if (!keyboard_scan && dev->kbd_in_cmd) { + if ((dev->kbd_cmd == 0xf3) && (dev->kbd_data & 0x80)) { + kbd_log("ATkbd: Command F3 data %02X has bit 7 set\n", dev->kbd_data); + kbd_nack(dev); + } else { + kbd_log("ATkbd: Command %02X data %02X\n", dev->kbd_cmd, dev->kbd_data); + kbd_do_command(dev); + } + } else { + kbd_log("ATkbd: Scanning or not in command, NACK\n"); + kbd_nack(dev); + } + } +} + + +/* Keyboard processing */ +static void +kbd_process(atkbd_t *dev) +{ + /* The real 8048 keyboard firmware stops transmitting if host wants to transmit. */ + if (dev->kbc_written[1] && dev->kbd_written) + dev->kbc_written[1] = 0; + + /* The host has either acknowledged the transmitted byte or we have not transmitted anything (yet). */ + if (!dev->kbc_written[1]) switch (dev->kbd_poll_phase) { + case KBD_MAIN_LOOP: + kbd_main_loop(dev); + break; + case KBD_CMD_PROCESS: + kbd_cmd_process(dev); + break; + } +} + + +static void +kbc_send_to_ob(atkbd_t *dev, uint8_t val, uint8_t channel, uint8_t stat_hi) +{ + uint8_t ch = (channel > 0) ? channel : 1; + uint8_t do_irq = (dev->mem[0x20] & ch); + int translate = (channel == 1) && (keyboard_mode & 0x60); + + if ((channel == 2) && !(dev->flags & KBC_FLAG_PS2)) + return; + + stat_hi |= dev->inhibit; + + if (!dev->kbc_send_pending) { + dev->kbc_send_pending = 1; + dev->kbc_to_send = val; + dev->kbc_channel = channel; + dev->kbc_stat_hi = stat_hi; + return; + } + + if (translate) { + /* Allow for scan code translation. */ + if (val == 0xf0) { + kbd_log("ATkbd: translate is on, F0 prefix detected\n"); + sc_or = 0x80; + return; + } + + /* Skip break code if translated make code has bit 7 set. */ + if ((sc_or == 0x80) && (val & 0x80)) { + kbd_log("ATkbd: translate is on, skipping scan code: %02X (original: F0 %02X)\n", nont_to_t[val], val); + sc_or = 0; + return; + } + } + + dev->last_irq = (ch == 2) ? 0x1000 : 0x0002; + if (do_irq) { + kbd_log("[%04X:%08X] ATKbc: IRQ %i\n", CS, cpu_state.pc, (ch == 2) ? 12 : 1); + picint(dev->last_irq); + } + kbd_log("ATkbc: %02X coming from channel %i (%i)\n", val, channel, do_irq); + dev->ob = translate ? (nont_to_t[val] | sc_or) : val; + + dev->status = (dev->status & 0x0f) | (stat_hi | (dev->mem[0x20] & STAT_SYSFLAG) | STAT_OFULL); + if (ch == 2) + dev->status |= STAT_MFULL; + + if (translate && (sc_or == 0x80)) + sc_or = 0; +} + + +static void +write_output(atkbd_t *dev, uint8_t val) +{ + uint8_t kbc_ven = dev->flags & KBC_VEN_MASK; + kbd_log("ATkbc: write output port: %02X (old: %02X)\n", val, dev->p2); + + if ((kbc_ven == KBC_VEN_AMI) || (dev->flags & KBC_FLAG_PS2)) + val |= ((dev->mem[0x20] << 4) & 0x30); + + dev->kbd_inhibit = (val & 0x40); + dev->mouse_inhibit = (val & 0x08); + + if ((dev->p2 ^ val) & 0x20) { /*IRQ 12*/ + if (val & 0x20) { + kbd_log("ATkbc: write_output(): IRQ 12\n"); + picint(1 << 12); + } else + picintc(1 << 12); + } + if ((dev->p2 ^ val) & 0x10) { /*IRQ 1*/ + if (val & 0x10) { + kbd_log("ATkbc: write_output(): IRQ 1\n"); + picint(1 << 1); + } else + picintc(1 << 1); + } + if ((dev->p2 ^ val) & 0x02) { /*A20 enable change*/ + mem_a20_key = val & 0x02; + mem_a20_recalc(); + flushmmucache(); + } + if ((dev->p2 ^ val) & 0x01) { /*Reset*/ + if (! (val & 0x01)) { + /* Pin 0 selected. */ + softresetx86(); /*Pulse reset!*/ + cpu_set_edx(); + smbase = is_am486dxl ? 0x00060000 : 0x00030000; + } + } + /* Mask off the A20 stuff because we use mem_a20_key directly for that. */ + dev->p2 = val; +} + + +static void +write_cmd(atkbd_t *dev, uint8_t val) +{ + uint8_t kbc_ven = dev->flags & KBC_VEN_MASK; + kbd_log("ATkbc: write command byte: %02X (old: %02X)\n", val, dev->mem[0x20]); + + /* PS/2 type 2 keyboard controllers always force the XLAT bit to 0. */ + if ((dev->flags & KBC_TYPE_MASK) == KBC_TYPE_PS2_2) + val &= ~CCB_TRANSLATE; + + dev->mem[0x20] = val; + + /* Scan code translate ON/OFF. */ + keyboard_mode &= 0x93; + keyboard_mode |= (val & MODE_MASK); + + kbd_log("ATkbc: keyboard interrupt is now %s\n", (val & 0x01) ? "enabled" : "disabled"); + + /* ISA AT keyboard controllers use bit 5 for keyboard mode (1 = PC/XT, 2 = AT); + PS/2 (and EISA/PCI) keyboard controllers use it as the PS/2 mouse enable switch. + The AMIKEY firmware apparently uses this bit for something else. */ + if ((kbc_ven == KBC_VEN_AMI) || (dev->flags & KBC_FLAG_PS2)) { + keyboard_mode &= ~CCB_PCMODE; + /* Update the output port to mirror the KBD DIS and AUX DIS bits, if active. */ + write_output(dev, dev->p2); + + kbd_log("ATkbc: mouse interrupt is now %s\n", (val & 0x02) ? "enabled" : "disabled"); + } + + kbd_log("Command byte now: %02X (%02X)\n", dev->mem[0x20], val); + + dev->status = (dev->status & ~STAT_SYSFLAG) | (val & STAT_SYSFLAG); +} + + +static void +pulse_output(atkbd_t *dev, uint8_t mask) +{ + if (mask != 0x0f) { + dev->old_p2 = dev->p2 & ~(0xf0 | mask); + kbd_log("pulse_output(): Output port now: %02X\n", dev->p2 & (0xf0 | mask | (dev->mem[0x20] & 0x30))); + write_output(dev, dev->p2 & (0xf0 | mask | (dev->mem[0x20] & 0x30))); + timer_set_delay_u64(&dev->pulse_cb, 6ULL * TIMER_USEC); + } +} + + +static void +set_enable_kbd(atkbd_t *dev, uint8_t enable) +{ + dev->mem[0x20] &= 0xef; + dev->mem[0x20] |= (enable ? 0x00 : 0x10); +} + + +static void +set_enable_mouse(atkbd_t *dev, uint8_t enable) +{ + dev->mem[0x20] &= 0xdf; + dev->mem[0x20] |= (enable ? 0x00 : 0x20); +} + + +static void +kbc_transmit(atkbd_t *dev, uint8_t val) +{ + kbc_send_to_ob(dev, val, 0, 0x00); +} + + +static void +kbc_command(atkbd_t *dev) +{ + uint8_t mask, val = dev->ib; + uint8_t kbc_ven = dev->flags & KBC_VEN_MASK; + int bad = 1; + + if ((dev->kbc_phase > 0) && (dev->kbc_cmd == 0xac)) { + if (dev-> kbc_phase < 16) + kbc_transmit(dev, dev->mem[dev->kbc_phase]); + else if (dev-> kbc_phase == 16) + kbc_transmit(dev, (dev->p1 & 0xf0) | 0x80); + else if (dev-> kbc_phase == 17) + kbc_transmit(dev, dev->p2); + else if (dev-> kbc_phase == 18) + kbc_transmit(dev, dev->status); + + dev->kbc_phase++; + if (dev->kbc_phase == 19) { + dev->kbc_phase = 0; + dev->kbc_cmd = 0x00; + } + return; + } else if ((dev->kbc_phase > 0) && (dev->kbc_cmd == 0xa0) && (kbc_ven >= KBC_VEN_AMI)) { + val = ami_copr[dev->kbc_phase]; + kbc_transmit(dev, val); + if (val == 0x00) { + dev->kbc_phase = 0; + dev->kbc_cmd = 0x00; + } else + dev->kbc_phase++; + return; + } else if ((dev->kbc_in > 0) && (dev->kbc_cmd == 0xa5) && (dev->flags & KBC_FLAG_PS2)) { + /* load security */ + kbd_log("ATkbc: load security\n"); + dev->mem[0x50 + dev->kbc_in - 0x01] = val; + if ((dev->kbc_in == 0x80) && (val != 0x00)) { + /* Security string too long, set it to 0x00. */ + dev->mem[0x50] = 0x00; + dev->kbc_in = 0; + dev->kbc_cmd = 0; + } else if (val == 0x00) { + /* Security string finished. */ + dev->kbc_in = 0; + dev->kbc_cmd = 0; + } else /* Increase pointer and request another byte. */ + dev->kbc_in++; + return; + } + + /* If the written port is 64, go straight to the beginning of the command. */ + if (!(dev->status & STAT_CD) && dev->kbc_in) { + /* Write data to controller. */ + dev->kbc_in = 0; + dev->kbc_phase = 0; + + switch (dev->kbc_cmd) { + case 0x60 ... 0x7f: + if (dev->kbc_cmd == 0x60) + write_cmd(dev, val); + else + dev->mem[(dev->kbc_cmd & 0x1f) + 0x20] = val; + break; + + case 0xc7: /* or input port with system data */ + dev->p1 |= val; + break; + + case 0xcb: /* set keyboard mode */ + kbd_log("New AMIKey mode: %02X\n", val); + dev->ami_mode = val; + dev->flags &= ~KBC_FLAG_PS2; + if (val & 1) + dev->flags |= KBC_FLAG_PS2; + break; + + case 0xd1: /* write output port */ + kbd_log("ATkbc: write output port\n"); + if (dev->p2_locked) { + /*If keyboard controller lines P22-P23 are blocked, + we force them to remain unchanged.*/ + val &= ~0x0c; + val |= (dev->p2 & 0x0c); + } + write_output(dev, val); + break; + + case 0xd2: /* write to keyboard output buffer */ + kbd_log("ATkbc: write to keyboard output buffer\n"); + // kbc_send_to_ob(dev, val, 1, 0x00); + /* Should be channel 1, but we send to 0 to avoid translation, + since bytes output using this command do *NOT* get translated. */ + kbc_send_to_ob(dev, val, 0, 0x00); + break; + + case 0xd3: /* write to mouse output buffer */ + kbd_log("ATkbc: write to mouse output buffer\n"); + if (dev->flags & KBC_FLAG_PS2) + kbc_send_to_ob(dev, val, 2, 0x00); + break; + + case 0xd4: /* write to mouse */ + kbd_log("ATkbc: write to mouse (%02X)\n", val); + + if (dev->flags & KBC_FLAG_PS2) { + set_enable_mouse(dev, 1); + dev->mem[0x20] &= ~0x20; + if (mouse_write && !dev->kbc_written[2]) { + kbd_log("ATkbc: Sending %02X to mouse...\n", dev->ib); + dev->mouse_data = val; + dev->mouse_written = 1; + dev->kbc_wait_for_response = 2; + } else + kbc_send_to_ob(dev, 0xfe, 2, 0x40); + } + break; + + default: + /* + * Run the vendor-specific handler + * if we have one. Otherwise, or if + * it returns an error, log a bad + * controller command. + */ + if (dev->write60_ven) + bad = dev->write60_ven(dev, val); + +#ifdef ENABLE_KEYBOARD_AT_LOG + if (bad) + kbd_log("ATkbc: bad controller command %02x data %02x\n", dev->kbc_cmd, val); +#endif + } + } else { + /* Controller command. */ + kbd_log("ATkbc: Controller command: %02X\n", val); + dev->kbc_in = 0; + dev->kbc_phase = 0; + + switch (val) { + /* Read data from KBC memory. */ + case 0x20 ... 0x3f: + kbc_transmit(dev, dev->mem[(val & 0x1f) + 0x20]); + break; + + /* Write data to KBC memory. */ + case 0x60 ... 0x7f: + dev->kbc_in = 1; + break; + + case 0xaa: /* self-test */ + kbd_log("ATkbc: self-test\n"); + write_output(dev, (dev->flags & KBC_FLAG_PS2) ? 0x4b : 0xcf); + + /* Always reinitialize all queues - the real hardware pulls keyboard and mouse + clocks high, which stops keyboard scanning. */ + kbd_log("ATkbc: self-test reinitialization\n"); + dev->kbd_in_cmd = dev->mouse_in_cmd = 0; + dev->status &= ~STAT_OFULL; + dev->last_irq = 0; + dev->kbc_phase = 0; + + /* Phoenix MultiKey should have 0x60 | STAT_SYSFLAG. */ + if (dev->flags & KBC_FLAG_PS2) + write_cmd(dev, 0x30 | STAT_SYSFLAG); + else + write_cmd(dev, 0x10 | STAT_SYSFLAG); + kbc_transmit(dev, 0x55); + break; + + case 0xab: /* interface test */ + kbd_log("ATkbc: interface test\n"); + /* No error. */ + kbc_transmit(dev, 0x00); + break; + + case 0xac: /* diagnostic dump */ + kbd_log("ATkbc: diagnostic dump\n"); + kbc_transmit(dev, dev->mem[0x20]); + dev->kbc_phase = 1; + break; + + case 0xad: /* disable keyboard */ + kbd_log("ATkbc: disable keyboard\n"); + set_enable_kbd(dev, 0); + break; + + case 0xae: /* enable keyboard */ + kbd_log("ATkbc: enable keyboard\n"); + set_enable_kbd(dev, 1); + break; + + case 0xc7: /* or input port with system data */ + kbd_log("ATkbc: Phoenix - or input port with system data\n"); + dev->kbc_in = 1; + break; + + case 0xca: /* read keyboard mode */ + kbd_log("ATkbc: AMI - read keyboard mode\n"); + kbc_transmit(dev, dev->ami_mode); + break; + + case 0xcb: /* set keyboard mode */ + kbd_log("ATkbc: AMI - set keyboard mode\n"); + dev->kbc_in = 1; + break; + + case 0xd0: /* read output port */ + kbd_log("ATkbc: read output port\n"); + mask = 0xff; + if (dev->mem[0x20] & 0x10) + mask &= 0xbf; + if ((dev->flags & KBC_FLAG_PS2) && (dev->mem[0x20] & 0x20)) + mask &= 0xf7; + kbc_transmit(dev, dev->p2 & mask); + break; + + case 0xd1: /* write output port */ + kbd_log("ATkbc: write output port\n"); + dev->kbc_in = 1; + break; + + case 0xd2: /* write keyboard output buffer */ + kbd_log("ATkbc: write keyboard output buffer\n"); + if (dev->flags & KBC_FLAG_PS2) + dev->kbc_in = 1; + else + kbc_transmit(dev, 0x00); /* NCR */ + break; + + case 0xdd: /* disable A20 address line */ + case 0xdf: /* enable A20 address line */ + kbd_log("ATkbc: %sable A20\n", (val == 0xdd) ? "dis": "en"); + write_output(dev, (dev->p2 & 0xfd) | (val & 0x02)); + break; + + case 0xe0: /* read test inputs */ + kbd_log("ATkbc: read test inputs\n"); + kbc_transmit(dev, 0x00); + break; + + case 0xe1: case 0xea: + kbd_log("ATkbc: setting P23-P21 to %01X\n", val & 0x0e); + write_output(dev, (dev->p2 & 0xf1) | (val & 0x0e)); + break; + + default: + /* + * Unrecognized controller command. + * + * If we have a vendor-specific handler, run + * that. Otherwise, or if that handler fails, + * log a bad command. + */ + if (dev->write64_ven) + bad = dev->write64_ven(dev, val); + + kbd_log(bad ? "ATkbc: bad controller command %02X\n" : "", val); + } + + /* If the command needs data, remember the command. */ + if (dev->kbc_in || (dev->kbc_phase > 0)) + dev->kbc_cmd = val; + } +} + + +static void +kbc_dev_data_to_ob(atkbd_t *dev, uint8_t channel) +{ + dev->kbc_written[channel] = 0; + kbd_log("ATkbd: Forwarding %02X from channel %i...\n", dev->kbc_data[channel], channel); + kbc_send_to_ob(dev, dev->kbc_data[channel], channel, 0x00); +} + + +static void +kbc_main_loop_scan(atkbd_t *dev) +{ + uint8_t port_dis = dev->mem[0x20] & 0x30; + uint8_t ps2 = (dev->flags & KBC_FLAG_PS2); + + if (!ps2) + port_dis |= 0x20; + + if (!(dev->status & STAT_OFULL)) { + if (port_dis & 0x20) { + if (!(port_dis & 0x10)) { + kbd_log("ATkbc: kbc_process()\n" + "ATkbc: Main loop\n" + "ATkbc: Scan: AUX DIS, KBD EN\n"); + // kbd_log("ATkbc: Scan: AUX DIS, KBD EN\n"); + /* Enable communication with keyboard. */ + dev->p2 &= 0xbf; + dev->kbd_inhibit = 0; + kbc_wait(dev, 1); + } +#ifdef ENABLE_KEYBOARD_AT_LOG + else { + kbd_log("ATkbc: kbc_process()\n" + "ATkbc: Main loop\n" + "ATkbc: Scan: AUX DIS, KBD DIS\n"); + // kbd_log("ATkbc: Scan: AUX DIS, KBD DIS\n"); + } +#endif + } else { + /* Enable communication with mouse. */ + dev->p2 &= 0xf7; + dev->mouse_inhibit = 0; + if (dev->mem[0x20] & 0x10) { + kbd_log("ATkbc: kbc_process()\n" + "ATkbc: Main loop\n" + "ATkbc: Scan: AUX EN , KBD DIS\n"); + // kbd_log("ATkbc: Scan: AUX EN , KBD DIS\n"); + kbc_wait(dev, 2); + } else { + /* Enable communication with keyboard. */ + kbd_log("ATkbc: kbc_process()\n" + "ATkbc: Main loop\n" + "ATkbc: Scan: AUX EN , KBD EN\n"); + // kbd_log("ATkbc: Scan: AUX EN , KBD EN\n"); + dev->p2 &= 0xbf; + dev->kbd_inhibit = 0; + kbc_wait(dev, 3); + } + } + } +#ifdef ENABLE_KEYBOARD_AT_LOG + else { + kbd_log("ATkbc: kbc_process()\n" + "ATkbc: Main loop\n" + "ATkbc: Scan: IBF not full and OBF full, do nothing\n"); + // kbd_log("ATkbc: Scan: IBF not full and OBF full, do nothing\n"); + } +#endif +} + + +static void +kbc_process_ib(atkbd_t *dev) +{ + dev->status &= ~STAT_IFULL; + + if (dev->status & STAT_CD) { + dev->kbc_in_cmd = 1; + kbc_command(dev); + + if ((dev->kbc_phase == 0) && !dev->kbc_in) + dev->kbc_in_cmd = 0; + else + return; + } else { + dev->mem[0x20] &= ~0x10; + dev->kbd_data = dev->ib; + dev->kbd_written = 1; + dev->kbc_wait_for_response = 1; + } + + dev->kbc_poll_phase = KBC_MAIN_LOOP; + if (!dev->kbc_wait_for_response) + kbc_main_loop_scan(dev); +} + + +static void +kbc_wait(atkbd_t *dev, uint8_t flags) +{ + if ((flags & 1) && dev->kbc_written[1]) { + /* Disable communication with mouse. */ + dev->p2 |= 0x08; + dev->mouse_inhibit = 1; + /* Send keyboard byte to host. */ + kbc_dev_data_to_ob(dev, CHANNEL_KBD); + dev->kbc_poll_phase = KBC_MAIN_LOOP; + } else if ((flags & 2) && dev->kbc_written[2]) { + /* Disable communication with keyboard. */ + dev->p2 |= 0x40; + dev->kbd_inhibit = 1; + /* Send mouse byte to host. */ + kbc_dev_data_to_ob(dev, CHANNEL_MOUSE); + dev->kbc_poll_phase = KBC_MAIN_LOOP; + } else if (dev->status & STAT_IFULL) { + /* Disable communication with keyboard and mouse. */ + dev->p2 |= 0x48; + dev->kbd_inhibit = dev->mouse_inhibit = 1; + kbc_process_ib(dev); + } else + dev->kbc_poll_phase = KBC_WAIT | flags; +} + + +/* Controller processing */ +static void +kbc_process(atkbd_t *dev) +{ + // kbd_log("ATkbc: kbc_process()\n"); + + /* If we're waiting for the response from the keyboard or mouse, do nothing + until the device has repsonded back. */ + if (dev->kbc_wait_for_response > 0) { + if (dev->kbc_written[dev->kbc_wait_for_response]) + dev->kbc_wait_for_response = 0; + else + return; + } + + if (dev->kbc_send_pending) { + kbd_log("ATkbc: Sending delayed %02X on channel %i with high status %02X\n", + dev->kbc_to_send, dev->kbc_channel, dev->kbc_stat_hi); + kbc_send_to_ob(dev, dev->kbc_to_send, dev->kbc_channel, dev->kbc_stat_hi); + dev->kbc_send_pending = 0; + } + + if (dev->kbc_poll_phase == KBC_RESET) { + kbd_log("ATkbc: kbc_process()\n" + "ATkbc: Reset loop()\n"); + + if (dev->status & STAT_IFULL) { + dev->status &= ~STAT_IFULL; + + if ((dev->status & STAT_CD) && (dev->ib == 0xaa)) { + dev->kbc_in_cmd = 1; + kbc_command(dev); + + if ((dev->kbc_phase == 0) && !dev->kbc_in) + dev->kbc_in_cmd = 0; + + dev->kbc_poll_phase = KBC_MAIN_LOOP; + } + } + + return; + } + + if (dev->kbc_in_cmd || (dev->kbc_phase > 0) || dev->kbc_in) { + kbd_log("ATkbc: kbc_process()\n" + "ATkbc: In a command\n"); + if (!dev->kbc_in && (dev->status & STAT_OFULL)) { + kbd_log("ATkbc: !dev->kbc_in && (dev->status & STAT_OFULL)\n"); + return; /* We do not want input and we're waiting for the host to read the data + we transmitted, but it has not done that yet, do nothing. */ + } else if (dev->kbc_in && !(dev->status & STAT_IFULL)) { + kbd_log("ATkbc: dev->kbc_in && !(dev->status & STAT_IFULL)\n"); + return; /* We want input and the host has not provided us with any yet, do nothing. */ + } +#ifdef ENABLE_KEYBOARD_AT_LOG + else + kbd_log("ATkbc: Normal condition\n"); +#endif + + if (dev->status & STAT_IFULL) { + dev->status &= ~STAT_IFULL; + + if (dev->status & STAT_CD) { + kbd_log("ATkbc: Resetting command\n"); + dev->kbc_phase = 0; + dev->kbc_in = 0; + } + } + + /* Process command. */ + kbc_command(dev); + + if ((dev->kbc_phase == 0) && !dev->kbc_in) + dev->kbc_in_cmd = 0; + else + return; + + if (!(dev->status & STAT_OFULL)) + kbc_main_loop_scan(dev); + /* Make absolutely sure to do nothing if OBF is full and IBF is empty. */ + } else if (!(dev->status & STAT_OFULL) || (dev->status & STAT_IFULL)) switch (dev->kbc_poll_phase) { + case KBC_MAIN_LOOP: + // kbd_log("ATkbc: Main loop\n"); + if (dev->status & STAT_IFULL) { + kbd_log("ATkbc: kbc_process()\n" + "ATkbc: Main loop\n" + "ATkbc: IBF full, process\n"); + kbc_process_ib(dev); + } else + kbc_main_loop_scan(dev); + break; + case KBC_WAIT_FOR_KBD: + case KBC_WAIT_FOR_MOUSE: + case KBC_WAIT_FOR_BOTH: + kbd_log("ATkbc: kbc_process()\n" + "ATkbc: Scan: Phase %i\n", dev->kbc_poll_phase); + kbc_wait(dev, dev->kbc_poll_phase & 3); + break; + default: + kbd_log("ATkbc: kbc_process()\n" + "ATkbc: Scan: Invalid phase %i\n", dev->kbc_poll_phase); + break; + } } @@ -742,105 +1792,29 @@ static void kbd_poll(void *priv) { atkbd_t *dev = (atkbd_t *)priv; -#ifdef ENABLE_KEYBOARD_AT_LOG - const uint8_t channels[4] = { 1, 2, 0, 0 }; -#endif timer_advance_u64(&dev->send_delay_timer, (100ULL * TIMER_USEC)); - if (dev->out_new != -1 && !dev->last_irq) { - dev->wantirq = 0; - if (dev->out_new & 0x100) { - if (dev->mem[0] & 0x02) - picint(0x1000); - kbd_log("ATkbc: %02X coming from channel 2\n"); - dev->out = dev->out_new & 0xff; - dev->out_new = -1; - dev->status = (dev->status & ~STAT_IFULL) | (STAT_OFULL | STAT_MFULL); - dev->last_irq = 0x1000; - } else { - if (dev->mem[0] & 0x01) - picint(2); - kbd_log("ATkbc: %02X coming from channel %i\n", dev->out_new & 0xff, channels[(dev->out_new >> 8) & 0x03]); - dev->out = dev->out_new & 0xff; - dev->out_new = -1; - dev->status = (dev->status & ~(STAT_IFULL | STAT_MFULL)) | STAT_OFULL; - dev->last_irq = 2; - } - } + /* We process all three devices at the same time, in an arbitrary order. */ - if (dev->out_new == -1 && !(dev->status & STAT_OFULL) && key_ctrl_queue_start != key_ctrl_queue_end) { - kbd_log("ATkbc: %02X on channel 0\n", key_ctrl_queue[key_ctrl_queue_start]); - dev->out_new = key_ctrl_queue[key_ctrl_queue_start] | 0x200; - key_ctrl_queue_start = (key_ctrl_queue_start + 1) & 0xf; - } else if (!(dev->status & STAT_OFULL) && dev->out_new == -1 && dev->out_delayed != -1) { - kbd_log("ATkbc: %02X delayed on channel %i\n", dev->out_delayed & 0xff, channels[(dev->out_delayed >> 8) & 0x03]); - dev->out_new = dev->out_delayed; - dev->out_delayed = -1; - } else if (!(dev->status & STAT_OFULL) && dev->out_new == -1 && mouse_queue_start != mouse_queue_end) { - kbd_log("ATkbc: %02X on channel 2\n", mouse_queue[mouse_queue_start]); - dev->out_new = mouse_queue[mouse_queue_start] | 0x100; - mouse_queue_start = (mouse_queue_start + 1) & 0xf; - } else if (!(dev->status & STAT_OFULL) && dev->out_new == -1 && !(dev->mem[0] & 0x10) && key_queue_start != key_queue_end) { - kbd_log("ATkbc: %02X on channel 1\n", key_queue[key_queue_start]); - dev->out_new = key_queue[key_queue_start]; - key_queue_start = (key_queue_start + 1) & 0xf; - } + /* Keyboard processing */ + kbd_process(dev); - if (dev->reset_delay) { - dev->reset_delay--; - if (!dev->reset_delay) { - kbd_log("ATkbc: Sending AA on keyboard reset...\n"); - add_data_kbd_direct(dev, 0xaa); - } - } -} + /* TODO: Mouse processing */ + // mouse_process(dev); - -static void -add_data(atkbd_t *dev, uint8_t val) -{ - kbd_log("ATkbc: add to queue\n"); - - kbd_log("ATkbc: key_ctrl_queue[%02X] = %02X;\n", key_ctrl_queue_end, val); - kbc_queue_add(dev, val, 0, 0x00); - - if (!(dev->out_new & 0x300)) { - dev->out_delayed = dev->out_new; - dev->out_new = -1; - } + /* Controller processing */ + kbc_process(dev); } static void add_data_vals(atkbd_t *dev, uint8_t *val, uint8_t len) { - int xt_mode = (keyboard_mode & 0x20) && ((dev->flags & KBC_TYPE_MASK) < KBC_TYPE_PS2_NOREF); - int translate = (keyboard_mode & 0x40); int i; - uint8_t or = 0; - uint8_t send; - if (dev->reset_delay) - return; - - translate = translate || (keyboard_mode & 0x40) || xt_mode; - translate = translate || ((dev->flags & KBC_TYPE_MASK) == KBC_TYPE_PS2_2); - - for (i = 0; i < len; i++) { - if (translate) { - if (val[i] == 0xf0) { - or = 0x80; - continue; - } - send = nont_to_t[val[i]] | or; - if (or == 0x80) - or = 0; - } else - send = val[i]; - - add_data_kbd_queue(dev, 0, send); - } + for (i = 0; i < len; i++) + add_data_kbd_queue(dev, 0, val[i]); } @@ -848,56 +1822,21 @@ static void add_data_kbd(uint16_t val) { atkbd_t *dev = SavedKbd; - int xt_mode = (keyboard_mode & 0x20) && ((dev->flags & KBC_TYPE_MASK) < KBC_TYPE_PS2_NOREF); - int translate = (keyboard_mode & 0x40); uint8_t fake_shift[4]; uint8_t num_lock = 0, shift_states = 0; uint8_t kbc_ven = dev->flags & KBC_VEN_MASK; - if (dev->reset_delay) + if (dev->kbd_in || (dev->kbd_phase > 0)) return; - translate = translate || (keyboard_mode & 0x40) || xt_mode; - translate = translate || ((dev->flags & KBC_TYPE_MASK) == KBC_TYPE_PS2_2); - keyboard_get_states(NULL, &num_lock, NULL); shift_states = keyboard_get_shift() & STATE_SHIFT_MASK; - /* Allow for scan code translation. */ - if (translate && (val == 0xf0)) { - kbd_log("ATkbd: translate is on, F0 prefix detected\n"); - sc_or = 0x80; - return; - } - - /* Skip break code if translated make code has bit 7 set. */ - if (translate && (sc_or == 0x80) && (val & 0x80)) { - kbd_log("ATkbd: translate is on, skipping scan code: %02X (original: F0 %02X)\n", nont_to_t[val], val); - sc_or = 0; - return; - } - /* Test for T3100E 'Fn' key (Right Alt / Right Ctrl) */ - if ((dev != NULL) && (kbc_ven == KBC_VEN_TOSHIBA) && - (keyboard_recv(0xb8) || keyboard_recv(0x9d))) switch (val) { - case 0x4f: t3100e_notify_set(0x01); break; /* End */ - case 0x50: t3100e_notify_set(0x02); break; /* Down */ - case 0x51: t3100e_notify_set(0x03); break; /* PgDn */ - case 0x52: t3100e_notify_set(0x04); break; /* Ins */ - case 0x53: t3100e_notify_set(0x05); break; /* Del */ - case 0x54: t3100e_notify_set(0x06); break; /* SysRQ */ - case 0x45: t3100e_notify_set(0x07); break; /* NumLock */ - case 0x46: t3100e_notify_set(0x08); break; /* ScrLock */ - case 0x47: t3100e_notify_set(0x09); break; /* Home */ - case 0x48: t3100e_notify_set(0x0a); break; /* Up */ - case 0x49: t3100e_notify_set(0x0b); break; /* PgUp */ - case 0x4A: t3100e_notify_set(0x0c); break; /* Keypad -*/ - case 0x4B: t3100e_notify_set(0x0d); break; /* Left */ - case 0x4C: t3100e_notify_set(0x0e); break; /* KP 5 */ - case 0x4D: t3100e_notify_set(0x0f); break; /* Right */ - } + if ((dev != NULL) && (kbc_ven == KBC_VEN_TOSHIBA) && (keyboard_recv(0xb8) || keyboard_recv(0x9d)) && + (val >= 0x4f) && (val <= 0x54) && (val != 0x4e)) + t3100e_notify_set((val + 2) & 0x0f); - kbd_log("ATkbd: translate is %s, ", translate ? "on" : "off"); switch(val) { case FAKE_LSHIFT_ON: kbd_log("fake left shift on, scan code: "); @@ -1030,18 +1969,7 @@ add_data_kbd(uint16_t val) break; default: -#ifdef ENABLE_KEYBOARD_AT_LOG - kbd_log("scan code: "); - if (translate) { - kbd_log("%02X (original: ", (nont_to_t[val] | sc_or)); - if (sc_or == 0x80) - kbd_log("F0 "); - kbd_log("%02X)\n", val); - } else - kbd_log("%02X\n", val); -#endif - - add_data_kbd_queue(dev, 0, translate ? (nont_to_t[val] | sc_or) : val); + add_data_kbd_queue(dev, 0, val); break; } @@ -1050,121 +1978,13 @@ add_data_kbd(uint16_t val) } -static void -write_output(atkbd_t *dev, uint8_t val) -{ - uint8_t kbc_ven = dev->flags & KBC_VEN_MASK; - kbd_log("ATkbc: write output port: %02X (old: %02X)\n", val, dev->output_port); - - if ((kbc_ven == KBC_VEN_AMI) || ((dev->flags & KBC_TYPE_MASK) < KBC_TYPE_PS2_NOREF)) - val |= ((dev->mem[0] << 4) & 0x10); - - if ((dev->output_port ^ val) & 0x20) { /*IRQ 12*/ - if (val & 0x20) - picint(1 << 12); - else - picintc(1 << 12); - } - if ((dev->output_port ^ val) & 0x10) { /*IRQ 1*/ - if (val & 0x10) - picint(1 << 1); - else - picintc(1 << 1); - } - if ((dev->output_port ^ val) & 0x02) { /*A20 enable change*/ - mem_a20_key = val & 0x02; - mem_a20_recalc(); - flushmmucache(); - } - if ((dev->output_port ^ val) & 0x01) { /*Reset*/ - if (! (val & 0x01)) { - /* Pin 0 selected. */ - softresetx86(); /*Pulse reset!*/ - cpu_set_edx(); - smbase = is_am486dxl ? 0x00060000 : 0x00030000; - } - } - /* Mask off the A20 stuff because we use mem_a20_key directly for that. */ - dev->output_port = val; -} - - -static void -write_cmd(atkbd_t *dev, uint8_t val) -{ - uint8_t kbc_ven = dev->flags & KBC_VEN_MASK; - kbd_log("ATkbc: write command byte: %02X (old: %02X)\n", val, dev->mem[0]); - - if ((val & 1) && (dev->status & STAT_OFULL)) - dev->wantirq = 1; - if (!(val & 1) && dev->wantirq) - dev->wantirq = 0; - - /* PS/2 type 2 keyboard controllers always force the XLAT bit to 0. */ - if ((dev->flags & KBC_TYPE_MASK) == KBC_TYPE_PS2_2) { - val &= ~CCB_TRANSLATE; - dev->mem[0] &= ~CCB_TRANSLATE; - } - - /* Scan code translate ON/OFF. */ - keyboard_mode &= 0x93; - keyboard_mode |= (val & MODE_MASK); - - kbd_log("ATkbc: keyboard interrupt is now %s\n", (val & 0x01) ? "enabled" : "disabled"); - - /* ISA AT keyboard controllers use bit 5 for keyboard mode (1 = PC/XT, 2 = AT); - PS/2 (and EISA/PCI) keyboard controllers use it as the PS/2 mouse enable switch. - The AMIKEY firmware apparently uses this bit for something else. */ - if ((kbc_ven == KBC_VEN_AMI) || - ((dev->flags & KBC_TYPE_MASK) >= KBC_TYPE_PS2_NOREF)) { - keyboard_mode &= ~CCB_PCMODE; - /* Update the output port to mirror the KBD DIS and AUX DIS bits, if active. */ - write_output(dev, dev->output_port); - - kbd_log("ATkbc: mouse interrupt is now %s\n", (val & 0x02) ? "enabled" : "disabled"); - } - - kbd_log("Command byte now: %02X (%02X)\n", dev->mem[0], val); - - dev->status = (dev->status & ~STAT_SYSFLAG) | (val & STAT_SYSFLAG); -} - - -static void -pulse_output(atkbd_t *dev, uint8_t mask) -{ - if (mask != 0x0f) { - dev->old_output_port = dev->output_port & ~(0xf0 | mask); - kbd_log("pulse_output(): Output port now: %02X\n", dev->output_port & (0xf0 | mask)); - write_output(dev, dev->output_port & (0xf0 | mask)); - timer_set_delay_u64(&dev->pulse_cb, 6ULL * TIMER_USEC); - } -} - - static void pulse_poll(void *priv) { atkbd_t *dev = (atkbd_t *)priv; - kbd_log("pulse_poll(): Output port now: %02X\n", dev->output_port | dev->old_output_port); - write_output(dev, dev->output_port | dev->old_output_port); -} - - -static void -set_enable_kbd(atkbd_t *dev, uint8_t enable) -{ - dev->mem[0] &= 0xef; - dev->mem[0] |= (enable ? 0x00 : 0x10); -} - - -static void -set_enable_mouse(atkbd_t *dev, uint8_t enable) -{ - dev->mem[0] &= 0xdf; - dev->mem[0] |= (enable ? 0x00 : 0x20); + kbd_log("pulse_poll(): Output port now: %02X\n", dev->p2 | dev->old_p2); + write_output(dev, dev->p2 | dev->old_p2); } @@ -1173,49 +1993,70 @@ write64_generic(void *priv, uint8_t val) { atkbd_t *dev = (atkbd_t *)priv; uint8_t current_drive, fixed_bits; - uint8_t kbc_ven = 0x0; - kbc_ven = dev->flags & KBC_VEN_MASK; - + uint8_t kbc_ven = 0x0; + kbc_ven = dev->flags & KBC_VEN_MASK; switch (val) { case 0xa4: /* check if password installed */ - if ((dev->flags & KBC_TYPE_MASK) >= KBC_TYPE_PS2_NOREF) { + if (dev->flags & KBC_FLAG_PS2) { kbd_log("ATkbc: check if password installed\n"); - add_data(dev, 0xf1); + kbc_transmit(dev, (dev->mem[0x50] == 0x00) ? 0xf1 : 0xfa); + return 0; + } + break; + + case 0xa5: /* load security */ + if (dev->flags & KBC_FLAG_PS2) { + kbd_log("ATkbc: load security\n"); + dev->kbc_in = 1; return 0; } break; case 0xa7: /* disable mouse port */ - if ((dev->flags & KBC_TYPE_MASK) >= KBC_TYPE_PS2_NOREF) { + if (dev->flags & KBC_FLAG_PS2) { kbd_log("ATkbc: disable mouse port\n"); - set_enable_mouse(dev, 0); + // kbc_transmit(dev, 0); return 0; } break; case 0xa8: /*Enable mouse port*/ - if ((dev->flags & KBC_TYPE_MASK) >= KBC_TYPE_PS2_NOREF) { + if (dev->flags & KBC_FLAG_PS2) { kbd_log("ATkbc: enable mouse port\n"); - set_enable_mouse(dev, 1); + // kbc_transmit(dev, 1); return 0; } break; case 0xa9: /*Test mouse port*/ kbd_log("ATkbc: test mouse port\n"); - if ((dev->flags & KBC_TYPE_MASK) >= KBC_TYPE_PS2_NOREF) { - add_data(dev, 0x00); /* no error, this is testing the channel 2 interface */ + if (dev->flags & KBC_FLAG_PS2) { + /* No error, this is testing the channel 2 interface. */ + kbc_transmit(dev, 0x00); return 0; } break; case 0xaf: /* read keyboard version */ kbd_log("ATkbc: read keyboard version\n"); - add_data(dev, 0x00); + kbc_transmit(dev, 0x00); return 0; case 0xc0: /* read input port */ + /* IBM PS/1: + Bit 2 and 4 ignored (we return always 0), + Bit 6 must 1 for 5.25" floppy drive, 0 for 3.5". + Intel AMI: + Bit 2 ignored (we return always 1), + Bit 4 must be 1, + Bit 6 must be 1 or else error in SMM. + Acer: + Bit 2 must be 0 (and Acer V10 disables CMOS setup if it's 1), + Bit 4 must be 0, + Bit 6 ignored. + P6RP4: + Bit 2 must be 1 or CMOS setup is disabled. */ kbd_log("ATkbc: read input port\n"); fixed_bits = 4; /* The SMM handlers of Intel AMI Pentium BIOS'es expect bit 6 to be set. */ @@ -1223,11 +2064,8 @@ write64_generic(void *priv, uint8_t val) fixed_bits |= 0x40; if (kbc_ven == KBC_VEN_IBM_PS1) { current_drive = fdc_get_current_drive(); - add_to_kbc_queue_front(dev, dev->input_port | fixed_bits | (fdd_is_525(current_drive) ? 0x40 : 0x00), - 0, 0x00); - dev->input_port = ((dev->input_port + 1) & 3) | - (dev->input_port & 0xfc) | - (fdd_is_525(current_drive) ? 0x40 : 0x00); + kbc_transmit(dev, dev->p1 | fixed_bits | (fdd_is_525(current_drive) ? 0x40 : 0x00)); + dev->p1 = ((dev->p1 + 1) & 3) | (dev->p1 & 0xfc) | (fdd_is_525(current_drive) ? 0x40 : 0x00); } else if (kbc_ven == KBC_VEN_NCR) { /* switch settings * bit 7: keyboard disable @@ -1239,39 +2077,34 @@ write64_generic(void *priv, uint8_t val) * bit 1: high/auto speed * bit 0: dma mode */ - add_to_kbc_queue_front(dev, (dev->input_port | fixed_bits | (video_is_mda() ? 0x40 : 0x00) | (hasfpu ? 0x08 : 0x00)) & 0xdf, - 0, 0x00); - dev->input_port = ((dev->input_port + 1) & 3) | - (dev->input_port & 0xfc); + kbc_transmit(dev, (dev->p1 | fixed_bits | (video_is_mda() ? 0x40 : 0x00) | (hasfpu ? 0x08 : 0x00)) & 0xdf); + dev->p1 = ((dev->p1 + 1) & 3) | (dev->p1 & 0xfc); } else { - if (((dev->flags & KBC_TYPE_MASK) >= KBC_TYPE_PS2_NOREF) && - ((dev->flags & KBC_VEN_MASK) != KBC_VEN_INTEL_AMI)) - add_to_kbc_queue_front(dev, (dev->input_port | fixed_bits) & - (((dev->flags & KBC_VEN_MASK) == KBC_VEN_ACER) ? 0xeb : 0xef), 0, 0x00); + pclog("[%04X:%08X] Reading %02X from input port\n", CS, cpu_state.pc, ((dev->p1 | fixed_bits) & 0xf0) | 0x0c); + if ((dev->flags & KBC_FLAG_PS2) && ((dev->flags & KBC_VEN_MASK) != KBC_VEN_INTEL_AMI)) + // kbc_transmit(dev, ((dev->p1 | fixed_bits) & 0xf0) | 0x0c); + kbc_transmit(dev, ((dev->p1 | fixed_bits) & 0xf0) | 0x08); + // kbc_transmit(dev, (dev->p1 | fixed_bits) & (((dev->flags & KBC_VEN_MASK) == KBC_VEN_ACER) ? 0xeb : 0xef)); else - add_to_kbc_queue_front(dev, dev->input_port | fixed_bits, 0, 0x00); - dev->input_port = ((dev->input_port + 1) & 3) | - (dev->input_port & 0xfc); + kbc_transmit(dev, dev->p1 | fixed_bits); + dev->p1 = ((dev->p1 + 1) & 3) | (dev->p1 & 0xfc); } return 0; case 0xd3: /* write mouse output buffer */ - if ((dev->flags & KBC_TYPE_MASK) >= KBC_TYPE_PS2_NOREF) { + if (dev->flags & KBC_FLAG_PS2) { kbd_log("ATkbc: write mouse output buffer\n"); - dev->want60 = 1; + dev->kbc_in = 1; return 0; } break; case 0xd4: /* write to mouse */ kbd_log("ATkbc: write to mouse\n"); - dev->want60 = 1; + dev->kbc_in = 1; return 0; - case 0xf0: case 0xf1: case 0xf2: case 0xf3: - case 0xf4: case 0xf5: case 0xf6: case 0xf7: - case 0xf8: case 0xf9: case 0xfa: case 0xfb: - case 0xfc: case 0xfd: case 0xfe: case 0xff: + case 0xf0 ... 0xff: kbd_log("ATkbc: pulse %01X\n", val & 0x0f); pulse_output(dev, val & 0x0f); return 0; @@ -1286,35 +2119,168 @@ static uint8_t write60_ami(void *priv, uint8_t val) { atkbd_t *dev = (atkbd_t *)priv; + uint16_t index = 0x00c0; - switch(dev->command) { - /* 0x40 - 0x5F are aliases for 0x60-0x7F */ - case 0x40: case 0x41: case 0x42: case 0x43: - case 0x44: case 0x45: case 0x46: case 0x47: - case 0x48: case 0x49: case 0x4a: case 0x4b: - case 0x4c: case 0x4d: case 0x4e: case 0x4f: - case 0x50: case 0x51: case 0x52: case 0x53: - case 0x54: case 0x55: case 0x56: case 0x57: - case 0x58: case 0x59: case 0x5a: case 0x5b: - case 0x5c: case 0x5d: case 0x5e: case 0x5f: - kbd_log("ATkbc: AMI - alias write to %08X\n", dev->command); - dev->mem[dev->command & 0x1f] = val; - if (dev->command == 0x60) + switch(dev->kbc_cmd) { + /* 0x40 - 0x5F are aliases for 0x60 - 0x7F */ + case 0x40 ... 0x5f: + kbd_log("ATkbc: AMI - alias write to %08X\n", dev->kbc_cmd); + if (dev->kbc_cmd == 0x40) write_cmd(dev, val); + else + dev->mem[(dev->kbc_cmd & 0x1f) + 0x20] = val; return 0; case 0xaf: /* set extended controller RAM */ - kbd_log("ATkbc: AMI - set extended controller RAM\n"); - if (dev->secr_phase == 1) { - dev->mem_addr = val; - dev->want60 = 1; - dev->secr_phase = 2; - } else if (dev->secr_phase == 2) { - dev->mem[dev->mem_addr] = val; + kbd_log("ATkbc: AMI - set extended controller RAM, input phase %i\n", dev->secr_phase); + if (dev->secr_phase == 0) { + dev->mem_index = val; + dev->kbc_in = 1; + dev->secr_phase++; + } else if (dev->secr_phase == 1) { + if (dev->mem_index == 0x20) + write_cmd(dev, val); + else + dev->mem[dev->mem_index] = val; dev->secr_phase = 0; } return 0; + case 0xb8: + kbd_log("ATkbc: AMI MegaKey - memory index %02X\n", val); + dev->mem_index = val; + return 0; + + case 0xbb: + kbd_log("ATkbc: AMI MegaKey - write %02X to memory index %02X\n", val, dev->mem_index); + if (dev->mem_index >= 0x80) { + switch (dev->mem[0x9b] & 0xc0) { + case 0x00: + index = 0x0080; + break; + case 0x40: case 0x80: + index = 0x0000; + break; + case 0xc0: + index = 0x0100; + break; + } + dev->mem[index + dev->mem_index] = val; + } else if (dev->mem_index == 0x60) + write_cmd(dev, val); + else if (dev->mem_index == 0x42) + dev->status = val; + else if (dev->mem_index >= 0x40) + dev->mem[dev->mem_index - 0x40] = val; + else + dev->mem_int[dev->mem_index] = val; + return 0; + + case 0xbd: + kbd_log("ATkbc: AMI MegaKey - write %02X to config index %02X\n", val, dev->mem_index); + switch (dev->mem_index) { + case 0x00: /* STAT8042 */ + dev->status = val; + break; + case 0x01: /* Password_ptr */ + dev->mem[0x1c] = val; + break; + case 0x02: /* Wakeup_Tsk_Reg */ + dev->mem[0x1e] = val; + break; + case 0x03: /* CCB */ + write_cmd(dev, val); + break; + case 0x04: /* Debounce_time */ + dev->mem[0x4d] = val; + break; + case 0x05: /* Pulse_Width */ + dev->mem[0x4e] = val; + break; + case 0x06: /* Pk_sel_byte */ + dev->mem[0x4c] = val; + break; + case 0x07: /* Func_Tsk_Reg */ + dev->mem[0x7e] = val; + break; + case 0x08: /* TypematicRate */ + dev->mem[0x80] = val; + break; + case 0x09: /* Led_Flag_Byte */ + dev->mem[0x81] = val; + break; + case 0x0a: /* Kbms_Command_St */ + dev->mem[0x87] = val; + break; + case 0x0b: /* Delay_Count_Byte */ + dev->mem[0x86] = val; + break; + case 0x0c: /* KBC_Flags */ + dev->mem[0x9b] = val; + break; + case 0x0d: /* SCODE_HK1 */ + dev->mem[0x50] = val; + break; + case 0x0e: /* SCODE_HK2 */ + dev->mem[0x51] = val; + break; + case 0x0f: /* SCODE_HK3 */ + dev->mem[0x52] = val; + break; + case 0x10: /* SCODE_HK4 */ + dev->mem[0x53] = val; + break; + case 0x11: /* SCODE_HK5 */ + dev->mem[0x54] = val; + break; + case 0x12: /* SCODE_HK6 */ + dev->mem[0x55] = val; + break; + case 0x13: /* TASK_HK1 */ + dev->mem[0x56] = val; + break; + case 0x14: /* TASK_HK2 */ + dev->mem[0x57] = val; + break; + case 0x15: /* TASK_HK3 */ + dev->mem[0x58] = val; + break; + case 0x16: /* TASK_HK4 */ + dev->mem[0x59] = val; + break; + case 0x17: /* TASK_HK5 */ + dev->mem[0x5a] = val; + break; + /* The next 4 bytes have uncertain correspondences. */ + case 0x18: /* Batt_Poll_delay_Time */ + dev->mem[0x5b] = val; + break; + case 0x19: /* Batt_Alarm_Reg1 */ + dev->mem[0x5c] = val; + break; + case 0x1a: /* Batt_Alarm_Reg2 */ + dev->mem[0x5d] = val; + break; + case 0x1b: /* Batt_Alarm_Tsk_Reg */ + dev->mem[0x5e] = val; + break; + case 0x1c: /* Kbc_State1 */ + dev->mem[0x9d] = val; + break; + case 0x1d: /* Aux_Config */ + dev->mem[0x75] = val; + break; + case 0x1e: /* Kbc_State3 */ + dev->mem[0x73] = val; + break; + } + return 0; + + case 0xc1: /* write input port */ + kbd_log("ATkbc: AMI MegaKey - write %02X to input port\n", val); + dev->p1 = val; + return 0; + case 0xcb: /* set keyboard mode */ kbd_log("ATkbc: AMI - set keyboard mode\n"); return 0; @@ -1328,62 +2294,50 @@ static uint8_t write64_ami(void *priv, uint8_t val) { atkbd_t *dev = (atkbd_t *)priv; + uint16_t index = 0x00c0; switch (val) { - case 0x00: case 0x01: case 0x02: case 0x03: - case 0x04: case 0x05: case 0x06: case 0x07: - case 0x08: case 0x09: case 0x0a: case 0x0b: - case 0x0c: case 0x0d: case 0x0e: case 0x0f: - case 0x10: case 0x11: case 0x12: case 0x13: - case 0x14: case 0x15: case 0x16: case 0x17: - case 0x18: case 0x19: case 0x1a: case 0x1b: - case 0x1c: case 0x1d: case 0x1e: case 0x1f: + case 0x00 ... 0x1f: kbd_log("ATkbc: AMI - alias read from %08X\n", val); - add_data(dev, dev->mem[val]); + kbc_transmit(dev, dev->mem[val + 0x20]); return 0; - case 0x40: case 0x41: case 0x42: case 0x43: - case 0x44: case 0x45: case 0x46: case 0x47: - case 0x48: case 0x49: case 0x4a: case 0x4b: - case 0x4c: case 0x4d: case 0x4e: case 0x4f: - case 0x50: case 0x51: case 0x52: case 0x53: - case 0x54: case 0x55: case 0x56: case 0x57: - case 0x58: case 0x59: case 0x5a: case 0x5b: - case 0x5c: case 0x5d: case 0x5e: case 0x5f: - kbd_log("ATkbc: AMI - alias write to %08X\n", dev->command); - dev->want60 = 1; + case 0x40 ... 0x5f: + kbd_log("ATkbc: AMI - alias write to %08X\n", dev->kbc_cmd); + dev->kbc_in = 1; return 0; case 0xa0: /* copyright message */ - add_data(dev, 0x28); - add_data(dev, 0x00); - break; + kbc_transmit(dev, ami_copr[0]); + dev->kbc_phase = 1; + return 0; case 0xa1: /* get controller version */ kbd_log("ATkbc: AMI - get controller version\n"); - add_data(dev, 'H'); + // kbc_transmit(dev, 'H'); + kbc_transmit(dev, '5'); return 0; case 0xa2: /* clear keyboard controller lines P22/P23 */ - if ((dev->flags & KBC_TYPE_MASK) < KBC_TYPE_PS2_NOREF) { + if (!(dev->flags & KBC_FLAG_PS2)) { kbd_log("ATkbc: AMI - clear KBC lines P22 and P23\n"); - write_output(dev, dev->output_port & 0xf3); - add_data(dev, 0x00); + write_output(dev, dev->p2 & 0xf3); + kbc_transmit(dev, 0x00); return 0; } break; case 0xa3: /* set keyboard controller lines P22/P23 */ - if ((dev->flags & KBC_TYPE_MASK) < KBC_TYPE_PS2_NOREF) { + if (!(dev->flags & KBC_FLAG_PS2)) { kbd_log("ATkbc: AMI - set KBC lines P22 and P23\n"); - write_output(dev, dev->output_port | 0x0c); - add_data(dev, 0x00); + write_output(dev, dev->p2 | 0x0c); + kbc_transmit(dev, 0x00); return 0; } break; case 0xa4: /* write clock = low */ - if ((dev->flags & KBC_TYPE_MASK) < KBC_TYPE_PS2_NOREF) { + if (!(dev->flags & KBC_FLAG_PS2)) { kbd_log("ATkbc: AMI - write clock = low\n"); dev->ami_stat &= 0xfe; return 0; @@ -1391,7 +2345,7 @@ write64_ami(void *priv, uint8_t val) break; case 0xa5: /* write clock = high */ - if ((dev->flags & KBC_TYPE_MASK) < KBC_TYPE_PS2_NOREF) { + if (!(dev->flags & KBC_FLAG_PS2)) { kbd_log("ATkbc: AMI - write clock = high\n"); dev->ami_stat |= 0x01; return 0; @@ -1399,15 +2353,15 @@ write64_ami(void *priv, uint8_t val) break; case 0xa6: /* read clock */ - if ((dev->flags & KBC_TYPE_MASK) < KBC_TYPE_PS2_NOREF) { + if (!(dev->flags & KBC_FLAG_PS2)) { kbd_log("ATkbc: AMI - read clock\n"); - add_data(dev, !!(dev->ami_stat & 1)); + kbc_transmit(dev, !!(dev->ami_stat & 1)); return 0; } break; case 0xa7: /* write cache bad */ - if ((dev->flags & KBC_TYPE_MASK) < KBC_TYPE_PS2_NOREF) { + if (!(dev->flags & KBC_FLAG_PS2)) { kbd_log("ATkbc: AMI - write cache bad\n"); dev->ami_stat &= 0xfd; return 0; @@ -1415,7 +2369,7 @@ write64_ami(void *priv, uint8_t val) break; case 0xa8: /* write cache good */ - if ((dev->flags & KBC_TYPE_MASK) < KBC_TYPE_PS2_NOREF) { + if (!(dev->flags & KBC_FLAG_PS2)) { kbd_log("ATkbc: AMI - write cache good\n"); dev->ami_stat |= 0x02; return 0; @@ -1423,68 +2377,237 @@ write64_ami(void *priv, uint8_t val) break; case 0xa9: /* read cache */ - if ((dev->flags & KBC_TYPE_MASK) < KBC_TYPE_PS2_NOREF) { + if (!(dev->flags & KBC_FLAG_PS2)) { kbd_log("ATkbc: AMI - read cache\n"); - add_data(dev, !!(dev->ami_stat & 2)); + kbc_transmit(dev, !!(dev->ami_stat & 2)); return 0; } break; case 0xaf: /* set extended controller RAM */ kbd_log("ATkbc: set extended controller RAM\n"); - dev->want60 = 1; - dev->secr_phase = 1; + dev->kbc_in = 1; return 0; - case 0xb0: case 0xb1: case 0xb2: case 0xb3: + case 0xb0 ... 0xb3: /* set KBC lines P10-P13 (input port bits 0-3) low */ kbd_log("ATkbc: set KBC lines P10-P13 (input port bits 0-3) low\n"); - if (!PCI || (val > 0xb1)) - dev->input_port &= ~(1 << (val & 0x03)); - add_data(dev, 0x00); + if (!(dev->flags & KBC_FLAG_PS2) || (val > 0xb1)) { + dev->p1 &= ~(1 << (val & 0x03)); + } + kbc_transmit(dev, 0x00); return 0; case 0xb4: case 0xb5: /* set KBC lines P22-P23 (output port bits 2-3) low */ kbd_log("ATkbc: set KBC lines P22-P23 (output port bits 2-3) low\n"); - if (! PCI) - write_output(dev, dev->output_port & ~(4 << (val & 0x01))); - add_data(dev, 0x00); + if (!(dev->flags & KBC_FLAG_PS2)) + write_output(dev, dev->p2 & ~(4 << (val & 0x01))); + kbc_transmit(dev, 0x00); return 0; - case 0xb8: case 0xb9: case 0xba: case 0xbb: +#if 0 + case 0xb8 ... 0xbb: +#else + case 0xb9: +#endif /* set KBC lines P10-P13 (input port bits 0-3) high */ kbd_log("ATkbc: set KBC lines P10-P13 (input port bits 0-3) high\n"); - if (!PCI || (val > 0xb9)) { - dev->input_port |= (1 << (val & 0x03)); - add_data(dev, 0x00); + if (!(dev->flags & KBC_FLAG_PS2) || (val > 0xb9)) { + dev->p1 |= (1 << (val & 0x03)); + kbc_transmit(dev, 0x00); } return 0; + case 0xb8: + kbd_log("ATkbc: AMI MegaKey - memory index\n"); + dev->kbc_in = 1; + return 0; + + case 0xba: + kbd_log("ATkbc: AMI MegaKey - read %02X memory from index %02X\n", dev->mem[dev->mem_index], dev->mem_index); + if (dev->mem_index >= 0x80) { + switch (dev->mem[0x9b] & 0xc0) { + case 0x00: + index = 0x0080; + break; + case 0x40: case 0x80: + index = 0x0000; + break; + case 0xc0: + index = 0x0100; + break; + } + kbc_transmit(dev, dev->mem[index + dev->mem_index]); + } else if (dev->mem_index == 0x42) + kbc_transmit(dev, dev->status); + else if (dev->mem_index >= 0x40) + kbc_transmit(dev, dev->mem[dev->mem_index - 0x40]); + else + kbc_transmit(dev, dev->mem_int[dev->mem_index]); + return 0; + + case 0xbb: + kbd_log("ATkbc: AMI MegaKey - write to memory index %02X\n", dev->mem_index); + dev->kbc_in = 1; + return 0; + +#if 0 case 0xbc: case 0xbd: /* set KBC lines P22-P23 (output port bits 2-3) high */ kbd_log("ATkbc: set KBC lines P22-P23 (output port bits 2-3) high\n"); - if (! PCI) - write_output(dev, dev->output_port | (4 << (val & 0x01))); - add_data(dev, 0x00); + if (!(dev->flags & KBC_FLAG_PS2)) + write_output(dev, dev->p2 | (4 << (val & 0x01))); + kbc_transmit(dev, 0x00); + return 0; +#endif + + case 0xbc: + switch (dev->mem_index) { + case 0x00: /* STAT8042 */ + kbc_transmit(dev, dev->status); + break; + case 0x01: /* Password_ptr */ + kbc_transmit(dev, dev->mem[0x1c]); + break; + case 0x02: /* Wakeup_Tsk_Reg */ + kbc_transmit(dev, dev->mem[0x1e]); + break; + case 0x03: /* CCB */ + kbc_transmit(dev, dev->mem[0x20]); + break; + case 0x04: /* Debounce_time */ + kbc_transmit(dev, dev->mem[0x4d]); + break; + case 0x05: /* Pulse_Width */ + kbc_transmit(dev, dev->mem[0x4e]); + break; + case 0x06: /* Pk_sel_byte */ + kbc_transmit(dev, dev->mem[0x4c]); + break; + case 0x07: /* Func_Tsk_Reg */ + kbc_transmit(dev, dev->mem[0x7e]); + break; + case 0x08: /* TypematicRate */ + kbc_transmit(dev, dev->mem[0x80]); + break; + case 0x09: /* Led_Flag_Byte */ + kbc_transmit(dev, dev->mem[0x81]); + break; + case 0x0a: /* Kbms_Command_St */ + kbc_transmit(dev, dev->mem[0x87]); + break; + case 0x0b: /* Delay_Count_Byte */ + kbc_transmit(dev, dev->mem[0x86]); + break; + case 0x0c: /* KBC_Flags */ + kbc_transmit(dev, dev->mem[0x9b]); + break; + case 0x0d: /* SCODE_HK1 */ + kbc_transmit(dev, dev->mem[0x50]); + break; + case 0x0e: /* SCODE_HK2 */ + kbc_transmit(dev, dev->mem[0x51]); + break; + case 0x0f: /* SCODE_HK3 */ + kbc_transmit(dev, dev->mem[0x52]); + break; + case 0x10: /* SCODE_HK4 */ + kbc_transmit(dev, dev->mem[0x53]); + break; + case 0x11: /* SCODE_HK5 */ + kbc_transmit(dev, dev->mem[0x54]); + break; + case 0x12: /* SCODE_HK6 */ + kbc_transmit(dev, dev->mem[0x55]); + break; + case 0x13: /* TASK_HK1 */ + kbc_transmit(dev, dev->mem[0x56]); + break; + case 0x14: /* TASK_HK2 */ + kbc_transmit(dev, dev->mem[0x57]); + break; + case 0x15: /* TASK_HK3 */ + kbc_transmit(dev, dev->mem[0x58]); + break; + case 0x16: /* TASK_HK4 */ + kbc_transmit(dev, dev->mem[0x59]); + break; + case 0x17: /* TASK_HK5 */ + kbc_transmit(dev, dev->mem[0x5a]); + break; + /* The next 4 bytes have uncertain correspondences. */ + case 0x18: /* Batt_Poll_delay_Time */ + kbc_transmit(dev, dev->mem[0x5b]); + break; + case 0x19: /* Batt_Alarm_Reg1 */ + kbc_transmit(dev, dev->mem[0x5c]); + break; + case 0x1a: /* Batt_Alarm_Reg2 */ + kbc_transmit(dev, dev->mem[0x5d]); + break; + case 0x1b: /* Batt_Alarm_Tsk_Reg */ + kbc_transmit(dev, dev->mem[0x5e]); + break; + case 0x1c: /* Kbc_State1 */ + kbc_transmit(dev, dev->mem[0x9d]); + break; + case 0x1d: /* Aux_Config */ + kbc_transmit(dev, dev->mem[0x75]); + break; + case 0x1e: /* Kbc_State3 */ + kbc_transmit(dev, dev->mem[0x73]); + break; + default: + kbc_transmit(dev, 0x00); + break; + } + kbd_log("ATkbc: AMI MegaKey - read from config index %02X\n", dev->mem_index); return 0; - case 0xc8: + case 0xbd: + kbd_log("ATkbc: AMI MegaKey - write to config index %02X\n", dev->mem_index); + dev->kbc_in = 1; + return 0; + + case 0xc1: /* write input port */ + kbd_log("ATkbc: AMI MegaKey - write input port\n"); + dev->kbc_in = 1; + return 0; + + case 0xc4: + /* set KBC line P14 low */ + kbd_log("ATkbc: set KBC line P14 (input port bit 4) low\n"); + dev->p1 &= 0xef; + kbc_transmit(dev, 0x00); + return 0; + case 0xc5: + /* set KBC line P15 low */ + kbd_log("ATkbc: set KBC line P15 (input port bit 5) low\n"); + dev->p1 &= 0xdf; + kbc_transmit(dev, 0x00); + return 0; + + case 0xc8: case 0xc9: /* - * unblock KBC lines P22/P23 + * (un)block KBC lines P22/P23 * (allow command D1 to change bits 2/3 of the output port) */ - kbd_log("ATkbc: AMI - unblock KBC lines P22 and P23\n"); - dev->output_locked = 1; + kbd_log("ATkbc: AMI - %sblock KBC lines P22 and P23\n", (val & 1) ? "" : "un"); + dev->p2_locked = (val & 1); return 0; - case 0xc9: - /* - * block KBC lines P22/P23 - * (disallow command D1 from changing bits 2/3 of the port) - */ - kbd_log("ATkbc: AMI - block KBC lines P22 and P23\n"); - dev->output_locked = 1; + case 0xcc: + /* set KBC line P14 high */ + kbd_log("ATkbc: set KBC line P14 (input port bit 4) high\n"); + dev->p1 |= 0x10; + kbc_transmit(dev, 0x00); + return 0; + case 0xcd: + /* set KBC line P15 high */ + kbd_log("ATkbc: set KBC line P15 (input port bit 5) high\n"); + dev->p1 |= 0x20; + kbc_transmit(dev, 0x00); return 0; case 0xef: /* ??? - sent by AMI486 */ @@ -1505,23 +2628,20 @@ write64_ibm_mca(void *priv, uint8_t val) case 0xc1: /*Copy bits 0 to 3 of input port to status bits 4 to 7*/ kbd_log("ATkbc: copy bits 0 to 3 of input port to status bits 4 to 7\n"); dev->status &= 0x0f; - dev->status |= ((((dev->input_port & 0xfc) | 0x84) & 0x0f) << 4); + dev->status |= ((((dev->p1 & 0xfc) | 0x84) & 0x0f) << 4); return 0; case 0xc2: /*Copy bits 4 to 7 of input port to status bits 4 to 7*/ kbd_log("ATkbc: copy bits 4 to 7 of input port to status bits 4 to 7\n"); dev->status &= 0x0f; - dev->status |= (((dev->input_port & 0xfc) | 0x84) & 0xf0); + dev->status |= (((dev->p1 & 0xfc) | 0x84) & 0xf0); return 0; case 0xaf: kbd_log("ATkbc: bad KBC command AF\n"); return 1; - case 0xf0: case 0xf1: case 0xf2: case 0xf3: - case 0xf4: case 0xf5: case 0xf6: case 0xf7: - case 0xf8: case 0xf9: case 0xfa: case 0xfb: - case 0xfc: case 0xfd: case 0xfe: case 0xff: + case 0xf0 ... 0xff: kbd_log("ATkbc: pulse: %01X\n", (val & 0x03) | 0x0c); pulse_output(dev, (val & 0x03) | 0x0c); return 0; @@ -1536,7 +2656,7 @@ write60_quadtel(void *priv, uint8_t val) { atkbd_t *dev = (atkbd_t *)priv; - switch(dev->command) { + switch(dev->kbc_cmd) { case 0xcf: /*??? - sent by MegaPC BIOS*/ kbd_log("ATkbc: ??? - sent by MegaPC BIOS\n"); return 0; @@ -1545,12 +2665,34 @@ write60_quadtel(void *priv, uint8_t val) return 1; } + static uint8_t write64_olivetti(void *priv, uint8_t val) { atkbd_t *dev = (atkbd_t *)priv; switch (val) { + /* This appears to be a clone of "Read input port", in which case, the bis would be: + 7: M290 (AT KBC): + Keyboard lock (1 = unlocked, 0 = locked); + M300 (PS/2 KBC): + Bus expansion board present (1 = present, 0 = not present); + 6: Usually: + Display (1 = MDA, 0 = CGA, but can have its polarity inverted); + 5: Manufacturing jumper (1 = not installed, 0 = installed (infinite loop)); + 4: RAM on motherboard (1 = 256 kB, 0 = 512 kB - which machine actually uses this?); + 3: Fast Ram check (if inactive keyboard works erratically); + 2: Keyboard fuse present + This appears to be in-line with PS/2: 1 = no power, 0 = keyboard power normal; + 1: M290 (AT KBC): + Unused; + M300 (PS/2 KBC): + Mouse data in; + 0: M290 (AT KBC): + Unused; + M300 (PS/2 KBC): + Key data in. + */ case 0x80: /* Olivetti-specific command */ /* * bit 7: bus expansion board present (M300) / keyboard unlocked (M290) @@ -1559,11 +2701,9 @@ write64_olivetti(void *priv, uint8_t val) * bit 2: keyboard fuse present * bits 0-1: ??? */ - add_to_kbc_queue_front(dev, (0x0c | ((is386) ? 0x00 : 0x80)) & 0xdf, 0, 0x00); - dev->input_port = ((dev->input_port + 1) & 3) | - (dev->input_port & 0xfc); + kbc_transmit(dev, 0x0c | (is386 ? 0x00 : 0x80)); return 0; - } + } return write64_generic(dev, val); } @@ -1581,7 +2721,7 @@ write64_quadtel(void *priv, uint8_t val) case 0xcf: /*??? - sent by MegaPC BIOS*/ kbd_log("ATkbc: ??? - sent by MegaPC BIOS\n"); - dev->want60 = 1; + dev->kbc_in = 1; return 0; } @@ -1594,7 +2734,7 @@ write60_toshiba(void *priv, uint8_t val) { atkbd_t *dev = (atkbd_t *)priv; - switch(dev->command) { + switch(dev->kbc_cmd) { case 0xb6: /* T3100e - set color/mono switch */ kbd_log("ATkbc: T3100e - set color/mono switch\n"); t3100e_mono_set(val); @@ -1637,29 +2777,30 @@ write64_toshiba(void *priv, uint8_t val) case 0xb4: /* T3100e: Get configuration / status */ kbd_log("ATkbc: T3100e: Get configuration / status\n"); - add_data(dev, t3100e_config_get()); + kbc_transmit(dev, t3100e_config_get()); return 0; case 0xb5: /* T3100e: Get colour / mono byte */ kbd_log("ATkbc: T3100e: Get colour / mono byte\n"); - add_data(dev, t3100e_mono_get()); + kbc_transmit(dev, t3100e_mono_get()); return 0; case 0xb6: /* T3100e: Set colour / mono byte */ kbd_log("ATkbc: T3100e: Set colour / mono byte\n"); - dev->want60 = 1; + dev->kbc_in = 1; return 0; case 0xb7: /* T3100e: Emulate PS/2 keyboard */ case 0xb8: /* T3100e: Emulate AT keyboard */ - dev->flags &= ~KBC_TYPE_MASK; + dev->flags &= ~KBC_FLAG_PS2; if (val == 0xb7) { kbd_log("ATkbc: T3100e: Emulate PS/2 keyboard\n"); - dev->flags |= KBC_TYPE_PS2_NOREF; - } else { - kbd_log("ATkbc: T3100e: Emulate AT keyboard\n"); - dev->flags |= KBC_TYPE_ISA; + dev->flags |= KBC_FLAG_PS2; } +#ifdef ENABLE_KEYBOARD_AT_LOG + else + kbd_log("ATkbc: T3100e: Emulate AT keyboard\n"); +#endif return 0; case 0xbb: /* T3100e: Read 'Fn' key. @@ -1669,8 +2810,9 @@ write64_toshiba(void *priv, uint8_t val) kbd_log("ATkbc: T3100e: Read 'Fn' key\n"); if (keyboard_recv(0xb8) || /* Right Alt */ keyboard_recv(0x9d)) /* Right Ctrl */ - add_data(dev, 0x04); - else add_data(dev, 0x00); + kbc_transmit(dev, 0x04); + else + kbc_transmit(dev, 0x00); return 0; case 0xbc: /* T3100e: Reset Fn+Key notification */ @@ -1683,8 +2825,8 @@ write64_toshiba(void *priv, uint8_t val) /* The T3100e returns all bits set except bit 6 which * is set by t3100e_mono_set() */ - dev->input_port = (t3100e_mono_get() & 1) ? 0xff : 0xbf; - add_data(dev, dev->input_port); + dev->p1 = (t3100e_mono_get() & 1) ? 0xff : 0xbf; + kbc_transmit(dev, dev->p1); return 0; } @@ -1697,423 +2839,46 @@ static void kbd_write(uint16_t port, uint8_t val, void *priv) { atkbd_t *dev = (atkbd_t *)priv; - int i = 0, bad = 1; - uint8_t mask, kbc_ven = 0x0; - kbc_ven = dev->flags & KBC_VEN_MASK; - if ((kbc_ven == KBC_VEN_XI8088) && (port == 0x63)) - port = 0x61; - - kbd_log((port == 0x61) ? "" : "ATkbc: write(%04X, %02X)\n", port, val); + kbd_log("[%04X:%08X] ATkbc: write(%04X, %02X)\n", CS, cpu_state.pc, port, val); switch (port) { case 0x60: - dev->status &= ~STAT_CD; - if (dev->want60) { - /* Write data to controller. */ - dev->want60 = 0; + dev->status = (dev->status & ~STAT_CD) | STAT_IFULL; + dev->ib = val; + // kbd_status("Write %02X: %02X, Status = %02X\n", port, val, dev->status); - switch (dev->command) { - case 0x60: case 0x61: case 0x62: case 0x63: - case 0x64: case 0x65: case 0x66: case 0x67: - case 0x68: case 0x69: case 0x6a: case 0x6b: - case 0x6c: case 0x6d: case 0x6e: case 0x6f: - case 0x70: case 0x71: case 0x72: case 0x73: - case 0x74: case 0x75: case 0x76: case 0x77: - case 0x78: case 0x79: case 0x7a: case 0x7b: - case 0x7c: case 0x7d: case 0x7e: case 0x7f: - dev->mem[dev->command & 0x1f] = val; - if (dev->command == 0x60) - write_cmd(dev, val); - break; - - case 0xd1: /* write output port */ - kbd_log("ATkbc: write output port\n"); - if (dev->output_locked) { - /*If keyboard controller lines P22-P23 are blocked, - we force them to remain unchanged.*/ - val &= ~0x0c; - val |= (dev->output_port & 0x0c); - } - write_output(dev, val); - break; - - case 0xd2: /* write to keyboard output buffer */ - kbd_log("ATkbc: write to keyboard output buffer\n"); - add_data_kbd_direct(dev, val); - break; - - case 0xd3: /* write to mouse output buffer */ - kbd_log("ATkbc: write to mouse output buffer\n"); - if (mouse_write && ((dev->flags & KBC_TYPE_MASK) >= KBC_TYPE_PS2_NOREF)) - keyboard_at_adddata_mouse(val); - break; - - case 0xd4: /* write to mouse */ - kbd_log("ATkbc: write to mouse (%02X)\n", val); - - if (val == 0xbb) - break; - - if ((dev->flags & KBC_TYPE_MASK) >= KBC_TYPE_PS2_NOREF) { - set_enable_mouse(dev, 1); - if (mouse_write) - mouse_write(val, mouse_p); - else - add_to_kbc_queue_front(dev, 0xfe, 2, 0x40); - } - break; - - default: - /* - * Run the vendor-specific handler - * if we have one. Otherwise, or if - * it returns an error, log a bad - * controller command. - */ - if (dev->write60_ven) - bad = dev->write60_ven(dev, val); - - if (bad) { - kbd_log("ATkbc: bad controller command %02x data %02x\n", dev->command, val); - add_data_kbd(0xfe); - } - } - } else { - /* Write data to keyboard. */ - dev->mem[0] &= ~0x10; - - if (dev->key_wantdata) { - dev->key_wantdata = 0; - - /* - * Several system BIOSes and OS device drivers - * mess up with this, and repeat the command - * code many times. Fun! - */ - if (val == dev->key_command) { - /* Respond NAK and ignore it. */ - add_data_kbd(0xfe); - dev->key_command = 0x00; - break; - } - - switch (dev->key_command) { - case 0xed: /* set/reset LEDs */ - add_data_kbd_direct(dev, 0xfa); - kbd_log("ATkbd: set LEDs [%02x]\n", val); - break; - - case 0xf0: /* get/set scancode set */ - add_data_kbd_direct(dev, 0xfa); - if (val == 0) { - kbd_log("Get scan code set: %02X\n", keyboard_mode & 3); - add_data_kbd_direct(dev, keyboard_mode & 3); - } else { - if ((val <= 3) && (val != 1)) { - keyboard_mode &= 0xfc; - keyboard_mode |= (val & 3); - kbd_log("Scan code set now: %02X\n", val); - } - set_scancode_map(dev); - } - break; - - case 0xf3: /* set typematic rate/delay */ - add_data_kbd_direct(dev, 0xfa); - break; - - default: - kbd_log("ATkbd: bad keyboard 0060 write %02X command %02X\n", val, dev->key_command); - add_data_kbd_direct(dev, 0xfe); - break; - } - - /* Keyboard command is now done. */ - dev->key_command = 0x00; - } else { - /* No keyboard command in progress. */ - dev->key_command = 0x00; - - set_enable_kbd(dev, 1); - - switch (val) { - case 0x00: - kbd_log("ATkbd: command 00\n"); - add_data_kbd_direct(dev, 0xfa); - break; - - case 0x05: /*??? - sent by NT 4.0*/ - kbd_log("ATkbd: command 05 (NT 4.0)\n"); - add_data_kbd_direct(dev, 0xfe); - break; - - /* Sent by Pentium-era AMI BIOS'es.*/ - case 0x71: case 0x82: - kbd_log("ATkbd: Pentium-era AMI BIOS command %02X\n", val); - break; - - case 0xed: /* set/reset LEDs */ - kbd_log("ATkbd: set/reset leds\n"); - add_data_kbd_direct(dev, 0xfa); - - dev->key_wantdata = 1; - break; - - case 0xee: /* diagnostic echo */ - kbd_log("ATkbd: ECHO\n"); - add_data_kbd_direct(dev, 0xee); - break; - - case 0xef: /* NOP (reserved for future use) */ - kbd_log("ATkbd: NOP\n"); - break; - - case 0xf0: /* get/set scan code set */ - kbd_log("ATkbd: scan code set\n"); - add_data_kbd_direct(dev, 0xfa); - dev->key_wantdata = 1; - break; - - case 0xf2: /* read ID */ - /* Fixed as translation will be done in add_data_kbd(). */ - kbd_log("ATkbd: read keyboard id\n"); - /* TODO: After keyboard type selection is implemented, make this - return the correct keyboard ID for the selected type. */ - add_data_kbd_direct(dev, 0xfa); - add_data_kbd_direct(dev, 0xab); - add_data_kbd_direct(dev, 0x83); - break; - - case 0xf3: /* set typematic rate/delay */ - kbd_log("ATkbd: set typematic rate/delay\n"); - add_data_kbd_direct(dev, 0xfa); - dev->key_wantdata = 1; - break; - - case 0xf4: /* enable keyboard */ - kbd_log("ATkbd: enable keyboard\n"); - add_data_kbd_direct(dev, 0xfa); - keyboard_scan = 1; - break; - - case 0xf5: /* set defaults and disable keyboard */ - case 0xf6: /* set defaults */ - kbd_log("ATkbd: set defaults%s\n", (val == 0xf6) ? "" : " and disable keyboard"); - keyboard_scan = (val == 0xf6); - kbd_log("val = %02X, keyboard_scan = %i, dev->mem[0] = %02X\n", - val, keyboard_scan, dev->mem[0]); - add_data_kbd_direct(dev, 0xfa); - - keyboard_set3_all_break = 0; - keyboard_set3_all_repeat = 0; - memset(keyboard_set3_flags, 0, 512); - keyboard_mode = (keyboard_mode & 0xfc) | 0x02; - set_scancode_map(dev); - break; - - case 0xf7: /* set all keys to repeat */ - kbd_log("ATkbd: set all keys to repeat\n"); - add_data_kbd_direct(dev, 0xfa); - keyboard_set3_all_break = 1; - break; - - case 0xf8: /* set all keys to give make/break codes */ - kbd_log("ATkbd: set all keys to give make/break codes\n"); - add_data_kbd_direct(dev, 0xfa); - keyboard_set3_all_break = 1; - break; - - case 0xf9: /* set all keys to give make codes only */ - kbd_log("ATkbd: set all keys to give make codes only\n"); - add_data_kbd_direct(dev, 0xfa); - keyboard_set3_all_break = 0; - break; - - case 0xfa: /* set all keys to repeat and give make/break codes */ - kbd_log("ATkbd: set all keys to repeat and give make/break codes\n"); - add_data_kbd_direct(dev, 0xfa); - keyboard_set3_all_repeat = 1; - keyboard_set3_all_break = 1; - break; - - case 0xfe: /* resend last scan code */ - kbd_log("ATkbd: reset last scan code\n"); - add_data_kbd_raw(dev, kbd_last_scan_code); - break; - - case 0xff: /* reset */ - kbd_log("ATkbd: kbd reset\n"); - kbc_queue_reset(1); - kbd_last_scan_code = 0x00; - add_data_kbd_direct(dev, 0xfa); - - /* Set scan code set to 2. */ - keyboard_mode = (keyboard_mode & 0xfc) | 0x02; - set_scancode_map(dev); - - dev->reset_delay = RESET_DELAY_TIME; - break; - - default: - kbd_log("ATkbd: bad keyboard command %02X\n", val); - add_data_kbd_direct(dev, 0xfe); - } - - /* If command needs data, remember command. */ - if (dev->key_wantdata == 1) - dev->key_command = val; - } +#if 0 + if ((dev->fast_a20_phase == 1)/* && ((val == 0xdd) || (val == 0xdf))*/) { + dev->status &= ~STAT_IFULL; + write_output(dev, val); + dev->fast_a20_phase = 0; } +#endif break; - - case 0x61: - ppi.pb = (ppi.pb & 0x10) | (val & 0x0f); - - speaker_update(); - speaker_gated = val & 1; - speaker_enable = val & 2; - if (speaker_enable) - was_speaker_enable = 1; - pit_ctr_set_gate(&pit->counters[2], val & 1); - - if (kbc_ven == KBC_VEN_XI8088) - xi8088_turbo_set(!!(val & 0x04)); - break; - case 0x64: - /* Controller command. */ - dev->want60 = 0; - dev->status |= STAT_CD; + dev->status |= (STAT_CD | STAT_IFULL); + dev->ib = val; + // kbd_status("Write %02X: %02X, Status = %02X\n", port, val, dev->status); - switch (val) { - /* Read data from KBC memory. */ - case 0x20: case 0x21: case 0x22: case 0x23: - case 0x24: case 0x25: case 0x26: case 0x27: - case 0x28: case 0x29: case 0x2a: case 0x2b: - case 0x2c: case 0x2d: case 0x2e: case 0x2f: - case 0x30: case 0x31: case 0x32: case 0x33: - case 0x34: case 0x35: case 0x36: case 0x37: - case 0x38: case 0x39: case 0x3a: case 0x3b: - case 0x3c: case 0x3d: case 0x3e: case 0x3f: - add_data(dev, dev->mem[val & 0x1f]); - break; - - /* Write data to KBC memory. */ - case 0x60: case 0x61: case 0x62: case 0x63: - case 0x64: case 0x65: case 0x66: case 0x67: - case 0x68: case 0x69: case 0x6a: case 0x6b: - case 0x6c: case 0x6d: case 0x6e: case 0x6f: - case 0x70: case 0x71: case 0x72: case 0x73: - case 0x74: case 0x75: case 0x76: case 0x77: - case 0x78: case 0x79: case 0x7a: case 0x7b: - case 0x7c: case 0x7d: case 0x7e: case 0x7f: - dev->want60 = 1; - break; - - case 0xaa: /* self-test */ - kbd_log("ATkbc: self-test\n"); - if ((kbc_ven == KBC_VEN_TOSHIBA) || (kbc_ven == KBC_VEN_SAMSUNG)) - dev->status |= STAT_IFULL; - write_output(dev, ((dev->flags & KBC_TYPE_MASK) >= KBC_TYPE_PS2_NOREF) ? 0x4b : 0xcf); - - /* Always reinitialize all queues - the real hardware pulls keyboard and mouse - clocks high, which stops keyboard scanning. */ - kbd_log("ATkbc: self-test reinitialization\n"); - dev->out_new = dev->out_delayed = -1; - for (i = 0; i < 3; i++) - kbc_queue_reset(i); - kbd_last_scan_code = 0x00; - dev->status &= ~STAT_OFULL; - dev->last_irq = dev->old_last_irq = 0; - - if ((dev->flags & KBC_TYPE_MASK) >= KBC_TYPE_PS2_NOREF) - write_cmd(dev, 0x30 | STAT_SYSFLAG); - else - write_cmd(dev, 0x10 | STAT_SYSFLAG); - add_data(dev, 0x55); - break; - - case 0xab: /* interface test */ - kbd_log("ATkbc: interface test\n"); - add_data(dev, 0x00); /*no error*/ - break; - - case 0xac: /* diagnostic dump */ - kbd_log("ATkbc: diagnostic dump\n"); - for (i = 0; i < 16; i++) - add_data(dev, dev->mem[i]); - add_data(dev, (dev->input_port & 0xf0) | 0x80); - add_data(dev, dev->output_port); - add_data(dev, dev->status); - break; - - case 0xad: /* disable keyboard */ - kbd_log("ATkbc: disable keyboard\n"); - set_enable_kbd(dev, 0); - break; - - case 0xae: /* enable keyboard */ - kbd_log("ATkbc: enable keyboard\n"); - set_enable_kbd(dev, 1); - break; - - case 0xca: /* read keyboard mode */ - kbd_log("ATkbc: AMI - read keyboard mode\n"); - add_data(dev, ((dev->flags & KBC_TYPE_MASK) >= KBC_TYPE_PS2_NOREF) ? 0x01 : 0x00); /*ISA mode*/ - break; - - case 0xcb: /* set keyboard mode */ - kbd_log("ATkbc: AMI - set keyboard mode\n"); - dev->want60 = 1; - break; - - case 0xd0: /* read output port */ - kbd_log("ATkbc: read output port\n"); - mask = 0xff; - if (((dev->flags & KBC_TYPE_MASK) < KBC_TYPE_PS2_NOREF) && (dev->mem[0] & 0x10)) - mask &= 0xbf; - add_to_kbc_queue_front(dev, dev->output_port & mask, 0, 0x00); - break; - - case 0xd1: /* write output port */ - kbd_log("ATkbc: write output port\n"); - dev->want60 = 1; - break; - - case 0xd2: /* write keyboard output buffer */ - kbd_log("ATkbc: write keyboard output buffer\n"); - dev->want60 = 1; - break; - - case 0xdd: /* disable A20 address line */ - case 0xdf: /* enable A20 address line */ - kbd_log("ATkbc: %sable A20\n", (val == 0xdd) ? "dis": "en"); - write_output(dev, (dev->output_port & 0xfd) | (val & 0x02)); - break; - - case 0xe0: /* read test inputs */ - kbd_log("ATkbc: read test inputs\n"); - add_data(dev, 0x00); - break; - - default: - /* - * Unrecognized controller command. - * - * If we have a vendor-specific handler, run - * that. Otherwise, or if that handler fails, - * log a bad command. - */ - if (dev->write64_ven) - bad = dev->write64_ven(dev, val); - - kbd_log(bad ? "ATkbc: bad controller command %02X\n" : "", val); +#if 0 + if (val == 0xd1) { + dev->status &= ~STAT_IFULL; + dev->fast_a20_phase = 1; + } else if (val == 0xfe) { + dev->status &= ~STAT_IFULL; + pulse_output(dev, 0x0e); + } else if ((val == 0xad) || (val == 0xae)) { + dev->status &= ~STAT_IFULL; + if (val & 0x01) + dev->mem[0x20] |= 0x10; + else + dev->mem[0x20] &= ~0x10; + } else if (val == 0xa1) { + dev->status &= ~STAT_IFULL; + kbc_send_to_ob(dev, 'H', 0, 0x00); } - - /* If the command needs data, remember the command. */ - if (dev->want60) - dev->command = val; +#endif break; } } @@ -2124,83 +2889,20 @@ kbd_read(uint16_t port, void *priv) { atkbd_t *dev = (atkbd_t *)priv; uint8_t ret = 0xff; - uint8_t kbc_ven = 0x0; - kbc_ven = dev->flags & KBC_VEN_MASK; - if ((dev->flags & KBC_TYPE_MASK) >= KBC_TYPE_PS2_NOREF) - cycles -= ISA_CYCLES(8); - - if ((kbc_ven == KBC_VEN_XI8088) && (port == 0x63)) - port = 0x61; + // if (dev->flags & KBC_FLAG_PS2) + // cycles -= ISA_CYCLES(8); switch (port) { case 0x60: - ret = dev->out; + ret = dev->ob; dev->status &= ~STAT_OFULL; picintc(dev->last_irq); dev->last_irq = 0; break; - case 0x61: - ret = ppi.pb & ~0xe0; - if (ppispeakon) - ret |= 0x20; - if ((dev->flags & KBC_TYPE_MASK) > KBC_TYPE_PS2_NOREF) { - if (dev->refresh) - ret |= 0x10; - else - ret &= ~0x10; - } - if (kbc_ven == KBC_VEN_XI8088) { - if (xi8088_turbo_get()) - ret |= 0x04; - else - ret &= ~0x04; - } - break; - - case 0x62: - ret = 0xff; - if (kbc_ven == KBC_VEN_OLIVETTI) { - /* SWA on Olivetti M240 mainboard (off=1) */ - ret = 0x00; - if (ppi.pb & 0x8) { - /* Switches 4, 5 - floppy drives (number) */ - int i, fdd_count = 0; - for (i = 0; i < FDD_NUM; i++) { - if (fdd_get_flags(i)) - fdd_count++; - } - if (!fdd_count) - ret |= 0x00; - else - ret |= ((fdd_count - 1) << 2); - /* Switches 6, 7 - monitor type */ - if (video_is_mda()) - ret |= 0x3; - else if (video_is_cga()) - ret |= 0x2; /* 0x10 would be 40x25 */ - else - ret |= 0x0; - } else { - /* bit 2 always on */ - ret |= 0x4; - /* Switch 8 - 8087 FPU. */ - if (hasfpu) - ret |= 0x02; - } - } - break; case 0x64: - ret = (dev->status & 0xfb); - if (dev->mem[0] & STAT_SYSFLAG) - ret |= STAT_SYSFLAG; - /* Only clear the transmit timeout flag on non-PS/2 controllers, as on - PS/2 controller, it is the keyboard/mouse output source bit. */ - // dev->status &= ~STAT_RTIMEOUT; - if (((dev->flags & KBC_TYPE_MASK) > KBC_TYPE_PS2_NOREF) && - (kbc_ven != KBC_VEN_IBM_MCA)) - dev->status &= ~STAT_TTIMEOUT; + ret = dev->status; break; default: @@ -2208,22 +2910,12 @@ kbd_read(uint16_t port, void *priv) break; } - kbd_log((port == 0x61) ? "" : "ATkbc: read(%04X) = %02X\n", port, ret); + kbd_log("[%04X:%08X] ATkbc: read(%04X) = %02X\n",CS, cpu_state.pc, port, ret); return(ret); } -static void -kbd_refresh(void *priv) -{ - atkbd_t *dev = (atkbd_t *)priv; - - dev->refresh = !dev->refresh; - timer_advance_u64(&dev->refresh_time, PS2_REFRESH_TIME); -} - - static void kbd_reset(void *priv) { @@ -2232,25 +2924,26 @@ kbd_reset(void *priv) uint8_t kbc_ven = 0x0; kbc_ven = dev->flags & KBC_VEN_MASK; - dev->first_write = 1; - // dev->status = STAT_UNLOCKED | STAT_CD; dev->status = STAT_UNLOCKED; - dev->mem[0] = 0x01; - dev->mem[0] |= CCB_TRANSLATE; - dev->wantirq = 0; + dev->mem[0x20] = 0x01; + dev->mem[0x20] |= CCB_TRANSLATE; write_output(dev, 0xcf); - dev->last_irq = dev->old_last_irq = 0; + dev->last_irq = 0; dev->secr_phase = 0; - dev->key_wantdata = 0; + dev->kbd_in = 0; + dev->ami_mode = !!(dev->flags & KBC_FLAG_PS2); /* Set up the correct Video Type bits. */ + dev->p1 = video_is_mda() ? 0xf0 : 0xb0; if ((kbc_ven == KBC_VEN_XI8088) || (kbc_ven == KBC_VEN_ACER)) - dev->input_port = video_is_mda() ? 0xb0 : 0xf0; + dev->p1 ^= 0x40; + if ((kbc_ven == KBC_VEN_AMI) || (dev->flags & KBC_FLAG_PS2)) + dev->inhibit = ((dev->p1 & 0x80) >> 3); else - dev->input_port = video_is_mda() ? 0xf0 : 0xb0; - kbd_log("ATkbc: input port = %02x\n", dev->input_port); + dev->inhibit = 0x10; + kbd_log("ATkbc: input port = %02x\n", dev->p1); - keyboard_mode = 0x02 | (dev->mem[0] & CCB_TRANSLATE); + keyboard_mode = 0x02 | (dev->mem[0x20] & CCB_TRANSLATE); /* Enable keyboard, disable mouse. */ set_enable_kbd(dev, 1); @@ -2258,16 +2951,18 @@ kbd_reset(void *priv) set_enable_mouse(dev, 0); mouse_scan = 0; - dev->out_new = dev->out_delayed = -1; - for (i = 0; i < 3; i++) - kbc_queue_reset(i); - kbd_last_scan_code = 0; + dev->ob = 0xff; sc_or = 0; + for (i = 1; i <= 2; i++) + kbc_queue_reset(i); + memset(keyboard_set3_flags, 0, 512); set_scancode_map(dev); + + dev->mem[0x31] = 0xfe; } @@ -2289,7 +2984,6 @@ kbd_close(void *priv) /* Stop timers. */ timer_disable(&dev->send_delay_timer); - timer_disable(&dev->refresh_time); keyboard_scan = 0; keyboard_send = NULL; @@ -2313,17 +3007,14 @@ kbd_init(const device_t *info) dev->flags = info->local; video_reset(gfxcard); - kbd_reset(dev); + dev->kbc_poll_phase = KBC_RESET; + kbd_send_to_host(dev, 0xaa); - io_sethandler(0x0060, 5, - kbd_read, NULL, NULL, kbd_write, NULL, NULL, dev); + io_sethandler(0x0060, 1, kbd_read, NULL, NULL, kbd_write, NULL, NULL, dev); + io_sethandler(0x0064, 1, kbd_read, NULL, NULL, kbd_write, NULL, NULL, dev); keyboard_send = add_data_kbd; timer_add(&dev->send_delay_timer, kbd_poll, dev, 1); - - if ((dev->flags & KBC_TYPE_MASK) > KBC_TYPE_PS2_NOREF) - timer_add(&dev->refresh_time, kbd_refresh, dev, 1); - timer_add(&dev->pulse_cb, pulse_poll, dev, 0); dev->write60_ven = NULL; @@ -2339,12 +3030,14 @@ kbd_init(const device_t *info) break; case KBC_VEN_OLIVETTI: + /* The Olivetti controller is a special case - starts directly in the + main loop instead of the reset loop. */ + dev->kbc_poll_phase = KBC_MAIN_LOOP; dev->write64_ven = write64_olivetti; break; case KBC_VEN_AMI: case KBC_VEN_INTEL_AMI: - case KBC_VEN_SAMSUNG: dev->write60_ven = write60_ami; dev->write64_ven = write64_ami; break; @@ -2364,6 +3057,8 @@ kbd_init(const device_t *info) break; } + kbd_reset(dev); + /* We need this, sadly. */ SavedKbd = dev; @@ -2391,16 +3086,6 @@ const device_t keyboard_at_ami_device = { { NULL }, NULL, NULL, NULL }; -const device_t keyboard_at_samsung_device = { - "PC/AT Keyboard (Samsung)", - 0, - KBC_TYPE_ISA | KBC_VEN_SAMSUNG, - kbd_init, - kbd_close, - kbd_reset, - { NULL }, NULL, NULL, NULL -}; - const device_t keyboard_at_toshiba_device = { "PC/AT Keyboard (Toshiba)", 0, @@ -2432,16 +3117,6 @@ const device_t keyboard_at_ncr_device = { }; const device_t keyboard_ps2_device = { - "PS/2 Keyboard", - 0, - KBC_TYPE_PS2_NOREF | KBC_VEN_GENERIC, - kbd_init, - kbd_close, - kbd_reset, - { NULL }, NULL, NULL, NULL -}; - -const device_t keyboard_ps2_ps2_device = { "PS/2 Keyboard", 0, KBC_TYPE_PS2_1 | KBC_VEN_GENERIC, @@ -2454,7 +3129,7 @@ const device_t keyboard_ps2_ps2_device = { const device_t keyboard_ps2_ps1_device = { "PS/2 Keyboard (IBM PS/1)", 0, - KBC_TYPE_PS2_NOREF | KBC_VEN_IBM_PS1, + KBC_TYPE_PS2_1 | KBC_VEN_IBM_PS1, kbd_init, kbd_close, kbd_reset, @@ -2464,7 +3139,7 @@ const device_t keyboard_ps2_ps1_device = { const device_t keyboard_ps2_ps1_pci_device = { "PS/2 Keyboard (IBM PS/1)", DEVICE_PCI, - KBC_TYPE_PS2_NOREF | KBC_VEN_IBM_PS1, + KBC_TYPE_PS2_1 | KBC_VEN_IBM_PS1, kbd_init, kbd_close, kbd_reset, @@ -2484,7 +3159,7 @@ const device_t keyboard_ps2_xi8088_device = { const device_t keyboard_ps2_ami_device = { "PS/2 Keyboard (AMI)", 0, - KBC_TYPE_PS2_NOREF | KBC_VEN_AMI, + KBC_TYPE_PS2_1 | KBC_VEN_AMI, kbd_init, kbd_close, kbd_reset, @@ -2494,7 +3169,7 @@ const device_t keyboard_ps2_ami_device = { const device_t keyboard_ps2_olivetti_device = { "PS/2 Keyboard (Olivetti)", 0, - KBC_TYPE_PS2_NOREF | KBC_VEN_OLIVETTI, + KBC_TYPE_PS2_1 | KBC_VEN_OLIVETTI, kbd_init, kbd_close, kbd_reset, @@ -2524,7 +3199,7 @@ const device_t keyboard_ps2_mca_2_device = { const device_t keyboard_ps2_quadtel_device = { "PS/2 Keyboard (Quadtel/MegaPC)", 0, - KBC_TYPE_PS2_NOREF | KBC_VEN_QUADTEL, + KBC_TYPE_PS2_1 | KBC_VEN_QUADTEL, kbd_init, kbd_close, kbd_reset, @@ -2534,7 +3209,7 @@ const device_t keyboard_ps2_quadtel_device = { const device_t keyboard_ps2_pci_device = { "PS/2 Keyboard", DEVICE_PCI, - KBC_TYPE_PS2_NOREF | KBC_VEN_GENERIC, + KBC_TYPE_PS2_1 | KBC_VEN_GENERIC, kbd_init, kbd_close, kbd_reset, @@ -2544,7 +3219,7 @@ const device_t keyboard_ps2_pci_device = { const device_t keyboard_ps2_ami_pci_device = { "PS/2 Keyboard (AMI)", DEVICE_PCI, - KBC_TYPE_PS2_NOREF | KBC_VEN_AMI, + KBC_TYPE_PS2_1 | KBC_VEN_AMI, kbd_init, kbd_close, kbd_reset, @@ -2554,7 +3229,7 @@ const device_t keyboard_ps2_ami_pci_device = { const device_t keyboard_ps2_intel_ami_pci_device = { "PS/2 Keyboard (AMI)", DEVICE_PCI, - KBC_TYPE_PS2_NOREF | KBC_VEN_INTEL_AMI, + KBC_TYPE_PS2_1 | KBC_VEN_INTEL_AMI, kbd_init, kbd_close, kbd_reset, @@ -2564,7 +3239,7 @@ const device_t keyboard_ps2_intel_ami_pci_device = { const device_t keyboard_ps2_acer_pci_device = { "PS/2 Keyboard (Acer 90M002A)", DEVICE_PCI, - KBC_TYPE_PS2_NOREF | KBC_VEN_ACER, + KBC_TYPE_PS2_1 | KBC_VEN_ACER, kbd_init, kbd_close, kbd_reset, @@ -2575,17 +3250,8 @@ const device_t keyboard_ps2_acer_pci_device = { void keyboard_at_set_mouse(void (*func)(uint8_t val, void *priv), void *priv) { - mouse_write = func; - mouse_p = priv; -} - - -void -keyboard_at_adddata_keyboard_raw(uint8_t val) -{ - atkbd_t *dev = SavedKbd; - - add_data_kbd_queue(dev, 0, val); + // mouse_write = func; + // mouse_p = priv; } @@ -2598,10 +3264,30 @@ keyboard_at_adddata_mouse(uint8_t val) } +void +keyboard_at_adddata_mouse_direct(uint8_t val) +{ + // atkbd_t *dev = SavedKbd; + + return; +} + + +void +keyboard_at_adddata_mouse_cmd(uint8_t val) +{ + // atkbd_t *dev = SavedKbd; + + return; +} + + void keyboard_at_mouse_reset(void) { - kbc_queue_reset(2); + // atkbd_t *dev = SavedKbd; + + return; } @@ -2612,13 +3298,22 @@ keyboard_at_mouse_pos(void) } +int +keyboard_at_fixed_channel(void) +{ + // atkbd_t *dev = SavedKbd; + + return 0x000; +} + + void keyboard_at_set_mouse_scan(uint8_t val) { atkbd_t *dev = SavedKbd; uint8_t temp_mouse_scan = val ? 1 : 0; - if (temp_mouse_scan == !(dev->mem[0] & 0x20)) + if (temp_mouse_scan == !(dev->mem[0x20] & 0x20)) return; set_enable_mouse(dev, val ? 1 : 0); @@ -2632,7 +3327,7 @@ keyboard_at_get_mouse_scan(void) { atkbd_t *dev = SavedKbd; - return((dev->mem[0] & 0x20) ? 0x00 : 0x10); + return((dev->mem[0x20] & 0x20) ? 0x00 : 0x10); } @@ -2641,5 +3336,17 @@ keyboard_at_set_a20_key(int state) { atkbd_t *dev = SavedKbd; - write_output(dev, (dev->output_port & 0xfd) | ((!!state) << 1)); + write_output(dev, (dev->p2 & 0xfd) | ((!!state) << 1)); +} + + +void +keyboard_at_set_mode(int ps2) +{ + atkbd_t *dev = SavedKbd; + + if (ps2) + dev->flags |= KBC_FLAG_PS2; + else + dev->flags &= ~KBC_FLAG_PS2; }