diff --git a/src/chipset/ali1543.c b/src/chipset/ali1543.c index 00146c90e..2e2f74305 100644 --- a/src/chipset/ali1543.c +++ b/src/chipset/ali1543.c @@ -906,6 +906,7 @@ ali5237_write(int func, int addr, uint8_t val, void *priv) case 0x0c: /* Cache Line Size */ case 0x0d: /* Latency Timer */ + dev->usb_conf[addr] = val; break; case 0x3c: /* Interrupt Line Register */ @@ -1430,14 +1431,14 @@ ali7101_read(int func, int addr, void *priv) } static void -ali5237_usb_raise_interrupt(usb_t* usb, void *priv) +ali5237_usb_update_interrupt(usb_t* usb, void *priv) { ali1543_t *dev = (ali1543_t *) priv; - if (!dev->usb_dev_enable) - return; - - pci_set_irq(dev->usb_slot, PCI_INTA); + if (usb->irq_level) + pci_set_mirq(4, !!(dev->pci_conf[0x74] & 0x10)); + else + pci_clear_mirq(4, !!(dev->pci_conf[0x74] & 0x10)); } static void @@ -1590,10 +1591,10 @@ ali1543_init(const device_t *info) dev->smbus = device_add(&ali7101_smbus_device); /* USB */ - dev->usb_params.parent_priv = dev; - dev->usb_params.smi_handle = NULL; - dev->usb_params.raise_interrupt = ali5237_usb_raise_interrupt; - dev->usb = device_add_parameters(&usb_device, &dev->usb_params); + dev->usb_params.parent_priv = dev; + dev->usb_params.smi_handle = NULL; + dev->usb_params.update_interrupt = ali5237_usb_update_interrupt; + dev->usb = device_add_parameters(&usb_device, &dev->usb_params); dev->type = info->local & 0xff; dev->offset = (info->local >> 8) & 0x7f; diff --git a/src/chipset/intel_piix.c b/src/chipset/intel_piix.c index c6cfe8c9f..470978611 100644 --- a/src/chipset/intel_piix.c +++ b/src/chipset/intel_piix.c @@ -1427,11 +1427,14 @@ piix_fast_off_count(void *priv) } static void -piix_usb_raise_interrupt(usb_t* usb, void *priv) +piix_usb_update_interrupt(usb_t* usb, void *priv) { piix_t *dev = (piix_t *) priv; - pci_set_irq(dev->pci_slot, PCI_INTD); + if (usb->irq_level) + pci_set_irq(dev->pci_slot, PCI_INTD); + else + pci_clear_irq(dev->pci_slot, PCI_INTD); } static void @@ -1579,10 +1582,10 @@ piix_init(const device_t *info) } if (dev->type >= 3) { - dev->usb_params.parent_priv = dev; - dev->usb_params.smi_handle = NULL; - dev->usb_params.raise_interrupt = piix_usb_raise_interrupt; - dev->usb = device_add_parameters(&usb_device, &dev->usb_params); + dev->usb_params.parent_priv = dev; + dev->usb_params.smi_handle = NULL; + dev->usb_params.update_interrupt = piix_usb_update_interrupt; + dev->usb = device_add_parameters(&usb_device, &dev->usb_params); } if (dev->type > 3) { diff --git a/src/chipset/sis_5571.c b/src/chipset/sis_5571.c index aa8ea62f3..c158e2d63 100644 --- a/src/chipset/sis_5571.c +++ b/src/chipset/sis_5571.c @@ -641,7 +641,7 @@ pci_isa_bridge_read(int func, int addr, void *priv) } static void -sis_5571_usb_raise_interrupt(usb_t* usb, void* priv) +sis_5571_usb_update_interrupt(usb_t* usb, void* priv) { sis_5571_t *dev = (sis_5571_t *) priv; @@ -655,11 +655,17 @@ sis_5571_usb_raise_interrupt(usb_t* usb, void* priv) case 0x0d: break; default: - picint(1 << dev->pci_conf_sb[0][0x68] & 0x0F); + if (usb->irq_level) + picint(1 << dev->pci_conf_sb[0][0x68] & 0x0f); + else + picintc(1 << dev->pci_conf_sb[0][0x68] & 0x0f); break; } } else { - pci_set_irq(dev->sb_pci_slot, PCI_INTA); + if (usb->irq_level) + pci_set_irq(dev->sb_pci_slot, PCI_INTA); + else + pci_clear_irq(dev->sb_pci_slot, PCI_INTA); } } @@ -754,10 +760,10 @@ sis_5571_init(const device_t *info) dev->ide_drive[1] = device_add_inst(&sff8038i_device, 2); /* USB */ - dev->usb_params.parent_priv = dev; - dev->usb_params.raise_interrupt = sis_5571_usb_raise_interrupt; - dev->usb_params.smi_handle = sis_5571_usb_handle_smi; - dev->usb = device_add_parameters(&usb_device, &dev->usb_params); + dev->usb_params.parent_priv = dev; + dev->usb_params.update_interrupt = sis_5571_usb_update_interrupt; + dev->usb_params.smi_handle = sis_5571_usb_handle_smi; + dev->usb = device_add_parameters(&usb_device, &dev->usb_params); sis_5571_reset(dev); diff --git a/src/chipset/stpc.c b/src/chipset/stpc.c index 84720f802..2e4b045f2 100644 --- a/src/chipset/stpc.c +++ b/src/chipset/stpc.c @@ -875,11 +875,14 @@ stpc_setup(stpc_t *dev) } static void -stpc_usb_raise_interrupt(usb_t* usb, void* priv) +stpc_usb_update_interrupt(usb_t* usb, void* priv) { stpc_t *dev = (stpc_t *) priv; - pci_set_irq(dev->usb_slot, PCI_INTA); + if (usb->irq_level) + pci_set_irq(dev->usb_slot, PCI_INTA); + else + pci_clear_irq(dev->usb_slot, PCI_INTA); } static void @@ -907,9 +910,9 @@ stpc_init(const device_t *info) pci_add_card(PCI_ADD_NORTHBRIDGE, stpc_nb_read, stpc_nb_write, dev); dev->ide_slot = pci_add_card(PCI_ADD_SOUTHBRIDGE, stpc_isab_read, stpc_isab_write, dev); if (dev->local == STPC_ATLAS) { - dev->usb_params.smi_handle = NULL; - dev->usb_params.raise_interrupt = stpc_usb_raise_interrupt; - dev->usb_params.parent_priv = dev; + dev->usb_params.smi_handle = NULL; + dev->usb_params.update_interrupt = stpc_usb_update_interrupt; + dev->usb_params.parent_priv = dev; dev->ide_slot = pci_add_card(PCI_ADD_SOUTHBRIDGE, stpc_ide_read, stpc_ide_write, dev); dev->usb = device_add_parameters(&usb_device, &dev->usb_params); diff --git a/src/device/keyboard_at - Cópia.c b/src/device/keyboard_at - Cópia.c new file mode 100644 index 000000000..3a841ad91 --- /dev/null +++ b/src/device/keyboard_at - Cópia.c @@ -0,0 +1,3258 @@ +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * This file is part of the 86Box distribution. + * + * Intel 8042 (AT keyboard controller) emulation. + * + * + * + * Authors: Sarah Walker, + * Miran Grca, + * Fred N. van Kempen, + * EngiNerd, + * + * Copyright 2008-2020 Sarah Walker. + * Copyright 2016-2020 Miran Grca. + * Copyright 2017-2020 Fred N. van Kempen. + * Copyright 2020 EngiNerd. + */ +#include +#include +#include +#include +#include +#define HAVE_STDARG_H +#include +#include <86box/86box.h> +#include "cpu.h" +#include <86box/timer.h> +#include <86box/io.h> +#include <86box/pic.h> +#include <86box/pit.h> +#include <86box/ppi.h> +#include <86box/mem.h> +#include <86box/device.h> +#include <86box/machine.h> +#include <86box/m_at_t3100e.h> +#include <86box/fdd.h> +#include <86box/fdc.h> +#include <86box/sound.h> +#include <86box/snd_speaker.h> +#include <86box/video.h> +#include <86box/keyboard.h> + +#define STAT_PARITY 0x80 +#define STAT_RTIMEOUT 0x40 +#define STAT_TTIMEOUT 0x20 +#define STAT_MFULL 0x20 +#define STAT_UNLOCKED 0x10 +#define STAT_CD 0x08 +#define STAT_SYSFLAG 0x04 +#define STAT_IFULL 0x02 +#define STAT_OFULL 0x01 + +#define CCB_UNUSED 0x80 +#define CCB_TRANSLATE 0x40 +#define CCB_PCMODE 0x20 +#define CCB_ENABLEKBD 0x10 +#define CCB_IGNORELOCK 0x08 +#define CCB_SYSTEM 0x04 +#define CCB_ENABLEMINT 0x02 +#define CCB_ENABLEKINT 0x01 + +#define CCB_MASK 0x68 +#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_VEN_GENERIC 0x00 +#define KBC_VEN_AMI 0x04 +#define KBC_VEN_IBM_MCA 0x08 +#define KBC_VEN_QUADTEL 0x0c +#define KBC_VEN_TOSHIBA 0x10 +#define KBC_VEN_IBM_PS1 0x14 +#define KBC_VEN_ACER 0x18 +#define KBC_VEN_INTEL_AMI 0x1c +#define KBC_VEN_OLIVETTI 0x20 +#define KBC_VEN_NCR 0x24 +#define KBC_VEN_PHOENIX 0x28 +#define KBC_VEN_ALI 0x2c +#define KBC_VEN_TG 0x30 +#define KBC_VEN_TG_GREEN 0x34 +#define KBC_VEN_MASK 0x3c + +enum { + KBC_STATE_RESET = 0, + KBC_STATE_MAIN_IBF, + KBC_STATE_MAIN_KBD, + KBC_STATE_MAIN_MOUSE, + KBC_STATE_MAIN_BOTH, + KBC_STATE_KBC_OUT, + KBC_STATE_KBC_PARAM, + KBC_STATE_SEND_KBD, + KBC_STATE_KBD, + KBC_STATE_SEND_MOUSE, + KBC_STATE_MOUSE +}; +#define KBC_STATE_SCAN_KBD KBC_STATE_KBD +#define KBC_STATE_SCAN_MOUSE KBC_STATE_MOUSE + +enum { + DEV_STATE_MAIN_1 = 0, + DEV_STATE_MAIN_2, + DEV_STATE_MAIN_CMD, + DEV_STATE_MAIN_OUT, + DEV_STATE_MAIN_WANT_IN, + DEV_STATE_MAIN_IN +}; + +typedef struct { + /* Controller. */ + uint8_t pci, kbc_state, command, want60, + status, ib, out, old_out, + sc_or, secr_phase, mem_addr, input_port, + output_port, old_output_port, output_locked, ami_stat, + ami_flags, key_ctrl_queue_start, key_ctrl_queue_end; + + /* Keyboard. */ + uint8_t key_command, key_wantdata, kbd_last_scan_code, + kbd_state, key_wantcmd, key_dat, key_cmd_queue_start, + key_cmd_queue_end, key_queue_start, key_queue_end; + + /* Mouse. */ + uint8_t mouse_state, mouse_wantcmd, mouse_dat, mouse_cmd_queue_start, + mouse_cmd_queue_end, mouse_queue_start, mouse_queue_end; + + /* Controller. */ + uint8_t mem[0x100]; + + /* Controller - internal FIFO for the purpose of commands with multi-byte output. */ + uint8_t key_ctrl_queue[64]; + + /* Keyboard - command response FIFO. */ + uint8_t key_cmd_queue[16]; + + /* Keyboard - scan FIFO. */ + uint8_t key_queue[16]; + + /* Mouse - command response FIFO. */ + uint8_t mouse_cmd_queue[16]; + + /* Mouse - scan FIFO. */ + uint8_t mouse_queue[16]; + + /* Keyboard. */ + int out_new; + + /* Mouse. */ + int out_new_mouse; + + /* Controller. */ + uint32_t flags; + + /* Controller (main timer). */ + pc_timer_t send_delay_timer; + + /* Controller (P2 pulse callback timer). */ + pc_timer_t pulse_cb; + + uint8_t (*write60_ven)(void *p, uint8_t val); + uint8_t (*write64_ven)(void *p, uint8_t val); +} atkbd_t; + +/* Global keyboard flags for scan code set 3: + bit 0 = repeat, bit 1 = makes break code? */ +uint8_t keyboard_set3_flags[512]; +uint8_t keyboard_set3_all_repeat; +uint8_t keyboard_set3_all_break; + +/* Global keyboard mode: + Bits 0 - 1 = scan code set. */ +uint8_t keyboard_mode = 0x02; + +/* Keyboard controller ports. */ +kbc_port_t *kbc_ports[2] = { NULL, NULL }; + +static void (*mouse_write)(uint8_t val, void *priv) = NULL; +static void *mouse_p = NULL; +static atkbd_t *SavedKbd = NULL; // FIXME: remove!!! --FvK + +/* Non-translated to translated scan codes. */ +static const uint8_t nont_to_t[256] = { + 0xff, 0x43, 0x41, 0x3f, 0x3d, 0x3b, 0x3c, 0x58, + 0x64, 0x44, 0x42, 0x40, 0x3e, 0x0f, 0x29, 0x59, + 0x65, 0x38, 0x2a, 0x70, 0x1d, 0x10, 0x02, 0x5a, + 0x66, 0x71, 0x2c, 0x1f, 0x1e, 0x11, 0x03, 0x5b, + 0x67, 0x2e, 0x2d, 0x20, 0x12, 0x05, 0x04, 0x5c, + 0x68, 0x39, 0x2f, 0x21, 0x14, 0x13, 0x06, 0x5d, + 0x69, 0x31, 0x30, 0x23, 0x22, 0x15, 0x07, 0x5e, + 0x6a, 0x72, 0x32, 0x24, 0x16, 0x08, 0x09, 0x5f, + 0x6b, 0x33, 0x25, 0x17, 0x18, 0x0b, 0x0a, 0x60, + 0x6c, 0x34, 0x35, 0x26, 0x27, 0x19, 0x0c, 0x61, + 0x6d, 0x73, 0x28, 0x74, 0x1a, 0x0d, 0x62, 0x6e, + 0x3a, 0x36, 0x1c, 0x1b, 0x75, 0x2b, 0x63, 0x76, + 0x55, 0x56, 0x77, 0x78, 0x79, 0x7a, 0x0e, 0x7b, + 0x7c, 0x4f, 0x7d, 0x4b, 0x47, 0x7e, 0x7f, 0x6f, + 0x52, 0x53, 0x50, 0x4c, 0x4d, 0x48, 0x01, 0x45, + 0x57, 0x4e, 0x51, 0x4a, 0x37, 0x49, 0x46, 0x54, + 0x80, 0x81, 0x82, 0x41, 0x54, 0x85, 0x86, 0x87, + 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, + 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, + 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, + 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, + 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, + 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, + 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, + 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, + 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, + 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, + 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, + 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, + 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, + 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, + 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff +}; + +static const scancode scancode_set1[512] = { + // clang-format off + { { 0},{ 0} }, { { 0x01,0},{ 0x81,0} }, { { 0x02,0},{ 0x82,0} }, { { 0x03,0},{ 0x83,0} }, /*000*/ + { { 0x04,0},{ 0x84,0} }, { { 0x05,0},{ 0x85,0} }, { { 0x06,0},{ 0x86,0} }, { { 0x07,0},{ 0x87,0} }, /*004*/ + { { 0x08,0},{ 0x88,0} }, { { 0x09,0},{ 0x89,0} }, { { 0x0a,0},{ 0x8a,0} }, { { 0x0b,0},{ 0x8b,0} }, /*008*/ + { { 0x0c,0},{ 0x8c,0} }, { { 0x0d,0},{ 0x8d,0} }, { { 0x0e,0},{ 0x8e,0} }, { { 0x0f,0},{ 0x8f,0} }, /*00c*/ + { { 0x10,0},{ 0x90,0} }, { { 0x11,0},{ 0x91,0} }, { { 0x12,0},{ 0x92,0} }, { { 0x13,0},{ 0x93,0} }, /*010*/ + { { 0x14,0},{ 0x94,0} }, { { 0x15,0},{ 0x95,0} }, { { 0x16,0},{ 0x96,0} }, { { 0x17,0},{ 0x97,0} }, /*014*/ + { { 0x18,0},{ 0x98,0} }, { { 0x19,0},{ 0x99,0} }, { { 0x1a,0},{ 0x9a,0} }, { { 0x1b,0},{ 0x9b,0} }, /*018*/ + { { 0x1c,0},{ 0x9c,0} }, { { 0x1d,0},{ 0x9d,0} }, { { 0x1e,0},{ 0x9e,0} }, { { 0x1f,0},{ 0x9f,0} }, /*01c*/ + { { 0x20,0},{ 0xa0,0} }, { { 0x21,0},{ 0xa1,0} }, { { 0x22,0},{ 0xa2,0} }, { { 0x23,0},{ 0xa3,0} }, /*020*/ + { { 0x24,0},{ 0xa4,0} }, { { 0x25,0},{ 0xa5,0} }, { { 0x26,0},{ 0xa6,0} }, { { 0x27,0},{ 0xa7,0} }, /*024*/ + { { 0x28,0},{ 0xa8,0} }, { { 0x29,0},{ 0xa9,0} }, { { 0x2a,0},{ 0xaa,0} }, { { 0x2b,0},{ 0xab,0} }, /*028*/ + { { 0x2c,0},{ 0xac,0} }, { { 0x2d,0},{ 0xad,0} }, { { 0x2e,0},{ 0xae,0} }, { { 0x2f,0},{ 0xaf,0} }, /*02c*/ + { { 0x30,0},{ 0xb0,0} }, { { 0x31,0},{ 0xb1,0} }, { { 0x32,0},{ 0xb2,0} }, { { 0x33,0},{ 0xb3,0} }, /*030*/ + { { 0x34,0},{ 0xb4,0} }, { { 0x35,0},{ 0xb5,0} }, { { 0x36,0},{ 0xb6,0} }, { { 0x37,0},{ 0xb7,0} }, /*034*/ + { { 0x38,0},{ 0xb8,0} }, { { 0x39,0},{ 0xb9,0} }, { { 0x3a,0},{ 0xba,0} }, { { 0x3b,0},{ 0xbb,0} }, /*038*/ + { { 0x3c,0},{ 0xbc,0} }, { { 0x3d,0},{ 0xbd,0} }, { { 0x3e,0},{ 0xbe,0} }, { { 0x3f,0},{ 0xbf,0} }, /*03c*/ + { { 0x40,0},{ 0xc0,0} }, { { 0x41,0},{ 0xc1,0} }, { { 0x42,0},{ 0xc2,0} }, { { 0x43,0},{ 0xc3,0} }, /*040*/ + { { 0x44,0},{ 0xc4,0} }, { { 0x45,0},{ 0xc5,0} }, { { 0x46,0},{ 0xc6,0} }, { { 0x47,0},{ 0xc7,0} }, /*044*/ + { { 0x48,0},{ 0xc8,0} }, { { 0x49,0},{ 0xc9,0} }, { { 0x4a,0},{ 0xca,0} }, { { 0x4b,0},{ 0xcb,0} }, /*048*/ + { { 0x4c,0},{ 0xcc,0} }, { { 0x4d,0},{ 0xcd,0} }, { { 0x4e,0},{ 0xce,0} }, { { 0x4f,0},{ 0xcf,0} }, /*04c*/ + { { 0x50,0},{ 0xd0,0} }, { { 0x51,0},{ 0xd1,0} }, { { 0x52,0},{ 0xd2,0} }, { { 0x53,0},{ 0xd3,0} }, /*050*/ + { { 0x54,0},{ 0xd4,0} }, { { 0x55,0},{ 0xd5,0} }, { { 0x56,0},{ 0xd6,0} }, { { 0x57,0},{ 0xd7,0} }, /*054*/ + { { 0x58,0},{ 0xd8,0} }, { { 0x59,0},{ 0xd9,0} }, { { 0x5a,0},{ 0xda,0} }, { { 0x5b,0},{ 0xdb,0} }, /*058*/ + { { 0x5c,0},{ 0xdc,0} }, { { 0x5d,0},{ 0xdd,0} }, { { 0x5e,0},{ 0xde,0} }, { { 0x5f,0},{ 0xdf,0} }, /*05c*/ + { { 0x60,0},{ 0xe0,0} }, { { 0x61,0},{ 0xe1,0} }, { { 0x62,0},{ 0xe2,0} }, { { 0x63,0},{ 0xe3,0} }, /*060*/ + { { 0x64,0},{ 0xe4,0} }, { { 0x65,0},{ 0xe5,0} }, { { 0x66,0},{ 0xe6,0} }, { { 0x67,0},{ 0xe7,0} }, /*064*/ + { { 0x68,0},{ 0xe8,0} }, { { 0x69,0},{ 0xe9,0} }, { { 0x6a,0},{ 0xea,0} }, { { 0x6b,0},{ 0xeb,0} }, /*068*/ + { { 0x6c,0},{ 0xec,0} }, { { 0x6d,0},{ 0xed,0} }, { { 0x6e,0},{ 0xee,0} }, { { 0x6f,0},{ 0xef,0} }, /*06c*/ + { { 0x70,0},{ 0xf0,0} }, { { 0x71,0},{ 0xf1,0} }, { { 0x72,0},{ 0xf2,0} }, { { 0x73,0},{ 0xf3,0} }, /*070*/ + { { 0x74,0},{ 0xf4,0} }, { { 0x75,0},{ 0xf5,0} }, { { 0x76,0},{ 0xf6,0} }, { { 0x77,0},{ 0xf7,0} }, /*074*/ + { { 0x78,0},{ 0xf8,0} }, { { 0x79,0},{ 0xf9,0} }, { { 0x7a,0},{ 0xfa,0} }, { { 0x7b,0},{ 0xfb,0} }, /*078*/ + { { 0x7c,0},{ 0xfc,0} }, { { 0x7d,0},{ 0xfd,0} }, { { 0x7e,0},{ 0xfe,0} }, { { 0x7f,0},{ 0xff,0} }, /*07c*/ + + { { 0x80,0},{ 0} }, { { 0x81,0},{ 0} }, { { 0x82,0},{ 0} }, { { 0},{ 0} }, /*080*/ + { { 0},{ 0} }, { { 0x85,0},{ 0} }, { { 0x86,0},{ 0} }, { { 0x87,0},{ 0} }, /*084*/ + { { 0x88,0},{ 0} }, { { 0x89,0},{ 0} }, { { 0x8a,0},{ 0} }, { { 0x8b,0},{ 0} }, /*088*/ + { { 0x8c,0},{ 0} }, { { 0x8d,0},{ 0} }, { { 0x8e,0},{ 0} }, { { 0x8f,0},{ 0} }, /*08c*/ + { { 0x90,0},{ 0} }, { { 0x91,0},{ 0} }, { { 0x92,0},{ 0} }, { { 0x93,0},{ 0} }, /*090*/ + { { 0x94,0},{ 0} }, { { 0x95,0},{ 0} }, { { 0x96,0},{ 0} }, { { 0x97,0},{ 0} }, /*094*/ + { { 0x98,0},{ 0} }, { { 0x99,0},{ 0} }, { { 0x9a,0},{ 0} }, { { 0x9b,0},{ 0} }, /*098*/ + { { 0x9c,0},{ 0} }, { { 0x9d,0},{ 0} }, { { 0x9e,0},{ 0} }, { { 0x9f,0},{ 0} }, /*09c*/ + { { 0xa0,0},{ 0} }, { { 0xa1,0},{ 0} }, { { 0xa2,0},{ 0} }, { { 0xa3,0},{ 0} }, /*0a0*/ + { { 0xa4,0},{ 0} }, { { 0xa5,0},{ 0} }, { { 0xa6,0},{ 0} }, { { 0xa7,0},{ 0} }, /*0a4*/ + { { 0xa8,0},{ 0} }, { { 0xa9,0},{ 0} }, { { 0xaa,0},{ 0} }, { { 0xab,0},{ 0} }, /*0a8*/ + { { 0xac,0},{ 0} }, { { 0xad,0},{ 0} }, { { 0xae,0},{ 0} }, { { 0xaf,0},{ 0} }, /*0ac*/ + { { 0xb0,0},{ 0} }, { { 0xb1,0},{ 0} }, { { 0xb2,0},{ 0} }, { { 0xb3,0},{ 0} }, /*0b0*/ + { { 0xb4,0},{ 0} }, { { 0xb5,0},{ 0} }, { { 0xb6,0},{ 0} }, { { 0xb7,0},{ 0} }, /*0b4*/ + { { 0xb8,0},{ 0} }, { { 0xb9,0},{ 0} }, { { 0xba,0},{ 0} }, { { 0xbb,0},{ 0} }, /*0b8*/ + { { 0xbc,0},{ 0} }, { { 0xbd,0},{ 0} }, { { 0xbe,0},{ 0} }, { { 0xbf,0},{ 0} }, /*0bc*/ + { { 0xc0,0},{ 0} }, { { 0xc1,0},{ 0} }, { { 0xc2,0},{ 0} }, { { 0xc3,0},{ 0} }, /*0c0*/ + { { 0xc4,0},{ 0} }, { { 0xc5,0},{ 0} }, { { 0xc6,0},{ 0} }, { { 0xc7,0},{ 0} }, /*0c4*/ + { { 0xc8,0},{ 0} }, { { 0xc9,0},{ 0} }, { { 0xca,0},{ 0} }, { { 0xcb,0},{ 0} }, /*0c8*/ + { { 0xcc,0},{ 0} }, { { 0xcd,0},{ 0} }, { { 0xce,0},{ 0} }, { { 0xcf,0},{ 0} }, /*0cc*/ + { { 0xd0,0},{ 0} }, { { 0xd1,0},{ 0} }, { { 0xd2,0},{ 0} }, { { 0xd3,0},{ 0} }, /*0d0*/ + { { 0xd4,0},{ 0} }, { { 0xd5,0},{ 0} }, { { 0xd6,0},{ 0} }, { { 0xd7,0},{ 0} }, /*0d4*/ + { { 0xd8,0},{ 0} }, { { 0xd9,0},{ 0} }, { { 0xda,0},{ 0} }, { { 0xdb,0},{ 0} }, /*0d8*/ + { { 0xdc,0},{ 0} }, { { 0xdd,0},{ 0} }, { { 0xde,0},{ 0} }, { { 0xdf,0},{ 0} }, /*0dc*/ + { { 0xe0,0},{ 0} }, { { 0xe1,0},{ 0} }, { { 0xe2,0},{ 0} }, { { 0xe3,0},{ 0} }, /*0e0*/ + { { 0xe4,0},{ 0} }, { { 0xe5,0},{ 0} }, { { 0xe6,0},{ 0} }, { { 0xe7,0},{ 0} }, /*0e4*/ + { { 0xe8,0},{ 0} }, { { 0xe9,0},{ 0} }, { { 0xea,0},{ 0} }, { { 0xeb,0},{ 0} }, /*0e8*/ + { { 0xec,0},{ 0} }, { { 0xed,0},{ 0} }, { { 0xee,0},{ 0} }, { { 0xef,0},{ 0} }, /*0ec*/ + { { 0},{ 0} }, { { 0xf1,0},{ 0} }, { { 0xf2,0},{ 0} }, { { 0xf3,0},{ 0} }, /*0f0*/ + { { 0xf4,0},{ 0} }, { { 0xf5,0},{ 0} }, { { 0xf6,0},{ 0} }, { { 0xf7,0},{ 0} }, /*0f4*/ + { { 0xf8,0},{ 0} }, { { 0xf9,0},{ 0} }, { { 0xfa,0},{ 0} }, { { 0xfb,0},{ 0} }, /*0f8*/ + { { 0xfc,0},{ 0} }, { { 0xfd,0},{ 0} }, { { 0xfe,0},{ 0} }, { { 0xff,0},{ 0} }, /*0fc*/ + + { {0xe1,0x1d,0},{0xe1, 0x9d,0} }, { {0xe0,0x01,0},{0xe0, 0x81,0} }, { {0xe0,0x02,0},{0xe0, 0x82,0} }, { {0xe0,0x03,0},{0xe0, 0x83,0} }, /*100*/ + { {0xe0,0x04,0},{0xe0, 0x84,0} }, { {0xe0,0x05,0},{0xe0, 0x85,0} }, { {0xe0,0x06,0},{0xe0, 0x86,0} }, { {0xe0,0x07,0},{0xe0, 0x87,0} }, /*104*/ + { {0xe0,0x08,0},{0xe0, 0x88,0} }, { {0xe0,0x09,0},{0xe0, 0x89,0} }, { {0xe0,0x0a,0},{0xe0, 0x8a,0} }, { {0xe0,0x0b,0},{0xe0, 0x8b,0} }, /*108*/ + { {0xe0,0x0c,0},{0xe0, 0x8c,0} }, { { 0},{ 0} }, { {0xe0,0x0e,0},{0xe0, 0x8e,0} }, { {0xe0,0x0f,0},{0xe0, 0x8f,0} }, /*10c*/ + { {0xe0,0x10,0},{0xe0, 0x90,0} }, { {0xe0,0x11,0},{0xe0, 0x91,0} }, { {0xe0,0x12,0},{0xe0, 0x92,0} }, { {0xe0,0x13,0},{0xe0, 0x93,0} }, /*110*/ + { {0xe0,0x14,0},{0xe0, 0x94,0} }, { {0xe0,0x15,0},{0xe0, 0x95,0} }, { {0xe0,0x16,0},{0xe0, 0x96,0} }, { {0xe0,0x17,0},{0xe0, 0x97,0} }, /*114*/ + { {0xe0,0x18,0},{0xe0, 0x98,0} }, { {0xe0,0x19,0},{0xe0, 0x99,0} }, { {0xe0,0x1a,0},{0xe0, 0x9a,0} }, { {0xe0,0x1b,0},{0xe0, 0x9b,0} }, /*118*/ + { {0xe0,0x1c,0},{0xe0, 0x9c,0} }, { {0xe0,0x1d,0},{0xe0, 0x9d,0} }, { {0xe0,0x1e,0},{0xe0, 0x9e,0} }, { {0xe0,0x1f,0},{0xe0, 0x9f,0} }, /*11c*/ + { {0xe0,0x20,0},{0xe0, 0xa0,0} }, { {0xe0,0x21,0},{0xe0, 0xa1,0} }, { {0xe0,0x22,0},{0xe0, 0xa2,0} }, { {0xe0,0x23,0},{0xe0, 0xa3,0} }, /*120*/ + { {0xe0,0x24,0},{0xe0, 0xa4,0} }, { {0xe0,0x25,0},{0xe0, 0xa5,0} }, { {0xe0,0x26,0},{0xe0, 0xa6,0} }, { { 0},{ 0} }, /*124*/ + { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*128*/ + { {0xe0,0x2c,0},{0xe0, 0xac,0} }, { {0xe0,0x2d,0},{0xe0, 0xad,0} }, { {0xe0,0x2e,0},{0xe0, 0xae,0} }, { {0xe0,0x2f,0},{0xe0, 0xaf,0} }, /*12c*/ + { {0xe0,0x30,0},{0xe0, 0xb0,0} }, { {0xe0,0x31,0},{0xe0, 0xb1,0} }, { {0xe0,0x32,0},{0xe0, 0xb2,0} }, { { 0},{ 0} }, /*130*/ + { {0xe0,0x34,0},{0xe0, 0xb4,0} }, { {0xe0,0x35,0},{0xe0, 0xb5,0} }, { { 0},{ 0} }, { {0xe0,0x37,0},{0xe0, 0xb7,0} }, /*134*/ + { {0xe0,0x38,0},{0xe0, 0xb8,0} }, { { 0},{ 0} }, { {0xe0,0x3a,0},{0xe0, 0xba,0} }, { {0xe0,0x3b,0},{0xe0, 0xbb,0} }, /*138*/ + { {0xe0,0x3c,0},{0xe0, 0xbc,0} }, { {0xe0,0x3d,0},{0xe0, 0xbd,0} }, { {0xe0,0x3e,0},{0xe0, 0xbe,0} }, { {0xe0,0x3f,0},{0xe0, 0xbf,0} }, /*13c*/ + { {0xe0,0x40,0},{0xe0, 0xc0,0} }, { {0xe0,0x41,0},{0xe0, 0xc1,0} }, { {0xe0,0x42,0},{0xe0, 0xc2,0} }, { {0xe0,0x43,0},{0xe0, 0xc3,0} }, /*140*/ + { {0xe0,0x44,0},{0xe0, 0xc4,0} }, { { 0},{ 0} }, { {0xe0,0x46,0},{0xe0, 0xc6,0} }, { {0xe0,0x47,0},{0xe0, 0xc7,0} }, /*144*/ + { {0xe0,0x48,0},{0xe0, 0xc8,0} }, { {0xe0,0x49,0},{0xe0, 0xc9,0} }, { { 0},{ 0} }, { {0xe0,0x4b,0},{0xe0, 0xcb,0} }, /*148*/ + { {0xe0,0x4c,0},{0xe0, 0xcc,0} }, { {0xe0,0x4d,0},{0xe0, 0xcd,0} }, { {0xe0,0x4e,0},{0xe0, 0xce,0} }, { {0xe0,0x4f,0},{0xe0, 0xcf,0} }, /*14c*/ + { {0xe0,0x50,0},{0xe0, 0xd0,0} }, { {0xe0,0x51,0},{0xe0, 0xd1,0} }, { {0xe0,0x52,0},{0xe0, 0xd2,0} }, { {0xe0,0x53,0},{0xe0, 0xd3,0} }, /*150*/ + { { 0},{ 0} }, { {0xe0,0x55,0},{0xe0, 0xd5,0} }, { { 0},{ 0} }, { {0xe0,0x57,0},{0xe0, 0xd7,0} }, /*154*/ + { {0xe0,0x58,0},{0xe0, 0xd8,0} }, { {0xe0,0x59,0},{0xe0, 0xd9,0} }, { {0xe0,0x5a,0},{0xe0, 0xaa,0} }, { {0xe0,0x5b,0},{0xe0, 0xdb,0} }, /*158*/ + { {0xe0,0x5c,0},{0xe0, 0xdc,0} }, { {0xe0,0x5d,0},{0xe0, 0xdd,0} }, { {0xe0,0x5e,0},{0xe0, 0xee,0} }, { {0xe0,0x5f,0},{0xe0, 0xdf,0} }, /*15c*/ + { { 0},{ 0} }, { {0xe0,0x61,0},{0xe0, 0xe1,0} }, { {0xe0,0x62,0},{0xe0, 0xe2,0} }, { {0xe0,0x63,0},{0xe0, 0xe3,0} }, /*160*/ + { {0xe0,0x64,0},{0xe0, 0xe4,0} }, { {0xe0,0x65,0},{0xe0, 0xe5,0} }, { {0xe0,0x66,0},{0xe0, 0xe6,0} }, { {0xe0,0x67,0},{0xe0, 0xe7,0} }, /*164*/ + { {0xe0,0x68,0},{0xe0, 0xe8,0} }, { {0xe0,0x69,0},{0xe0, 0xe9,0} }, { {0xe0,0x6a,0},{0xe0, 0xea,0} }, { {0xe0,0x6b,0},{0xe0, 0xeb,0} }, /*168*/ + { {0xe0,0x6c,0},{0xe0, 0xec,0} }, { {0xe0,0x6d,0},{0xe0, 0xed,0} }, { {0xe0,0x6e,0},{0xe0, 0xee,0} }, { { 0},{ 0} }, /*16c*/ + { {0xe0,0x70,0},{0xe0, 0xf0,0} }, { {0xe0,0x71,0},{0xe0, 0xf1,0} }, { {0xe0,0x72,0},{0xe0, 0xf2,0} }, { {0xe0,0x73,0},{0xe0, 0xf3,0} }, /*170*/ + { {0xe0,0x74,0},{0xe0, 0xf4,0} }, { {0xe0,0x75,0},{0xe0, 0xf5,0} }, { { 0},{ 0} }, { {0xe0,0x77,0},{0xe0, 0xf7,0} }, /*174*/ + { {0xe0,0x78,0},{0xe0, 0xf8,0} }, { {0xe0,0x79,0},{0xe0, 0xf9,0} }, { {0xe0,0x7a,0},{0xe0, 0xfa,0} }, { {0xe0,0x7b,0},{0xe0, 0xfb,0} }, /*178*/ + { {0xe0,0x7c,0},{0xe0, 0xfc,0} }, { {0xe0,0x7d,0},{0xe0, 0xfd,0} }, { {0xe0,0x7e,0},{0xe0, 0xfe,0} }, { {0xe0,0x7f,0},{0xe0, 0xff,0} }, /*17c*/ + + { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*180*/ + { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*184*/ + { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*188*/ + { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*18c*/ + { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*190*/ + { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*194*/ + { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*198*/ + { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*19c*/ + { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*1a0*/ + { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*1a4*/ + { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*1a8*/ + { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*1ac*/ + { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*1c0*/ + { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*1c4*/ + { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*1c8*/ + { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*1cc*/ + { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*1d0*/ + { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*1d4*/ + { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*1d8*/ + { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*1dc*/ + { { 0},{ 0} }, { {0xe0,0xe1,0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*1e0*/ + { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*1e4*/ + { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*1e8*/ + { { 0},{ 0} }, { { 0},{ 0} }, { {0xe0,0xee,0},{ 0} }, { { 0},{ 0} }, /*1ec*/ + { { 0},{ 0} }, { {0xe0,0xf1,0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*1f0*/ + { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*1f4*/ + { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*1f8*/ + { { 0},{ 0} }, { { 0},{ 0} }, { {0xe0,0xfe,0},{ 0} }, { {0xe0,0xff,0},{ 0} } /*1fc*/ + // clang-format on +}; + +static const scancode scancode_set2[512] = { + // clang-format off + { { 0},{ 0} }, { { 0x76,0},{ 0xF0,0x76,0} }, { { 0x16,0},{ 0xF0,0x16,0} }, { { 0x1E,0},{ 0xF0,0x1E,0} }, /*000*/ + { { 0x26,0},{ 0xF0,0x26,0} }, { { 0x25,0},{ 0xF0,0x25,0} }, { { 0x2E,0},{ 0xF0,0x2E,0} }, { { 0x36,0},{ 0xF0,0x36,0} }, /*004*/ + { { 0x3D,0},{ 0xF0,0x3D,0} }, { { 0x3E,0},{ 0xF0,0x3E,0} }, { { 0x46,0},{ 0xF0,0x46,0} }, { { 0x45,0},{ 0xF0,0x45,0} }, /*008*/ + { { 0x4E,0},{ 0xF0,0x4E,0} }, { { 0x55,0},{ 0xF0,0x55,0} }, { { 0x66,0},{ 0xF0,0x66,0} }, { { 0x0D,0},{ 0xF0,0x0D,0} }, /*00c*/ + { { 0x15,0},{ 0xF0,0x15,0} }, { { 0x1D,0},{ 0xF0,0x1D,0} }, { { 0x24,0},{ 0xF0,0x24,0} }, { { 0x2D,0},{ 0xF0,0x2D,0} }, /*010*/ + { { 0x2C,0},{ 0xF0,0x2C,0} }, { { 0x35,0},{ 0xF0,0x35,0} }, { { 0x3C,0},{ 0xF0,0x3C,0} }, { { 0x43,0},{ 0xF0,0x43,0} }, /*014*/ + { { 0x44,0},{ 0xF0,0x44,0} }, { { 0x4D,0},{ 0xF0,0x4D,0} }, { { 0x54,0},{ 0xF0,0x54,0} }, { { 0x5B,0},{ 0xF0,0x5B,0} }, /*018*/ + { { 0x5A,0},{ 0xF0,0x5A,0} }, { { 0x14,0},{ 0xF0,0x14,0} }, { { 0x1C,0},{ 0xF0,0x1C,0} }, { { 0x1B,0},{ 0xF0,0x1B,0} }, /*01c*/ + { { 0x23,0},{ 0xF0,0x23,0} }, { { 0x2B,0},{ 0xF0,0x2B,0} }, { { 0x34,0},{ 0xF0,0x34,0} }, { { 0x33,0},{ 0xF0,0x33,0} }, /*020*/ + { { 0x3B,0},{ 0xF0,0x3B,0} }, { { 0x42,0},{ 0xF0,0x42,0} }, { { 0x4B,0},{ 0xF0,0x4B,0} }, { { 0x4C,0},{ 0xF0,0x4C,0} }, /*024*/ + { { 0x52,0},{ 0xF0,0x52,0} }, { { 0x0E,0},{ 0xF0,0x0E,0} }, { { 0x12,0},{ 0xF0,0x12,0} }, { { 0x5D,0},{ 0xF0,0x5D,0} }, /*028*/ + { { 0x1A,0},{ 0xF0,0x1A,0} }, { { 0x22,0},{ 0xF0,0x22,0} }, { { 0x21,0},{ 0xF0,0x21,0} }, { { 0x2A,0},{ 0xF0,0x2A,0} }, /*02c*/ + { { 0x32,0},{ 0xF0,0x32,0} }, { { 0x31,0},{ 0xF0,0x31,0} }, { { 0x3A,0},{ 0xF0,0x3A,0} }, { { 0x41,0},{ 0xF0,0x41,0} }, /*030*/ + { { 0x49,0},{ 0xF0,0x49,0} }, { { 0x4A,0},{ 0xF0,0x4A,0} }, { { 0x59,0},{ 0xF0,0x59,0} }, { { 0x7C,0},{ 0xF0,0x7C,0} }, /*034*/ + { { 0x11,0},{ 0xF0,0x11,0} }, { { 0x29,0},{ 0xF0,0x29,0} }, { { 0x58,0},{ 0xF0,0x58,0} }, { { 0x05,0},{ 0xF0,0x05,0} }, /*038*/ + { { 0x06,0},{ 0xF0,0x06,0} }, { { 0x04,0},{ 0xF0,0x04,0} }, { { 0x0C,0},{ 0xF0,0x0C,0} }, { { 0x03,0},{ 0xF0,0x03,0} }, /*03c*/ + { { 0x0B,0},{ 0xF0,0x0B,0} }, { { 0x83,0},{ 0xF0,0x83,0} }, { { 0x0A,0},{ 0xF0,0x0A,0} }, { { 0x01,0},{ 0xF0,0x01,0} }, /*040*/ + { { 0x09,0},{ 0xF0,0x09,0} }, { { 0x77,0},{ 0xF0,0x77,0} }, { { 0x7E,0},{ 0xF0,0x7E,0} }, { { 0x6C,0},{ 0xF0,0x6C,0} }, /*044*/ + { { 0x75,0},{ 0xF0,0x75,0} }, { { 0x7D,0},{ 0xF0,0x7D,0} }, { { 0x7B,0},{ 0xF0,0x7B,0} }, { { 0x6B,0},{ 0xF0,0x6B,0} }, /*048*/ + { { 0x73,0},{ 0xF0,0x73,0} }, { { 0x74,0},{ 0xF0,0x74,0} }, { { 0x79,0},{ 0xF0,0x79,0} }, { { 0x69,0},{ 0xF0,0x69,0} }, /*04c*/ + { { 0x72,0},{ 0xF0,0x72,0} }, { { 0x7A,0},{ 0xF0,0x7A,0} }, { { 0x70,0},{ 0xF0,0x70,0} }, { { 0x71,0},{ 0xF0,0x71,0} }, /*050*/ + { { 0x84,0},{ 0xF0,0x84,0} }, { { 0x60,0},{ 0xF0,0x60,0} }, { { 0x61,0},{ 0xF0,0x61,0} }, { { 0x78,0},{ 0xF0,0x78,0} }, /*054*/ + { { 0x07,0},{ 0xF0,0x07,0} }, { { 0x0F,0},{ 0xF0,0x0F,0} }, { { 0x17,0},{ 0xF0,0x17,0} }, { { 0x1F,0},{ 0xF0,0x1F,0} }, /*058*/ + { { 0x27,0},{ 0xF0,0x27,0} }, { { 0x2F,0},{ 0xF0,0x2F,0} }, { { 0x37,0},{ 0xF0,0x37,0} }, { { 0x3F,0},{ 0xF0,0x3F,0} }, /*05c*/ + { { 0x47,0},{ 0xF0,0x47,0} }, { { 0x4F,0},{ 0xF0,0x4F,0} }, { { 0x56,0},{ 0xF0,0x56,0} }, { { 0x5E,0},{ 0xF0,0x5E,0} }, /*060*/ + { { 0x08,0},{ 0xF0,0x08,0} }, { { 0x10,0},{ 0xF0,0x10,0} }, { { 0x18,0},{ 0xF0,0x18,0} }, { { 0x20,0},{ 0xF0,0x20,0} }, /*064*/ + { { 0x28,0},{ 0xF0,0x28,0} }, { { 0x30,0},{ 0xF0,0x30,0} }, { { 0x38,0},{ 0xF0,0x38,0} }, { { 0x40,0},{ 0xF0,0x40,0} }, /*068*/ + { { 0x48,0},{ 0xF0,0x48,0} }, { { 0x50,0},{ 0xF0,0x50,0} }, { { 0x57,0},{ 0xF0,0x57,0} }, { { 0x6F,0},{ 0xF0,0x6F,0} }, /*06c*/ + { { 0x13,0},{ 0xF0,0x13,0} }, { { 0x19,0},{ 0xF0,0x19,0} }, { { 0x39,0},{ 0xF0,0x39,0} }, { { 0x51,0},{ 0xF0,0x51,0} }, /*070*/ + { { 0x53,0},{ 0xF0,0x53,0} }, { { 0x5C,0},{ 0xF0,0x5C,0} }, { { 0x5F,0},{ 0xF0,0x5F,0} }, { { 0x62,0},{ 0xF0,0x62,0} }, /*074*/ + { { 0x63,0},{ 0xF0,0x63,0} }, { { 0x64,0},{ 0xF0,0x64,0} }, { { 0x65,0},{ 0xF0,0x65,0} }, { { 0x67,0},{ 0xF0,0x67,0} }, /*078*/ + { { 0x68,0},{ 0xF0,0x68,0} }, { { 0x6A,0},{ 0xF0,0x6A,0} }, { { 0x6D,0},{ 0xF0,0x6D,0} }, { { 0x6E,0},{ 0xF0,0x6E,0} }, /*07c*/ + + { { 0x80,0},{ 0xf0,0x80,0} }, { { 0x81,0},{ 0xf0,0x81,0} }, { { 0x82,0},{ 0xf0,0x82,0} }, { { 0},{ 0} }, /*080*/ + { { 0},{ 0} }, { { 0x85,0},{ 0xf0,0x54,0} }, { { 0x86,0},{ 0xf0,0x86,0} }, { { 0x87,0},{ 0xf0,0x87,0} }, /*084*/ + { { 0x88,0},{ 0xf0,0x88,0} }, { { 0x89,0},{ 0xf0,0x89,0} }, { { 0x8a,0},{ 0xf0,0x8a,0} }, { { 0x8b,0},{ 0xf0,0x8b,0} }, /*088*/ + { { 0x8c,0},{ 0xf0,0x8c,0} }, { { 0x8d,0},{ 0xf0,0x8d,0} }, { { 0x8e,0},{ 0xf0,0x8e,0} }, { { 0x8f,0},{ 0xf0,0x8f,0} }, /*08c*/ + { { 0x90,0},{ 0xf0,0x90,0} }, { { 0x91,0},{ 0xf0,0x91,0} }, { { 0x92,0},{ 0xf0,0x92,0} }, { { 0x93,0},{ 0xf0,0x93,0} }, /*090*/ + { { 0x94,0},{ 0xf0,0x94,0} }, { { 0x95,0},{ 0xf0,0x95,0} }, { { 0x96,0},{ 0xf0,0x96,0} }, { { 0x97,0},{ 0xf0,0x97,0} }, /*094*/ + { { 0x98,0},{ 0xf0,0x98,0} }, { { 0x99,0},{ 0xf0,0x99,0} }, { { 0x9a,0},{ 0xf0,0x9a,0} }, { { 0x9b,0},{ 0xf0,0x9b,0} }, /*098*/ + { { 0x9c,0},{ 0xf0,0x9c,0} }, { { 0x9d,0},{ 0xf0,0x9d,0} }, { { 0x9e,0},{ 0xf0,0x9e,0} }, { { 0x9f,0},{ 0xf0,0x9f,0} }, /*09c*/ + { { 0xa0,0},{ 0xf0,0xa0,0} }, { { 0xa1,0},{ 0xf0,0xa1,0} }, { { 0xa2,0},{ 0xf0,0xa2,0} }, { { 0xa3,0},{ 0xf0,0xa3,0} }, /*0a0*/ + { { 0xa4,0},{ 0xf0,0xa4,0} }, { { 0xa5,0},{ 0xf0,0xa5,0} }, { { 0xa6,0},{ 0xf0,0xa6,0} }, { { 0xa7,0},{ 0xf0,0xa7,0} }, /*0a4*/ + { { 0xa8,0},{ 0xf0,0xa8,0} }, { { 0xa9,0},{ 0xf0,0xa9,0} }, { { 0xaa,0},{ 0xf0,0xaa,0} }, { { 0xab,0},{ 0xf0,0xab,0} }, /*0a8*/ + { { 0xac,0},{ 0xf0,0xac,0} }, { { 0xad,0},{ 0xf0,0xad,0} }, { { 0xae,0},{ 0xf0,0xae,0} }, { { 0xaf,0},{ 0xf0,0xaf,0} }, /*0ac*/ + { { 0xb0,0},{ 0xf0,0xb0,0} }, { { 0xb1,0},{ 0xf0,0xb1,0} }, { { 0xb2,0},{ 0xf0,0xb2,0} }, { { 0xb3,0},{ 0xf0,0xb3,0} }, /*0b0*/ + { { 0xb4,0},{ 0xf0,0xb4,0} }, { { 0xb5,0},{ 0xf0,0xb5,0} }, { { 0xb6,0},{ 0xf0,0xb6,0} }, { { 0xb7,0},{ 0xf0,0xb7,0} }, /*0b4*/ + { { 0xb8,0},{ 0xf0,0xb8,0} }, { { 0xb9,0},{ 0xf0,0xb9,0} }, { { 0xba,0},{ 0xf0,0xba,0} }, { { 0xbb,0},{ 0xf0,0xbb,0} }, /*0b8*/ + { { 0xbc,0},{ 0xf0,0xbc,0} }, { { 0xbd,0},{ 0xf0,0xbd,0} }, { { 0xbe,0},{ 0xf0,0xbe,0} }, { { 0xbf,0},{ 0xf0,0xbf,0} }, /*0bc*/ + { { 0xc0,0},{ 0xf0,0xc0,0} }, { { 0xc1,0},{ 0xf0,0xc1,0} }, { { 0xc2,0},{ 0xf0,0xc2,0} }, { { 0xc3,0},{ 0xf0,0xc3,0} }, /*0c0*/ + { { 0xc4,0},{ 0xf0,0xc4,0} }, { { 0xc5,0},{ 0xf0,0xc5,0} }, { { 0xc6,0},{ 0xf0,0xc6,0} }, { { 0xc7,0},{ 0xf0,0xc7,0} }, /*0c4*/ + { { 0xc8,0},{ 0xf0,0xc8,0} }, { { 0xc9,0},{ 0xf0,0xc9,0} }, { { 0xca,0},{ 0xf0,0xca,0} }, { { 0xcb,0},{ 0xf0,0xcb,0} }, /*0c8*/ + { { 0xcc,0},{ 0xf0,0xcc,0} }, { { 0xcd,0},{ 0xf0,0xcd,0} }, { { 0xce,0},{ 0xf0,0xce,0} }, { { 0xcf,0},{ 0xf0,0xcf,0} }, /*0cc*/ + { { 0xd0,0},{ 0xf0,0xd0,0} }, { { 0xd1,0},{ 0xf0,0xd0,0} }, { { 0xd2,0},{ 0xf0,0xd2,0} }, { { 0xd3,0},{ 0xf0,0xd3,0} }, /*0d0*/ + { { 0xd4,0},{ 0xf0,0xd4,0} }, { { 0xd5,0},{ 0xf0,0xd5,0} }, { { 0xd6,0},{ 0xf0,0xd6,0} }, { { 0xd7,0},{ 0xf0,0xd7,0} }, /*0d4*/ + { { 0xd8,0},{ 0xf0,0xd8,0} }, { { 0xd9,0},{ 0xf0,0xd9,0} }, { { 0xda,0},{ 0xf0,0xda,0} }, { { 0xdb,0},{ 0xf0,0xdb,0} }, /*0d8*/ + { { 0xdc,0},{ 0xf0,0xdc,0} }, { { 0xdd,0},{ 0xf0,0xdd,0} }, { { 0xde,0},{ 0xf0,0xde,0} }, { { 0xdf,0},{ 0xf0,0xdf,0} }, /*0dc*/ + { { 0xe0,0},{ 0xf0,0xe0,0} }, { { 0xe1,0},{ 0xf0,0xe1,0} }, { { 0xe2,0},{ 0xf0,0xe2,0} }, { { 0xe3,0},{ 0xf0,0xe3,0} }, /*0e0*/ + { { 0xe4,0},{ 0xf0,0xe4,0} }, { { 0xe5,0},{ 0xf0,0xe5,0} }, { { 0xe6,0},{ 0xf0,0xe6,0} }, { { 0xe7,0},{ 0xf0,0xe7,0} }, /*0e4*/ + { { 0xe8,0},{ 0xf0,0xe8,0} }, { { 0xe9,0},{ 0xf0,0xe9,0} }, { { 0xea,0},{ 0xf0,0xea,0} }, { { 0xeb,0},{ 0xf0,0xeb,0} }, /*0e8*/ + { { 0xec,0},{ 0xf0,0xec,0} }, { { 0xed,0},{ 0xf0,0xed,0} }, { { 0xee,0},{ 0xf0,0xee,0} }, { { 0xef,0},{ 0xf0,0xef,0} }, /*0ec*/ + { { 0},{ 0} }, { { 0xf1,0},{ 0xf0,0xf1,0} }, { { 0xf2,0},{ 0xf0,0xf2,0} }, { { 0xf3,0},{ 0xf0,0xf3,0} }, /*0f0*/ + { { 0xf4,0},{ 0xf0,0xf4,0} }, { { 0xf5,0},{ 0xf0,0xf5,0} }, { { 0xf6,0},{ 0xf0,0xf6,0} }, { { 0xf7,0},{ 0xf0,0xf7,0} }, /*0f4*/ + { { 0xf8,0},{ 0xf0,0xf8,0} }, { { 0xf9,0},{ 0xf0,0xf9,0} }, { { 0xfa,0},{ 0xf0,0xfa,0} }, { { 0xfb,0},{ 0xf0,0xfb,0} }, /*0f8*/ + { { 0xfc,0},{ 0xf0,0xfc,0} }, { { 0xfd,0},{ 0xf0,0xfd,0} }, { { 0xfe,0},{ 0xf0,0xfe,0} }, { { 0xff,0},{ 0xf0,0xff,0} }, /*0fc*/ + + { {0xe1,0x14,0},{0xe1,0xf0,0x14,0} }, { {0xe0,0x76,0},{0xe0,0xF0,0x76,0} }, { {0xe0,0x16,0},{0xe0,0xF0,0x16,0} }, { {0xe0,0x1E,0},{0xe0,0xF0,0x1E,0} }, /*100*/ + { {0xe0,0x26,0},{0xe0,0xF0,0x26,0} }, { {0xe0,0x25,0},{0xe0,0xF0,0x25,0} }, { {0xe0,0x2E,0},{0xe0,0xF0,0x2E,0} }, { {0xe0,0x36,0},{0xe0,0xF0,0x36,0} }, /*104*/ + { {0xe0,0x3D,0},{0xe0,0xF0,0x3D,0} }, { {0xe0,0x3E,0},{0xe0,0xF0,0x3E,0} }, { {0xe0,0x46,0},{0xe0,0xF0,0x46,0} }, { {0xe0,0x45,0},{0xe0,0xF0,0x45,0} }, /*108*/ + { {0xe0,0x4E,0},{0xe0,0xF0,0x4E,0} }, { { 0},{ 0} }, { {0xe0,0x66,0},{0xe0,0xF0,0x66,0} }, { {0xe0,0x0D,0},{0xe0,0xF0,0x0D,0} }, /*10c*/ + { {0xe0,0x15,0},{0xe0,0xF0,0x15,0} }, { {0xe0,0x1D,0},{0xe0,0xF0,0x1D,0} }, { {0xe0,0x24,0},{0xe0,0xF0,0x24,0} }, { {0xe0,0x2D,0},{0xe0,0xF0,0x2D,0} }, /*110*/ + { {0xe0,0x2C,0},{0xe0,0xF0,0x2C,0} }, { {0xe0,0x35,0},{0xe0,0xF0,0x35,0} }, { {0xe0,0x3C,0},{0xe0,0xF0,0x3C,0} }, { {0xe0,0x43,0},{0xe0,0xF0,0x43,0} }, /*114*/ + { {0xe0,0x44,0},{0xe0,0xF0,0x44,0} }, { {0xe0,0x4D,0},{0xe0,0xF0,0x4D,0} }, { {0xe0,0x54,0},{0xe0,0xF0,0x54,0} }, { {0xe0,0x5B,0},{0xe0,0xF0,0x5B,0} }, /*118*/ + { {0xe0,0x5A,0},{0xe0,0xF0,0x5A,0} }, { {0xe0,0x14,0},{0xe0,0xF0,0x14,0} }, { {0xe0,0x1C,0},{0xe0,0xF0,0x1C,0} }, { {0xe0,0x1B,0},{0xe0,0xF0,0x1B,0} }, /*11c*/ + { {0xe0,0x23,0},{0xe0,0xF0,0x23,0} }, { {0xe0,0x2B,0},{0xe0,0xF0,0x2B,0} }, { {0xe0,0x34,0},{0xe0,0xF0,0x34,0} }, { {0xe0,0x33,0},{0xe0,0xF0,0x33,0} }, /*120*/ + { {0xe0,0x3B,0},{0xe0,0xF0,0x3B,0} }, { {0xe0,0x42,0},{0xe0,0xF0,0x42,0} }, { {0xe0,0x4B,0},{0xe0,0xF0,0x4B,0} }, { { 0},{ 0} }, /*124*/ + { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*128*/ + { {0xe0,0x1A,0},{0xe0,0xF0,0x1A,0} }, { {0xe0,0x22,0},{0xe0,0xF0,0x22,0} }, { {0xe0,0x21,0},{0xe0,0xF0,0x21,0} }, { {0xe0,0x2A,0},{0xe0,0xF0,0x2A,0} }, /*12c*/ + { {0xe0,0x32,0},{0xe0,0xF0,0x32,0} }, { {0xe0,0x31,0},{0xe0,0xF0,0x31,0} }, { {0xe0,0x3A,0},{0xe0,0xF0,0x3A,0} }, { { 0},{ 0} }, /*130*/ + { {0xe0,0x49,0},{0xe0,0xF0,0x49,0} }, { {0xe0,0x4A,0},{0xe0,0xF0,0x4A,0} }, { { 0},{ 0} }, { {0xe0,0x7C,0},{0xe0,0xF0,0x7C,0} }, /*134*/ + { {0xe0,0x11,0},{0xe0,0xF0,0x11,0} }, { { 0},{ 0} }, { {0xe0,0x58,0},{0xe0,0xF0,0x58,0} }, { {0xe0,0x05,0},{0xe0,0xF0,0x05,0} }, /*138*/ + { {0xe0,0x06,0},{0xe0,0xF0,0x06,0} }, { {0xe0,0x04,0},{0xe0,0xF0,0x04,0} }, { {0xe0,0x0C,0},{0xe0,0xF0,0x0C,0} }, { {0xe0,0x03,0},{0xe0,0xF0,0x03,0} }, /*13c*/ + { {0xe0,0x0B,0},{0xe0,0xF0,0x0B,0} }, { {0xe0,0x02,0},{0xe0,0xF0,0x02,0} }, { {0xe0,0x0A,0},{0xe0,0xF0,0x0A,0} }, { {0xe0,0x01,0},{0xe0,0xF0,0x01,0} }, /*140*/ + { {0xe0,0x09,0},{0xe0,0xF0,0x09,0} }, { { 0},{ 0} }, { {0xe0,0x7E,0},{0xe0,0xF0,0x7E,0} }, { {0xe0,0x6C,0},{0xe0,0xF0,0x6C,0} }, /*144*/ + { {0xe0,0x75,0},{0xe0,0xF0,0x75,0} }, { {0xe0,0x7D,0},{0xe0,0xF0,0x7D,0} }, { { 0},{ 0} }, { {0xe0,0x6B,0},{0xe0,0xF0,0x6B,0} }, /*148*/ + { {0xe0,0x73,0},{0xe0,0xF0,0x73,0} }, { {0xe0,0x74,0},{0xe0,0xF0,0x74,0} }, { {0xe0,0x79,0},{0xe0,0xF0,0x79,0} }, { {0xe0,0x69,0},{0xe0,0xF0,0x69,0} }, /*14c*/ + { {0xe0,0x72,0},{0xe0,0xF0,0x72,0} }, { {0xe0,0x7A,0},{0xe0,0xF0,0x7A,0} }, { {0xe0,0x70,0},{0xe0,0xF0,0x70,0} }, { {0xe0,0x71,0},{0xe0,0xF0,0x71,0} }, /*150*/ + { { 0},{ 0} }, { {0xe0,0x60,0},{0xe0,0xF0,0x60,0} }, { { 0},{ 0} }, { {0xe0,0x78,0},{0xe0,0xF0,0x78,0} }, /*154*/ + { {0xe0,0x07,0},{0xe0,0xF0,0x07,0} }, { {0xe0,0x0F,0},{0xe0,0xF0,0x0F,0} }, { {0xe0,0x17,0},{0xe0,0xF0,0x17,0} }, { {0xe0,0x1F,0},{0xe0,0xF0,0x1F,0} }, /*158*/ + { {0xe0,0x27,0},{0xe0,0xF0,0x27,0} }, { {0xe0,0x2F,0},{0xe0,0xF0,0x2F,0} }, { {0xe0,0x37,0},{0xe0,0xF0,0x37,0} }, { {0xe0,0x3F,0},{0xe0,0xF0,0x3F,0} }, /*15c*/ + { { 0},{ 0} }, { {0xe0,0x4F,0},{0xe0,0xF0,0x4F,0} }, { {0xe0,0x56,0},{0xe0,0xF0,0x56,0} }, { {0xe0,0x5E,0},{0xe0,0xF0,0x5E,0} }, /*160*/ + { {0xe0,0x08,0},{0xe0,0xF0,0x08,0} }, { {0xe0,0x10,0},{0xe0,0xF0,0x10,0} }, { {0xe0,0x18,0},{0xe0,0xF0,0x18,0} }, { {0xe0,0x20,0},{0xe0,0xF0,0x20,0} }, /*164*/ + { {0xe0,0x28,0},{0xe0,0xF0,0x28,0} }, { {0xe0,0x30,0},{0xe0,0xF0,0x30,0} }, { {0xe0,0x38,0},{0xe0,0xF0,0x38,0} }, { {0xe0,0x40,0},{0xe0,0xF0,0x40,0} }, /*168*/ + { {0xe0,0x48,0},{0xe0,0xF0,0x48,0} }, { {0xe0,0x50,0},{0xe0,0xF0,0x50,0} }, { {0xe0,0x57,0},{0xe0,0xF0,0x57,0} }, { { 0},{ 0} }, /*16c*/ + { {0xe0,0x13,0},{0xe0,0xF0,0x13,0} }, { {0xe0,0x19,0},{0xe0,0xF0,0x19,0} }, { {0xe0,0x39,0},{0xe0,0xF0,0x39,0} }, { {0xe0,0x51,0},{0xe0,0xF0,0x51,0} }, /*170*/ + { {0xe0,0x53,0},{0xe0,0xF0,0x53,0} }, { {0xe0,0x5C,0},{0xe0,0xF0,0x5C,0} }, { { 0},{ 0} }, { {0xe0,0x62,0},{0xe0,0xF0,0x62,0} }, /*174*/ + { {0xe0,0x63,0},{0xe0,0xF0,0x63,0} }, { {0xe0,0x64,0},{0xe0,0xF0,0x64,0} }, { {0xe0,0x65,0},{0xe0,0xF0,0x65,0} }, { {0xe0,0x67,0},{0xe0,0xF0,0x67,0} }, /*178*/ + { {0xe0,0x68,0},{0xe0,0xF0,0x68,0} }, { {0xe0,0x6A,0},{0xe0,0xF0,0x6A,0} }, { {0xe0,0x6D,0},{0xe0,0xF0,0x6D,0} }, { {0xe0,0x6E,0},{0xe0,0xF0,0x6E,0} }, /*17c*/ + + { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*180*/ + { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*184*/ + { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*188*/ + { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*18c*/ + { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*190*/ + { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*194*/ + { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*198*/ + { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*19c*/ + { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*1a0*/ + { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*1a4*/ + { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*1a8*/ + { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*1ac*/ + { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*1c0*/ + { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*1c4*/ + { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*1c8*/ + { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*1cc*/ + { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*1d0*/ + { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*1d4*/ + { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*1d8*/ + { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*1dc*/ + { { 0},{ 0} }, { {0xe0,0xe1,0},{0xe0,0xF0,0xE1,0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*1e0*/ + { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*1e4*/ + { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*1e8*/ + { { 0},{ 0} }, { { 0},{ 0} }, { {0xe0,0xee,0},{0xe0,0xF0,0xEE,0} }, { { 0},{ 0} }, /*1ec*/ + { { 0},{ 0} }, { {0xe0,0xf1,0},{0xe0,0xF0,0xF1,0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*1f0*/ + { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*1f4*/ + { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*1f8*/ + { { 0},{ 0} }, { { 0},{ 0} }, { {0xe0,0xfe,0},{0xe0,0xF0,0xFE,0} }, { {0xe0,0xff,0},{0xe0,0xF0,0xFF,0} } /*1fc*/ + // clang-format on +}; + +static const scancode scancode_set3[512] = { + // clang-format off + { { 0},{ 0} }, { { 0x08,0},{ 0xf0,0x08,0} }, { { 0x16,0},{ 0xf0,0x16,0} }, { { 0x1E,0},{ 0xf0,0x1E,0} }, /*000*/ + { { 0x26,0},{ 0xf0,0x26,0} }, { { 0x25,0},{ 0xf0,0x25,0} }, { { 0x2E,0},{ 0xf0,0x2E,0} }, { { 0x36,0},{ 0xf0,0x36,0} }, /*004*/ + { { 0x3D,0},{ 0xf0,0x3D,0} }, { { 0x3E,0},{ 0xf0,0x3E,0} }, { { 0x46,0},{ 0xf0,0x46,0} }, { { 0x45,0},{ 0xf0,0x45,0} }, /*008*/ + { { 0x4E,0},{ 0xf0,0x4E,0} }, { { 0x55,0},{ 0xf0,0x55,0} }, { { 0x66,0},{ 0xf0,0x66,0} }, { { 0x0D,0},{ 0xf0,0x0D,0} }, /*00c*/ + { { 0x15,0},{ 0xf0,0x15,0} }, { { 0x1D,0},{ 0xf0,0x1D,0} }, { { 0x24,0},{ 0xf0,0x24,0} }, { { 0x2D,0},{ 0xf0,0x2D,0} }, /*010*/ + { { 0x2C,0},{ 0xf0,0x2C,0} }, { { 0x35,0},{ 0xf0,0x35,0} }, { { 0x3C,0},{ 0xf0,0x3C,0} }, { { 0x43,0},{ 0xf0,0x43,0} }, /*014*/ + { { 0x44,0},{ 0xf0,0x44,0} }, { { 0x4D,0},{ 0xf0,0x4D,0} }, { { 0x54,0},{ 0xf0,0x54,0} }, { { 0x5B,0},{ 0xf0,0x5B,0} }, /*018*/ + { { 0x5A,0},{ 0xf0,0x5A,0} }, { { 0x11,0},{ 0xf0,0x11,0} }, { { 0x1C,0},{ 0xf0,0x1C,0} }, { { 0x1B,0},{ 0xf0,0x1B,0} }, /*01c*/ + { { 0x23,0},{ 0xf0,0x23,0} }, { { 0x2B,0},{ 0xf0,0x2B,0} }, { { 0x34,0},{ 0xf0,0x34,0} }, { { 0x33,0},{ 0xf0,0x33,0} }, /*020*/ + { { 0x3B,0},{ 0xf0,0x3B,0} }, { { 0x42,0},{ 0xf0,0x42,0} }, { { 0x4B,0},{ 0xf0,0x4B,0} }, { { 0x4C,0},{ 0xf0,0x4C,0} }, /*024*/ + { { 0x52,0},{ 0xf0,0x52,0} }, { { 0x0E,0},{ 0xf0,0x0E,0} }, { { 0x12,0},{ 0xf0,0x12,0} }, { { 0x5C,0},{ 0xf0,0x5C,0} }, /*028*/ + { { 0x1A,0},{ 0xf0,0x1A,0} }, { { 0x22,0},{ 0xf0,0x22,0} }, { { 0x21,0},{ 0xf0,0x21,0} }, { { 0x2A,0},{ 0xf0,0x2A,0} }, /*02c*/ + { { 0x32,0},{ 0xf0,0x32,0} }, { { 0x31,0},{ 0xf0,0x31,0} }, { { 0x3A,0},{ 0xf0,0x3A,0} }, { { 0x41,0},{ 0xf0,0x41,0} }, /*030*/ + { { 0x49,0},{ 0xf0,0x49,0} }, { { 0x4A,0},{ 0xf0,0x4A,0} }, { { 0x59,0},{ 0xf0,0x59,0} }, { { 0x7E,0},{ 0xf0,0x7E,0} }, /*034*/ + { { 0x19,0},{ 0xf0,0x19,0} }, { { 0x29,0},{ 0xf0,0x29,0} }, { { 0x14,0},{ 0xf0,0x14,0} }, { { 0x07,0},{ 0xf0,0x07,0} }, /*038*/ + { { 0x0F,0},{ 0xf0,0x0F,0} }, { { 0x17,0},{ 0xf0,0x17,0} }, { { 0x1F,0},{ 0xf0,0x1F,0} }, { { 0x27,0},{ 0xf0,0x27,0} }, /*03c*/ + { { 0x2F,0},{ 0xf0,0x2F,0} }, { { 0x37,0},{ 0xf0,0x37,0} }, { { 0x3F,0},{ 0xf0,0x3F,0} }, { { 0x47,0},{ 0xf0,0x47,0} }, /*040*/ + { { 0x4F,0},{ 0xf0,0x4F,0} }, { { 0x76,0},{ 0xf0,0x76,0} }, { { 0x5F,0},{ 0xf0,0x5F,0} }, { { 0x6C,0},{ 0xf0,0x6C,0} }, /*044*/ + { { 0x75,0},{ 0xf0,0x75,0} }, { { 0x7D,0},{ 0xf0,0x7D,0} }, { { 0x84,0},{ 0xf0,0x84,0} }, { { 0x6B,0},{ 0xf0,0x6B,0} }, /*048*/ + { { 0x73,0},{ 0xf0,0x73,0} }, { { 0x74,0},{ 0xf0,0x74,0} }, { { 0x7C,0},{ 0xf0,0x7C,0} }, { { 0x69,0},{ 0xf0,0x69,0} }, /*04c*/ + { { 0x72,0},{ 0xf0,0x72,0} }, { { 0x7A,0},{ 0xf0,0x7A,0} }, { { 0x70,0},{ 0xf0,0x70,0} }, { { 0x71,0},{ 0xf0,0x71,0} }, /*050*/ + { { 0x57,0},{ 0xf0,0x57,0} }, { { 0x60,0},{ 0xf0,0x60,0} }, { { 0},{ 0} }, { { 0x56,0},{ 0xf0,0x56,0} }, /*054*/ + { { 0x5E,0},{ 0xf0,0x5E,0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*058*/ + { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*05c*/ + { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*060*/ + { { 0},{ 0} }, { { 0x10,0},{ 0xf0,0x10,0} }, { { 0x18,0},{ 0xf0,0x18,0} }, { { 0x20,0},{ 0xf0,0x20,0} }, /*064*/ + { { 0x28,0},{ 0xf0,0x28,0} }, { { 0x30,0},{ 0xf0,0x30,0} }, { { 0x38,0},{ 0xf0,0x38,0} }, { { 0x40,0},{ 0xf0,0x40,0} }, /*068*/ + { { 0x48,0},{ 0xf0,0x48,0} }, { { 0x50,0},{ 0xf0,0x50,0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*06c*/ + { { 0x87,0},{ 0xf0,0x87,0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0x51,0},{ 0xf0,0x51,0} }, /*070*/ + { { 0x53,0},{ 0xf0,0x53,0} }, { { 0x5C,0},{ 0xf0,0x5C,0} }, { { 0},{ 0} }, { { 0x62,0},{ 0xf0,0x62,0} }, /*074*/ + { { 0x63,0},{ 0xf0,0x63,0} }, { { 0x86,0},{ 0xf0,0x86,0} }, { { 0},{ 0} }, { { 0x85,0},{ 0xf0,0x85,0} }, /*078*/ + { { 0x68,0},{ 0xf0,0x68,0} }, { { 0x13,0},{ 0xf0,0x13,0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*07c*/ + + { { 0x80,0},{ 0xf0,0x80,0} }, { { 0x81,0},{ 0xf0,0x81,0} }, { { 0x82,0},{ 0xf0,0x82,0} }, { { 0},{ 0} }, /*080*/ + { { 0},{ 0} }, { { 0x85,0},{ 0xf0,0x54,0} }, { { 0x86,0},{ 0xf0,0x86,0} }, { { 0x87,0},{ 0xf0,0x87,0} }, /*084*/ + { { 0x88,0},{ 0xf0,0x88,0} }, { { 0x89,0},{ 0xf0,0x89,0} }, { { 0x8a,0},{ 0xf0,0x8a,0} }, { { 0x8b,0},{ 0xf0,0x8b,0} }, /*088*/ + { { 0},{ 0} }, { { 0},{ 0} }, { { 0x8e,0},{ 0xf0,0x8e,0} }, { { 0x8f,0},{ 0xf0,0x8f,0} }, /*08c*/ + { { 0x90,0},{ 0xf0,0x90,0} }, { { 0x91,0},{ 0xf0,0x91,0} }, { { 0x92,0},{ 0xf0,0x92,0} }, { { 0x93,0},{ 0xf0,0x93,0} }, /*090*/ + { { 0x94,0},{ 0xf0,0x94,0} }, { { 0x95,0},{ 0xf0,0x95,0} }, { { 0x96,0},{ 0xf0,0x96,0} }, { { 0x97,0},{ 0xf0,0x97,0} }, /*094*/ + { { 0x98,0},{ 0xf0,0x98,0} }, { { 0x99,0},{ 0xf0,0x99,0} }, { { 0x9a,0},{ 0xf0,0x9a,0} }, { { 0x9b,0},{ 0xf0,0x9b,0} }, /*098*/ + { { 0x9c,0},{ 0xf0,0x9c,0} }, { { 0x9d,0},{ 0xf0,0x9d,0} }, { { 0x9e,0},{ 0xf0,0x9e,0} }, { { 0x9f,0},{ 0xf0,0x9f,0} }, /*09c*/ + { { 0xa0,0},{ 0xf0,0xa0,0} }, { { 0xa1,0},{ 0xf0,0xa1,0} }, { { 0xa2,0},{ 0xf0,0xa2,0} }, { { 0xa3,0},{ 0xf0,0xa3,0} }, /*0a0*/ + { { 0xa4,0},{ 0xf0,0xa4,0} }, { { 0xa5,0},{ 0xf0,0xa5,0} }, { { 0xa6,0},{ 0xf0,0xa6,0} }, { { 0xa7,0},{ 0xf0,0xa7,0} }, /*0a4*/ + { { 0xa8,0},{ 0xf0,0xa8,0} }, { { 0xa9,0},{ 0xf0,0xa9,0} }, { { 0xaa,0},{ 0xf0,0xaa,0} }, { { 0xab,0},{ 0xf0,0xab,0} }, /*0a8*/ + { { 0xac,0},{ 0xf0,0xac,0} }, { { 0xad,0},{ 0xf0,0xad,0} }, { { 0xae,0},{ 0xf0,0xae,0} }, { { 0xaf,0},{ 0xf0,0xaf,0} }, /*0ac*/ + { { 0xb0,0},{ 0xf0,0xb0,0} }, { { 0xb1,0},{ 0xf0,0xb1,0} }, { { 0xb2,0},{ 0xf0,0xb2,0} }, { { 0xb3,0},{ 0xf0,0xb3,0} }, /*0b0*/ + { { 0xb4,0},{ 0xf0,0xb4,0} }, { { 0xb5,0},{ 0xf0,0xb5,0} }, { { 0xb6,0},{ 0xf0,0xb6,0} }, { { 0xb7,0},{ 0xf0,0xb7,0} }, /*0b4*/ + { { 0xb8,0},{ 0xf0,0xb8,0} }, { { 0xb9,0},{ 0xf0,0xb9,0} }, { { 0xba,0},{ 0xf0,0xba,0} }, { { 0xbb,0},{ 0xf0,0xbb,0} }, /*0b8*/ + { { 0xbc,0},{ 0xf0,0xbc,0} }, { { 0xbd,0},{ 0xf0,0xbd,0} }, { { 0xbe,0},{ 0xf0,0xbe,0} }, { { 0xbf,0},{ 0xf0,0xbf,0} }, /*0bc*/ + { { 0xc0,0},{ 0xf0,0xc0,0} }, { { 0xc1,0},{ 0xf0,0xc1,0} }, { { 0xc2,0},{ 0xf0,0xc2,0} }, { { 0xc3,0},{ 0xf0,0xc3,0} }, /*0c0*/ + { { 0xc4,0},{ 0xf0,0xc4,0} }, { { 0xc5,0},{ 0xf0,0xc5,0} }, { { 0xc6,0},{ 0xf0,0xc6,0} }, { { 0xc7,0},{ 0xf0,0xc7,0} }, /*0c4*/ + { { 0xc8,0},{ 0xf0,0xc8,0} }, { { 0xc9,0},{ 0xf0,0xc9,0} }, { { 0xca,0},{ 0xf0,0xca,0} }, { { 0xcb,0},{ 0xf0,0xcb,0} }, /*0c8*/ + { { 0xcc,0},{ 0xf0,0xcc,0} }, { { 0xcd,0},{ 0xf0,0xcd,0} }, { { 0xce,0},{ 0xf0,0xce,0} }, { { 0xcf,0},{ 0xf0,0xcf,0} }, /*0cc*/ + { { 0xd0,0},{ 0xf0,0xd0,0} }, { { 0xd1,0},{ 0xf0,0xd0,0} }, { { 0xd2,0},{ 0xf0,0xd2,0} }, { { 0xd3,0},{ 0xf0,0xd3,0} }, /*0d0*/ + { { 0xd4,0},{ 0xf0,0xd4,0} }, { { 0xd5,0},{ 0xf0,0xd5,0} }, { { 0xd6,0},{ 0xf0,0xd6,0} }, { { 0xd7,0},{ 0xf0,0xd7,0} }, /*0d4*/ + { { 0xd8,0},{ 0xf0,0xd8,0} }, { { 0xd9,0},{ 0xf0,0xd9,0} }, { { 0xda,0},{ 0xf0,0xda,0} }, { { 0xdb,0},{ 0xf0,0xdb,0} }, /*0d8*/ + { { 0xdc,0},{ 0xf0,0xdc,0} }, { { 0xdd,0},{ 0xf0,0xdd,0} }, { { 0xde,0},{ 0xf0,0xde,0} }, { { 0xdf,0},{ 0xf0,0xdf,0} }, /*0dc*/ + { { 0xe0,0},{ 0xf0,0xe0,0} }, { { 0xe1,0},{ 0xf0,0xe1,0} }, { { 0xe2,0},{ 0xf0,0xe2,0} }, { { 0xe3,0},{ 0xf0,0xe3,0} }, /*0e0*/ + { { 0xe4,0},{ 0xf0,0xe4,0} }, { { 0xe5,0},{ 0xf0,0xe5,0} }, { { 0xe6,0},{ 0xf0,0xe6,0} }, { { 0xe7,0},{ 0xf0,0xe7,0} }, /*0e4*/ + { { 0xe8,0},{ 0xf0,0xe8,0} }, { { 0xe9,0},{ 0xf0,0xe9,0} }, { { 0xea,0},{ 0xf0,0xea,0} }, { { 0xeb,0},{ 0xf0,0xeb,0} }, /*0e8*/ + { { 0xec,0},{ 0xf0,0xec,0} }, { { 0xed,0},{ 0xf0,0xed,0} }, { { 0xee,0},{ 0xf0,0xee,0} }, { { 0xef,0},{ 0xf0,0xef,0} }, /*0ec*/ + { { 0},{ 0} }, { { 0xf1,0},{ 0xf0,0xf1,0} }, { { 0xf2,0},{ 0xf0,0xf2,0} }, { { 0xf3,0},{ 0xf0,0xf3,0} }, /*0f0*/ + { { 0xf4,0},{ 0xf0,0xf4,0} }, { { 0xf5,0},{ 0xf0,0xf5,0} }, { { 0xf6,0},{ 0xf0,0xf6,0} }, { { 0xf7,0},{ 0xf0,0xf7,0} }, /*0f4*/ + { { 0xf8,0},{ 0xf0,0xf8,0} }, { { 0xf9,0},{ 0xf0,0xf9,0} }, { { 0xfa,0},{ 0xf0,0xfa,0} }, { { 0xfb,0},{ 0xf0,0xfb,0} }, /*0f8*/ + { { 0xfc,0},{ 0xf0,0xfc,0} }, { { 0xfd,0},{ 0xf0,0xfd,0} }, { { 0xfe,0},{ 0xf0,0xfe,0} }, { { 0xff,0},{ 0xf0,0xff,0} }, /*0fc*/ + + { { 0x62,0},{ 0xF0,0x62,0} }, { {0xe0,0x76,0},{0xe0,0xF0,0x76,0} }, { {0xe0,0x16,0},{0xe0,0xF0,0x16,0} }, { {0xe0,0x1E,0},{0xe0,0xF0,0x1E,0} }, /*100*/ + { {0xe0,0x26,0},{0xe0,0xF0,0x26,0} }, { {0xe0,0x25,0},{0xe0,0xF0,0x25,0} }, { {0xe0,0x2E,0},{0xe0,0xF0,0x2E,0} }, { {0xe0,0x36,0},{0xe0,0xF0,0x36,0} }, /*104*/ + { {0xe0,0x3D,0},{0xe0,0xF0,0x3D,0} }, { {0xe0,0x3E,0},{0xe0,0xF0,0x3E,0} }, { {0xe0,0x46,0},{0xe0,0xF0,0x46,0} }, { {0xe0,0x45,0},{0xe0,0xF0,0x45,0} }, /*108*/ + { {0xe0,0x4E,0},{0xe0,0xF0,0x4E,0} }, { { 0},{ 0} }, { {0xe0,0x66,0},{0xe0,0xF0,0x66,0} }, { {0xe0,0x0D,0},{0xe0,0xF0,0x0D,0} }, /*10c*/ + { {0xe0,0x15,0},{0xe0,0xF0,0x15,0} }, { {0xe0,0x1D,0},{0xe0,0xF0,0x1D,0} }, { {0xe0,0x24,0},{0xe0,0xF0,0x24,0} }, { {0xe0,0x2D,0},{0xe0,0xF0,0x2D,0} }, /*110*/ + { {0xe0,0x2C,0},{0xe0,0xF0,0x2C,0} }, { {0xe0,0x35,0},{0xe0,0xF0,0x35,0} }, { {0xe0,0x3C,0},{0xe0,0xF0,0x3C,0} }, { {0xe0,0x43,0},{0xe0,0xF0,0x43,0} }, /*114*/ + { {0xe0,0x44,0},{0xe0,0xF0,0x44,0} }, { {0xe0,0x4D,0},{0xe0,0xF0,0x4D,0} }, { {0xe0,0x54,0},{0xe0,0xF0,0x54,0} }, { {0xe0,0x5B,0},{0xe0,0xF0,0x5B,0} }, /*118*/ + { { 0x79,0},{ 0xf0,0x79,0} }, { { 0x58,0},{ 0xf0,0x58,0} }, { {0xe0,0x1C,0},{0xe0,0xF0,0x1C,0} }, { {0xe0,0x1B,0},{0xe0,0xF0,0x1B,0} }, /*11c*/ + { {0xe0,0x23,0},{0xe0,0xF0,0x23,0} }, { {0xe0,0x2B,0},{0xe0,0xF0,0x2B,0} }, { {0xe0,0x34,0},{0xe0,0xF0,0x34,0} }, { {0xe0,0x33,0},{0xe0,0xF0,0x33,0} }, /*120*/ + { {0xe0,0x3B,0},{0xe0,0xF0,0x3B,0} }, { {0xe0,0x42,0},{0xe0,0xF0,0x42,0} }, { {0xe0,0x4B,0},{0xe0,0xF0,0x4B,0} }, { { 0},{ 0} }, /*124*/ + { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*128*/ + { {0xe0,0x1A,0},{0xe0,0xF0,0x1A,0} }, { {0xe0,0x22,0},{0xe0,0xF0,0x22,0} }, { {0xe0,0x21,0},{0xe0,0xF0,0x21,0} }, { {0xe0,0x2A,0},{0xe0,0xF0,0x2A,0} }, /*12c*/ + { {0xe0,0x32,0},{0xe0,0xF0,0x32,0} }, { {0xe0,0x31,0},{0xe0,0xF0,0x31,0} }, { {0xe0,0x3A,0},{0xe0,0xF0,0x3A,0} }, { { 0},{ 0} }, /*130*/ + { {0xe0,0x49,0},{0xe0,0xF0,0x49,0} }, { { 0x77,0},{ 0xf0,0x77,0} }, { { 0},{ 0} }, { { 0x57,0},{ 0xf0,0x57,0} }, /*134*/ + { { 0x39,0},{ 0xf0,0x39,0} }, { { 0},{ 0} }, { {0xe0,0x58,0},{0xe0,0xF0,0x58,0} }, { {0xe0,0x05,0},{0xe0,0xF0,0x05,0} }, /*138*/ + { {0xe0,0x06,0},{0xe0,0xF0,0x06,0} }, { {0xe0,0x04,0},{0xe0,0xF0,0x04,0} }, { {0xe0,0x0C,0},{0xe0,0xF0,0x0C,0} }, { {0xe0,0x03,0},{0xe0,0xF0,0x03,0} }, /*13c*/ + { {0xe0,0x0B,0},{0xe0,0xF0,0x0B,0} }, { {0xe0,0x02,0},{0xe0,0xF0,0x02,0} }, { {0xe0,0x0A,0},{0xe0,0xF0,0x0A,0} }, { {0xe0,0x01,0},{0xe0,0xF0,0x01,0} }, /*140*/ + { {0xe0,0x09,0},{0xe0,0xF0,0x09,0} }, { { 0},{ 0} }, { {0xe0,0x7E,0},{0xe0,0xF0,0x7E,0} }, { { 0x6E,0},{ 0xf0,0x6E,0} }, /*144*/ + { { 0x63,0},{ 0xf0,0x63,0} }, { { 0x6F,0},{ 0xf0,0x6F,0} }, { { 0},{ 0} }, { { 0x61,0},{ 0xf0,0x61,0} }, /*148*/ + { {0xe0,0x73,0},{0xe0,0xF0,0x73,0} }, { { 0x6A,0},{ 0xf0,0x6A,0} }, { {0xe0,0x79,0},{0xe0,0xF0,0x79,0} }, { { 0x65,0},{ 0xf0,0x65,0} }, /*14c*/ + { { 0x60,0},{ 0xf0,0x60,0} }, { { 0x6D,0},{ 0xf0,0x6D,0} }, { { 0x67,0},{ 0xf0,0x67,0} }, { { 0x64,0},{ 0xf0,0x64,0} }, /*150*/ + { { 0xd4,0},{ 0xf0,0xD4,0} }, { {0xe0,0x60,0},{0xe0,0xF0,0x60,0} }, { { 0},{ 0} }, { {0xe0,0x78,0},{0xe0,0xF0,0x78,0} }, /*154*/ + { {0xe0,0x07,0},{0xe0,0xF0,0x07,0} }, { {0xe0,0x0F,0},{0xe0,0xF0,0x0F,0} }, { {0xe0,0x17,0},{0xe0,0xF0,0x17,0} }, { { 0x8B,0},{ 0xf0,0x8B,0} }, /*158*/ + { { 0x8C,0},{ 0xf0,0x8C,0} }, { { 0x8D,0},{ 0xf0,0x8D,0} }, { { 0},{ 0} }, { { 0x7F,0},{ 0xf0,0x7F,0} }, /*15c*/ + { { 0},{ 0} }, { {0xe0,0x4F,0},{0xe0,0xF0,0x4F,0} }, { {0xe0,0x56,0},{0xe0,0xF0,0x56,0} }, { { 0},{ 0} }, /*160*/ + { {0xe0,0x08,0},{0xe0,0xF0,0x08,0} }, { {0xe0,0x10,0},{0xe0,0xF0,0x10,0} }, { {0xe0,0x18,0},{0xe0,0xF0,0x18,0} }, { {0xe0,0x20,0},{0xe0,0xF0,0x20,0} }, /*164*/ + { {0xe0,0x28,0},{0xe0,0xF0,0x28,0} }, { {0xe0,0x30,0},{0xe0,0xF0,0x30,0} }, { {0xe0,0x38,0},{0xe0,0xF0,0x38,0} }, { {0xe0,0x40,0},{0xe0,0xF0,0x40,0} }, /*168*/ + { {0xe0,0x48,0},{0xe0,0xF0,0x48,0} }, { {0xe0,0x50,0},{0xe0,0xF0,0x50,0} }, { {0xe0,0x57,0},{0xe0,0xF0,0x57,0} }, { { 0},{ 0} }, /*16c*/ + { {0xe0,0x13,0},{0xe0,0xF0,0x13,0} }, { {0xe0,0x19,0},{0xe0,0xF0,0x19,0} }, { {0xe0,0x39,0},{0xe0,0xF0,0x39,0} }, { {0xe0,0x51,0},{0xe0,0xF0,0x51,0} }, /*170*/ + { {0xe0,0x53,0},{0xe0,0xF0,0x53,0} }, { {0xe0,0x5C,0},{0xe0,0xF0,0x5C,0} }, { { 0},{ 0} }, { {0xe0,0x62,0},{0xe0,0xF0,0x62,0} }, /*174*/ + { {0xe0,0x63,0},{0xe0,0xF0,0x63,0} }, { {0xe0,0x64,0},{0xe0,0xF0,0x64,0} }, { {0xe0,0x65,0},{0xe0,0xF0,0x65,0} }, { {0xe0,0x67,0},{0xe0,0xF0,0x67,0} }, /*178*/ + { {0xe0,0x68,0},{0xe0,0xF0,0x68,0} }, { {0xe0,0x6A,0},{0xe0,0xF0,0x6A,0} }, { {0xe0,0x6D,0},{0xe0,0xF0,0x6D,0} }, { {0xe0,0x6E,0},{0xe0,0xF0,0x6E,0} }, /*17c*/ + + { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*180*/ + { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*184*/ + { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*188*/ + { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*18c*/ + { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*190*/ + { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*194*/ + { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*198*/ + { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*19c*/ + { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*1a0*/ + { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*1a4*/ + { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*1a8*/ + { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*1ac*/ + { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*1c0*/ + { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*1c4*/ + { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*1c8*/ + { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*1cc*/ + { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*1d0*/ + { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*1d4*/ + { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*1d8*/ + { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*1dc*/ + { { 0},{ 0} }, { {0xe0,0xe1,0},{0xe0,0xF0,0xE1,0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*1e0*/ + { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*1e4*/ + { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*1e8*/ + { { 0},{ 0} }, { { 0},{ 0} }, { {0xe0,0xee,0},{0xe0,0xF0,0xEE,0} }, { { 0},{ 0} }, /*1ec*/ + { { 0},{ 0} }, { {0xe0,0xf1,0},{0xe0,0xF0,0xF1,0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*1f0*/ + { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*1f4*/ + { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*1f8*/ + { { 0},{ 0} }, { { 0},{ 0} }, { {0xe0,0xfe,0},{0xe0,0xF0,0xFE,0} }, { {0xe0,0xff,0},{0xe0,0xF0,0xFF,0} } /*1fc*/ + // clang-format on +}; + +// #define ENABLE_KEYBOARD_AT_LOG 1 +#ifdef ENABLE_KEYBOARD_AT_LOG +int keyboard_at_do_log = ENABLE_KEYBOARD_AT_LOG; + +static void +kbd_log(const char *fmt, ...) +{ + va_list ap; + + if (keyboard_at_do_log) { + va_start(ap, fmt); + pclog_ex(fmt, ap); + va_end(ap); + } +} +#else +# define kbd_log(fmt, ...) +#endif + +static void +set_scancode_map(atkbd_t *dev) +{ + switch (keyboard_mode) { + case 1: + default: + keyboard_set_table(scancode_set1); + break; + case 2: + keyboard_set_table(scancode_set2); + break; + + case 3: + keyboard_set_table(scancode_set3); + break; + } +} + +static void +kbc_queue_reset(atkbd_t *dev, uint8_t channel) +{ + switch (channel) { + case 1: + dev->key_queue_start = dev->key_queue_end = 0; + memset(dev->key_queue, 0x00, sizeof(dev->key_queue)); + /* FALLTHROUGH */ + case 4: + dev->key_cmd_queue_start = dev->key_cmd_queue_end = 0; + memset(dev->key_cmd_queue, 0x00, sizeof(dev->key_cmd_queue)); + break; + + case 2: + dev->mouse_queue_start = dev->mouse_queue_end = 0; + memset(dev->mouse_queue, 0x00, sizeof(dev->mouse_queue)); + /* FALLTHROUGH */ + case 3: + dev->mouse_cmd_queue_start = dev->mouse_cmd_queue_end = 0; + memset(dev->mouse_cmd_queue, 0x00, sizeof(dev->mouse_cmd_queue)); + break; + + case 0: + default: + dev->key_ctrl_queue_start = dev->key_ctrl_queue_end = 0; + memset(dev->key_ctrl_queue, 0x00, sizeof(dev->key_ctrl_queue)); + } +} + +static void +kbc_queue_add(atkbd_t *dev, uint8_t val, uint8_t channel) +{ + switch (channel) { + case 4: + kbd_log("ATkbc: dev->key_cmd_queue[%02X] = %02X;\n", dev->key_cmd_queue_end, val); + dev->key_cmd_queue[dev->key_cmd_queue_end] = val; + dev->key_cmd_queue_end = (dev->key_cmd_queue_end + 1) & 0xf; + break; + case 3: + kbd_log("ATkbc: dev->mouse_cmd_queue[%02X] = %02X;\n", dev->mouse_cmd_queue_end, val); + dev->mouse_cmd_queue[dev->mouse_cmd_queue_end] = val; + dev->mouse_cmd_queue_end = (dev->mouse_cmd_queue_end + 1) & 0xf; + break; + case 2: + kbd_log("ATkbc: dev->mouse_queue[%02X] = %02X;\n", dev->mouse_queue_end, val); + dev->mouse_queue[dev->mouse_queue_end] = val; + dev->mouse_queue_end = (dev->mouse_queue_end + 1) & 0xf; + break; + case 1: + kbd_log("ATkbc: dev->key_queue[%02X] = %02X;\n", dev->key_queue_end, val); + dev->key_queue[dev->key_queue_end] = val; + dev->key_queue_end = (dev->key_queue_end + 1) & 0xf; + break; + case 0: + default: + kbd_log("ATkbc: dev->key_ctrl_queue[%02X] = %02X;\n", dev->key_ctrl_queue_end, val); + dev->key_ctrl_queue[dev->key_ctrl_queue_end] = val; + dev->key_ctrl_queue_end = (dev->key_ctrl_queue_end + 1) & 0x3f; + break; + } +} + +static int +kbc_translate(atkbd_t *dev, uint8_t val) +{ + int xt_mode = (dev->mem[0x20] & 0x20) && ((dev->flags & KBC_TYPE_MASK) < KBC_TYPE_PS2_NOREF); + int translate = (dev->mem[0x20] & 0x40) || xt_mode || ((dev->flags & KBC_TYPE_MASK) == KBC_TYPE_PS2_2); + uint8_t kbc_ven = dev->flags & KBC_VEN_MASK; + int ret = - 1; + + /* Allow for scan code translation. */ + if (translate && (val == 0xf0)) { + kbd_log("ATkbd: translate is on, F0 prefix detected\n"); + dev->sc_or = 0x80; + return ret; + } + + /* Skip break code if translated make code has bit 7 set. */ + if (translate && (dev->sc_or == 0x80) && (nont_to_t[val] & 0x80)) { + kbd_log("ATkbd: translate is on, skipping scan code: %02X (original: F0 %02X)\n", nont_to_t[val], val); + dev->sc_or = 0; + return ret; + } + + /* Test for T3100E 'Fn' key (Right Alt / Right Ctrl) */ + if ((dev != NULL) && (kbc_ven == KBC_VEN_TOSHIBA) && + (keyboard_recv(0x138) || keyboard_recv(0x11d))) 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 */ + } + + kbd_log("ATkbd: translate is %s, ", translate ? "on" : "off"); +#ifdef ENABLE_KEYBOARD_AT_LOG + kbd_log("scan code: "); + if (translate) { + kbd_log("%02X (original: ", (nont_to_t[val] | dev->sc_or)); + if (dev->sc_or == 0x80) + kbd_log("F0 "); + kbd_log("%02X)\n", val); + } else + kbd_log("%02X\n", val); +#endif + + ret = translate ? (nont_to_t[val] | dev->sc_or) : val; + + if (dev->sc_or == 0x80) + dev->sc_or = 0; + + return ret; +} + +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; + int temp = (channel == 1) ? kbc_translate(dev, val) : val; + + if (temp == -1) + return; + + if ((kbc_ven == KBC_VEN_AMI) || (kbc_ven == KBC_VEN_TG) || + (kbc_ven == KBC_VEN_TG_GREEN) || ((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 on channel %i...\n", temp, channel); + dev->status = (dev->status & ~0xf0) | STAT_OFULL | stat_hi; + + /* WARNING: On PS/2, all IRQ's are level-triggered, but the IBM PS/2 KBC firmware is explicitly + written to pulse its P2 IRQ bits, so they should be kept as as edge-triggered here. */ + if ((dev->flags & KBC_TYPE_MASK) >= KBC_TYPE_PS2_NOREF) { + if (channel >= 2) { + dev->status |= STAT_MFULL; + + if (dev->mem[0x20] & 0x02) + picint_common(1 << 12, 0, 1); + picint_common(1 << 1, 0, 0); + } else { + if (dev->mem[0x20] & 0x01) + picint_common(1 << 1, 0, 1); + picint_common(1 << 12, 0, 0); + } + } else if (dev->mem[0x20] & 0x01) + picintlevel(1 << 1); /* AT KBC: IRQ 1 is level-triggered because it is tied to OBF. */ + + dev->out = temp; +} + +static void +add_data_kbd_cmd_queue(atkbd_t *dev, uint8_t val) +{ + if (dev->key_cmd_queue_end >= 16) { + kbd_log("ATkbc: Unable to add to queue, dev->key_cmd_queue_end >= 16\n"); + return; + } + kbd_log("ATkbc: dev->key_cmd_queue[%02X] = %02X;\n", dev->key_cmd_queue_end, val); + kbc_queue_add(dev, val, 4); + dev->kbd_last_scan_code = val; +} + +static void +add_data_kbd_queue(atkbd_t *dev, uint8_t val) +{ + if (!keyboard_scan || (dev->key_queue_end >= 16)) { + kbd_log("ATkbc: Unable to add to queue, conditions: %i, %i\n", !keyboard_scan, (dev->key_queue_end >= 16)); + return; + } + kbd_log("ATkbc: key_queue[%02X] = %02X;\n", dev->key_queue_end, val); + kbc_queue_add(dev, val, 1); + dev->kbd_last_scan_code = val; +} + +static void +add_data_kbd_front(atkbd_t *dev, uint8_t val) +{ + add_data_kbd_cmd_queue(dev, val); +} + +static void kbd_process_cmd(void *priv); +static void kbc_process_cmd(void *priv); + +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_ibf_process(atkbd_t *dev) +{ + /* IBF set, process both commands and data. */ + dev->status &= ~STAT_IFULL; + dev->kbc_state = KBC_STATE_MAIN_IBF; + if (dev->status & STAT_CD) + kbc_process_cmd(dev); + else { + set_enable_kbd(dev, 1); + dev->key_wantcmd = 1; + dev->key_dat = dev->ib; + dev->kbc_state = KBC_STATE_SEND_KBD; + } +} + +static void +kbc_scan_kbd_at(atkbd_t *dev) +{ + if (!(dev->mem[0x20] & 0x10)) { + /* Both OBF and IBF clear and keyboard is enabled. */ + /* XT mode. */ + if (dev->mem[0x20] & 0x20) { + if (dev->out_new != -1) { + add_to_kbc_queue_front(dev, dev->out_new, 1, 0x00); + dev->out_new = -1; + dev->kbc_state = KBC_STATE_MAIN_IBF; + } else if (dev->status & STAT_IFULL) + kbc_ibf_process(dev); + /* AT mode. */ + } else { + // dev->t = dev->mem[0x28]; + if (dev->mem[0x2e] != 0x00) { + // if (!(dev->t & 0x02)) + // return; + dev->mem[0x2e] = 0x00; + } + dev->output_port &= 0xbf; + if (dev->out_new != -1) { + /* In our case, we never have noise on the line, so we can simplify this. */ + /* Read data from the keyboard. */ + if (dev->mem[0x20] & 0x40) { + if ((dev->mem[0x20] & 0x08) || (dev->input_port & 0x80)) + add_to_kbc_queue_front(dev, dev->out_new, 1, 0x00); + dev->mem[0x2d] = (dev->out_new == 0xf0) ? 0x80 : 0x00; + } else + add_to_kbc_queue_front(dev, dev->out_new, 1, 0x00); + dev->out_new = -1; + dev->kbc_state = KBC_STATE_MAIN_IBF; + } + } + } +} + +static void write_output(atkbd_t *dev, uint8_t val); + +static void +kbc_poll_at(atkbd_t *dev) +{ + switch (dev->kbc_state) { + case KBC_STATE_RESET: + if (dev->status & STAT_IFULL) { + dev->status = ((dev->status & 0x0f) | 0x10) & ~STAT_IFULL; + if ((dev->status & STAT_CD) && (dev->ib == 0xaa)) + kbc_process_cmd(dev); + } + break; + case KBC_STATE_MAIN_IBF: + default: + if (dev->status & STAT_OFULL) { + /* OBF set, wait until it is cleared but still process commands. */ + if ((dev->status & STAT_IFULL) && (dev->status & STAT_CD)) { + dev->status &= ~STAT_IFULL; + kbc_process_cmd(dev); + } + } else if (dev->status & STAT_IFULL) + kbc_ibf_process(dev); + else if (!(dev->mem[0x20] & 0x10)) + dev->kbc_state = KBC_STATE_MAIN_KBD; + break; + case KBC_STATE_MAIN_KBD: + case KBC_STATE_MAIN_BOTH: + if (dev->status & STAT_IFULL) + kbc_ibf_process(dev); + else { + (void) kbc_scan_kbd_at(dev); + dev->kbc_state = KBC_STATE_MAIN_IBF; + } + break; + case KBC_STATE_KBC_OUT: + /* Keyboard controller command want to output multiple bytes. */ + if (dev->status & STAT_IFULL) { + /* Data from host aborts dumping. */ + dev->kbc_state = KBC_STATE_MAIN_IBF; + kbc_ibf_process(dev); + } + /* Do not continue dumping until OBF is clear. */ + if (!(dev->status & STAT_OFULL)) { + kbd_log("ATkbc: %02X coming from channel 0\n", dev->key_ctrl_queue[dev->key_ctrl_queue_start]); + add_to_kbc_queue_front(dev, dev->key_ctrl_queue[dev->key_ctrl_queue_start], 0, 0x00); + dev->key_ctrl_queue_start = (dev->key_ctrl_queue_start + 1) & 0x3f; + if (dev->key_ctrl_queue_start == dev->key_ctrl_queue_end) + dev->kbc_state = KBC_STATE_MAIN_IBF; + } + break; + case KBC_STATE_KBC_PARAM: + /* Keyboard controller command wants data, wait for said data. */ + if (dev->status & STAT_IFULL) { + /* Command written, abort current command. */ + if (dev->status & STAT_CD) + dev->kbc_state = KBC_STATE_MAIN_IBF; + + dev->status &= ~STAT_IFULL; + kbc_process_cmd(dev); + } + break; + case KBC_STATE_SEND_KBD: + if (!dev->key_wantcmd) + dev->kbc_state = KBC_STATE_SCAN_KBD; + break; + case KBC_STATE_SCAN_KBD: + kbc_scan_kbd_at(dev); + break; + } +} + +/* + Correct Procedure: + 1. Controller asks the device (keyboard or mouse) for a byte. + 2. The device, unless it's in the reset or command states, sees if there's anything to give it, + and if yes, begins the transfer. + 3. The controller checks if there is a transfer, if yes, transfers the byte and sends it to the host, + otherwise, checks the next device, or if there is no device left to check, checks if IBF is full + and if yes, processes it. + */ +static int +kbc_scan_kbd_ps2(atkbd_t *dev) +{ + if (dev->out_new != -1) { + kbd_log("ATkbc: %02X coming from channel 1\n", dev->out_new & 0xff); + add_to_kbc_queue_front(dev, dev->out_new, 1, 0x00); + dev->out_new = -1; + dev->kbc_state = KBC_STATE_MAIN_IBF; + return 1; + } + + return 0; +} + +static int +kbc_scan_aux_ps2(atkbd_t *dev) +{ + if (dev->out_new_mouse != -1) { + kbd_log("ATkbc: %02X coming from channel 2\n", dev->out_new_mouse & 0xff); + add_to_kbc_queue_front(dev, dev->out_new_mouse, 2, 0x00); + dev->out_new_mouse = -1; + dev->kbc_state = KBC_STATE_MAIN_IBF; + return 1; + } + + return 0; +} + +static void +kbc_poll_ps2(atkbd_t *dev) +{ + switch (dev->kbc_state) { + case KBC_STATE_RESET: + if (dev->status & STAT_IFULL) { + dev->status = ((dev->status & 0x0f) | 0x10) & ~STAT_IFULL; + if ((dev->status & STAT_CD) && (dev->ib == 0xaa)) + kbc_process_cmd(dev); + } + break; + case KBC_STATE_MAIN_IBF: + default: + if (dev->status & STAT_IFULL) + kbc_ibf_process(dev); + else if (!(dev->status & STAT_OFULL)) { + if (dev->mem[0x20] & 0x20) { + if (!(dev->mem[0x20] & 0x10)) { + dev->output_port &= 0xbf; + dev->kbc_state = KBC_STATE_MAIN_KBD; + } + } else { + dev->output_port &= 0xf7; + if (dev->mem[0x20] & 0x10) + dev->kbc_state = KBC_STATE_MAIN_MOUSE; + else { + dev->output_port &= 0xbf; + dev->kbc_state = KBC_STATE_MAIN_BOTH; + } + } + } + break; + case KBC_STATE_MAIN_KBD: + if (dev->status & STAT_IFULL) + kbc_ibf_process(dev); + else { + (void) kbc_scan_kbd_ps2(dev); + dev->kbc_state = KBC_STATE_MAIN_IBF; + } + break; + case KBC_STATE_MAIN_MOUSE: + if (dev->status & STAT_IFULL) + kbc_ibf_process(dev); + else { + (void) kbc_scan_aux_ps2(dev); + dev->kbc_state = KBC_STATE_MAIN_IBF; + } + break; + case KBC_STATE_MAIN_BOTH: + if (kbc_scan_kbd_ps2(dev)) + dev->kbc_state = KBC_STATE_MAIN_IBF; + else + dev->kbc_state = KBC_STATE_MAIN_MOUSE; + break; + case KBC_STATE_KBC_OUT: + /* Keyboard controller command want to output multiple bytes. */ + if (dev->status & STAT_IFULL) { + /* Data from host aborts dumping. */ + dev->kbc_state = KBC_STATE_MAIN_IBF; + kbc_ibf_process(dev); + } + /* Do not continue dumping until OBF is clear. */ + if (!(dev->status & STAT_OFULL)) { + kbd_log("ATkbc: %02X coming from channel 0\n", dev->out_new & 0xff); + add_to_kbc_queue_front(dev, dev->key_ctrl_queue[dev->key_ctrl_queue_start], 0, 0x00); + dev->key_ctrl_queue_start = (dev->key_ctrl_queue_start + 1) & 0x3f; + if (dev->key_ctrl_queue_start == dev->key_ctrl_queue_end) + dev->kbc_state = KBC_STATE_MAIN_IBF; + } + break; + case KBC_STATE_KBC_PARAM: + /* Keyboard controller command wants data, wait for said data. */ + if (dev->status & STAT_IFULL) { + /* Command written, abort current command. */ + if (dev->status & STAT_CD) + dev->kbc_state = KBC_STATE_MAIN_IBF; + + dev->status &= ~STAT_IFULL; + kbc_process_cmd(dev); + } + break; + case KBC_STATE_SEND_KBD: + if (!dev->key_wantcmd) + dev->kbc_state = KBC_STATE_SCAN_KBD; + break; + case KBC_STATE_SCAN_KBD: + (void) kbc_scan_kbd_ps2(dev); + break; + case KBC_STATE_SEND_MOUSE: + if (!dev->mouse_wantcmd) + dev->kbc_state = KBC_STATE_SCAN_MOUSE; + break; + case KBC_STATE_SCAN_MOUSE: + (void) kbc_scan_aux_ps2(dev); + break; + } +} + +static void +kbc_poll_kbd(atkbd_t *dev) +{ + switch (dev->kbd_state) { + case DEV_STATE_MAIN_1: + /* Process the command if needed and then return to main loop #2. */ + if (dev->key_wantcmd) { + kbd_log("ATkbc: Processing keyboard command %02X...\n", dev->key_dat); + kbc_queue_reset(dev, 4); + // dev->out_new = -1; + kbd_process_cmd(dev); + dev->key_wantcmd = 0; + } else + dev->kbd_state = DEV_STATE_MAIN_2; + break; + case DEV_STATE_MAIN_2: + /* Output from scan queue if needed and then return to main loop #1. */ + if (keyboard_scan && (dev->out_new == -1) && (dev->key_queue_start != dev->key_queue_end)) { + kbd_log("ATkbc: %02X (DATA) on channel 1\n", dev->key_queue[dev->key_queue_start]); + dev->out_new = dev->key_queue[dev->key_queue_start]; + dev->key_queue_start = (dev->key_queue_start + 1) & 0xf; + } + if (!keyboard_scan || dev->key_wantcmd) + dev->kbd_state = DEV_STATE_MAIN_1; + break; + case DEV_STATE_MAIN_OUT: + /* If host wants to send command while we're sending a byte to host, process the command. */ + if (dev->key_wantcmd) { + kbd_log("ATkbc: Processing keyboard command %02X...\n", dev->key_dat); + kbc_queue_reset(dev, 4); + kbd_process_cmd(dev); + dev->key_wantcmd = 0; + break; + } + /* FALLTHROUGH */ + case DEV_STATE_MAIN_WANT_IN: + /* Output command response and then wait for host data. */ + if ((dev->out_new == -1) && (dev->key_cmd_queue_start != dev->key_cmd_queue_end)) { + kbd_log("ATkbc: %02X (CMD ) on channel 1\n", dev->key_cmd_queue[dev->key_cmd_queue_start]); + dev->out_new = dev->key_cmd_queue[dev->key_cmd_queue_start]; + dev->key_cmd_queue_start = (dev->key_cmd_queue_start + 1) & 0xf; + } + if (dev->key_cmd_queue_start == dev->key_cmd_queue_end) + dev->kbd_state = (dev->kbd_state == DEV_STATE_MAIN_OUT) ? DEV_STATE_MAIN_2 : DEV_STATE_MAIN_IN; + break; + case DEV_STATE_MAIN_IN: + /* Wait for host data. */ + if (dev->key_wantcmd) { + kbd_log("ATkbc: Processing keyboard command %02X parameter %02X...\n", dev->key_command, dev->key_dat); + kbc_queue_reset(dev, 4); + // dev->out_new = -1; + kbd_process_cmd(dev); + dev->key_wantcmd = 0; + } + break; + } +} + +static void +kbc_poll_aux(atkbd_t *dev) +{ + switch (dev->mouse_state) { + case DEV_STATE_MAIN_1: + /* Process the command if needed and then return to main loop #2. */ + if (dev->mouse_wantcmd) { + kbd_log("ATkbc: Processing mouse command %02X...\n", dev->mouse_dat); + kbc_queue_reset(dev, 3); + // dev->out_new_mouse = -1; + dev->mouse_state = DEV_STATE_MAIN_OUT; + mouse_write(dev->mouse_dat, mouse_p); + if ((dev->mouse_dat == 0xe8) || (dev->mouse_dat == 0xf3)) + dev->mouse_state = DEV_STATE_MAIN_WANT_IN; + dev->mouse_wantcmd = 0; + } else + dev->mouse_state = DEV_STATE_MAIN_2; + break; + case DEV_STATE_MAIN_2: + /* Output from scan queue if needed and then return to main loop #1. */ + if (mouse_scan && (dev->out_new_mouse == -1) && (dev->mouse_queue_start != dev->mouse_queue_end)) { + kbd_log("ATkbc: %02X (DATA) on channel 2\n", dev->mouse_queue[dev->mouse_queue_start]); + dev->out_new_mouse = dev->mouse_queue[dev->mouse_queue_start]; + dev->mouse_queue_start = (dev->mouse_queue_start + 1) & 0xf; + } + if (!mouse_scan || dev->mouse_wantcmd) + dev->mouse_state = DEV_STATE_MAIN_1; + break; + case DEV_STATE_MAIN_OUT: + /* If host wants to send command while we're sending a byte to host, process the command. */ + if (dev->mouse_wantcmd) { + kbd_log("ATkbc: Processing mouse command %02X...\n", dev->mouse_dat); + kbc_queue_reset(dev, 3); + dev->mouse_state = DEV_STATE_MAIN_OUT; + mouse_write(dev->mouse_dat, mouse_p); + if ((dev->mouse_dat == 0xe8) || (dev->mouse_dat == 0xf3)) + dev->mouse_state = DEV_STATE_MAIN_WANT_IN; + dev->mouse_wantcmd = 0; + break; + } + /* FALLTHROUGH */ + case DEV_STATE_MAIN_WANT_IN: + /* Output command response and then wait for host data. */ + if ((dev->out_new_mouse == -1) && (dev->mouse_cmd_queue_start != dev->mouse_cmd_queue_end)) { + kbd_log("ATkbc: %02X (CMD ) on channel 2\n", dev->mouse_cmd_queue[dev->mouse_cmd_queue_start]); + dev->out_new_mouse = dev->mouse_cmd_queue[dev->mouse_cmd_queue_start]; + dev->mouse_cmd_queue_start = (dev->mouse_cmd_queue_start + 1) & 0xf; + } + if (dev->mouse_cmd_queue_start == dev->mouse_cmd_queue_end) + dev->mouse_state = (dev->mouse_state == DEV_STATE_MAIN_OUT) ? DEV_STATE_MAIN_2 : DEV_STATE_MAIN_IN; + break; + case DEV_STATE_MAIN_IN: + /* Wait for host data. */ + if (dev->mouse_wantcmd) { + kbd_log("ATkbc: Processing mouse command parameter %02X...\n", dev->mouse_dat); + kbc_queue_reset(dev, 3); + // dev->out_new_mouse = -1; + dev->mouse_state = DEV_STATE_MAIN_OUT; + mouse_write(dev->mouse_dat, mouse_p); + dev->mouse_wantcmd = 0; + } + break; + } +} + +/* TODO: State machines for controller, keyboard, and mouse. */ +static void +kbd_poll(void *priv) +{ + atkbd_t *dev = (atkbd_t *) priv; + + timer_advance_u64(&dev->send_delay_timer, (100ULL * TIMER_USEC)); + + /* TODO: Use a fuction pointer for this (also needed to the AMI KBC mode switching) + and implement the password security state. */ + if ((dev->flags & KBC_TYPE_MASK) >= KBC_TYPE_PS2_NOREF) + kbc_poll_ps2(dev); + else + kbc_poll_at(dev); + + kbc_poll_kbd(dev); + + if (((dev->flags & KBC_TYPE_MASK) >= KBC_TYPE_PS2_NOREF) && mouse_write) + kbc_poll_aux(dev); + + // if (kbc_ports[0] && kbc_ports[0]>-priv) + // kbc_ports[0]>poll(kbc_ports[0]>-priv); + + // if (((dev->flags & KBC_TYPE_MASK) >= KBC_TYPE_PS2_NOREF) && kbc_ports[1] && kbc_ports[1]>-priv) + // kbc_ports[1]>poll(kbc_ports[1]>-priv); +} + +static void +add_data_vals(atkbd_t *dev, uint8_t *val, uint8_t len) +{ + int i; + + for (i = 0; i < len; i++) + add_data_kbd_queue(dev, val[i]); +} + +static void +add_data_kbd(uint16_t val) +{ + atkbd_t *dev = SavedKbd; + uint8_t fake_shift[4]; + uint8_t num_lock = 0, shift_states = 0; + + keyboard_get_states(NULL, &num_lock, NULL); + shift_states = keyboard_get_shift() & STATE_SHIFT_MASK; + + switch (val) { + case FAKE_LSHIFT_ON: + kbd_log("fake left shift on, scan code: "); + if (num_lock) { + if (shift_states) { + kbd_log("N/A (one or both shifts on)\n"); + break; + } else { + /* Num lock on and no shifts are pressed, send non-inverted fake shift. */ + switch (keyboard_mode & 0x02) { + case 1: + fake_shift[0] = 0xe0; + fake_shift[1] = 0x2a; + add_data_vals(dev, fake_shift, 2); + break; + + case 2: + fake_shift[0] = 0xe0; + fake_shift[1] = 0x12; + add_data_vals(dev, fake_shift, 2); + break; + + default: + kbd_log("N/A (scan code set %i)\n", keyboard_mode & 0x02); + break; + } + } + } else { + if (shift_states & STATE_LSHIFT) { + /* Num lock off and left shift pressed. */ + switch (keyboard_mode & 0x02) { + case 1: + fake_shift[0] = 0xe0; + fake_shift[1] = 0xaa; + add_data_vals(dev, fake_shift, 2); + break; + + case 2: + fake_shift[0] = 0xe0; + fake_shift[1] = 0xf0; + fake_shift[2] = 0x12; + add_data_vals(dev, fake_shift, 3); + break; + + default: + kbd_log("N/A (scan code set %i)\n", keyboard_mode & 0x02); + break; + } + } + if (shift_states & STATE_RSHIFT) { + /* Num lock off and right shift pressed. */ + switch (keyboard_mode & 0x02) { + case 1: + fake_shift[0] = 0xe0; + fake_shift[1] = 0xb6; + add_data_vals(dev, fake_shift, 2); + break; + + case 2: + fake_shift[0] = 0xe0; + fake_shift[1] = 0xf0; + fake_shift[2] = 0x59; + add_data_vals(dev, fake_shift, 3); + break; + + default: + kbd_log("N/A (scan code set %i)\n", keyboard_mode & 0x02); + break; + } + } + kbd_log(shift_states ? "" : "N/A (both shifts off)\n"); + } + break; + + case FAKE_LSHIFT_OFF: + kbd_log("fake left shift on, scan code: "); + if (num_lock) { + if (shift_states) { + kbd_log("N/A (one or both shifts on)\n"); + break; + } else { + /* Num lock on and no shifts are pressed, send non-inverted fake shift. */ + switch (keyboard_mode & 0x02) { + case 1: + fake_shift[0] = 0xe0; + fake_shift[1] = 0xaa; + add_data_vals(dev, fake_shift, 2); + break; + + case 2: + fake_shift[0] = 0xe0; + fake_shift[1] = 0xf0; + fake_shift[2] = 0x12; + add_data_vals(dev, fake_shift, 3); + break; + + default: + kbd_log("N/A (scan code set %i)\n", keyboard_mode & 0x02); + break; + } + } + } else { + if (shift_states & STATE_LSHIFT) { + /* Num lock off and left shift pressed. */ + switch (keyboard_mode & 0x02) { + case 1: + fake_shift[0] = 0xe0; + fake_shift[1] = 0x2a; + add_data_vals(dev, fake_shift, 2); + break; + + case 2: + fake_shift[0] = 0xe0; + fake_shift[1] = 0x12; + add_data_vals(dev, fake_shift, 2); + break; + + default: + kbd_log("N/A (scan code set %i)\n", keyboard_mode & 0x02); + break; + } + } + if (shift_states & STATE_RSHIFT) { + /* Num lock off and right shift pressed. */ + switch (keyboard_mode & 0x02) { + case 1: + fake_shift[0] = 0xe0; + fake_shift[1] = 0x36; + add_data_vals(dev, fake_shift, 2); + break; + + case 2: + fake_shift[0] = 0xe0; + fake_shift[1] = 0x59; + add_data_vals(dev, fake_shift, 2); + break; + + default: + kbd_log("N/A (scan code set %i)\n", keyboard_mode & 0x02); + break; + } + } + kbd_log(shift_states ? "" : "N/A (both shifts off)\n"); + } + break; + + default: + add_data_kbd_queue(dev, val); + break; + } +} + +static void +write_output(atkbd_t *dev, uint8_t val) +{ + uint8_t old = dev->output_port; + kbd_log("ATkbc: write output port: %02X (old: %02X)\n", val, dev->output_port); + + uint8_t kbc_ven = dev->flags & KBC_VEN_MASK; + +#if 0 + /* PS/2: Handle IRQ's. */ + if ((dev->flags & KBC_TYPE_MASK) >= KBC_TYPE_PS2_NOREF) { + /* IRQ 12 */ + picint_common(1 << 12, 0, val & 0x20); + + /* IRQ 1 */ + picint_common(1 << 1, 0, val & 0x10); + } +#endif + + /* AT, PS/2: Handle A20. */ + if ((old ^ val) & 0x02) { /* A20 enable change */ + mem_a20_key = val & 0x02; + mem_a20_recalc(); + flushmmucache(); + } + + /* AT, PS/2: Handle reset. */ + /* 0 holds the CPU in the RESET state, 1 releases it. To simplify this, + we just do everything on release. */ + if ((old ^ val) & 0x01) { /*Reset*/ + if (!(val & 0x01)) { /* Pin 0 selected. */ + /* Pin 0 selected. */ + kbd_log("write_output(): Pulse reset!\n"); + if (machines[machine].flags & MACHINE_COREBOOT) { + /* The SeaBIOS hard reset code attempts a KBC reset if ACPI RESET_REG + is not available. However, the KBC reset is normally a soft reset, so + SeaBIOS gets caught in a soft reset loop as it tries to hard reset the + machine. Hack around this by making the KBC reset a hard reset only on + coreboot machines. */ + pc_reset_hard(); + } else { + softresetx86(); /*Pulse reset!*/ + cpu_set_edx(); + flushmmucache(); + if (kbc_ven == KBC_VEN_ALI) + smbase = 0x00030000; + } + } + } + + /* Do this here to avoid an infinite reset loop. */ + dev->output_port = val; +} + +static void +write_output_fast_a20(atkbd_t *dev, uint8_t val) +{ + uint8_t old = dev->output_port; + kbd_log("ATkbc: write output port in fast A20 mode: %02X (old: %02X)\n", val, dev->output_port); + + /* AT, PS/2: Handle A20. */ + if ((old ^ val) & 0x02) { /* A20 enable change */ + mem_a20_key = val & 0x02; + mem_a20_recalc(); + flushmmucache(); + } + + /* Do this here to avoid an infinite reset loop. */ + dev->output_port = val; +} + +static void +write_cmd(atkbd_t *dev, uint8_t val) +{ + 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] &= ~CCB_TRANSLATE; + } else if ((dev->flags & KBC_TYPE_MASK) < KBC_TYPE_PS2_NOREF) { + if (val & 0x10) + dev->mem[0x2e] = 0x01; + } + + kbd_log("ATkbc: keyboard interrupt is now %s\n", (val & 0x01) ? "enabled" : "disabled"); + + if ((dev->flags & KBC_TYPE_MASK) < KBC_TYPE_PS2_NOREF) { + /* Update the output port to mirror the IBF and OBF bits, if active. */ + write_output(dev, (dev->output_port & 0x0f) | ((val & 0x03) << 4) | ((val & 0x20) ? 0xc0 : 0x00)); + } + + 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_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 uint8_t +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; + + switch (val) { + case 0xa4: /* check if password installed */ + if ((dev->flags & KBC_TYPE_MASK) >= KBC_TYPE_PS2_NOREF) { + kbd_log("ATkbc: check if password installed\n"); + add_to_kbc_queue_front(dev, 0xf1, 0, 0x00); + return 0; + } + break; + + case 0xa7: /* disable mouse port */ + if ((dev->flags & KBC_TYPE_MASK) >= KBC_TYPE_PS2_NOREF) { + kbd_log("ATkbc: disable mouse port\n"); + set_enable_mouse(dev, 0); + return 0; + } + break; + + case 0xa8: /*Enable mouse port*/ + if ((dev->flags & KBC_TYPE_MASK) >= KBC_TYPE_PS2_NOREF) { + kbd_log("ATkbc: enable mouse port\n"); + set_enable_mouse(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_to_kbc_queue_front(dev, 0x00, 0, 0x00); /* no error, this is testing the channel 2 interface */ + return 0; + } + break; + + case 0xaf: /* read keyboard version */ + kbd_log("ATkbc: read keyboard version\n"); + add_to_kbc_queue_front(dev, 0x42, 0, 0x00); + return 0; + + case 0xc0: /* read input port */ + 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. */ + if (kbc_ven == KBC_VEN_INTEL_AMI) + 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); + } else if (kbc_ven == KBC_VEN_NCR) { + /* switch settings + * bit 7: keyboard disable + * bit 6: display type (0 color, 1 mono) + * bit 5: power-on default speed (0 high, 1 low) + * bit 4: sense RAM size (0 unsupported, 1 512k on system board) + * bit 3: coprocessor detect + * bit 2: unused + * 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); + } else { + if ((kbc_ven == KBC_VEN_TG) || (kbc_ven == KBC_VEN_TG_GREEN)) { + /* Bit 3, 2: + 1, 1: TriGem logo; + 1, 0: Garbled logo; + 0, 1: Epson logo; + 0, 0: Generic AMI logo. */ + if (dev->pci) + fixed_bits |= 8; + add_to_kbc_queue_front(dev, dev->input_port | fixed_bits, 0, 0x00); + } else if (((dev->flags & KBC_TYPE_MASK) >= KBC_TYPE_PS2_NOREF) && ((dev->flags & KBC_VEN_MASK) != KBC_VEN_INTEL_AMI)) +#if 0 + add_to_kbc_queue_front(dev, (dev->input_port | fixed_bits) & + (((dev->flags & KBC_VEN_MASK) == KBC_VEN_ACER) ? 0xeb : 0xef), 0, 0x00); +#else + add_to_kbc_queue_front(dev, ((dev->input_port | fixed_bits) & 0xf0) | (((dev->flags & KBC_VEN_MASK) == KBC_VEN_ACER) ? 0x08 : 0x0c), 0, 0x00); +#endif + 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); + } + return 0; + + case 0xd3: /* write mouse output buffer */ + if ((dev->flags & KBC_TYPE_MASK) >= KBC_TYPE_PS2_NOREF) { + kbd_log("ATkbc: write mouse output buffer\n"); + dev->want60 = 1; + dev->kbc_state = KBC_STATE_KBC_PARAM; + return 0; + } + break; + + case 0xd4: /* write to mouse */ + kbd_log("ATkbc: write to mouse\n"); + dev->want60 = 1; + dev->kbc_state = KBC_STATE_KBC_PARAM; + return 0; + + case 0xf0 ... 0xff: + kbd_log("ATkbc: pulse %01X\n", val & 0x0f); + pulse_output(dev, val & 0x0f); + return 0; + } + + kbd_log("ATkbc: bad command %02X\n", val); + return 1; +} + +static uint8_t +write60_ami(void *priv, uint8_t val) +{ + atkbd_t *dev = (atkbd_t *) priv; + + switch (dev->command) { + /* 0x40 - 0x5F are aliases for 0x60-0x7F */ + case 0x40 ... 0x5f: + kbd_log("ATkbc: AMI - alias write to %08X\n", dev->command); + dev->mem[(dev->command & 0x1f) + 0x20] = val; + if (dev->command == 0x60) + write_cmd(dev, val); + return 0; + + case 0xa5: /* get extended controller RAM */ + kbd_log("ATkbc: AMI - get extended controller RAM\n"); + add_to_kbc_queue_front(dev, dev->mem[val], 0, 0x00); + 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->kbc_state = KBC_STATE_KBC_PARAM; + dev->secr_phase = 2; + } else if (dev->secr_phase == 2) { + dev->mem[dev->mem_addr] = val; + dev->secr_phase = 0; + } + return 0; + + case 0xc1: + kbd_log("ATkbc: AMI MegaKey - write %02X to input port\n", val); + dev->input_port = val; + return 0; + + case 0xcb: /* set keyboard mode */ + kbd_log("ATkbc: AMI - set keyboard mode\n"); + dev->ami_flags = val; + return 0; + } + + return 1; +} + +static uint8_t +write64_ami(void *priv, uint8_t val) +{ + atkbd_t *dev = (atkbd_t *) priv; + uint8_t kbc_ven = dev->flags & KBC_VEN_MASK; + + switch (val) { + case 0x00 ... 0x1f: + kbd_log("ATkbc: AMI - alias read from %08X\n", val); + add_to_kbc_queue_front(dev, dev->mem[val + 0x20], 0, 0x00); + return 0; + + case 0x40 ... 0x5f: + kbd_log("ATkbc: AMI - alias write to %08X\n", dev->command); + dev->want60 = 1; + dev->kbc_state = KBC_STATE_KBC_PARAM; + return 0; + + case 0xa0: /* copyright message */ + kbc_queue_add(dev, 0x28, 0); + kbc_queue_add(dev, 0x00, 0); + dev->kbc_state = KBC_STATE_KBC_OUT; + break; + + case 0xa1: /* get controller version */ + kbd_log("ATkbc: AMI - get controller version\n"); + if ((kbc_ven == KBC_VEN_TG) || (kbc_ven == KBC_VEN_TG_GREEN)) + add_to_kbc_queue_front(dev, 'Z', 0, 0x00); + else if ((dev->flags & KBC_TYPE_MASK) >= KBC_TYPE_PS2_NOREF) { + if (kbc_ven == KBC_VEN_ALI) + add_to_kbc_queue_front(dev, 'F', 0, 0x00); + else if ((dev->flags & KBC_VEN_MASK) == KBC_VEN_INTEL_AMI) + add_to_kbc_queue_front(dev, '5', 0, 0x00); + else if (cpu_64bitbus) + add_to_kbc_queue_front(dev, 'R', 0, 0x00); + else if (is486) + add_to_kbc_queue_front(dev, 'P', 0, 0x00); + else + add_to_kbc_queue_front(dev, 'H', 0, 0x00); + } else if (is386 && !is486) { + if (cpu_16bitbus) + add_to_kbc_queue_front(dev, 'D', 0, 0x00); + else + add_to_kbc_queue_front(dev, 'B', 0, 0x00); + } else if (!is386) + add_to_kbc_queue_front(dev, '8', 0, 0x00); + else + add_to_kbc_queue_front(dev, 'F', 0, 0x00); + return 0; + + case 0xa2: /* clear keyboard controller lines P22/P23 */ + if ((dev->flags & KBC_TYPE_MASK) < KBC_TYPE_PS2_NOREF) { + kbd_log("ATkbc: AMI - clear KBC lines P22 and P23\n"); + write_output(dev, dev->output_port & 0xf3); + add_to_kbc_queue_front(dev, 0x00, 0, 0x00); + return 0; + } + break; + + case 0xa3: /* set keyboard controller lines P22/P23 */ + if ((dev->flags & KBC_TYPE_MASK) < KBC_TYPE_PS2_NOREF) { + kbd_log("ATkbc: AMI - set KBC lines P22 and P23\n"); + write_output(dev, dev->output_port | 0x0c); + add_to_kbc_queue_front(dev, 0x00, 0, 0x00); + return 0; + } + break; + + case 0xa4: /* write clock = low */ + if ((dev->flags & KBC_TYPE_MASK) < KBC_TYPE_PS2_NOREF) { + kbd_log("ATkbc: AMI - write clock = low\n"); + dev->ami_stat &= 0xfe; + return 0; + } + break; + + case 0xa5: /* write clock = high */ + if ((dev->flags & KBC_TYPE_MASK) < KBC_TYPE_PS2_NOREF) { + kbd_log("ATkbc: AMI - write clock = high\n"); + dev->ami_stat |= 0x01; + } else { + kbd_log("ATkbc: get extended controller RAM\n"); + dev->want60 = 1; + dev->kbc_state = KBC_STATE_KBC_PARAM; + } + return 0; + + case 0xa6: /* read clock */ + if ((dev->flags & KBC_TYPE_MASK) < KBC_TYPE_PS2_NOREF) { + kbd_log("ATkbc: AMI - read clock\n"); + add_to_kbc_queue_front(dev, (dev->ami_stat & 1) ? 0xff : 0x00, 0, 0x00); + return 0; + } + break; + + case 0xa7: /* write cache bad */ + if ((dev->flags & KBC_TYPE_MASK) < KBC_TYPE_PS2_NOREF) { + kbd_log("ATkbc: AMI - write cache bad\n"); + dev->ami_stat &= 0xfd; + return 0; + } + break; + + case 0xa8: /* write cache good */ + if ((dev->flags & KBC_TYPE_MASK) < KBC_TYPE_PS2_NOREF) { + kbd_log("ATkbc: AMI - write cache good\n"); + dev->ami_stat |= 0x02; + return 0; + } + break; + + case 0xa9: /* read cache */ + if ((dev->flags & KBC_TYPE_MASK) < KBC_TYPE_PS2_NOREF) { + kbd_log("ATkbc: AMI - read cache\n"); + add_to_kbc_queue_front(dev, (dev->ami_stat & 2) ? 0xff : 0x00, 0, 0x00); + return 0; + } + break; + + case 0xaf: /* set extended controller RAM */ + if (kbc_ven == KBC_VEN_ALI) { + kbd_log("ATkbc: Award/ALi/VIA keyboard controller revision\n"); + add_to_kbc_queue_front(dev, 0x43, 0, 0x00); + } else { + kbd_log("ATkbc: set extended controller RAM\n"); + dev->want60 = 1; + dev->kbc_state = KBC_STATE_KBC_PARAM; + dev->secr_phase = 1; + } + return 0; + + 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 (!(dev->flags & DEVICE_PCI) || (val > 0xb1)) + dev->input_port &= ~(1 << (val & 0x03)); + add_to_kbc_queue_front(dev, 0x00, 0, 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 (!(dev->flags & DEVICE_PCI)) + write_output(dev, dev->output_port & ~(4 << (val & 0x01))); + add_to_kbc_queue_front(dev, 0x00, 0, 0x00); + return 0; + + case 0xb8 ... 0xbb: + /* 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 (!(dev->flags & DEVICE_PCI) || (val > 0xb9)) { + dev->input_port |= (1 << (val & 0x03)); + add_to_kbc_queue_front(dev, 0x00, 0, 0x00); + } + return 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 (!(dev->flags & DEVICE_PCI)) + write_output(dev, dev->output_port | (4 << (val & 0x01))); + add_to_kbc_queue_front(dev, 0x00, 0, 0x00); + return 0; + + case 0xc1: /* write input port */ + kbd_log("ATkbc: AMI MegaKey - write input port\n"); + dev->want60 = 1; + dev->kbc_state = KBC_STATE_KBC_PARAM; + return 0; + + case 0xc4: + /* set KBC line P14 low */ + kbd_log("ATkbc: set KBC line P14 (input port bit 4) low\n"); + dev->input_port &= 0xef; + add_to_kbc_queue_front(dev, 0x00, 0, 0x00); + return 0; + case 0xc5: + /* set KBC line P15 low */ + kbd_log("ATkbc: set KBC line P15 (input port bit 5) low\n"); + dev->input_port &= 0xdf; + add_to_kbc_queue_front(dev, 0x00, 0, 0x00); + return 0; + + case 0xc8: + /* + * unblock 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->ami_flags &= 0xfb; + 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->ami_flags |= 0x04; + return 0; + + case 0xcc: + /* set KBC line P14 high */ + kbd_log("ATkbc: set KBC line P14 (input port bit 4) high\n"); + dev->input_port |= 0x10; + add_to_kbc_queue_front(dev, 0x00, 0, 0x00); + return 0; + case 0xcd: + /* set KBC line P15 high */ + kbd_log("ATkbc: set KBC line P15 (input port bit 5) high\n"); + dev->input_port |= 0x20; + add_to_kbc_queue_front(dev, 0x00, 0, 0x00); + return 0; + + case 0xef: /* ??? - sent by AMI486 */ + kbd_log("ATkbc: ??? - sent by AMI486\n"); + return 0; + } + + return write64_generic(dev, val); +} + +static uint8_t +write64_ibm_mca(void *priv, uint8_t val) +{ + atkbd_t *dev = (atkbd_t *) priv; + + switch (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); + 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); + return 0; + + case 0xaf: + kbd_log("ATkbc: bad KBC command AF\n"); + return 1; + + case 0xf0 ... 0xff: + kbd_log("ATkbc: pulse: %01X\n", (val & 0x03) | 0x0c); + pulse_output(dev, (val & 0x03) | 0x0c); + return 0; + } + + return write64_generic(dev, val); +} + +static uint8_t +write60_quadtel(void *priv, uint8_t val) +{ + atkbd_t *dev = (atkbd_t *) priv; + + switch (dev->command) { + case 0xcf: /*??? - sent by MegaPC BIOS*/ + kbd_log("ATkbc: ??? - sent by MegaPC BIOS\n"); + return 0; + } + + return 1; +} + +static uint8_t +write64_olivetti(void *priv, uint8_t val) +{ + atkbd_t *dev = (atkbd_t *) priv; + + switch (val) { + case 0x80: /* Olivetti-specific command */ + /* + * bit 7: bus expansion board present (M300) / keyboard unlocked (M290) + * bits 4-6: ??? + * bit 3: fast ram check (if inactive keyboard works erratically) + * 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); + return 0; + } + + return write64_generic(dev, val); +} + +static uint8_t +write64_quadtel(void *priv, uint8_t val) +{ + atkbd_t *dev = (atkbd_t *) priv; + + switch (val) { + case 0xaf: + kbd_log("ATkbc: bad KBC command AF\n"); + return 1; + + case 0xcf: /*??? - sent by MegaPC BIOS*/ + kbd_log("ATkbc: ??? - sent by MegaPC BIOS\n"); + dev->want60 = 1; + dev->kbc_state = KBC_STATE_KBC_PARAM; + return 0; + } + + return write64_generic(dev, val); +} + +static uint8_t +write60_toshiba(void *priv, uint8_t val) +{ + atkbd_t *dev = (atkbd_t *) priv; + + switch (dev->command) { + case 0xb6: /* T3100e - set color/mono switch */ + kbd_log("ATkbc: T3100e - set color/mono switch\n"); + t3100e_mono_set(val); + return 0; + } + + return 1; +} + +static uint8_t +write64_toshiba(void *priv, uint8_t val) +{ + atkbd_t *dev = (atkbd_t *) priv; + + switch (val) { + case 0xaf: + kbd_log("ATkbc: bad KBC command AF\n"); + return 1; + + case 0xb0: /* T3100e: Turbo on */ + kbd_log("ATkbc: T3100e: Turbo on\n"); + t3100e_turbo_set(1); + return 0; + + case 0xb1: /* T3100e: Turbo off */ + kbd_log("ATkbc: T3100e: Turbo off\n"); + t3100e_turbo_set(0); + return 0; + + case 0xb2: /* T3100e: Select external display */ + kbd_log("ATkbc: T3100e: Select external display\n"); + t3100e_display_set(0x00); + return 0; + + case 0xb3: /* T3100e: Select internal display */ + kbd_log("ATkbc: T3100e: Select internal display\n"); + t3100e_display_set(0x01); + return 0; + + case 0xb4: /* T3100e: Get configuration / status */ + kbd_log("ATkbc: T3100e: Get configuration / status\n"); + add_to_kbc_queue_front(dev, t3100e_config_get(), 0, 0x00); + return 0; + + case 0xb5: /* T3100e: Get colour / mono byte */ + kbd_log("ATkbc: T3100e: Get colour / mono byte\n"); + add_to_kbc_queue_front(dev, t3100e_mono_get(), 0, 0x00); + return 0; + + case 0xb6: /* T3100e: Set colour / mono byte */ + kbd_log("ATkbc: T3100e: Set colour / mono byte\n"); + dev->want60 = 1; + dev->kbc_state = KBC_STATE_KBC_PARAM; + return 0; + + case 0xb7: /* T3100e: Emulate PS/2 keyboard */ + case 0xb8: /* T3100e: Emulate AT keyboard */ + dev->flags &= ~KBC_TYPE_MASK; + 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; + } + return 0; + + case 0xbb: /* T3100e: Read 'Fn' key. + Return it for right Ctrl and right Alt; on the real + T3100e, these keystrokes could only be generated + using 'Fn'. */ + kbd_log("ATkbc: T3100e: Read 'Fn' key\n"); + if (keyboard_recv(0xb8) || /* Right Alt */ + keyboard_recv(0x9d)) /* Right Ctrl */ + add_to_kbc_queue_front(dev, 0x04, 0, 0x00); + else + add_to_kbc_queue_front(dev, 0x00, 0, 0x00); + return 0; + + case 0xbc: /* T3100e: Reset Fn+Key notification */ + kbd_log("ATkbc: T3100e: Reset Fn+Key notification\n"); + t3100e_notify_set(0x00); + return 0; + + case 0xc0: /*Read input port*/ + kbd_log("ATkbc: read input port\n"); + + /* 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_to_kbc_queue_front(dev, dev->input_port, 0, 0x00); + return 0; + } + + return write64_generic(dev, val); +} + +static void +kbd_key_reset(atkbd_t *dev, int do_fa) +{ + dev->out_new = -1; + kbc_queue_reset(dev, 1); + + dev->kbd_last_scan_code = 0x00; + + /* Set scan code set to 2. */ + keyboard_mode = 0x02; + set_scancode_map(dev); + + /* The BAT enables scanning. */ + keyboard_scan = 1; + + dev->sc_or = 0; + + if (do_fa) + add_data_kbd_front(dev, 0xfa); + add_data_kbd_front(dev, 0xaa); + + if (!do_fa) + dev->kbd_state = DEV_STATE_MAIN_OUT; +} + +static void +kbd_aux_reset(atkbd_t *dev, int do_fa) +{ + dev->out_new_mouse = -1; + kbc_queue_reset(dev, 2); + + /* The BAT enables scanning. */ + mouse_scan = 1; + + if (!do_fa) { + add_data_kbd_front(dev, 0xaa); + add_data_kbd_front(dev, 0x00); + + dev->mouse_state = DEV_STATE_MAIN_OUT; + } +} + +void +keyboard_at_mouse_reset(void) +{ + atkbd_t *dev = SavedKbd; + + kbd_aux_reset(dev, 1); +} + +static void +kbd_process_cmd(void *priv) +{ + atkbd_t *dev = (atkbd_t *) priv; + + dev->kbd_state = DEV_STATE_MAIN_OUT; + + 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 (dev->key_dat == dev->key_command) { + /* Respond NAK and ignore it. */ + add_data_kbd_front(dev, 0xfe); + dev->key_command = 0x00; + return; + } + + switch (dev->key_command) { + case 0xed: /* set/reset LEDs */ + add_data_kbd_front(dev, 0xfa); + kbd_log("ATkbd: set LEDs [%02x]\n", dev->key_dat); + break; + + case 0xf0: /* get/set scancode set */ + add_data_kbd_front(dev, 0xfa); + if (dev->key_dat == 0) { + kbd_log("Get scan code set: %02X\n", keyboard_mode); + add_data_kbd_front(dev, keyboard_mode); + } else { + if (dev->key_dat <= 3) { + keyboard_mode = dev->key_dat; + kbd_log("Scan code set now: %02X\n", keyboard_mode); + } + set_scancode_map(dev); + } + break; + + case 0xf3: /* set typematic rate/delay */ + add_data_kbd_front(dev, 0xfa); + break; + + default: + kbd_log("ATkbd: bad keyboard 0060 write %02X command %02X\n", dev->key_dat, dev->key_command); + add_data_kbd_front(dev, 0xfe); + break; + } + + /* Keyboard command is now done. */ + dev->key_command = 0x00; + } else { + /* No keyboard command in progress. */ + dev->key_command = 0x00; + + switch (dev->key_dat) { + case 0x00 ... 0x7f: + kbd_log("ATkbd: invalid command %02X\n", dev->key_dat); + add_data_kbd_front(dev, 0xfe); + break; + + case 0xed: /* set/reset LEDs */ + kbd_log("ATkbd: set/reset leds\n"); + add_data_kbd_front(dev, 0xfa); + + dev->key_wantdata = 1; + dev->kbd_state = DEV_STATE_MAIN_WANT_IN; + break; + + case 0xee: /* diagnostic echo */ + kbd_log("ATkbd: ECHO\n"); + add_data_kbd_front(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_front(dev, 0xfa); + dev->key_wantdata = 1; + dev->kbd_state = DEV_STATE_MAIN_WANT_IN; + break; + + case 0xf2: /* read ID */ + 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_front(dev, 0xfa); + add_data_kbd_front(dev, 0xab); + add_data_kbd_front(dev, 0x83); + break; + + case 0xf3: /* set typematic rate/delay */ + kbd_log("ATkbd: set typematic rate/delay\n"); + add_data_kbd_front(dev, 0xfa); + dev->key_wantdata = 1; + dev->kbd_state = DEV_STATE_MAIN_WANT_IN; + break; + + case 0xf4: /* enable keyboard */ + kbd_log("ATkbd: enable keyboard\n"); + add_data_kbd_front(dev, 0xfa); + keyboard_scan = 1; + break; + + case 0xf5: /* set defaults and disable keyboard */ + case 0xf6: /* set defaults */ + kbd_log("ATkbd: set defaults%s\n", (dev->key_dat == 0xf6) ? "" : " and disable keyboard"); + keyboard_scan = (dev->key_dat == 0xf6); + kbd_log("dev->key_dat = %02X, keyboard_scan = %i, dev->mem[0x20] = %02X\n", + dev->key_dat, keyboard_scan, dev->mem[0]); + add_data_kbd_front(dev, 0xfa); + + keyboard_set3_all_break = 0; + keyboard_set3_all_repeat = 0; + memset(keyboard_set3_flags, 0, 512); + keyboard_mode = 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_front(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_front(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_front(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_front(dev, 0xfa); + keyboard_set3_all_repeat = 1; + keyboard_set3_all_break = 1; + break; + + case 0xfe: /* resend last scan code */ + kbd_log("ATkbd: resend last scan code\n"); + add_data_kbd_front(dev, dev->kbd_last_scan_code); + break; + + case 0xff: /* reset */ + kbd_log("ATkbd: kbd reset\n"); + kbd_key_reset(dev, 1); + break; + + default: + kbd_log("ATkbd: bad keyboard command %02X\n", dev->key_dat); + add_data_kbd_front(dev, 0xfe); + } + + /* If command needs data, remember command. */ + if (dev->key_wantdata == 1) + dev->key_command = dev->key_dat; + } +} + +static void +kbc_process_cmd(void *priv) +{ + atkbd_t *dev = (atkbd_t *) priv; + int i = 0, bad = 1; + uint8_t mask, kbc_ven = dev->flags & KBC_VEN_MASK; + uint8_t cmd_ac_conv[16] = { 0x0b, 2, 3, 4, 5, 6, 7, 8, 9, 0x0a, 0x1e, 0x30, 0x2e, 0x20, 0x12, 0x21 }; + + if (dev->status & STAT_CD) { + /* Controller command. */ + dev->want60 = 0; + dev->kbc_state = KBC_STATE_MAIN_IBF; + + /* Clear the keyboard controller queue. */ + kbc_queue_reset(dev, 0); + + switch (dev->ib) { + /* Read data from KBC memory. */ + case 0x20 ... 0x3f: + add_to_kbc_queue_front(dev, dev->mem[dev->ib], 0, 0x00); + break; + + /* Write data to KBC memory. */ + case 0x60 ... 0x7f: + dev->want60 = 1; + dev->kbc_state = KBC_STATE_KBC_PARAM; + break; + + case 0xaa: /* self-test */ + kbd_log("ATkbc: self-test\n"); + + if ((dev->flags & KBC_TYPE_MASK) >= KBC_TYPE_PS2_NOREF) { + if (dev->kbc_state != KBC_STATE_RESET) { + kbd_log("ATkbc: self-test reinitialization\n"); + /* Yes, the firmware has an OR, but we need to make sure to keep any forcibly lowered bytes lowered. */ + /* TODO: Proper P1 implementation, with OR and AND flags in the machine table. */ + dev->input_port = dev->input_port & 0xff; + write_output(dev, 0x4b); + } + + dev->status = (dev->status & 0x0f) | 0x60; + + dev->mem[0x20] = 0x30; + dev->mem[0x21] = 0x01; + dev->mem[0x22] = 0x0b; + dev->mem[0x25] = 0x02; + dev->mem[0x27] = 0xf8; + dev->mem[0x28] = 0xce; + dev->mem[0x29] = 0x0b; + dev->mem[0x2a] = 0x10; + dev->mem[0x2b] = 0x20; + dev->mem[0x2c] = 0x15; + dev->mem[0x30] = 0x0b; + } else { + if (dev->kbc_state != KBC_STATE_RESET) { + kbd_log("ATkbc: self-test reinitialization\n"); + /* Yes, the firmware has an OR, but we need to make sure to keep any forcibly lowered bytes lowered. */ + /* TODO: Proper P1 implementation, with OR and AND flags in the machine table. */ + dev->input_port = dev->input_port & 0xff; + write_output(dev, 0xcf); + } + + dev->status = (dev->status & 0x0f) | 0x60; + + dev->mem[0x20] = 0x10; + dev->mem[0x21] = 0x01; + dev->mem[0x22] = 0x06; + dev->mem[0x25] = 0x01; + dev->mem[0x27] = 0xfb; + dev->mem[0x28] = 0xe0; + dev->mem[0x29] = 0x06; + dev->mem[0x2a] = 0x10; + dev->mem[0x2b] = 0x20; + dev->mem[0x2c] = 0x15; + } + + dev->out_new = dev->out_new_mouse = -1; + kbc_queue_reset(dev, 0); + + // dev->kbc_state = KBC_STATE_MAIN_IBF; + dev->kbc_state = KBC_STATE_KBC_OUT; + + // add_to_kbc_queue_front(dev, 0x55, 0, 0x00); + kbc_queue_add(dev, 0x55, 0); + break; + + case 0xab: /* interface test */ + kbd_log("ATkbc: interface test\n"); + add_to_kbc_queue_front(dev, 0x00, 0, 0x00); /*no error*/ + break; + + case 0xac: /* diagnostic dump */ + if ((dev->flags & KBC_TYPE_MASK) >= KBC_TYPE_PS2_NOREF) { + kbd_log("ATkbc: diagnostic dump\n"); + dev->mem[0x30] = (dev->input_port & 0xf0) | 0x80; + dev->mem[0x31] = dev->output_port; + dev->mem[0x32] = 0x00; /* T0 and T1. */ + dev->mem[0x33] = 0x00; /* PSW - Program Status Word - always return 0x00 because we do not emulate this byte. */ + /* 20 bytes in high nibble in set 1, low nibble in set 1, set 1 space format = 60 bytes. */ + for (i = 0; i < 20; i++) { + kbc_queue_add(dev, cmd_ac_conv[dev->mem[i + 0x20] >> 4], 0); + kbc_queue_add(dev, cmd_ac_conv[dev->mem[i + 0x20] & 0x0f], 0); + kbc_queue_add(dev, 0x39, 0); + } + dev->kbc_state = KBC_STATE_KBC_OUT; + } + 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: /* set port1 bits */ + kbd_log("ATkbc: Phoenix - set port1 bits\n"); + dev->want60 = 1; + dev->kbc_state = KBC_STATE_KBC_PARAM; + break; + + case 0xca: /* read keyboard mode */ + kbd_log("ATkbc: AMI - read keyboard mode\n"); + add_to_kbc_queue_front(dev, dev->ami_flags, 0, 0x00); + break; + + case 0xcb: /* set keyboard mode */ + kbd_log("ATkbc: AMI - set keyboard mode\n"); + dev->want60 = 1; + dev->kbc_state = KBC_STATE_KBC_PARAM; + break; + + case 0xd0: /* read output port */ + kbd_log("ATkbc: read output port\n"); + mask = 0xff; + if ((kbc_ven != KBC_VEN_OLIVETTI) && ((dev->flags & KBC_TYPE_MASK) < KBC_TYPE_PS2_NOREF) && (dev->mem[0x20] & 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; + dev->kbc_state = KBC_STATE_KBC_PARAM; + break; + + case 0xd2: /* write keyboard output buffer */ + kbd_log("ATkbc: write keyboard output buffer\n"); + dev->want60 = 1; + dev->kbc_state = KBC_STATE_KBC_PARAM; + break; + + case 0xdd: /* disable A20 address line */ + case 0xdf: /* enable A20 address line */ + kbd_log("ATkbc: %sable A20\n", (dev->ib == 0xdd) ? "dis" : "en"); + write_output_fast_a20(dev, (dev->output_port & 0xfd) | (dev->ib & 0x02)); + break; + + case 0xe0: /* read test inputs */ + kbd_log("ATkbc: read test inputs\n"); + add_to_kbc_queue_front(dev, 0x00, 0, 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, dev->ib); + + kbd_log(bad ? "ATkbc: bad controller command %02X\n" : "", dev->ib); + } + + /* If the command needs data, remember the command. */ + if (dev->want60) + dev->command = dev->ib; + } else if (dev->want60) { + /* Write data to controller. */ + dev->want60 = 0; + dev->kbc_state = KBC_STATE_MAIN_IBF; + + switch (dev->command) { + case 0x60 ... 0x7f: + dev->mem[(dev->command & 0x1f) + 0x20] = dev->ib; + if (dev->command == 0x60) + write_cmd(dev, dev->ib); + break; + + case 0xc7: /* set port1 bits */ + kbd_log("ATkbc: Phoenix - set port1 bits\n"); + dev->input_port |= dev->ib; + break; + + case 0xd1: /* write output port */ + kbd_log("ATkbc: write output port\n"); + /* Bit 2 of AMI flags is P22-P23 blocked (1 = yes, 0 = no), + discovered by reverse-engineering the AOpen Vi15G BIOS. */ + if (dev->ami_flags & 0x04) { + /* If keyboard controller lines P22-P23 are blocked, + we force them to remain unchanged. */ + dev->ib &= ~0x0c; + dev->ib |= (dev->output_port & 0x0c); + } + write_output(dev, dev->ib | 0x01); + break; + + case 0xd2: /* write to keyboard output buffer */ + kbd_log("ATkbc: write to keyboard output buffer\n"); + add_to_kbc_queue_front(dev, dev->ib, 0, 0x00); + 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(dev->ib); + break; + + case 0xd4: /* write to mouse */ + kbd_log("ATkbc: write to mouse (%02X)\n", dev->ib); + + if (dev->ib == 0xbb) + break; + + if ((dev->flags & KBC_TYPE_MASK) >= KBC_TYPE_PS2_NOREF) { + set_enable_mouse(dev, 1); + if (mouse_write) { + dev->mouse_wantcmd = 1; + dev->mouse_dat = dev->ib; + dev->kbc_state = KBC_STATE_SEND_MOUSE; + } 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, dev->ib); + + if (bad) { + kbd_log("ATkbc: bad controller command %02x data %02x\n", dev->command, dev->ib); + } + } + } +} + +static void +kbd_write(uint16_t port, uint8_t val, void *priv) +{ + atkbd_t *dev = (atkbd_t *) priv; + + kbd_log((port == 0x61) ? "" : "[%04X:%08X] ATkbc: write(%04X) = %02X\n", CS, cpu_state.pc, port, val); + + switch (port) { + case 0x60: + dev->status &= ~STAT_CD; + if (dev->want60 && (dev->command == 0xd1)) { + kbd_log("ATkbc: write output port\n"); + + /* Fast A20 - ignore all other bits. */ + val = (val & 0x02) | (dev->output_port & 0xfd); + + /* Bit 2 of AMI flags is P22-P23 blocked (1 = yes, 0 = no), + discovered by reverse-engineering the AOpeN Vi15G BIOS. */ + if (dev->ami_flags & 0x04) { + /* If keyboard controller lines P22-P23 are blocked, + we force them to remain unchanged. */ + val &= ~0x0c; + val |= (dev->output_port & 0x0c); + } + + write_output_fast_a20(dev, val | 0x01); + + dev->want60 = 0; + dev->kbc_state = KBC_STATE_MAIN_IBF; + return; + } + break; + + case 0x64: + dev->status |= STAT_CD; + if (val == 0xd1) { + kbd_log("ATkbc: write output port\n"); + dev->want60 = 1; + dev->kbc_state = KBC_STATE_KBC_PARAM; + dev->command = 0xd1; + return; + } + break; + } + + dev->ib = val; + dev->status |= STAT_IFULL; +} + +static uint8_t +kbd_read(uint16_t port, void *priv) +{ + atkbd_t *dev = (atkbd_t *) priv; + uint8_t ret = 0xff; + + if ((dev->flags & KBC_TYPE_MASK) >= KBC_TYPE_PS2_NOREF) + cycles -= ISA_CYCLES(8); + + switch (port) { + case 0x60: + ret = dev->out; + dev->status &= ~STAT_OFULL; + /* TODO: IRQ is only tied to OBF on the AT KBC, on the PS/2 KBC, it is controlled by a bit the + output port (P2). + This also means that in AT mode, the IRQ is level-triggered. */ + if ((dev->flags & KBC_TYPE_MASK) < KBC_TYPE_PS2_NOREF) + picintc(1 << 1); + break; + + case 0x64: + ret = dev->status; + break; + + default: + kbd_log("ATkbc: read(%04x) invalid!\n",port); + break; + } + + kbd_log((port == 0x61) ? "" : "[%04X:%08X] ATkbc: read (%04X) = %02X\n", CS, cpu_state.pc, port, ret); + + return (ret); +} + +static void +kbd_reset(void *priv) +{ + atkbd_t *dev = (atkbd_t *) priv; + int i; + uint8_t kbc_ven = dev->flags & KBC_VEN_MASK; + + dev->status = STAT_UNLOCKED; + dev->mem[0x20] = 0x01; + dev->mem[0x20] |= CCB_TRANSLATE; + dev->secr_phase = 0; + dev->key_wantdata = 0; + + /* Set up the correct Video Type bits. */ + if (!is286 || (kbc_ven == KBC_VEN_ACER)) + dev->input_port = video_is_mda() ? 0xb0 : 0xf0; + else + dev->input_port = video_is_mda() ? 0xf0 : 0xb0; + kbd_log("ATkbc: input port = %02x\n", dev->input_port); + + /* Enable keyboard, disable mouse. */ + set_enable_kbd(dev, 0); + keyboard_scan = 0; + set_enable_mouse(dev, 0); + mouse_scan = 0; + + dev->out_new = dev->out_new_mouse = -1; + for (i = 0; i < 3; i++) + kbc_queue_reset(dev, i); + dev->kbd_last_scan_code = 0; + + dev->sc_or = 0; + + keyboard_mode = 0x02; + + memset(keyboard_set3_flags, 0, 512); + + set_scancode_map(dev); + + dev->ami_flags = ((dev->flags & KBC_TYPE_MASK) >= KBC_TYPE_PS2_NOREF) ? 0x01 : 0x00; + dev->ami_stat |= 0x02; + + dev->output_port = 0xcd; + if ((dev->flags & KBC_TYPE_MASK) >= KBC_TYPE_PS2_NOREF) { + write_output(dev, 0x4b); + } else { + /* The real thing writes CF and then AND's it with BF. */ + write_output(dev, 0x8f); + } + + /* Stage 1. */ + dev->status = (dev->status & 0x0f) | (dev->input_port & 0xf0); + + /* Reset the keyboard. */ + kbd_key_reset(dev, 0); + + /* Reset the mouse. */ + kbd_aux_reset(dev, 0); +} + +/* Reset the AT keyboard - this is needed for the PCI TRC and is done + until a better solution is found. */ +void +keyboard_at_reset(void) +{ + kbd_reset(SavedKbd); +} + +void +kbc_at_a20_reset(void) +{ + if (SavedKbd) { + SavedKbd->output_port = 0xcd; + if ((SavedKbd->flags & KBC_TYPE_MASK) >= KBC_TYPE_PS2_NOREF) { + write_output(SavedKbd, 0x4b); + } else { + /* The real thing writes CF and then AND's it with BF. */ + write_output(SavedKbd, 0x8f); + } + } +} + +static void +kbd_close(void *priv) +{ + atkbd_t *dev = (atkbd_t *) priv; + int i, max_ports = ((dev->flags & KBC_TYPE_MASK) >= KBC_TYPE_PS2_NOREF) ? 2 : 1; + + kbd_reset(dev); + + /* Stop timers. */ + timer_disable(&dev->send_delay_timer); + + keyboard_scan = 0; + keyboard_send = NULL; + + /* Disable the scancode maps. */ + keyboard_set_table(NULL); + + SavedKbd = NULL; + + for (i = 0; i < max_ports; i++) { + if (kbc_ports[i] != NULL) { + free(kbc_ports[i]); + kbc_ports[i] = NULL; + } + } + + free(dev); +} + +static void * +kbd_init(const device_t *info) +{ + atkbd_t *dev; + int i, max_ports; + + dev = (atkbd_t *) malloc(sizeof(atkbd_t)); + memset(dev, 0x00, sizeof(atkbd_t)); + + dev->flags = info->local; + dev->pci = !!(info->flags & DEVICE_PCI); + + /* We need this, sadly. */ + SavedKbd = dev; + + video_reset(gfxcard[0]); + kbd_reset(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); + timer_add(&dev->pulse_cb, pulse_poll, dev, 0); + + dev->write60_ven = NULL; + dev->write64_ven = NULL; + + switch (dev->flags & KBC_VEN_MASK) { + case KBC_VEN_ACER: + case KBC_VEN_GENERIC: + case KBC_VEN_NCR: + case KBC_VEN_IBM_PS1: + dev->write64_ven = write64_generic; + break; + + case KBC_VEN_OLIVETTI: + dev->write64_ven = write64_olivetti; + break; + + case KBC_VEN_AMI: + case KBC_VEN_INTEL_AMI: + case KBC_VEN_ALI: + case KBC_VEN_TG: + case KBC_VEN_TG_GREEN: + dev->write60_ven = write60_ami; + dev->write64_ven = write64_ami; + break; + + case KBC_VEN_IBM_MCA: + dev->write64_ven = write64_ibm_mca; + break; + + case KBC_VEN_QUADTEL: + dev->write60_ven = write60_quadtel; + dev->write64_ven = write64_quadtel; + break; + + case KBC_VEN_TOSHIBA: + dev->write60_ven = write60_toshiba; + dev->write64_ven = write64_toshiba; + break; + } + + max_ports = ((dev->flags & KBC_TYPE_MASK) >= KBC_TYPE_PS2_NOREF) ? 2 : 1; + + for (i = 0; i < max_ports; i++) { + kbc_ports[i] = (kbc_port_t *) malloc(sizeof(kbc_port_t)); + memset(kbc_ports[i], 0x00, sizeof(kbc_port_t)); + } + + return (dev); +} + +const device_t keyboard_at_device = { + .name = "PC/AT Keyboard", + .internal_name = "keyboard_at", + .flags = 0, + .local = KBC_TYPE_ISA | KBC_VEN_GENERIC, + .init = kbd_init, + .close = kbd_close, + .reset = kbd_reset, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL +}; + +const device_t keyboard_at_ami_device = { + .name = "PC/AT Keyboard (AMI)", + .internal_name = "keyboard_at_ami", + .flags = 0, + .local = KBC_TYPE_ISA | KBC_VEN_AMI, + .init = kbd_init, + .close = kbd_close, + .reset = kbd_reset, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL +}; + +const device_t keyboard_at_tg_ami_device = { + .name = "PC/AT Keyboard (TriGem AMI)", + .internal_name = "keyboard_at_tg_ami", + .flags = 0, + .local = KBC_TYPE_ISA | KBC_VEN_TG, + .init = kbd_init, + .close = kbd_close, + .reset = kbd_reset, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL +}; + +const device_t keyboard_at_toshiba_device = { + .name = "PC/AT Keyboard (Toshiba)", + .internal_name = "keyboard_at_toshiba", + .flags = 0, + .local = KBC_TYPE_ISA | KBC_VEN_TOSHIBA, + .init = kbd_init, + .close = kbd_close, + .reset = kbd_reset, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL +}; + +const device_t keyboard_at_olivetti_device = { + .name = "PC/AT Keyboard (Olivetti)", + .internal_name = "keyboard_at_olivetti", + .flags = 0, + .local = KBC_TYPE_ISA | KBC_VEN_OLIVETTI, + .init = kbd_init, + .close = kbd_close, + .reset = kbd_reset, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL +}; + +const device_t keyboard_at_ncr_device = { + .name = "PC/AT Keyboard (NCR)", + .internal_name = "keyboard_at_ncr", + .flags = 0, + .local = KBC_TYPE_ISA | KBC_VEN_NCR, + .init = kbd_init, + .close = kbd_close, + .reset = kbd_reset, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL +}; + +const device_t keyboard_ps2_device = { + .name = "PS/2 Keyboard", + .internal_name = "keyboard_ps2", + .flags = 0, + .local = KBC_TYPE_PS2_NOREF | KBC_VEN_GENERIC, + .init = kbd_init, + .close = kbd_close, + .reset = kbd_reset, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL +}; + +const device_t keyboard_ps2_ps1_device = { + .name = "PS/2 Keyboard (IBM PS/1)", + .internal_name = "keyboard_ps2_ps1", + .flags = 0, + .local = KBC_TYPE_PS2_NOREF | KBC_VEN_IBM_PS1, + .init = kbd_init, + .close = kbd_close, + .reset = kbd_reset, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL +}; + +const device_t keyboard_ps2_ps1_pci_device = { + .name = "PS/2 Keyboard (IBM PS/1)", + .internal_name = "keyboard_ps2_ps1_pci", + .flags = DEVICE_PCI, + .local = KBC_TYPE_PS2_NOREF | KBC_VEN_IBM_PS1, + .init = kbd_init, + .close = kbd_close, + .reset = kbd_reset, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL +}; + +const device_t keyboard_ps2_xi8088_device = { + .name = "PS/2 Keyboard (Xi8088)", + .internal_name = "keyboard_ps2_xi8088", + .flags = 0, + .local = KBC_TYPE_PS2_1 | KBC_VEN_GENERIC, + .init = kbd_init, + .close = kbd_close, + .reset = kbd_reset, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL +}; + +const device_t keyboard_ps2_ami_device = { + .name = "PS/2 Keyboard (AMI)", + .internal_name = "keyboard_ps2_ami", + .flags = 0, + .local = KBC_TYPE_PS2_NOREF | KBC_VEN_AMI, + .init = kbd_init, + .close = kbd_close, + .reset = kbd_reset, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL +}; + +const device_t keyboard_ps2_tg_ami_device = { + .name = "PS/2 Keyboard (TriGem AMI)", + .internal_name = "keyboard_ps2_tg_ami", + .flags = 0, + .local = KBC_TYPE_PS2_NOREF | KBC_VEN_TG, + .init = kbd_init, + .close = kbd_close, + .reset = kbd_reset, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL +}; + +const device_t keyboard_ps2_mca_device = { + .name = "PS/2 Keyboard", + .internal_name = "keyboard_ps2_mca", + .flags = 0, + .local = KBC_TYPE_PS2_1 | KBC_VEN_IBM_MCA, + .init = kbd_init, + .close = kbd_close, + .reset = kbd_reset, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL +}; + +const device_t keyboard_ps2_mca_2_device = { + .name = "PS/2 Keyboard", + .internal_name = "keyboard_ps2_mca_2", + .flags = 0, + .local = KBC_TYPE_PS2_2 | KBC_VEN_IBM_MCA, + .init = kbd_init, + .close = kbd_close, + .reset = kbd_reset, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL +}; + +const device_t keyboard_ps2_quadtel_device = { + .name = "PS/2 Keyboard (Quadtel/MegaPC)", + .internal_name = "keyboard_ps2_quadtel", + .flags = 0, + .local = KBC_TYPE_PS2_NOREF | KBC_VEN_QUADTEL, + .init = kbd_init, + .close = kbd_close, + .reset = kbd_reset, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL +}; + +const device_t keyboard_ps2_pci_device = { + .name = "PS/2 Keyboard", + .internal_name = "keyboard_ps2_pci", + .flags = DEVICE_PCI, + .local = KBC_TYPE_PS2_NOREF | KBC_VEN_GENERIC, + .init = kbd_init, + .close = kbd_close, + .reset = kbd_reset, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL +}; + +const device_t keyboard_ps2_ami_pci_device = { + .name = "PS/2 Keyboard (AMI)", + .internal_name = "keyboard_ps2_ami_pci", + .flags = DEVICE_PCI, + .local = KBC_TYPE_PS2_NOREF | KBC_VEN_AMI, + .init = kbd_init, + .close = kbd_close, + .reset = kbd_reset, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL +}; + +const device_t keyboard_ps2_ali_pci_device = { + .name = "PS/2 Keyboard (ALi M5123/M1543C)", + .internal_name = "keyboard_ps2_ali_pci", + .flags = DEVICE_PCI, + .local = KBC_TYPE_PS2_NOREF | KBC_VEN_ALI, + .init = kbd_init, + .close = kbd_close, + .reset = kbd_reset, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL +}; + +const device_t keyboard_ps2_intel_ami_pci_device = { + .name = "PS/2 Keyboard (AMI)", + .internal_name = "keyboard_ps2_intel_ami_pci", + .flags = DEVICE_PCI, + .local = KBC_TYPE_PS2_NOREF | KBC_VEN_INTEL_AMI, + .init = kbd_init, + .close = kbd_close, + .reset = kbd_reset, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL +}; + +const device_t keyboard_ps2_tg_ami_pci_device = { + .name = "PS/2 Keyboard (TriGem AMI)", + .internal_name = "keyboard_ps2_tg_ami_pci", + .flags = DEVICE_PCI, + .local = KBC_TYPE_PS2_NOREF | KBC_VEN_TG, + .init = kbd_init, + .close = kbd_close, + .reset = kbd_reset, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL +}; + +const device_t keyboard_ps2_acer_pci_device = { + .name = "PS/2 Keyboard (Acer 90M002A)", + .internal_name = "keyboard_ps2_acer_pci", + .flags = DEVICE_PCI, + .local = KBC_TYPE_PS2_NOREF | KBC_VEN_ACER, + .init = kbd_init, + .close = kbd_close, + .reset = kbd_reset, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL +}; + +void +keyboard_at_set_mouse(void (*func)(uint8_t val, void *priv), void *priv) +{ + mouse_write = func; + mouse_p = priv; +} + +void +keyboard_at_adddata_mouse(uint8_t val) +{ + atkbd_t *dev = SavedKbd; + + if (!mouse_scan || (dev->mouse_queue_end >= 16)) { + kbd_log("ATkbc: Unable to add to queue, conditions: %i, %i\n", !mouse_scan, (dev->mouse_queue_end >= 16)); + return; + } + kbc_queue_add(dev, val, 2); +} + +void +keyboard_at_adddata_mouse_cmd(uint8_t val) +{ + atkbd_t *dev = SavedKbd; + + if (dev->mouse_cmd_queue_end >= 16) { + kbd_log("ATkbc: Unable to add to queue, dev->mouse_cmd_queue_end >= 16\n"); + return; + } + kbc_queue_add(dev, val, 3); +} + +uint8_t +keyboard_at_mouse_pos(void) +{ + atkbd_t *dev = SavedKbd; + + return ((dev->mouse_queue_end - dev->mouse_queue_start) & 0xf); +} + +void +keyboard_at_set_a20_key(int state) +{ + atkbd_t *dev = SavedKbd; + + write_output(dev, (dev->output_port & 0xfd) | ((!!state) << 1)); +} diff --git a/src/device/mouse_ps2 - Cópia.c b/src/device/mouse_ps2 - Cópia.c new file mode 100644 index 000000000..1c8e0334d --- /dev/null +++ b/src/device/mouse_ps2 - Cópia.c @@ -0,0 +1,404 @@ +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * This file is part of the 86Box distribution. + * + * Implementation of PS/2 series Mouse devices. + * + * + * + * Authors: Fred N. van Kempen, + */ +#include +#include +#include +#include +#include +#include +#define HAVE_STDARG_H +#include <86box/86box.h> +#include <86box/device.h> +#include <86box/keyboard.h> +#include <86box/mouse.h> + +enum { + MODE_STREAM, + MODE_REMOTE, + MODE_ECHO +}; + +typedef struct { + const char *name; /* name of this device */ + int8_t type; /* type of this device */ + + int mode; + + uint16_t flags; + uint8_t resolution; + uint8_t sample_rate; + + uint8_t command; + + int x, y, z, b; + + uint8_t last_data[6]; +} mouse_t; +#define FLAG_5BTN 0x100 /* using Intellimouse Optical mode */ +#define FLAG_INTELLI 0x80 /* device is IntelliMouse */ +#define FLAG_INTMODE 0x40 /* using Intellimouse mode */ +#define FLAG_SCALED 0x20 /* enable delta scaling */ +#define FLAG_ENABLED 0x10 /* dev is enabled for use */ +#define FLAG_CTRLDAT 0x08 /* ctrl or data mode */ + +int mouse_scan = 0; + +#ifdef ENABLE_MOUSE_PS2_LOG +int mouse_ps2_do_log = ENABLE_MOUSE_PS2_LOG; + +static void +mouse_ps2_log(const char *fmt, ...) +{ + va_list ap; + + if (mouse_ps2_do_log) { + va_start(ap, fmt); + pclog_ex(fmt, ap); + va_end(ap); + } +} +#else +# define mouse_ps2_log(fmt, ...) +#endif + +void +mouse_clear_data(void *priv) +{ + mouse_t *dev = (mouse_t *) priv; + + dev->flags &= ~FLAG_CTRLDAT; +} + +static void +ps2_report_coordinates(mouse_t *dev, int cmd) +{ + uint8_t buff[3] = { 0x08, 0x00, 0x00 }; + int temp_z; + + if (dev->x > 255) { + dev->x = 255; + buff[0] |= 0x40; + } + if (dev->x < -256) { + dev->x = -256; + buff[0] |= 0x40; + } + if (dev->y > 255) { + dev->y = 255; + buff[0] |= 0x80; + } + if (dev->y < -256) { + dev->y = -256; + buff[0] |= 0x80; + } + if (dev->z < -8) + dev->z = -8; + if (dev->z > 7) + dev->z = 7; + + if (dev->x < 0) + buff[0] |= 0x10; + if (dev->y < 0) + buff[0] |= 0x20; + if (mouse_buttons & 0x01) + buff[0] |= 0x01; + if (mouse_buttons & 0x02) + buff[0] |= 0x02; + if (dev->flags & FLAG_INTELLI) { + if (mouse_buttons & 0x04) + buff[0] |= 0x04; + } + buff[1] = (dev->x & 0xff); + buff[2] = (dev->y & 0xff); + + if (cmd) { + keyboard_at_adddata_mouse_cmd(buff[0]); + keyboard_at_adddata_mouse_cmd(buff[1]); + keyboard_at_adddata_mouse_cmd(buff[2]); + } else { + keyboard_at_adddata_mouse(buff[0]); + keyboard_at_adddata_mouse(buff[1]); + keyboard_at_adddata_mouse(buff[2]); + } + if (dev->flags & FLAG_INTMODE) { + temp_z = dev->z & 0x0f; + if ((dev->flags & FLAG_5BTN)) { + if (mouse_buttons & 8) + temp_z |= 0x10; + if (mouse_buttons & 16) + temp_z |= 0x20; + } else { + /* The wheel coordinate is sign-extended. */ + if (temp_z & 0x08) + temp_z |= 0xf0; + } + if (cmd) + keyboard_at_adddata_mouse_cmd(temp_z); + else + keyboard_at_adddata_mouse(temp_z); + } + + dev->x = dev->y = dev->z = 0; +} + +static void +ps2_write(uint8_t val, void *priv) +{ + mouse_t *dev = (mouse_t *) priv; + uint8_t temp; + + if (dev->flags & FLAG_CTRLDAT) { + dev->flags &= ~FLAG_CTRLDAT; + + if (val == 0xff) + goto mouse_reset; + + switch (dev->command) { + case 0xe8: /* set mouse resolution */ + dev->resolution = val; + keyboard_at_adddata_mouse_cmd(0xfa); + break; + + case 0xf3: /* set sample rate */ + dev->sample_rate = val; + keyboard_at_adddata_mouse_cmd(0xfa); /* Command response */ + break; + + default: + keyboard_at_adddata_mouse_cmd(0xfc); + } + } else { + dev->command = val; + + switch (dev->command) { + case 0xe6: /* set scaling to 1:1 */ + dev->flags &= ~FLAG_SCALED; + keyboard_at_adddata_mouse_cmd(0xfa); + break; + + case 0xe7: /* set scaling to 2:1 */ + dev->flags |= FLAG_SCALED; + keyboard_at_adddata_mouse_cmd(0xfa); + break; + + case 0xe8: /* set mouse resolution */ + dev->flags |= FLAG_CTRLDAT; + keyboard_at_adddata_mouse_cmd(0xfa); + break; + + case 0xe9: /* status request */ + keyboard_at_adddata_mouse_cmd(0xfa); + temp = (dev->flags & 0x30); + if (mouse_buttons & 1) + temp |= 4; + if (mouse_buttons & 2) + temp |= 1; + if ((mouse_buttons & 4) && (dev->flags & FLAG_INTELLI)) + temp |= 2; + keyboard_at_adddata_mouse_cmd(temp); + keyboard_at_adddata_mouse_cmd(dev->resolution); + keyboard_at_adddata_mouse_cmd(dev->sample_rate); + break; + + case 0xea: /* set stream */ + dev->flags &= ~FLAG_CTRLDAT; + mouse_scan = 1; + keyboard_at_adddata_mouse_cmd(0xfa); /* ACK for command byte */ + break; + + case 0xeb: /* Get mouse data */ + keyboard_at_adddata_mouse_cmd(0xfa); + + ps2_report_coordinates(dev, 1); + break; + + case 0xf2: /* read ID */ + keyboard_at_adddata_mouse_cmd(0xfa); + if (dev->flags & FLAG_INTMODE) + keyboard_at_adddata_mouse_cmd((dev->flags & FLAG_5BTN) ? 0x04 : 0x03); + else + keyboard_at_adddata_mouse_cmd(0x00); + break; + + case 0xf3: /* set command mode */ + dev->flags |= FLAG_CTRLDAT; + keyboard_at_adddata_mouse_cmd(0xfa); /* ACK for command byte */ + break; + + case 0xf4: /* enable */ + dev->flags |= FLAG_ENABLED; + mouse_scan = 1; + keyboard_at_adddata_mouse_cmd(0xfa); + break; + + case 0xf5: /* disable */ + dev->flags &= ~FLAG_ENABLED; + mouse_scan = 0; + keyboard_at_adddata_mouse_cmd(0xfa); + break; + + case 0xf6: /* set defaults */ + case 0xff: /* reset */ +mouse_reset: + dev->mode = MODE_STREAM; + dev->flags &= 0x88; + mouse_scan = 1; + keyboard_at_mouse_reset(); + keyboard_at_adddata_mouse_cmd(0xfa); + if (dev->command == 0xff) { + keyboard_at_adddata_mouse_cmd(0xaa); + keyboard_at_adddata_mouse_cmd(0x00); + } + break; + + default: + keyboard_at_adddata_mouse_cmd(0xfe); + } + } + + if (dev->flags & FLAG_INTELLI) { + for (temp = 0; temp < 5; temp++) + dev->last_data[temp] = dev->last_data[temp + 1]; + + dev->last_data[5] = val; + + if ((dev->last_data[0] == 0xf3) && (dev->last_data[1] == 0xc8) && + (dev->last_data[2] == 0xf3) && (dev->last_data[3] == 0x64) && + (dev->last_data[4] == 0xf3) && (dev->last_data[5] == 0x50)) + dev->flags |= FLAG_INTMODE; + + if ((dev->flags & FLAG_INTMODE) && (dev->last_data[0] == 0xf3) && (dev->last_data[1] == 0xc8) && + (dev->last_data[2] == 0xf3) && (dev->last_data[3] == 0xc8) && + (dev->last_data[4] == 0xf3) && (dev->last_data[5] == 0x50)) + dev->flags |= FLAG_5BTN; + } +} + +static int +ps2_poll(int x, int y, int z, int b, double abs_x, double abs_y, void *priv) +{ + mouse_t *dev = (mouse_t *) priv; + + if (!x && !y && !z && (b == dev->b)) + return (0xff); + +#if 0 + if (!(dev->flags & FLAG_ENABLED)) + return(0xff); +#endif + + if (!mouse_scan) + return (0xff); + + dev->x += x; + dev->y -= y; + dev->z -= z; +#if 0 + if ((dev->mode == MODE_STREAM) && (dev->flags & FLAG_ENABLED) && (keyboard_at_mouse_pos() < 13)) { +#else + if ((dev->mode == MODE_STREAM) && (keyboard_at_mouse_pos() < 13)) { +#endif + dev->b = b; + + ps2_report_coordinates(dev, 0); + } + + return (0); +} + +/* + * Initialize the device for use by the user. + * + * We also get called from the various machines. + */ +void * +mouse_ps2_init(const device_t *info) +{ + mouse_t *dev; + int i; + + dev = (mouse_t *) malloc(sizeof(mouse_t)); + memset(dev, 0x00, sizeof(mouse_t)); + dev->name = info->name; + dev->type = info->local; + + dev->mode = MODE_STREAM; + i = device_get_config_int("buttons"); + if (i > 2) + dev->flags |= FLAG_INTELLI; + + if (i == 4) + i = 3; + + /* Hook into the general AT Keyboard driver. */ + keyboard_at_set_mouse(ps2_write, dev); + + mouse_ps2_log("%s: buttons=%d\n", dev->name, i); + + /* Tell them how many buttons we have. */ + mouse_set_buttons(i); + + /* Return our private data to the I/O layer. */ + return (dev); +} + +static void +ps2_close(void *priv) +{ + mouse_t *dev = (mouse_t *) priv; + + /* Unhook from the general AT Keyboard driver. */ + keyboard_at_set_mouse(NULL, NULL); + + free(dev); +} + +static const device_config_t ps2_config[] = { + // clang-format off + { + .name = "buttons", + .description = "Buttons", + .type = CONFIG_SELECTION, + .default_string = "", + .default_int = 2, + .file_filter = "", + .spinner = { 0 }, + .selection = { + { .description = "Two", .value = 2 }, + { .description = "Three", .value = 3 }, + { .description = "Wheel", .value = 4 }, + { .description = "Five + Wheel", .value = 5 }, + { .description = "" } + } + }, + { + .name = "", .description = "", .type = CONFIG_END + } + // clang-format on +}; + +const device_t mouse_ps2_device = { + .name = "Standard PS/2 Mouse", + .internal_name = "ps2", + .flags = DEVICE_PS2, + .local = MOUSE_TYPE_PS2, + .init = mouse_ps2_init, + .close = ps2_close, + .reset = NULL, + { .poll = ps2_poll }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = ps2_config +}; diff --git a/src/include/86box/usb.h b/src/include/86box/usb.h index ab9ae53a7..6582f05e4 100644 --- a/src/include/86box/usb.h +++ b/src/include/86box/usb.h @@ -27,25 +27,27 @@ typedef struct usb_t usb_t; /* USB device creation parameters struct */ typedef struct { - void (*raise_interrupt)(usb_t*, void*); + void (*update_interrupt)(usb_t*, void*); /* Handle (but do not raise) SMI. Returns 1 if SMI can be raised, 0 otherwise. */ uint8_t (*smi_handle)(usb_t*, void*); void* parent_priv; } usb_params_t; +typedef union +{ + uint32_t l; + uint16_t w[2]; + uint8_t b[4]; +} ohci_mmio_t; + /* USB Host Controller device struct */ typedef struct usb_t { - union - { - uint8_t ohci_mmio[4096]; - uint16_t ohci_mmio_w[2048]; - uint32_t ohci_mmio_l[1024]; - }; uint8_t uhci_io[32]; + ohci_mmio_t ohci_mmio[1024]; uint16_t uhci_io_base; int uhci_enable, ohci_enable; - uint32_t ohci_mem_base; + uint32_t ohci_mem_base, irq_level; mem_mapping_t ohci_mmio_mapping; pc_timer_t ohci_frame_timer; pc_timer_t ohci_interrupt_desc_poll_timer; diff --git a/src/mem/mem - Cópia.c b/src/mem/mem - Cópia.c new file mode 100644 index 000000000..a8d9e994d --- /dev/null +++ b/src/mem/mem - Cópia.c @@ -0,0 +1,3092 @@ +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * This file is part of the 86Box distribution. + * + * Memory handling and MMU. + * + * Authors: Sarah Walker, + * Miran Grca, + * Fred N. van Kempen, + * + * Copyright 2008-2020 Sarah Walker. + * Copyright 2016-2020 Miran Grca. + * Copyright 2017-2020 Fred N. van Kempen. + */ +#include +#include +#include +#include +#include +#include +#include +#define HAVE_STDARG_H +#include <86box/86box.h> +#include <86box/version.h> +#include "cpu.h" +#include "x86_ops.h" +#include "x86.h" +#include <86box/machine.h> +#include <86box/m_xt_xi8088.h> +#include <86box/config.h> +#include <86box/io.h> +#include <86box/mem.h> +#include <86box/plat.h> +#include <86box/rom.h> +#include <86box/gdbstub.h> +#ifdef USE_DYNAREC +# include "codegen_public.h" +#else +# ifdef USE_NEW_DYNAREC +# define PAGE_MASK_SHIFT 6 +# else +# define PAGE_MASK_INDEX_MASK 3 +# define PAGE_MASK_INDEX_SHIFT 10 +# define PAGE_MASK_SHIFT 4 +# endif +# define PAGE_MASK_MASK 63 +#endif +#if (!defined(USE_DYNAREC) && defined(USE_NEW_DYNAREC)) +# define BLOCK_PC_INVALID 0xffffffff +# define BLOCK_INVALID 0 +#endif + +mem_mapping_t ram_low_mapping, /* 0..640K mapping */ + ram_mid_mapping, /* 640..1024K mapping */ + ram_mid_mapping2, /* 640..1024K mapping, second part, for SiS 471 in relocate mode */ + ram_remapped_mapping, /* 640..1024K mapping */ + ram_remapped_mapping2, /* 640..1024K second mapping, for SiS 471 mode */ + ram_high_mapping, /* 1024K+ mapping */ + ram_2gb_mapping, /* 1024M+ mapping */ + ram_split_mapping, + bios_mapping, + bios_high_mapping; + +page_t *pages, /* RAM page table */ + **page_lookup; /* pagetable lookup */ +uint32_t pages_sz; /* #pages in table */ + +uint8_t *ram, *ram2; /* the virtual RAM */ +uint8_t page_ff[4096]; +uint32_t rammask; +uint32_t addr_space_size; + +uint8_t *rom; /* the virtual ROM */ +uint32_t biosmask, biosaddr; + +uint32_t pccache; +uint8_t *pccache2; + +int readlnext; +int readlookup[256]; +uintptr_t *readlookup2; +uintptr_t old_rl2; +uint8_t uncached = 0; +int writelnext; +int writelookup[256]; +uintptr_t *writelookup2; + +uint32_t mem_logical_addr; + +int shadowbios = 0, + shadowbios_write; +int readlnum = 0, + writelnum = 0; +int cachesize = 256; + +uint32_t get_phys_virt, + get_phys_phys; + +int mem_a20_key = 0, + mem_a20_alt = 0, + mem_a20_state = 0; + +int mmuflush = 0; +int mmu_perm = 4; + +#ifdef USE_NEW_DYNAREC +uint64_t *byte_dirty_mask; +uint64_t *byte_code_present_mask; + +uint32_t purgable_page_list_head = 0; +int purgeable_page_count = 0; +#endif + +uint8_t high_page = 0; /* if a high (> 4 gb) page was detected */ + +/* FIXME: re-do this with a 'mem_ops' struct. */ +static uint8_t *page_lookupp; /* pagetable mmu_perm lookup */ +static uint8_t *readlookupp; +static uint8_t *writelookupp; +static mem_mapping_t *base_mapping, *last_mapping; +static mem_mapping_t *read_mapping[MEM_MAPPINGS_NO]; +static mem_mapping_t *write_mapping[MEM_MAPPINGS_NO]; +static mem_mapping_t *read_mapping_bus[MEM_MAPPINGS_NO]; +static mem_mapping_t *write_mapping_bus[MEM_MAPPINGS_NO]; +static uint8_t *_mem_exec[MEM_MAPPINGS_NO]; +static uint8_t ff_pccache[4] = { 0xff, 0xff, 0xff, 0xff }; +static mem_state_t _mem_state[MEM_MAPPINGS_NO]; +static uint32_t remap_start_addr, remap_start_addr2; +#if (!(defined __amd64__ || defined _M_X64 || defined __aarch64__ || defined _M_ARM64)) +static size_t ram_size = 0, ram2_size = 0; +#else +static size_t ram_size = 0; +#endif + +#ifdef ENABLE_MEM_LOG +int mem_do_log = ENABLE_MEM_LOG; + +static void +mem_log(const char *fmt, ...) +{ + va_list ap; + + if (mem_do_log) { + va_start(ap, fmt); + pclog_ex(fmt, ap); + va_end(ap); + } +} +#else +# define mem_log(fmt, ...) +#endif + +int +mem_addr_is_ram(uint32_t addr) +{ + mem_mapping_t *mapping = read_mapping[addr >> MEM_GRANULARITY_BITS]; + + return (mapping == &ram_low_mapping) || (mapping == &ram_high_mapping) || (mapping == &ram_mid_mapping) || + (mapping == &ram_mid_mapping2) || (mapping == &ram_remapped_mapping); +} + +void +resetreadlookup(void) +{ + int c; + + /* Initialize the page lookup table. */ + memset(page_lookup, 0x00, (1 << 20) * sizeof(page_t *)); + + /* Initialize the tables for lower (<= 1024K) RAM. */ + for (c = 0; c < 256; c++) { + readlookup[c] = 0xffffffff; + writelookup[c] = 0xffffffff; + } + + /* Initialize the tables for high (> 1024K) RAM. */ + memset(readlookup2, 0xff, (1 << 20) * sizeof(uintptr_t)); + memset(readlookupp, 0x04, (1 << 20) * sizeof(uint8_t)); + + memset(writelookup2, 0xff, (1 << 20) * sizeof(uintptr_t)); + memset(writelookupp, 0x04, (1 << 20) * sizeof(uint8_t)); + + readlnext = 0; + writelnext = 0; + pccache = 0xffffffff; + high_page = 0; +} + +void +flushmmucache(void) +{ + int c; + + for (c = 0; c < 256; c++) { + if (readlookup[c] != (int) 0xffffffff) { + readlookup2[readlookup[c]] = LOOKUP_INV; + readlookupp[readlookup[c]] = 4; + readlookup[c] = 0xffffffff; + } + if (writelookup[c] != (int) 0xffffffff) { + page_lookup[writelookup[c]] = NULL; + page_lookupp[writelookup[c]] = 4; + writelookup2[writelookup[c]] = LOOKUP_INV; + writelookupp[writelookup[c]] = 4; + writelookup[c] = 0xffffffff; + } + } + mmuflush++; + + pccache = (uint32_t) 0xffffffff; + pccache2 = (uint8_t *) 0xffffffff; + +#ifdef USE_DYNAREC + codegen_flush(); +#endif +} + +void +flushmmucache_nopc(void) +{ + int c; + + for (c = 0; c < 256; c++) { + if (readlookup[c] != (int) 0xffffffff) { + readlookup2[readlookup[c]] = LOOKUP_INV; + readlookupp[readlookup[c]] = 4; + readlookup[c] = 0xffffffff; + } + if (writelookup[c] != (int) 0xffffffff) { + page_lookup[writelookup[c]] = NULL; + page_lookupp[writelookup[c]] = 4; + writelookup2[writelookup[c]] = LOOKUP_INV; + writelookupp[writelookup[c]] = 4; + writelookup[c] = 0xffffffff; + } + } +} + +void +mem_flush_write_page(uint32_t addr, uint32_t virt) +{ + page_t *page_target = &pages[addr >> 12]; + int c; +#if (!(defined __amd64__ || defined _M_X64 || defined __aarch64__ || defined _M_ARM64)) + uint32_t a; +#endif + + for (c = 0; c < 256; c++) { + if (writelookup[c] != (int) 0xffffffff) { +#if (defined __amd64__ || defined _M_X64 || defined __aarch64__ || defined _M_ARM64) + uintptr_t target = (uintptr_t) &ram[(uintptr_t) (addr & ~0xfff) - (virt & ~0xfff)]; +#else + a = (uintptr_t) (addr & ~0xfff) - (virt & ~0xfff); + uintptr_t target; + + if ((addr & ~0xfff) >= (1 << 30)) + target = (uintptr_t) &ram2[a - (1 << 30)]; + else + target = (uintptr_t) &ram[a]; +#endif + + if (writelookup2[writelookup[c]] == target || page_lookup[writelookup[c]] == page_target) { + writelookup2[writelookup[c]] = LOOKUP_INV; + page_lookup[writelookup[c]] = NULL; + writelookup[c] = 0xffffffff; + } + } + } +} + +#define mmutranslate_read(addr) mmutranslatereal(addr, 0) +#define mmutranslate_write(addr) mmutranslatereal(addr, 1) +#define rammap(x) ((uint32_t *) (_mem_exec[(x) >> MEM_GRANULARITY_BITS]))[((x) >> 2) & MEM_GRANULARITY_QMASK] +#define rammap64(x) ((uint64_t *) (_mem_exec[(x) >> MEM_GRANULARITY_BITS]))[((x) >> 3) & MEM_GRANULARITY_PMASK] + +static __inline uint64_t +mmutranslatereal_normal(uint32_t addr, int rw) +{ + uint32_t temp, temp2, temp3; + uint32_t addr2; + + if (cpu_state.abrt) + return 0xffffffffffffffffULL; + + addr2 = ((cr3 & ~0xfff) + ((addr >> 20) & 0xffc)); + temp = temp2 = rammap(addr2); + if (!(temp & 1)) { + cr2 = addr; + temp &= 1; + if (CPL == 3) + temp |= 4; + if (rw) + temp |= 2; + cpu_state.abrt = ABRT_PF; + abrt_error = temp; + return 0xffffffffffffffffULL; + } + + if ((temp & 0x80) && (cr4 & CR4_PSE)) { + /*4MB page*/ + if (((CPL == 3) && !(temp & 4) && !cpl_override) || (rw && !(temp & 2) && (((CPL == 3) && !cpl_override) || ((is486 || isibm486) && (cr0 & WP_FLAG))))) { + cr2 = addr; + temp &= 1; + if (CPL == 3) + temp |= 4; + if (rw) + temp |= 2; + cpu_state.abrt = ABRT_PF; + abrt_error = temp; + + return 0xffffffffffffffffULL; + } + + mmu_perm = temp & 4; + rammap(addr2) |= (rw ? 0x60 : 0x20); + + return (temp & ~0x3fffff) + (addr & 0x3fffff); + } + + temp = rammap((temp & ~0xfff) + ((addr >> 10) & 0xffc)); + temp3 = temp & temp2; + if (!(temp & 1) || ((CPL == 3) && !(temp3 & 4) && !cpl_override) || (rw && !(temp3 & 2) && (((CPL == 3) && !cpl_override) || ((is486 || isibm486) && (cr0 & WP_FLAG))))) { + cr2 = addr; + temp &= 1; + if (CPL == 3) + temp |= 4; + if (rw) + temp |= 2; + cpu_state.abrt = ABRT_PF; + abrt_error = temp; + return 0xffffffffffffffffULL; + } + + mmu_perm = temp & 4; + rammap(addr2) |= 0x20; + rammap((temp2 & ~0xfff) + ((addr >> 10) & 0xffc)) |= (rw ? 0x60 : 0x20); + + return (uint64_t) ((temp & ~0xfff) + (addr & 0xfff)); +} + +static __inline uint64_t +mmutranslatereal_pae(uint32_t addr, int rw) +{ + uint64_t temp, temp2, temp3, temp4; + uint64_t addr2, addr3, addr4; + + if (cpu_state.abrt) + return 0xffffffffffffffffULL; + + addr2 = (cr3 & ~0x1f) + ((addr >> 27) & 0x18); + temp = temp2 = rammap64(addr2) & 0x000000ffffffffffULL; + if (!(temp & 1)) { + cr2 = addr; + temp &= 1; + if (CPL == 3) + temp |= 4; + if (rw) + temp |= 2; + cpu_state.abrt = ABRT_PF; + abrt_error = temp; + return 0xffffffffffffffffULL; + } + + addr3 = (temp & ~0xfffULL) + ((addr >> 18) & 0xff8); + temp = temp4 = rammap64(addr3) & 0x000000ffffffffffULL; + temp3 = temp & temp2; + if (!(temp & 1)) { + cr2 = addr; + temp &= 1; + if (CPL == 3) + temp |= 4; + if (rw) + temp |= 2; + cpu_state.abrt = ABRT_PF; + abrt_error = temp; + return 0xffffffffffffffffULL; + } + + if (temp & 0x80) { + /*2MB page*/ + if (((CPL == 3) && !(temp & 4) && !cpl_override) || (rw && !(temp & 2) && (((CPL == 3) && !cpl_override) || (cr0 & WP_FLAG)))) { + cr2 = addr; + temp &= 1; + if (CPL == 3) + temp |= 4; + if (rw) + temp |= 2; + cpu_state.abrt = ABRT_PF; + abrt_error = temp; + + return 0xffffffffffffffffULL; + } + mmu_perm = temp & 4; + rammap64(addr3) |= (rw ? 0x60 : 0x20); + + return ((temp & ~0x1fffffULL) + (addr & 0x1fffffULL)) & 0x000000ffffffffffULL; + } + + addr4 = (temp & ~0xfffULL) + ((addr >> 9) & 0xff8); + temp = rammap64(addr4) & 0x000000ffffffffffULL; + temp3 = temp & temp4; + if (!(temp & 1) || ((CPL == 3) && !(temp3 & 4) && !cpl_override) || (rw && !(temp3 & 2) && (((CPL == 3) && !cpl_override) || (cr0 & WP_FLAG)))) { + cr2 = addr; + temp &= 1; + if (CPL == 3) + temp |= 4; + if (rw) + temp |= 2; + cpu_state.abrt = ABRT_PF; + abrt_error = temp; + return 0xffffffffffffffffULL; + } + + mmu_perm = temp & 4; + rammap64(addr3) |= 0x20; + rammap64(addr4) |= (rw ? 0x60 : 0x20); + + return ((temp & ~0xfffULL) + ((uint64_t) (addr & 0xfff))) & 0x000000ffffffffffULL; +} + +uint64_t +mmutranslatereal(uint32_t addr, int rw) +{ + /* Fast path to return invalid without any call if an exception has occurred beforehand. */ + if (cpu_state.abrt) + return 0xffffffffffffffffULL; + + if (cr4 & CR4_PAE) + return mmutranslatereal_pae(addr, rw); + else + return mmutranslatereal_normal(addr, rw); +} + +/* This is needed because the old recompiler calls this to check for page fault. */ +uint32_t +mmutranslatereal32(uint32_t addr, int rw) +{ + /* Fast path to return invalid without any call if an exception has occurred beforehand. */ + if (cpu_state.abrt) + return (uint32_t) 0xffffffffffffffffULL; + + return (uint32_t) mmutranslatereal(addr, rw); +} + +static __inline uint64_t +mmutranslate_noabrt_normal(uint32_t addr, int rw) +{ + uint32_t temp, temp2, temp3; + uint32_t addr2; + + if (cpu_state.abrt) + return 0xffffffffffffffffULL; + + addr2 = ((cr3 & ~0xfff) + ((addr >> 20) & 0xffc)); + temp = temp2 = rammap(addr2); + + if (!(temp & 1)) + return 0xffffffffffffffffULL; + + if ((temp & 0x80) && (cr4 & CR4_PSE)) { + /*4MB page*/ + if (((CPL == 3) && !(temp & 4) && !cpl_override) || (rw && !(temp & 2) && ((CPL == 3) || (cr0 & WP_FLAG)))) + return 0xffffffffffffffffULL; + + return (temp & ~0x3fffff) + (addr & 0x3fffff); + } + + temp = rammap((temp & ~0xfff) + ((addr >> 10) & 0xffc)); + temp3 = temp & temp2; + + if (!(temp & 1) || ((CPL == 3) && !(temp3 & 4) && !cpl_override) || (rw && !(temp3 & 2) && ((CPL == 3) || (cr0 & WP_FLAG)))) + return 0xffffffffffffffffULL; + + return (uint64_t) ((temp & ~0xfff) + (addr & 0xfff)); +} + +static __inline uint64_t +mmutranslate_noabrt_pae(uint32_t addr, int rw) +{ + uint64_t temp, temp2, temp3, temp4; + uint64_t addr2, addr3, addr4; + + if (cpu_state.abrt) + return 0xffffffffffffffffULL; + + addr2 = (cr3 & ~0x1f) + ((addr >> 27) & 0x18); + temp = temp2 = rammap64(addr2) & 0x000000ffffffffffULL; + + if (!(temp & 1)) + return 0xffffffffffffffffULL; + + addr3 = (temp & ~0xfffULL) + ((addr >> 18) & 0xff8); + temp = temp4 = rammap64(addr3) & 0x000000ffffffffffULL; + temp3 = temp & temp2; + + if (!(temp & 1)) + return 0xffffffffffffffffULL; + + if (temp & 0x80) { + /*2MB page*/ + if (((CPL == 3) && !(temp & 4) && !cpl_override) || (rw && !(temp & 2) && ((CPL == 3) || (cr0 & WP_FLAG)))) + return 0xffffffffffffffffULL; + + return ((temp & ~0x1fffffULL) + (addr & 0x1fffff)) & 0x000000ffffffffffULL; + } + + addr4 = (temp & ~0xfffULL) + ((addr >> 9) & 0xff8); + temp = rammap64(addr4) & 0x000000ffffffffffULL; + ; + temp3 = temp & temp4; + + if (!(temp & 1) || ((CPL == 3) && !(temp3 & 4) && !cpl_override) || (rw && !(temp3 & 2) && ((CPL == 3) || (cr0 & WP_FLAG)))) + return 0xffffffffffffffffULL; + + return ((temp & ~0xfffULL) + ((uint64_t) (addr & 0xfff))) & 0x000000ffffffffffULL; +} + +uint64_t +mmutranslate_noabrt(uint32_t addr, int rw) +{ + /* Fast path to return invalid without any call if an exception has occurred beforehand. */ + if (cpu_state.abrt) + return 0xffffffffffffffffULL; + + if (cr4 & CR4_PAE) + return mmutranslate_noabrt_pae(addr, rw); + else + return mmutranslate_noabrt_normal(addr, rw); +} + +void +mmu_invalidate(uint32_t addr) +{ + flushmmucache_cr3(); +} + +uint8_t +mem_addr_range_match(uint32_t addr, uint32_t start, uint32_t len) +{ + if (addr < start) + return 0; + else if (addr >= (start + len)) + return 0; + else + return 1; +} + +uint32_t +mem_addr_translate(uint32_t addr, uint32_t chunk_start, uint32_t len) +{ + uint32_t mask = len - 1; + + return chunk_start + (addr & mask); +} + +void +addreadlookup(uint32_t virt, uint32_t phys) +{ +#if (!(defined __amd64__ || defined _M_X64 || defined __aarch64__ || defined _M_ARM64)) + uint32_t a; +#endif + + if (virt == 0xffffffff) + return; + + if (readlookup2[virt >> 12] != (uintptr_t) LOOKUP_INV) + return; + + if (readlookup[readlnext] != (int) 0xffffffff) { + if ((readlookup[readlnext] == ((es + DI) >> 12)) || (readlookup[readlnext] == ((es + EDI) >> 12))) + uncached = 1; + readlookup2[readlookup[readlnext]] = LOOKUP_INV; + } + +#if (defined __amd64__ || defined _M_X64 || defined __aarch64__ || defined _M_ARM64) + readlookup2[virt >> 12] = (uintptr_t) &ram[(uintptr_t) (phys & ~0xFFF) - (uintptr_t) (virt & ~0xfff)]; +#else + a = ((uint32_t) (phys & ~0xfff) - (uint32_t) (virt & ~0xfff)); + + if ((phys & ~0xfff) >= (1 << 30)) + readlookup2[virt >> 12] = (uintptr_t) &ram2[a - (1 << 30)]; + else + readlookup2[virt >> 12] = (uintptr_t) &ram[a]; +#endif + readlookupp[virt >> 12] = mmu_perm; + + readlookup[readlnext++] = virt >> 12; + readlnext &= (cachesize - 1); + + cycles -= 9; +} + +void +addwritelookup(uint32_t virt, uint32_t phys) +{ +#if (!(defined __amd64__ || defined _M_X64 || defined __aarch64__ || defined _M_ARM64)) + uint32_t a; +#endif + + if (virt == 0xffffffff) + return; + + if (page_lookup[virt >> 12]) + return; + + if (writelookup[writelnext] != -1) { + page_lookup[writelookup[writelnext]] = NULL; + writelookup2[writelookup[writelnext]] = LOOKUP_INV; + } + +#ifdef USE_NEW_DYNAREC +# ifdef USE_DYNAREC + if (pages[phys >> 12].block || (phys & ~0xfff) == recomp_page) { +# else + if (pages[phys >> 12].block) { +# endif +#else +# ifdef USE_DYNAREC + if (pages[phys >> 12].block[0] || pages[phys >> 12].block[1] || pages[phys >> 12].block[2] || pages[phys >> 12].block[3] || (phys & ~0xfff) == recomp_page) { +# else + if (pages[phys >> 12].block[0] || pages[phys >> 12].block[1] || pages[phys >> 12].block[2] || pages[phys >> 12].block[3]) { +# endif +#endif + page_lookup[virt >> 12] = &pages[phys >> 12]; + page_lookupp[virt >> 12] = mmu_perm; + } else { +#if (defined __amd64__ || defined _M_X64 || defined __aarch64__ || defined _M_ARM64) + writelookup2[virt >> 12] = (uintptr_t) &ram[(uintptr_t) (phys & ~0xFFF) - (uintptr_t) (virt & ~0xfff)]; +#else + a = ((uint32_t) (phys & ~0xfff) - (uint32_t) (virt & ~0xfff)); + + if ((phys & ~0xfff) >= (1 << 30)) + writelookup2[virt >> 12] = (uintptr_t) &ram2[a - (1 << 30)]; + else + writelookup2[virt >> 12] = (uintptr_t) &ram[a]; +#endif + } + writelookupp[virt >> 12] = mmu_perm; + + writelookup[writelnext++] = virt >> 12; + writelnext &= (cachesize - 1); + + cycles -= 9; +} + +uint8_t * +getpccache(uint32_t a) +{ + uint64_t a64 = (uint64_t) a; + uint32_t a2; + + a2 = a; + + if (cr0 >> 31) { + a64 = mmutranslate_read(a64); + + if (a64 == 0xffffffffffffffffULL) + return ram; + } + a64 &= rammask; + + if (_mem_exec[a64 >> MEM_GRANULARITY_BITS]) { + if (is286) { + if (read_mapping[a64 >> MEM_GRANULARITY_BITS] && (read_mapping[a64 >> MEM_GRANULARITY_BITS]->flags & MEM_MAPPING_ROM_WS)) + cpu_prefetch_cycles = cpu_rom_prefetch_cycles; + else + cpu_prefetch_cycles = cpu_mem_prefetch_cycles; + } + + return &_mem_exec[a64 >> MEM_GRANULARITY_BITS][(uintptr_t) (a64 & MEM_GRANULARITY_PAGE) - (uintptr_t) (a2 & ~0xfff)]; + } + + mem_log("Bad getpccache %08X%08X\n", (uint32_t) (a64 >> 32), (uint32_t) (a64 & 0xffffffffULL)); + + return (uint8_t *) &ff_pccache; +} + +uint8_t +read_mem_b(uint32_t addr) +{ + mem_mapping_t *map; + uint8_t ret = 0xff; + int old_cycles = cycles; + + mem_logical_addr = addr; + addr &= rammask; + + map = read_mapping[addr >> MEM_GRANULARITY_BITS]; + if (map && map->read_b) + ret = map->read_b(addr, map->p); + + resub_cycles(old_cycles); + + return ret; +} + +uint16_t +read_mem_w(uint32_t addr) +{ + mem_mapping_t *map; + uint16_t ret = 0xffff; + int old_cycles = cycles; + + mem_logical_addr = addr; + addr &= rammask; + + if (addr & 1) + ret = read_mem_b(addr) | (read_mem_b(addr + 1) << 8); + else { + map = read_mapping[addr >> MEM_GRANULARITY_BITS]; + + if (map && map->read_w) + ret = map->read_w(addr, map->p); + else if (map && map->read_b) + ret = map->read_b(addr, map->p) | (map->read_b(addr + 1, map->p) << 8); + } + + resub_cycles(old_cycles); + + return ret; +} + +void +write_mem_b(uint32_t addr, uint8_t val) +{ + mem_mapping_t *map; + int old_cycles = cycles; + + mem_logical_addr = addr; + addr &= rammask; + + map = write_mapping[addr >> MEM_GRANULARITY_BITS]; + if (map && map->write_b) + map->write_b(addr, val, map->p); + + resub_cycles(old_cycles); +} + +void +write_mem_w(uint32_t addr, uint16_t val) +{ + mem_mapping_t *map; + int old_cycles = cycles; + + mem_logical_addr = addr; + addr &= rammask; + + if (addr & 1) { + write_mem_b(addr, val); + write_mem_b(addr + 1, val >> 8); + } else { + map = write_mapping[addr >> MEM_GRANULARITY_BITS]; + if (map) { + if (map->write_w) + map->write_w(addr, val, map->p); + else if (map->write_b) { + map->write_b(addr, val, map->p); + map->write_b(addr + 1, val >> 8, map->p); + } + } + } + + resub_cycles(old_cycles); +} + +uint8_t +readmembl(uint32_t addr) +{ + mem_mapping_t *map; + uint64_t a; + + if ((addr >= 0xec000000) && (addr <= 0xecffffff)) + pclog("[RB ] %08X\n", addr); + + GDBSTUB_MEM_ACCESS(addr, GDBSTUB_MEM_READ, 1); + + addr64 = (uint64_t) addr; + mem_logical_addr = addr; + + high_page = 0; + + if (cr0 >> 31) { + a = mmutranslate_read(addr); + addr64 = (uint32_t) a; + + if (a > 0xffffffffULL) + return 0xff; + } + addr = (uint32_t) (addr64 & rammask); + + map = read_mapping[addr >> MEM_GRANULARITY_BITS]; + if (map && map->read_b) + return map->read_b(addr, map->p); + + return 0xff; +} + +void +writemembl(uint32_t addr, uint8_t val) +{ + mem_mapping_t *map; + uint64_t a; + + if ((addr >= 0xec000000) && (addr <= 0xecffffff)) + pclog("[WB ] %08X = %02X\n", addr, val); + + GDBSTUB_MEM_ACCESS(addr, GDBSTUB_MEM_WRITE, 1); + + addr64 = (uint64_t) addr; + mem_logical_addr = addr; + + high_page = 0; + + if (page_lookup[addr >> 12] && page_lookup[addr >> 12]->write_b) { + page_lookup[addr >> 12]->write_b(addr, val, page_lookup[addr >> 12]); + return; + } + + if (cr0 >> 31) { + a = mmutranslate_write(addr); + addr64 = (uint32_t) a; + + if (a > 0xffffffffULL) + return; + } + addr = (uint32_t) (addr64 & rammask); + + map = write_mapping[addr >> MEM_GRANULARITY_BITS]; + if (map && map->write_b) + map->write_b(addr, val, map->p); +} + +/* Read a byte from memory without MMU translation - result of previous MMU translation passed as value. */ +uint8_t +readmembl_no_mmut(uint32_t addr, uint32_t a64) +{ + mem_mapping_t *map; + + if ((addr >= 0xec000000) && (addr <= 0xecffffff)) + pclog("[RBN] %08X\n", addr); + + GDBSTUB_MEM_ACCESS(addr, GDBSTUB_MEM_READ, 1); + + mem_logical_addr = addr; + + if (cr0 >> 31) { + if (cpu_state.abrt || high_page) + return 0xff; + + addr = a64 & rammask; + } else + addr &= rammask; + + map = read_mapping[addr >> MEM_GRANULARITY_BITS]; + if (map && map->read_b) + return map->read_b(addr, map->p); + + return 0xff; +} + +/* Write a byte to memory without MMU translation - result of previous MMU translation passed as value. */ +void +writemembl_no_mmut(uint32_t addr, uint32_t a64, uint8_t val) +{ + mem_mapping_t *map; + + if ((addr >= 0xec000000) && (addr <= 0xecffffff)) + pclog("[WBN] %08X = %02X\n", addr, val); + + GDBSTUB_MEM_ACCESS(addr, GDBSTUB_MEM_WRITE, 1); + + mem_logical_addr = addr; + + if (page_lookup[addr >> 12] && page_lookup[addr >> 12]->write_b) { + page_lookup[addr >> 12]->write_b(addr, val, page_lookup[addr >> 12]); + return; + } + + if (cr0 >> 31) { + if (cpu_state.abrt || high_page) + return; + + addr = a64 & rammask; + } else + addr &= rammask; + + map = write_mapping[addr >> MEM_GRANULARITY_BITS]; + if (map && map->write_b) + map->write_b(addr, val, map->p); +} + +uint16_t +readmemwl(uint32_t addr) +{ + mem_mapping_t *map; + int i; + uint64_t a; + + if ((addr >= 0xec000000) && (addr <= 0xecffffff)) + pclog("[RW ] %08X\n", addr); + + addr64a[0] = addr; + addr64a[1] = addr + 1; + GDBSTUB_MEM_ACCESS_FAST(addr64a, GDBSTUB_MEM_READ, 2); + + mem_logical_addr = addr; + + high_page = 0; + + if (addr & 1) { + if (!cpu_cyrix_alignment || (addr & 7) == 7) + cycles -= timing_misaligned; + if ((addr & 0xfff) > 0xffe) { + if (cr0 >> 31) { + for (i = 0; i < 2; i++) { + a = mmutranslate_read(addr + i); + addr64a[i] = (uint32_t) a; + + if (a > 0xffffffffULL) + return 0xffff; + } + } + + return readmembl_no_mmut(addr, addr64a[0]) | (((uint16_t) readmembl_no_mmut(addr + 1, addr64a[1])) << 8); + } else if (readlookup2[addr >> 12] != (uintptr_t) LOOKUP_INV) { + mmu_perm = readlookupp[addr >> 12]; + return *(uint16_t *) (readlookup2[addr >> 12] + addr); + } + } + + if (cr0 >> 31) { + a = mmutranslate_read(addr); + addr64a[0] = (uint32_t) a; + + if (a > 0xffffffffULL) + return 0xffff; + } else + addr64a[0] = (uint64_t) addr; + + addr = addr64a[0] & rammask; + + map = read_mapping[addr >> MEM_GRANULARITY_BITS]; + + if (map && map->read_w) + return map->read_w(addr, map->p); + + if (map && map->read_b) { + return map->read_b(addr, map->p) | ((uint16_t) (map->read_b(addr + 1, map->p)) << 8); + } + + return 0xffff; +} + +void +writememwl(uint32_t addr, uint16_t val) +{ + mem_mapping_t *map; + int i; + uint64_t a; + + if ((addr >= 0xec000000) && (addr <= 0xecffffff)) + pclog("[WW ] %08X = %04X\n", addr, val); + + addr64a[0] = addr; + addr64a[1] = addr + 1; + GDBSTUB_MEM_ACCESS_FAST(addr64a, GDBSTUB_MEM_WRITE, 2); + + mem_logical_addr = addr; + + high_page = 0; + + if (addr & 1) { + if (!cpu_cyrix_alignment || (addr & 7) == 7) + cycles -= timing_misaligned; + if ((addr & 0xfff) > 0xffe) { + if (cr0 >> 31) { + for (i = 0; i < 2; i++) { + /* Do not translate a page that has a valid lookup, as that is by definition valid + and the whole purpose of the lookup is to avoid repeat identical translations. */ + if (!page_lookup[(addr + i) >> 12] || !page_lookup[(addr + i) >> 12]->write_b) { + a = mmutranslate_write(addr + i); + addr64a[i] = (uint32_t) a; + + if (a > 0xffffffffULL) + return; + } + } + } + + /* No need to waste precious CPU host cycles on mmutranslate's that were already done, just pass + their result as a parameter to be used if needed. */ + writemembl_no_mmut(addr, addr64a[0], val); + writemembl_no_mmut(addr + 1, addr64a[1], val >> 8); + return; + } else if (writelookup2[addr >> 12] != (uintptr_t) LOOKUP_INV) { + mmu_perm = writelookupp[addr >> 12]; + *(uint16_t *) (writelookup2[addr >> 12] + addr) = val; + return; + } + } + + if (page_lookup[addr >> 12] && page_lookup[addr >> 12]->write_w) { + page_lookup[addr >> 12]->write_w(addr, val, page_lookup[addr >> 12]); + mmu_perm = page_lookupp[addr >> 12]; + return; + } + + if (cr0 >> 31) { + a = mmutranslate_write(addr); + addr64a[0] = (uint32_t) a; + + if (a > 0xffffffffULL) + return; + } + + addr = addr64a[0] & rammask; + + map = write_mapping[addr >> MEM_GRANULARITY_BITS]; + + if (map && map->write_w) { + map->write_w(addr, val, map->p); + return; + } + + if (map && map->write_b) { + map->write_b(addr, val, map->p); + map->write_b(addr + 1, val >> 8, map->p); + return; + } +} + +/* Read a word from memory without MMU translation - results of previous MMU translation passed as array. */ +uint16_t +readmemwl_no_mmut(uint32_t addr, uint32_t *a64) +{ + mem_mapping_t *map; + + if ((addr >= 0xec000000) && (addr <= 0xecffffff)) + pclog("[RWN] %08X\n", addr); + + GDBSTUB_MEM_ACCESS(addr, GDBSTUB_MEM_READ, 2); + + mem_logical_addr = addr; + + if (addr & 1) { + if (!cpu_cyrix_alignment || (addr & 7) == 7) + cycles -= timing_misaligned; + if ((addr & 0xfff) > 0xffe) { + if (cr0 >> 31) { + if (cpu_state.abrt || high_page) + return 0xffff; + } + + return readmembl_no_mmut(addr, a64[0]) | (((uint16_t) readmembl_no_mmut(addr + 1, a64[1])) << 8); + } else if (readlookup2[addr >> 12] != (uintptr_t) LOOKUP_INV) { + mmu_perm = readlookupp[addr >> 12]; + return *(uint16_t *) (readlookup2[addr >> 12] + addr); + } + } + + if (cr0 >> 31) { + if (cpu_state.abrt || high_page) + return 0xffff; + + addr = (uint32_t) (a64[0] & rammask); + } else + addr &= rammask; + + map = read_mapping[addr >> MEM_GRANULARITY_BITS]; + + if (map && map->read_w) + return map->read_w(addr, map->p); + + if (map && map->read_b) { + return map->read_b(addr, map->p) | ((uint16_t) (map->read_b(addr + 1, map->p)) << 8); + } + + return 0xffff; +} + +/* Write a word to memory without MMU translation - results of previous MMU translation passed as array. */ +void +writememwl_no_mmut(uint32_t addr, uint32_t *a64, uint16_t val) +{ + mem_mapping_t *map; + + if ((addr >= 0xec000000) && (addr <= 0xecffffff)) + pclog("[WWN] %08X = %04X\n", addr, val); + + GDBSTUB_MEM_ACCESS(addr, GDBSTUB_MEM_WRITE, 2); + + mem_logical_addr = addr; + + if (addr & 1) { + if (!cpu_cyrix_alignment || (addr & 7) == 7) + cycles -= timing_misaligned; + if ((addr & 0xfff) > 0xffe) { + if (cr0 >> 31) { + if (cpu_state.abrt || high_page) + return; + } + + writemembl_no_mmut(addr, a64[0], val); + writemembl_no_mmut(addr + 1, a64[1], val >> 8); + return; + } else if (writelookup2[addr >> 12] != (uintptr_t) LOOKUP_INV) { + mmu_perm = writelookupp[addr >> 12]; + *(uint16_t *) (writelookup2[addr >> 12] + addr) = val; + return; + } + } + + if (page_lookup[addr >> 12] && page_lookup[addr >> 12]->write_w) { + mmu_perm = page_lookupp[addr >> 12]; + page_lookup[addr >> 12]->write_w(addr, val, page_lookup[addr >> 12]); + return; + } + + if (cr0 >> 31) { + if (cpu_state.abrt || high_page) + return; + + addr = (uint32_t) (a64[0] & rammask); + } else + addr &= rammask; + + map = write_mapping[addr >> MEM_GRANULARITY_BITS]; + + if (map && map->write_w) { + map->write_w(addr, val, map->p); + return; + } + + if (map && map->write_b) { + map->write_b(addr, val, map->p); + map->write_b(addr + 1, val >> 8, map->p); + return; + } +} + +uint32_t +readmemll(uint32_t addr) +{ + mem_mapping_t *map; + int i; + uint64_t a = 0x0000000000000000ULL; + + if ((addr >= 0xec000000) && (addr <= 0xecffffff)) + pclog("[RL ] %08X\n", addr); + + for (i = 0; i < 4; i++) + addr64a[i] = (uint64_t) (addr + i); + GDBSTUB_MEM_ACCESS_FAST(addr64a, GDBSTUB_MEM_READ, 4); + + mem_logical_addr = addr; + + high_page = 0; + + if (addr & 3) { + if (!cpu_cyrix_alignment || (addr & 7) > 4) + cycles -= timing_misaligned; + if ((addr & 0xfff) > 0xffc) { + if (cr0 >> 31) { + for (i = 0; i < 4; i++) { + if (i == 0) { + a = mmutranslate_read(addr + i); + addr64a[i] = (uint32_t) a; + } else if (!((addr + i) & 0xfff)) { + a = mmutranslate_read(addr + 3); + addr64a[i] = (uint32_t) a; + if (!cpu_state.abrt) { + a = (a & ~0xfffLL) | ((uint64_t) ((addr + i) & 0xfff)); + addr64a[i] = (uint32_t) a; + } + } else { + a = (a & ~0xfffLL) | ((uint64_t) ((addr + i) & 0xfff)); + addr64a[i] = (uint32_t) a; + } + + if (a > 0xffffffffULL) + return 0xffff; + } + } + + /* No need to waste precious CPU host cycles on mmutranslate's that were already done, just pass + their result as a parameter to be used if needed. */ + return readmemwl_no_mmut(addr, addr64a) | (((uint32_t) readmemwl_no_mmut(addr + 2, &(addr64a[2]))) << 16); + } else if (readlookup2[addr >> 12] != (uintptr_t) LOOKUP_INV) { + mmu_perm = readlookupp[addr >> 12]; + return *(uint32_t *) (readlookup2[addr >> 12] + addr); + } + } + + if (cr0 >> 31) { + a = mmutranslate_read(addr); + addr64a[0] = (uint32_t) a; + + if (a > 0xffffffffULL) + return 0xffffffff; + } + + addr = addr64a[0] & rammask; + + map = read_mapping[addr >> MEM_GRANULARITY_BITS]; + + if (map && map->read_l) + return map->read_l(addr, map->p); + + if (map && map->read_w) + return map->read_w(addr, map->p) | ((uint32_t) (map->read_w(addr + 2, map->p)) << 16); + + if (map && map->read_b) + return map->read_b(addr, map->p) | ((uint32_t) (map->read_b(addr + 1, map->p)) << 8) | ((uint32_t) (map->read_b(addr + 2, map->p)) << 16) | ((uint32_t) (map->read_b(addr + 3, map->p)) << 24); + + return 0xffffffff; +} + +void +writememll(uint32_t addr, uint32_t val) +{ + mem_mapping_t *map; + int i; + uint64_t a = 0x0000000000000000ULL; + + if ((addr >= 0xec000000) && (addr <= 0xecffffff)) + pclog("[WL ] %08X = %08X\n", addr, val); + + for (i = 0; i < 4; i++) + addr64a[i] = (uint64_t) (addr + i); + GDBSTUB_MEM_ACCESS_FAST(addr64a, GDBSTUB_MEM_WRITE, 4); + + mem_logical_addr = addr; + + high_page = 0; + + if (addr & 3) { + if (!cpu_cyrix_alignment || (addr & 7) > 4) + cycles -= timing_misaligned; + if ((addr & 0xfff) > 0xffc) { + if (cr0 >> 31) { + for (i = 0; i < 4; i++) { + /* Do not translate a page that has a valid lookup, as that is by definition valid + and the whole purpose of the lookup is to avoid repeat identical translations. */ + if (!page_lookup[(addr + i) >> 12] || !page_lookup[(addr + i) >> 12]->write_b) { + if (i == 0) { + a = mmutranslate_write(addr + i); + addr64a[i] = (uint32_t) a; + } else if (!((addr + i) & 0xfff)) { + a = mmutranslate_write(addr + 3); + addr64a[i] = (uint32_t) a; + if (!cpu_state.abrt) { + a = (a & ~0xfffLL) | ((uint64_t) ((addr + i) & 0xfff)); + addr64a[i] = (uint32_t) a; + } + } else { + a = (a & ~0xfffLL) | ((uint64_t) ((addr + i) & 0xfff)); + addr64a[i] = (uint32_t) a; + } + + if (a > 0xffffffffULL) + return; + } + } + } + + /* No need to waste precious CPU host cycles on mmutranslate's that were already done, just pass + their result as a parameter to be used if needed. */ + writememwl_no_mmut(addr, &(addr64a[0]), val); + writememwl_no_mmut(addr + 2, &(addr64a[2]), val >> 16); + return; + } else if (writelookup2[addr >> 12] != (uintptr_t) LOOKUP_INV) { + mmu_perm = writelookupp[addr >> 12]; + *(uint32_t *) (writelookup2[addr >> 12] + addr) = val; + return; + } + } + + if (page_lookup[addr >> 12] && page_lookup[addr >> 12]->write_l) { + mmu_perm = page_lookupp[addr >> 12]; + page_lookup[addr >> 12]->write_l(addr, val, page_lookup[addr >> 12]); + return; + } + + if (cr0 >> 31) { + a = mmutranslate_write(addr); + addr64a[0] = (uint32_t) a; + + if (a > 0xffffffffULL) + return; + } + + addr = addr64a[0] & rammask; + + map = write_mapping[addr >> MEM_GRANULARITY_BITS]; + if ((addr >= 0xec000000) && (addr <= 0xecffffff)) + pclog("[WL ] map = %08X\n", map); + + if (map && map->write_l) { + map->write_l(addr, val, map->p); + return; + } + if (map && map->write_w) { + map->write_w(addr, val, map->p); + map->write_w(addr + 2, val >> 16, map->p); + return; + } + if (map && map->write_b) { + map->write_b(addr, val, map->p); + map->write_b(addr + 1, val >> 8, map->p); + map->write_b(addr + 2, val >> 16, map->p); + map->write_b(addr + 3, val >> 24, map->p); + return; + } +} + +/* Read a long from memory without MMU translation - results of previous MMU translation passed as array. */ +uint32_t +readmemll_no_mmut(uint32_t addr, uint32_t *a64) +{ + mem_mapping_t *map; + + if ((addr >= 0xec000000) && (addr <= 0xecffffff)) + pclog("[RLN] %08X\n", addr); + + GDBSTUB_MEM_ACCESS(addr, GDBSTUB_MEM_READ, 4); + + mem_logical_addr = addr; + + if (addr & 3) { + if (!cpu_cyrix_alignment || (addr & 7) > 4) + cycles -= timing_misaligned; + if ((addr & 0xfff) > 0xffc) { + if (cr0 >> 31) { + if (cpu_state.abrt || high_page) + return 0xffffffff; + } + + return readmemwl_no_mmut(addr, a64) | ((uint32_t) (readmemwl_no_mmut(addr + 2, &(a64[2]))) << 16); + } else if (readlookup2[addr >> 12] != (uintptr_t) LOOKUP_INV) { + mmu_perm = readlookupp[addr >> 12]; + return *(uint32_t *) (readlookup2[addr >> 12] + addr); + } + } + + if (cr0 >> 31) { + if (cpu_state.abrt || high_page) + return 0xffffffff; + + addr = (uint32_t) (a64[0] & rammask); + } else + addr &= rammask; + + map = read_mapping[addr >> MEM_GRANULARITY_BITS]; + + if (map && map->read_l) + return map->read_l(addr, map->p); + + if (map && map->read_w) + return map->read_w(addr, map->p) | ((uint32_t) (map->read_w(addr + 2, map->p)) << 16); + + if (map && map->read_b) + return map->read_b(addr, map->p) | ((uint32_t) (map->read_b(addr + 1, map->p)) << 8) | ((uint32_t) (map->read_b(addr + 2, map->p)) << 16) | ((uint32_t) (map->read_b(addr + 3, map->p)) << 24); + + return 0xffffffff; +} + +/* Write a long to memory without MMU translation - results of previous MMU translation passed as array. */ +void +writememll_no_mmut(uint32_t addr, uint32_t *a64, uint32_t val) +{ + mem_mapping_t *map; + + if ((addr >= 0xec000000) && (addr <= 0xecffffff)) + pclog("[WLN] %08X = %08X\n", addr, val); + + GDBSTUB_MEM_ACCESS(addr, GDBSTUB_MEM_WRITE, 4); + + mem_logical_addr = addr; + + if (addr & 3) { + if (!cpu_cyrix_alignment || (addr & 7) > 4) + cycles -= timing_misaligned; + if ((addr & 0xfff) > 0xffc) { + if (cr0 >> 31) { + if (cpu_state.abrt || high_page) + return; + } + + writememwl_no_mmut(addr, &(a64[0]), val); + writememwl_no_mmut(addr + 2, &(a64[2]), val >> 16); + return; + } else if (writelookup2[addr >> 12] != (uintptr_t) LOOKUP_INV) { + mmu_perm = writelookupp[addr >> 12]; + *(uint32_t *) (writelookup2[addr >> 12] + addr) = val; + return; + } + } + + if (page_lookup[addr >> 12] && page_lookup[addr >> 12]->write_l) { + mmu_perm = page_lookupp[addr >> 12]; + page_lookup[addr >> 12]->write_l(addr, val, page_lookup[addr >> 12]); + return; + } + + if (cr0 >> 31) { + if (cpu_state.abrt || high_page) + return; + + addr = (uint32_t) (a64[0] & rammask); + } else + addr &= rammask; + + map = write_mapping[addr >> MEM_GRANULARITY_BITS]; + + if (map && map->write_l) { + map->write_l(addr, val, map->p); + return; + } + if (map && map->write_w) { + map->write_w(addr, val, map->p); + map->write_w(addr + 2, val >> 16, map->p); + return; + } + if (map && map->write_b) { + map->write_b(addr, val, map->p); + map->write_b(addr + 1, val >> 8, map->p); + map->write_b(addr + 2, val >> 16, map->p); + map->write_b(addr + 3, val >> 24, map->p); + return; + } +} + +uint64_t +readmemql(uint32_t addr) +{ + mem_mapping_t *map; + int i; + uint64_t a = 0x0000000000000000ULL; + + if ((addr >= 0xec000000) && (addr <= 0xecffffff)) + pclog("[RQ ] %08X\n", addr); + + for (i = 0; i < 8; i++) + addr64a[i] = (uint64_t) (addr + i); + GDBSTUB_MEM_ACCESS_FAST(addr64a, GDBSTUB_MEM_READ, 8); + + mem_logical_addr = addr; + + high_page = 0; + + if (addr & 7) { + cycles -= timing_misaligned; + if ((addr & 0xfff) > 0xff8) { + if (cr0 >> 31) { + for (i = 0; i < 8; i++) { + if (i == 0) { + a = mmutranslate_read(addr + i); + addr64a[i] = (uint32_t) a; + } else if (!((addr + i) & 0xfff)) { + a = mmutranslate_read(addr + 7); + addr64a[i] = (uint32_t) a; + if (!cpu_state.abrt) { + a = (a & ~0xfffLL) | ((uint64_t) ((addr + i) & 0xfff)); + addr64a[i] = (uint32_t) a; + } + } else { + a = (a & ~0xfffLL) | ((uint64_t) ((addr + i) & 0xfff)); + addr64a[i] = (uint32_t) a; + } + + if (a > 0xffffffffULL) + return 0xffff; + } + } + + /* No need to waste precious CPU host cycles on mmutranslate's that were already done, just pass + their result as a parameter to be used if needed. */ + return readmemll_no_mmut(addr, addr64a) | (((uint64_t) readmemll_no_mmut(addr + 4, &(addr64a[4]))) << 32); + } else if (readlookup2[addr >> 12] != (uintptr_t) LOOKUP_INV) { + mmu_perm = readlookupp[addr >> 12]; + return *(uint64_t *) (readlookup2[addr >> 12] + addr); + } + } + + if (cr0 >> 31) { + a = mmutranslate_read(addr); + addr64a[0] = (uint32_t) a; + + if (a > 0xffffffffULL) + return 0xffffffffffffffffULL; + } + + addr = addr64a[0] & rammask; + + map = read_mapping[addr >> MEM_GRANULARITY_BITS]; + if (map && map->read_l) + return map->read_l(addr, map->p) | ((uint64_t) map->read_l(addr + 4, map->p) << 32); + + return readmemll(addr) | ((uint64_t) readmemll(addr + 4) << 32); +} + +void +writememql(uint32_t addr, uint64_t val) +{ + mem_mapping_t *map; + int i; + uint64_t a = 0x0000000000000000ULL; + + if ((addr >= 0xec000000) && (addr <= 0xecffffff)) + pclog("[WQ ] %08X = %016" PRIX64 "\n", addr, val); + + for (i = 0; i < 8; i++) + addr64a[i] = (uint64_t) (addr + i); + GDBSTUB_MEM_ACCESS_FAST(addr64a, GDBSTUB_MEM_WRITE, 8); + + mem_logical_addr = addr; + + high_page = 0; + + if (addr & 7) { + cycles -= timing_misaligned; + if ((addr & 0xfff) > 0xff8) { + if (cr0 >> 31) { + for (i = 0; i < 8; i++) { + /* Do not translate a page that has a valid lookup, as that is by definition valid + and the whole purpose of the lookup is to avoid repeat identical translations. */ + if (!page_lookup[(addr + i) >> 12] || !page_lookup[(addr + i) >> 12]->write_b) { + if (i == 0) { + a = mmutranslate_write(addr + i); + addr64a[i] = (uint32_t) a; + } else if (!((addr + i) & 0xfff)) { + a = mmutranslate_write(addr + 7); + addr64a[i] = (uint32_t) a; + if (!cpu_state.abrt) { + a = (a & ~0xfffLL) | ((uint64_t) ((addr + i) & 0xfff)); + addr64a[i] = (uint32_t) a; + } + } else { + a = (a & ~0xfffLL) | ((uint64_t) ((addr + i) & 0xfff)); + addr64a[i] = (uint32_t) a; + } + + if (addr64a[i] > 0xffffffffULL) + return; + } + } + } + + /* No need to waste precious CPU host cycles on mmutranslate's that were already done, just pass + their result as a parameter to be used if needed. */ + writememll_no_mmut(addr, addr64a, val); + writememll_no_mmut(addr + 4, &(addr64a[4]), val >> 32); + return; + } else if (writelookup2[addr >> 12] != (uintptr_t) LOOKUP_INV) { + mmu_perm = writelookupp[addr >> 12]; + *(uint64_t *) (writelookup2[addr >> 12] + addr) = val; + return; + } + } + + if (page_lookup[addr >> 12] && page_lookup[addr >> 12]->write_l) { + mmu_perm = page_lookupp[addr >> 12]; + page_lookup[addr >> 12]->write_l(addr, val, page_lookup[addr >> 12]); + page_lookup[addr >> 12]->write_l(addr + 4, val >> 32, page_lookup[addr >> 12]); + return; + } + + if (cr0 >> 31) { + addr64a[0] = mmutranslate_write(addr); + if (addr64a[0] > 0xffffffffULL) + return; + } + + addr = addr64a[0] & rammask; + + map = write_mapping[addr >> MEM_GRANULARITY_BITS]; + + if (map && map->write_l) { + map->write_l(addr, val, map->p); + map->write_l(addr + 4, val >> 32, map->p); + return; + } + if (map && map->write_w) { + map->write_w(addr, val, map->p); + map->write_w(addr + 2, val >> 16, map->p); + map->write_w(addr + 4, val >> 32, map->p); + map->write_w(addr + 6, val >> 48, map->p); + return; + } + if (map && map->write_b) { + map->write_b(addr, val, map->p); + map->write_b(addr + 1, val >> 8, map->p); + map->write_b(addr + 2, val >> 16, map->p); + map->write_b(addr + 3, val >> 24, map->p); + map->write_b(addr + 4, val >> 32, map->p); + map->write_b(addr + 5, val >> 40, map->p); + map->write_b(addr + 6, val >> 48, map->p); + map->write_b(addr + 7, val >> 56, map->p); + return; + } +} + +void +do_mmutranslate(uint32_t addr, uint32_t *a64, int num, int write) +{ + int i, cond = 1; + uint32_t last_addr = addr + (num - 1); + uint64_t a = 0x0000000000000000ULL; + + for (i = 0; i < num; i++) + a64[i] = (uint64_t) addr; + + for (i = 0; i < num; i++) { + if (cr0 >> 31) { + if (write && ((i == 0) || !(addr & 0xfff))) + cond = (!page_lookup[addr >> 12] || !page_lookup[addr >> 12]->write_b); + + if (cond) { + /* If we have encountered at least one page fault, mark all subsequent addresses as + having page faulted, prevents false negatives in readmem*l_no_mmut. */ + if ((i > 0) && cpu_state.abrt && !high_page) + a64[i] = a64[i - 1]; + /* If we are on the same page, there is no need to translate again, as we can just + reuse the previous result. */ + else if (i == 0) { + a = mmutranslatereal(addr, write); + a64[i] = (uint32_t) a; + + high_page = high_page || (!cpu_state.abrt && (a > 0xffffffffULL)); + } else if (!(addr & 0xfff)) { + a = mmutranslatereal(last_addr, write); + a64[i] = (uint32_t) a; + + high_page = high_page || (!cpu_state.abrt && (a64[i] > 0xffffffffULL)); + + if (!cpu_state.abrt) { + a = (a & 0xfffffffffffff000ULL) | ((uint64_t) (addr & 0xfff)); + a64[i] = (uint32_t) a; + } + } else { + a = (a & 0xfffffffffffff000ULL) | ((uint64_t) (addr & 0xfff)); + a64[i] = (uint32_t) a; + } + } else + mmu_perm = page_lookupp[addr >> 12]; + } + + addr++; + } +} + +uint8_t +mem_readb_phys(uint32_t addr) +{ + mem_mapping_t *map = read_mapping_bus[addr >> MEM_GRANULARITY_BITS]; + uint8_t ret = 0xff; + + mem_logical_addr = 0xffffffff; + + if (map) { + if (map->exec) + ret = map->exec[(addr - map->base) & map->mask]; + else if (map->read_b) + ret = map->read_b(addr, map->p); + } + + return ret; +} + +uint16_t +mem_readw_phys(uint32_t addr) +{ + mem_mapping_t *map = read_mapping_bus[addr >> MEM_GRANULARITY_BITS]; + uint16_t ret, *p; + + mem_logical_addr = 0xffffffff; + + if (((addr & MEM_GRANULARITY_MASK) <= MEM_GRANULARITY_HBOUND) && (map && map->exec)) { + p = (uint16_t *) &(map->exec[(addr - map->base) & map->mask]); + ret = *p; + } else if (((addr & MEM_GRANULARITY_MASK) <= MEM_GRANULARITY_HBOUND) && (map && map->read_w)) + ret = map->read_w(addr, map->p); + else { + ret = mem_readb_phys(addr + 1) << 8; + ret |= mem_readb_phys(addr); + } + + return ret; +} + +uint32_t +mem_readl_phys(uint32_t addr) +{ + mem_mapping_t *map = read_mapping_bus[addr >> MEM_GRANULARITY_BITS]; + uint32_t ret, *p; + + mem_logical_addr = 0xffffffff; + + if (((addr & MEM_GRANULARITY_MASK) <= MEM_GRANULARITY_QBOUND) && (map && map->exec)) { + p = (uint32_t *) &(map->exec[(addr - map->base) & map->mask]); + ret = *p; + } else if (((addr & MEM_GRANULARITY_MASK) <= MEM_GRANULARITY_QBOUND) && (map && map->read_l)) + ret = map->read_l(addr, map->p); + else { + ret = mem_readw_phys(addr + 2) << 16; + ret |= mem_readw_phys(addr); + } + + return ret; +} + +void +mem_read_phys(void *dest, uint32_t addr, int transfer_size) +{ + uint8_t *pb; + uint16_t *pw; + uint32_t *pl; + + if (transfer_size == 4) { + pl = (uint32_t *) dest; + *pl = mem_readl_phys(addr); + } else if (transfer_size == 2) { + pw = (uint16_t *) dest; + *pw = mem_readw_phys(addr); + } else if (transfer_size == 1) { + pb = (uint8_t *) dest; + *pb = mem_readb_phys(addr); + } +} + +void +mem_writeb_phys(uint32_t addr, uint8_t val) +{ + mem_mapping_t *map = write_mapping_bus[addr >> MEM_GRANULARITY_BITS]; + + mem_logical_addr = 0xffffffff; + + if (map) { + if (map->exec) + map->exec[(addr - map->base) & map->mask] = val; + else if (map->write_b) + map->write_b(addr, val, map->p); + } +} + +void +mem_writew_phys(uint32_t addr, uint16_t val) +{ + mem_mapping_t *map = write_mapping_bus[addr >> MEM_GRANULARITY_BITS]; + uint16_t *p; + + mem_logical_addr = 0xffffffff; + + if (((addr & MEM_GRANULARITY_MASK) <= MEM_GRANULARITY_HBOUND) && (map && map->exec)) { + p = (uint16_t *) &(map->exec[(addr - map->base) & map->mask]); + *p = val; + } else if (((addr & MEM_GRANULARITY_MASK) <= MEM_GRANULARITY_HBOUND) && (map && map->write_w)) + map->write_w(addr, val, map->p); + else { + mem_writeb_phys(addr, val & 0xff); + mem_writeb_phys(addr + 1, (val >> 8) & 0xff); + } +} + +void +mem_writel_phys(uint32_t addr, uint32_t val) +{ + mem_mapping_t *map = write_mapping_bus[addr >> MEM_GRANULARITY_BITS]; + uint32_t *p; + + mem_logical_addr = 0xffffffff; + + if (((addr & MEM_GRANULARITY_MASK) <= MEM_GRANULARITY_QBOUND) && (map && map->exec)) { + p = (uint32_t *) &(map->exec[(addr - map->base) & map->mask]); + *p = val; + } else if (((addr & MEM_GRANULARITY_MASK) <= MEM_GRANULARITY_QBOUND) && (map && map->write_l)) + map->write_l(addr, val, map->p); + else { + mem_writew_phys(addr, val & 0xffff); + mem_writew_phys(addr + 2, (val >> 16) & 0xffff); + } +} + +void +mem_write_phys(void *src, uint32_t addr, int transfer_size) +{ + uint8_t *pb; + uint16_t *pw; + uint32_t *pl; + + if (transfer_size == 4) { + pl = (uint32_t *) src; + mem_writel_phys(addr, *pl); + } else if (transfer_size == 2) { + pw = (uint16_t *) src; + mem_writew_phys(addr, *pw); + } else if (transfer_size == 1) { + pb = (uint8_t *) src; + mem_writeb_phys(addr, *pb); + } +} + +uint8_t +mem_read_ram(uint32_t addr, void *priv) +{ +#ifdef ENABLE_MEM_LOG + if ((addr >= 0xa0000) && (addr <= 0xbffff)) + mem_log("Read B %02X from %08X\n", ram[addr], addr); +#endif + + if (is286) + addreadlookup(mem_logical_addr, addr); + + return ram[addr]; +} + +uint16_t +mem_read_ramw(uint32_t addr, void *priv) +{ +#ifdef ENABLE_MEM_LOG + if ((addr >= 0xa0000) && (addr <= 0xbffff)) + mem_log("Read W %04X from %08X\n", *(uint16_t *) &ram[addr], addr); +#endif + + if (is286) + addreadlookup(mem_logical_addr, addr); + + return *(uint16_t *) &ram[addr]; +} + +uint32_t +mem_read_raml(uint32_t addr, void *priv) +{ +#ifdef ENABLE_MEM_LOG + if ((addr >= 0xa0000) && (addr <= 0xbffff)) + mem_log("Read L %08X from %08X\n", *(uint32_t *) &ram[addr], addr); +#endif + + if (is286) + addreadlookup(mem_logical_addr, addr); + + return *(uint32_t *) &ram[addr]; +} + +uint8_t +mem_read_ram_2gb(uint32_t addr, void *priv) +{ +#ifdef ENABLE_MEM_LOG + if ((addr >= 0xa0000) && (addr <= 0xbffff)) + mem_log("Read B %02X from %08X\n", ram[addr], addr); +#endif + + addreadlookup(mem_logical_addr, addr); + + return ram2[addr - (1 << 30)]; +} + +uint16_t +mem_read_ram_2gbw(uint32_t addr, void *priv) +{ +#ifdef ENABLE_MEM_LOG + if ((addr >= 0xa0000) && (addr <= 0xbffff)) + mem_log("Read W %04X from %08X\n", *(uint16_t *) &ram[addr], addr); +#endif + + addreadlookup(mem_logical_addr, addr); + + return *(uint16_t *) &ram2[addr - (1 << 30)]; +} + +uint32_t +mem_read_ram_2gbl(uint32_t addr, void *priv) +{ +#ifdef ENABLE_MEM_LOG + if ((addr >= 0xa0000) && (addr <= 0xbffff)) + mem_log("Read L %08X from %08X\n", *(uint32_t *) &ram[addr], addr); +#endif + + addreadlookup(mem_logical_addr, addr); + + return *(uint32_t *) &ram2[addr - (1 << 30)]; +} + +#ifdef USE_NEW_DYNAREC +static inline int +page_index(page_t *p) +{ + return ((uintptr_t) p - (uintptr_t) pages) / sizeof(page_t); +} + +void +page_add_to_evict_list(page_t *p) +{ + pages[purgable_page_list_head].evict_prev = page_index(p); + p->evict_next = purgable_page_list_head; + p->evict_prev = 0; + purgable_page_list_head = pages[purgable_page_list_head].evict_prev; + purgeable_page_count++; +} + +void +page_remove_from_evict_list(page_t *p) +{ + if (!page_in_evict_list(p)) + fatal("page_remove_from_evict_list: not in evict list!\n"); + if (p->evict_prev) + pages[p->evict_prev].evict_next = p->evict_next; + else + purgable_page_list_head = p->evict_next; + if (p->evict_next) + pages[p->evict_next].evict_prev = p->evict_prev; + p->evict_prev = EVICT_NOT_IN_LIST; + purgeable_page_count--; +} + +void +mem_write_ramb_page(uint32_t addr, uint8_t val, page_t *p) +{ + if (p == NULL) + return; + +# ifdef USE_DYNAREC + if ((p->mem == NULL) || (p->mem == page_ff) || (val != p->mem[addr & 0xfff]) || codegen_in_recompile) { +# else + if ((p->mem == NULL) || (p->mem == page_ff) || (val != p->mem[addr & 0xfff])) { +# endif + uint64_t mask = (uint64_t) 1 << ((addr >> PAGE_MASK_SHIFT) & PAGE_MASK_MASK); + int byte_offset = (addr >> PAGE_BYTE_MASK_SHIFT) & PAGE_BYTE_MASK_OFFSET_MASK; + uint64_t byte_mask = (uint64_t) 1 << (addr & PAGE_BYTE_MASK_MASK); + + p->mem[addr & 0xfff] = val; + p->dirty_mask |= mask; + if ((p->code_present_mask & mask) && !page_in_evict_list(p)) + page_add_to_evict_list(p); + p->byte_dirty_mask[byte_offset] |= byte_mask; + if ((p->byte_code_present_mask[byte_offset] & byte_mask) && !page_in_evict_list(p)) + page_add_to_evict_list(p); + } +} + +void +mem_write_ramw_page(uint32_t addr, uint16_t val, page_t *p) +{ + if (p == NULL) + return; + +# ifdef USE_DYNAREC + if ((p->mem == NULL) || (p->mem == page_ff) || (val != *(uint16_t *) &p->mem[addr & 0xfff]) || codegen_in_recompile) { +# else + if ((p->mem == NULL) || (p->mem == page_ff) || (val != *(uint16_t *) &p->mem[addr & 0xfff])) { +# endif + uint64_t mask = (uint64_t) 1 << ((addr >> PAGE_MASK_SHIFT) & PAGE_MASK_MASK); + int byte_offset = (addr >> PAGE_BYTE_MASK_SHIFT) & PAGE_BYTE_MASK_OFFSET_MASK; + uint64_t byte_mask = (uint64_t) 1 << (addr & PAGE_BYTE_MASK_MASK); + + if ((addr & 0xf) == 0xf) + mask |= (mask << 1); + *(uint16_t *) &p->mem[addr & 0xfff] = val; + p->dirty_mask |= mask; + if ((p->code_present_mask & mask) && !page_in_evict_list(p)) + page_add_to_evict_list(p); + if ((addr & PAGE_BYTE_MASK_MASK) == PAGE_BYTE_MASK_MASK) { + p->byte_dirty_mask[byte_offset + 1] |= 1; + if ((p->byte_code_present_mask[byte_offset + 1] & 1) && !page_in_evict_list(p)) + page_add_to_evict_list(p); + } else + byte_mask |= (byte_mask << 1); + + p->byte_dirty_mask[byte_offset] |= byte_mask; + + if ((p->byte_code_present_mask[byte_offset] & byte_mask) && !page_in_evict_list(p)) + page_add_to_evict_list(p); + } +} + +void +mem_write_raml_page(uint32_t addr, uint32_t val, page_t *p) +{ + if (p == NULL) + return; + +# ifdef USE_DYNAREC + if ((p->mem == NULL) || (p->mem == page_ff) || (val != *(uint32_t *) &p->mem[addr & 0xfff]) || codegen_in_recompile) { +# else + if ((p->mem == NULL) || (p->mem == page_ff) || (val != *(uint32_t *) &p->mem[addr & 0xfff])) { +# endif + uint64_t mask = (uint64_t) 1 << ((addr >> PAGE_MASK_SHIFT) & PAGE_MASK_MASK); + int byte_offset = (addr >> PAGE_BYTE_MASK_SHIFT) & PAGE_BYTE_MASK_OFFSET_MASK; + uint64_t byte_mask = (uint64_t) 0xf << (addr & PAGE_BYTE_MASK_MASK); + + if ((addr & 0xf) >= 0xd) + mask |= (mask << 1); + *(uint32_t *) &p->mem[addr & 0xfff] = val; + p->dirty_mask |= mask; + p->byte_dirty_mask[byte_offset] |= byte_mask; + if (!page_in_evict_list(p) && ((p->code_present_mask & mask) || (p->byte_code_present_mask[byte_offset] & byte_mask))) + page_add_to_evict_list(p); + if ((addr & PAGE_BYTE_MASK_MASK) > (PAGE_BYTE_MASK_MASK - 3)) { + uint32_t byte_mask_2 = 0xf >> (4 - (addr & 3)); + + p->byte_dirty_mask[byte_offset + 1] |= byte_mask_2; + if ((p->byte_code_present_mask[byte_offset + 1] & byte_mask_2) && !page_in_evict_list(p)) + page_add_to_evict_list(p); + } + } +} +#else +void +mem_write_ramb_page(uint32_t addr, uint8_t val, page_t *p) +{ + if (p == NULL) + return; + +# ifdef USE_DYNAREC + if ((p->mem == NULL) || (p->mem == page_ff) || (val != p->mem[addr & 0xfff]) || codegen_in_recompile) { +# else + if ((p->mem == NULL) || (p->mem == page_ff) || (val != p->mem[addr & 0xfff])) { +# endif + uint64_t mask = (uint64_t) 1 << ((addr >> PAGE_MASK_SHIFT) & PAGE_MASK_MASK); + p->dirty_mask[(addr >> PAGE_MASK_INDEX_SHIFT) & PAGE_MASK_INDEX_MASK] |= mask; + p->mem[addr & 0xfff] = val; + } +} + +void +mem_write_ramw_page(uint32_t addr, uint16_t val, page_t *p) +{ + if (p == NULL) + return; + +# ifdef USE_DYNAREC + if ((p->mem == NULL) || (p->mem == page_ff) || (val != *(uint16_t *) &p->mem[addr & 0xfff]) || codegen_in_recompile) { +# else + if ((p->mem == NULL) || (p->mem == page_ff) || (val != *(uint16_t *) &p->mem[addr & 0xfff])) { +# endif + uint64_t mask = (uint64_t) 1 << ((addr >> PAGE_MASK_SHIFT) & PAGE_MASK_MASK); + if ((addr & 0xf) == 0xf) + mask |= (mask << 1); + p->dirty_mask[(addr >> PAGE_MASK_INDEX_SHIFT) & PAGE_MASK_INDEX_MASK] |= mask; + *(uint16_t *) &p->mem[addr & 0xfff] = val; + } +} + +void +mem_write_raml_page(uint32_t addr, uint32_t val, page_t *p) +{ + if (p == NULL) + return; + +# ifdef USE_DYNAREC + if ((p->mem == NULL) || (p->mem == page_ff) || (val != *(uint32_t *) &p->mem[addr & 0xfff]) || codegen_in_recompile) { +# else + if ((p->mem == NULL) || (p->mem == page_ff) || (val != *(uint32_t *) &p->mem[addr & 0xfff])) { +# endif + uint64_t mask = (uint64_t) 1 << ((addr >> PAGE_MASK_SHIFT) & PAGE_MASK_MASK); + if ((addr & 0xf) >= 0xd) + mask |= (mask << 1); + p->dirty_mask[(addr >> PAGE_MASK_INDEX_SHIFT) & PAGE_MASK_INDEX_MASK] |= mask; + *(uint32_t *) &p->mem[addr & 0xfff] = val; + } +} +#endif + +void +mem_write_ram(uint32_t addr, uint8_t val, void *priv) +{ +#ifdef ENABLE_MEM_LOG + if ((addr >= 0xa0000) && (addr <= 0xbffff)) + mem_log("Write B %02X to %08X\n", val, addr); +#endif + if (is286) { + addwritelookup(mem_logical_addr, addr); + mem_write_ramb_page(addr, val, &pages[addr >> 12]); + } else + ram[addr] = val; +} + +void +mem_write_ramw(uint32_t addr, uint16_t val, void *priv) +{ +#ifdef ENABLE_MEM_LOG + if ((addr >= 0xa0000) && (addr <= 0xbffff)) + mem_log("Write W %04X to %08X\n", val, addr); +#endif + if (is286) { + addwritelookup(mem_logical_addr, addr); + mem_write_ramw_page(addr, val, &pages[addr >> 12]); + } else + *(uint16_t *) &ram[addr] = val; +} + +void +mem_write_raml(uint32_t addr, uint32_t val, void *priv) +{ +#ifdef ENABLE_MEM_LOG + if ((addr >= 0xa0000) && (addr <= 0xbffff)) + mem_log("Write L %08X to %08X\n", val, addr); +#endif + if (is286) { + addwritelookup(mem_logical_addr, addr); + mem_write_raml_page(addr, val, &pages[addr >> 12]); + } else + *(uint32_t *) &ram[addr] = val; +} + +static uint8_t +mem_read_remapped(uint32_t addr, void *priv) +{ + addr = 0xA0000 + (addr - remap_start_addr); + if (is286) + addreadlookup(mem_logical_addr, addr); + return ram[addr]; +} + +static uint16_t +mem_read_remappedw(uint32_t addr, void *priv) +{ + addr = 0xA0000 + (addr - remap_start_addr); + if (is286) + addreadlookup(mem_logical_addr, addr); + return *(uint16_t *) &ram[addr]; +} + +static uint32_t +mem_read_remappedl(uint32_t addr, void *priv) +{ + addr = 0xA0000 + (addr - remap_start_addr); + if (is286) + addreadlookup(mem_logical_addr, addr); + return *(uint32_t *) &ram[addr]; +} + +static uint8_t +mem_read_remapped2(uint32_t addr, void *priv) +{ + addr = 0xD0000 + (addr - remap_start_addr2); + if (is286) + addreadlookup(mem_logical_addr, addr); + return ram[addr]; +} + +static uint16_t +mem_read_remappedw2(uint32_t addr, void *priv) +{ + addr = 0xD0000 + (addr - remap_start_addr2); + if (is286) + addreadlookup(mem_logical_addr, addr); + return *(uint16_t *) &ram[addr]; +} + +static uint32_t +mem_read_remappedl2(uint32_t addr, void *priv) +{ + addr = 0xD0000 + (addr - remap_start_addr2); + if (is286) + addreadlookup(mem_logical_addr, addr); + return *(uint32_t *) &ram[addr]; +} + +static void +mem_write_remapped(uint32_t addr, uint8_t val, void *priv) +{ + uint32_t oldaddr = addr; + addr = 0xA0000 + (addr - remap_start_addr); + if (is286) { + addwritelookup(mem_logical_addr, addr); + mem_write_ramb_page(addr, val, &pages[oldaddr >> 12]); + } else + ram[addr] = val; +} + +static void +mem_write_remappedw(uint32_t addr, uint16_t val, void *priv) +{ + uint32_t oldaddr = addr; + addr = 0xA0000 + (addr - remap_start_addr); + if (is286) { + addwritelookup(mem_logical_addr, addr); + mem_write_ramw_page(addr, val, &pages[oldaddr >> 12]); + } else + *(uint16_t *) &ram[addr] = val; +} + +static void +mem_write_remappedl(uint32_t addr, uint32_t val, void *priv) +{ + uint32_t oldaddr = addr; + addr = 0xA0000 + (addr - remap_start_addr); + if (is286) { + addwritelookup(mem_logical_addr, addr); + mem_write_raml_page(addr, val, &pages[oldaddr >> 12]); + } else + *(uint32_t *) &ram[addr] = val; +} + +static void +mem_write_remapped2(uint32_t addr, uint8_t val, void *priv) +{ + uint32_t oldaddr = addr; + addr = 0xD0000 + (addr - remap_start_addr2); + if (is286) { + addwritelookup(mem_logical_addr, addr); + mem_write_ramb_page(addr, val, &pages[oldaddr >> 12]); + } else + ram[addr] = val; +} + +static void +mem_write_remappedw2(uint32_t addr, uint16_t val, void *priv) +{ + uint32_t oldaddr = addr; + addr = 0xD0000 + (addr - remap_start_addr2); + if (is286) { + addwritelookup(mem_logical_addr, addr); + mem_write_ramw_page(addr, val, &pages[oldaddr >> 12]); + } else + *(uint16_t *) &ram[addr] = val; +} + +static void +mem_write_remappedl2(uint32_t addr, uint32_t val, void *priv) +{ + uint32_t oldaddr = addr; + addr = 0xD0000 + (addr - remap_start_addr2); + if (is286) { + addwritelookup(mem_logical_addr, addr); + mem_write_raml_page(addr, val, &pages[oldaddr >> 12]); + } else + *(uint32_t *) &ram[addr] = val; +} + +void +mem_invalidate_range(uint32_t start_addr, uint32_t end_addr) +{ +#ifdef USE_NEW_DYNAREC + page_t *p; + + start_addr &= ~PAGE_MASK_MASK; + end_addr = (end_addr + PAGE_MASK_MASK) & ~PAGE_MASK_MASK; + + for (; start_addr <= end_addr; start_addr += 0x1000) { + if ((start_addr >> 12) >= pages_sz) + continue; + + p = &pages[start_addr >> 12]; + if (p) { + p->dirty_mask = 0xffffffffffffffffULL; + + if (p->byte_dirty_mask) + memset(p->byte_dirty_mask, 0xff, 64 * sizeof(uint64_t)); + + if (!page_in_evict_list(p)) + page_add_to_evict_list(p); + } + } +#else + uint32_t cur_addr; + start_addr &= ~PAGE_MASK_MASK; + end_addr = (end_addr + PAGE_MASK_MASK) & ~PAGE_MASK_MASK; + + for (; start_addr <= end_addr; start_addr += 0x1000) { + /* Do nothing if the pages array is empty or DMA reads/writes to/from PCI device memory addresses + may crash the emulator. */ + cur_addr = (start_addr >> 12); + if (cur_addr < pages_sz) + memset(pages[cur_addr].dirty_mask, 0xff, sizeof(pages[cur_addr].dirty_mask)); + } +#endif +} + +static __inline int +mem_mapping_access_allowed(uint32_t flags, uint16_t access) +{ + int ret = 0; + + if (!(access & ACCESS_DISABLED)) { + if (access & ACCESS_CACHE) + ret = (flags & MEM_MAPPING_CACHE); + else if (access & ACCESS_SMRAM) + ret = (flags & MEM_MAPPING_SMRAM); + else if (!(access & ACCESS_INTERNAL)) { + if (flags & MEM_MAPPING_IS_ROM) { + if (access & ACCESS_ROMCS) + ret = (flags & MEM_MAPPING_ROMCS); + else + ret = !(flags & MEM_MAPPING_ROMCS); + } else + ret = 1; + + ret = ret && !(flags & MEM_MAPPING_INTERNAL) && !(flags & MEM_MAPPING_SMRAM); + } else + ret = !(flags & MEM_MAPPING_EXTERNAL) && !(flags & MEM_MAPPING_SMRAM); + } else { + /* Still allow SMRAM if access is DISABLED but also has CACHE and/or SMRAM flags set. */ + if (access & ACCESS_CACHE) + ret = (flags & MEM_MAPPING_CACHE); + else if (access & ACCESS_SMRAM) + ret = (flags & MEM_MAPPING_SMRAM); + } + + return ret; +} + +void +mem_mapping_recalc(uint64_t base, uint64_t size) +{ + mem_mapping_t *map; + int n; + uint64_t c; + + if ((base >= 0xec000000) && (base <= 0xecffffff)) + pclog("mem_mapping_recalc(%016" PRIX64 ", %016" PRIX64 ")\n", base, size); + + if (!size || (base_mapping == NULL)) + return; + + map = base_mapping; + + /* Clear out old mappings. */ + for (c = base; c < base + size; c += MEM_GRANULARITY_SIZE) { + _mem_exec[c >> MEM_GRANULARITY_BITS] = NULL; + write_mapping[c >> MEM_GRANULARITY_BITS] = NULL; + read_mapping[c >> MEM_GRANULARITY_BITS] = NULL; + write_mapping_bus[c >> MEM_GRANULARITY_BITS] = NULL; + read_mapping_bus[c >> MEM_GRANULARITY_BITS] = NULL; + } + + /* Walk mapping list. */ + while (map != NULL) { + /* In range? */ + if (map->enable && (uint64_t) map->base < ((uint64_t) base + (uint64_t) size) && ((uint64_t) map->base + (uint64_t) map->size) > (uint64_t) base) { + uint64_t start = (map->base < base) ? map->base : base; + uint64_t end = (((uint64_t) map->base + (uint64_t) map->size) < (base + size)) ? ((uint64_t) map->base + (uint64_t) map->size) : (base + size); + if (start < map->base) + start = map->base; + + for (c = start; c < end; c += MEM_GRANULARITY_SIZE) { + /* CPU */ + n = !!in_smm; + if ((c >= 0xec000000) && (c <= 0xecffffff)) + pclog("mem_mapping_recalc(): map = %08X (%02X) (%02X, %02X, %02X)\n", map, map->flags, _mem_state[c >> MEM_GRANULARITY_BITS].states[n].r, _mem_state[c >> MEM_GRANULARITY_BITS].states[n].w, _mem_state[c >> MEM_GRANULARITY_BITS].states[n].x); + if (map->exec && mem_mapping_access_allowed(map->flags, _mem_state[c >> MEM_GRANULARITY_BITS].states[n].x)) + _mem_exec[c >> MEM_GRANULARITY_BITS] = map->exec + (c - map->base); + if ((map->write_b || map->write_w || map->write_l) && mem_mapping_access_allowed(map->flags, _mem_state[c >> MEM_GRANULARITY_BITS].states[n].w)) + write_mapping[c >> MEM_GRANULARITY_BITS] = map; + if ((map->read_b || map->read_w || map->read_l) && mem_mapping_access_allowed(map->flags, _mem_state[c >> MEM_GRANULARITY_BITS].states[n].r)) + read_mapping[c >> MEM_GRANULARITY_BITS] = map; + + /* Bus */ + n |= STATE_BUS; + if ((map->write_b || map->write_w || map->write_l) && mem_mapping_access_allowed(map->flags, _mem_state[c >> MEM_GRANULARITY_BITS].states[n].w)) + write_mapping_bus[c >> MEM_GRANULARITY_BITS] = map; + if ((map->read_b || map->read_w || map->read_l) && mem_mapping_access_allowed(map->flags, _mem_state[c >> MEM_GRANULARITY_BITS].states[n].r)) + read_mapping_bus[c >> MEM_GRANULARITY_BITS] = map; + } + } + map = map->next; + } + + flushmmucache_cr3(); + +#ifdef ENABLE_MEM_LOG + pclog("\nMemory map:\n"); + mem_mapping_t *write = (mem_mapping_t *) -1, *read = (mem_mapping_t *) -1, *write_bus = (mem_mapping_t *) -1, *read_bus = (mem_mapping_t *) -1; + for (c = 0; c < (sizeof(write_mapping) / sizeof(write_mapping[0])); c++) { + if ((write_mapping[c] == write) && (read_mapping[c] == read) && (write_mapping_bus[c] == write_bus) && (read_mapping_bus[c] == read_bus)) + continue; + write = write_mapping[c]; + read = read_mapping[c]; + write_bus = write_mapping_bus[c]; + read_bus = read_mapping_bus[c]; + + pclog("%08X | ", c << MEM_GRANULARITY_BITS); + if (read) { + pclog("R%c%c%c %08X+% 8X", + read->read_b ? 'b' : ' ', read->read_w ? 'w' : ' ', read->read_l ? 'l' : ' ', + read->base, read->size); + } else { + pclog(" "); + } + if (write) { + pclog(" | W%c%c%c %08X+% 8X", + write->write_b ? 'b' : ' ', write->write_w ? 'w' : ' ', write->write_l ? 'l' : ' ', + write->base, write->size); + } else { + pclog(" | "); + } + pclog(" | %c\n", _mem_exec[c] ? 'X' : ' '); + + if ((write != write_bus) || (read != read_bus)) { + pclog(" ^ bus | "); + if (read_bus) { + pclog("R%c%c%c %08X+% 8X", + read_bus->read_b ? 'b' : ' ', read_bus->read_w ? 'w' : ' ', read_bus->read_l ? 'l' : ' ', + read_bus->base, read_bus->size); + } else { + pclog(" "); + } + if (write_bus) { + pclog(" | W%c%c%c %08X+% 8X", + write_bus->write_b ? 'b' : ' ', write_bus->write_w ? 'w' : ' ', write_bus->write_l ? 'l' : ' ', + write_bus->base, write_bus->size); + } else { + pclog(" | "); + } + pclog(" |\n"); + } + } + pclog("\n"); +#endif +} + +void +mem_mapping_set(mem_mapping_t *map, + uint32_t base, + uint32_t size, + uint8_t (*read_b)(uint32_t addr, void *p), + uint16_t (*read_w)(uint32_t addr, void *p), + uint32_t (*read_l)(uint32_t addr, void *p), + void (*write_b)(uint32_t addr, uint8_t val, void *p), + void (*write_w)(uint32_t addr, uint16_t val, void *p), + void (*write_l)(uint32_t addr, uint32_t val, void *p), + uint8_t *exec, + uint32_t fl, + void *p) +{ + if (size != 0x00000000) + map->enable = 1; + else + map->enable = 0; + map->base = base; + map->size = size; + map->mask = (map->size ? 0xffffffff : 0x00000000); + map->read_b = read_b; + map->read_w = read_w; + map->read_l = read_l; + map->write_b = write_b; + map->write_w = write_w; + map->write_l = write_l; + map->exec = exec; + map->flags = fl; + map->p = p; + map->next = NULL; + mem_log("mem_mapping_add(): Linked list structure: %08X -> %08X -> %08X\n", map->prev, map, map->next); + + /* If the mapping is disabled, there is no need to recalc anything. */ + if (size != 0x00000000) + mem_mapping_recalc(map->base, map->size); +} + +void +mem_mapping_add(mem_mapping_t *map, + uint32_t base, + uint32_t size, + uint8_t (*read_b)(uint32_t addr, void *p), + uint16_t (*read_w)(uint32_t addr, void *p), + uint32_t (*read_l)(uint32_t addr, void *p), + void (*write_b)(uint32_t addr, uint8_t val, void *p), + void (*write_w)(uint32_t addr, uint16_t val, void *p), + void (*write_l)(uint32_t addr, uint32_t val, void *p), + uint8_t *exec, + uint32_t fl, + void *p) +{ + /* Do a sanity check */ + if ((base_mapping == NULL) && (last_mapping != NULL)) { + fatal("mem_mapping_add(): NULL base mapping with non-NULL last mapping\n"); + return; + } else if ((base_mapping != NULL) && (last_mapping == NULL)) { + fatal("mem_mapping_add(): Non-NULL base mapping with NULL last mapping\n"); + return; + } else if ((base_mapping != NULL) && (base_mapping->prev != NULL)) { + fatal("mem_mapping_add(): Base mapping with a preceding mapping\n"); + return; + } else if ((last_mapping != NULL) && (last_mapping->next != NULL)) { + fatal("mem_mapping_add(): Last mapping with a following mapping\n"); + return; + } + + /* Add mapping to the beginning of the list if necessary.*/ + if (base_mapping == NULL) + base_mapping = map; + + /* Add mapping to the end of the list.*/ + if (last_mapping == NULL) + map->prev = NULL; + else { + map->prev = last_mapping; + last_mapping->next = map; + } + last_mapping = map; + + mem_mapping_set(map, base, size, read_b, read_w, read_l, + write_b, write_w, write_l, exec, fl, p); +} + +void +mem_mapping_do_recalc(mem_mapping_t *map) +{ + mem_mapping_recalc(map->base, map->size); +} + +void +mem_mapping_set_handler(mem_mapping_t *map, + uint8_t (*read_b)(uint32_t addr, void *p), + uint16_t (*read_w)(uint32_t addr, void *p), + uint32_t (*read_l)(uint32_t addr, void *p), + void (*write_b)(uint32_t addr, uint8_t val, void *p), + void (*write_w)(uint32_t addr, uint16_t val, void *p), + void (*write_l)(uint32_t addr, uint32_t val, void *p)) +{ + map->read_b = read_b; + map->read_w = read_w; + map->read_l = read_l; + map->write_b = write_b; + map->write_w = write_w; + map->write_l = write_l; + + mem_mapping_recalc(map->base, map->size); +} + +void +mem_mapping_set_addr(mem_mapping_t *map, uint32_t base, uint32_t size) +{ + if ((base >= 0xec000000) && (base <= 0xecffffff)) + pclog("[0] mem_mapping_set_addr(%08X, %08X)\n", base, size); + + /* Remove old mapping. */ + map->enable = 0; + mem_mapping_recalc(map->base, map->size); + + if ((base >= 0xec000000) && (base <= 0xecffffff)) + pclog("[1] mem_mapping_set_addr(%08X, %08X)\n", base, size); + + /* Set new mapping. */ + map->enable = 1; + map->base = base; + map->size = size; + + if ((base >= 0xec000000) && (base <= 0xecffffff)) + pclog("[2] mem_mapping_set_addr(%08X, %08X)\n", base, size); + + mem_mapping_recalc((uint64_t) map->base, (uint64_t) map->size); +} + +void +mem_mapping_set_exec(mem_mapping_t *map, uint8_t *exec) +{ + map->exec = exec; + + mem_mapping_recalc((uint64_t) map->base, (uint64_t) map->size); +} + +void +mem_mapping_set_mask(mem_mapping_t *map, uint32_t mask) +{ + map->mask = mask; + + mem_mapping_recalc((uint64_t) map->base, (uint64_t) map->size); +} + +void +mem_mapping_set_p(mem_mapping_t *map, void *p) +{ + map->p = p; +} + +void +mem_mapping_disable(mem_mapping_t *map) +{ + map->enable = 0; + + mem_mapping_recalc((uint64_t) map->base, (uint64_t) map->size); +} + +void +mem_mapping_enable(mem_mapping_t *map) +{ + map->enable = 1; + + mem_mapping_recalc((uint64_t) map->base, (uint64_t) map->size); +} + +void +mem_set_access(uint8_t bitmap, int mode, uint32_t base, uint32_t size, uint16_t access) +{ + uint32_t c; + uint16_t mask, smstate = 0x0000; + const uint16_t smstates[4] = { 0x0000, (MEM_READ_SMRAM | MEM_WRITE_SMRAM), + MEM_READ_SMRAM_EX, (MEM_READ_DISABLED_EX | MEM_WRITE_DISABLED_EX) }; + + int i; + + if (mode) + mask = 0x2d6b; + else + mask = 0x1084; + + if (mode) { + if (mode == 1) + access = !!access; + + if (mode == 3) { + if (access & ACCESS_SMRAM_X) + smstate |= MEM_EXEC_SMRAM; + if (access & ACCESS_SMRAM_R) + smstate |= MEM_READ_SMRAM_2; + if (access & ACCESS_SMRAM_W) + smstate |= MEM_WRITE_SMRAM; + } else + smstate = smstates[access & 0x07]; + } else + smstate = access & 0x6f7b; + + for (c = 0; c < size; c += MEM_GRANULARITY_SIZE) { + for (i = 0; i < 4; i++) { + if (bitmap & (1 << i)) { + _mem_state[(c + base) >> MEM_GRANULARITY_BITS].vals[i] = (_mem_state[(c + base) >> MEM_GRANULARITY_BITS].vals[i] & mask) | smstate; + } + } + +#ifdef ENABLE_MEM_LOG + if (((c + base) >= 0xa0000) && ((c + base) <= 0xbffff)) { + mem_log("Set mem state for block at %08X to %04X with bitmap %02X\n", + c + base, smstate, bitmap); + } +#endif + } + + mem_mapping_recalc(base, size); +} + +void +mem_a20_init(void) +{ + if (is286) { + mem_a20_key = mem_a20_alt = mem_a20_state = 0; + rammask = cpu_16bitbus ? 0xffffff : 0xffffffff; + if (is6117) + rammask |= 0x03000000; + flushmmucache(); + // mem_a20_state = mem_a20_key | mem_a20_alt; + } else { + rammask = 0xfffff; + flushmmucache(); + mem_a20_key = mem_a20_alt = mem_a20_state = 0; + } +} + +/* Close all the memory mappings. */ +void +mem_close(void) +{ + mem_mapping_t *map = base_mapping, *next; + + while (map != NULL) { + next = map->next; + map->prev = map->next = NULL; + map = next; + } + + base_mapping = last_mapping = 0; +} + +static void +mem_add_ram_mapping(mem_mapping_t *mapping, uint32_t base, uint32_t size) +{ + mem_mapping_add(mapping, base, size, + mem_read_ram, mem_read_ramw, mem_read_raml, + mem_write_ram, mem_write_ramw, mem_write_raml, + ram + base, MEM_MAPPING_INTERNAL, NULL); +} + +static void +mem_init_ram_mapping(mem_mapping_t *mapping, uint32_t base, uint32_t size) +{ + mem_set_mem_state_both(base, size, MEM_READ_INTERNAL | MEM_WRITE_INTERNAL); + mem_add_ram_mapping(mapping, base, size); +} + +/* Reset the memory state. */ +void +mem_reset(void) +{ + uint32_t c; + size_t m; + + memset(page_ff, 0xff, sizeof(page_ff)); + +#ifdef USE_NEW_DYNAREC + if (byte_dirty_mask) { + free(byte_dirty_mask); + byte_dirty_mask = NULL; + } + + if (byte_code_present_mask) { + free(byte_code_present_mask); + byte_code_present_mask = NULL; + } +#endif + + /* Free the old pages array, if necessary. */ + if (pages) { + free(pages); + pages = NULL; + } + + if (ram != NULL) { + plat_munmap(ram, ram_size); + ram = NULL; + ram_size = 0; + } +#if (!(defined __amd64__ || defined _M_X64 || defined __aarch64__ || defined _M_ARM64)) + if (ram2 != NULL) { + plat_munmap(ram2, ram2_size); + ram2 = NULL; + ram2_size = 0; + } + + if (mem_size > 2097152) + mem_size = 2097152; +#endif + + m = 1024UL * (size_t) mem_size; + +#if (!(defined __amd64__ || defined _M_X64 || defined __aarch64__ || defined _M_ARM64)) + if (mem_size > 1048576) { + ram_size = 1 << 30; + ram = (uint8_t *) plat_mmap(ram_size, 0); /* allocate and clear the RAM block of the first 1 GB */ + if (ram == NULL) { + fatal("Failed to allocate primary RAM block. Make sure you have enough RAM available.\n"); + return; + } + memset(ram, 0x00, ram_size); + ram2_size = m - (1 << 30); + ram2 = (uint8_t *) plat_mmap(ram2_size, 0); /* allocate and clear the RAM block above 1 GB */ + if (ram2 == NULL) { + if (config_changed == 2) + fatal(EMU_NAME " must be restarted for the memory amount change to be applied.\n"); + else + fatal("Failed to allocate secondary RAM block. Make sure you have enough RAM available.\n"); + return; + } + memset(ram2, 0x00, ram2_size); + } else +#endif + { + ram_size = m; + ram = (uint8_t *) plat_mmap(ram_size, 0); /* allocate and clear the RAM block */ + if (ram == NULL) { + fatal("Failed to allocate RAM block. Make sure you have enough RAM available.\n"); + return; + } + memset(ram, 0x00, ram_size); + if (mem_size > 1048576) + ram2 = &(ram[1 << 30]); + } + + /* + * Allocate the page table based on how much RAM we have. + * We re-allocate the table on each (hard) reset, as the + * memory amount could have changed. + */ + if (is286) { + if (cpu_16bitbus) { + /* 80286/386SX; maximum address space is 16MB. */ + m = 4096; + /* ALi M6117; maximum address space is 64MB. */ + if (is6117) + m <<= 2; + } else { + /* 80386DX+; maximum address space is 4GB. */ + m = 1048576; + } + } else { + /* 8088/86; maximum address space is 1MB. */ + m = 256; + } + + addr_space_size = m; + + /* + * Allocate and initialize the (new) page table. + */ + pages_sz = m; + pages = (page_t *) malloc(m * sizeof(page_t)); + + memset(page_lookup, 0x00, (1 << 20) * sizeof(page_t *)); + memset(page_lookupp, 0x04, (1 << 20) * sizeof(uint8_t)); + + memset(pages, 0x00, pages_sz * sizeof(page_t)); + +#ifdef USE_NEW_DYNAREC + byte_dirty_mask = malloc((mem_size * 1024) / 8); + memset(byte_dirty_mask, 0, (mem_size * 1024) / 8); + + byte_code_present_mask = malloc((mem_size * 1024) / 8); + memset(byte_code_present_mask, 0, (mem_size * 1024) / 8); +#endif + + for (c = 0; c < pages_sz; c++) { + if ((c << 12) >= (mem_size << 10)) + pages[c].mem = page_ff; + else { +#if (!(defined __amd64__ || defined _M_X64 || defined __aarch64__ || defined _M_ARM64)) + if (mem_size > 1048576) { + if ((c << 12) < (1 << 30)) + pages[c].mem = &ram[c << 12]; + else + pages[c].mem = &ram2[(c << 12) - (1 << 30)]; + } else + pages[c].mem = &ram[c << 12]; +#else + pages[c].mem = &ram[c << 12]; +#endif + } + if (c < m) { + pages[c].write_b = mem_write_ramb_page; + pages[c].write_w = mem_write_ramw_page; + pages[c].write_l = mem_write_raml_page; + } +#ifdef USE_NEW_DYNAREC + pages[c].evict_prev = EVICT_NOT_IN_LIST; + pages[c].byte_dirty_mask = &byte_dirty_mask[c * 64]; + pages[c].byte_code_present_mask = &byte_code_present_mask[c * 64]; +#endif + } + + memset(_mem_exec, 0x00, sizeof(_mem_exec)); + memset(write_mapping, 0x00, sizeof(write_mapping)); + memset(read_mapping, 0x00, sizeof(read_mapping)); + memset(write_mapping_bus, 0x00, sizeof(write_mapping_bus)); + memset(read_mapping_bus, 0x00, sizeof(read_mapping_bus)); + + base_mapping = last_mapping = NULL; + + /* Set the entire memory space as external. */ + memset(_mem_state, 0x00, sizeof(_mem_state)); + + /* Set the low RAM space as internal. */ + mem_init_ram_mapping(&ram_low_mapping, 0x000000, (mem_size > 640) ? 0xa0000 : mem_size * 1024); + + if (mem_size > 1024) { + if (cpu_16bitbus && !is6117 && mem_size > 16256) + mem_init_ram_mapping(&ram_high_mapping, 0x100000, (16256 - 1024) * 1024); + else if (cpu_16bitbus && is6117 && mem_size > 65408) + mem_init_ram_mapping(&ram_high_mapping, 0x100000, (65408 - 1024) * 1024); + else { + if (mem_size > 1048576) { + mem_init_ram_mapping(&ram_high_mapping, 0x100000, (1048576 - 1024) * 1024); + + mem_set_mem_state_both((1 << 30), (mem_size - 1048576) * 1024, + MEM_READ_INTERNAL | MEM_WRITE_INTERNAL); + mem_mapping_add(&ram_2gb_mapping, (1 << 30), + ((mem_size - 1048576) * 1024), + mem_read_ram_2gb, mem_read_ram_2gbw, mem_read_ram_2gbl, + mem_write_ram, mem_write_ramw, mem_write_raml, + ram2, MEM_MAPPING_INTERNAL, NULL); + } else + mem_init_ram_mapping(&ram_high_mapping, 0x100000, (mem_size - 1024) * 1024); + } + } + + if (mem_size > 768) { + mem_add_ram_mapping(&ram_mid_mapping, 0xa0000, 0x60000); + + mem_add_ram_mapping(&ram_mid_mapping2, 0xa0000, 0x60000); + mem_mapping_disable(&ram_mid_mapping2); + } + + mem_mapping_add(&ram_remapped_mapping, mem_size * 1024, 256 * 1024, + mem_read_remapped, mem_read_remappedw, mem_read_remappedl, + mem_write_remapped, mem_write_remappedw, mem_write_remappedl, + ram + 0xa0000, MEM_MAPPING_INTERNAL, NULL); + mem_mapping_disable(&ram_remapped_mapping); + + /* Mapping for SiS 471 relocation which relocates A0000-BFFFF, D0000-EFFFF, which is non-contiguous. */ + mem_mapping_add(&ram_remapped_mapping2, mem_size * 1024, 256 * 1024, + mem_read_remapped2, mem_read_remappedw2, mem_read_remappedl2, + mem_write_remapped2, mem_write_remappedw2, mem_write_remappedl2, + ram + 0xd0000, MEM_MAPPING_INTERNAL, NULL); + mem_mapping_disable(&ram_remapped_mapping2); + + mem_a20_init(); + +#ifdef USE_NEW_DYNAREC + purgable_page_list_head = 0; + purgeable_page_count = 0; +#endif +} + +void +mem_init(void) +{ + /* Perform a one-time init. */ + ram = rom = NULL; + ram2 = NULL; + pages = NULL; + + /* Allocate the lookup tables. */ + page_lookup = (page_t **) malloc((1 << 20) * sizeof(page_t *)); + page_lookupp = (uint8_t *) malloc((1 << 20) * sizeof(uint8_t)); + readlookup2 = malloc((1 << 20) * sizeof(uintptr_t)); + readlookupp = malloc((1 << 20) * sizeof(uint8_t)); + writelookup2 = malloc((1 << 20) * sizeof(uintptr_t)); + writelookupp = malloc((1 << 20) * sizeof(uint8_t)); +} + +void +mem_remap_top(int kb) +{ + uint32_t c; + uint32_t start = (mem_size >= 1024) ? mem_size : 1024; + int offset, size = mem_size - 640; + int set = 1; + static int old_kb = 0; + int sis_mode = 0; + uint32_t start_addr = 0, addr = 0; + + mem_log("MEM: remapping top %iKB (mem=%i)\n", kb, mem_size); + if (mem_size <= 640) + return; + + /* SiS 471 special mode. */ + if (kb == -256) { + kb = 256; + sis_mode = 1; + } + + /* Do not remap if we're have more than (16 MB - RAM) memory. */ + if ((kb != 0) && (mem_size >= (16384 - kb))) + return; + + if (kb == 0) { + kb = old_kb; + set = 0; + } else + old_kb = kb; + + if (size > kb) + size = kb; + + remap_start_addr = start << 10; + remap_start_addr2 = (start << 10) + 0x00020000; + + for (c = ((start * 1024) >> 12); c < (((start + size) * 1024) >> 12); c++) { + offset = c - ((start * 1024) >> 12); + /* Use A0000-BFFFF, D0000-EFFFF instead of C0000-DFFFF, E0000-FFFFF. */ + addr = 0xa0000 + (offset << 12); + if (sis_mode) { + /* A0000-DFFFF -> A0000-BFFFF, D0000-EFFFF */ + if (addr >= 0x000c0000) + addr += 0x00010000; + } + if (start_addr == 0) + start_addr = addr; + pages[c].mem = set ? &ram[addr] : page_ff; + pages[c].write_b = set ? mem_write_ramb_page : NULL; + pages[c].write_w = set ? mem_write_ramw_page : NULL; + pages[c].write_l = set ? mem_write_raml_page : NULL; +#ifdef USE_NEW_DYNAREC + pages[c].evict_prev = EVICT_NOT_IN_LIST; + pages[c].byte_dirty_mask = &byte_dirty_mask[(addr >> 12) * 64]; + pages[c].byte_code_present_mask = &byte_code_present_mask[(addr >> 12) * 64]; +#endif + } + + mem_set_mem_state_both(start * 1024, size * 1024, set ? (MEM_READ_INTERNAL | MEM_WRITE_INTERNAL) : (MEM_READ_EXTERNAL | MEM_WRITE_EXTERNAL)); + + for (c = 0xa0; c < 0xf0; c++) { + if ((c >= 0xc0) && (c <= 0xcf)) + continue; + + if (sis_mode || ((c << 12) >= (mem_size << 10))) + pages[c].mem = page_ff; + else { +#if (!(defined __amd64__ || defined _M_X64 || defined __aarch64__ || defined _M_ARM64)) + if (mem_size > 1048576) { + if ((c << 12) < (1 << 30)) + pages[c].mem = &ram[c << 12]; + else + pages[c].mem = &ram2[(c << 12) - (1 << 30)]; + } else + pages[c].mem = &ram[c << 12]; +#else + pages[c].mem = &ram[c << 12]; +#endif + } + if (!sis_mode && (c < addr_space_size)) { + pages[c].write_b = mem_write_ramb_page; + pages[c].write_w = mem_write_ramw_page; + pages[c].write_l = mem_write_raml_page; + } else { + pages[c].write_b = NULL; + pages[c].write_w = NULL; + pages[c].write_l = NULL; + } +#ifdef USE_NEW_DYNAREC + pages[c].evict_prev = EVICT_NOT_IN_LIST; + pages[c].byte_dirty_mask = &byte_dirty_mask[c * 64]; + pages[c].byte_code_present_mask = &byte_code_present_mask[c * 64]; +#endif + } + + if (set) { + if (sis_mode) { + mem_mapping_set_addr(&ram_remapped_mapping, start * 1024, 0x00020000); + mem_mapping_set_exec(&ram_remapped_mapping, ram + 0x000a0000); + mem_mapping_set_addr(&ram_remapped_mapping2, (start * 1024) + 0x00020000, 0x00020000); + mem_mapping_set_exec(&ram_remapped_mapping2, ram + 0x000d0000); + + mem_mapping_set_addr(&ram_mid_mapping, 0x000c0000, 0x00010000); + mem_mapping_set_exec(&ram_mid_mapping, ram + 0x000c0000); + mem_mapping_set_addr(&ram_mid_mapping2, 0x000f0000, 0x00010000); + mem_mapping_set_exec(&ram_mid_mapping2, ram + 0x000f0000); + } else { + mem_mapping_set_addr(&ram_remapped_mapping, start * 1024, size * 1024); + mem_mapping_set_exec(&ram_remapped_mapping, ram + start_addr); + mem_mapping_disable(&ram_remapped_mapping2); + + mem_mapping_set_addr(&ram_mid_mapping, 0x000a0000, 0x00060000); + mem_mapping_set_exec(&ram_mid_mapping, ram + 0x000a0000); + mem_mapping_disable(&ram_mid_mapping2); + } + } else { + mem_mapping_disable(&ram_remapped_mapping); + mem_mapping_disable(&ram_remapped_mapping2); + + mem_mapping_set_addr(&ram_mid_mapping, 0x000a0000, 0x00060000); + mem_mapping_set_exec(&ram_mid_mapping, ram + 0x000a0000); + mem_mapping_disable(&ram_mid_mapping2); + } + + flushmmucache(); +} + +void +mem_reset_page_blocks(void) +{ + uint32_t c; + + if (pages == NULL) + return; + + for (c = 0; c < pages_sz; c++) { + pages[c].write_b = mem_write_ramb_page; + pages[c].write_w = mem_write_ramw_page; + pages[c].write_l = mem_write_raml_page; +#ifdef USE_NEW_DYNAREC + pages[c].block = BLOCK_INVALID; + pages[c].block_2 = BLOCK_INVALID; + pages[c].head = BLOCK_INVALID; +#else + pages[c].block[0] = pages[c].block[1] = pages[c].block[2] = pages[c].block[3] = NULL; + pages[c].block_2[0] = pages[c].block_2[1] = pages[c].block_2[2] = pages[c].block_2[3] = NULL; + pages[c].head = NULL; +#endif + } +} + +void +mem_a20_recalc(void) +{ + int state; + + if (!is286) { + rammask = 0xfffff; + flushmmucache(); + mem_a20_key = mem_a20_alt = mem_a20_state = 0; + + return; + } + + state = mem_a20_key | mem_a20_alt; + if (state && !mem_a20_state) { + rammask = (cpu_16bitbus) ? 0xffffff : 0xffffffff; + if (is6117) + rammask |= 0x03000000; + flushmmucache(); + } else if (!state && mem_a20_state) { + rammask = (cpu_16bitbus) ? 0xefffff : 0xffefffff; + if (is6117) + rammask |= 0x03000000; + flushmmucache(); + } + + mem_a20_state = state; +} diff --git a/src/mouse.patch b/src/mouse.patch new file mode 100644 index 000000000..4d9d67d2a --- /dev/null +++ b/src/mouse.patch @@ -0,0 +1,69 @@ +diff --git a/src/86box.c b/src/86box.c +index a14f51c41..3c96d88a4 100644 +--- a/src/86box.c ++++ b/src/86box.c +@@ -1263,9 +1263,9 @@ pc_run(void) + startblit(); + cpu_exec(cpu_s->rspeed / 100); + #ifdef USE_GDBSTUB /* avoid a KBC FIFO overflow when CPU emulation is stalled */ +- if (gdbstub_step == GDBSTUB_EXEC) ++ // if (gdbstub_step == GDBSTUB_EXEC) + #endif +- mouse_process(); ++ // mouse_process(); + joystick_process(); + endblit(); + +diff --git a/src/device/mouse.c b/src/device/mouse.c +index 7eb6a08a9..329397d43 100644 +--- a/src/device/mouse.c ++++ b/src/device/mouse.c +@@ -27,6 +27,8 @@ + #define HAVE_STDARG_H + #include <86box/86box.h> + #include <86box/device.h> ++#include <86box/timer.h> ++#include <86box/gdbstub.h> + #include <86box/mouse.h> + + typedef struct { +@@ -45,6 +47,8 @@ int mouse_x, + double mouse_x_abs, + mouse_y_abs; + ++pc_timer_t mouse_timer; /* mouse event timer */ ++ + static const device_t mouse_none_device = { + .name = "None", + .internal_name = "none", +@@ -141,6 +145,20 @@ mouse_close(void) + mouse_priv = NULL; + mouse_nbut = 0; + mouse_dev_poll = NULL; ++ ++ timer_stop(&mouse_timer); ++} ++ ++static void ++mouse_timer_poll(void *priv) ++{ ++ // timer_on_auto(&mouse_timer, 1388.0 + (8.0 / 9.0)); ++ timer_on_auto(&mouse_timer, 277.0 + (7.0 / 9.0)); ++ ++#ifdef USE_GDBSTUB /* avoid a KBC FIFO overflow when CPU emulation is stalled */ ++ if (gdbstub_step == GDBSTUB_EXEC) ++#endif ++ mouse_process(); + } + + void +@@ -165,6 +183,9 @@ mouse_reset(void) + + if (mouse_curr != NULL) + mouse_priv = device_add(mouse_curr); ++ ++ timer_add(&mouse_timer, mouse_timer_poll, NULL, 0); ++ timer_on_auto(&mouse_timer, 10000.0); + } + + /* Callback from the hardware driver. */ diff --git a/src/pic - Cópia.c b/src/pic - Cópia.c new file mode 100644 index 000000000..70a8a7805 --- /dev/null +++ b/src/pic - Cópia.c @@ -0,0 +1,838 @@ +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * This file is part of the 86Box distribution. + * + * Implementation of the Intel PIC chip emulation, partially + * ported from reenigne's XTCE. + * + * + * + * Authors: Andrew Jenner, + * Miran Grca, + * + * Copyright 2015-2020 Andrew Jenner. + * Copyright 2016-2020 Miran Grca. + */ +#include +#include +#include +#include +#include +#include + +#define HAVE_STDARG_H +#include <86box/86box.h> +#include "cpu.h" +#include <86box/machine.h> +#include <86box/io.h> +#include <86box/pci.h> +#include <86box/pic.h> +#include <86box/timer.h> +#include <86box/pit.h> +#include <86box/device.h> +#include <86box/apm.h> +#include <86box/nvr.h> +#include <86box/acpi.h> + +enum { + STATE_NONE = 0, + STATE_ICW2, + STATE_ICW3, + STATE_ICW4 +}; + +pic_t pic, pic2; + +static pc_timer_t pic_timer; + +static int shadow = 0, elcr_enabled = 0, + tmr_inited = 0, latched = 0, + pic_pci = 0, kbd_latch = 0, + mouse_latch = 0; + +static uint16_t smi_irq_mask = 0x0000, + smi_irq_status = 0x0000; + +static uint16_t latched_irqs = 0x0000; + +static void (*update_pending)(void); + +#ifdef ENABLE_PIC_LOG +int pic_do_log = ENABLE_PIC_LOG; + +static void +pic_log(const char *fmt, ...) +{ + va_list ap; + + if (pic_do_log) { + va_start(ap, fmt); + pclog_ex(fmt, ap); + va_end(ap); + } +} +#else +# define pic_log(fmt, ...) +#endif + +void +pic_reset_smi_irq_mask(void) +{ + smi_irq_mask = 0x0000; +} + +void +pic_set_smi_irq_mask(int irq, int set) +{ + if ((irq >= 0) && (irq <= 15)) { + if (set) + smi_irq_mask |= (1 << irq); + else + smi_irq_mask &= ~(1 << irq); + } +} + +uint16_t +pic_get_smi_irq_status(void) +{ + return smi_irq_status; +} + +void +pic_clear_smi_irq_status(int irq) +{ + if ((irq >= 0) && (irq <= 15)) + smi_irq_status &= ~(1 << irq); +} + +void +pic_elcr_write(uint16_t port, uint8_t val, void *priv) +{ + pic_t *dev = (pic_t *) priv; + + pic_log("ELCR%i: WRITE %02X\n", port & 1, val); + + if (port & 1) + val &= 0xde; + else + val &= 0xf8; + + dev->elcr = val; + + pic_log("ELCR %i: %c %c %c %c %c %c %c %c\n", + port & 1, + (val & 1) ? 'L' : 'E', + (val & 2) ? 'L' : 'E', + (val & 4) ? 'L' : 'E', + (val & 8) ? 'L' : 'E', + (val & 0x10) ? 'L' : 'E', + (val & 0x20) ? 'L' : 'E', + (val & 0x40) ? 'L' : 'E', + (val & 0x80) ? 'L' : 'E'); +} + +uint8_t +pic_elcr_read(uint16_t port, void *priv) +{ + pic_t *dev = (pic_t *) priv; + + pic_log("ELCR%i: READ %02X\n", port & 1, dev->elcr); + + return dev->elcr; +} + +int +pic_elcr_get_enabled(void) +{ + return elcr_enabled; +} + +void +pic_elcr_set_enabled(int enabled) +{ + elcr_enabled = enabled; +} + +void +pic_elcr_io_handler(int set) +{ + io_handler(set, 0x04d0, 0x0001, + pic_elcr_read, NULL, NULL, + pic_elcr_write, NULL, NULL, &pic); + io_handler(set, 0x04d1, 0x0001, + pic_elcr_read, NULL, NULL, + pic_elcr_write, NULL, NULL, &pic2); +} + +static uint8_t +pic_cascade_mode(pic_t *dev) +{ + return !(dev->icw1 & 2); +} + +static __inline uint8_t +pic_slave_on(pic_t *dev, int channel) +{ + pic_log("pic_slave_on(%i): %i, %02X, %02X\n", channel, pic_cascade_mode(dev), dev->icw4 & 0x0c, dev->icw3 & (1 << channel)); + + return pic_cascade_mode(dev) && (dev->is_master || ((dev->icw4 & 0x0c) == 0x0c)) && (dev->icw3 & (1 << channel)); +} + +static __inline int +find_best_interrupt(pic_t *dev) +{ + uint8_t b; + uint8_t intr; + int i, j; + int ret = -1; + + for (i = 0; i < 8; i++) { + j = (i + dev->priority) & 7; + b = 1 << j; + + if (dev->isr & b) + break; + else if ((dev->state == 0) && ((dev->irr & ~dev->imr) & b)) { + ret = j; + break; + } + } + + intr = dev->interrupt = (ret == -1) ? 0x17 : ret; + + if (dev->at && (ret != -1)) { + if (dev == &pic2) + intr += 8; + + if (cpu_fast_off_flags & (1u << intr)) + cpu_fast_off_advance(); + } + + return ret; +} + +static __inline void +pic_update_pending_xt(void) +{ + if (find_best_interrupt(&pic) != -1) { + latched++; + if (latched == 1) + timer_on_auto(&pic_timer, 0.35); + } else if (latched == 0) + pic.int_pending = 0; +} + +static __inline void +pic_update_pending_at(void) +{ + pic2.int_pending = (find_best_interrupt(&pic2) != -1); + + if (pic2.int_pending) + pic.irr |= (1 << pic2.icw3); + else + pic.irr &= ~(1 << pic2.icw3); + + pic.int_pending = (find_best_interrupt(&pic) != -1); +} + +static void +pic_callback(void *priv) +{ + pic_t *dev = (pic_t *) priv; + + dev->int_pending = 1; + + latched--; + if (latched > 0) + timer_on_auto(&pic_timer, 0.35); +} + +void +pic_reset(void) +{ + int is_at = IS_AT(machine); + is_at = is_at || !strcmp(machine_get_internal_name(), "xi8088"); + + memset(&pic, 0, sizeof(pic_t)); + memset(&pic2, 0, sizeof(pic_t)); + + pic.is_master = 1; + pic.interrupt = pic2.interrupt = 0x17; + + if (is_at) + pic.slaves[2] = &pic2; + + if (tmr_inited) + timer_on_auto(&pic_timer, 0.0); + memset(&pic_timer, 0x00, sizeof(pc_timer_t)); + timer_add(&pic_timer, pic_callback, &pic, 0); + tmr_inited = 1; + + update_pending = is_at ? pic_update_pending_at : pic_update_pending_xt; + pic.at = pic2.at = is_at; + + smi_irq_mask = smi_irq_status = 0x0000; + + shadow = 0; + pic_pci = 0; +} + +void +pic_set_shadow(int sh) +{ + shadow = sh; +} + +int +pic_get_pci_flag(void) +{ + return pic_pci; +} + +void +pic_set_pci_flag(int pci) +{ + pic_pci = pci; +} + +static uint8_t +pic_level_triggered(pic_t *dev, int irq) +{ + if (elcr_enabled) + return !!(dev->elcr & (1 << irq)); + else + return !!(dev->icw1 & 8); +} + +int +picint_is_level(int irq) +{ + return pic_level_triggered(((irq > 7) ? &pic2 : &pic), irq & 7); +} + +static void +pic_acknowledge(pic_t *dev) +{ + int pic_int = dev->interrupt & 7; + int pic_int_num = 1 << pic_int; + + dev->isr |= pic_int_num; + if (!pic_level_triggered(dev, pic_int) || !(dev->lines & pic_int_num)) + dev->irr &= ~pic_int_num; +} + +/* Find IRQ for non-specific EOI (either by command or automatic) by finding the highest IRQ + priority with ISR bit set, that is also not masked if the PIC is in special mask mode. */ +static uint8_t +pic_non_specific_find(pic_t *dev) +{ + int i, j; + uint8_t b, irq = 0xff; + + for (i = 0; i < 8; i++) { + j = (i + dev->priority) & 7; + b = (1 << j); + + if ((dev->isr & b) && (!dev->special_mask_mode || !(dev->imr & b))) { + irq = j; + break; + } + } + + return irq; +} + +/* Do the EOI and rotation, if either is requested, on the given IRQ. */ +static void +pic_action(pic_t *dev, uint8_t irq, uint8_t eoi, uint8_t rotate) +{ + uint8_t b = (1 << irq); + + if (irq != 0xff) { + if (eoi) + dev->isr &= ~b; + if (rotate) + dev->priority = (irq + 1) & 7; + + update_pending(); + } +} + +/* Automatic non-specific EOI. */ +static __inline void +pic_auto_non_specific_eoi(pic_t *dev) +{ + uint8_t irq; + + if (dev->icw4 & 2) { + irq = pic_non_specific_find(dev); + + pic_action(dev, irq, 1, dev->auto_eoi_rotate); + } +} + +/* Do the PIC command specified by bits 7-5 of the value written to the OCW2 register. */ +static void +pic_command(pic_t *dev) +{ + uint8_t irq = 0xff; + + if (dev->ocw2 & 0x60) { /* SL and/or EOI set */ + if (dev->ocw2 & 0x40) /* SL set, specific priority level */ + irq = (dev->ocw2 & 0x07); + else /* SL clear, non-specific priority level (find highest with ISR set) */ + irq = pic_non_specific_find(dev); + + pic_action(dev, irq, dev->ocw2 & 0x20, dev->ocw2 & 0x80); + } else /* SL and EOI clear */ + dev->auto_eoi_rotate = !!(dev->ocw2 & 0x80); +} + +uint8_t +pic_latch_read(uint16_t addr, void *priv) +{ + uint8_t ret = 0xff; + + pic_log("pic_latch_read(%i, %i): %02X%02X\n", kbd_latch, mouse_latch, pic2.lines & 0x10, pic.lines & 0x02); + + if (kbd_latch && (latched_irqs & 0x0002)) + picintc(0x0002); + + if (mouse_latch && (latched_irqs & 0x1000)) + picintc(0x1000); + + /* Return FF - we just lower IRQ 1 and IRQ 12. */ + return ret; +} + +uint8_t +pic_read(uint16_t addr, void *priv) +{ + pic_t *dev = (pic_t *) priv; + + if (shadow) { + /* VIA PIC shadow read */ + if (addr & 0x0001) + dev->data_bus = ((dev->icw2 & 0xf8) >> 3) << 0; + else { + dev->data_bus = ((dev->ocw3 & 0x20) >> 5) << 4; + dev->data_bus |= ((dev->ocw2 & 0x80) >> 7) << 3; + dev->data_bus |= ((dev->icw4 & 0x10) >> 4) << 2; + dev->data_bus |= ((dev->icw4 & 0x02) >> 1) << 1; + dev->data_bus |= ((dev->icw4 & 0x08) >> 3) << 0; + } + } else { + /* Standard 8259 PIC read */ +#ifndef UNDEFINED_READ + /* Put the IRR on to the data bus by default until the real PIC is probed. */ + dev->data_bus = dev->irr; +#endif + if (dev->ocw3 & 0x04) { + dev->interrupt &= ~0x20; /* Freeze the interrupt until the poll is over. */ + if (dev->int_pending) { + dev->data_bus = 0x80 | (dev->interrupt & 7); + pic_acknowledge(dev); + dev->int_pending = 0; + update_pending(); + } else + dev->data_bus = 0x00; + dev->ocw3 &= ~0x04; + } else if (addr & 0x0001) + dev->data_bus = dev->imr; + else if (dev->ocw3 & 0x02) { + if (dev->ocw3 & 0x01) + dev->data_bus = dev->isr; +#ifdef UNDEFINED_READ + else + dev->data_bus = 0x00; +#endif + } + /* If A0 = 0, VIA shadow is disabled, and poll mode is disabled, + simply read whatever is currently on the data bus. */ + } + + pic_log("pic_read(%04X, %08X) = %02X\n", addr, priv, dev->data_bus); + + return dev->data_bus; +} + +static void +pic_write(uint16_t addr, uint8_t val, void *priv) +{ + pic_t *dev = (pic_t *) priv; + + pic_log("pic_write(%04X, %02X, %08X)\n", addr, val, priv); + + dev->data_bus = val; + + if (addr & 0x0001) { + switch (dev->state) { + case STATE_ICW2: + dev->icw2 = val; + if (pic_cascade_mode(dev)) + dev->state = STATE_ICW3; + else + dev->state = (dev->icw1 & 1) ? STATE_ICW4 : STATE_NONE; + break; + case STATE_ICW3: + dev->icw3 = val; + dev->state = (dev->icw1 & 1) ? STATE_ICW4 : STATE_NONE; + break; + case STATE_ICW4: + dev->icw4 = val; + dev->state = STATE_NONE; + break; + case STATE_NONE: + dev->imr = val; + update_pending(); + break; + } + } else { + if (val & 0x10) { + /* Treat any write with any of the bits 7 to 5 set as invalid if PCI. */ + if (pic_pci && (val & 0xe0)) + return; + + dev->icw1 = val; + dev->icw2 = dev->icw3 = 0x00; + if (!(dev->icw1 & 1)) + dev->icw4 = 0x00; + dev->ocw2 = dev->ocw3 = 0x00; + dev->irr = dev->lines; + dev->imr = dev->isr = 0x00; + dev->ack_bytes = dev->priority = 0x00; + dev->auto_eoi_rotate = dev->special_mask_mode = 0x00; + dev->interrupt = 0x17; + dev->int_pending = 0x00; + dev->state = STATE_ICW2; + update_pending(); + } else if (val & 0x08) { + dev->ocw3 = val; + if (dev->ocw3 & 0x04) + dev->interrupt |= 0x20; /* Freeze the interrupt until the poll is over. */ + if (dev->ocw3 & 0x40) + dev->special_mask_mode = !!(dev->ocw3 & 0x20); + } else { + dev->ocw2 = val; + pic_command(dev); + } + } +} + +void +pic_set_pci(void) +{ + int i; + + for (i = 0x0024; i < 0x0040; i += 4) { + io_sethandler(i, 0x0002, pic_read, NULL, NULL, pic_write, NULL, NULL, &pic); + io_sethandler(i + 0x0080, 0x0002, pic_read, NULL, NULL, pic_write, NULL, NULL, &pic2); + } + + for (i = 0x1120; i < 0x1140; i += 4) { + io_sethandler(i, 0x0002, pic_read, NULL, NULL, pic_write, NULL, NULL, &pic); + io_sethandler(i + 0x0080, 0x0002, pic_read, NULL, NULL, pic_write, NULL, NULL, &pic2); + } +} + +void +pic_kbd_latch(int enable) +{ + pic_log("PIC keyboard latch now %sabled\n", enable ? "en" : "dis"); + + if (!!(enable | mouse_latch) != !!(kbd_latch | mouse_latch)) + io_handler(!!(enable | mouse_latch), 0x0060, 0x0001, pic_latch_read, NULL, NULL, NULL, NULL, NULL, NULL); + + kbd_latch = !!enable; + + if (!enable) + picintc(0x0002); +} + +void +pic_mouse_latch(int enable) +{ + pic_log("PIC mouse latch now %sabled\n", enable ? "en" : "dis"); + + if (!!(kbd_latch | enable) != !!(kbd_latch | mouse_latch)) + io_handler(!!(kbd_latch | enable), 0x0060, 0x0001, pic_latch_read, NULL, NULL, NULL, NULL, NULL, NULL); + + mouse_latch = !!enable; + + if (!enable) + picintc(0x1000); +} + +static void +pic_reset_hard(void) +{ + pic_reset(); + + /* Explicitly reset the latches. */ + kbd_latch = mouse_latch = 0; + + /* The situation is as follows: There is a giant mess when it comes to these latches on real hardware, + to the point that there's even boards with board-level latched that get used in place of the latches + on the chipset, therefore, I'm just doing this here for the sake of simplicity. */ + if (machine_has_bus(machine, MACHINE_BUS_PS2)) { + pic_kbd_latch(0x01); + pic_mouse_latch(0x01); + } else { + pic_kbd_latch(0x00); + pic_mouse_latch(0x00); + } +} + +void +pic_init(void) +{ + pic_reset_hard(); + + shadow = 0; + io_sethandler(0x0020, 0x0002, pic_read, NULL, NULL, pic_write, NULL, NULL, &pic); +} + +void +pic_init_pcjr(void) +{ + pic_reset_hard(); + + shadow = 0; + io_sethandler(0x0020, 0x0008, pic_read, NULL, NULL, pic_write, NULL, NULL, &pic); +} + +void +pic2_init(void) +{ + io_sethandler(0x00a0, 0x0002, pic_read, NULL, NULL, pic_write, NULL, NULL, &pic2); + pic.slaves[2] = &pic2; +} + +void +picint_common(uint16_t num, int level, int set) +{ + int i, raise; + uint8_t b, slaves = 0; + + /* Make sure to ignore all slave IRQ's, and in case of AT+, + translate IRQ 2 to IRQ 9. */ + for (i = 0; i < 8; i++) { + b = (1 << i); + raise = num & b; + + if (pic.icw3 & b) { + slaves++; + + if (raise) { + num &= ~b; + if (pic.at && (i == 2)) + num |= (1 << 9); + } + } + } + + if (!slaves) + num &= 0x00ff; + + if (!num) { + pic_log("Attempting to %s null IRQ\n", set ? "raise" : "lower"); + return; + } + + if (num & 0x0100) + acpi_rtc_status = !!set; + + if (set) { + if (smi_irq_mask & num) { + smi_raise(); + smi_irq_status |= num; + } + + if (num & 0xff00) { + if (level) + pic2.lines |= (num >> 8); + + /* Latch IRQ 12 if the mouse latch is enabled. */ + if ((num & 0x1000) && mouse_latch) + latched_irqs |= 0x1000; + + pic2.irr |= (num >> 8); + } + + if (num & 0x00ff) { + if (level) + pic.lines |= (num & 0x00ff); + + /* Latch IRQ 1 if the keyboard latch is enabled. */ + if (kbd_latch && (num & 0x0002)) + latched_irqs |= 0x0002; + + pic.irr |= (num & 0x00ff); + } + } else { + smi_irq_status &= ~num; + + if (num & 0xff00) { + pic2.lines &= ~(num >> 8); + + /* Unlatch IRQ 12 if the mouse latch is enabled. */ + if ((num & 0x1000) && mouse_latch) + latched_irqs &= 0xefff; + + pic2.irr &= ~(num >> 8); + } + + if (num & 0x00ff) { + pic.lines &= ~(num & 0x00ff); + + /* Unlatch IRQ 1 if the keyboard latch is enabled. */ + if (kbd_latch && (num & 0x0002)) + latched_irqs &= 0xfffd; + + pic.irr &= ~(num & 0x00ff); + } + } + + if (!(pic.interrupt & 0x20) && !(pic2.interrupt & 0x20)) + update_pending(); +} + +void +picint(uint16_t num) +{ + picint_common(num, 0, 1); +} + +void +picintlevel(uint16_t num) +{ + picint_common(num, 1, 1); +} + +void +picintc(uint16_t num) +{ + picint_common(num, 0, 0); +} + +static uint8_t +pic_i86_mode(pic_t *dev) +{ + return !!(dev->icw4 & 1); +} + +static uint8_t +pic_irq_ack_read(pic_t *dev, int phase) +{ + uint8_t intr = dev->interrupt & 0x47; + uint8_t slave = intr & 0x40; + intr &= 0x07; + pic_log(" pic_irq_ack_read(%08X, %i)\n", dev, phase); + + if (dev != NULL) { + if (phase == 0) { + dev->interrupt |= 0x20; /* Freeze it so it still takes interrupts but they do not + override the one currently being processed. */ + pic_acknowledge(dev); + if (slave) + dev->data_bus = pic_irq_ack_read(dev->slaves[intr], phase); + else + dev->data_bus = pic_i86_mode(dev) ? 0xff : 0xcd; + } else if (pic_i86_mode(dev)) { + dev->int_pending = 0; + if (slave) + dev->data_bus = pic_irq_ack_read(dev->slaves[intr], phase); + else + dev->data_bus = intr + (dev->icw2 & 0xf8); + pic_auto_non_specific_eoi(dev); + } else if (phase == 1) { + if (slave) + dev->data_bus = pic_irq_ack_read(dev->slaves[intr], phase); + else if (dev->icw1 & 0x04) + dev->data_bus = (intr << 2) + (dev->icw1 & 0xe0); + else + dev->data_bus = (intr << 3) + (dev->icw1 & 0xc0); + } else if (phase == 2) { + dev->int_pending = 0; + if (slave) + dev->data_bus = pic_irq_ack_read(dev->slaves[intr], phase); + else + dev->data_bus = dev->icw2; + pic_auto_non_specific_eoi(dev); + } + } + + return dev->data_bus; +} + +uint8_t +pic_irq_ack(void) +{ + int ret; + + /* Needed for Xi8088. */ + if ((pic.ack_bytes == 0) && pic.int_pending && pic_slave_on(&pic, pic.interrupt)) { + if (!pic.slaves[pic.interrupt]->int_pending) { + /* If we are on AT, IRQ 2 is pending, and we cannot find a pending IRQ on PIC 2, fatal out. */ + fatal("IRQ %i pending on AT without a pending IRQ on PIC %i (normal)\n", pic.interrupt, pic.interrupt); + exit(-1); + return -1; + } + + pic.interrupt |= 0x40; /* Mark slave pending. */ + } + + ret = pic_irq_ack_read(&pic, pic.ack_bytes); + pic.ack_bytes = (pic.ack_bytes + 1) % (pic_i86_mode(&pic) ? 2 : 3); + + if (pic.ack_bytes == 0) { + /* Needed for Xi8088. */ + if (pic.interrupt & 0x40) + pic2.interrupt = 0x17; + pic.interrupt = 0x17; + update_pending(); + } + + return ret; +} + +int +picinterrupt(void) +{ + int i, ret = -1; + + if (pic.int_pending) { + if (pic_slave_on(&pic, pic.interrupt)) { + if (!pic.slaves[pic.interrupt]->int_pending) { + /* If we are on AT, IRQ 2 is pending, and we cannot find a pending IRQ on PIC 2, fatal out. */ + fatal("IRQ %i pending on AT without a pending IRQ on PIC %i (normal)\n", pic.interrupt, pic.interrupt); + exit(-1); + return -1; + } + + pic.interrupt |= 0x40; /* Mark slave pending. */ + } + + if ((pic.interrupt == 0) && (pit_devs[1].data != NULL)) + pit_devs[1].set_gate(pit_devs[1].data, 0, 0); + + /* Two ACK's - do them in a loop to avoid potential compiler misoptimizations. */ + for (i = 0; i < 2; i++) { + ret = pic_irq_ack_read(&pic, pic.ack_bytes); + pic.ack_bytes = (pic.ack_bytes + 1) % (pic_i86_mode(&pic) ? 2 : 3); + + if (pic.ack_bytes == 0) { + if (pic.interrupt & 0x40) + pic2.interrupt = 0x17; + pic.interrupt = 0x17; + update_pending(); + } + } + } + + return ret; +} diff --git a/src/usb.c b/src/usb.c index f0c7113b7..e45f82ae8 100644 --- a/src/usb.c +++ b/src/usb.c @@ -51,30 +51,58 @@ usb_log(const char *fmt, ...) /* OHCI registers */ enum { - OHCI_HcRevision = 0x00, - OHCI_HcControl = 0x04, - OHCI_HcCommandStatus = 0x08, - OHCI_HcInterruptStatus = 0x0C, - OHCI_HcInterruptEnable = 0x10, - OHCI_HcInterruptDisable = 0x14, - OHCI_HcHCCA = 0x18, - OHCI_HcPeriodCurrentED = 0x1C, - OHCI_HcControlHeadED = 0x20, - OHCI_HcControlCurrentED = 0x24, - OHCI_HcBulkHeadED = 0x28, - OHCI_HcBulkCurrentED = 0x2C, - OHCI_HcDoneHead = 0x30, - OHCI_HcFmInterval = 0x34, - OHCI_HcFmRemaining = 0x38, - OHCI_HcFmNumber = 0x3C, - OHCI_HcPeriodicStart = 0x40, - OHCI_HcLSThreshold = 0x44, - OHCI_HcRhDescriptorA = 0x48, - OHCI_HcRhDescriptorB = 0x4C, - OHCI_HcRhStatus = 0x50, - OHCI_HcRhPortStatus1 = 0x54, - OHCI_HcRhPortStatus2 = 0x58, - OHCI_HcRhPortStatus3 = 0x5C + OHCI_HcRevision = 0x00 /* 0x00 */, + OHCI_HcControl = 0x01 /* 0x04 */, + OHCI_HcCommandStatus = 0x02 /* 0x08 */, + OHCI_HcInterruptStatus = 0x03 /* 0x0c */, + OHCI_HcInterruptEnable = 0x04 /* 0x10 */, + OHCI_HcInterruptDisable = 0x05 /* 0x14 */, + OHCI_HcHCCA = 0x06 /* 0x18 */, + OHCI_HcPeriodCurrentED = 0x07 /* 0x1c */, + OHCI_HcControlHeadED = 0x08 /* 0x20 */, + OHCI_HcControlCurrentED = 0x09 /* 0x24 */, + OHCI_HcBulkHeadED = 0x0a /* 0x28 */, + OHCI_HcBulkCurrentED = 0x0b /* 0x2c */, + OHCI_HcDoneHead = 0x0c /* 0x30 */, + OHCI_HcFmInterval = 0x0d /* 0x34 */, + OHCI_HcFmRemaining = 0x0e /* 0x38 */, + OHCI_HcFmNumber = 0x0f /* 0x3c */, + OHCI_HcPeriodicStart = 0x10 /* 0x40 */, + OHCI_HcLSThreshold = 0x11 /* 0x44 */, + OHCI_HcRhDescriptorA = 0x12 /* 0x48 */, + OHCI_HcRhDescriptorB = 0x13 /* 0x4c */, + OHCI_HcRhStatus = 0x14 /* 0x50 */, + OHCI_HcRhPortStatus1 = 0x15 /* 0x54 */, + OHCI_HcRhPortStatus2 = 0x16 /* 0x58 */, + OHCI_HcRhPortStatus3 = 0x17 /* 0x5c */ +}; + +enum +{ + OHCI_aHcRevision = 0x00, + OHCI_aHcControl = 0x04, + OHCI_aHcCommandStatus = 0x08, + OHCI_aHcInterruptStatus = 0x0c, + OHCI_aHcInterruptEnable = 0x10, + OHCI_aHcInterruptDisable = 0x14, + OHCI_aHcHCCA = 0x18, + OHCI_aHcPeriodCurrentED = 0x1c, + OHCI_aHcControlHeadED = 0x20, + OHCI_aHcControlCurrentED = 0x24, + OHCI_aHcBulkHeadED = 0x28, + OHCI_aHcBulkCurrentED = 0x2c, + OHCI_aHcDoneHead = 0x30, + OHCI_aHcFmInterval = 0x34, + OHCI_aHcFmRemaining = 0x38, + OHCI_aHcFmNumber = 0x3c, + OHCI_aHcPeriodicStart = 0x40, + OHCI_aHcLSThreshold = 0x44, + OHCI_aHcRhDescriptorA = 0x48, + OHCI_aHcRhDescriptorB = 0x4c, + OHCI_aHcRhStatus = 0x50, + OHCI_aHcRhPortStatus1 = 0x54, + OHCI_aHcRhPortStatus2 = 0x58, + OHCI_aHcRhPortStatus3 = 0x5c }; /* OHCI HcInterruptEnable/Disable bits */ @@ -90,18 +118,17 @@ enum }; static void -usb_interrupt_ohci(usb_t* usb) +usb_interrupt_ohci(usb_t *dev, uint32_t level) { - if (usb->ohci_mmio[OHCI_HcControl + 1] & 1) { - if (usb->usb_params && usb->usb_params->smi_handle && !usb->usb_params->smi_handle(usb, usb->usb_params->parent_priv)) + if (dev->ohci_mmio[OHCI_HcControl].b[1] & 1) { + if (dev->usb_params && dev->usb_params->smi_handle && !dev->usb_params->smi_handle(dev, dev->usb_params->parent_priv)) return; - smi_raise(); - } - else if (usb->usb_params != NULL) { - if (usb->usb_params->parent_priv != NULL && usb->usb_params->raise_interrupt != NULL) { - usb->usb_params->raise_interrupt(usb, usb->usb_params->parent_priv); - } + if (level) + smi_raise(); + } else if (dev->usb_params != NULL) { + if ((dev->usb_params->parent_priv != NULL) && (dev->usb_params->update_interrupt != NULL)) + dev->usb_params->update_interrupt(dev, dev->usb_params->parent_priv); } } @@ -194,26 +221,28 @@ ohci_mmio_read(uint32_t addr, void *p) { usb_t *dev = (usb_t *) p; uint8_t ret = 0x00; +#ifdef ENABLE_USB_LOG + uint32_t old_addr = addr; +#endif addr &= 0x00000fff; - ret = dev->ohci_mmio[addr]; + ret = dev->ohci_mmio[addr >> 2].b[addr & 3]; switch (addr) { case 0x101: ret = (ret & 0xfe) | (!!mem_a20_key); break; - case OHCI_HcRhPortStatus1 + 1: - case OHCI_HcRhPortStatus2 + 1: - case OHCI_HcRhPortStatus3 + 1: + case OHCI_aHcRhPortStatus1 + 1: + case OHCI_aHcRhPortStatus2 + 1: + case OHCI_aHcRhPortStatus3 + 1: ret |= 0x1; break; - case OHCI_HcInterruptDisable: - case OHCI_HcInterruptDisable + 1: - case OHCI_HcInterruptDisable + 2: - case OHCI_HcInterruptDisable + 3: - ret = dev->ohci_mmio[OHCI_HcInterruptEnable + (addr - OHCI_HcInterruptDisable)]; - break; + case OHCI_aHcInterruptDisable: + case OHCI_aHcInterruptDisable + 1: + case OHCI_aHcInterruptDisable + 2: + case OHCI_aHcInterruptDisable + 3: + ret = dev->ohci_mmio[OHCI_HcInterruptEnable].b[addr & 3]; default: break; } @@ -221,30 +250,58 @@ ohci_mmio_read(uint32_t addr, void *p) if (addr == 0x101) ret = (ret & 0xfe) | (!!mem_a20_key); +#ifdef ENABLE_USB_LOG + usb_log("[R] %08X = %04X\n", old_addr, ret); +#endif + return ret; } -void -ohci_set_interrupt(usb_t* usb, uint8_t bit) +static uint16_t +ohci_mmio_readw(uint32_t addr, void *p) { - if (!(usb->ohci_mmio[OHCI_HcInterruptEnable + 3] & 0x80)) + return ohci_mmio_read(addr, p) | (ohci_mmio_read(addr + 1, p) << 8); +} + +static uint32_t +ohci_mmio_readl(uint32_t addr, void *p) +{ + return ohci_mmio_readw(addr, p) | (ohci_mmio_readw(addr + 2, p) << 16); +} + +static void +ohci_update_irq(usb_t *dev) +{ + uint32_t level = !!(dev->ohci_mmio[OHCI_HcInterruptStatus].l & dev->ohci_mmio[OHCI_HcInterruptEnable].l); + + if (level != dev->irq_level) { + dev->irq_level = level; + usb_interrupt_ohci(dev, level); + } +} + +void +ohci_set_interrupt(usb_t *dev, uint8_t bit) +{ + if (!(dev->ohci_mmio[OHCI_HcInterruptEnable].b[3] & 0x80)) return; - if (!(usb->ohci_mmio[OHCI_HcInterruptEnable] & bit)) + if (!(dev->ohci_mmio[OHCI_HcInterruptEnable].b[0] & bit)) return; - if (usb->ohci_mmio[OHCI_HcInterruptDisable] & bit) + if (dev->ohci_mmio[OHCI_HcInterruptDisable].b[0] & bit) return; - usb->ohci_mmio[OHCI_HcInterruptStatus] |= bit; - usb_interrupt_ohci(usb); + dev->ohci_mmio[OHCI_HcInterruptStatus].b[0] |= bit; + + ohci_update_irq(dev); } void ohci_end_of_frame(usb_t* dev) { /* TODO: Put endpoint and transfer descriptor processing here. */ - dev->ohci_mmio_w[OHCI_HcFmNumber / 2]++; + dev->ohci_mmio[OHCI_HcFmNumber].w[0]++; } void @@ -258,17 +315,17 @@ ohci_update_frame_counter(void* priv) { usb_t *dev = (usb_t *) priv; - dev->ohci_mmio_w[OHCI_HcFmRemaining / 2] &= 0x3fff; - if (dev->ohci_mmio_w[OHCI_HcFmRemaining / 2] == 0) { + dev->ohci_mmio[OHCI_HcFmRemaining].w[0] &= 0x3fff; + if (dev->ohci_mmio[OHCI_HcFmRemaining].w[0] == 0) { ohci_end_of_frame(dev); - dev->ohci_mmio_w[OHCI_HcFmRemaining / 2] = dev->ohci_mmio_w[OHCI_HcFmInterval / 2] & 0x3fff; - dev->ohci_mmio_l[OHCI_HcFmRemaining / 4] &= ~(1 << 31); - dev->ohci_mmio_l[OHCI_HcFmRemaining / 4] |= dev->ohci_mmio_l[OHCI_HcFmInterval / 4] & (1 << 31); + dev->ohci_mmio[OHCI_HcFmRemaining].w[0] = dev->ohci_mmio[OHCI_HcFmInterval].w[0] & 0x3fff; + dev->ohci_mmio[OHCI_HcFmRemaining].l &= ~(1 << 31); + dev->ohci_mmio[OHCI_HcFmRemaining].l |= dev->ohci_mmio[OHCI_HcFmInterval].l & (1 << 31); ohci_start_of_frame(dev); timer_on_auto(&dev->ohci_frame_timer, 1. / (12. * 1000. * 1000.)); return; } - if (dev->ohci_mmio_w[OHCI_HcFmRemaining / 2]) dev->ohci_mmio_w[OHCI_HcFmRemaining / 2]--; + if (dev->ohci_mmio[OHCI_HcFmRemaining].w[0]) dev->ohci_mmio[OHCI_HcFmRemaining].w[0]--; timer_on_auto(&dev->ohci_frame_timer, 1. / (12. * 1000. * 1000.)); } @@ -288,8 +345,8 @@ ohci_port_reset_callback(void* priv) { usb_t *dev = (usb_t *) priv; - dev->ohci_mmio[OHCI_HcRhPortStatus1] &= ~0x10; - dev->ohci_mmio[OHCI_HcRhPortStatus1 + 2] |= 0x10; + dev->ohci_mmio[OHCI_HcRhPortStatus1].b[0] &= ~0x10; + dev->ohci_mmio[OHCI_HcRhPortStatus1].b[2] |= 0x10; } void @@ -297,244 +354,260 @@ ohci_port_reset_callback_2(void* priv) { usb_t *dev = (usb_t *) priv; - dev->ohci_mmio[OHCI_HcRhPortStatus2] &= ~0x10; - dev->ohci_mmio[OHCI_HcRhPortStatus2 + 2] |= 0x10; + dev->ohci_mmio[OHCI_HcRhPortStatus2].b[0] &= ~0x10; + dev->ohci_mmio[OHCI_HcRhPortStatus2].b[2] |= 0x10; } + static void ohci_mmio_write(uint32_t addr, uint8_t val, void *p) { usb_t *dev = (usb_t *) p; uint8_t old; +#ifdef ENABLE_USB_LOG + usb_log("[W] %08X = %04X\n", addr, val); +#endif + addr &= 0x00000fff; switch (addr) { - case OHCI_HcControl: + case OHCI_aHcControl: if ((val & 0xc0) == 0x00) { /* UsbReset */ - dev->ohci_mmio[OHCI_HcRhPortStatus1 + 2] = dev->ohci_mmio[OHCI_HcRhPortStatus2 + 2] = 0x16; + dev->ohci_mmio[OHCI_HcRhPortStatus1].b[2] = dev->ohci_mmio[OHCI_HcRhPortStatus2].b[2] = 0x16; } break; - case OHCI_HcCommandStatus: + case OHCI_aHcCommandStatus: /* bit OwnershipChangeRequest triggers an ownership change (SMM <-> OS) */ if (val & 0x08) { - dev->ohci_mmio[OHCI_HcInterruptStatus + 3] = 0x40; - if ((dev->ohci_mmio[OHCI_HcInterruptEnable + 3] & 0xc0) == 0xc0) + dev->ohci_mmio[OHCI_HcInterruptStatus].b[3] = 0x40; + if ((dev->ohci_mmio[OHCI_HcInterruptEnable].b[3] & 0xc0) == 0xc0) smi_raise(); } /* bit HostControllerReset must be cleared for the controller to be seen as initialized */ if (val & 0x01) { memset(dev->ohci_mmio, 0x00, 4096); - dev->ohci_mmio[OHCI_HcRevision] = 0x10; - dev->ohci_mmio[OHCI_HcRevision + 1] = 0x01; - dev->ohci_mmio[OHCI_HcRhDescriptorA] = 0x02; + dev->ohci_mmio[OHCI_HcRevision].b[0] = 0x10; + dev->ohci_mmio[OHCI_HcRevision].b[1] = 0x01; + dev->ohci_mmio[OHCI_HcRhDescriptorA].b[0] = 0x02; val &= ~0x01; } break; - case OHCI_HcHCCA: + case OHCI_aHcHCCA: return; - case OHCI_HcInterruptEnable: - dev->ohci_mmio[addr] = (val & 0x7f); - dev->ohci_mmio[OHCI_HcInterruptDisable] &= ~(val & 0x7f); + case OHCI_aHcInterruptEnable: + dev->ohci_mmio[addr >> 2].b[addr & 3] = (val & 0x7f); + dev->ohci_mmio[OHCI_HcInterruptDisable].b[0] &= ~(val & 0x7f); + ohci_update_irq(dev); return; - case OHCI_HcInterruptEnable + 1: - case OHCI_HcInterruptEnable + 2: + case OHCI_aHcInterruptEnable + 1: + case OHCI_aHcInterruptEnable + 2: return; - case OHCI_HcInterruptEnable + 3: - dev->ohci_mmio[addr] = (val & 0x40); - dev->ohci_mmio[addr] |= (val & 0x80); - if (val & 0x80) - dev->ohci_mmio[OHCI_HcInterruptDisable + 3] &= ~0x80; - if (val & 0x40) - dev->ohci_mmio[OHCI_HcInterruptDisable + 3] &= ~0x40; + case OHCI_aHcInterruptEnable + 3: + dev->ohci_mmio[addr >> 2].b[addr & 3] = (val & 0xc0); + dev->ohci_mmio[OHCI_HcInterruptDisable].b[3] &= ~(val & 0xc0); + ohci_update_irq(dev); return; - case OHCI_HcInterruptDisable: - dev->ohci_mmio[addr] = (val & 0x7f); - dev->ohci_mmio[OHCI_HcInterruptEnable] &= ~(val & 0x7f); + case OHCI_aHcInterruptDisable: + dev->ohci_mmio[addr >> 2].b[addr & 3] = (val & 0x7f); + dev->ohci_mmio[OHCI_HcInterruptEnable].b[0] &= ~(val & 0x7f); + ohci_update_irq(dev); return; - case OHCI_HcInterruptDisable + 1: - case OHCI_HcInterruptDisable + 2: + case OHCI_aHcInterruptDisable + 1: + case OHCI_aHcInterruptDisable + 2: return; - case OHCI_HcInterruptDisable + 3: - dev->ohci_mmio[addr] = (val & 0x40); - dev->ohci_mmio[addr] |= (val & 0x80); - if (val & 0x80) - dev->ohci_mmio[OHCI_HcInterruptEnable + 3] &= ~0x80; - if (val & 0x40) - dev->ohci_mmio[OHCI_HcInterruptEnable + 3] &= ~0x40; + case OHCI_aHcInterruptDisable + 3: + dev->ohci_mmio[addr >> 2].b[addr & 3] = (val & 0xc0); + dev->ohci_mmio[OHCI_HcInterruptEnable].b[3] &= ~(val & 0xc0); + ohci_update_irq(dev); return; - case OHCI_HcInterruptStatus: - dev->ohci_mmio[addr] &= ~(val & 0x7f); + case OHCI_aHcInterruptStatus: + dev->ohci_mmio[addr >> 2].b[addr & 3] &= ~(val & 0x7f); return; - case OHCI_HcInterruptStatus + 1: - case OHCI_HcInterruptStatus + 2: + case OHCI_aHcInterruptStatus + 1: + case OHCI_aHcInterruptStatus + 2: return; - case OHCI_HcInterruptStatus + 3: - dev->ohci_mmio[addr] &= ~(val & 0x40); + case OHCI_aHcInterruptStatus + 3: + dev->ohci_mmio[addr >> 2].b[addr & 3] &= ~(val & 0x40); return; - case OHCI_HcFmRemaining + 3: - dev->ohci_mmio[addr] = (val & 0x80); + case OHCI_aHcFmRemaining + 3: + dev->ohci_mmio[addr >> 2].b[addr & 3] = (val & 0x80); return; - case OHCI_HcFmRemaining + 1: - case OHCI_HcPeriodicStart + 1: - dev->ohci_mmio[addr] = (val & 0x3f); + case OHCI_aHcFmRemaining + 1: + case OHCI_aHcPeriodicStart + 1: + dev->ohci_mmio[addr >> 2].b[addr & 3] = (val & 0x3f); return; - case OHCI_HcLSThreshold + 1: - dev->ohci_mmio[addr] = (val & 0x0f); + case OHCI_aHcLSThreshold + 1: + dev->ohci_mmio[addr >> 2].b[addr & 3] = (val & 0x0f); return; - case OHCI_HcFmRemaining + 2: - case OHCI_HcFmNumber + 2: - case OHCI_HcFmNumber + 3: - case OHCI_HcPeriodicStart + 2: - case OHCI_HcPeriodicStart + 3: - case OHCI_HcLSThreshold + 2: - case OHCI_HcLSThreshold + 3: - case OHCI_HcRhDescriptorA: - case OHCI_HcRhDescriptorA + 2: + case OHCI_aHcFmRemaining + 2: + case OHCI_aHcFmNumber + 2: + case OHCI_aHcFmNumber + 3: + case OHCI_aHcPeriodicStart + 2: + case OHCI_aHcPeriodicStart + 3: + case OHCI_aHcLSThreshold + 2: + case OHCI_aHcLSThreshold + 3: + case OHCI_aHcRhDescriptorA: + case OHCI_aHcRhDescriptorA + 2: return; - case OHCI_HcRhDescriptorA + 1: - dev->ohci_mmio[addr] = (val & 0x1b); + case OHCI_aHcRhDescriptorA + 1: + dev->ohci_mmio[addr >> 2].b[addr & 3] = (val & 0x1b); if (val & 0x02) { - dev->ohci_mmio[OHCI_HcRhPortStatus1 + 1] |= 0x01; - dev->ohci_mmio[OHCI_HcRhPortStatus2 + 1] |= 0x01; + dev->ohci_mmio[OHCI_HcRhPortStatus1].b[1] |= 0x01; + dev->ohci_mmio[OHCI_HcRhPortStatus2].b[1] |= 0x01; } return; - case OHCI_HcRhDescriptorA + 3: - dev->ohci_mmio[addr] = (val & 0x03); + case OHCI_aHcRhDescriptorA + 3: + dev->ohci_mmio[addr >> 2].b[addr & 3] = (val & 0x03); return; - case OHCI_HcRhDescriptorB: - case OHCI_HcRhDescriptorB + 2: - dev->ohci_mmio[addr] = (val & 0x06); + case OHCI_aHcRhDescriptorB: + case OHCI_aHcRhDescriptorB + 2: + dev->ohci_mmio[addr >> 2].b[addr & 3] = (val & 0x06); if ((addr == OHCI_HcRhDescriptorB) && !(val & 0x04)) { - if (!(dev->ohci_mmio[OHCI_HcRhPortStatus2] & 0x01)) - dev->ohci_mmio[OHCI_HcRhPortStatus2 + 2] |= 0x01; - dev->ohci_mmio[OHCI_HcRhPortStatus2] |= 0x01; + if (!(dev->ohci_mmio[OHCI_HcRhPortStatus2].b[0] & 0x01)) + dev->ohci_mmio[OHCI_HcRhPortStatus2].b[2] |= 0x01; + dev->ohci_mmio[OHCI_HcRhPortStatus2].b[0] |= 0x01; } if ((addr == OHCI_HcRhDescriptorB) && !(val & 0x02)) { - if (!(dev->ohci_mmio[OHCI_HcRhPortStatus1] & 0x01)) - dev->ohci_mmio[OHCI_HcRhPortStatus1 + 2] |= 0x01; - dev->ohci_mmio[OHCI_HcRhPortStatus1] |= 0x01; + if (!(dev->ohci_mmio[OHCI_HcRhPortStatus1].b[0] & 0x01)) + dev->ohci_mmio[OHCI_HcRhPortStatus1].b[2] |= 0x01; + dev->ohci_mmio[OHCI_HcRhPortStatus1].b[0] |= 0x01; } return; - case OHCI_HcRhDescriptorB + 1: - case OHCI_HcRhDescriptorB + 3: + case OHCI_aHcRhDescriptorB + 1: + case OHCI_aHcRhDescriptorB + 3: return; - case OHCI_HcRhStatus: + case OHCI_aHcRhStatus: if (val & 0x01) { - if ((dev->ohci_mmio[OHCI_HcRhDescriptorA + 1] & 0x03) == 0x00) { - dev->ohci_mmio[OHCI_HcRhPortStatus1 + 1] &= ~0x01; - dev->ohci_mmio[OHCI_HcRhPortStatus1] &= ~0x17; - dev->ohci_mmio[OHCI_HcRhPortStatus1 + 2] &= ~0x17; - dev->ohci_mmio[OHCI_HcRhPortStatus2 + 1] &= ~0x01; - dev->ohci_mmio[OHCI_HcRhPortStatus2] &= ~0x17; - dev->ohci_mmio[OHCI_HcRhPortStatus2 + 2] &= ~0x17; - } else if ((dev->ohci_mmio[OHCI_HcRhDescriptorA + 1] & 0x03) == 0x01) { - if (!(dev->ohci_mmio[OHCI_HcRhDescriptorB + 2] & 0x02)) { - dev->ohci_mmio[OHCI_HcRhPortStatus1 + 1] &= ~0x01; - dev->ohci_mmio[OHCI_HcRhPortStatus1] &= ~0x17; - dev->ohci_mmio[OHCI_HcRhPortStatus1 + 2] &= ~0x17; + if ((dev->ohci_mmio[OHCI_HcRhDescriptorA].b[1] & 0x03) == 0x00) { + dev->ohci_mmio[OHCI_HcRhPortStatus1].b[1] &= ~0x01; + dev->ohci_mmio[OHCI_HcRhPortStatus1].b[0] &= ~0x17; + dev->ohci_mmio[OHCI_HcRhPortStatus1].b[2] &= ~0x17; + dev->ohci_mmio[OHCI_HcRhPortStatus2].b[1] &= ~0x01; + dev->ohci_mmio[OHCI_HcRhPortStatus2].b[0] &= ~0x17; + dev->ohci_mmio[OHCI_HcRhPortStatus2].b[2] &= ~0x17; + } else if ((dev->ohci_mmio[OHCI_HcRhDescriptorA].b[1] & 0x03) == 0x01) { + if (!(dev->ohci_mmio[OHCI_HcRhDescriptorB].b[2] & 0x02)) { + dev->ohci_mmio[OHCI_HcRhPortStatus1].b[1] &= ~0x01; + dev->ohci_mmio[OHCI_HcRhPortStatus1].b[0] &= ~0x17; + dev->ohci_mmio[OHCI_HcRhPortStatus1].b[2] &= ~0x17; } - if (!(dev->ohci_mmio[OHCI_HcRhDescriptorB + 2] & 0x04)) { - dev->ohci_mmio[OHCI_HcRhPortStatus2 + 1] &= ~0x01; - dev->ohci_mmio[OHCI_HcRhPortStatus2] &= ~0x17; - dev->ohci_mmio[OHCI_HcRhPortStatus2 + 2] &= ~0x17; + if (!(dev->ohci_mmio[OHCI_HcRhDescriptorB].b[2] & 0x04)) { + dev->ohci_mmio[OHCI_HcRhPortStatus2].b[1] &= ~0x01; + dev->ohci_mmio[OHCI_HcRhPortStatus2].b[0] &= ~0x17; + dev->ohci_mmio[OHCI_HcRhPortStatus2].b[2] &= ~0x17; } } } return; - case OHCI_HcRhStatus + 1: + case OHCI_aHcRhStatus + 1: if (val & 0x80) - dev->ohci_mmio[addr] |= 0x80; + dev->ohci_mmio[addr >> 2].b[addr & 3] |= 0x80; return; - case OHCI_HcRhStatus + 2: - dev->ohci_mmio[addr] &= ~(val & 0x02); + case OHCI_aHcRhStatus + 2: + dev->ohci_mmio[addr >> 2].b[addr & 3] &= ~(val & 0x02); if (val & 0x01) { - if ((dev->ohci_mmio[OHCI_HcRhDescriptorA + 1] & 0x03) == 0x00) { - dev->ohci_mmio[OHCI_HcRhPortStatus1 + 1] |= 0x01; - dev->ohci_mmio[OHCI_HcRhPortStatus2 + 1] |= 0x01; - } else if ((dev->ohci_mmio[OHCI_HcRhDescriptorA + 1] & 0x03) == 0x01) { - if (!(dev->ohci_mmio[OHCI_HcRhDescriptorB + 2] & 0x02)) - dev->ohci_mmio[OHCI_HcRhPortStatus1 + 1] |= 0x01; - if (!(dev->ohci_mmio[OHCI_HcRhDescriptorB + 2] & 0x04)) - dev->ohci_mmio[OHCI_HcRhPortStatus2 + 1] |= 0x01; + if ((dev->ohci_mmio[OHCI_HcRhDescriptorA].b[1] & 0x03) == 0x00) { + dev->ohci_mmio[OHCI_HcRhPortStatus1].b[1] |= 0x01; + dev->ohci_mmio[OHCI_HcRhPortStatus2].b[1] |= 0x01; + } else if ((dev->ohci_mmio[OHCI_HcRhDescriptorA].b[1] & 0x03) == 0x01) { + if (!(dev->ohci_mmio[OHCI_HcRhDescriptorB].b[2] & 0x02)) + dev->ohci_mmio[OHCI_HcRhPortStatus1].b[1] |= 0x01; + if (!(dev->ohci_mmio[OHCI_HcRhDescriptorB].b[2] & 0x04)) + dev->ohci_mmio[OHCI_HcRhPortStatus2].b[1] |= 0x01; } } return; - case OHCI_HcRhStatus + 3: + case OHCI_aHcRhStatus + 3: if (val & 0x80) - dev->ohci_mmio[OHCI_HcRhStatus + 1] &= ~0x80; + dev->ohci_mmio[OHCI_HcRhStatus].b[1] &= ~0x80; return; - case OHCI_HcRhPortStatus1: - case OHCI_HcRhPortStatus2: - old = dev->ohci_mmio[addr]; + case OHCI_aHcRhPortStatus1: + case OHCI_aHcRhPortStatus2: + old = dev->ohci_mmio[addr >> 2].b[addr & 3]; if (val & 0x10) { if (old & 0x01) { - dev->ohci_mmio[addr] |= 0x10; - timer_on_auto(&dev->ohci_port_reset_timer[(addr - OHCI_HcRhPortStatus1) / 4], 10000.); + dev->ohci_mmio[addr >> 2].b[addr & 3] |= 0x10; + timer_on_auto(&dev->ohci_port_reset_timer[(addr - OHCI_aHcRhPortStatus1) / 4], 10000.); } else - dev->ohci_mmio[addr + 2] |= 0x01; + dev->ohci_mmio[(addr + 2) >> 2].b[(addr + 2) & 3] |= 0x01; } if (val & 0x08) - dev->ohci_mmio[addr] &= ~0x04; + dev->ohci_mmio[addr >> 2].b[addr & 3] &= ~0x04; if (val & 0x04) - dev->ohci_mmio[addr] |= 0x04; + dev->ohci_mmio[addr >> 2].b[addr & 3] |= 0x04; if (val & 0x02) { if (old & 0x01) - dev->ohci_mmio[addr] |= 0x02; + dev->ohci_mmio[addr >> 2].b[addr & 3] |= 0x02; else - dev->ohci_mmio[addr + 2] |= 0x01; + dev->ohci_mmio[(addr + 2) >> 2].b[(addr + 2) & 3] |= 0x01; } if (val & 0x01) { if (old & 0x01) - dev->ohci_mmio[addr] &= ~0x02; + dev->ohci_mmio[addr >> 2].b[addr & 3] &= ~0x02; else - dev->ohci_mmio[addr + 2] |= 0x01; + dev->ohci_mmio[(addr + 2) >> 2].b[(addr + 2) & 3] |= 0x01; } - if (!(dev->ohci_mmio[addr] & 0x04) && (old & 0x04)) - dev->ohci_mmio[addr + 2] |= 0x04; - /* if (!(dev->ohci_mmio[addr] & 0x02)) - dev->ohci_mmio[addr + 2] |= 0x02; */ + if (!(dev->ohci_mmio[addr >> 2].b[addr & 3] & 0x04) && (old & 0x04)) + dev->ohci_mmio[(addr + 2) >> 2].b[(addr + 2) & 3] |= 0x04; + /* if (!(dev->ohci_mmio[addr >> 2].b[addr & 3] & 0x02)) + dev->ohci_mmio[(addr + 2) >> 2].b[(addr + 2) & 3] |= 0x02; */ return; - case OHCI_HcRhPortStatus1 + 1: - if ((val & 0x02) && ((dev->ohci_mmio[OHCI_HcRhDescriptorA + 1] & 0x03) == 0x00) && (dev->ohci_mmio[OHCI_HcRhDescriptorB + 2] & 0x02)) { - dev->ohci_mmio[addr] &= ~0x01; - dev->ohci_mmio[OHCI_HcRhPortStatus1] &= ~0x17; - dev->ohci_mmio[OHCI_HcRhPortStatus1 + 2] &= ~0x17; + case OHCI_aHcRhPortStatus1 + 1: + if ((val & 0x02) && ((dev->ohci_mmio[OHCI_HcRhDescriptorA].b[1] & 0x03) == 0x00) && (dev->ohci_mmio[OHCI_HcRhDescriptorB].b[2] & 0x02)) { + dev->ohci_mmio[addr >> 2].b[addr & 3] &= ~0x01; + dev->ohci_mmio[OHCI_HcRhPortStatus1].b[0] &= ~0x17; + dev->ohci_mmio[OHCI_HcRhPortStatus1].b[2] &= ~0x17; } - if ((val & 0x01) && ((dev->ohci_mmio[OHCI_HcRhDescriptorA + 1] & 0x03) == 0x00) && (dev->ohci_mmio[OHCI_HcRhDescriptorB + 2] & 0x02)) { - dev->ohci_mmio[addr] |= 0x01; - dev->ohci_mmio[OHCI_HcRhPortStatus2] &= ~0x17; - dev->ohci_mmio[OHCI_HcRhPortStatus2 + 2] &= ~0x17; + if ((val & 0x01) && ((dev->ohci_mmio[OHCI_HcRhDescriptorA].b[1] & 0x03) == 0x00) && (dev->ohci_mmio[OHCI_HcRhDescriptorB].b[2] & 0x02)) { + dev->ohci_mmio[addr >> 2].b[addr & 3] |= 0x01; + dev->ohci_mmio[OHCI_HcRhPortStatus2].b[0] &= ~0x17; + dev->ohci_mmio[OHCI_HcRhPortStatus2].b[2] &= ~0x17; } return; - case OHCI_HcRhPortStatus2 + 1: - if ((val & 0x02) && ((dev->ohci_mmio[OHCI_HcRhDescriptorA + 1] & 0x03) == 0x00) && (dev->ohci_mmio[OHCI_HcRhDescriptorB + 2] & 0x04)) - dev->ohci_mmio[addr] &= ~0x01; - if ((val & 0x01) && ((dev->ohci_mmio[OHCI_HcRhDescriptorA + 1] & 0x03) == 0x00) && (dev->ohci_mmio[OHCI_HcRhDescriptorB + 2] & 0x04)) - dev->ohci_mmio[addr] |= 0x01; + case OHCI_aHcRhPortStatus2 + 1: + if ((val & 0x02) && ((dev->ohci_mmio[OHCI_HcRhDescriptorA].b[1] & 0x03) == 0x00) && (dev->ohci_mmio[OHCI_HcRhDescriptorB].b[2] & 0x04)) + dev->ohci_mmio[addr >> 2].b[addr & 3] &= ~0x01; + if ((val & 0x01) && ((dev->ohci_mmio[OHCI_HcRhDescriptorA].b[1] & 0x03) == 0x00) && (dev->ohci_mmio[OHCI_HcRhDescriptorB].b[2] & 0x04)) + dev->ohci_mmio[addr >> 2].b[addr & 3] |= 0x01; return; - case OHCI_HcRhPortStatus1 + 2: - case OHCI_HcRhPortStatus2 + 2: - dev->ohci_mmio[addr] &= ~(val & 0x1f); + case OHCI_aHcRhPortStatus1 + 2: + case OHCI_aHcRhPortStatus2 + 2: + dev->ohci_mmio[addr >> 2].b[addr & 3] &= ~(val & 0x1f); return; - case OHCI_HcRhPortStatus1 + 3: - case OHCI_HcRhPortStatus2 + 3: + case OHCI_aHcRhPortStatus1 + 3: + case OHCI_aHcRhPortStatus2 + 3: return; - case OHCI_HcDoneHead: - case OHCI_HcBulkCurrentED: - case OHCI_HcBulkHeadED: - case OHCI_HcControlCurrentED: - case OHCI_HcControlHeadED: - case OHCI_HcPeriodCurrentED: - dev->ohci_mmio[addr] = (val & 0xf0); + case OHCI_aHcDoneHead: + case OHCI_aHcBulkCurrentED: + case OHCI_aHcBulkHeadED: + case OHCI_aHcControlCurrentED: + case OHCI_aHcControlHeadED: + case OHCI_aHcPeriodCurrentED: + dev->ohci_mmio[addr >> 2].b[addr & 3] = (val & 0xf0); return; } - dev->ohci_mmio[addr] = val; + dev->ohci_mmio[addr >> 2].b[addr & 3] = val; } + +static void +ohci_mmio_writew(uint32_t addr, uint16_t val, void *p) +{ + ohci_mmio_write(addr, val & 0xff, p); + ohci_mmio_write(addr + 1, val >> 8, p); +} + +static void +ohci_mmio_writel(uint32_t addr, uint32_t val, void *p) +{ + ohci_mmio_writew(addr, val & 0xffff, p); + ohci_mmio_writew(addr + 2, val >> 16, p); +} + void ohci_update_mem_mapping(usb_t *dev, uint8_t base1, uint8_t base2, uint8_t base3, int enable) { @@ -544,8 +617,13 @@ ohci_update_mem_mapping(usb_t *dev, uint8_t base1, uint8_t base2, uint8_t base3, dev->ohci_mem_base = ((base1 << 8) | (base2 << 16) | (base3 << 24)) & 0xfffff000; dev->ohci_enable = enable; - if (dev->ohci_enable && (dev->ohci_mem_base != 0x00000000)) + if (dev->ohci_enable && (dev->ohci_mem_base != 0x00000000)) { + dev->ohci_mmio_mapping.flags = MEM_MAPPING_EXTERNAL; mem_mapping_set_addr(&dev->ohci_mmio_mapping, dev->ohci_mem_base, 0x1000); + mem_mapping_enable(&dev->ohci_mmio_mapping); + } + + usb_log("ohci_update_mem_mapping(): OHCI %sabled at %08X\n", dev->ohci_enable ? "en" : "dis", dev->ohci_mem_base); } uint8_t @@ -565,21 +643,24 @@ usb_reset(void *priv) { usb_t *dev = (usb_t *) priv; - memset(dev->uhci_io, 0x00, 128); + memset(dev->uhci_io, 0x00, sizeof(dev->uhci_io)); dev->uhci_io[0x0c] = 0x40; dev->uhci_io[0x10] = dev->uhci_io[0x12] = 0x80; - memset(dev->ohci_mmio, 0x00, 4096); - dev->ohci_mmio[OHCI_HcRevision] = 0x10; - dev->ohci_mmio[OHCI_HcRevision + 1] = 0x01; - dev->ohci_mmio[OHCI_HcRhDescriptorA] = 0x02; - dev->ohci_mmio[OHCI_HcRhDescriptorA + 1] = 0x02; + memset(dev->ohci_mmio, 0x00, sizeof(dev->ohci_mmio)); + dev->ohci_mmio[OHCI_HcRevision].b[0] = 0x10; + dev->ohci_mmio[OHCI_HcRevision].b[1] = 0x01; + dev->ohci_mmio[OHCI_HcRhDescriptorA].b[0] = 0x02; + dev->ohci_mmio[OHCI_HcRhDescriptorA].b[1] = 0x02; io_removehandler(dev->uhci_io_base, 0x20, uhci_reg_read, NULL, NULL, uhci_reg_write, uhci_reg_writew, NULL, dev); dev->uhci_enable = 0; mem_mapping_disable(&dev->ohci_mmio_mapping); dev->ohci_enable = 0; + + usb_log("usb_reset(): OHCI %sabled at %08X\n", dev->ohci_enable ? "en" : "dis", dev->ohci_mem_base); + usb_log("usb_reset(): map = %08X\n", &dev->ohci_mmio_mapping); } static void @@ -591,7 +672,7 @@ usb_close(void *priv) } static void * -usb_init_ext(const device_t *info, void* params) +usb_init_ext(const device_t *info, void *params) { usb_t *dev; @@ -600,16 +681,20 @@ usb_init_ext(const device_t *info, void* params) return (NULL); memset(dev, 0x00, sizeof(usb_t)); - dev->usb_params = (usb_params_t*)params; + dev->usb_params = (usb_params_t *) params; - mem_mapping_add(&dev->ohci_mmio_mapping, 0, 0, - ohci_mmio_read, NULL, NULL, - ohci_mmio_write, NULL, NULL, + mem_mapping_add(&dev->ohci_mmio_mapping, 0, 0x1000, + ohci_mmio_read, ohci_mmio_readw, ohci_mmio_readl, + ohci_mmio_write, ohci_mmio_writew, ohci_mmio_writel, NULL, MEM_MAPPING_EXTERNAL, dev); + + mem_mapping_disable(&dev->ohci_mmio_mapping); + timer_add(&dev->ohci_frame_timer, ohci_update_frame_counter, dev, 0); /* Unused for now, to be used for frame counting. */ timer_add(&dev->ohci_port_reset_timer[0], ohci_port_reset_callback, dev, 0); timer_add(&dev->ohci_port_reset_timer[1], ohci_port_reset_callback_2, dev, 0); timer_add(&dev->ohci_interrupt_desc_poll_timer, ohci_poll_interrupt_descriptors, dev, 0); + usb_reset(dev); return dev;