From c95424b8d9b15f7e3faa16e82e78eceedf2b4a41 Mon Sep 17 00:00:00 2001 From: RichardG867 Date: Tue, 18 Apr 2023 15:03:26 -0300 Subject: [PATCH 01/20] config: Migrate standalone SSI-2001, CMS and GUS from v3.11 and older --- src/config.c | 33 ++++++++++++++++++++++++++++++++- 1 file changed, 32 insertions(+), 1 deletion(-) diff --git a/src/config.c b/src/config.c index 6399c91ab..4b94fb2ac 100644 --- a/src/config.c +++ b/src/config.c @@ -718,6 +718,20 @@ load_sound(void) mpu401_standalone_enable = !!ini_section_get_int(cat, "mpu401_standalone", 0); + /* Backwards compatibility for standalone SSI-2001, CMS and GUS from v3.11 and older. */ + char *legacy_cards[][2] = {{"ssi2001", "ssi2001"}, {"gameblaster", "cms"}, {"gus", "gus"}}; + for (int i = 0, j = 0; i < (sizeof(legacy_cards) / sizeof(legacy_cards[0])); i++) { + if (ini_section_get_int(cat, legacy_cards[i][0], 0) == 1) { + /* Migrate to the first available sound card slot. */ + for (; j < (sizeof(sound_card_current) / sizeof(sound_card_current[0])); j++) { + if (!sound_card_current[j]) { + sound_card_current[j] = sound_card_get_from_internal_name(legacy_cards[i][1]); + break; + } + } + } + } + memset(temp, '\0', sizeof(temp)); p = ini_section_get_string(cat, "sound_type", "float"); if (strlen(p) > 511) @@ -2159,7 +2173,7 @@ save_machine(void) else ini_section_delete_var(cat, "cpu_override"); - /* Forwards compatibility with the previous CPU model system. */ + /* Downgrade compatibility with the previous CPU model system. */ ini_section_delete_var(cat, "cpu_manufacturer"); ini_section_delete_var(cat, "cpu"); @@ -2390,6 +2404,23 @@ save_sound(void) else ini_section_set_int(cat, "mpu401_standalone", mpu401_standalone_enable); + /* Downgrade compatibility for standalone SSI-2001, CMS and GUS from v3.11 and older. */ + char *legacy_cards[][2] = {{"ssi2001", "ssi2001"}, {"gameblaster", "cms"}, {"gus", "gus"}}; + for (int i = 0; i < (sizeof(legacy_cards) / sizeof(legacy_cards[0])); i++) { + int card_id = sound_card_get_from_internal_name(legacy_cards[i][1]); + for (int j = 0; j < (sizeof(sound_card_current) / sizeof(sound_card_current[0])); j++) { + if (sound_card_current[j] == card_id) { + /* A special value of 2 still enables the cards on older versions, + but lets newer versions know that they've already been migrated. */ + ini_section_set_int(cat, legacy_cards[i][0], 2); + card_id = 0; /* mark as found */ + break; + } + } + if (card_id > 0) /* not found */ + ini_section_delete_var(cat, legacy_cards[i][0]); + } + if (sound_is_float == 1) ini_section_delete_var(cat, "sound_type"); else From fb8ef3e40c6819b9d5624fb85e1d2d97ddf6331f Mon Sep 17 00:00:00 2001 From: RichardG867 Date: Tue, 18 Apr 2023 16:14:44 -0300 Subject: [PATCH 02/20] ini: Constify parameters to optimize execution --- src/config.c | 4 ++-- src/include/86box/ini.h | 40 +++++++++++++++++----------------- src/include/86box/sound.h | 2 +- src/ini.c | 46 +++++++++++++++++++-------------------- src/sound/sound.c | 2 +- 5 files changed, 47 insertions(+), 47 deletions(-) diff --git a/src/config.c b/src/config.c index 4b94fb2ac..96f9374ef 100644 --- a/src/config.c +++ b/src/config.c @@ -719,7 +719,7 @@ load_sound(void) mpu401_standalone_enable = !!ini_section_get_int(cat, "mpu401_standalone", 0); /* Backwards compatibility for standalone SSI-2001, CMS and GUS from v3.11 and older. */ - char *legacy_cards[][2] = {{"ssi2001", "ssi2001"}, {"gameblaster", "cms"}, {"gus", "gus"}}; + const char *legacy_cards[][2] = {{"ssi2001", "ssi2001"}, {"gameblaster", "cms"}, {"gus", "gus"}}; for (int i = 0, j = 0; i < (sizeof(legacy_cards) / sizeof(legacy_cards[0])); i++) { if (ini_section_get_int(cat, legacy_cards[i][0], 0) == 1) { /* Migrate to the first available sound card slot. */ @@ -2405,7 +2405,7 @@ save_sound(void) ini_section_set_int(cat, "mpu401_standalone", mpu401_standalone_enable); /* Downgrade compatibility for standalone SSI-2001, CMS and GUS from v3.11 and older. */ - char *legacy_cards[][2] = {{"ssi2001", "ssi2001"}, {"gameblaster", "cms"}, {"gus", "gus"}}; + const char *legacy_cards[][2] = {{"ssi2001", "ssi2001"}, {"gameblaster", "cms"}, {"gus", "gus"}}; for (int i = 0; i < (sizeof(legacy_cards) / sizeof(legacy_cards[0])); i++) { int card_id = sound_card_get_from_internal_name(legacy_cards[i][1]); for (int j = 0; j < (sizeof(sound_card_current) / sizeof(sound_card_current[0])); j++) { diff --git a/src/include/86box/ini.h b/src/include/86box/ini.h index 5eca9ab8c..866787352 100644 --- a/src/include/86box/ini.h +++ b/src/include/86box/ini.h @@ -30,26 +30,26 @@ typedef void *ini_t; typedef void *ini_section_t; extern ini_t ini_new(void); -extern ini_t ini_read(char *fn); -extern void ini_write(ini_t ini, char *fn); +extern ini_t ini_read(const char *fn); +extern void ini_write(ini_t ini, const char *fn); extern void ini_dump(ini_t ini); extern void ini_close(ini_t ini); -extern void ini_section_delete_var(ini_section_t section, char *name); -extern int ini_section_get_int(ini_section_t section, char *name, int def); -extern double ini_section_get_double(ini_section_t section, char *name, double def); -extern int ini_section_get_hex16(ini_section_t section, char *name, int def); -extern int ini_section_get_hex20(ini_section_t section, char *name, int def); -extern int ini_section_get_mac(ini_section_t section, char *name, int def); -extern char *ini_section_get_string(ini_section_t section, char *name, char *def); -extern wchar_t *ini_section_get_wstring(ini_section_t section, char *name, wchar_t *def); -extern void ini_section_set_int(ini_section_t section, char *name, int val); -extern void ini_section_set_double(ini_section_t section, char *name, double val); -extern void ini_section_set_hex16(ini_section_t section, char *name, int val); -extern void ini_section_set_hex20(ini_section_t section, char *name, int val); -extern void ini_section_set_mac(ini_section_t section, char *name, int val); +extern void ini_section_delete_var(ini_section_t section, const char *name); +extern int ini_section_get_int(ini_section_t section, const char *name, int def); +extern double ini_section_get_double(ini_section_t section, const char *name, double def); +extern int ini_section_get_hex16(ini_section_t section, const char *name, int def); +extern int ini_section_get_hex20(ini_section_t section, const char *name, int def); +extern int ini_section_get_mac(ini_section_t section, const char *name, int def); +extern char *ini_section_get_string(ini_section_t section, const char *name, char *def); +extern wchar_t *ini_section_get_wstring(ini_section_t section, const char *name, wchar_t *def); +extern void ini_section_set_int(ini_section_t section, const char *name, int val); +extern void ini_section_set_double(ini_section_t section, const char *name, double val); +extern void ini_section_set_hex16(ini_section_t section, const char *name, int val); +extern void ini_section_set_hex20(ini_section_t section, const char *name, int val); +extern void ini_section_set_mac(ini_section_t section, const char *name, int val); extern void ini_section_set_string(ini_section_t section, const char *name, const char *val); -extern void ini_section_set_wstring(ini_section_t section, char *name, wchar_t *val); +extern void ini_section_set_wstring(ini_section_t section, const char *name, wchar_t *val); #define ini_delete_var(ini, head, name) ini_section_delete_var(ini_find_section(ini, head), name) @@ -69,13 +69,13 @@ extern void ini_section_set_wstring(ini_section_t section, char *name, wchar #define ini_set_string(ini, head, name, val) ini_section_set_string(ini_find_or_create_section(ini, head), name, val) #define ini_set_wstring(ini, head, name, val) ini_section_set_wstring(ini_find_or_create_section(ini, head), name, val) -extern ini_section_t ini_find_section(ini_t ini, char *name); -extern ini_section_t ini_find_or_create_section(ini_t ini, char *name); -extern void ini_rename_section(ini_section_t section, char *name); +extern ini_section_t ini_find_section(ini_t ini, const char *name); +extern ini_section_t ini_find_or_create_section(ini_t ini, const char *name); +extern void ini_rename_section(ini_section_t section, const char *name); extern void ini_delete_section_if_empty(ini_t ini, ini_section_t section); #ifdef __cplusplus } #endif -#endif \ No newline at end of file +#endif diff --git a/src/include/86box/sound.h b/src/include/86box/sound.h index dada9e164..1cb9357a6 100644 --- a/src/include/86box/sound.h +++ b/src/include/86box/sound.h @@ -62,7 +62,7 @@ extern const device_t *sound_card_getdevice(int card); #endif extern int sound_card_has_config(int card); extern char *sound_card_get_internal_name(int card); -extern int sound_card_get_from_internal_name(char *s); +extern int sound_card_get_from_internal_name(const char *s); extern void sound_card_init(void); extern void sound_set_cd_volume(unsigned int vol_l, unsigned int vol_r); diff --git a/src/ini.c b/src/ini.c index 009d21c0b..d41573bed 100644 --- a/src/ini.c +++ b/src/ini.c @@ -101,10 +101,10 @@ ini_log(const char *fmt, ...) #endif static section_t * -find_section(list_t *head, char *name) +find_section(list_t *head, const char *name) { section_t *sec = (section_t *) head->next; - char blank[] = ""; + const char blank[] = ""; if (name == NULL) name = blank; @@ -120,7 +120,7 @@ find_section(list_t *head, char *name) } ini_section_t -ini_find_section(ini_t ini, char *name) +ini_find_section(ini_t ini, const char *name) { if (ini == NULL) return NULL; @@ -129,7 +129,7 @@ ini_find_section(ini_t ini, char *name) } void -ini_rename_section(ini_section_t section, char *name) +ini_rename_section(ini_section_t section, const char *name) { section_t *sec = (section_t *) section; @@ -197,7 +197,7 @@ ini_delete_section_if_empty(ini_t ini, ini_section_t section) } static section_t * -create_section(list_t *head, char *name) +create_section(list_t *head, const char *name) { section_t *ns = malloc(sizeof(section_t)); @@ -209,7 +209,7 @@ create_section(list_t *head, char *name) } ini_section_t -ini_find_or_create_section(ini_t ini, char *name) +ini_find_or_create_section(ini_t ini, const char *name) { if (ini == NULL) return NULL; @@ -263,7 +263,7 @@ ini_close(ini_t ini) } static int -ini_detect_bom(char *fn) +ini_detect_bom(const char *fn) { FILE *f; unsigned char bom[4] = { 0, 0, 0, 0 }; @@ -311,7 +311,7 @@ ini_fgetws(wchar_t *str, int count, FILE *stream) /* Read and parse the configuration file into memory. */ ini_t -ini_read(char *fn) +ini_read(const char *fn) { char sname[128], ename[128]; wchar_t buff[1024]; @@ -438,7 +438,7 @@ ini_read(char *fn) /* Write the in-memory configuration to disk. */ void -ini_write(ini_t ini, char *fn) +ini_write(ini_t ini, const char *fn) { wchar_t wtemp[512]; list_t *list = (list_t *) ini; @@ -521,7 +521,7 @@ ini_dump(ini_t ini) } void -ini_section_delete_var(ini_section_t self, char *name) +ini_section_delete_var(ini_section_t self, const char *name) { section_t *section = (section_t *) self; entry_t *entry; @@ -537,7 +537,7 @@ ini_section_delete_var(ini_section_t self, char *name) } int -ini_section_get_int(ini_section_t self, char *name, int def) +ini_section_get_int(ini_section_t self, const char *name, int def) { section_t *section = (section_t *) self; entry_t *entry; @@ -556,7 +556,7 @@ ini_section_get_int(ini_section_t self, char *name, int def) } double -ini_section_get_double(ini_section_t self, char *name, double def) +ini_section_get_double(ini_section_t self, const char *name, double def) { section_t *section = (section_t *) self; entry_t *entry; @@ -575,7 +575,7 @@ ini_section_get_double(ini_section_t self, char *name, double def) } int -ini_section_get_hex16(ini_section_t self, char *name, int def) +ini_section_get_hex16(ini_section_t self, const char *name, int def) { section_t *section = (section_t *) self; entry_t *entry; @@ -594,7 +594,7 @@ ini_section_get_hex16(ini_section_t self, char *name, int def) } int -ini_section_get_hex20(ini_section_t self, char *name, int def) +ini_section_get_hex20(ini_section_t self, const char *name, int def) { section_t *section = (section_t *) self; entry_t *entry; @@ -613,7 +613,7 @@ ini_section_get_hex20(ini_section_t self, char *name, int def) } int -ini_section_get_mac(ini_section_t self, char *name, int def) +ini_section_get_mac(ini_section_t self, const char *name, int def) { section_t *section = (section_t *) self; entry_t *entry; @@ -632,7 +632,7 @@ ini_section_get_mac(ini_section_t self, char *name, int def) } char * -ini_section_get_string(ini_section_t self, char *name, char *def) +ini_section_get_string(ini_section_t self, const char *name, char *def) { section_t *section = (section_t *) self; entry_t *entry; @@ -648,7 +648,7 @@ ini_section_get_string(ini_section_t self, char *name, char *def) } wchar_t * -ini_section_get_wstring(ini_section_t self, char *name, wchar_t *def) +ini_section_get_wstring(ini_section_t self, const char *name, wchar_t *def) { section_t *section = (section_t *) self; entry_t *entry; @@ -664,7 +664,7 @@ ini_section_get_wstring(ini_section_t self, char *name, wchar_t *def) } void -ini_section_set_int(ini_section_t self, char *name, int val) +ini_section_set_int(ini_section_t self, const char *name, int val) { section_t *section = (section_t *) self; entry_t *ent; @@ -681,7 +681,7 @@ ini_section_set_int(ini_section_t self, char *name, int val) } void -ini_section_set_double(ini_section_t self, char *name, double val) +ini_section_set_double(ini_section_t self, const char *name, double val) { section_t *section = (section_t *) self; entry_t *ent; @@ -698,7 +698,7 @@ ini_section_set_double(ini_section_t self, char *name, double val) } void -ini_section_set_hex16(ini_section_t self, char *name, int val) +ini_section_set_hex16(ini_section_t self, const char *name, int val) { section_t *section = (section_t *) self; entry_t *ent; @@ -715,7 +715,7 @@ ini_section_set_hex16(ini_section_t self, char *name, int val) } void -ini_section_set_hex20(ini_section_t self, char *name, int val) +ini_section_set_hex20(ini_section_t self, const char *name, int val) { section_t *section = (section_t *) self; entry_t *ent; @@ -732,7 +732,7 @@ ini_section_set_hex20(ini_section_t self, char *name, int val) } void -ini_section_set_mac(ini_section_t self, char *name, int val) +ini_section_set_mac(ini_section_t self, const char *name, int val) { section_t *section = (section_t *) self; entry_t *ent; @@ -774,7 +774,7 @@ ini_section_set_string(ini_section_t self, const char *name, const char *val) } void -ini_section_set_wstring(ini_section_t self, char *name, wchar_t *val) +ini_section_set_wstring(ini_section_t self, const char *name, wchar_t *val) { section_t *section = (section_t *) self; entry_t *ent; diff --git a/src/sound/sound.c b/src/sound/sound.c index dbfaf0fdb..d8791d0cf 100644 --- a/src/sound/sound.c +++ b/src/sound/sound.c @@ -202,7 +202,7 @@ sound_card_get_internal_name(int card) } int -sound_card_get_from_internal_name(char *s) +sound_card_get_from_internal_name(const char *s) { int c = 0; From 5813d425e95a78831df6f36f9a252e9f342794ae Mon Sep 17 00:00:00 2001 From: RichardG867 Date: Tue, 18 Apr 2023 16:16:42 -0300 Subject: [PATCH 03/20] clang-format my previous commits --- src/config.c | 12 ++++++++++-- src/include/86box/sound.h | 12 ++++++------ 2 files changed, 16 insertions(+), 8 deletions(-) diff --git a/src/config.c b/src/config.c index 96f9374ef..7641c637c 100644 --- a/src/config.c +++ b/src/config.c @@ -719,7 +719,11 @@ load_sound(void) mpu401_standalone_enable = !!ini_section_get_int(cat, "mpu401_standalone", 0); /* Backwards compatibility for standalone SSI-2001, CMS and GUS from v3.11 and older. */ - const char *legacy_cards[][2] = {{"ssi2001", "ssi2001"}, {"gameblaster", "cms"}, {"gus", "gus"}}; + const char *legacy_cards[][2] = { + {"ssi2001", "ssi2001"}, + { "gameblaster", "cms" }, + { "gus", "gus" } + }; for (int i = 0, j = 0; i < (sizeof(legacy_cards) / sizeof(legacy_cards[0])); i++) { if (ini_section_get_int(cat, legacy_cards[i][0], 0) == 1) { /* Migrate to the first available sound card slot. */ @@ -2405,7 +2409,11 @@ save_sound(void) ini_section_set_int(cat, "mpu401_standalone", mpu401_standalone_enable); /* Downgrade compatibility for standalone SSI-2001, CMS and GUS from v3.11 and older. */ - const char *legacy_cards[][2] = {{"ssi2001", "ssi2001"}, {"gameblaster", "cms"}, {"gus", "gus"}}; + const char *legacy_cards[][2] = { + {"ssi2001", "ssi2001"}, + { "gameblaster", "cms" }, + { "gus", "gus" } + }; for (int i = 0; i < (sizeof(legacy_cards) / sizeof(legacy_cards[0])); i++) { int card_id = sound_card_get_from_internal_name(legacy_cards[i][1]); for (int j = 0; j < (sizeof(sound_card_current) / sizeof(sound_card_current[0])); j++) { diff --git a/src/include/86box/sound.h b/src/include/86box/sound.h index 1cb9357a6..9f36a70b6 100644 --- a/src/include/86box/sound.h +++ b/src/include/86box/sound.h @@ -24,13 +24,13 @@ extern int sound_gain; -#define FREQ_44100 44100 -#define FREQ_48000 48000 -#define FREQ_49716 49716 -#define FREQ_88200 88200 -#define FREQ_96000 96000 +#define FREQ_44100 44100 +#define FREQ_48000 48000 +#define FREQ_49716 49716 +#define FREQ_88200 88200 +#define FREQ_96000 96000 -#define SOUND_FREQ FREQ_48000 +#define SOUND_FREQ FREQ_48000 #define SOUNDBUFLEN (SOUND_FREQ / 50) #define CD_FREQ FREQ_44100 From beb1df4f5cb9f0f9931389f80d60210bb2558401 Mon Sep 17 00:00:00 2001 From: RichardG867 Date: Tue, 18 Apr 2023 20:28:03 -0300 Subject: [PATCH 04/20] qt: Hide unused CD-ROM controller selector --- src/qt/qt_settingsstoragecontrollers.ui | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/src/qt/qt_settingsstoragecontrollers.ui b/src/qt/qt_settingsstoragecontrollers.ui index 558d4c441..9fc0ea519 100644 --- a/src/qt/qt_settingsstoragecontrollers.ui +++ b/src/qt/qt_settingsstoragecontrollers.ui @@ -54,16 +54,26 @@ CD-ROM Controller: + + false + - + + + false + + Configure + + false + From 19d155cdd7947b241d880482b8c41efb9893b2ab Mon Sep 17 00:00:00 2001 From: OBattler Date: Wed, 19 Apr 2023 23:34:32 +0200 Subject: [PATCH 05/20] Keyboard controller file split and assorted clean-ups and fixes --- src/acpi.c | 3 +- src/chipset/ali1543.c | 2 +- src/cpu/386_common.c | 4 +- src/cpu/x86.c | 6 +- src/device.c | 18 +- src/device/CMakeLists.txt | 4 +- src/device/keyboard_at.c | 2861 ++++------------------------------ src/device/mouse_ps2.c | 200 +-- src/include/86box/device.h | 34 +- src/include/86box/keyboard.h | 29 +- src/io.c | 25 +- src/pci.c | 3 +- src/win/Makefile.mingw | 16 +- 13 files changed, 497 insertions(+), 2708 deletions(-) diff --git a/src/acpi.c b/src/acpi.c index cafa06229..625fdfef2 100644 --- a/src/acpi.c +++ b/src/acpi.c @@ -687,14 +687,13 @@ acpi_reg_write_common_regs(int size, uint16_t addr, uint8_t val, void *p) } if (sus_typ & SUS_RESET_PCI) - device_reset_all_pci(); + device_reset_all(DEVICE_PCI); if (sus_typ & SUS_RESET_CPU) cpu_alt_reset = 0; if (sus_typ & SUS_RESET_PCI) { pci_reset(); - keyboard_at_reset(); mem_a20_alt = 0; mem_a20_recalc(); diff --git a/src/chipset/ali1543.c b/src/chipset/ali1543.c index 5aabd6c63..0b5fe5761 100644 --- a/src/chipset/ali1543.c +++ b/src/chipset/ali1543.c @@ -153,7 +153,7 @@ ali1533_write(int func, int addr, uint8_t val, void *priv) case 0x41: /* TODO: Bit 7 selects keyboard controller type: 0 = AT, 1 = PS/2 */ - pic_kbd_latch(!!(val & 0x80)); + pic_kbd_latch(1); pic_mouse_latch(!!(val & 0x40)); dev->pci_conf[addr] = val & 0xbf; break; diff --git a/src/cpu/386_common.c b/src/cpu/386_common.c index f8e7c11ce..2df72c20e 100644 --- a/src/cpu/386_common.c +++ b/src/cpu/386_common.c @@ -780,8 +780,8 @@ smram_restore_state_p6(uint32_t *saved_state) cpu_state.seg_gs.ar_high = (saved_state[SMRAM_FIELD_P6_GS_SELECTOR_AR] >> 24) & 0xff; smm_seg_load(&cpu_state.seg_gs); - mem_a20_alt = 0; - keyboard_at_set_a20_key(!saved_state[SMRAM_FIELD_P6_A20M]); + mem_a20_alt = 0x00; + mem_a20_key = saved_state[SMRAM_FIELD_P6_A20M] ? 0x00 : 0x02; mem_a20_recalc(); if (SMM_REVISION_ID & SMM_SMBASE_RELOCATION) diff --git a/src/cpu/x86.c b/src/cpu/x86.c index 47250045f..76101c344 100644 --- a/src/cpu/x86.c +++ b/src/cpu/x86.c @@ -245,7 +245,7 @@ reset_common(int hard) /* TODO: Hack, but will do for time being, because all AT machines currently are 286+, and vice-versa. */ dma_set_at(is286); - device_reset_all(); + device_reset_all(DEVICE_ALL); } } @@ -322,7 +322,7 @@ reset_common(int hard) /* If we have an AT or PS/2 keyboard controller, make sure the A20 state is correct. */ - kbc_at_a20_reset(); + device_reset_all(DEVICE_KBC); } if (!is286) @@ -359,7 +359,7 @@ hardresetx86(void) /* TODO: Hack, but will do for time being, because all AT machines currently are 286+, and vice-versa. */ dma_set_at(is286); - device_reset_all(); + device_reset_all(DEVICE_ALL); cpu_alt_reset = 0; diff --git a/src/device.c b/src/device.c index 5d739b13c..d0b502ca1 100644 --- a/src/device.c +++ b/src/device.c @@ -315,27 +315,13 @@ device_close_all(void) } void -device_reset_all(void) +device_reset_all(uint32_t match_flags) { int c; for (c = 0; c < DEVICE_MAX; c++) { if (devices[c] != NULL) { - if (devices[c]->reset != NULL) - devices[c]->reset(device_priv[c]); - } - } -} - -/* Reset all attached PCI devices - needed for PCI turbo reset control. */ -void -device_reset_all_pci(void) -{ - int c; - - for (c = 0; c < DEVICE_MAX; c++) { - if (devices[c] != NULL) { - if ((devices[c]->reset != NULL) && (devices[c]->flags & DEVICE_PCI)) + if ((devices[c]->reset != NULL) && (devices[c]->flags & match_flags)) devices[c]->reset(device_priv[c]); } } diff --git a/src/device/CMakeLists.txt b/src/device/CMakeLists.txt index e60856293..ef3a392ee 100644 --- a/src/device/CMakeLists.txt +++ b/src/device/CMakeLists.txt @@ -18,7 +18,9 @@ add_library(dev OBJECT bugger.c cassette.c cartridge.c hasp.c hwm.c hwm_lm75.c hwm_lm78.c hwm_gl518sm.c hwm_vt82c686.c ibm_5161.c isamem.c isartc.c ../lpt.c pci_bridge.c postcard.c serial.c clock_ics9xxx.c isapnp.c i2c.c i2c_gpio.c - smbus_piix4.c smbus_ali7101.c keyboard.c keyboard_xt.c keyboard_at.c + smbus_piix4.c smbus_ali7101.c keyboard.c keyboard_xt.c + kbc_at.c kbc_at_dev.c + keyboard_at.c mouse.c mouse_bus.c mouse_serial.c mouse_ps2.c phoenix_486_jumper.c mouse_wacom_tablet.c serial_passthrough.c) diff --git a/src/device/keyboard_at.c b/src/device/keyboard_at.c index 3a841ad91..ab1980b72 100644 --- a/src/device/keyboard_at.c +++ b/src/device/keyboard_at.c @@ -6,167 +6,56 @@ * * This file is part of the 86Box distribution. * - * Intel 8042 (AT keyboard controller) emulation. + * Implementation of PS/2 series Mouse devices. * * * - * 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. + * Authors: Fred N. van Kempen, */ +#include #include #include -#include #include -#include -#define HAVE_STDARG_H +#include #include +#define HAVE_STDARG_H #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> +#include <86box/mouse.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 +#define FLAG_PS2 0x08 /* dev is AT or PS/2 */ +#define FLAG_AT 0x00 /* dev is AT or PS/2 */ +#define FLAG_TYPE_MASK 0x07 /* mask for type */ 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 + KBD_84_KEY = 0, + KBD_101_KEY, + KBD_102_KEY, + KBD_JIS, + KBD_KOREAN }; -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; +#define FLAG_ENABLED 0x10 /* dev is enabled for use */ +#define FLAG_CTRLDAT 0x08 /* ctrl or data mode */ - /* 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; +const uint8_t id_bytes[16][4] = { { 0x00, 0x00, 0x00, 0x00 }, /* AT 84-key */ + { 0x00, 0x00, 0x00, 0x00 }, /* AT 101/102/106-key */ + { 0x00, 0x00, 0x00, 0x00 }, + { 0x00, 0x00, 0x00, 0x00 }, + { 0x00, 0x00, 0x00, 0x00 }, /* AT Korean */ + { 0x00, 0x00, 0x00, 0x00 }, + { 0x00, 0x00, 0x00, 0x00 }, + { 0x00, 0x00, 0x00, 0x00 }, + { 0x00, 0x00, 0x00, 0x00 }, + { 0xab, 0x83, 0x00, 0x00 }, /* PS/2 101-key */ + { 0xab, 0x83, 0x00, 0x00 }, /* PS/2 102-key */ + { 0xab, 0x90, 0x00, 0x00 }, /* PS/2 106-key JIS */ + /* Japanese keyboard ID - TODO: Find the actual Korean one. */ + { 0xab, 0x90, 0x00, 0x00 }, /* PS/2 Korean */ + { 0x00, 0x00, 0x00, 0x00 }, + { 0x00, 0x00, 0x00, 0x00 }, + { 0x00, 0x00, 0x00, 0x00 } }; /* Global keyboard flags for scan code set 3: bit 0 = repeat, bit 1 = makes break code? */ @@ -178,48 +67,7 @@ uint8_t keyboard_set3_all_break; 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 atkbc_dev_t *SavedKbd = NULL; static const scancode scancode_set1[512] = { // clang-format off @@ -617,12 +465,11 @@ static const scancode scancode_set3[512] = { // 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, ...) +keyboard_at_log(const char *fmt, ...) { va_list ap; @@ -633,690 +480,41 @@ kbd_log(const char *fmt, ...) } } #else -# define kbd_log(fmt, ...) +# define keyboard_at_log(fmt, ...) #endif static void -set_scancode_map(atkbd_t *dev) +keyboard_at_set_scancode_set(void) { switch (keyboard_mode) { - case 1: + case 0x01: default: keyboard_set_table(scancode_set1); break; - case 2: + + case 0x02: keyboard_set_table(scancode_set2); break; - case 3: + case 0x03: 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) +add_data_vals(atkbc_dev_t *dev, uint8_t *val, uint8_t len) { int i; for (i = 0; i < len; i++) - add_data_kbd_queue(dev, val[i]); + kbc_at_dev_queue_add(dev, val[i], 1); } static void add_data_kbd(uint16_t val) { - atkbd_t *dev = SavedKbd; + atkbc_dev_t *dev = SavedKbd; uint8_t fake_shift[4]; uint8_t num_lock = 0, shift_states = 0; @@ -1325,10 +523,10 @@ add_data_kbd(uint16_t val) switch (val) { case FAKE_LSHIFT_ON: - kbd_log("fake left shift on, scan code: "); + keyboard_at_log("%s: Fake left shift on, scan code: ", dev->name); if (num_lock) { if (shift_states) { - kbd_log("N/A (one or both shifts on)\n"); + keyboard_at_log("N/A (one or both shifts on)\n"); break; } else { /* Num lock on and no shifts are pressed, send non-inverted fake shift. */ @@ -1346,7 +544,7 @@ add_data_kbd(uint16_t val) break; default: - kbd_log("N/A (scan code set %i)\n", keyboard_mode & 0x02); + keyboard_at_log("N/A (scan code set %i)\n", keyboard_mode & 0x02); break; } } @@ -1368,7 +566,7 @@ add_data_kbd(uint16_t val) break; default: - kbd_log("N/A (scan code set %i)\n", keyboard_mode & 0x02); + keyboard_at_log("N/A (scan code set %i)\n", keyboard_mode & 0x02); break; } } @@ -1389,19 +587,19 @@ add_data_kbd(uint16_t val) break; default: - kbd_log("N/A (scan code set %i)\n", keyboard_mode & 0x02); + keyboard_at_log("N/A (scan code set %i)\n", keyboard_mode & 0x02); break; } } - kbd_log(shift_states ? "" : "N/A (both shifts off)\n"); + keyboard_at_log(shift_states ? "" : "N/A (both shifts off)\n"); } break; case FAKE_LSHIFT_OFF: - kbd_log("fake left shift on, scan code: "); + keyboard_at_log("%s: Fake left shift on, scan code: ", dev->name); if (num_lock) { if (shift_states) { - kbd_log("N/A (one or both shifts on)\n"); + keyboard_at_log("N/A (one or both shifts on)\n"); break; } else { /* Num lock on and no shifts are pressed, send non-inverted fake shift. */ @@ -1420,7 +618,7 @@ add_data_kbd(uint16_t val) break; default: - kbd_log("N/A (scan code set %i)\n", keyboard_mode & 0x02); + keyboard_at_log("N/A (scan code set %i)\n", keyboard_mode & 0x02); break; } } @@ -1441,7 +639,7 @@ add_data_kbd(uint16_t val) break; default: - kbd_log("N/A (scan code set %i)\n", keyboard_mode & 0x02); + keyboard_at_log("N/A (scan code set %i)\n", keyboard_mode & 0x02); break; } } @@ -1461,1368 +659,347 @@ add_data_kbd(uint16_t val) break; default: - kbd_log("N/A (scan code set %i)\n", keyboard_mode & 0x02); + keyboard_at_log("N/A (scan code set %i)\n", keyboard_mode & 0x02); break; } } - kbd_log(shift_states ? "" : "N/A (both shifts off)\n"); + keyboard_at_log(shift_states ? "" : "N/A (both shifts off)\n"); } break; default: - add_data_kbd_queue(dev, val); + kbc_at_dev_queue_add(dev, val, 1); 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) +keyboard_at_clear_data(void *priv) { - atkbd_t *dev = SavedKbd; + atkbc_dev_t *dev = (atkbc_dev_t *) priv; - kbd_aux_reset(dev, 1); + dev->flags &= ~FLAG_CTRLDAT; } static void -kbd_process_cmd(void *priv) +keyboard_at_set_defaults(atkbc_dev_t *dev) { - atkbd_t *dev = (atkbd_t *) priv; + dev->rate = 1; + dev->flags &= FLAG_ENABLED; - dev->kbd_state = DEV_STATE_MAIN_OUT; + keyboard_set3_all_break = 0; + keyboard_set3_all_repeat = 0; + memset(keyboard_set3_flags, 0, 512); - if (dev->key_wantdata) { - dev->key_wantdata = 0; + keyboard_mode = 0x02; + keyboard_at_set_scancode_set(); +} - /* - * 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; - } +static void +keyboard_at_bat(void *priv) +{ + atkbc_dev_t *dev = (atkbc_dev_t *) priv; - 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); + keyboard_at_set_defaults(dev); + + keyboard_scan = 1; + dev->flags |= FLAG_ENABLED; + + kbc_at_dev_queue_add(dev, 0xaa, 0); +} + +static void +keyboard_at_invalid_cmd(atkbc_dev_t *dev) +{ + /* The AT firmware sends FA on unknown but semantically valid (ie. >= 0xED) commands. */ + keyboard_at_log("%s: Invalid AT command [%02X]\n", dev->name, dev->port->dat); + kbc_at_dev_queue_add(dev, 0xfa, 0); +} + +static void +keyboard_ps2_invalid_cmd(atkbc_dev_t *dev) +{ + /* Send FE on unknown/invalid command per the PS/2 technical reference. */ + keyboard_at_log("%s: Invalid PS/2 command [%02X]\n", dev->name, dev->port->dat); + kbc_at_dev_queue_add(dev, 0xfe, 0); +} + +static void +keyboard_at_write(void *priv) +{ + atkbc_dev_t *dev = (atkbc_dev_t *) priv; + uint8_t i, val; + + if (dev->port == NULL) + return; + + val = dev->port->dat; + + dev->state = DEV_STATE_MAIN_OUT; + + if ((val < 0xed) && (dev->flags & FLAG_CTRLDAT)) { + dev->flags &= ~FLAG_CTRLDAT; + + switch (dev->command) { + case 0xed: /* Set/reset LEDs */ + kbc_at_dev_queue_add(dev, 0xfa, 0); + keyboard_at_log("%s: Set/reset LEDs [%02X]\n", dev->name, val); 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); + case 0xf0: /* Get/set scancode set */ + kbc_at_dev_queue_add(dev, (val > 3) ? 0xfe : 0xfa, 0); + if (val == 0) { + keyboard_at_log("%s: Get scan code set [%02X]\n", dev->name, keyboard_mode); + kbc_at_dev_queue_add(dev, keyboard_mode, 0); } else { - if (dev->key_dat <= 3) { - keyboard_mode = dev->key_dat; - kbd_log("Scan code set now: %02X\n", keyboard_mode); + if (val <= 3) { + keyboard_mode = val; + keyboard_at_log("%s: Set scan code set [%02X]\n", dev->name, keyboard_mode); + keyboard_at_set_scancode_set(); + } else { + /* Fatal so any instance of anything attempting to set scan code > 3 can be reported to us. */ + fatal("%s: Scan code set [%02X] invalid, resend\n", dev->name, val); + dev->flags |= FLAG_CTRLDAT; + dev->state = DEV_STATE_MAIN_WANT_IN; } - set_scancode_map(dev); } break; case 0xf3: /* set typematic rate/delay */ - add_data_kbd_front(dev, 0xfa); + if (val & 0x80) { + keyboard_at_log("%s: Set typematic rate/delay [%02X] has bit 7 set - invalid\n", dev->name, val); + dev->flags |= FLAG_CTRLDAT; /* Resend = keep waiting for parameter. */ + kbc_at_dev_queue_add(dev, 0xfe, 0); /* Command response */ + dev->state = DEV_STATE_MAIN_WANT_IN; + } else { + dev->rate = val; + kbc_at_dev_queue_add(dev, 0xfa, 0); /* Command response */ + keyboard_at_log("%s: Set typematic rate/delay [%02X]\n", dev->name, val); + } 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; + fatal("%s: Parameter [%02X] for invalid command [%02X] - possibly memory corruption!\n", dev->name, val, dev->command); + kbc_at_dev_queue_add(dev, 0xfe, 0); + } + } else { + if (dev->flags & FLAG_CTRLDAT) { + if (val == 0xfe) { + /* Special case - resend last scan code command during another command that wants + input - output as normal but do not cancel the command (so keep waiting for + input). */ + keyboard_at_log("%s: resend last scan code during command [%02X]\n", dev->name, dev->command); + dev->state = DEV_STATE_MAIN_WANT_IN; + kbc_at_dev_queue_add(dev, 0xfa, dev->last_scan_code); + } else { + /* Special case - another command during another command that wants input - proceed + as normal but do not cancel the command (so keep waiting for input), unless the + command in progress is ED (Set/reset LEDs). */ + if (dev->command == 0xed) { + keyboard_scan = 1; + dev->flags &= ~FLAG_CTRLDAT; + } else + dev->state = DEV_STATE_MAIN_WANT_IN; + } } - /* 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; + dev->command = val; + switch (dev->command) { 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; + keyboard_at_log("%s: set/reset LEDs\n", dev->name); + dev->flags |= FLAG_CTRLDAT; + kbc_at_dev_queue_add(dev, 0xfa, 0); /* ACK for command byte */ + dev->state = DEV_STATE_MAIN_WANT_IN; break; case 0xee: /* diagnostic echo */ - kbd_log("ATkbd: ECHO\n"); - add_data_kbd_front(dev, 0xee); + keyboard_at_log("%s: ECHO\n", dev->name); + kbc_at_dev_queue_add(dev, 0xee, 0); break; - case 0xef: /* NOP (reserved for future use) */ - kbd_log("ATkbd: NOP\n"); + case 0xef: /* Invalid command */ + case 0xf1: /* Invalid command */ + if (dev->type & FLAG_PS2) + keyboard_ps2_invalid_cmd(dev); + else + keyboard_at_invalid_cmd(dev); 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; + if (dev->type & FLAG_PS2) { + keyboard_at_log("%s: scan code set\n", dev->name); + dev->flags |= FLAG_CTRLDAT; + kbc_at_dev_queue_add(dev, 0xfa, 0); /* ACK for command byte */ + dev->state = DEV_STATE_MAIN_WANT_IN; + } else + keyboard_at_invalid_cmd(dev); break; case 0xf2: /* read ID */ - kbd_log("ATkbd: read keyboard id\n"); + keyboard_at_log("%s: read keyboard id\n", dev->name); /* 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); + kbc_at_dev_queue_add(dev, 0xfa, 0); + for (i = 0; i < 4; i++) { + if (id_bytes[dev->type][i] == 0) + break; + + kbc_at_dev_queue_add(dev, id_bytes[dev->type][i], 0); + } 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; + case 0xf3: /* set command mode */ + keyboard_at_log("%s: set typematic rate/delay\n", dev->name); + dev->flags |= FLAG_CTRLDAT; + kbc_at_dev_queue_add(dev, 0xfa, 0); /* ACK for command byte */ + dev->state = DEV_STATE_MAIN_WANT_IN; break; - case 0xf4: /* enable keyboard */ - kbd_log("ATkbd: enable keyboard\n"); - add_data_kbd_front(dev, 0xfa); + case 0xf4: /* enable */ + keyboard_at_log("%s: enable keyboard\n", dev->name); + dev->flags |= FLAG_ENABLED; keyboard_scan = 1; + kbc_at_dev_queue_add(dev, 0xfa, 0); 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_at_log("%s: set defaults%s\n", (val == 0xf6) ? "" : " and disable keyboard"); + keyboard_scan = (val == 0xf6); + keyboard_at_log("%s: val = %02X, keyboard_scan = %i\n", + dev->name, val, keyboard_scan); + kbc_at_dev_queue_add(dev, 0xfa, 0); keyboard_set3_all_break = 0; keyboard_set3_all_repeat = 0; memset(keyboard_set3_flags, 0, 512); + keyboard_mode = 0x02; - set_scancode_map(dev); + keyboard_at_set_scancode_set(); 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; + if (dev->type & FLAG_PS2) { + keyboard_at_log("%s: set all keys to repeat\n", dev->name); + kbc_at_dev_queue_add(dev, 0xfa, 0); + keyboard_set3_all_break = 1; + } else + keyboard_at_invalid_cmd(dev); 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; + if (dev->type & FLAG_PS2) { + keyboard_at_log("%s: set all keys to give make/break codes\n", dev->name); + kbc_at_dev_queue_add(dev, 0xfa, 0); + keyboard_set3_all_break = 1; + } else + keyboard_at_invalid_cmd(dev); 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; + if (dev->type & FLAG_PS2) { + keyboard_at_log("%s: set all keys to give make codes only\n", dev->name); + kbc_at_dev_queue_add(dev, 0xfa, 0); + keyboard_set3_all_break = 0; + } else + keyboard_at_invalid_cmd(dev); 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; + if (dev->type & FLAG_PS2) { + keyboard_at_log("%s: set all keys to repeat and give make/break codes\n", dev->name); + kbc_at_dev_queue_add(dev, 0xfa, 0); + keyboard_set3_all_repeat = 1; + keyboard_set3_all_break = 1; + } else + keyboard_at_invalid_cmd(dev); break; + /* TODO: Actually implement these commands. */ + case 0xfb: /* set some keys to repeat */ + if (dev->type & FLAG_PS2) { + keyboard_at_log("%s: set some keys to repeat\n", dev->name); + kbc_at_dev_queue_add(dev, 0xfe, 0); + } else + keyboard_at_invalid_cmd(dev); + break; + + case 0xfc: /* set some keys to give make/break codes */ + if (dev->type & FLAG_PS2) { + keyboard_at_log("%s: set some keys to give make/break codes\n", dev->name); + kbc_at_dev_queue_add(dev, 0xfe, 0); + } else + keyboard_at_invalid_cmd(dev); + break; + + case 0xfd: /* set some keys to give make codes only */ + if (dev->type & FLAG_PS2) { + keyboard_at_log("%s: set some keys to give make codes only\n", dev->name); + kbc_at_dev_queue_add(dev, 0xfe, 0); + } else + keyboard_at_invalid_cmd(dev); + break; + + /* TODO: This is supposed to resend multiple bytes after some commands. */ case 0xfe: /* resend last scan code */ - kbd_log("ATkbd: resend last scan code\n"); - add_data_kbd_front(dev, dev->kbd_last_scan_code); + keyboard_at_log("%s: resend last scan code\n", dev->name); + kbc_at_dev_queue_add(dev, 0xfa, dev->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); + kbc_at_dev_reset(dev, 1); 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); - } + kbc_at_dev_queue_add(dev, 0xfe, 0); } } } -static void -kbd_write(uint16_t port, uint8_t val, void *priv) +/* + * Initialize the device for use by the user. + * + * We also get called from the various machines. + */ +void * +keyboard_at_init(const device_t *info) { - atkbd_t *dev = (atkbd_t *) priv; + atkbc_dev_t *dev = kbc_at_dev_init(DEV_KBD); - kbd_log((port == 0x61) ? "" : "[%04X:%08X] ATkbc: write(%04X) = %02X\n", CS, cpu_state.pc, port, val); + dev->name = info->name; + /* Key 14 = Japanese key next to backspace, scan code: 13 (Yen 7D); + Key 29 = US backslash, scan code: 5C (Backslash 2B); + Key 42 = European backslash, scan code: 53 (Backslash 2B); + Key 45 = European key next to left shift, scan code: 13 (Key 56); + Key 56 = Japanese key next to right shift, scan code: 5C (Backslash 73); + Key 59 = Japanese key between left Ctrl and left Alt, scan code: 85 (Muhenkan 7B); + Key 63 = Japanese key between right Ctrl and right Alt, scan code: 86 (Henkan/Zenkouho 79); + Key 65? = Japanese key between right Ctrl and right Alt, scan code: 87 (Hiragana/Katakana 70). + */ + dev->type = FLAG_PS2 | KBD_102_KEY /* device_get_config_int("type") */; - switch (port) { - case 0x60: - dev->status &= ~STAT_CD; - if (dev->want60 && (dev->command == 0xd1)) { - kbd_log("ATkbc: write output port\n"); + keyboard_at_log("%s: type=%d\n", dev->name, dev->type); - /* Fast A20 - ignore all other bits. */ - val = (val & 0x02) | (dev->output_port & 0xfd); + dev->process_cmd = keyboard_at_write; + dev->execute_bat = keyboard_at_bat; - /* 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); - } + dev->scan = &keyboard_scan; - write_output_fast_a20(dev, val | 0x01); + if (dev->port != NULL) + kbc_at_dev_reset(dev, 0); - dev->want60 = 0; - dev->kbc_state = KBC_STATE_MAIN_IBF; - return; - } - break; + keyboard_send = add_data_kbd; + SavedKbd = dev; - 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); + /* Return our private data to the I/O layer. */ + return (dev); } static void -kbd_reset(void *priv) +keyboard_at_close(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); + atkbc_dev_t *dev = (atkbc_dev_t *) priv; keyboard_scan = 0; keyboard_send = NULL; @@ -2832,427 +1009,47 @@ kbd_close(void *priv) 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; +static const device_config_t keyboard_at_config[] = { + // clang-format off + { + .name = "type", + .description = "Type", + .type = CONFIG_SELECTION, + .default_string = "", + .default_int = 2, + .file_filter = "", + .spinner = { 0 }, + .selection = { + { .description = "AT 84-key", .value = FLAG_AT | KBD_84_KEY }, + { .description = "AT 101/102/106-key", .value = FLAG_AT | KBD_101_KEY }, + { .description = "AT Korean", .value = FLAG_AT | KBD_KOREAN }, + { .description = "PS/2 101-key", .value = FLAG_PS2 | KBD_101_KEY }, + { .description = "PS/2 102-key", .value = FLAG_PS2 | KBD_102_KEY }, + { .description = "PS/2 106-key JIS", .value = FLAG_PS2 | KBD_JIS }, + { .description = "PS/2 Korean", .value = FLAG_PS2 | KBD_KOREAN }, + { .description = "" } + } + }, + { + .name = "", .description = "", .type = CONFIG_END } - - 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 + // clang-format on }; -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 }, +/* TODO: Add more keyboard types. */ +const device_t keyboard_at_generic_device = { + .name = "Standard AT or PS/2 Keyboard", + .internal_name = "ps2", + .flags = DEVICE_PS2, + .local = 0, + .init = keyboard_at_init, + .close = keyboard_at_close, + .reset = NULL, + { .poll = NULL }, .speed_changed = NULL, .force_redraw = NULL, - .config = NULL + .config = keyboard_at_config }; - -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 b/src/device/mouse_ps2.c index 1c8e0334d..eae528058 100644 --- a/src/device/mouse_ps2.c +++ b/src/device/mouse_ps2.c @@ -30,22 +30,7 @@ enum { 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_EXPLORER 0x200 /* Has 5 buttons */ #define FLAG_5BTN 0x100 /* using Intellimouse Optical mode */ #define FLAG_INTELLI 0x80 /* device is IntelliMouse */ #define FLAG_INTMODE 0x40 /* using Intellimouse mode */ @@ -76,13 +61,13 @@ mouse_ps2_log(const char *fmt, ...) void mouse_clear_data(void *priv) { - mouse_t *dev = (mouse_t *) priv; + atkbc_dev_t *dev = (atkbc_dev_t *) priv; dev->flags &= ~FLAG_CTRLDAT; } static void -ps2_report_coordinates(mouse_t *dev, int cmd) +ps2_report_coordinates(atkbc_dev_t *dev, int main) { uint8_t buff[3] = { 0x08, 0x00, 0x00 }; int temp_z; @@ -123,15 +108,9 @@ ps2_report_coordinates(mouse_t *dev, int cmd) 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]); - } + kbc_at_dev_queue_add(dev, buff[0], main); + kbc_at_dev_queue_add(dev, buff[1], main); + kbc_at_dev_queue_add(dev, buff[2], main); if (dev->flags & FLAG_INTMODE) { temp_z = dev->z & 0x0f; if ((dev->flags & FLAG_5BTN)) { @@ -144,62 +123,94 @@ ps2_report_coordinates(mouse_t *dev, int cmd) if (temp_z & 0x08) temp_z |= 0xf0; } - if (cmd) - keyboard_at_adddata_mouse_cmd(temp_z); - else - keyboard_at_adddata_mouse(temp_z); + kbc_at_dev_queue_add(dev, temp_z, main); } dev->x = dev->y = dev->z = 0; } static void -ps2_write(uint8_t val, void *priv) +ps2_set_defaults(atkbc_dev_t *dev) { - mouse_t *dev = (mouse_t *) priv; - uint8_t temp; + dev->mode = MODE_STREAM; + dev->rate = 1; + dev->flags &= (0x88 | FLAG_ENABLED); +} + +static void +ps2_bat(void *priv) +{ + atkbc_dev_t *dev = (atkbc_dev_t *) priv; + + ps2_set_defaults(dev); + + mouse_scan = 1; + dev->flags |= FLAG_ENABLED; + + kbc_at_dev_queue_add(dev, 0xaa, 0); + kbc_at_dev_queue_add(dev, 0x00, 0); +} + +static void +ps2_write(void *priv) +{ + atkbc_dev_t *dev = (atkbc_dev_t *) priv; + uint8_t temp, val; + + if (dev->port == NULL) + return; + + val = dev->port->dat; + + dev->state = DEV_STATE_MAIN_OUT; if (dev->flags & FLAG_CTRLDAT) { dev->flags &= ~FLAG_CTRLDAT; if (val == 0xff) - goto mouse_reset; - - switch (dev->command) { + kbc_at_dev_reset(dev, 1); + else switch (dev->command) { case 0xe8: /* set mouse resolution */ dev->resolution = val; - keyboard_at_adddata_mouse_cmd(0xfa); + kbc_at_dev_queue_add(dev, 0xfa, 0); + mouse_ps2_log("%s: Set mouse resolution [%02X]\n", dev->name, val); break; case 0xf3: /* set sample rate */ - dev->sample_rate = val; - keyboard_at_adddata_mouse_cmd(0xfa); /* Command response */ + dev->rate = val; + kbc_at_dev_queue_add(dev, 0xfa, 0); /* Command response */ + mouse_ps2_log("%s: Set sample rate [%02X]\n", dev->name, val); break; default: - keyboard_at_adddata_mouse_cmd(0xfc); + kbc_at_dev_queue_add(dev, 0xfc, 0); } } else { dev->command = val; switch (dev->command) { case 0xe6: /* set scaling to 1:1 */ + mouse_ps2_log("%s: Set scaling to 1:1\n", dev->name); dev->flags &= ~FLAG_SCALED; - keyboard_at_adddata_mouse_cmd(0xfa); + kbc_at_dev_queue_add(dev, 0xfa, 0); break; case 0xe7: /* set scaling to 2:1 */ + mouse_ps2_log("%s: Set scaling to 2:1\n", dev->name); dev->flags |= FLAG_SCALED; - keyboard_at_adddata_mouse_cmd(0xfa); + kbc_at_dev_queue_add(dev, 0xfa, 0); break; case 0xe8: /* set mouse resolution */ + mouse_ps2_log("%s: Set mouse resolution\n", dev->name); dev->flags |= FLAG_CTRLDAT; - keyboard_at_adddata_mouse_cmd(0xfa); + kbc_at_dev_queue_add(dev, 0xfa, 0); + dev->state = DEV_STATE_MAIN_WANT_IN; break; case 0xe9: /* status request */ - keyboard_at_adddata_mouse_cmd(0xfa); + mouse_ps2_log("%s: Status request\n", dev->name); + kbc_at_dev_queue_add(dev, 0xfa, 0); temp = (dev->flags & 0x30); if (mouse_buttons & 1) temp |= 4; @@ -207,64 +218,68 @@ ps2_write(uint8_t val, void *priv) 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); + kbc_at_dev_queue_add(dev, temp, 0); + kbc_at_dev_queue_add(dev, dev->resolution, 0); + kbc_at_dev_queue_add(dev, dev->rate, 0); break; case 0xea: /* set stream */ + mouse_ps2_log("%s: Set stream\n", dev->name); dev->flags &= ~FLAG_CTRLDAT; mouse_scan = 1; - keyboard_at_adddata_mouse_cmd(0xfa); /* ACK for command byte */ + kbc_at_dev_queue_add(dev, 0xfa, 0); /* ACK for command byte */ break; case 0xeb: /* Get mouse data */ - keyboard_at_adddata_mouse_cmd(0xfa); + mouse_ps2_log("%s: Get mouse data\n", dev->name); + kbc_at_dev_queue_add(dev, 0xfa, 0); - ps2_report_coordinates(dev, 1); + ps2_report_coordinates(dev, 0); break; case 0xf2: /* read ID */ - keyboard_at_adddata_mouse_cmd(0xfa); + mouse_ps2_log("%s: Read ID\n", dev->name); + kbc_at_dev_queue_add(dev, 0xfa, 0); if (dev->flags & FLAG_INTMODE) - keyboard_at_adddata_mouse_cmd((dev->flags & FLAG_5BTN) ? 0x04 : 0x03); + kbc_at_dev_queue_add(dev, (dev->flags & FLAG_5BTN) ? 0x04 : 0x03, 0); else - keyboard_at_adddata_mouse_cmd(0x00); + kbc_at_dev_queue_add(dev, 0x00, 0); break; - case 0xf3: /* set command mode */ + case 0xf3: /* set sample rate */ + mouse_ps2_log("%s: Set sample rate\n", dev->name); dev->flags |= FLAG_CTRLDAT; - keyboard_at_adddata_mouse_cmd(0xfa); /* ACK for command byte */ + kbc_at_dev_queue_add(dev, 0xfa, 0); /* ACK for command byte */ + dev->state = DEV_STATE_MAIN_WANT_IN; break; case 0xf4: /* enable */ + mouse_ps2_log("%s: Enable\n", dev->name); dev->flags |= FLAG_ENABLED; mouse_scan = 1; - keyboard_at_adddata_mouse_cmd(0xfa); + kbc_at_dev_queue_add(dev, 0xfa, 0); break; case 0xf5: /* disable */ + mouse_ps2_log("%s: Disable\n", dev->name); dev->flags &= ~FLAG_ENABLED; mouse_scan = 0; - keyboard_at_adddata_mouse_cmd(0xfa); + kbc_at_dev_queue_add(dev, 0xfa, 0); break; case 0xf6: /* set defaults */ + mouse_ps2_log("%s: Set defaults\n", dev->name); + ps2_set_defaults(dev); + kbc_at_dev_queue_add(dev, 0xfa, 0); + break; + 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); - } + mouse_ps2_log("%s: Reset\n", dev->name); + kbc_at_dev_reset(dev, 1); break; default: - keyboard_at_adddata_mouse_cmd(0xfe); + kbc_at_dev_queue_add(dev, 0xfe, 0); } } @@ -279,7 +294,8 @@ mouse_reset: (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) && + if ((dev->flags & FLAG_EXPLORER) && (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; @@ -289,30 +305,18 @@ mouse_reset: 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; + atkbc_dev_t *dev = (atkbc_dev_t *) priv; - if (!x && !y && !z && (b == dev->b)) - return (0xff); - -#if 0 - if (!(dev->flags & FLAG_ENABLED)) - return(0xff); -#endif - - if (!mouse_scan) + if (!mouse_scan || (!x && !y && !z && (b == dev->b))) 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 + if ((dev->mode == MODE_STREAM) && (kbc_at_dev_queue_pos(dev, 1) < 13)) { dev->b = b; - ps2_report_coordinates(dev, 0); + ps2_report_coordinates(dev, 1); } return (0); @@ -326,11 +330,9 @@ ps2_poll(int x, int y, int z, int b, double abs_x, double abs_y, void *priv) void * mouse_ps2_init(const device_t *info) { - mouse_t *dev; + atkbc_dev_t *dev = kbc_at_dev_init(DEV_AUX); int i; - dev = (mouse_t *) malloc(sizeof(mouse_t)); - memset(dev, 0x00, sizeof(mouse_t)); dev->name = info->name; dev->type = info->local; @@ -338,18 +340,25 @@ mouse_ps2_init(const device_t *info) i = device_get_config_int("buttons"); if (i > 2) dev->flags |= FLAG_INTELLI; + if (i > 4) + dev->flags |= FLAG_EXPLORER; - if (i == 4) + 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); + dev->process_cmd = ps2_write; + dev->execute_bat = ps2_bat; + + dev->scan = &mouse_scan; + + if (dev->port != NULL) + kbc_at_dev_reset(dev, 0); + /* Return our private data to the I/O layer. */ return (dev); } @@ -357,10 +366,7 @@ mouse_ps2_init(const device_t *info) 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); + atkbc_dev_t *dev = (atkbc_dev_t *) priv; free(dev); } diff --git a/src/include/86box/device.h b/src/include/86box/device.h index f85be460d..2390e5128 100644 --- a/src/include/86box/device.h +++ b/src/include/86box/device.h @@ -57,21 +57,24 @@ #define CONFIG_SERPORT 12 enum { - DEVICE_PCJR = 2, /* requires an IBM PCjr */ - DEVICE_AT = 4, /* requires an AT-compatible system */ - DEVICE_PS2 = 8, /* requires a PS/1 or PS/2 system */ - DEVICE_ISA = 0x10, /* requires the ISA bus */ - DEVICE_CBUS = 0x20, /* requires the C-BUS bus */ - DEVICE_MCA = 0x40, /* requires the MCA bus */ - DEVICE_EISA = 0x80, /* requires the EISA bus */ - DEVICE_VLB = 0x100, /* requires the PCI bus */ - DEVICE_PCI = 0x200, /* requires the VLB bus */ - DEVICE_AGP = 0x400, /* requires the AGP bus */ - DEVICE_AC97 = 0x800, /* requires the AC'97 bus */ - DEVICE_COM = 0x1000, /* requires a serial port */ - DEVICE_LPT = 0x2000, /* requires a parallel port */ + DEVICE_PCJR = 2, /* requires an IBM PCjr */ + DEVICE_AT = 4, /* requires an AT-compatible system */ + DEVICE_PS2 = 8, /* requires a PS/1 or PS/2 system */ + DEVICE_ISA = 0x10, /* requires the ISA bus */ + DEVICE_CBUS = 0x20, /* requires the C-BUS bus */ + DEVICE_MCA = 0x40, /* requires the MCA bus */ + DEVICE_EISA = 0x80, /* requires the EISA bus */ + DEVICE_VLB = 0x100, /* requires the PCI bus */ + DEVICE_PCI = 0x200, /* requires the VLB bus */ + DEVICE_AGP = 0x400, /* requires the AGP bus */ + DEVICE_AC97 = 0x800, /* requires the AC'97 bus */ + DEVICE_COM = 0x1000, /* requires a serial port */ + DEVICE_LPT = 0x2000, /* requires a parallel port */ + DEVICE_KBC = 0x4000, /* is a keyboard controller */ - DEVICE_EXTPARAMS = 0x40000000 /* accepts extended parameters */ + DEVICE_EXTPARAMS = 0x40000000, /* accepts extended parameters */ + + DEVICE_ALL = 0xffffffff /* match all devices */ }; #define BIOS_NORMAL 0 @@ -171,8 +174,7 @@ extern void *device_cadd_inst_parameters(const device_t *d, const device_t *cd, extern void device_cadd_inst_ex(const device_t *d, const device_t *cd, void *priv, int inst); extern void device_cadd_inst_ex_parameters(const device_t *d, const device_t *cd, void *priv, int inst, void *params); extern void device_close_all(void); -extern void device_reset_all(void); -extern void device_reset_all_pci(void); +extern void device_reset_all(uint32_t match_flags); extern void *device_get_priv(const device_t *d); extern int device_available(const device_t *d); extern int device_poll(const device_t *d, int x, int y, int z, int b); diff --git a/src/include/86box/keyboard.h b/src/include/86box/keyboard.h index 2834937ff..08a425f6d 100644 --- a/src/include/86box/keyboard.h +++ b/src/include/86box/keyboard.h @@ -27,6 +27,15 @@ enum { DEV_AUX }; +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 +}; + /* Used by the AT / PS/2 keyboard controller, common device, keyboard, and mouse. */ typedef struct { uint8_t wantcmd, dat, pad, pad0; @@ -36,7 +45,7 @@ typedef struct { void *priv; void (*poll)(void *priv); -} kbc_port_t; +} kbc_at_port_t; /* Used by the AT / PS/2 common device, keyboard, and mouse. */ typedef struct { @@ -65,7 +74,7 @@ typedef struct { void (*process_cmd)(void *priv); void (*execute_bat)(void *priv); - kbc_port_t *port; + kbc_at_port_t *port; } atkbc_dev_t; typedef struct { @@ -188,7 +197,7 @@ extern int mouse_queue_start, mouse_queue_end; extern int mouse_cmd_queue_start, mouse_cmd_queue_end; extern int mouse_scan; -extern kbc_port_t *kbc_ports[2]; +extern kbc_at_port_t *kbc_at_ports[2]; #ifdef EMU_DEVICE_H extern const device_t keyboard_pc_device; @@ -228,6 +237,8 @@ extern const device_t keyboard_ps2_intel_ami_pci_device; extern const device_t keyboard_ps2_acer_pci_device; extern const device_t keyboard_ps2_ali_pci_device; extern const device_t keyboard_ps2_tg_ami_pci_device; + +extern const device_t keyboard_at_generic_device; #endif /*EMU_DEVICE_H*/ extern void keyboard_init(void); @@ -249,14 +260,10 @@ extern int keyboard_isfsexit_down(void); extern int keyboard_ismsexit(void); extern void keyboard_set_is_amstrad(int ams); -extern void keyboard_at_adddata_mouse(uint8_t val); -extern void keyboard_at_adddata_mouse_cmd(uint8_t val); -extern void keyboard_at_mouse_reset(void); -extern uint8_t keyboard_at_mouse_pos(void); -extern void keyboard_at_set_mouse(void (*mouse_write)(uint8_t val, void *), void *); -extern void keyboard_at_set_a20_key(int state); -extern void keyboard_at_reset(void); -extern void kbc_at_a20_reset(void); +extern uint8_t kbc_at_dev_queue_pos(atkbc_dev_t *dev, uint8_t main); +extern void kbc_at_dev_queue_add(atkbc_dev_t *dev, uint8_t val, uint8_t main); +extern void kbc_at_dev_reset(atkbc_dev_t *dev, int do_fa); +extern atkbc_dev_t *kbc_at_dev_init(uint8_t inst); #ifdef __cplusplus } diff --git a/src/io.c b/src/io.c index 87cceae62..0cd7cd87b 100644 --- a/src/io.c +++ b/src/io.c @@ -56,7 +56,6 @@ typedef struct { int initialized = 0; io_t *io[NPORTS], *io_last[NPORTS]; -// #define ENABLE_IO_LOG 1 #ifdef ENABLE_IO_LOG int io_do_log = ENABLE_IO_LOG; @@ -311,9 +310,7 @@ inb(uint16_t port) /* if (port == 0x1ed) ret = 0xfe; */ - if (port == 0x92) { - io_log("[%04X:%08X] (%i, %i, %04i) in b(%04X) = %02X\n", CS, cpu_state.pc, in_smm, found, qfound, port, ret); - } + io_log("[%04X:%08X] (%i, %i, %04i) in b(%04X) = %02X\n", CS, cpu_state.pc, in_smm, found, qfound, port, ret); return (ret); } @@ -344,9 +341,7 @@ outb(uint16_t port, uint8_t val) #endif } - if (port == 0x92) { - io_log("[%04X:%08X] (%i, %i, %04i) outb(%04X, %02X)\n", CS, cpu_state.pc, in_smm, found, qfound, port, val); - } + io_log("[%04X:%08X] (%i, %i, %04i) outb(%04X, %02X)\n", CS, cpu_state.pc, in_smm, found, qfound, port, val); return; } @@ -400,9 +395,7 @@ inw(uint16_t port) if (!found) cycles -= io_delay; - if (port == 0x92) { - io_log("[%04X:%08X] (%i, %i, %04i) in w(%04X) = %04X\n", CS, cpu_state.pc, in_smm, found, qfound, port, ret); - } + io_log("[%04X:%08X] (%i, %i, %04i) in w(%04X) = %04X\n", CS, cpu_state.pc, in_smm, found, qfound, port, ret); return ret; } @@ -447,9 +440,7 @@ outw(uint16_t port, uint16_t val) #endif } - if (port == 0x92) { - io_log("[%04X:%08X] (%i, %i, %04i) outw(%04X, %04X)\n", CS, cpu_state.pc, in_smm, found, qfound, port, val); - } + io_log("[%04X:%08X] (%i, %i, %04i) outw(%04X, %04X)\n", CS, cpu_state.pc, in_smm, found, qfound, port, val); return; } @@ -531,9 +522,7 @@ inl(uint16_t port) if (!found) cycles -= io_delay; - if (port == 0x92) { - io_log("[%04X:%08X] (%i, %i, %04i) in l(%04X) = %08X\n", CS, cpu_state.pc, in_smm, found, qfound, port, ret); - } + io_log("[%04X:%08X] (%i, %i, %04i) in l(%04X) = %08X\n", CS, cpu_state.pc, in_smm, found, qfound, port, ret); return ret; } @@ -593,9 +582,7 @@ outl(uint16_t port, uint32_t val) #endif } - if (port == 0x92) { - io_log("[%04X:%08X] (%i, %i, %04i) outl(%04X, %08X)\n", CS, cpu_state.pc, in_smm, found, qfound, port, val); - } + io_log("[%04X:%08X] (%i, %i, %04i) outl(%04X, %08X)\n", CS, cpu_state.pc, in_smm, found, qfound, port, val); return; } diff --git a/src/pci.c b/src/pci.c index f9155e2e3..692733422 100644 --- a/src/pci.c +++ b/src/pci.c @@ -922,12 +922,11 @@ trc_reset(uint8_t val) dma_reset(); dma_set_at(1); - device_reset_all(); + device_reset_all(DEVICE_ALL); cpu_alt_reset = 0; pci_reset(); - keyboard_at_reset(); mem_a20_alt = 0; mem_a20_recalc(); diff --git a/src/win/Makefile.mingw b/src/win/Makefile.mingw index 76d402a83..3725e6e09 100644 --- a/src/win/Makefile.mingw +++ b/src/win/Makefile.mingw @@ -209,6 +209,9 @@ endif ifndef MINITRACE MINITRACE := n endif +ifndef AVX + AVX := n +endif ifeq ($(DYNAREC), y) ifeq ($(ARM), y) ifeq ($(NEW_DYNAREC), n) @@ -314,7 +317,11 @@ else endif endif endif -AFLAGS := -msse2 -mfpmath=sse +ifeq ($(AVX), y) + AFLAGS := -msse2 -msse3 -mssse3 -msse4 -msse4a -mavx -mavx2 -mfpmath=sse +else + AFLAGS := -msse2 -mfpmath=sse +endif ifeq ($(ARM), y) DFLAGS := -march=armv7-a AOPTIM := @@ -581,11 +588,8 @@ MCHOBJ := machine.o machine_table.o \ m_at_socket8.o m_at_slot1.o m_at_slot2.o m_at_socket370.o \ m_at_misc.o -ifeq ($(NEW_KBC), y) - KBCOBJ := kbc_at.o kbd_at.o -else - KBCOBJ := keyboard_at.o -endif +KBCOBJ := kbc_at.o kbc_at_dev.o \ + keyboard_at.o DEVOBJ := bugger.o cartridge.o cassette.o hasp.o hwm.o hwm_lm75.o hwm_lm78.o hwm_gl518sm.o hwm_vt82c686.o \ ibm_5161.o isamem.o isartc.o lpt.o pci_bridge.o postcard.o serial.o \ From 06fc5e9d0d8b5fd6325594d212e2521288d3c182 Mon Sep 17 00:00:00 2001 From: OBattler Date: Wed, 19 Apr 2023 23:46:33 +0200 Subject: [PATCH 06/20] Committed the two missing files. --- src/device/kbc_at.c | 2111 +++++++++++++++++++++++++++++++++++++++ src/device/kbc_at_dev.c | 198 ++++ 2 files changed, 2309 insertions(+) create mode 100644 src/device/kbc_at.c create mode 100644 src/device/kbc_at_dev.c diff --git a/src/device/kbc_at.c b/src/device/kbc_at.c new file mode 100644 index 000000000..7026815a4 --- /dev/null +++ b/src/device/kbc_at.c @@ -0,0 +1,2111 @@ +/* + * 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: Miran Grca, + * EngiNerd, + * + * Copyright 2023 Miran Grca. + * Copyright 2023 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 + +#define FLAG_CLOCK 0x01 +#define FLAG_CACHE 0x02 +#define FLAG_PS2 0x04 +#define FLAG_PCI 0x08 + +enum { + STATE_RESET = 0, + STATE_MAIN_IBF, + STATE_MAIN_KBD, + STATE_MAIN_AUX, + STATE_MAIN_BOTH, + STATE_KBC_OUT, + STATE_KBC_PARAM, + STATE_SEND_KBD, + STATE_SCAN_KBD, + STATE_SEND_AUX, + STATE_SCAN_AUX +}; + +typedef struct { + uint8_t state, command, command_phase, status, + wantdata, ib, ob, sc_or, + mem_addr, p1, p2, old_p2, + misc_flags, ami_flags, key_ctrl_queue_start, key_ctrl_queue_end; + + uint8_t mem[0x100]; + + /* Internal FIFO for the purpose of commands with multi-byte output. */ + uint8_t key_ctrl_queue[64]; + + uint32_t flags; + + /* Main timer. */ + pc_timer_t send_delay_timer; + + /* P2 pulse callback timer. */ + pc_timer_t pulse_cb; + + /* Local copies of the pointers to both ports for easier swapping (AMI '5' MegaKey). */ + kbc_at_port_t *ports[2]; + + uint8_t (*write60_ven)(void *p, uint8_t val); + uint8_t (*write64_ven)(void *p, uint8_t val); +} atkbc_t; + +/* Keyboard controller ports. */ +kbc_at_port_t *kbc_at_ports[2] = { NULL, NULL }; + +/* 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 +}; + +#ifdef ENABLE_KBC_AT_LOG +int kbc_at_do_log = ENABLE_KBC_AT_LOG; + +static void +kbc_at_log(const char *fmt, ...) +{ + va_list ap; + + if (kbc_at_do_log) { + va_start(ap, fmt); + pclog_ex(fmt, ap); + va_end(ap); + } +} +#else +# define kbc_at_log(fmt, ...) +#endif + +static void +kbc_at_queue_reset(atkbc_t *dev) +{ + 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_at_queue_add(atkbc_t *dev, uint8_t val) +{ + kbc_at_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; +} + +static int +kbc_translate(atkbc_t *dev, uint8_t val) +{ + int xt_mode = (dev->mem[0x20] & 0x20) && !(dev->misc_flags & FLAG_PS2); + 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)) { + kbc_at_log("ATkbc: 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)) { + kbc_at_log("ATkbc: 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 */ + } + + kbc_at_log("ATkbc: translate is %s, ", translate ? "on" : "off"); +#ifdef ENABLE_KEYBOARD_AT_LOG + kbc_at_log("scan code: "); + if (translate) { + kbc_at_log("%02X (original: ", (nont_to_t[val] | dev->sc_or)); + if (dev->sc_or == 0x80) + kbc_at_log("F0 "); + kbc_at_log("%02X)\n", val); + } else + kbc_at_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(atkbc_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->misc_flags & FLAG_PS2)) + stat_hi |= ((dev->p1 & 0x80) ? 0x10 : 0x00); + else + stat_hi |= 0x10; + + kbc_at_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->misc_flags & FLAG_PS2) { + 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->ob = temp; +} + +static void kbc_at_process_cmd(void *priv); + +static void +set_enable_kbd(atkbc_t *dev, uint8_t enable) +{ + dev->mem[0x20] &= 0xef; + dev->mem[0x20] |= (enable ? 0x00 : 0x10); +} + +static void +set_enable_aux(atkbc_t *dev, uint8_t enable) +{ + dev->mem[0x20] &= 0xdf; + dev->mem[0x20] |= (enable ? 0x00 : 0x20); +} + +static void +kbc_ibf_process(atkbc_t *dev) +{ + /* IBF set, process both commands and data. */ + dev->status &= ~STAT_IFULL; + dev->state = STATE_MAIN_IBF; + if (dev->status & STAT_CD) + kbc_at_process_cmd(dev); + else { + set_enable_kbd(dev, 1); + if ((dev->ports[0] != NULL) && (dev->ports[0]->priv != NULL)) { + dev->ports[0]->wantcmd = 1; + dev->ports[0]->dat = dev->ib; + dev->state = STATE_SEND_KBD; + } else + add_to_kbc_queue_front(dev, 0xfe, 1, 0x40); + } +} + +static void +kbc_scan_kbd_at(atkbc_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->ports[0] != NULL) && (dev->ports[0]->out_new != -1)) { + add_to_kbc_queue_front(dev, dev->ports[0]->out_new, 1, 0x00); + dev->ports[0]->out_new = -1; + dev->state = 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->p2 &= 0xbf; + if ((dev->ports[0] != NULL) && (dev->ports[0]->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->p1 & 0x80)) + add_to_kbc_queue_front(dev, dev->ports[0]->out_new, 1, 0x00); + dev->mem[0x2d] = (dev->ports[0]->out_new == 0xf0) ? 0x80 : 0x00; + } else + add_to_kbc_queue_front(dev, dev->ports[0]->out_new, 1, 0x00); + dev->ports[0]->out_new = -1; + dev->state = STATE_MAIN_IBF; + } + } + } +} + +static void write_p2(atkbc_t *dev, uint8_t val); + +static void +kbc_at_poll_at(atkbc_t *dev) +{ + switch (dev->state) { + case STATE_RESET: + if (dev->status & STAT_IFULL) { + dev->status = ((dev->status & 0x0f) | 0x10) & ~STAT_IFULL; + if ((dev->status & STAT_CD) && (dev->ib == 0xaa)) + kbc_at_process_cmd(dev); + } + break; + case 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_at_process_cmd(dev); + } + } else if (dev->status & STAT_IFULL) + kbc_ibf_process(dev); + else if (!(dev->mem[0x20] & 0x10)) + dev->state = STATE_MAIN_KBD; + break; + case STATE_MAIN_KBD: + case STATE_MAIN_BOTH: + if (dev->status & STAT_IFULL) + kbc_ibf_process(dev); + else { + (void) kbc_scan_kbd_at(dev); + dev->state = STATE_MAIN_IBF; + } + break; + case STATE_KBC_OUT: + /* Keyboard controller command want to output multiple bytes. */ + if (dev->status & STAT_IFULL) { + /* Data from host aborts dumping. */ + dev->state = STATE_MAIN_IBF; + kbc_ibf_process(dev); + } + /* Do not continue dumping until OBF is clear. */ + if (!(dev->status & STAT_OFULL)) { + kbc_at_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->state = STATE_MAIN_IBF; + } + break; + case 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->state = STATE_MAIN_IBF; + + dev->status &= ~STAT_IFULL; + kbc_at_process_cmd(dev); + } + break; + case STATE_SEND_KBD: + if (!dev->ports[0]->wantcmd) + dev->state = STATE_SCAN_KBD; + break; + case STATE_SCAN_KBD: + kbc_scan_kbd_at(dev); + break; + } +} + +/* + Correct Procedure: + 1. Controller asks the device (keyboard or auxiliary device) 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(atkbc_t *dev) +{ + if ((dev->ports[0] != NULL) && (dev->ports[0]->out_new != -1)) { + kbc_at_log("ATkbc: %02X coming from channel 1\n", dev->ports[0]->out_new & 0xff); + add_to_kbc_queue_front(dev, dev->ports[0]->out_new, 1, 0x00); + dev->ports[0]->out_new = -1; + dev->state = STATE_MAIN_IBF; + return 1; + } + + return 0; +} + +static int +kbc_scan_aux_ps2(atkbc_t *dev) +{ + if ((dev->ports[1] != NULL) && (dev->ports[1]->out_new != -1)) { + kbc_at_log("ATkbc: %02X coming from channel 2\n", dev->ports[1]->out_new & 0xff); + add_to_kbc_queue_front(dev, dev->ports[1]->out_new, 2, 0x00); + dev->ports[1]->out_new = -1; + dev->state = STATE_MAIN_IBF; + return 1; + } + + return 0; +} + +static void +kbc_at_poll_ps2(atkbc_t *dev) +{ + switch (dev->state) { + case STATE_RESET: + if (dev->status & STAT_IFULL) { + dev->status = ((dev->status & 0x0f) | 0x10) & ~STAT_IFULL; + if ((dev->status & STAT_CD) && (dev->ib == 0xaa)) + kbc_at_process_cmd(dev); + } + break; + case 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->p2 &= 0xbf; + dev->state = STATE_MAIN_KBD; + } + } else { + dev->p2 &= 0xf7; + if (dev->mem[0x20] & 0x10) + dev->state = STATE_MAIN_AUX; + else { + dev->p2 &= 0xbf; + dev->state = STATE_MAIN_BOTH; + } + } + } + break; + case STATE_MAIN_KBD: + if (dev->status & STAT_IFULL) + kbc_ibf_process(dev); + else { + (void) kbc_scan_kbd_ps2(dev); + dev->state = STATE_MAIN_IBF; + } + break; + case STATE_MAIN_AUX: + if (dev->status & STAT_IFULL) + kbc_ibf_process(dev); + else { + (void) kbc_scan_aux_ps2(dev); + dev->state = STATE_MAIN_IBF; + } + break; + case STATE_MAIN_BOTH: + if (kbc_scan_kbd_ps2(dev)) + dev->state = STATE_MAIN_IBF; + else + dev->state = STATE_MAIN_AUX; + break; + case STATE_KBC_OUT: + /* Keyboard controller command want to output multiple bytes. */ + if (dev->status & STAT_IFULL) { + /* Data from host aborts dumping. */ + dev->state = STATE_MAIN_IBF; + kbc_ibf_process(dev); + } + /* Do not continue dumping until OBF is clear. */ + if (!(dev->status & STAT_OFULL)) { + kbc_at_log("ATkbc: %02X coming from channel 0\n", dev->key_ctrl_queue[dev->key_ctrl_queue_start] & 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->state = STATE_MAIN_IBF; + } + break; + case 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->state = STATE_MAIN_IBF; + + dev->status &= ~STAT_IFULL; + kbc_at_process_cmd(dev); + } + break; + case STATE_SEND_KBD: + if (!dev->ports[0]->wantcmd) + dev->state = STATE_SCAN_KBD; + break; + case STATE_SCAN_KBD: + (void) kbc_scan_kbd_ps2(dev); + break; + case STATE_SEND_AUX: + if (!dev->ports[1]->wantcmd) + dev->state = STATE_SCAN_AUX; + break; + case STATE_SCAN_AUX: + (void) kbc_scan_aux_ps2(dev); + break; + } +} + +static void +kbc_at_poll(void *priv) +{ + atkbc_t *dev = (atkbc_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->misc_flags & FLAG_PS2) + kbc_at_poll_ps2(dev); + else + kbc_at_poll_at(dev); + + if ((kbc_at_ports[0] != NULL) && (kbc_at_ports[0]->priv != NULL)) + kbc_at_ports[0]->poll(kbc_at_ports[0]->priv); + + if ((dev->misc_flags & FLAG_PS2) && (kbc_at_ports[1] != NULL) && (kbc_at_ports[1]->priv != NULL)) + kbc_at_ports[1]->poll(kbc_at_ports[1]->priv); +} + +static void +write_p2(atkbc_t *dev, uint8_t val) +{ + uint8_t old = dev->p2; + kbc_at_log("ATkbc: write P2: %02X (old: %02X)\n", val, dev->p2); + + uint8_t kbc_ven = dev->flags & KBC_VEN_MASK; + +#if 0 + /* PS/2: Handle IRQ's. */ + if (dev->misc_flags & FLAG_PS2) { + /* 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 ((mem_a20_key ^ 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. */ + kbc_at_log("write_p2(): 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->p2 = val; +} + +static void +write_p2_fast_a20(atkbc_t *dev, uint8_t val) +{ + uint8_t old = dev->p2; + kbc_at_log("ATkbc: write P2 in fast A20 mode: %02X (old: %02X)\n", val, dev->p2); + + /* 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->p2 = val; +} + +static void +write_cmd(atkbc_t *dev, uint8_t val) +{ + kbc_at_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->misc_flags & FLAG_PS2)) { + if (val & 0x10) + dev->mem[0x2e] = 0x01; + } + + kbc_at_log("ATkbc: keyboard interrupt is now %s\n", (val & 0x01) ? "enabled" : "disabled"); + + if (!(dev->misc_flags & FLAG_PS2)) { + /* Update P2 to mirror the IBF and OBF bits, if active. */ + write_p2(dev, (dev->p2 & 0x0f) | ((val & 0x03) << 4) | ((val & 0x20) ? 0xc0 : 0x00)); + } + + kbc_at_log("ATkbc: Command byte now: %02X (%02X)\n", dev->mem[0x20], val); + + dev->status = (dev->status & ~STAT_SYSFLAG) | (val & STAT_SYSFLAG); +} + +static void +pulse_output(atkbc_t *dev, uint8_t mask) +{ + if (mask != 0x0f) { + dev->old_p2 = dev->p2 & ~(0xf0 | mask); + kbc_at_log("ATkbc: pulse_output(): P2 now: %02X\n", dev->p2 & (0xf0 | mask)); + write_p2(dev, dev->p2 & (0xf0 | mask)); + timer_set_delay_u64(&dev->pulse_cb, 6ULL * TIMER_USEC); + } +} + +static void +pulse_poll(void *priv) +{ + atkbc_t *dev = (atkbc_t *) priv; + + kbc_at_log("ATkbc: pulse_poll(): P2 now: %02X\n", dev->p2 | dev->old_p2); + write_p2(dev, dev->p2 | dev->old_p2); +} + +static uint8_t +write64_generic(void *priv, uint8_t val) +{ + atkbc_t *dev = (atkbc_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->misc_flags & FLAG_PS2) { + kbc_at_log("ATkbc: check if password installed\n"); + add_to_kbc_queue_front(dev, 0xf1, 0, 0x00); + return 0; + } + break; + + case 0xa7: /* disable auxiliary port */ + if (dev->misc_flags & FLAG_PS2) { + kbc_at_log("ATkbc: disable auxiliary port\n"); + set_enable_aux(dev, 0); + return 0; + } + break; + + case 0xa8: /* Enable auxiliary port */ + if (dev->misc_flags & FLAG_PS2) { + kbc_at_log("ATkbc: enable auxiliary port\n"); + set_enable_aux(dev, 1); + return 0; + } + break; + + case 0xa9: /* Test auxiliary port */ + kbc_at_log("ATkbc: test auxiliary port\n"); + if (dev->misc_flags & FLAG_PS2) { + 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 */ + kbc_at_log("ATkbc: read keyboard version\n"); + add_to_kbc_queue_front(dev, 0x42, 0, 0x00); + return 0; + + case 0xc0: /* read P1 */ + kbc_at_log("ATkbc: read P1\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->p1 | fixed_bits | (fdd_is_525(current_drive) ? 0x40 : 0x00), + 0, 0x00); + dev->p1 = ((dev->p1 + 1) & 3) | (dev->p1 & 0xfc) | (fdd_is_525(current_drive) ? 0x40 : 0x00); + } else if (kbc_ven == KBC_VEN_NCR) { + /* switch settings + * bit 7: keyboard disable + * 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->p1 | fixed_bits | (video_is_mda() ? 0x40 : 0x00) | (hasfpu ? 0x08 : 0x00)) & 0xdf, + 0, 0x00); + dev->p1 = ((dev->p1 + 1) & 3) | (dev->p1 & 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->misc_flags & FLAG_PCI) + fixed_bits |= 8; + add_to_kbc_queue_front(dev, dev->p1 | 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->p1 | fixed_bits) & + (((dev->flags & KBC_VEN_MASK) == KBC_VEN_ACER) ? 0xeb : 0xef), 0, 0x00); +#else + add_to_kbc_queue_front(dev, ((dev->p1 | fixed_bits) & 0xf0) | (((dev->flags & KBC_VEN_MASK) == KBC_VEN_ACER) ? 0x08 : 0x0c), 0, 0x00); +#endif + else + add_to_kbc_queue_front(dev, dev->p1 | fixed_bits, 0, 0x00); + dev->p1 = ((dev->p1 + 1) & 3) | (dev->p1 & 0xfc); + } + return 0; + + case 0xd3: /* write auxiliary output buffer */ + if (dev->misc_flags & FLAG_PS2) { + kbc_at_log("ATkbc: write auxiliary output buffer\n"); + dev->wantdata = 1; + dev->state = STATE_KBC_PARAM; + return 0; + } + break; + + case 0xd4: /* write to auxiliary port */ + kbc_at_log("ATkbc: write to auxiliary port\n"); + dev->wantdata = 1; + dev->state = STATE_KBC_PARAM; + return 0; + + case 0xf0 ... 0xff: + kbc_at_log("ATkbc: pulse %01X\n", val & 0x0f); + pulse_output(dev, val & 0x0f); + return 0; + } + + kbc_at_log("ATkbc: bad command %02X\n", val); + return 1; +} + +static uint8_t +write60_ami(void *priv, uint8_t val) +{ + atkbc_t *dev = (atkbc_t *) priv; + + switch (dev->command) { + /* 0x40 - 0x5F are aliases for 0x60-0x7F */ + case 0x40 ... 0x5f: + kbc_at_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 */ + kbc_at_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 */ + kbc_at_log("ATkbc: AMI - set extended controller RAM\n"); + if (dev->command_phase == 1) { + dev->mem_addr = val; + dev->wantdata = 1; + dev->state = STATE_KBC_PARAM; + dev->command_phase = 2; + } else if (dev->command_phase == 2) { + dev->mem[dev->mem_addr] = val; + dev->command_phase = 0; + } + return 0; + + case 0xc1: + kbc_at_log("ATkbc: AMI MegaKey - write %02X to P1\n", val); + dev->p1 = val; + return 0; + + case 0xcb: /* set keyboard mode */ + kbc_at_log("ATkbc: AMI - set keyboard mode\n"); + dev->ami_flags = val; + dev->misc_flags &= ~FLAG_PS2; + if (val & 0x01) + dev->misc_flags |= FLAG_PS2; + return 0; + } + + return 1; +} + +static uint8_t +write64_ami(void *priv, uint8_t val) +{ + atkbc_t *dev = (atkbc_t *) priv; + uint8_t kbc_ven = dev->flags & KBC_VEN_MASK; + + switch (val) { + case 0x00 ... 0x1f: + kbc_at_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: + kbc_at_log("ATkbc: AMI - alias write to %08X\n", dev->command); + dev->wantdata = 1; + dev->state = STATE_KBC_PARAM; + return 0; + + case 0xa0: /* copyright message */ + kbc_at_queue_add(dev, 0x28); + kbc_at_queue_add(dev, 0x00); + dev->state = STATE_KBC_OUT; + break; + + case 0xa1: /* get controller version */ + kbc_at_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->misc_flags & FLAG_PS2)) { + kbc_at_log("ATkbc: AMI - clear KBC lines P22 and P23\n"); + write_p2(dev, dev->p2 & 0xf3); + add_to_kbc_queue_front(dev, 0x00, 0, 0x00); + return 0; + } + break; + + case 0xa3: /* set keyboard controller lines P22/P23 */ + if (!(dev->misc_flags & FLAG_PS2)) { + kbc_at_log("ATkbc: AMI - set KBC lines P22 and P23\n"); + write_p2(dev, dev->p2 | 0x0c); + add_to_kbc_queue_front(dev, 0x00, 0, 0x00); + return 0; + } + break; + + case 0xa4: /* write clock = low */ + if (!(dev->misc_flags & FLAG_PS2)) { + kbc_at_log("ATkbc: AMI - write clock = low\n"); + dev->misc_flags &= ~FLAG_CLOCK; + return 0; + } + break; + + case 0xa5: /* write clock = high */ + if (!(dev->misc_flags & FLAG_PS2)) { + kbc_at_log("ATkbc: AMI - write clock = high\n"); + dev->misc_flags |= FLAG_CLOCK; + } else { + kbc_at_log("ATkbc: get extended controller RAM\n"); + dev->wantdata = 1; + dev->state = STATE_KBC_PARAM; + } + return 0; + + case 0xa6: /* read clock */ + if (!(dev->misc_flags & FLAG_PS2)) { + kbc_at_log("ATkbc: AMI - read clock\n"); + add_to_kbc_queue_front(dev, (dev->misc_flags & FLAG_CLOCK) ? 0xff : 0x00, 0, 0x00); + return 0; + } + break; + + case 0xa7: /* write cache bad */ + if (!(dev->misc_flags & FLAG_PS2)) { + kbc_at_log("ATkbc: AMI - write cache bad\n"); + dev->misc_flags &= FLAG_CACHE; + return 0; + } + break; + + case 0xa8: /* write cache good */ + if (!(dev->misc_flags & FLAG_PS2)) { + kbc_at_log("ATkbc: AMI - write cache good\n"); + dev->misc_flags |= FLAG_CACHE; + return 0; + } + break; + + case 0xa9: /* read cache */ + if (!(dev->misc_flags & FLAG_PS2)) { + kbc_at_log("ATkbc: AMI - read cache\n"); + add_to_kbc_queue_front(dev, (dev->misc_flags & FLAG_CACHE) ? 0xff : 0x00, 0, 0x00); + return 0; + } + break; + + case 0xaf: /* set extended controller RAM */ + if (kbc_ven == KBC_VEN_ALI) { + kbc_at_log("ATkbc: Award/ALi/VIA keyboard controller revision\n"); + add_to_kbc_queue_front(dev, 0x43, 0, 0x00); + } else { + kbc_at_log("ATkbc: set extended controller RAM\n"); + dev->wantdata = 1; + dev->state = STATE_KBC_PARAM; + dev->command_phase = 1; + } + return 0; + + case 0xb0 ... 0xb3: + /* set KBC lines P10-P13 (P1 bits 0-3) low */ + kbc_at_log("ATkbc: set KBC lines P10-P13 (P1 bits 0-3) low\n"); + if (!(dev->flags & DEVICE_PCI) || (val > 0xb1)) + dev->p1 &= ~(1 << (val & 0x03)); + add_to_kbc_queue_front(dev, 0x00, 0, 0x00); + return 0; + + case 0xb4: case 0xb5: + /* set KBC lines P22-P23 (P2 bits 2-3) low */ + kbc_at_log("ATkbc: set KBC lines P22-P23 (P2 bits 2-3) low\n"); + if (!(dev->flags & DEVICE_PCI)) + write_p2(dev, dev->p2 & ~(4 << (val & 0x01))); + add_to_kbc_queue_front(dev, 0x00, 0, 0x00); + return 0; + + case 0xb8 ... 0xbb: + /* set KBC lines P10-P13 (P1 bits 0-3) high */ + kbc_at_log("ATkbc: set KBC lines P10-P13 (P1 bits 0-3) high\n"); + if (!(dev->flags & DEVICE_PCI) || (val > 0xb9)) { + dev->p1 |= (1 << (val & 0x03)); + add_to_kbc_queue_front(dev, 0x00, 0, 0x00); + } + return 0; + + case 0xbc: case 0xbd: + /* set KBC lines P22-P23 (P2 bits 2-3) high */ + kbc_at_log("ATkbc: set KBC lines P22-P23 (P2 bits 2-3) high\n"); + if (!(dev->flags & DEVICE_PCI)) + write_p2(dev, dev->p2 | (4 << (val & 0x01))); + add_to_kbc_queue_front(dev, 0x00, 0, 0x00); + return 0; + + case 0xc1: /* write P1 */ + kbc_at_log("ATkbc: AMI MegaKey - write P1\n"); + dev->wantdata = 1; + dev->state = STATE_KBC_PARAM; + return 0; + + case 0xc4: + /* set KBC line P14 low */ + kbc_at_log("ATkbc: set KBC line P14 (P1 bit 4) low\n"); + dev->p1 &= 0xef; + add_to_kbc_queue_front(dev, 0x00, 0, 0x00); + return 0; + case 0xc5: + /* set KBC line P15 low */ + kbc_at_log("ATkbc: set KBC line P15 (P1 bit 5) low\n"); + dev->p1 &= 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 P2) + */ + kbc_at_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) + */ + kbc_at_log("ATkbc: AMI - block KBC lines P22 and P23\n"); + dev->ami_flags |= 0x04; + return 0; + + case 0xcc: + /* set KBC line P14 high */ + kbc_at_log("ATkbc: set KBC line P14 (P1 bit 4) high\n"); + dev->p1 |= 0x10; + add_to_kbc_queue_front(dev, 0x00, 0, 0x00); + return 0; + case 0xcd: + /* set KBC line P15 high */ + kbc_at_log("ATkbc: set KBC line P15 (P1 bit 5) high\n"); + dev->p1 |= 0x20; + add_to_kbc_queue_front(dev, 0x00, 0, 0x00); + return 0; + + case 0xef: /* ??? - sent by AMI486 */ + kbc_at_log("ATkbc: ??? - sent by AMI486\n"); + return 0; + } + + return write64_generic(dev, val); +} + +static uint8_t +write64_ibm_mca(void *priv, uint8_t val) +{ + atkbc_t *dev = (atkbc_t *) priv; + + switch (val) { + case 0xc1: /*Copy bits 0 to 3 of P1 to status bits 4 to 7*/ + kbc_at_log("ATkbc: copy bits 0 to 3 of P1 to status bits 4 to 7\n"); + dev->status &= 0x0f; + dev->status |= ((((dev->p1 & 0xfc) | 0x84) & 0x0f) << 4); + return 0; + + case 0xc2: /*Copy bits 4 to 7 of P1 to status bits 4 to 7*/ + kbc_at_log("ATkbc: copy bits 4 to 7 of P1 to status bits 4 to 7\n"); + dev->status &= 0x0f; + dev->status |= (((dev->p1 & 0xfc) | 0x84) & 0xf0); + return 0; + + case 0xaf: + kbc_at_log("ATkbc: bad KBC command AF\n"); + return 1; + + case 0xf0 ... 0xff: + kbc_at_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) +{ + atkbc_t *dev = (atkbc_t *) priv; + + switch (dev->command) { + case 0xcf: /*??? - sent by MegaPC BIOS*/ + kbc_at_log("ATkbc: ??? - sent by MegaPC BIOS\n"); + return 0; + } + + return 1; +} + +static uint8_t +write64_olivetti(void *priv, uint8_t val) +{ + atkbc_t *dev = (atkbc_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->p1 = ((dev->p1 + 1) & 3) | (dev->p1 & 0xfc); + return 0; + } + + return write64_generic(dev, val); +} + +static uint8_t +write64_quadtel(void *priv, uint8_t val) +{ + atkbc_t *dev = (atkbc_t *) priv; + + switch (val) { + case 0xaf: + kbc_at_log("ATkbc: bad KBC command AF\n"); + return 1; + + case 0xcf: /*??? - sent by MegaPC BIOS*/ + kbc_at_log("ATkbc: ??? - sent by MegaPC BIOS\n"); + dev->wantdata = 1; + dev->state = STATE_KBC_PARAM; + return 0; + } + + return write64_generic(dev, val); +} + +static uint8_t +write60_toshiba(void *priv, uint8_t val) +{ + atkbc_t *dev = (atkbc_t *) priv; + + switch (dev->command) { + case 0xb6: /* T3100e - set color/mono switch */ + kbc_at_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) +{ + atkbc_t *dev = (atkbc_t *) priv; + + switch (val) { + case 0xaf: + kbc_at_log("ATkbc: bad KBC command AF\n"); + return 1; + + case 0xb0: /* T3100e: Turbo on */ + kbc_at_log("ATkbc: T3100e: Turbo on\n"); + t3100e_turbo_set(1); + return 0; + + case 0xb1: /* T3100e: Turbo off */ + kbc_at_log("ATkbc: T3100e: Turbo off\n"); + t3100e_turbo_set(0); + return 0; + + case 0xb2: /* T3100e: Select external display */ + kbc_at_log("ATkbc: T3100e: Select external display\n"); + t3100e_display_set(0x00); + return 0; + + case 0xb3: /* T3100e: Select internal display */ + kbc_at_log("ATkbc: T3100e: Select internal display\n"); + t3100e_display_set(0x01); + return 0; + + case 0xb4: /* T3100e: Get configuration / status */ + kbc_at_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 */ + kbc_at_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 */ + kbc_at_log("ATkbc: T3100e: Set colour / mono byte\n"); + dev->wantdata = 1; + dev->state = 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) { + kbc_at_log("ATkbc: T3100e: Emulate PS/2 keyboard\n"); + dev->flags |= KBC_TYPE_PS2_NOREF; + } else { + kbc_at_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'. */ + kbc_at_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 */ + kbc_at_log("ATkbc: T3100e: Reset Fn+Key notification\n"); + t3100e_notify_set(0x00); + return 0; + + case 0xc0: /* Read P1 */ + kbc_at_log("ATkbc: read P1\n"); + + /* The T3100e returns all bits set except bit 6 which + * is set by t3100e_mono_set() */ + dev->p1 = (t3100e_mono_get() & 1) ? 0xff : 0xbf; + add_to_kbc_queue_front(dev, dev->p1, 0, 0x00); + return 0; + } + + return write64_generic(dev, val); +} + +static void +kbc_at_process_cmd(void *priv) +{ + atkbc_t *dev = (atkbc_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->wantdata = 0; + dev->state = STATE_MAIN_IBF; + + /* Clear the keyboard controller queue. */ + kbc_at_queue_reset(dev); + + 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->wantdata = 1; + dev->state = STATE_KBC_PARAM; + break; + + case 0xaa: /* self-test */ + kbc_at_log("ATkbc: self-test\n"); + + if ((dev->flags & KBC_TYPE_MASK) >= KBC_TYPE_PS2_NOREF) { + if (dev->state != STATE_RESET) { + kbc_at_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->p1 = dev->p1 & 0xff; + write_p2(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->state != STATE_RESET) { + kbc_at_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->p1 = dev->p1 & 0xff; + write_p2(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; + } + + if (dev->ports[0] != NULL) + dev->ports[0]->out_new = -1; + if (dev->ports[1] != NULL) + dev->ports[1]->out_new = -1; + kbc_at_queue_reset(dev); + + // dev->state = STATE_MAIN_IBF; + dev->state = STATE_KBC_OUT; + + // add_to_kbc_queue_front(dev, 0x55, 0, 0x00); + kbc_at_queue_add(dev, 0x55); + break; + + case 0xab: /* interface test */ + kbc_at_log("ATkbc: interface test\n"); + add_to_kbc_queue_front(dev, 0x00, 0, 0x00); /*no error*/ + break; + + case 0xac: /* diagnostic dump */ + if (dev->misc_flags & FLAG_PS2) { + kbc_at_log("ATkbc: diagnostic dump\n"); + dev->mem[0x30] = (dev->p1 & 0xf0) | 0x80; + dev->mem[0x31] = dev->p2; + 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_at_queue_add(dev, cmd_ac_conv[dev->mem[i + 0x20] >> 4]); + kbc_at_queue_add(dev, cmd_ac_conv[dev->mem[i + 0x20] & 0x0f]); + kbc_at_queue_add(dev, 0x39); + } + dev->state = STATE_KBC_OUT; + } + break; + + case 0xad: /* disable keyboard */ + kbc_at_log("ATkbc: disable keyboard\n"); + set_enable_kbd(dev, 0); + break; + + case 0xae: /* enable keyboard */ + kbc_at_log("ATkbc: enable keyboard\n"); + set_enable_kbd(dev, 1); + break; + + case 0xc7: /* set port1 bits */ + kbc_at_log("ATkbc: Phoenix - set port1 bits\n"); + dev->wantdata = 1; + dev->state = STATE_KBC_PARAM; + break; + + case 0xca: /* read keyboard mode */ + kbc_at_log("ATkbc: AMI - read keyboard mode\n"); + add_to_kbc_queue_front(dev, dev->ami_flags, 0, 0x00); + break; + + case 0xcb: /* set keyboard mode */ + kbc_at_log("ATkbc: AMI - set keyboard mode\n"); + dev->wantdata = 1; + dev->state = STATE_KBC_PARAM; + break; + + case 0xd0: /* read P2 */ + kbc_at_log("ATkbc: read P2\n"); + mask = 0xff; + if ((kbc_ven != KBC_VEN_OLIVETTI) && !(dev->misc_flags & FLAG_PS2) && (dev->mem[0x20] & 0x10)) + mask &= 0xbf; + add_to_kbc_queue_front(dev, (((dev->p2 & 0xfd) | mem_a20_key) & mask), 0, 0x00); + break; + + case 0xd1: /* write P2 */ + kbc_at_log("ATkbc: write P2\n"); + dev->wantdata = 1; + dev->state = STATE_KBC_PARAM; + break; + + case 0xd2: /* write keyboard output buffer */ + kbc_at_log("ATkbc: write keyboard output buffer\n"); + dev->wantdata = 1; + dev->state = STATE_KBC_PARAM; + break; + + case 0xdd: /* disable A20 address line */ + case 0xdf: /* enable A20 address line */ + kbc_at_log("ATkbc: %sable A20\n", (dev->ib == 0xdd) ? "dis" : "en"); + write_p2_fast_a20(dev, (dev->p2 & 0xfd) | (dev->ib & 0x02)); + break; + + case 0xe0: /* read test inputs */ + kbc_at_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); + + kbc_at_log(bad ? "ATkbc: bad controller command %02X\n" : "", dev->ib); + } + + /* If the command needs data, remember the command. */ + if (dev->wantdata) + dev->command = dev->ib; + } else if (dev->wantdata) { + /* Write data to controller. */ + dev->wantdata = 0; + dev->state = 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 */ + kbc_at_log("ATkbc: Phoenix - set port1 bits\n"); + dev->p1 |= dev->ib; + break; + + case 0xd1: /* write P2 */ + kbc_at_log("ATkbc: write P2\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->p2 & 0x0c); + } + write_p2(dev, dev->ib | 0x01); + break; + + case 0xd2: /* write to keyboard output buffer */ + kbc_at_log("ATkbc: write to keyboard output buffer\n"); + add_to_kbc_queue_front(dev, dev->ib, 0, 0x00); + break; + + case 0xd3: /* write to auxiliary output buffer */ + kbc_at_log("ATkbc: write to auxiliary output buffer\n"); + add_to_kbc_queue_front(dev, dev->ib, 2, 0x00); + break; + + case 0xd4: /* write to auxiliary port */ + kbc_at_log("ATkbc: write to auxiliary port (%02X)\n", dev->ib); + + if (dev->ib == 0xbb) + break; + + if ((dev->flags & KBC_TYPE_MASK) >= KBC_TYPE_PS2_NOREF) { + set_enable_aux(dev, 1); + if ((dev->ports[1] != NULL) && (dev->ports[1]->priv != NULL)) { + dev->ports[1]->wantcmd = 1; + dev->ports[1]->dat = dev->ib; + dev->state = STATE_SEND_AUX; + } 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) { + kbc_at_log("ATkbc: bad controller command %02x data %02x\n", dev->command, dev->ib); + } + } + } +} + +static void +kbc_at_write(uint16_t port, uint8_t val, void *priv) +{ + atkbc_t *dev = (atkbc_t *) priv; + + kbc_at_log("ATkbc: [%04X:%08X] write(%04X) = %02X\n", CS, cpu_state.pc, port, val); + + switch (port) { + case 0x60: + dev->status &= ~STAT_CD; + if (dev->wantdata && (dev->command == 0xd1)) { + kbc_at_log("ATkbc: write P2\n"); + + /* Fast A20 - ignore all other bits. */ + val = (val & 0x02) | (dev->p2 & 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->p2 & 0x0c); + } + + write_p2_fast_a20(dev, val | 0x01); + + dev->wantdata = 0; + dev->state = STATE_MAIN_IBF; + return; + } + break; + + case 0x64: + dev->status |= STAT_CD; + if (val == 0xd1) { + kbc_at_log("ATkbc: write P2\n"); + dev->wantdata = 1; + dev->state = STATE_KBC_PARAM; + dev->command = 0xd1; + return; + } + break; + } + + dev->ib = val; + dev->status |= STAT_IFULL; +} + +static uint8_t +kbc_at_read(uint16_t port, void *priv) +{ + atkbc_t *dev = (atkbc_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->ob; + 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 P2 bit. + This also means that in AT mode, the IRQ is level-triggered. */ + if (!(dev->misc_flags & FLAG_PS2)) + picintc(1 << 1); + break; + + case 0x64: + ret = dev->status; + break; + + default: + kbc_at_log("ATkbc: read(%04x) invalid!\n",port); + break; + } + + kbc_at_log("ATkbc: [%04X:%08X] read (%04X) = %02X\n", CS, cpu_state.pc, port, ret); + + return (ret); +} + +static void +kbc_at_reset(void *priv) +{ + atkbc_t *dev = (atkbc_t *) priv; + uint8_t kbc_ven = dev->flags & KBC_VEN_MASK; + + dev->status = STAT_UNLOCKED; + dev->mem[0x20] = 0x01; + dev->mem[0x20] |= CCB_TRANSLATE; + dev->command_phase = 0; + + /* Set up the correct Video Type bits. */ + if (!is286 || (kbc_ven == KBC_VEN_ACER)) + dev->p1 = video_is_mda() ? 0xb0 : 0xf0; + else + dev->p1 = video_is_mda() ? 0xf0 : 0xb0; + kbc_at_log("ATkbc: P1 = %02x\n", dev->p1); + + /* Disabled both the keyboard and auxiliary ports. */ + set_enable_kbd(dev, 0); + set_enable_aux(dev, 0); + + kbc_at_queue_reset(dev); + + dev->sc_or = 0; + + dev->ami_flags = ((dev->flags & KBC_TYPE_MASK) >= KBC_TYPE_PS2_NOREF) ? 0x01 : 0x00; + + if ((dev->flags & KBC_TYPE_MASK) >= KBC_TYPE_PS2_NOREF) + dev->misc_flags |= FLAG_PS2; + dev->misc_flags |= FLAG_CACHE; + + dev->p2 = 0xcd; + if ((dev->flags & KBC_TYPE_MASK) >= KBC_TYPE_PS2_NOREF) { + write_p2(dev, 0x4b); + } else { + /* The real thing writes CF and then AND's it with BF. */ + write_p2(dev, 0x8f); + } + + /* Stage 1. */ + dev->status = (dev->status & 0x0f) | (dev->p1 & 0xf0); +} + +static void +kbc_at_close(void *priv) +{ + atkbc_t *dev = (atkbc_t *) priv; + int i, max_ports = ((dev->flags & KBC_TYPE_MASK) >= KBC_TYPE_PS2_NOREF) ? 2 : 1; + + kbc_at_reset(dev); + + /* Stop timers. */ + timer_disable(&dev->send_delay_timer); + + for (i = 0; i < max_ports; i++) { + if (kbc_at_ports[i] != NULL) { + free(kbc_at_ports[i]); + kbc_at_ports[i] = NULL; + } + } + + free(dev); +} + +static void * +kbc_at_init(const device_t *info) +{ + atkbc_t *dev; + int i, max_ports; + + dev = (atkbc_t *) malloc(sizeof(atkbc_t)); + memset(dev, 0x00, sizeof(atkbc_t)); + + dev->flags = info->local; + + if (info->flags & DEVICE_PCI) + dev->misc_flags |= FLAG_PCI; + + video_reset(gfxcard[0]); + kbc_at_reset(dev); + + io_sethandler(0x0060, 1, kbc_at_read, NULL, NULL, kbc_at_write, NULL, NULL, dev); + io_sethandler(0x0064, 1, kbc_at_read, NULL, NULL, kbc_at_write, NULL, NULL, dev); + + timer_add(&dev->send_delay_timer, kbc_at_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_at_ports[i] = (kbc_at_port_t *) malloc(sizeof(kbc_at_port_t)); + memset(kbc_at_ports[i], 0x00, sizeof(kbc_at_port_t)); + kbc_at_ports[i]->out_new = -1; + } + + dev->ports[0] = kbc_at_ports[0]; + dev->ports[1] = kbc_at_ports[1]; + + /* The actual keyboard. */ + device_add(&keyboard_at_generic_device); + + return (dev); +} + +const device_t keyboard_at_device = { + .name = "PC/AT Keyboard", + .internal_name = "keyboard_at", + .flags = DEVICE_KBC, + .local = KBC_TYPE_ISA | KBC_VEN_GENERIC, + .init = kbc_at_init, + .close = kbc_at_close, + .reset = kbc_at_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 = DEVICE_KBC, + .local = KBC_TYPE_ISA | KBC_VEN_AMI, + .init = kbc_at_init, + .close = kbc_at_close, + .reset = kbc_at_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 = DEVICE_KBC, + .local = KBC_TYPE_ISA | KBC_VEN_TG, + .init = kbc_at_init, + .close = kbc_at_close, + .reset = kbc_at_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 = DEVICE_KBC, + .local = KBC_TYPE_ISA | KBC_VEN_TOSHIBA, + .init = kbc_at_init, + .close = kbc_at_close, + .reset = kbc_at_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 = DEVICE_KBC, + .local = KBC_TYPE_ISA | KBC_VEN_OLIVETTI, + .init = kbc_at_init, + .close = kbc_at_close, + .reset = kbc_at_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 = DEVICE_KBC, + .local = KBC_TYPE_ISA | KBC_VEN_NCR, + .init = kbc_at_init, + .close = kbc_at_close, + .reset = kbc_at_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 = DEVICE_KBC, + .local = KBC_TYPE_PS2_NOREF | KBC_VEN_GENERIC, + .init = kbc_at_init, + .close = kbc_at_close, + .reset = kbc_at_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 = DEVICE_KBC, + .local = KBC_TYPE_PS2_NOREF | KBC_VEN_IBM_PS1, + .init = kbc_at_init, + .close = kbc_at_close, + .reset = kbc_at_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_KBC | DEVICE_PCI, + .local = KBC_TYPE_PS2_NOREF | KBC_VEN_IBM_PS1, + .init = kbc_at_init, + .close = kbc_at_close, + .reset = kbc_at_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 = DEVICE_KBC, + .local = KBC_TYPE_PS2_1 | KBC_VEN_GENERIC, + .init = kbc_at_init, + .close = kbc_at_close, + .reset = kbc_at_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 = DEVICE_KBC, + .local = KBC_TYPE_PS2_NOREF | KBC_VEN_AMI, + .init = kbc_at_init, + .close = kbc_at_close, + .reset = kbc_at_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 = DEVICE_KBC, + .local = KBC_TYPE_PS2_NOREF | KBC_VEN_TG, + .init = kbc_at_init, + .close = kbc_at_close, + .reset = kbc_at_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 = DEVICE_KBC, + .local = KBC_TYPE_PS2_1 | KBC_VEN_IBM_MCA, + .init = kbc_at_init, + .close = kbc_at_close, + .reset = kbc_at_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 = DEVICE_KBC, + .local = KBC_TYPE_PS2_2 | KBC_VEN_IBM_MCA, + .init = kbc_at_init, + .close = kbc_at_close, + .reset = kbc_at_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 = DEVICE_KBC, + .local = KBC_TYPE_PS2_NOREF | KBC_VEN_QUADTEL, + .init = kbc_at_init, + .close = kbc_at_close, + .reset = kbc_at_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_KBC | DEVICE_PCI, + .local = KBC_TYPE_PS2_NOREF | KBC_VEN_GENERIC, + .init = kbc_at_init, + .close = kbc_at_close, + .reset = kbc_at_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_KBC | DEVICE_PCI, + .local = KBC_TYPE_PS2_NOREF | KBC_VEN_AMI, + .init = kbc_at_init, + .close = kbc_at_close, + .reset = kbc_at_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_KBC | DEVICE_PCI, + .local = KBC_TYPE_PS2_NOREF | KBC_VEN_ALI, + .init = kbc_at_init, + .close = kbc_at_close, + .reset = kbc_at_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_KBC | DEVICE_PCI, + .local = KBC_TYPE_PS2_NOREF | KBC_VEN_INTEL_AMI, + .init = kbc_at_init, + .close = kbc_at_close, + .reset = kbc_at_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_KBC | DEVICE_PCI, + .local = KBC_TYPE_PS2_NOREF | KBC_VEN_TG, + .init = kbc_at_init, + .close = kbc_at_close, + .reset = kbc_at_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_KBC | DEVICE_PCI, + .local = KBC_TYPE_PS2_NOREF | KBC_VEN_ACER, + .init = kbc_at_init, + .close = kbc_at_close, + .reset = kbc_at_reset, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL +}; diff --git a/src/device/kbc_at_dev.c b/src/device/kbc_at_dev.c new file mode 100644 index 000000000..a2baa21a0 --- /dev/null +++ b/src/device/kbc_at_dev.c @@ -0,0 +1,198 @@ +/* + * 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. + * + * AT / PS/2 attached device emulation. + * + * + * + * Authors: Miran Grca, + * + * Copyright 2023 Miran Grca. + */ +#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> + +#ifdef ENABLE_KBC_AT_DEV_LOG +int kbc_at_dev_do_log = ENABLE_KBC_AT_DEV_LOG; + +static void +kbc_at_dev_log(const char *fmt, ...) +{ + va_list ap; + + if (kbc_at_dev_do_log) { + va_start(ap, fmt); + pclog_ex(fmt, ap); + va_end(ap); + } +} +#else +# define kbc_at_dev_log(fmt, ...) +#endif + +static void +kbc_at_dev_queue_reset(atkbc_dev_t *dev, uint8_t reset_main) +{ + if (reset_main) { + dev->queue_start = dev->queue_end = 0; + memset(dev->queue, 0x00, sizeof(dev->queue)); + } + + dev->cmd_queue_start = dev->cmd_queue_end = 0; + memset(dev->cmd_queue, 0x00, sizeof(dev->cmd_queue)); +} + +uint8_t +kbc_at_dev_queue_pos(atkbc_dev_t *dev, uint8_t main) +{ + uint8_t ret; + + if (main) + ret = ((dev->queue_end - dev->queue_start) & 0xf); + else + ret = ((dev->cmd_queue_end - dev->cmd_queue_start) & 0xf); + + return ret; +} + +void +kbc_at_dev_queue_add(atkbc_dev_t *dev, uint8_t val, uint8_t main) +{ + if (main) { + kbc_at_dev_log("%s: dev->queue[%02X] = %02X;\n", dev->name, dev->queue_end, val); + dev->queue[dev->queue_end] = val; + dev->queue_end = (dev->queue_end + 1) & 0xf; + } else { + kbc_at_dev_log("%s: dev->cmd_queue[%02X] = %02X;\n", dev->name, dev->cmd_queue_end, val); + dev->cmd_queue[dev->cmd_queue_end] = val; + dev->cmd_queue_end = (dev->cmd_queue_end + 1) & 0xf; + } + + /* TODO: This should be done on actual send to host. */ + if (val != 0xfe) + dev->last_scan_code = val; +} + +static void +kbc_at_dev_poll(void *priv) +{ + atkbc_dev_t *dev = (atkbc_dev_t *) priv; + + switch (dev->state) { + case DEV_STATE_MAIN_1: + /* Process the command if needed and then return to main loop #2. */ + if (dev->port->wantcmd) { + kbc_at_dev_log("%s: Processing keyboard command %02X...\n", dev->name, dev->port->dat); + kbc_at_dev_queue_reset(dev, 0); + dev->process_cmd(dev); + dev->port->wantcmd = 0; + } else + dev->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 (*dev->scan && (dev->port->out_new == -1) && (dev->queue_start != dev->queue_end)) { + kbc_at_dev_log("%s %1: %02X (DATA) on channel 1\n", dev->name, dev->inst, dev->queue[dev->queue_start]); + dev->port->out_new = dev->queue[dev->queue_start]; + dev->queue_start = (dev->queue_start + 1) & 0xf; + } + if (!(*dev->scan) || dev->port->wantcmd) + dev->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->port->wantcmd) { + kbc_at_dev_log("%s: Processing keyboard command %02X...\n", dev->name, dev->port->dat); + kbc_at_dev_queue_reset(dev, 0); + dev->process_cmd(dev); + dev->port->wantcmd = 0; + break; + } + /* FALLTHROUGH */ + case DEV_STATE_MAIN_WANT_IN: + /* Output command response and then return to main loop #2. */ + if ((dev->port->out_new == -1) && (dev->cmd_queue_start != dev->cmd_queue_end)) { + kbc_at_dev_log("%s: %02X (CMD ) on channel 1\n", dev->name, dev->cmd_queue[dev->cmd_queue_start]); + dev->port->out_new = dev->cmd_queue[dev->cmd_queue_start]; + dev->cmd_queue_start = (dev->cmd_queue_start + 1) & 0xf; + } + if (dev->cmd_queue_start == dev->cmd_queue_end) + dev->state = (dev->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->port->wantcmd) { + kbc_at_dev_log("%s: Processing keyboard command %02X parameter %02X...\n", dev->name, dev->command, dev->port->dat); + kbc_at_dev_queue_reset(dev, 0); + dev->process_cmd(dev); + dev->port->wantcmd = 0; + } + break; + } +} + +void +kbc_at_dev_reset(atkbc_dev_t *dev, int do_fa) +{ + dev->port->out_new = -1; + dev->port->wantcmd = 0; + + kbc_at_dev_queue_reset(dev, 1); + + dev->last_scan_code = 0x00; + + *dev->scan = 1; + + if (do_fa) + kbc_at_dev_queue_add(dev, 0xfa, 0); + + dev->execute_bat(dev); + + dev->state = DEV_STATE_MAIN_OUT; +} + +atkbc_dev_t * +kbc_at_dev_init(uint8_t inst) +{ + atkbc_dev_t *dev; + + dev = (atkbc_dev_t *) malloc(sizeof(atkbc_dev_t)); + memset(dev, 0x00, sizeof(atkbc_dev_t)); + + dev->port = kbc_at_ports[inst]; + + if (dev->port != NULL) { + dev->port->priv = dev; + dev->port->poll = kbc_at_dev_poll; + } + + /* Return our private data to the I/O layer. */ + return (dev); +} From 333e9377ff54696ed2e7f81017fdf71b9ca10c37 Mon Sep 17 00:00:00 2001 From: OBattler Date: Thu, 20 Apr 2023 02:24:03 +0200 Subject: [PATCH 07/20] Some minor CPU bugfixes - one for 808x and one for the new dynarec. --- src/cpu/808x.c | 6 +++--- src/cpu/cpu.h | 4 ++++ 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/src/cpu/808x.c b/src/cpu/808x.c index b2859153a..1a842dd9c 100644 --- a/src/cpu/808x.c +++ b/src/cpu/808x.c @@ -426,13 +426,13 @@ pfq_write(void) free in the queue. */ tempw = readmemwf(pfq_ip); *(uint16_t *) &(pfq[pfq_pos]) = tempw; - pfq_ip += 2; + pfq_ip = (pfq_ip + 2) & 0xffff; pfq_pos += 2; } else if (!is8086 && (pfq_pos < pfq_size)) { /* The 8088 fetches 1 byte at a time, and only if there's at least 1 byte free in the queue. */ pfq[pfq_pos] = readmembf(pfq_ip); - pfq_ip++; + pfq_ip = (pfq_ip + 1) & 0xffff; pfq_pos++; } } @@ -2248,7 +2248,7 @@ execx86(int cycs) default: opcode = orig_opcode; - cpu_state.pc--; + cpu_state.pc = (cpu_state.pc - 1) & 0xffff; break; } } else diff --git a/src/cpu/cpu.h b/src/cpu/cpu.h index 229fcb9bb..93dae98d1 100644 --- a/src/cpu/cpu.h +++ b/src/cpu/cpu.h @@ -416,7 +416,11 @@ typedef struct { #define CPU_STATUS_PMODE (1 << 2) #define CPU_STATUS_V86 (1 << 3) #define CPU_STATUS_SMM (1 << 4) +#ifdef USE_NEW_DYNAREC +#define CPU_STATUS_FLAGS 0xff +#else #define CPU_STATUS_FLAGS 0xffff +#endif /*If the cpu_state.flags below are set in cpu_cur_status, they must be set in block->status. Otherwise they are ignored*/ From 0458034cbfb71d06692c9e674a1eb82ed651881e Mon Sep 17 00:00:00 2001 From: OBattler Date: Thu, 20 Apr 2023 14:28:37 +0200 Subject: [PATCH 08/20] Some clean-ups. --- src/device/keyboard_at.c | 89 +++++++++++++----------------------- src/device/mouse_ps2.c | 26 +++++------ src/include/86box/keyboard.h | 13 ++---- 3 files changed, 50 insertions(+), 78 deletions(-) diff --git a/src/device/keyboard_at.c b/src/device/keyboard_at.c index ab1980b72..886016023 100644 --- a/src/device/keyboard_at.c +++ b/src/device/keyboard_at.c @@ -69,6 +69,8 @@ uint8_t keyboard_mode = 0x02; static atkbc_dev_t *SavedKbd = NULL; +static uint8_t inv_cmd_response = 0xfa; + static const scancode scancode_set1[512] = { // clang-format off { { 0},{ 0} }, { { 0x01,0},{ 0x81,0} }, { { 0x02,0},{ 0x82,0} }, { { 0x03,0},{ 0x83,0} }, /*000*/ @@ -685,7 +687,6 @@ static void keyboard_at_set_defaults(atkbc_dev_t *dev) { dev->rate = 1; - dev->flags &= FLAG_ENABLED; keyboard_set3_all_break = 0; keyboard_set3_all_repeat = 0; @@ -703,7 +704,6 @@ keyboard_at_bat(void *priv) keyboard_at_set_defaults(dev); keyboard_scan = 1; - dev->flags |= FLAG_ENABLED; kbc_at_dev_queue_add(dev, 0xaa, 0); } @@ -711,18 +711,10 @@ keyboard_at_bat(void *priv) static void keyboard_at_invalid_cmd(atkbc_dev_t *dev) { - /* The AT firmware sends FA on unknown but semantically valid (ie. >= 0xED) commands. */ - keyboard_at_log("%s: Invalid AT command [%02X]\n", dev->name, dev->port->dat); - kbc_at_dev_queue_add(dev, 0xfa, 0); + keyboard_at_log("%s: Invalid command [%02X]\n", dev->name, dev->port->dat); + kbc_at_dev_queue_add(dev, inv_cmd_response, 0); } -static void -keyboard_ps2_invalid_cmd(atkbc_dev_t *dev) -{ - /* Send FE on unknown/invalid command per the PS/2 technical reference. */ - keyboard_at_log("%s: Invalid PS/2 command [%02X]\n", dev->name, dev->port->dat); - kbc_at_dev_queue_add(dev, 0xfe, 0); -} static void keyboard_at_write(void *priv) @@ -748,20 +740,22 @@ keyboard_at_write(void *priv) case 0xf0: /* Get/set scancode set */ kbc_at_dev_queue_add(dev, (val > 3) ? 0xfe : 0xfa, 0); - if (val == 0) { - keyboard_at_log("%s: Get scan code set [%02X]\n", dev->name, keyboard_mode); - kbc_at_dev_queue_add(dev, keyboard_mode, 0); - } else { - if (val <= 3) { + switch (val) { + case 0x00: + keyboard_at_log("%s: Get scan code set [%02X]\n", dev->name, keyboard_mode); + kbc_at_dev_queue_add(dev, keyboard_mode, 0); + break; + case 0x01 ... 0x03: keyboard_mode = val; keyboard_at_log("%s: Set scan code set [%02X]\n", dev->name, keyboard_mode); keyboard_at_set_scancode_set(); - } else { + break; + default: /* Fatal so any instance of anything attempting to set scan code > 3 can be reported to us. */ fatal("%s: Scan code set [%02X] invalid, resend\n", dev->name, val); dev->flags |= FLAG_CTRLDAT; dev->state = DEV_STATE_MAIN_WANT_IN; - } + break; } break; @@ -784,23 +778,14 @@ keyboard_at_write(void *priv) } } else { if (dev->flags & FLAG_CTRLDAT) { - if (val == 0xfe) { - /* Special case - resend last scan code command during another command that wants - input - output as normal but do not cancel the command (so keep waiting for - input). */ - keyboard_at_log("%s: resend last scan code during command [%02X]\n", dev->name, dev->command); + /* Special case - another command during another command that wants input - proceed + as normal but do not cancel the command (so keep waiting for input), unless the + command in progress is ED (Set/reset LEDs). */ + if (val == 0xed) { + keyboard_scan = 1; + dev->flags &= ~FLAG_CTRLDAT; + } else dev->state = DEV_STATE_MAIN_WANT_IN; - kbc_at_dev_queue_add(dev, 0xfa, dev->last_scan_code); - } else { - /* Special case - another command during another command that wants input - proceed - as normal but do not cancel the command (so keep waiting for input), unless the - command in progress is ED (Set/reset LEDs). */ - if (dev->command == 0xed) { - keyboard_scan = 1; - dev->flags &= ~FLAG_CTRLDAT; - } else - dev->state = DEV_STATE_MAIN_WANT_IN; - } } dev->command = val; @@ -820,10 +805,8 @@ keyboard_at_write(void *priv) case 0xef: /* Invalid command */ case 0xf1: /* Invalid command */ - if (dev->type & FLAG_PS2) - keyboard_ps2_invalid_cmd(dev); - else - keyboard_at_invalid_cmd(dev); + keyboard_at_log("%s: Invalid command [%02X]\n", dev->name, dev->port->dat); + kbc_at_dev_queue_add(dev, inv_cmd_response, 0); break; case 0xf0: /* get/set scan code set */ @@ -858,7 +841,6 @@ keyboard_at_write(void *priv) case 0xf4: /* enable */ keyboard_at_log("%s: enable keyboard\n", dev->name); - dev->flags |= FLAG_ENABLED; keyboard_scan = 1; kbc_at_dev_queue_add(dev, 0xfa, 0); break; @@ -866,7 +848,7 @@ keyboard_at_write(void *priv) case 0xf5: /* set defaults and disable keyboard */ case 0xf6: /* set defaults */ keyboard_at_log("%s: set defaults%s\n", (val == 0xf6) ? "" : " and disable keyboard"); - keyboard_scan = (val == 0xf6); + keyboard_scan = !(val & 0x01); keyboard_at_log("%s: val = %02X, keyboard_scan = %i\n", dev->name, val, keyboard_scan); kbc_at_dev_queue_add(dev, 0xfa, 0); @@ -918,33 +900,24 @@ keyboard_at_write(void *priv) /* TODO: Actually implement these commands. */ case 0xfb: /* set some keys to repeat */ - if (dev->type & FLAG_PS2) { - keyboard_at_log("%s: set some keys to repeat\n", dev->name); - kbc_at_dev_queue_add(dev, 0xfe, 0); - } else - keyboard_at_invalid_cmd(dev); + keyboard_at_log("%s: set some keys to repeat\n", dev->name); + kbc_at_dev_queue_add(dev, inv_cmd_response, 0); break; case 0xfc: /* set some keys to give make/break codes */ - if (dev->type & FLAG_PS2) { - keyboard_at_log("%s: set some keys to give make/break codes\n", dev->name); - kbc_at_dev_queue_add(dev, 0xfe, 0); - } else - keyboard_at_invalid_cmd(dev); + keyboard_at_log("%s: set some keys to give make/break codes\n", dev->name); + kbc_at_dev_queue_add(dev, inv_cmd_response, 0); break; case 0xfd: /* set some keys to give make codes only */ - if (dev->type & FLAG_PS2) { - keyboard_at_log("%s: set some keys to give make codes only\n", dev->name); - kbc_at_dev_queue_add(dev, 0xfe, 0); - } else - keyboard_at_invalid_cmd(dev); + keyboard_at_log("%s: set some keys to give make codes only\n", dev->name); + kbc_at_dev_queue_add(dev, inv_cmd_response, 0); break; /* TODO: This is supposed to resend multiple bytes after some commands. */ case 0xfe: /* resend last scan code */ keyboard_at_log("%s: resend last scan code\n", dev->name); - kbc_at_dev_queue_add(dev, 0xfa, dev->last_scan_code); + kbc_at_dev_queue_add(dev, dev->last_scan_code, 0); break; case 0xff: /* reset */ @@ -992,6 +965,8 @@ keyboard_at_init(const device_t *info) keyboard_send = add_data_kbd; SavedKbd = dev; + inv_cmd_response = (dev->type & FLAG_PS2) ? 0xfe : 0xfa; + /* Return our private data to the I/O layer. */ return (dev); } diff --git a/src/device/mouse_ps2.c b/src/device/mouse_ps2.c index eae528058..4027c6173 100644 --- a/src/device/mouse_ps2.c +++ b/src/device/mouse_ps2.c @@ -134,7 +134,7 @@ ps2_set_defaults(atkbc_dev_t *dev) { dev->mode = MODE_STREAM; dev->rate = 1; - dev->flags &= (0x88 | FLAG_ENABLED); + dev->flags &= 0x88; } static void @@ -145,7 +145,6 @@ ps2_bat(void *priv) ps2_set_defaults(dev); mouse_scan = 1; - dev->flags |= FLAG_ENABLED; kbc_at_dev_queue_add(dev, 0xaa, 0); kbc_at_dev_queue_add(dev, 0x00, 0); @@ -156,6 +155,7 @@ ps2_write(void *priv) { atkbc_dev_t *dev = (atkbc_dev_t *) priv; uint8_t temp, val; + static uint8_t last_data[6] = { 0x00 }; if (dev->port == NULL) return; @@ -211,7 +211,9 @@ ps2_write(void *priv) case 0xe9: /* status request */ mouse_ps2_log("%s: Status request\n", dev->name); kbc_at_dev_queue_add(dev, 0xfa, 0); - temp = (dev->flags & 0x30); + temp = (dev->flags & 0x20); + if (mouse_scan) + temp |= FLAG_ENABLED; if (mouse_buttons & 1) temp |= 4; if (mouse_buttons & 2) @@ -255,14 +257,12 @@ ps2_write(void *priv) case 0xf4: /* enable */ mouse_ps2_log("%s: Enable\n", dev->name); - dev->flags |= FLAG_ENABLED; mouse_scan = 1; kbc_at_dev_queue_add(dev, 0xfa, 0); break; case 0xf5: /* disable */ mouse_ps2_log("%s: Disable\n", dev->name); - dev->flags &= ~FLAG_ENABLED; mouse_scan = 0; kbc_at_dev_queue_add(dev, 0xfa, 0); break; @@ -285,19 +285,19 @@ ps2_write(void *priv) if (dev->flags & FLAG_INTELLI) { for (temp = 0; temp < 5; temp++) - dev->last_data[temp] = dev->last_data[temp + 1]; + last_data[temp] = last_data[temp + 1]; - dev->last_data[5] = val; + 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)) + if ((last_data[0] == 0xf3) && (last_data[1] == 0xc8) && + (last_data[2] == 0xf3) && (last_data[3] == 0x64) && + (last_data[4] == 0xf3) && (last_data[5] == 0x50)) dev->flags |= FLAG_INTMODE; if ((dev->flags & FLAG_EXPLORER) && (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)) + (last_data[0] == 0xf3) && (last_data[1] == 0xc8) && + (last_data[2] == 0xf3) && (last_data[3] == 0xc8) && + (last_data[4] == 0xf3) && (last_data[5] == 0x50)) dev->flags |= FLAG_5BTN; } } diff --git a/src/include/86box/keyboard.h b/src/include/86box/keyboard.h index 08a425f6d..6dec8a6db 100644 --- a/src/include/86box/keyboard.h +++ b/src/include/86box/keyboard.h @@ -38,9 +38,9 @@ enum { /* Used by the AT / PS/2 keyboard controller, common device, keyboard, and mouse. */ typedef struct { - uint8_t wantcmd, dat, pad, pad0; + uint8_t wantcmd, dat; - int out_new; + int16_t out_new; void *priv; @@ -51,12 +51,9 @@ typedef struct { typedef struct { const char *name; /* name of this device */ - uint8_t type, inst, command, wantdata, - last_scan_code, state, resolution, rate, - cmd_queue_start, cmd_queue_end, queue_start, queue_end; - - /* 6 bytes needed for mouse */ - uint8_t last_data[6]; + uint8_t type, command, last_scan_code, state, + resolution, rate, cmd_queue_start, cmd_queue_end, + queue_start, queue_end; uint16_t flags; From 634ecfeab9441a8ce78419c50e833ec611dbdbd6 Mon Sep 17 00:00:00 2001 From: OBattler Date: Thu, 20 Apr 2023 14:50:44 +0200 Subject: [PATCH 09/20] More clean-ups. --- src/device/kbc_at.c | 148 +++++++++++++++++++++++--------------------- 1 file changed, 79 insertions(+), 69 deletions(-) diff --git a/src/device/kbc_at.c b/src/device/kbc_at.c index 7026815a4..287d8b4d0 100644 --- a/src/device/kbc_at.c +++ b/src/device/kbc_at.c @@ -133,6 +133,11 @@ typedef struct { /* Keyboard controller ports. */ kbc_at_port_t *kbc_at_ports[2] = { NULL, NULL }; +static uint8_t kbc_ami_revision = '8'; +static uint8_t kbc_award_revision = 0x42; + +static void (*kbc_at_do_poll)(atkbc_t *dev); + /* Non-translated to translated scan codes. */ static const uint8_t nont_to_t[256] = { 0xff, 0x43, 0x41, 0x3f, 0x3d, 0x3b, 0x3c, 0x58, @@ -619,17 +624,13 @@ kbc_at_poll(void *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->misc_flags & FLAG_PS2) - kbc_at_poll_ps2(dev); - else - kbc_at_poll_at(dev); + /* TODO: Implement the password security state. */ + kbc_at_do_poll(dev); if ((kbc_at_ports[0] != NULL) && (kbc_at_ports[0]->priv != NULL)) kbc_at_ports[0]->poll(kbc_at_ports[0]->priv); - if ((dev->misc_flags & FLAG_PS2) && (kbc_at_ports[1] != NULL) && (kbc_at_ports[1]->priv != NULL)) + if ((kbc_at_ports[1] != NULL) && (kbc_at_ports[1]->priv != NULL)) kbc_at_ports[1]->poll(kbc_at_ports[1]->priv); } @@ -793,7 +794,7 @@ write64_generic(void *priv, uint8_t val) case 0xaf: /* read keyboard version */ kbc_at_log("ATkbc: read keyboard version\n"); - add_to_kbc_queue_front(dev, 0x42, 0, 0x00); + add_to_kbc_queue_front(dev, kbc_award_revision, 0, 0x00); return 0; case 0xc0: /* read P1 */ @@ -806,7 +807,6 @@ write64_generic(void *priv, uint8_t val) current_drive = fdc_get_current_drive(); add_to_kbc_queue_front(dev, dev->p1 | fixed_bits | (fdd_is_525(current_drive) ? 0x40 : 0x00), 0, 0x00); - dev->p1 = ((dev->p1 + 1) & 3) | (dev->p1 & 0xfc) | (fdd_is_525(current_drive) ? 0x40 : 0x00); } else if (kbc_ven == KBC_VEN_NCR) { /* switch settings * bit 7: keyboard disable @@ -820,28 +820,20 @@ write64_generic(void *priv, uint8_t val) */ add_to_kbc_queue_front(dev, (dev->p1 | fixed_bits | (video_is_mda() ? 0x40 : 0x00) | (hasfpu ? 0x08 : 0x00)) & 0xdf, 0, 0x00); - dev->p1 = ((dev->p1 + 1) & 3) | (dev->p1 & 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->misc_flags & FLAG_PCI) - fixed_bits |= 8; - add_to_kbc_queue_front(dev, dev->p1 | 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->p1 | fixed_bits) & - (((dev->flags & KBC_VEN_MASK) == KBC_VEN_ACER) ? 0xeb : 0xef), 0, 0x00); -#else - add_to_kbc_queue_front(dev, ((dev->p1 | fixed_bits) & 0xf0) | (((dev->flags & KBC_VEN_MASK) == KBC_VEN_ACER) ? 0x08 : 0x0c), 0, 0x00); -#endif - else - add_to_kbc_queue_front(dev, dev->p1 | fixed_bits, 0, 0x00); - dev->p1 = ((dev->p1 + 1) & 3) | (dev->p1 & 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->misc_flags & FLAG_PCI) + fixed_bits |= 8; + add_to_kbc_queue_front(dev, dev->p1 | fixed_bits, 0, 0x00); + } else if (((dev->flags & KBC_TYPE_MASK) >= KBC_TYPE_PS2_NOREF) && ((dev->flags & KBC_VEN_MASK) != KBC_VEN_INTEL_AMI)) + add_to_kbc_queue_front(dev, ((dev->p1 | fixed_bits) & 0xf0) | (((dev->flags & KBC_VEN_MASK) == KBC_VEN_ACER) ? 0x08 : 0x0c), 0, 0x00); + else + add_to_kbc_queue_front(dev, dev->p1 | fixed_bits, 0, 0x00); + dev->p1 = ((dev->p1 + 1) & 3) | (dev->p1 & 0xfc); return 0; case 0xd3: /* write auxiliary output buffer */ @@ -910,8 +902,11 @@ write60_ami(void *priv, uint8_t val) kbc_at_log("ATkbc: AMI - set keyboard mode\n"); dev->ami_flags = val; dev->misc_flags &= ~FLAG_PS2; - if (val & 0x01) + if (val & 0x01) { dev->misc_flags |= FLAG_PS2; + kbc_at_do_poll = kbc_at_poll_ps2; + } else + kbc_at_do_poll = kbc_at_poll_at; return 0; } @@ -944,28 +939,7 @@ write64_ami(void *priv, uint8_t val) case 0xa1: /* get controller version */ kbc_at_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); + add_to_kbc_queue_front(dev, kbc_ami_revision, 0, 0x00); return 0; case 0xa2: /* clear keyboard controller lines P22/P23 */ @@ -1038,16 +1012,14 @@ write64_ami(void *priv, uint8_t val) break; case 0xaf: /* set extended controller RAM */ - if (kbc_ven == KBC_VEN_ALI) { - kbc_at_log("ATkbc: Award/ALi/VIA keyboard controller revision\n"); - add_to_kbc_queue_front(dev, 0x43, 0, 0x00); - } else { + if (kbc_ven != KBC_VEN_ALI) { kbc_at_log("ATkbc: set extended controller RAM\n"); dev->wantdata = 1; dev->state = STATE_KBC_PARAM; dev->command_phase = 1; + return 0; } - return 0; + break; case 0xb0 ... 0xb3: /* set KBC lines P10-P13 (P1 bits 0-3) low */ @@ -1373,15 +1345,11 @@ kbc_at_process_cmd(void *priv) 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->state != STATE_RESET) { @@ -1395,17 +1363,18 @@ kbc_at_process_cmd(void *priv) 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->mem[0x21] = 0x01; + dev->mem[0x2a] = 0x10; + dev->mem[0x2b] = 0x20; + dev->mem[0x2c] = 0x15; + if (dev->ports[0] != NULL) dev->ports[0]->out_new = -1; if (dev->ports[1] != NULL) @@ -1699,9 +1668,14 @@ kbc_at_reset(void *priv) dev->sc_or = 0; dev->ami_flags = ((dev->flags & KBC_TYPE_MASK) >= KBC_TYPE_PS2_NOREF) ? 0x01 : 0x00; + dev->misc_flags = 0x00; - if ((dev->flags & KBC_TYPE_MASK) >= KBC_TYPE_PS2_NOREF) + if ((dev->flags & KBC_TYPE_MASK) >= KBC_TYPE_PS2_NOREF) { dev->misc_flags |= FLAG_PS2; + kbc_at_do_poll = kbc_at_poll_ps2; + } else + kbc_at_do_poll = kbc_at_poll_at; + dev->misc_flags |= FLAG_CACHE; dev->p2 = 0xcd; @@ -1763,6 +1737,9 @@ kbc_at_init(const device_t *info) dev->write60_ven = NULL; dev->write64_ven = NULL; + kbc_ami_revision = '8'; + kbc_award_revision = 0x42; + switch (dev->flags & KBC_VEN_MASK) { case KBC_VEN_ACER: case KBC_VEN_GENERIC: @@ -1775,11 +1752,44 @@ kbc_at_init(const device_t *info) dev->write64_ven = write64_olivetti; break; - case KBC_VEN_AMI: case KBC_VEN_INTEL_AMI: + kbc_ami_revision = '5'; + dev->write60_ven = write60_ami; + dev->write64_ven = write64_ami; + break; + case KBC_VEN_ALI: + kbc_ami_revision = 'F'; + kbc_award_revision = 0x43; + dev->write60_ven = write60_ami; + dev->write64_ven = write64_ami; + break; + case KBC_VEN_TG: case KBC_VEN_TG_GREEN: + kbc_ami_revision = 'Z'; + dev->write60_ven = write60_ami; + dev->write64_ven = write64_ami; + break; + + case KBC_VEN_AMI: + if ((dev->flags & KBC_TYPE_MASK) >= KBC_TYPE_PS2_NOREF) { + if (cpu_64bitbus) + kbc_ami_revision = 'R'; + else if (is486) + kbc_ami_revision = 'P'; + else + kbc_ami_revision = 'H'; + } else if (is386 && !is486) { + if (cpu_16bitbus) + kbc_ami_revision = 'D'; + else + kbc_ami_revision = 'B'; + } else if (!is386) + kbc_ami_revision = '8'; + else + kbc_ami_revision = 'F'; + dev->write60_ven = write60_ami; dev->write64_ven = write64_ami; break; From 041e916472c0e71cf65774aa1ddf02bd564a17b6 Mon Sep 17 00:00:00 2001 From: OBattler Date: Thu, 20 Apr 2023 15:05:51 +0200 Subject: [PATCH 10/20] AS small optimization. --- src/device/kbc_at_dev.c | 2 +- src/include/86box/keyboard.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/device/kbc_at_dev.c b/src/device/kbc_at_dev.c index a2baa21a0..87fdd51c6 100644 --- a/src/device/kbc_at_dev.c +++ b/src/device/kbc_at_dev.c @@ -144,7 +144,7 @@ kbc_at_dev_poll(void *priv) dev->cmd_queue_start = (dev->cmd_queue_start + 1) & 0xf; } if (dev->cmd_queue_start == dev->cmd_queue_end) - dev->state = (dev->state == DEV_STATE_MAIN_OUT) ? DEV_STATE_MAIN_2 : DEV_STATE_MAIN_IN; + dev->state++; break; case DEV_STATE_MAIN_IN: /* Wait for host data. */ diff --git a/src/include/86box/keyboard.h b/src/include/86box/keyboard.h index 6dec8a6db..6f7517e9d 100644 --- a/src/include/86box/keyboard.h +++ b/src/include/86box/keyboard.h @@ -29,9 +29,9 @@ enum { enum { DEV_STATE_MAIN_1 = 0, + DEV_STATE_MAIN_OUT, DEV_STATE_MAIN_2, DEV_STATE_MAIN_CMD, - DEV_STATE_MAIN_OUT, DEV_STATE_MAIN_WANT_IN, DEV_STATE_MAIN_IN }; From 5d9de974ee186d93ad3c75405dff15082b4aa760 Mon Sep 17 00:00:00 2001 From: OBattler Date: Sat, 22 Apr 2023 03:48:50 +0200 Subject: [PATCH 11/20] More keyboard controller clean-ups and fixes to mem/mem.c and port_92.c - OS/2 1.3 now works on IBM PS/2 MCA machines. --- src/device/kbc_at.c | 225 +++++++++++++++++++---------------- src/include/86box/keyboard.h | 1 - src/machine/m_ps2_mca.c | 6 +- src/mem/mem.c | 2 +- src/port_92.c | 20 +++- 5 files changed, 142 insertions(+), 112 deletions(-) diff --git a/src/device/kbc_at.c b/src/device/kbc_at.c index 287d8b4d0..2c9433bd9 100644 --- a/src/device/kbc_at.c +++ b/src/device/kbc_at.c @@ -64,25 +64,22 @@ #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_PS2_1 0x01 /* PS2 on PS/2, type 1 */ +#define KBC_TYPE_PS2_2 0x02 /* PS2 on PS/2, type 2 */ +#define KBC_TYPE_GREEN 0x03 /* PS2 green controller */ #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_IBM_PS1 0x04 +#define KBC_VEN_TOSHIBA 0x08 +#define KBC_VEN_OLIVETTI 0x0c +#define KBC_VEN_AMI 0x10 +#define KBC_VEN_TRIGEM_AMI 0x14 +#define KBC_VEN_QUADTEL 0x18 +#define KBC_VEN_PHOENIX 0x1c +#define KBC_VEN_ACER 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_ALI 0x28 #define KBC_VEN_MASK 0x3c #define FLAG_CLOCK 0x01 @@ -210,6 +207,7 @@ kbc_at_queue_add(atkbc_t *dev, uint8_t val) static int kbc_translate(atkbc_t *dev, uint8_t val) { + /* TODO: Does the IBM AT keyboard controller firmware apply translation in XT mode or not? */ int xt_mode = (dev->mem[0x20] & 0x20) && !(dev->misc_flags & FLAG_PS2); 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; @@ -308,8 +306,8 @@ add_to_kbc_queue_front(atkbc_t *dev, uint8_t val, uint8_t channel, uint8_t stat_ if (temp == -1) return; - if ((kbc_ven == KBC_VEN_AMI) || (kbc_ven == KBC_VEN_TG) || - (kbc_ven == KBC_VEN_TG_GREEN) || (dev->misc_flags & FLAG_PS2)) + if ((kbc_ven == KBC_VEN_AMI) || (kbc_ven == KBC_VEN_TRIGEM_AMI) || + (dev->misc_flags & FLAG_PS2)) stat_hi |= ((dev->p1 & 0x80) ? 0x10 : 0x00); else stat_hi |= 0x10; @@ -675,7 +673,7 @@ write_p2(atkbc_t *dev, uint8_t val) coreboot machines. */ pc_reset_hard(); } else { - softresetx86(); /*Pulse reset!*/ + softresetx86(); /* Pulse reset! */ cpu_set_edx(); flushmmucache(); if (kbc_ven == KBC_VEN_ALI) @@ -797,11 +795,59 @@ write64_generic(void *priv, uint8_t val) add_to_kbc_queue_front(dev, kbc_award_revision, 0, 0x00); return 0; + /* + P1 bits: 76543210 + ----------------- + IBM PS/1: xxxxxxxx + IBM PS/2 MCA: xxxxx1xx + Intel AMI Pentium BIOS'es with AMI MegaKey KB-5 keyboard controller: x1x1xxxx + Acer: xxx0x0xx + Packard Bell PB450: xxxxx1xx + P6RP4: xx1xx1xx + Epson Action Tower 2600: xxxx01xx + TriGem Hawk: xxxx11xx + + Bit 7: AT KBC only - keyboard inhibited (often physical lock): 0 = yes, 1 = no (also Compaq); + Bit 6: Mostly, display: 0 = CGA, 1 = MDA, inverted on Xi8088 and Acer KBC's; + Intel AMI MegaKey KB-5: Used for green features, SMM handler expects it to be set; + IBM PS/1 Model 2011: 0 = current FDD is 3.5", 1 = current FDD is 5.25"; + Comapq: 0 = Compaq dual-scan display, 1 = non-Compaq display. + Bit 5: Mostly, manufacturing jumper: 0 = installed (infinite loop at POST), 1 = not installed; + NCR: power-on default speed: 0 = high, 1 = low; + Compaq: System board DIP switch 5: 0 = ON, 1 = OFF. + Bit 4: (Which board?): RAM on motherboard: 0 = 512 kB, 1 = 256 kB; + NCR: RAM on motherboard: 0 = unsupported, 1 = 512 kB; + Acer: Must be 0; + Intel AMI MegaKey KB-5: Must be 1; + IBM PS/1: Ignored; + Compaq: 0 = Auto speed selected, 1 = High speed selected. + Bit 3: TriGem AMIKey: most significant bit of 2-bit OEM ID; + NCR: Coprocessor detect (1 = yes, 0 = no); + Compaq: 0 = Slow (4 MHz), 1 = Fast (8 MHz); + Sometimes configured for clock switching; + Bit 2: TriGem AMIKey: least significant bit of 2-bit OEM ID; + Bit 3, 2: + 1, 1: TriGem logo; + 1, 0: Garbled logo; + 0, 1: Epson logo; + 0, 0: Generic AMI logo. + NCR: Unused; + IBM PS/2: Keyboard power: 0 = no power (fuse error), 1 = OK + (for some reason, www.win.tue.nl has this in reverse); + Compaq: FPU: 0 = 80287, 1 = none; + Sometimes configured for clock switching; + Bit 1: PS/2: Auxiliary device data in; + Compaq: Reserved; + NCR: High/auto speed. + Bit 0: PS/2: Keyboard device data in; + Compaq: Reserved; + NCR: DMA mode. + */ case 0xc0: /* read P1 */ kbc_at_log("ATkbc: read P1\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) + if ((kbc_ven == KBC_VEN_AMI) && ((dev->flags & KBC_TYPE_MASK) == KBC_TYPE_GREEN)) fixed_bits |= 0x40; if (kbc_ven == KBC_VEN_IBM_PS1) { current_drive = fdc_get_current_drive(); @@ -820,7 +866,7 @@ write64_generic(void *priv, uint8_t val) */ add_to_kbc_queue_front(dev, (dev->p1 | fixed_bits | (video_is_mda() ? 0x40 : 0x00) | (hasfpu ? 0x08 : 0x00)) & 0xdf, 0, 0x00); - } else if ((kbc_ven == KBC_VEN_TG) || (kbc_ven == KBC_VEN_TG_GREEN)) { + } else if (kbc_ven == KBC_VEN_TRIGEM_AMI) { /* Bit 3, 2: 1, 1: TriGem logo; 1, 0: Garbled logo; @@ -829,13 +875,31 @@ write64_generic(void *priv, uint8_t val) if (dev->misc_flags & FLAG_PCI) fixed_bits |= 8; add_to_kbc_queue_front(dev, dev->p1 | fixed_bits, 0, 0x00); - } else if (((dev->flags & KBC_TYPE_MASK) >= KBC_TYPE_PS2_NOREF) && ((dev->flags & KBC_VEN_MASK) != KBC_VEN_INTEL_AMI)) + } else if (((dev->flags & KBC_TYPE_MASK) >= KBC_TYPE_PS2_1) && ((dev->flags & KBC_TYPE_MASK) < KBC_TYPE_GREEN)) add_to_kbc_queue_front(dev, ((dev->p1 | fixed_bits) & 0xf0) | (((dev->flags & KBC_VEN_MASK) == KBC_VEN_ACER) ? 0x08 : 0x0c), 0, 0x00); else add_to_kbc_queue_front(dev, dev->p1 | fixed_bits, 0, 0x00); dev->p1 = ((dev->p1 + 1) & 3) | (dev->p1 & 0xfc); return 0; + case 0xc1: /*Copy bits 0 to 3 of P1 to status bits 4 to 7*/ + if (dev->misc_flags & FLAG_PS2) { + kbc_at_log("ATkbc: copy bits 0 to 3 of P1 to status bits 4 to 7\n"); + dev->status &= 0x0f; + dev->status |= (dev->p1 << 4); + return 0; + } + break; + + case 0xc2: /*Copy bits 4 to 7 of P1 to status bits 4 to 7*/ + if (dev->misc_flags & FLAG_PS2) { + kbc_at_log("ATkbc: copy bits 4 to 7 of P1 to status bits 4 to 7\n"); + dev->status &= 0x0f; + dev->status |= (dev->p1 & 0xf0); + return 0; + } + break; + case 0xd3: /* write auxiliary output buffer */ if (dev->misc_flags & FLAG_PS2) { kbc_at_log("ATkbc: write auxiliary output buffer\n"); @@ -903,10 +967,13 @@ write60_ami(void *priv, uint8_t val) dev->ami_flags = val; dev->misc_flags &= ~FLAG_PS2; if (val & 0x01) { + kbc_at_log("ATkbc: AMI: Emulate PS/2 keyboard\n"); dev->misc_flags |= FLAG_PS2; kbc_at_do_poll = kbc_at_poll_ps2; - } else + } else { + kbc_at_log("ATkbc: AMI: Emulate AT keyboard\n"); kbc_at_do_poll = kbc_at_poll_at; + } return 0; } @@ -1112,37 +1179,6 @@ write64_ami(void *priv, uint8_t val) return write64_generic(dev, val); } -static uint8_t -write64_ibm_mca(void *priv, uint8_t val) -{ - atkbc_t *dev = (atkbc_t *) priv; - - switch (val) { - case 0xc1: /*Copy bits 0 to 3 of P1 to status bits 4 to 7*/ - kbc_at_log("ATkbc: copy bits 0 to 3 of P1 to status bits 4 to 7\n"); - dev->status &= 0x0f; - dev->status |= ((((dev->p1 & 0xfc) | 0x84) & 0x0f) << 4); - return 0; - - case 0xc2: /*Copy bits 4 to 7 of P1 to status bits 4 to 7*/ - kbc_at_log("ATkbc: copy bits 4 to 7 of P1 to status bits 4 to 7\n"); - dev->status &= 0x0f; - dev->status |= (((dev->p1 & 0xfc) | 0x84) & 0xf0); - return 0; - - case 0xaf: - kbc_at_log("ATkbc: bad KBC command AF\n"); - return 1; - - case 0xf0 ... 0xff: - kbc_at_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) { @@ -1260,15 +1296,17 @@ write64_toshiba(void *priv, uint8_t val) dev->state = STATE_KBC_PARAM; return 0; + /* TODO: Toshiba KBC mode switching. */ case 0xb7: /* T3100e: Emulate PS/2 keyboard */ case 0xb8: /* T3100e: Emulate AT keyboard */ - dev->flags &= ~KBC_TYPE_MASK; + dev->misc_flags &= ~FLAG_PS2; if (val == 0xb7) { kbc_at_log("ATkbc: T3100e: Emulate PS/2 keyboard\n"); - dev->flags |= KBC_TYPE_PS2_NOREF; + dev->misc_flags |= FLAG_PS2; + kbc_at_do_poll = kbc_at_poll_ps2; } else { kbc_at_log("ATkbc: T3100e: Emulate AT keyboard\n"); - dev->flags |= KBC_TYPE_ISA; + kbc_at_do_poll = kbc_at_poll_at; } return 0; @@ -1333,7 +1371,7 @@ kbc_at_process_cmd(void *priv) case 0xaa: /* self-test */ kbc_at_log("ATkbc: self-test\n"); - if ((dev->flags & KBC_TYPE_MASK) >= KBC_TYPE_PS2_NOREF) { + if ((dev->flags & KBC_TYPE_MASK) >= KBC_TYPE_PS2_1) { if (dev->state != STATE_RESET) { kbc_at_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. */ @@ -1531,7 +1569,7 @@ kbc_at_process_cmd(void *priv) if (dev->ib == 0xbb) break; - if ((dev->flags & KBC_TYPE_MASK) >= KBC_TYPE_PS2_NOREF) { + if (dev->misc_flags & FLAG_PS2) { set_enable_aux(dev, 1); if ((dev->ports[1] != NULL) && (dev->ports[1]->priv != NULL)) { dev->ports[1]->wantcmd = 1; @@ -1614,7 +1652,7 @@ kbc_at_read(uint16_t port, void *priv) atkbc_t *dev = (atkbc_t *) priv; uint8_t ret = 0xff; - if ((dev->flags & KBC_TYPE_MASK) >= KBC_TYPE_PS2_NOREF) + if ((dev->flags & KBC_TYPE_MASK) >= KBC_TYPE_PS2_1) cycles -= ISA_CYCLES(8); switch (port) { @@ -1667,10 +1705,10 @@ kbc_at_reset(void *priv) dev->sc_or = 0; - dev->ami_flags = ((dev->flags & KBC_TYPE_MASK) >= KBC_TYPE_PS2_NOREF) ? 0x01 : 0x00; + dev->ami_flags = ((dev->flags & KBC_TYPE_MASK) >= KBC_TYPE_PS2_1) ? 0x01 : 0x00; dev->misc_flags = 0x00; - if ((dev->flags & KBC_TYPE_MASK) >= KBC_TYPE_PS2_NOREF) { + if ((dev->flags & KBC_TYPE_MASK) >= KBC_TYPE_PS2_1) { dev->misc_flags |= FLAG_PS2; kbc_at_do_poll = kbc_at_poll_ps2; } else @@ -1679,7 +1717,7 @@ kbc_at_reset(void *priv) dev->misc_flags |= FLAG_CACHE; dev->p2 = 0xcd; - if ((dev->flags & KBC_TYPE_MASK) >= KBC_TYPE_PS2_NOREF) { + if ((dev->flags & KBC_TYPE_MASK) >= KBC_TYPE_PS2_1) { write_p2(dev, 0x4b); } else { /* The real thing writes CF and then AND's it with BF. */ @@ -1694,7 +1732,7 @@ static void kbc_at_close(void *priv) { atkbc_t *dev = (atkbc_t *) priv; - int i, max_ports = ((dev->flags & KBC_TYPE_MASK) >= KBC_TYPE_PS2_NOREF) ? 2 : 1; + int i, max_ports = ((dev->flags & KBC_TYPE_MASK) >= KBC_TYPE_PS2_1) ? 2 : 1; kbc_at_reset(dev); @@ -1752,12 +1790,6 @@ kbc_at_init(const device_t *info) dev->write64_ven = write64_olivetti; break; - case KBC_VEN_INTEL_AMI: - kbc_ami_revision = '5'; - dev->write60_ven = write60_ami; - dev->write64_ven = write64_ami; - break; - case KBC_VEN_ALI: kbc_ami_revision = 'F'; kbc_award_revision = 0x43; @@ -1765,15 +1797,16 @@ kbc_at_init(const device_t *info) dev->write64_ven = write64_ami; break; - case KBC_VEN_TG: - case KBC_VEN_TG_GREEN: + case KBC_VEN_TRIGEM_AMI: kbc_ami_revision = 'Z'; dev->write60_ven = write60_ami; dev->write64_ven = write64_ami; break; case KBC_VEN_AMI: - if ((dev->flags & KBC_TYPE_MASK) >= KBC_TYPE_PS2_NOREF) { + if ((dev->flags & KBC_TYPE_MASK) == KBC_TYPE_GREEN) + kbc_ami_revision = '5'; + else if ((dev->flags & KBC_TYPE_MASK) >= KBC_TYPE_PS2_1) { if (cpu_64bitbus) kbc_ami_revision = 'R'; else if (is486) @@ -1794,10 +1827,6 @@ kbc_at_init(const device_t *info) 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; @@ -1809,7 +1838,7 @@ kbc_at_init(const device_t *info) break; } - max_ports = ((dev->flags & KBC_TYPE_MASK) >= KBC_TYPE_PS2_NOREF) ? 2 : 1; + max_ports = ((dev->flags & KBC_TYPE_MASK) >= KBC_TYPE_PS2_1) ? 2 : 1; for (i = 0; i < max_ports; i++) { kbc_at_ports[i] = (kbc_at_port_t *) malloc(sizeof(kbc_at_port_t)); @@ -1858,7 +1887,7 @@ const device_t keyboard_at_tg_ami_device = { .name = "PC/AT Keyboard (TriGem AMI)", .internal_name = "keyboard_at_tg_ami", .flags = DEVICE_KBC, - .local = KBC_TYPE_ISA | KBC_VEN_TG, + .local = KBC_TYPE_ISA | KBC_VEN_TRIGEM_AMI, .init = kbc_at_init, .close = kbc_at_close, .reset = kbc_at_reset, @@ -1914,7 +1943,7 @@ const device_t keyboard_ps2_device = { .name = "PS/2 Keyboard", .internal_name = "keyboard_ps2", .flags = DEVICE_KBC, - .local = KBC_TYPE_PS2_NOREF | KBC_VEN_GENERIC, + .local = KBC_TYPE_PS2_1 | KBC_VEN_GENERIC, .init = kbc_at_init, .close = kbc_at_close, .reset = kbc_at_reset, @@ -1928,7 +1957,7 @@ const device_t keyboard_ps2_ps1_device = { .name = "PS/2 Keyboard (IBM PS/1)", .internal_name = "keyboard_ps2_ps1", .flags = DEVICE_KBC, - .local = KBC_TYPE_PS2_NOREF | KBC_VEN_IBM_PS1, + .local = KBC_TYPE_PS2_1 | KBC_VEN_IBM_PS1, .init = kbc_at_init, .close = kbc_at_close, .reset = kbc_at_reset, @@ -1942,7 +1971,7 @@ const device_t keyboard_ps2_ps1_pci_device = { .name = "PS/2 Keyboard (IBM PS/1)", .internal_name = "keyboard_ps2_ps1_pci", .flags = DEVICE_KBC | DEVICE_PCI, - .local = KBC_TYPE_PS2_NOREF | KBC_VEN_IBM_PS1, + .local = KBC_TYPE_PS2_1 | KBC_VEN_IBM_PS1, .init = kbc_at_init, .close = kbc_at_close, .reset = kbc_at_reset, @@ -1970,7 +1999,7 @@ const device_t keyboard_ps2_ami_device = { .name = "PS/2 Keyboard (AMI)", .internal_name = "keyboard_ps2_ami", .flags = DEVICE_KBC, - .local = KBC_TYPE_PS2_NOREF | KBC_VEN_AMI, + .local = KBC_TYPE_PS2_1 | KBC_VEN_AMI, .init = kbc_at_init, .close = kbc_at_close, .reset = kbc_at_reset, @@ -1984,21 +2013,7 @@ const device_t keyboard_ps2_tg_ami_device = { .name = "PS/2 Keyboard (TriGem AMI)", .internal_name = "keyboard_ps2_tg_ami", .flags = DEVICE_KBC, - .local = KBC_TYPE_PS2_NOREF | KBC_VEN_TG, - .init = kbc_at_init, - .close = kbc_at_close, - .reset = kbc_at_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 = DEVICE_KBC, - .local = KBC_TYPE_PS2_1 | KBC_VEN_IBM_MCA, + .local = KBC_TYPE_PS2_1 | KBC_VEN_TRIGEM_AMI, .init = kbc_at_init, .close = kbc_at_close, .reset = kbc_at_reset, @@ -2012,7 +2027,7 @@ const device_t keyboard_ps2_mca_2_device = { .name = "PS/2 Keyboard", .internal_name = "keyboard_ps2_mca_2", .flags = DEVICE_KBC, - .local = KBC_TYPE_PS2_2 | KBC_VEN_IBM_MCA, + .local = KBC_TYPE_PS2_2 | KBC_VEN_GENERIC, .init = kbc_at_init, .close = kbc_at_close, .reset = kbc_at_reset, @@ -2026,7 +2041,7 @@ const device_t keyboard_ps2_quadtel_device = { .name = "PS/2 Keyboard (Quadtel/MegaPC)", .internal_name = "keyboard_ps2_quadtel", .flags = DEVICE_KBC, - .local = KBC_TYPE_PS2_NOREF | KBC_VEN_QUADTEL, + .local = KBC_TYPE_PS2_1 | KBC_VEN_QUADTEL, .init = kbc_at_init, .close = kbc_at_close, .reset = kbc_at_reset, @@ -2040,7 +2055,7 @@ const device_t keyboard_ps2_pci_device = { .name = "PS/2 Keyboard", .internal_name = "keyboard_ps2_pci", .flags = DEVICE_KBC | DEVICE_PCI, - .local = KBC_TYPE_PS2_NOREF | KBC_VEN_GENERIC, + .local = KBC_TYPE_PS2_1 | KBC_VEN_GENERIC, .init = kbc_at_init, .close = kbc_at_close, .reset = kbc_at_reset, @@ -2054,7 +2069,7 @@ const device_t keyboard_ps2_ami_pci_device = { .name = "PS/2 Keyboard (AMI)", .internal_name = "keyboard_ps2_ami_pci", .flags = DEVICE_KBC | DEVICE_PCI, - .local = KBC_TYPE_PS2_NOREF | KBC_VEN_AMI, + .local = KBC_TYPE_PS2_1 | KBC_VEN_AMI, .init = kbc_at_init, .close = kbc_at_close, .reset = kbc_at_reset, @@ -2068,7 +2083,7 @@ const device_t keyboard_ps2_ali_pci_device = { .name = "PS/2 Keyboard (ALi M5123/M1543C)", .internal_name = "keyboard_ps2_ali_pci", .flags = DEVICE_KBC | DEVICE_PCI, - .local = KBC_TYPE_PS2_NOREF | KBC_VEN_ALI, + .local = KBC_TYPE_PS2_1 | KBC_VEN_ALI, .init = kbc_at_init, .close = kbc_at_close, .reset = kbc_at_reset, @@ -2082,7 +2097,7 @@ const device_t keyboard_ps2_intel_ami_pci_device = { .name = "PS/2 Keyboard (AMI)", .internal_name = "keyboard_ps2_intel_ami_pci", .flags = DEVICE_KBC | DEVICE_PCI, - .local = KBC_TYPE_PS2_NOREF | KBC_VEN_INTEL_AMI, + .local = KBC_TYPE_GREEN | KBC_VEN_AMI, .init = kbc_at_init, .close = kbc_at_close, .reset = kbc_at_reset, @@ -2096,7 +2111,7 @@ const device_t keyboard_ps2_tg_ami_pci_device = { .name = "PS/2 Keyboard (TriGem AMI)", .internal_name = "keyboard_ps2_tg_ami_pci", .flags = DEVICE_KBC | DEVICE_PCI, - .local = KBC_TYPE_PS2_NOREF | KBC_VEN_TG, + .local = KBC_TYPE_PS2_1 | KBC_VEN_TRIGEM_AMI, .init = kbc_at_init, .close = kbc_at_close, .reset = kbc_at_reset, @@ -2110,7 +2125,7 @@ const device_t keyboard_ps2_acer_pci_device = { .name = "PS/2 Keyboard (Acer 90M002A)", .internal_name = "keyboard_ps2_acer_pci", .flags = DEVICE_KBC | DEVICE_PCI, - .local = KBC_TYPE_PS2_NOREF | KBC_VEN_ACER, + .local = KBC_TYPE_PS2_1 | KBC_VEN_ACER, .init = kbc_at_init, .close = kbc_at_close, .reset = kbc_at_reset, diff --git a/src/include/86box/keyboard.h b/src/include/86box/keyboard.h index 6f7517e9d..fe642fec1 100644 --- a/src/include/86box/keyboard.h +++ b/src/include/86box/keyboard.h @@ -225,7 +225,6 @@ extern const device_t keyboard_ps2_ami_device; extern const device_t keyboard_ps2_tg_ami_device; extern const device_t keyboard_ps2_tg_ami_green_device; extern const device_t keyboard_ps2_olivetti_device; -extern const device_t keyboard_ps2_mca_device; extern const device_t keyboard_ps2_mca_2_device; extern const device_t keyboard_ps2_quadtel_device; extern const device_t keyboard_ps2_pci_device; diff --git a/src/machine/m_ps2_mca.c b/src/machine/m_ps2_mca.c index 3de9ef491..328de216b 100644 --- a/src/machine/m_ps2_mca.c +++ b/src/machine/m_ps2_mca.c @@ -998,7 +998,7 @@ ps2_mca_board_model_55sx_init(int has_sec_nvram, int slots) } mca_init(slots); - device_add(&keyboard_ps2_mca_device); + device_add(&keyboard_ps2_device); if (has_sec_nvram == 1) device_add(&ps2_nvr_55ls_device); @@ -1162,7 +1162,7 @@ ps2_mca_board_model_70_type34_init(int is_type4, int slots) ps2.split_addr = mem_size * 1024; mca_init(slots); - device_add(&keyboard_ps2_mca_device); + device_add(&keyboard_ps2_device); ps2.planar_read = model_70_type3_read; ps2.planar_write = model_70_type3_write; @@ -1255,7 +1255,7 @@ ps2_mca_board_model_80_type2_init(int is486) ps2.split_addr = mem_size * 1024; mca_init(8); - device_add(&keyboard_ps2_mca_device); + device_add(&keyboard_ps2_device); ps2.planar_read = model_80_read; ps2.planar_write = model_80_write; diff --git a/src/mem/mem.c b/src/mem/mem.c index f3f0f3110..910f67619 100644 --- a/src/mem/mem.c +++ b/src/mem/mem.c @@ -2898,7 +2898,7 @@ mem_remap_top(int kb) if (addr >= 0x000c0000) addr += 0x00010000; } - if (start_addr != 0) + 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; diff --git a/src/port_92.c b/src/port_92.c index cbc419569..fd0471b0e 100644 --- a/src/port_92.c +++ b/src/port_92.c @@ -69,11 +69,18 @@ port_92_readw(uint16_t port, void *priv) return ret; } +/* + This does the exact same thing as keyboard controller reset. + TODO: ALi M1543(c) behavior. + */ static void port_92_pulse(void *priv) { - resetx86(); + softresetx86(); /* Pulse reset! */ cpu_set_edx(); + flushmmucache(); + + cpu_alt_reset = 1; } static void @@ -166,6 +173,15 @@ port_92_remove(void *priv) port_92_readb, NULL, NULL, port_92_writeb, NULL, NULL, dev); } +static void +port_92_reset(void *priv) +{ + cpu_alt_reset = 0; + + mem_a20_alt = 0x00; + mem_a20_recalc(); +} + static void port_92_close(void *priv) { @@ -252,7 +268,7 @@ const device_t port_92_pci_device = { .local = PORT_92_PCI, .init = port_92_init, .close = port_92_close, - .reset = NULL, + .reset = port_92_reset, { .available = NULL }, .speed_changed = NULL, .force_redraw = NULL, From 8d6181de50133e8b7a0e48e391974cf225326abf Mon Sep 17 00:00:00 2001 From: OBattler Date: Sat, 22 Apr 2023 08:38:15 +0200 Subject: [PATCH 12/20] A small change in device/keyboard_at.c so the keyboard no longer loses track of what command a parameter is intended for when interrupted by another command. --- src/device/keyboard_at.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/device/keyboard_at.c b/src/device/keyboard_at.c index 886016023..19a754d7b 100644 --- a/src/device/keyboard_at.c +++ b/src/device/keyboard_at.c @@ -788,10 +788,9 @@ keyboard_at_write(void *priv) dev->state = DEV_STATE_MAIN_WANT_IN; } - dev->command = val; - - switch (dev->command) { + switch (val) { case 0xed: /* set/reset LEDs */ + dev->command = val; keyboard_at_log("%s: set/reset LEDs\n", dev->name); dev->flags |= FLAG_CTRLDAT; kbc_at_dev_queue_add(dev, 0xfa, 0); /* ACK for command byte */ @@ -811,6 +810,7 @@ keyboard_at_write(void *priv) case 0xf0: /* get/set scan code set */ if (dev->type & FLAG_PS2) { + dev->command = val; keyboard_at_log("%s: scan code set\n", dev->name); dev->flags |= FLAG_CTRLDAT; kbc_at_dev_queue_add(dev, 0xfa, 0); /* ACK for command byte */ @@ -833,6 +833,7 @@ keyboard_at_write(void *priv) break; case 0xf3: /* set command mode */ + dev->command = val; keyboard_at_log("%s: set typematic rate/delay\n", dev->name); dev->flags |= FLAG_CTRLDAT; kbc_at_dev_queue_add(dev, 0xfa, 0); /* ACK for command byte */ From cc4dd568bd48031a9169aa59190bd210979aae97 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20Hrdli=C4=8Dka?= Date: Sat, 22 Apr 2023 18:05:36 +0200 Subject: [PATCH 13/20] Update README.md The contribution requirements section is basically stating the sky is blue, not sure the point of it --- README.md | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/README.md b/README.md index a1e3985e1..05a2a9ed2 100644 --- a/README.md +++ b/README.md @@ -49,16 +49,6 @@ Licensing The emulator can also optionally make use of [munt](https://github.com/munt/munt), [FluidSynth](https://www.fluidsynth.org/), [Ghostscript](https://www.ghostscript.com/) and [Discord Game SDK](https://discord.com/developers/docs/game-sdk/sdk-starter-guide), which are distributed under their respective licenses. -Contribution requirements -------------------------- - Formal codification of the project's emulated hardware contribution requirements, which all have to be met to accept an addition: -* A ROM must be available; -* Documentation must be available or it must be feasible to reverse engineer with a reasonable amount of time and effort; -* It must be feasible to implement with a reasonable amount of time and effort; -* It has to fall inside the project's scope. - -Where unsure or for more details about the project's emulated hardware contribution requirements, contact a Contributor or higher. - Donations --------- We do not charge you for the emulator but donations are still welcome: From c076406450f46df3806015d44605e45be89673a7 Mon Sep 17 00:00:00 2001 From: RichardG867 Date: Sat, 22 Apr 2023 18:41:42 -0300 Subject: [PATCH 14/20] 386_common: Optimize I/O permission checking for word and dword operations (based on qemu) --- src/cpu/386_common.c | 19 ++++++++++--------- src/cpu/386_common.h | 6 +++--- src/cpu/cpu.h | 2 +- src/cpu/x86_ops_io.h | 40 ++++++++++++--------------------------- src/cpu/x86_ops_rep.h | 20 ++++++-------------- src/cpu/x86_ops_rep_dyn.h | 20 ++++++-------------- src/cpu/x86_ops_string.h | 40 ++++++++++++--------------------------- 7 files changed, 50 insertions(+), 97 deletions(-) diff --git a/src/cpu/386_common.c b/src/cpu/386_common.c index 2df72c20e..454815de0 100644 --- a/src/cpu/386_common.c +++ b/src/cpu/386_common.c @@ -1427,25 +1427,26 @@ x86illegal(void) } int -checkio(uint32_t port) +checkio(uint32_t port, int mask) { uint16_t t; - uint8_t d; cpl_override = 1; t = readmemw(tr.base, 0x66); - cpl_override = 0; - if (cpu_state.abrt) + if (cpu_state.abrt) { + cpl_override = 0; return 0; + } - if ((t + (port >> 3UL)) > tr.limit) - return 1; + if ((t + (port >> 3UL) + 1) > tr.limit) { + cpl_override = 0; + return mask; + } - cpl_override = 1; - d = readmembl(tr.base + t + (port >> 3)); + t = readmemwl(tr.base + t + (port >> 3)); cpl_override = 0; - return d & (1 << (port & 7)); + return (t >> (port & 7)) & mask; } #ifdef OLD_DIVEXCP diff --git a/src/cpu/386_common.h b/src/cpu/386_common.h index f26eb7f98..ae71347b6 100644 --- a/src/cpu/386_common.h +++ b/src/cpu/386_common.h @@ -97,11 +97,11 @@ if (writelookup2[(uint32_t) ((s) + (a)) >> 12] == (uintptr_t) LOOKUP_INV || (s) == 0xFFFFFFFF || (((s) + (a)) & 3)) \ do_mmutranslate((s) + (a), b, 4, 1) -int checkio(uint32_t port); +int checkio(uint32_t port, int mask); -#define check_io_perm(port) \ +#define check_io_perm(port, size) \ if (msw & 1 && ((CPL > IOPL) || (cpu_state.eflags & VM_FLAG))) { \ - int tempi = checkio(port); \ + int tempi = checkio(port, (1 << size) - 1); \ if (cpu_state.abrt) \ return 1; \ if (tempi) { \ diff --git a/src/cpu/cpu.h b/src/cpu/cpu.h index 93dae98d1..f8ffaced3 100644 --- a/src/cpu/cpu.h +++ b/src/cpu/cpu.h @@ -642,7 +642,7 @@ extern void cpu_CPUID(void); extern void cpu_RDMSR(void); extern void cpu_WRMSR(void); -extern int checkio(uint32_t port); +extern int checkio(uint32_t port, int mask); extern void codegen_block_end(void); extern void codegen_reset(void); extern void cpu_set_edx(void); diff --git a/src/cpu/x86_ops_io.h b/src/cpu/x86_ops_io.h index c4d46404d..8a99b8668 100644 --- a/src/cpu/x86_ops_io.h +++ b/src/cpu/x86_ops_io.h @@ -2,7 +2,7 @@ static int opIN_AL_imm(uint32_t fetchdat) { uint16_t port = (uint16_t) getbytef(); - check_io_perm(port); + check_io_perm(port, 1); AL = inb(port); CLOCK_CYCLES(12); PREFETCH_RUN(12, 2, -1, 1, 0, 0, 0, 0); @@ -14,8 +14,7 @@ static int opIN_AX_imm(uint32_t fetchdat) { uint16_t port = (uint16_t) getbytef(); - check_io_perm(port); - check_io_perm(port + 1); + check_io_perm(port, 2); AX = inw(port); CLOCK_CYCLES(12); PREFETCH_RUN(12, 2, -1, 1, 0, 0, 0, 0); @@ -27,10 +26,7 @@ static int opIN_EAX_imm(uint32_t fetchdat) { uint16_t port = (uint16_t) getbytef(); - check_io_perm(port); - check_io_perm(port + 1); - check_io_perm(port + 2); - check_io_perm(port + 3); + check_io_perm(port, 4); EAX = inl(port); CLOCK_CYCLES(12); PREFETCH_RUN(12, 2, -1, 0, 1, 0, 0, 0); @@ -43,7 +39,7 @@ static int opOUT_AL_imm(uint32_t fetchdat) { uint16_t port = (uint16_t) getbytef(); - check_io_perm(port); + check_io_perm(port, 1); outb(port, AL); CLOCK_CYCLES(10); PREFETCH_RUN(10, 2, -1, 0, 0, 1, 0, 0); @@ -57,8 +53,7 @@ static int opOUT_AX_imm(uint32_t fetchdat) { uint16_t port = (uint16_t) getbytef(); - check_io_perm(port); - check_io_perm(port + 1); + check_io_perm(port, 2); outw(port, AX); CLOCK_CYCLES(10); PREFETCH_RUN(10, 2, -1, 0, 0, 1, 0, 0); @@ -70,10 +65,7 @@ static int opOUT_EAX_imm(uint32_t fetchdat) { uint16_t port = (uint16_t) getbytef(); - check_io_perm(port); - check_io_perm(port + 1); - check_io_perm(port + 2); - check_io_perm(port + 3); + check_io_perm(port, 4); outl(port, EAX); CLOCK_CYCLES(10); PREFETCH_RUN(10, 2, -1, 0, 0, 0, 1, 0); @@ -85,7 +77,7 @@ opOUT_EAX_imm(uint32_t fetchdat) static int opIN_AL_DX(uint32_t fetchdat) { - check_io_perm(DX); + check_io_perm(DX, 1); AL = inb(DX); CLOCK_CYCLES(12); PREFETCH_RUN(12, 1, -1, 1, 0, 0, 0, 0); @@ -96,8 +88,7 @@ opIN_AL_DX(uint32_t fetchdat) static int opIN_AX_DX(uint32_t fetchdat) { - check_io_perm(DX); - check_io_perm(DX + 1); + check_io_perm(DX, 2); AX = inw(DX); CLOCK_CYCLES(12); PREFETCH_RUN(12, 1, -1, 1, 0, 0, 0, 0); @@ -108,10 +99,7 @@ opIN_AX_DX(uint32_t fetchdat) static int opIN_EAX_DX(uint32_t fetchdat) { - check_io_perm(DX); - check_io_perm(DX + 1); - check_io_perm(DX + 2); - check_io_perm(DX + 3); + check_io_perm(DX, 4); EAX = inl(DX); CLOCK_CYCLES(12); PREFETCH_RUN(12, 1, -1, 0, 1, 0, 0, 0); @@ -123,7 +111,7 @@ opIN_EAX_DX(uint32_t fetchdat) static int opOUT_AL_DX(uint32_t fetchdat) { - check_io_perm(DX); + check_io_perm(DX, 1); outb(DX, AL); CLOCK_CYCLES(11); PREFETCH_RUN(11, 1, -1, 0, 0, 1, 0, 0); @@ -134,8 +122,7 @@ opOUT_AL_DX(uint32_t fetchdat) static int opOUT_AX_DX(uint32_t fetchdat) { - check_io_perm(DX); - check_io_perm(DX + 1); + check_io_perm(DX, 2); outw(DX, AX); CLOCK_CYCLES(11); PREFETCH_RUN(11, 1, -1, 0, 0, 1, 0, 0); @@ -146,10 +133,7 @@ opOUT_AX_DX(uint32_t fetchdat) static int opOUT_EAX_DX(uint32_t fetchdat) { - check_io_perm(DX); - check_io_perm(DX + 1); - check_io_perm(DX + 2); - check_io_perm(DX + 3); + check_io_perm(DX, 4); outl(DX, EAX); PREFETCH_RUN(11, 1, -1, 0, 0, 0, 1, 0); if (nmi && nmi_enable && nmi_mask) diff --git a/src/cpu/x86_ops_rep.h b/src/cpu/x86_ops_rep.h index 67bd8433d..4b8f42185 100644 --- a/src/cpu/x86_ops_rep.h +++ b/src/cpu/x86_ops_rep.h @@ -9,7 +9,7 @@ uint8_t temp; \ \ SEG_CHECK_WRITE(&cpu_state.seg_es); \ - check_io_perm(DX); \ + check_io_perm(DX, 1); \ CHECK_WRITE(&cpu_state.seg_es, DEST_REG, DEST_REG); \ high_page = 0; \ do_mmut_wb(es, DEST_REG, &addr64); \ @@ -48,8 +48,7 @@ uint16_t temp; \ \ SEG_CHECK_WRITE(&cpu_state.seg_es); \ - check_io_perm(DX); \ - check_io_perm(DX + 1); \ + check_io_perm(DX, 2); \ CHECK_WRITE(&cpu_state.seg_es, DEST_REG, DEST_REG + 1UL); \ high_page = 0; \ do_mmut_ww(es, DEST_REG, addr64a); \ @@ -88,10 +87,7 @@ uint32_t temp; \ \ SEG_CHECK_WRITE(&cpu_state.seg_es); \ - check_io_perm(DX); \ - check_io_perm(DX + 1); \ - check_io_perm(DX + 2); \ - check_io_perm(DX + 3); \ + check_io_perm(DX, 4); \ CHECK_WRITE(&cpu_state.seg_es, DEST_REG, DEST_REG + 3UL); \ high_page = 0; \ do_mmut_wl(es, DEST_REG, addr64a); \ @@ -132,7 +128,7 @@ temp = readmemb(cpu_state.ea_seg->base, SRC_REG); \ if (cpu_state.abrt) \ return 1; \ - check_io_perm(DX); \ + check_io_perm(DX, 1); \ outb(DX, temp); \ if (cpu_state.flags & D_FLAG) \ SRC_REG--; \ @@ -163,8 +159,7 @@ temp = readmemw(cpu_state.ea_seg->base, SRC_REG); \ if (cpu_state.abrt) \ return 1; \ - check_io_perm(DX); \ - check_io_perm(DX + 1); \ + check_io_perm(DX, 2); \ outw(DX, temp); \ if (cpu_state.flags & D_FLAG) \ SRC_REG -= 2; \ @@ -195,10 +190,7 @@ temp = readmeml(cpu_state.ea_seg->base, SRC_REG); \ if (cpu_state.abrt) \ return 1; \ - check_io_perm(DX); \ - check_io_perm(DX + 1); \ - check_io_perm(DX + 2); \ - check_io_perm(DX + 3); \ + check_io_perm(DX, 4); \ outl(DX, temp); \ if (cpu_state.flags & D_FLAG) \ SRC_REG -= 4; \ diff --git a/src/cpu/x86_ops_rep_dyn.h b/src/cpu/x86_ops_rep_dyn.h index 576baa403..5c64ed94d 100644 --- a/src/cpu/x86_ops_rep_dyn.h +++ b/src/cpu/x86_ops_rep_dyn.h @@ -7,7 +7,7 @@ uint8_t temp; \ \ SEG_CHECK_WRITE(&cpu_state.seg_es); \ - check_io_perm(DX); \ + check_io_perm(DX, 1); \ CHECK_WRITE(&cpu_state.seg_es, DEST_REG, DEST_REG); \ high_page = 0; \ do_mmut_wb(es, DEST_REG, &addr64); \ @@ -40,8 +40,7 @@ uint16_t temp; \ \ SEG_CHECK_WRITE(&cpu_state.seg_es); \ - check_io_perm(DX); \ - check_io_perm(DX + 1); \ + check_io_perm(DX, 2); \ CHECK_WRITE(&cpu_state.seg_es, DEST_REG, DEST_REG + 1UL); \ high_page = 0; \ do_mmut_ww(es, DEST_REG, addr64a); \ @@ -74,10 +73,7 @@ uint32_t temp; \ \ SEG_CHECK_WRITE(&cpu_state.seg_es); \ - check_io_perm(DX); \ - check_io_perm(DX + 1); \ - check_io_perm(DX + 2); \ - check_io_perm(DX + 3); \ + check_io_perm(DX, 4); \ CHECK_WRITE(&cpu_state.seg_es, DEST_REG, DEST_REG + 3UL); \ high_page = 0; \ do_mmut_wl(es, DEST_REG, addr64a); \ @@ -112,7 +108,7 @@ temp = readmemb(cpu_state.ea_seg->base, SRC_REG); \ if (cpu_state.abrt) \ return 1; \ - check_io_perm(DX); \ + check_io_perm(DX, 1); \ outb(DX, temp); \ if (cpu_state.flags & D_FLAG) \ SRC_REG--; \ @@ -137,8 +133,7 @@ temp = readmemw(cpu_state.ea_seg->base, SRC_REG); \ if (cpu_state.abrt) \ return 1; \ - check_io_perm(DX); \ - check_io_perm(DX + 1); \ + check_io_perm(DX, 2); \ outw(DX, temp); \ if (cpu_state.flags & D_FLAG) \ SRC_REG -= 2; \ @@ -163,10 +158,7 @@ temp = readmeml(cpu_state.ea_seg->base, SRC_REG); \ if (cpu_state.abrt) \ return 1; \ - check_io_perm(DX); \ - check_io_perm(DX + 1); \ - check_io_perm(DX + 2); \ - check_io_perm(DX + 3); \ + check_io_perm(DX, 4); \ outl(DX, temp); \ if (cpu_state.flags & D_FLAG) \ SRC_REG -= 4; \ diff --git a/src/cpu/x86_ops_string.h b/src/cpu/x86_ops_string.h index 5cc5f3806..c3875a648 100644 --- a/src/cpu/x86_ops_string.h +++ b/src/cpu/x86_ops_string.h @@ -804,7 +804,7 @@ opINSB_a16(uint32_t fetchdat) addr64 = 0x00000000; SEG_CHECK_WRITE(&cpu_state.seg_es); - check_io_perm(DX); + check_io_perm(DX, 1); CHECK_WRITE(&cpu_state.seg_es, DI, DI); high_page = 0; do_mmut_wb(es, DI, &addr64); @@ -830,7 +830,7 @@ opINSB_a32(uint32_t fetchdat) addr64 = 0x00000000; SEG_CHECK_WRITE(&cpu_state.seg_es); - check_io_perm(DX); + check_io_perm(DX, 1); high_page = 0; CHECK_WRITE(&cpu_state.seg_es, EDI, EDI); do_mmut_wb(es, EDI, &addr64); @@ -857,8 +857,7 @@ opINSW_a16(uint32_t fetchdat) addr64a[0] = addr64a[1] = 0x00000000; SEG_CHECK_WRITE(&cpu_state.seg_es); - check_io_perm(DX); - check_io_perm(DX + 1); + check_io_perm(DX, 2); CHECK_WRITE(&cpu_state.seg_es, DI, DI + 1UL); high_page = 0; do_mmut_ww(es, DI, addr64a); @@ -885,8 +884,7 @@ opINSW_a32(uint32_t fetchdat) SEG_CHECK_WRITE(&cpu_state.seg_es); high_page = 0; - check_io_perm(DX); - check_io_perm(DX + 1); + check_io_perm(DX, 2); CHECK_WRITE(&cpu_state.seg_es, EDI, EDI + 1UL); do_mmut_ww(es, EDI, addr64a); if (cpu_state.abrt) @@ -912,10 +910,7 @@ opINSL_a16(uint32_t fetchdat) addr64a[0] = addr64a[1] = addr64a[2] = addr64a[3] = 0x00000000; SEG_CHECK_WRITE(&cpu_state.seg_es); - check_io_perm(DX); - check_io_perm(DX + 1); - check_io_perm(DX + 2); - check_io_perm(DX + 3); + check_io_perm(DX, 4); CHECK_WRITE(&cpu_state.seg_es, DI, DI + 3UL); high_page = 0; do_mmut_wl(es, DI, addr64a); @@ -941,10 +936,7 @@ opINSL_a32(uint32_t fetchdat) addr64a[0] = addr64a[1] = addr64a[2] = addr64a[3] = 0x00000000; SEG_CHECK_WRITE(&cpu_state.seg_es); - check_io_perm(DX); - check_io_perm(DX + 1); - check_io_perm(DX + 2); - check_io_perm(DX + 3); + check_io_perm(DX, 4); CHECK_WRITE(&cpu_state.seg_es, EDI, EDI + 3UL); high_page = 0; do_mmut_wl(es, DI, addr64a); @@ -973,7 +965,7 @@ opOUTSB_a16(uint32_t fetchdat) temp = readmemb(cpu_state.ea_seg->base, SI); if (cpu_state.abrt) return 1; - check_io_perm(DX); + check_io_perm(DX, 1); if (cpu_state.flags & D_FLAG) SI--; else @@ -993,7 +985,7 @@ opOUTSB_a32(uint32_t fetchdat) temp = readmemb(cpu_state.ea_seg->base, ESI); if (cpu_state.abrt) return 1; - check_io_perm(DX); + check_io_perm(DX, 1); if (cpu_state.flags & D_FLAG) ESI--; else @@ -1014,8 +1006,7 @@ opOUTSW_a16(uint32_t fetchdat) temp = readmemw(cpu_state.ea_seg->base, SI); if (cpu_state.abrt) return 1; - check_io_perm(DX); - check_io_perm(DX + 1); + check_io_perm(DX, 2); if (cpu_state.flags & D_FLAG) SI -= 2; else @@ -1035,8 +1026,7 @@ opOUTSW_a32(uint32_t fetchdat) temp = readmemw(cpu_state.ea_seg->base, ESI); if (cpu_state.abrt) return 1; - check_io_perm(DX); - check_io_perm(DX + 1); + check_io_perm(DX, 2); if (cpu_state.flags & D_FLAG) ESI -= 2; else @@ -1057,10 +1047,7 @@ opOUTSL_a16(uint32_t fetchdat) temp = readmeml(cpu_state.ea_seg->base, SI); if (cpu_state.abrt) return 1; - check_io_perm(DX); - check_io_perm(DX + 1); - check_io_perm(DX + 2); - check_io_perm(DX + 3); + check_io_perm(DX, 4); if (cpu_state.flags & D_FLAG) SI -= 4; else @@ -1080,10 +1067,7 @@ opOUTSL_a32(uint32_t fetchdat) temp = readmeml(cpu_state.ea_seg->base, ESI); if (cpu_state.abrt) return 1; - check_io_perm(DX); - check_io_perm(DX + 1); - check_io_perm(DX + 2); - check_io_perm(DX + 3); + check_io_perm(DX, 4); if (cpu_state.flags & D_FLAG) ESI -= 4; else From 9f55afc7a1b7ee85005904302444a9dc7c6347ba Mon Sep 17 00:00:00 2001 From: RichardG867 Date: Sat, 22 Apr 2023 21:37:41 -0300 Subject: [PATCH 15/20] Add LIKELY/UNLIKELY macros --- src/include/86box/86box.h | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/include/86box/86box.h b/src/include/86box/86box.h index b88fa24ef..a4c0a5761 100644 --- a/src/include/86box/86box.h +++ b/src/include/86box/86box.h @@ -55,6 +55,14 @@ #define BCD16(x) ((((x) / 1000) << 12) | (((x) / 100) << 8) | BCD8(x)) #define BCD32(x) ((((x) / 10000000) << 28) | (((x) / 1000000) << 24) | (((x) / 100000) << 20) | (((x) / 10000) << 16) | BCD16(x)) +#if defined(__GNUC__) || defined(__clang__) +# define UNLIKELY(x) __builtin_expect((x), 0) +# define LIKELY(x) __builtin_expect((x), 1) +#else +# define UNLIKELY(x) (x) +# define LIKELY(x) (x) +#endif + #ifdef __cplusplus extern "C" { #endif From 4253c7bae73daa5658c6de4d13bc299e33981347 Mon Sep 17 00:00:00 2001 From: RichardG867 Date: Sat, 22 Apr 2023 22:28:18 -0300 Subject: [PATCH 16/20] 386_common: Handle IOPB segment limit corner case more like the old code --- src/cpu/386_common.c | 31 +++++++++++++++++-------------- 1 file changed, 17 insertions(+), 14 deletions(-) diff --git a/src/cpu/386_common.c b/src/cpu/386_common.c index 454815de0..25afccc95 100644 --- a/src/cpu/386_common.c +++ b/src/cpu/386_common.c @@ -1053,13 +1053,13 @@ enter_smm(int in_hlt) memset(saved_state, 0x00, SMM_SAVE_STATE_MAP_SIZE * sizeof(uint32_t)); - if (is_cxsmm) /* Cx6x86 */ + if (is_cxsmm) /* Cx6x86 */ smram_save_state_cyrix(saved_state, in_hlt); else if (is_pentium || is_am486) /* Am486 / 5x86 / Intel P5 (Pentium) */ smram_save_state_p5(saved_state, in_hlt); - else if (is_k5 || is_k6) /* AMD K5 and K6 */ + else if (is_k5 || is_k6) /* AMD K5 and K6 */ smram_save_state_amd_k(saved_state, in_hlt); - else if (is_p6) /* Intel P6 (Pentium Pro, Pentium II, Celeron) */ + else if (is_p6) /* Intel P6 (Pentium Pro, Pentium II, Celeron) */ smram_save_state_p6(saved_state, in_hlt); cr0 &= ~0x8000000d; @@ -1224,13 +1224,13 @@ leave_smm(void) } x386_common_log("New SMBASE: %08X (%08X)\n", saved_state[SMRAM_FIELD_P5_SMBASE_OFFSET], saved_state[66]); - if (is_cxsmm) /* Cx6x86 */ + if (is_cxsmm) /* Cx6x86 */ smram_restore_state_cyrix(saved_state); else if (is_pentium || is_am486) /* Am486 / 5x86 / Intel P5 (Pentium) */ smram_restore_state_p5(saved_state); - else if (is_k5 || is_k6) /* AMD K5 and K6 */ + else if (is_k5 || is_k6) /* AMD K5 and K6 */ smram_restore_state_amd_k(saved_state); - else if (is_p6) /* Intel P6 (Pentium Pro, Pentium II, Celeron) */ + else if (is_p6) /* Intel P6 (Pentium Pro, Pentium II, Celeron) */ smram_restore_state_p6(saved_state); in_smm = 0; @@ -1429,24 +1429,27 @@ x86illegal(void) int checkio(uint32_t port, int mask) { - uint16_t t; + uint32_t t; cpl_override = 1; t = readmemw(tr.base, 0x66); - if (cpu_state.abrt) { + if (UNLIKELY(cpu_state.abrt)) { cpl_override = 0; return 0; } - if ((t + (port >> 3UL) + 1) > tr.limit) { - cpl_override = 0; - return mask; + t += (port >> 3UL); + mask <<= (port & 7); + if (UNLIKELY(mask & 0xff00)) { + if (LIKELY(t < tr.limit)) + mask &= readmemwl(tr.base + t); + } else { + if (LIKELY(t <= tr.limit)) + mask &= readmembl(tr.base + t); } - - t = readmemwl(tr.base + t + (port >> 3)); cpl_override = 0; - return (t >> (port & 7)) & mask; + return mask; } #ifdef OLD_DIVEXCP From 982c3a4f38cc63bc5d729ee9a7f98613566e98f2 Mon Sep 17 00:00:00 2001 From: Cacodemon345 Date: Sun, 23 Apr 2023 16:39:56 +0600 Subject: [PATCH 17/20] qt_d3d9renderer: HiDPI and stability fixes --- src/qt/qt_d3d9renderer.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/qt/qt_d3d9renderer.cpp b/src/qt/qt_d3d9renderer.cpp index fed8e72b3..bbbb80e59 100644 --- a/src/qt/qt_d3d9renderer.cpp +++ b/src/qt/qt_d3d9renderer.cpp @@ -80,7 +80,7 @@ D3D9Renderer::showEvent(QShowEvent *event) params.BackBufferCount = 1; params.FullScreen_RefreshRateInHz = D3DPRESENT_RATE_DEFAULT; params.PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE; - params.hDeviceWindow = windowHandle; + params.hDeviceWindow = (HWND) winId(); HRESULT result = d3d9->CreateDeviceEx(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, windowHandle, D3DCREATE_MULTITHREADED | D3DCREATE_HARDWARE_VERTEXPROCESSING, ¶ms, nullptr, &d3d9dev); if (FAILED(result)) @@ -118,10 +118,10 @@ D3D9Renderer::paintEvent(QPaintEvent *event) srcRect.bottom = source.bottom(); srcRect.left = source.left(); srcRect.right = source.right(); - dstRect.top = destination.top(); - dstRect.bottom = destination.bottom(); - dstRect.left = destination.left(); - dstRect.right = destination.right(); + dstRect.top = destination.top() * devicePixelRatioF(); + dstRect.bottom = destination.bottom() * devicePixelRatioF(); + dstRect.left = destination.left() * devicePixelRatioF(); + dstRect.right = destination.right() * devicePixelRatioF(); d3d9dev->BeginScene(); d3d9dev->Clear(0, nullptr, D3DCLEAR_TARGET, 0xFF000000, 0, 0); while (surfaceInUse) { } From 2d222f22c7b7d41252b4cbb4adf6a4444ad9a514 Mon Sep 17 00:00:00 2001 From: Cacodemon345 Date: Sun, 23 Apr 2023 20:39:34 +0600 Subject: [PATCH 18/20] qt: Destroy existing Direct3D 9 devices if it exists --- src/qt/qt_d3d9renderer.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/qt/qt_d3d9renderer.cpp b/src/qt/qt_d3d9renderer.cpp index bbbb80e59..f2c9fe9f4 100644 --- a/src/qt/qt_d3d9renderer.cpp +++ b/src/qt/qt_d3d9renderer.cpp @@ -24,11 +24,16 @@ D3D9Renderer::D3D9Renderer(QWidget *parent, int monitor_index) windowHandle = (HWND) winId(); surfaceInUse = true; + finalized = true; RendererCommon::parentWidget = parent; this->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); this->m_monitor_index = monitor_index; + + d3d9surface = nullptr; + d3d9dev = nullptr; + d3d9 = nullptr; } D3D9Renderer::~D3D9Renderer() @@ -67,6 +72,7 @@ D3D9Renderer::hideEvent(QHideEvent *event) void D3D9Renderer::showEvent(QShowEvent *event) { + if (d3d9) finalize(); params = {}; if (FAILED(Direct3DCreate9Ex(D3D_SDK_VERSION, &d3d9))) { From 3b54cb085eca1ef674604ae10c29cfa3349ecba7 Mon Sep 17 00:00:00 2001 From: OBattler Date: Mon, 24 Apr 2023 02:47:17 +0200 Subject: [PATCH 19/20] Some minor bugfixes. --- src/chipset/ali1543.c | 13 +++++++++---- src/device/kbc_at.c | 26 ++++++++++++++++++++++++-- src/device/kbc_at_dev.c | 2 +- src/device/mouse_ps2.c | 3 +-- src/sio/sio_ali5123.c | 4 ++++ 5 files changed, 39 insertions(+), 9 deletions(-) diff --git a/src/chipset/ali1543.c b/src/chipset/ali1543.c index 0b5fe5761..f3296bd20 100644 --- a/src/chipset/ali1543.c +++ b/src/chipset/ali1543.c @@ -151,11 +151,13 @@ ali1533_write(int func, int addr, uint8_t val, void *priv) break; case 0x41: - /* TODO: Bit 7 selects keyboard controller type: - 0 = AT, 1 = PS/2 */ pic_kbd_latch(1); - pic_mouse_latch(!!(val & 0x40)); - dev->pci_conf[addr] = val & 0xbf; + // pic_kbd_latch(!!(val & 0x80)); + if (dev->type == 1) + pic_mouse_latch(!!(val & 0x40) || !(dev->pci_conf[0x78] & 0x02)); + else + pic_mouse_latch(!!(val & 0x40)); + dev->pci_conf[addr] = val; break; case 0x42: /* ISA Bus Speed */ @@ -431,6 +433,7 @@ ali1533_write(int func, int addr, uint8_t val, void *priv) if (dev->type == 1) { ali1543_log("PCI78 = %02X\n", val); dev->pci_conf[addr] = val & 0x33; + pic_mouse_latch(!!(dev->pci_conf[0x41] & 0x40) || !(val & 0x02)); } break; @@ -1520,6 +1523,8 @@ ali1543_reset(void *priv) ali1533_write(0, 0x74, 0x00, dev); ali1533_write(0, 0x75, 0x00, dev); ali1533_write(0, 0x76, 0x00, dev); + if (dev->type == 1) + ali1533_write(0, 0x78, 0x00, dev); unmask_a20_in_smm = 1; } diff --git a/src/device/kbc_at.c b/src/device/kbc_at.c index 2c9433bd9..9b8a3de3d 100644 --- a/src/device/kbc_at.c +++ b/src/device/kbc_at.c @@ -801,12 +801,30 @@ write64_generic(void *priv, uint8_t val) IBM PS/1: xxxxxxxx IBM PS/2 MCA: xxxxx1xx Intel AMI Pentium BIOS'es with AMI MegaKey KB-5 keyboard controller: x1x1xxxx - Acer: xxx0x0xx + Acer: xxxxx0xx Packard Bell PB450: xxxxx1xx P6RP4: xx1xx1xx Epson Action Tower 2600: xxxx01xx TriGem Hawk: xxxx11xx + Machine input based on current code: 11111111 + Everything non-Green: Pull down bit 7 if not PS/2 and keyboard is inhibited. + Pull down bit 6 if primary display is CGA. + Xi8088: Pull down bit 6 if primary display is MDA. + Acer: Pull down bit 6 if primary display is MDA. + Pull down bit 2 always (must be so to enable CMOS Setup). + IBM PS/1: Pull down bit 6 if current floppy drive is 3.5". + Epson Action Tower 2600: Pull down bit 3 always (for Epson logo). + NCR: Pull down bit 5 always (power-on default speed = high). + Pull down bit 3 if there is no FPU. + Pull down bits 1 and 0 always? + Compaq: Pull down bit 6 if Compaq dual-scan display is in use. + Pull down bit 5 if system board DIP switch is ON. + Pull down bit 4 if CPU speed selected is auto. + Pull down bit 3 if CPU speed selected is slow (4 MHz). + Pull down bit 2 if FPU is present. + Pull down bits 1 and 0 always? + Bit 7: AT KBC only - keyboard inhibited (often physical lock): 0 = yes, 1 = no (also Compaq); Bit 6: Mostly, display: 0 = CGA, 1 = MDA, inverted on Xi8088 and Acer KBC's; Intel AMI MegaKey KB-5: Used for green features, SMM handler expects it to be set; @@ -817,7 +835,6 @@ write64_generic(void *priv, uint8_t val) Compaq: System board DIP switch 5: 0 = ON, 1 = OFF. Bit 4: (Which board?): RAM on motherboard: 0 = 512 kB, 1 = 256 kB; NCR: RAM on motherboard: 0 = unsupported, 1 = 512 kB; - Acer: Must be 0; Intel AMI MegaKey KB-5: Must be 1; IBM PS/1: Ignored; Compaq: 0 = Auto speed selected, 1 = High speed selected. @@ -851,6 +868,7 @@ write64_generic(void *priv, uint8_t val) fixed_bits |= 0x40; if (kbc_ven == KBC_VEN_IBM_PS1) { current_drive = fdc_get_current_drive(); + /* (B0 or F0) | (fdd_is_525(current_drive) on bit 6) */ add_to_kbc_queue_front(dev, dev->p1 | fixed_bits | (fdd_is_525(current_drive) ? 0x40 : 0x00), 0, 0x00); } else if (kbc_ven == KBC_VEN_NCR) { @@ -864,6 +882,7 @@ write64_generic(void *priv, uint8_t val) * bit 1: high/auto speed * bit 0: dma mode */ + /* (B0 or F0) | 0x04 | (display on bit 6) | (fpu on bit 3) */ add_to_kbc_queue_front(dev, (dev->p1 | fixed_bits | (video_is_mda() ? 0x40 : 0x00) | (hasfpu ? 0x08 : 0x00)) & 0xdf, 0, 0x00); } else if (kbc_ven == KBC_VEN_TRIGEM_AMI) { @@ -874,10 +893,13 @@ write64_generic(void *priv, uint8_t val) 0, 0: Generic AMI logo. */ if (dev->misc_flags & FLAG_PCI) fixed_bits |= 8; + /* (B0 or F0) | (0x04 or 0x0c) */ add_to_kbc_queue_front(dev, dev->p1 | fixed_bits, 0, 0x00); } else if (((dev->flags & KBC_TYPE_MASK) >= KBC_TYPE_PS2_1) && ((dev->flags & KBC_TYPE_MASK) < KBC_TYPE_GREEN)) + /* (B0 or F0) | (0x08 or 0x0c) */ add_to_kbc_queue_front(dev, ((dev->p1 | fixed_bits) & 0xf0) | (((dev->flags & KBC_VEN_MASK) == KBC_VEN_ACER) ? 0x08 : 0x0c), 0, 0x00); else + /* (B0 or F0) | (0x04 or 0x44) */ add_to_kbc_queue_front(dev, dev->p1 | fixed_bits, 0, 0x00); dev->p1 = ((dev->p1 + 1) & 3) | (dev->p1 & 0xfc); return 0; diff --git a/src/device/kbc_at_dev.c b/src/device/kbc_at_dev.c index 87fdd51c6..ca3dc1361 100644 --- a/src/device/kbc_at_dev.c +++ b/src/device/kbc_at_dev.c @@ -119,7 +119,7 @@ kbc_at_dev_poll(void *priv) case DEV_STATE_MAIN_2: /* Output from scan queue if needed and then return to main loop #1. */ if (*dev->scan && (dev->port->out_new == -1) && (dev->queue_start != dev->queue_end)) { - kbc_at_dev_log("%s %1: %02X (DATA) on channel 1\n", dev->name, dev->inst, dev->queue[dev->queue_start]); + kbc_at_dev_log("%s: %02X (DATA) on channel 1\n", dev->name, dev->queue[dev->queue_start]); dev->port->out_new = dev->queue[dev->queue_start]; dev->queue_start = (dev->queue_start + 1) & 0xf; } diff --git a/src/device/mouse_ps2.c b/src/device/mouse_ps2.c index 4027c6173..5563909ba 100644 --- a/src/device/mouse_ps2.c +++ b/src/device/mouse_ps2.c @@ -135,6 +135,7 @@ ps2_set_defaults(atkbc_dev_t *dev) dev->mode = MODE_STREAM; dev->rate = 1; dev->flags &= 0x88; + mouse_scan = 0; } static void @@ -144,8 +145,6 @@ ps2_bat(void *priv) ps2_set_defaults(dev); - mouse_scan = 1; - kbc_at_dev_queue_add(dev, 0xaa, 0); kbc_at_dev_queue_add(dev, 0x00, 0); } diff --git a/src/sio/sio_ali5123.c b/src/sio/sio_ali5123.c index 33e4022c6..54949a125 100644 --- a/src/sio/sio_ali5123.c +++ b/src/sio/sio_ali5123.c @@ -174,6 +174,7 @@ ali5123_reset(ali5123_t *dev) serial_setup(dev->uart[1], 0x03e8, dev->ld_regs[5][0x70]); /* Logical device 7: Keyboard */ + dev->ld_regs[7][0x30] = 1; dev->ld_regs[7][0x70] = 1; /* TODO: Register F0 bit 6: 0 = PS/2, 1 = AT */ @@ -253,6 +254,9 @@ ali5123_write(uint16_t port, uint8_t val, void *priv) case 0x06: case 0x08 ... 0x0a: return; + case 0x07: + if (dev->cur_reg == 0xf0) + val &= 0xbf; } dev->ld_regs[cur_ld][dev->cur_reg] = val; } From 78a897f07aaf24c9e3b0cbcfa52fe0f6678df5b9 Mon Sep 17 00:00:00 2001 From: OBattler Date: Wed, 26 Apr 2023 01:42:23 +0200 Subject: [PATCH 20/20] Some minor fixes, the PS/2 mouse command F0h (set remote mode) is now implemented, the PS/2 mouse command F3h (set sample rate) now actually changes the host mouse polling rate, and the Intel SIO IB and ZB now forcibly initialize a keyboard and mouse IRQ latch if the board has a PS/2 keyboard controller, to simulate the presence of a latch external to the chip. --- src/chipset/intel_sio.c | 20 +++++++++++++++++--- src/device/kbc_at.c | 3 ++- src/device/kbc_at_dev.c | 4 ++-- src/device/mouse.c | 24 ++++++++++++++++++------ src/device/mouse_ps2.c | 14 +++++++++++++- src/include/86box/mouse.h | 2 ++ src/pic.c | 4 ++-- 7 files changed, 56 insertions(+), 15 deletions(-) diff --git a/src/chipset/intel_sio.c b/src/chipset/intel_sio.c index eb7aad983..3f253d832 100644 --- a/src/chipset/intel_sio.c +++ b/src/chipset/intel_sio.c @@ -200,9 +200,11 @@ sio_write(int func, int addr, uint8_t val, void *priv) dev->regs[addr] = val; break; case 0x4c: + dev->regs[addr] = (val & 0x7f); + break; case 0x4d: dev->regs[addr] = (val & 0x7f); - pic_mouse_latch(!!(val & 0x10)); + // pic_mouse_latch(!!(val & 0x10)); break; case 0x4f: dev->regs[addr] = val; @@ -394,7 +396,7 @@ sio_reset_hard(void *priv) dev->regs[0x4b] = 0x0f; dev->regs[0x4c] = 0x56; dev->regs[0x4d] = 0x40; - pic_mouse_latch(0x00); + // pic_mouse_latch(0x00); dev->regs[0x4e] = 0x07; dev->regs[0x4f] = 0x4f; dev->regs[0x57] = 0x04; @@ -544,7 +546,19 @@ sio_init(const device_t *info) // device_add(&i8254_sec_device); - pic_kbd_latch(0x01); + // pic_kbd_latch(0x01); + + /* The situation is as follow: SIO.AB has the IRQ 1 latch but SIO.IB and SIO.ZB do not, + and I suspect that because of that, the IRQ 12 latch on SIO.IB and SIO.ZB, while + evidently planned and documented in the datashet, was basically non-functional, and + motherboard manufacturers had to install their own latches to use PS/2 keyboards + and/or mice. One such example is the AMI Excalibur PCI Pentium, which never enables + the SIO.ZB's IRQ 12 latch but clearly expects one since otherwise, the PS/2 mouse + behaves erractically in the WinBIOS CMOS Setup. */ + if (machine_has_bus(machine, MACHINE_BUS_PS2)) { + pic_kbd_latch(0x01); + pic_mouse_latch(0x01); + } return dev; } diff --git a/src/device/kbc_at.c b/src/device/kbc_at.c index 9b8a3de3d..24121e699 100644 --- a/src/device/kbc_at.c +++ b/src/device/kbc_at.c @@ -1024,7 +1024,7 @@ write64_ami(void *priv, uint8_t val) kbc_at_queue_add(dev, 0x28); kbc_at_queue_add(dev, 0x00); dev->state = STATE_KBC_OUT; - break; + return 0; case 0xa1: /* get controller version */ kbc_at_log("ATkbc: AMI - get controller version\n"); @@ -1118,6 +1118,7 @@ write64_ami(void *priv, uint8_t val) add_to_kbc_queue_front(dev, 0x00, 0, 0x00); return 0; + /* TODO: The ICS SB486PV sends command B4 but expects to read *TWO* bytes. */ case 0xb4: case 0xb5: /* set KBC lines P22-P23 (P2 bits 2-3) low */ kbc_at_log("ATkbc: set KBC lines P22-P23 (P2 bits 2-3) low\n"); diff --git a/src/device/kbc_at_dev.c b/src/device/kbc_at_dev.c index ca3dc1361..71a0b4e08 100644 --- a/src/device/kbc_at_dev.c +++ b/src/device/kbc_at_dev.c @@ -173,9 +173,9 @@ kbc_at_dev_reset(atkbc_dev_t *dev, int do_fa) if (do_fa) kbc_at_dev_queue_add(dev, 0xfa, 0); - dev->execute_bat(dev); - dev->state = DEV_STATE_MAIN_OUT; + + dev->execute_bat(dev); } atkbc_dev_t * diff --git a/src/device/mouse.c b/src/device/mouse.c index 13d9999c7..0ee714377 100644 --- a/src/device/mouse.c +++ b/src/device/mouse.c @@ -102,6 +102,8 @@ static int mouse_nbut; static int (*mouse_dev_poll)(int x, int y, int z, int b, void *priv); static void (*mouse_poll_ex)(void) = NULL; +static double sample_rate = 200.0; + #ifdef ENABLE_MOUSE_LOG int mouse_do_log = ENABLE_MOUSE_LOG; @@ -153,7 +155,7 @@ static void mouse_timer_poll(void *priv) { /* Poll at 255 Hz, maximum supported by PS/2 mic. */ - timer_on_auto(&mouse_timer, 1000000.0 / 255.0); + timer_on_auto(&mouse_timer, 1000000.0 / sample_rate); #ifdef USE_GDBSTUB /* avoid a KBC FIFO overflow when CPU emulation is stalled */ if (gdbstub_step == GDBSTUB_EXEC) @@ -161,6 +163,15 @@ mouse_timer_poll(void *priv) mouse_process(); } +void +mouse_set_sample_rate(double new_rate) +{ + timer_stop(&mouse_timer); + + sample_rate = new_rate; + timer_on_auto(&mouse_timer, 1000000.0 / sample_rate); +} + void mouse_reset(void) { @@ -179,15 +190,16 @@ mouse_reset(void) if (mouse_type == 0) return; + timer_add(&mouse_timer, mouse_timer_poll, NULL, 0); + + /* Poll at 100 Hz, the default of a PS/2 mouse. */ + sample_rate = 100.0; + timer_on_auto(&mouse_timer, 1000000.0 / sample_rate); + mouse_curr = mouse_devices[mouse_type].device; if (mouse_curr != NULL) mouse_priv = device_add(mouse_curr); - - timer_add(&mouse_timer, mouse_timer_poll, NULL, 0); - - /* Poll at 255 Hz, maximum supported by PS/2 mic. */ - timer_on_auto(&mouse_timer, 1000000.0 / 255.0); } /* Callback from the hardware driver. */ diff --git a/src/device/mouse_ps2.c b/src/device/mouse_ps2.c index 5563909ba..7d9730f28 100644 --- a/src/device/mouse_ps2.c +++ b/src/device/mouse_ps2.c @@ -133,7 +133,9 @@ static void ps2_set_defaults(atkbc_dev_t *dev) { dev->mode = MODE_STREAM; - dev->rate = 1; + dev->rate = 100; + mouse_set_sample_rate(100.0); + dev->resolution = 2; dev->flags &= 0x88; mouse_scan = 0; } @@ -177,6 +179,7 @@ ps2_write(void *priv) case 0xf3: /* set sample rate */ dev->rate = val; + mouse_set_sample_rate((double) val); kbc_at_dev_queue_add(dev, 0xfa, 0); /* Command response */ mouse_ps2_log("%s: Set sample rate [%02X]\n", dev->name, val); break; @@ -227,6 +230,7 @@ ps2_write(void *priv) case 0xea: /* set stream */ mouse_ps2_log("%s: Set stream\n", dev->name); dev->flags &= ~FLAG_CTRLDAT; + dev->mode = MODE_STREAM; mouse_scan = 1; kbc_at_dev_queue_add(dev, 0xfa, 0); /* ACK for command byte */ break; @@ -238,6 +242,14 @@ ps2_write(void *priv) ps2_report_coordinates(dev, 0); break; + case 0xf0: /* set remote */ + mouse_ps2_log("%s: Set remote\n", dev->name); + dev->flags &= ~FLAG_CTRLDAT; + dev->mode = MODE_REMOTE; + mouse_scan = 1; + kbc_at_dev_queue_add(dev, 0xfa, 0); /* ACK for command byte */ + break; + case 0xf2: /* read ID */ mouse_ps2_log("%s: Read ID\n", dev->name); kbc_at_dev_queue_add(dev, 0xfa, 0); diff --git a/src/include/86box/mouse.h b/src/include/86box/mouse.h index 317e267a0..b697c5d38 100644 --- a/src/include/86box/mouse.h +++ b/src/include/86box/mouse.h @@ -80,6 +80,8 @@ extern void mouse_poll(void); extern void mouse_bus_set_irq(void *priv, int irq); +extern void mouse_set_sample_rate(double new_rate); + extern char *mouse_get_name(int mouse); extern char *mouse_get_internal_name(int mouse); extern int mouse_get_from_internal_name(char *s); diff --git a/src/pic.c b/src/pic.c index 25a90e1c7..4f9b8aa8f 100644 --- a/src/pic.c +++ b/src/pic.c @@ -202,7 +202,7 @@ find_best_interrupt(pic_t *dev) intr = dev->interrupt = (ret == -1) ? 0x17 : ret; - if (dev->at && (ret != 1)) { + if (dev->at && (ret != -1)) { if (dev == &pic2) intr += 8; @@ -644,7 +644,7 @@ picint_common(uint16_t num, int level, int set) pic2.lines |= (num >> 8); /* Latch IRQ 12 if the mouse latch is enabled. */ - if (mouse_latch && (num & 0x1000)) + if ((num & 0x1000) && mouse_latch) pic2.lines |= 0x10; pic2.irr |= (num >> 8);