/* * 86Box A hypervisor and IBM PC system emulator that specializes in * running old operating systems and software designed for IBM * PC systems and compatibles from 1981 through fairly recent * system designs based on the PCI bus. * * This file is part of the 86Box distribution. * * Implementation of the XT-style keyboard. * * * * Authors: Sarah Walker, * Miran Grca, * Fred N. van Kempen, * * Copyright 2008-2019 Sarah Walker. * Copyright 2016-2019 Miran Grca. * Copyright 2017-2019 Fred N. van kempen. */ #include #include #include #include #include #include <86box/86box.h> #include <86box/device.h> #include <86box/timer.h> #include <86box/fdd.h> #include <86box/machine.h> #include <86box/m_xt_t1000.h> #include <86box/io.h> #include <86box/pic.h> #include <86box/pit.h> #include <86box/ppi.h> #include <86box/mem.h> #include <86box/rom.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_LOCK 0x10 #define STAT_CD 0x08 #define STAT_SYSFLAG 0x04 #define STAT_IFULL 0x02 #define STAT_OFULL 0x01 typedef struct { int want_irq; int blocked; int tandy; uint8_t pa, pb, pd; uint8_t key_waiting; uint8_t type; pc_timer_t send_delay_timer; } xtkbd_t; /*XT keyboard has no escape scancodes, and no scancodes beyond 53*/ const scancode scancode_xt[512] = { { {0}, {0} }, { {0x01, 0}, {0x81, 0} }, { {0x02, 0}, {0x82, 0} }, { {0x03, 0}, {0x83, 0} }, { {0x04, 0}, {0x84, 0} }, { {0x05, 0}, {0x85, 0} }, { {0x06, 0}, {0x86, 0} }, { {0x07, 0}, {0x87, 0} }, { {0x08, 0}, {0x88, 0} }, { {0x09, 0}, {0x89, 0} }, { {0x0a, 0}, {0x8a, 0} }, { {0x0b, 0}, {0x8b, 0} }, { {0x0c, 0}, {0x8c, 0} }, { {0x0d, 0}, {0x8d, 0} }, { {0x0e, 0}, {0x8e, 0} }, { {0x0f, 0}, {0x8f, 0} }, { {0x10, 0}, {0x90, 0} }, { {0x11, 0}, {0x91, 0} }, { {0x12, 0}, {0x92, 0} }, { {0x13, 0}, {0x93, 0} }, { {0x14, 0}, {0x94, 0} }, { {0x15, 0}, {0x95, 0} }, { {0x16, 0}, {0x96, 0} }, { {0x17, 0}, {0x97, 0} }, { {0x18, 0}, {0x98, 0} }, { {0x19, 0}, {0x99, 0} }, { {0x1a, 0}, {0x9a, 0} }, { {0x1b, 0}, {0x9b, 0} }, { {0x1c, 0}, {0x9c, 0} }, { {0x1d, 0}, {0x9d, 0} }, { {0x1e, 0}, {0x9e, 0} }, { {0x1f, 0}, {0x9f, 0} }, { {0x20, 0}, {0xa0, 0} }, { {0x21, 0}, {0xa1, 0} }, { {0x22, 0}, {0xa2, 0} }, { {0x23, 0}, {0xa3, 0} }, { {0x24, 0}, {0xa4, 0} }, { {0x25, 0}, {0xa5, 0} }, { {0x26, 0}, {0xa6, 0} }, { {0x27, 0}, {0xa7, 0} }, { {0x28, 0}, {0xa8, 0} }, { {0x29, 0}, {0xa9, 0} }, { {0x2a, 0}, {0xaa, 0} }, { {0x2b, 0}, {0xab, 0} }, { {0x2c, 0}, {0xac, 0} }, { {0x2d, 0}, {0xad, 0} }, { {0x2e, 0}, {0xae, 0} }, { {0x2f, 0}, {0xaf, 0} }, { {0x30, 0}, {0xb0, 0} }, { {0x31, 0}, {0xb1, 0} }, { {0x32, 0}, {0xb2, 0} }, { {0x33, 0}, {0xb3, 0} }, { {0x34, 0}, {0xb4, 0} }, { {0x35, 0}, {0xb5, 0} }, { {0x36, 0}, {0xb6, 0} }, { {0x37, 0}, {0xb7, 0} }, { {0x38, 0}, {0xb8, 0} }, { {0x39, 0}, {0xb9, 0} }, { {0x3a, 0}, {0xba, 0} }, { {0x3b, 0}, {0xbb, 0} }, { {0x3c, 0}, {0xbc, 0} }, { {0x3d, 0}, {0xbd, 0} }, { {0x3e, 0}, {0xbe, 0} }, { {0x3f, 0}, {0xbf, 0} }, { {0x40, 0}, {0xc0, 0} }, { {0x41, 0}, {0xc1, 0} }, { {0x42, 0}, {0xc2, 0} }, { {0x43, 0}, {0xc3, 0} }, { {0x44, 0}, {0xc4, 0} }, { {0x45, 0}, {0xc5, 0} }, { {0x46, 0}, {0xc6, 0} }, { {0x47, 0}, {0xc7, 0} }, { {0x48, 0}, {0xc8, 0} }, { {0x49, 0}, {0xc9, 0} }, { {0x4a, 0}, {0xca, 0} }, { {0x4b, 0}, {0xcb, 0} }, { {0x4c, 0}, {0xcc, 0} }, { {0x4d, 0}, {0xcd, 0} }, { {0x4e, 0}, {0xce, 0} }, { {0x4f, 0}, {0xcf, 0} }, { {0x50, 0}, {0xd0, 0} }, { {0x51, 0}, {0xd1, 0} }, { {0x52, 0}, {0xd2, 0} }, { {0x53, 0}, {0xd3, 0} }, { {0}, {0} }, { {0}, {0} }, { {0}, {0} }, { {0}, {0} }, /*054*/ { {0}, {0} }, { {0}, {0} }, { {0}, {0} }, { {0}, {0} }, /*058*/ { {0}, {0} }, { {0}, {0} }, { {0}, {0} }, { {0}, {0} }, /*05c*/ { {0}, {0} }, { {0}, {0} }, { {0}, {0} }, { {0}, {0} }, /*060*/ { {0}, {0} }, { {0}, {0} }, { {0}, {0} }, { {0}, {0} }, /*064*/ { {0}, {0} }, { {0}, {0} }, { {0}, {0} }, { {0}, {0} }, /*068*/ { {0}, {0} }, { {0}, {0} }, { {0}, {0} }, { {0}, {0} }, /*06c*/ { {0}, {0} }, { {0}, {0} }, { {0}, {0} }, { {0}, {0} }, /*070*/ { {0}, {0} }, { {0}, {0} }, { {0}, {0} }, { {0}, {0} }, /*074*/ { {0}, {0} }, { {0}, {0} }, { {0}, {0} }, { {0}, {0} }, /*078*/ { {0}, {0} }, { {0}, {0} }, { {0}, {0} }, { {0}, {0} }, /*07c*/ { {0}, {0} }, { {0}, {0} }, { {0}, {0} }, { {0}, {0} }, /*080*/ { {0}, {0} }, { {0}, {0} }, { {0}, {0} }, { {0}, {0} }, /*084*/ { {0}, {0} }, { {0}, {0} }, { {0}, {0} }, { {0}, {0} }, /*088*/ { {0}, {0} }, { {0}, {0} }, { {0}, {0} }, { {0}, {0} }, /*08c*/ { {0}, {0} }, { {0}, {0} }, { {0}, {0} }, { {0}, {0} }, /*090*/ { {0}, {0} }, { {0}, {0} }, { {0}, {0} }, { {0}, {0} }, /*094*/ { {0}, {0} }, { {0}, {0} }, { {0}, {0} }, { {0}, {0} }, /*098*/ { {0}, {0} }, { {0}, {0} }, { {0}, {0} }, { {0}, {0} }, /*09c*/ { {0}, {0} }, { {0}, {0} }, { {0}, {0} }, { {0}, {0} }, /*0a0*/ { {0}, {0} }, { {0}, {0} }, { {0}, {0} }, { {0}, {0} }, /*0a4*/ { {0}, {0} }, { {0}, {0} }, { {0}, {0} }, { {0}, {0} }, /*0a8*/ { {0}, {0} }, { {0}, {0} }, { {0}, {0} }, { {0}, {0} }, /*0ac*/ { {0}, {0} }, { {0}, {0} }, { {0}, {0} }, { {0}, {0} }, /*0b0*/ { {0}, {0} }, { {0}, {0} }, { {0}, {0} }, { {0}, {0} }, /*0b4*/ { {0}, {0} }, { {0}, {0} }, { {0}, {0} }, { {0}, {0} }, /*0b8*/ { {0}, {0} }, { {0}, {0} }, { {0}, {0} }, { {0}, {0} }, /*0bc*/ { {0}, {0} }, { {0}, {0} }, { {0}, {0} }, { {0}, {0} }, /*0c0*/ { {0}, {0} }, { {0}, {0} }, { {0}, {0} }, { {0}, {0} }, /*0c4*/ { {0}, {0} }, { {0}, {0} }, { {0}, {0} }, { {0}, {0} }, /*0c8*/ { {0}, {0} }, { {0}, {0} }, { {0}, {0} }, { {0}, {0} }, /*0cc*/ { {0}, {0} }, { {0}, {0} }, { {0}, {0} }, { {0}, {0} }, /*0d0*/ { {0}, {0} }, { {0}, {0} }, { {0}, {0} }, { {0}, {0} }, /*0d4*/ { {0}, {0} }, { {0}, {0} }, { {0}, {0} }, { {0}, {0} }, /*0d8*/ { {0}, {0} }, { {0}, {0} }, { {0}, {0} }, { {0}, {0} }, /*0dc*/ { {0}, {0} }, { {0}, {0} }, { {0}, {0} }, { {0}, {0} }, /*0e0*/ { {0}, {0} }, { {0}, {0} }, { {0}, {0} }, { {0}, {0} }, /*0e4*/ { {0}, {0} }, { {0}, {0} }, { {0}, {0} }, { {0}, {0} }, /*0e8*/ { {0}, {0} }, { {0}, {0} }, { {0}, {0} }, { {0}, {0} }, /*0ec*/ { {0}, {0} }, { {0}, {0} }, { {0}, {0} }, { {0}, {0} }, /*0f0*/ { {0}, {0} }, { {0}, {0} }, { {0}, {0} }, { {0}, {0} }, /*0f4*/ { {0}, {0} }, { {0}, {0} }, { {0}, {0} }, { {0}, {0} }, /*0f8*/ { {0}, {0} }, { {0}, {0} }, { {0}, {0} }, { {0}, {0} }, /*0fc*/ { {0}, {0} }, { {0}, {0} }, { {0}, {0} }, { {0}, {0} }, /*100*/ { {0}, {0} }, { {0}, {0} }, { {0}, {0} }, { {0}, {0} }, /*104*/ { {0}, {0} }, { {0}, {0} }, { {0}, {0} }, { {0}, {0} }, /*108*/ { {0}, {0} }, { {0}, {0} }, { {0}, {0} }, { {0}, {0} }, /*10c*/ { {0}, {0} }, { {0}, {0} }, { {0}, {0} }, { {0}, {0} }, /*110*/ { {0}, {0} }, { {0}, {0} }, { {0}, {0} }, { {0}, {0} }, /*114*/ { {0}, {0} }, { {0}, {0} }, { {0}, {0} }, { {0}, {0} }, /*118*/ { {0x1c, 0}, {0x9c, 0} }, { {0x1d, 0}, {0x9d, 0} }, { {0}, {0} }, { {0}, {0} }, /*11c*/ { {0}, {0} }, { {0}, {0} }, { {0}, {0} }, { {0}, {0} }, /*120*/ { {0}, {0} }, { {0}, {0} }, { {0}, {0} }, { {0}, {0} }, /*124*/ { {0}, {0} }, { {0}, {0} }, { {0}, {0} }, { {0}, {0} }, /*128*/ { {0}, {0} }, { {0}, {0} }, { {0}, {0} }, { {0}, {0} }, /*12c*/ { {0}, {0} }, { {0}, {0} }, { {0}, {0} }, { {0}, {0} }, /*130*/ { {0}, {0} }, { {0x35, 0}, {0xb5, 0} }, { {0}, {0} }, { {0x37, 0}, {0xb7, 0} }, /*134*/ { {0x38, 0}, {0xb8, 0} }, { {0}, {0} }, { {0}, {0} }, { {0}, {0} }, /*138*/ { {0}, {0} }, { {0}, {0} }, { {0}, {0} }, { {0}, {0} }, /*13c*/ { {0}, {0} }, { {0}, {0} }, { {0}, {0} }, { {0}, {0} }, /*140*/ { {0}, {0} }, { {0}, {0} }, { {0x46, 0}, {0xc6, 0} }, { {0x47, 0}, {0xc7, 0} }, /*144*/ { {0x48, 0}, {0xc8, 0} }, { {0x49, 0}, {0xc9, 0} }, { {0}, {0} }, { {0x4b, 0}, {0xcb, 0} }, /*148*/ { {0}, {0} }, { {0x4d, 0}, {0xcd, 0} }, { {0}, {0} }, { {0x4f, 0}, {0xcf, 0} }, /*14c*/ { {0x50, 0}, {0xd0, 0} }, { {0x51, 0}, {0xd1, 0} }, { {0x52, 0}, {0xd2, 0} }, { {0x53, 0}, {0xd3, 0} }, /*150*/ { {0}, {0} }, { {0}, {0} }, { {0}, {0} }, { {0}, {0} }, /*154*/ { {0}, {0} }, { {0}, {0} }, { {0}, {0} }, { {0}, {0} }, /*158*/ { {0}, {0} }, { {0}, {0} }, { {0}, {0} }, { {0}, {0} }, /*15c*/ { {0}, {0} }, { {0}, {0} }, { {0}, {0} }, { {0}, {0} }, /*160*/ { {0}, {0} }, { {0}, {0} }, { {0}, {0} }, { {0}, {0} }, /*164*/ { {0}, {0} }, { {0}, {0} }, { {0}, {0} }, { {0}, {0} }, /*168*/ { {0}, {0} }, { {0}, {0} }, { {0}, {0} }, { {0}, {0} }, /*16c*/ { {0}, {0} }, { {0}, {0} }, { {0}, {0} }, { {0}, {0} }, /*170*/ { {0}, {0} }, { {0}, {0} }, { {0}, {0} }, { {0}, {0} }, /*174*/ { {0}, {0} }, { {0}, {0} }, { {0}, {0} }, { {0}, {0} }, /*148*/ { {0}, {0} }, { {0}, {0} }, { {0}, {0} }, { {0}, {0} }, /*17c*/ { {0}, {0} }, { {0}, {0} }, { {0}, {0} }, { {0}, {0} }, /*180*/ { {0}, {0} }, { {0}, {0} }, { {0}, {0} }, { {0}, {0} }, /*184*/ { {0}, {0} }, { {0}, {0} }, { {0}, {0} }, { {0}, {0} }, /*88*/ { {0}, {0} }, { {0}, {0} }, { {0}, {0} }, { {0}, {0} }, /*18c*/ { {0}, {0} }, { {0}, {0} }, { {0}, {0} }, { {0}, {0} }, /*190*/ { {0}, {0} }, { {0}, {0} }, { {0}, {0} }, { {0}, {0} }, /*194*/ { {0}, {0} }, { {0}, {0} }, { {0}, {0} }, { {0}, {0} }, /*198*/ { {0}, {0} }, { {0}, {0} }, { {0}, {0} }, { {0}, {0} }, /*19c*/ { {0}, {0} }, { {0}, {0} }, { {0}, {0} }, { {0}, {0} }, /*1a0*/ { {0}, {0} }, { {0}, {0} }, { {0}, {0} }, { {0}, {0} }, /*1a4*/ { {0}, {0} }, { {0}, {0} }, { {0}, {0} }, { {0}, {0} }, /*1a8*/ { {0}, {0} }, { {0}, {0} }, { {0}, {0} }, { {0}, {0} }, /*1ac*/ { {0}, {0} }, { {0}, {0} }, { {0}, {0} }, { {0}, {0} }, /*1b0*/ { {0}, {0} }, { {0}, {0} }, { {0}, {0} }, { {0}, {0} }, /*1b4*/ { {0}, {0} }, { {0}, {0} }, { {0}, {0} }, { {0}, {0} }, /*1b8*/ { {0}, {0} }, { {0}, {0} }, { {0}, {0} }, { {0}, {0} }, /*1bc*/ { {0}, {0} }, { {0}, {0} }, { {0}, {0} }, { {0}, {0} }, /*1c0*/ { {0}, {0} }, { {0}, {0} }, { {0}, {0} }, { {0}, {0} }, /*1c4*/ { {0}, {0} }, { {0}, {0} }, { {0}, {0} }, { {0}, {0} }, /*1c8*/ { {0}, {0} }, { {0}, {0} }, { {0}, {0} }, { {0}, {0} }, /*1cc*/ { {0}, {0} }, { {0}, {0} }, { {0}, {0} }, { {0}, {0} }, /*1d0*/ { {0}, {0} }, { {0}, {0} }, { {0}, {0} }, { {0}, {0} }, /*1d4*/ { {0}, {0} }, { {0}, {0} }, { {0}, {0} }, { {0}, {0} }, /*1d8*/ { {0}, {0} }, { {0}, {0} }, { {0}, {0} }, { {0}, {0} }, /*1dc*/ { {0}, {0} }, { {0}, {0} }, { {0}, {0} }, { {0}, {0} }, /*1e0*/ { {0}, {0} }, { {0}, {0} }, { {0}, {0} }, { {0}, {0} }, /*1e4*/ { {0}, {0} }, { {0}, {0} }, { {0}, {0} }, { {0}, {0} }, /*1e8*/ { {0}, {0} }, { {0}, {0} }, { {0}, {0} }, { {0}, {0} }, /*1ec*/ { {0}, {0} }, { {0}, {0} }, { {0}, {0} }, { {0}, {0} }, /*1f0*/ { {0}, {0} }, { {0}, {0} }, { {0}, {0} }, { {0}, {0} }, /*1f4*/ { {0}, {0} }, { {0}, {0} }, { {0}, {0} }, { {0}, {0} }, /*1f8*/ { {0}, {0} }, { {0}, {0} }, { {0}, {0} }, { {0}, {0} } /*1fc*/ }; static uint8_t key_queue[16]; static int key_queue_start = 0, key_queue_end = 0; static int is_t1x00 = 0; #ifdef ENABLE_KEYBOARD_XT_LOG int keyboard_xt_do_log = ENABLE_KEYBOARD_XT_LOG; static void kbd_log(const char *fmt, ...) { va_list ap; if (keyboard_xt_do_log) { va_start(ap, fmt); pclog_ex(fmt, ap); va_end(ap); } } #else #define kbd_log(fmt, ...) #endif static void kbd_poll(void *priv) { xtkbd_t *kbd = (xtkbd_t *)priv; timer_advance_u64(&kbd->send_delay_timer, 1000 * TIMER_USEC); if (!(kbd->pb & 0x40) && (kbd->type != 5)) return; if (kbd->want_irq) { kbd->want_irq = 0; kbd->pa = kbd->key_waiting; kbd->blocked = 1; picint(2); #ifdef ENABLE_KEYBOARD_XT_LOG kbd_log("keyboard_xt : take IRQ\n"); #endif } if (key_queue_start != key_queue_end && !kbd->blocked) { kbd->key_waiting = key_queue[key_queue_start]; kbd_log("XTkbd: reading %02X from the key queue at %i\n", kbd->key_waiting, key_queue_start); key_queue_start = (key_queue_start + 1) & 0x0f; kbd->want_irq = 1; } } static void kbd_adddata(uint16_t val) { /* Test for T1000 'Fn' key (Right Alt / Right Ctrl) */ if (is_t1x00) { if (keyboard_recv(0xb8) || keyboard_recv(0x9d)) { /* 'Fn' pressed */ t1000_syskey(0x00, 0x04, 0x00); /* Set 'Fn' indicator */ switch (val) { case 0x45: /* Num Lock => toggle numpad */ t1000_syskey(0x00, 0x00, 0x10); break; case 0x47: /* Home => internal display */ t1000_syskey(0x40, 0x00, 0x00); break; case 0x49: /* PgDn => turbo on */ t1000_syskey(0x80, 0x00, 0x00); break; case 0x4D: /* Right => toggle LCD font */ t1000_syskey(0x00, 0x00, 0x20); break; case 0x4F: /* End => external display */ t1000_syskey(0x00, 0x40, 0x00); break; case 0x51: /* PgDn => turbo off */ t1000_syskey(0x00, 0x80, 0x00); break; case 0x54: /* SysRQ => toggle window */ t1000_syskey(0x00, 0x00, 0x08); break; } } else t1000_syskey(0x04, 0x00, 0x00); /* Reset 'Fn' indicator */ } key_queue[key_queue_end] = val; kbd_log("XTkbd: %02X added to key queue at %i\n", val, key_queue_end); key_queue_end = (key_queue_end + 1) & 0x0f; } void kbd_adddata_process(uint16_t val, void (*adddata)(uint16_t val)) { uint8_t num_lock = 0, shift_states = 0; if (!adddata) return; keyboard_get_states(NULL, &num_lock, NULL); shift_states = keyboard_get_shift() & STATE_SHIFT_MASK; switch(val) { case FAKE_LSHIFT_ON: if (num_lock) { if (!shift_states) { /* Num lock on and no shifts are pressed, send non-inverted fake shift. */ adddata(0x2a); } } else { if (shift_states & STATE_LSHIFT) { /* Num lock off and left shift pressed. */ adddata(0xaa); } if (shift_states & STATE_RSHIFT) { /* Num lock off and right shift pressed. */ adddata(0xb6); } } break; case FAKE_LSHIFT_OFF: if (num_lock) { if (!shift_states) { /* Num lock on and no shifts are pressed, send non-inverted fake shift. */ adddata(0xaa); } } else { if (shift_states & STATE_LSHIFT) { /* Num lock off and left shift pressed. */ adddata(0x2a); } if (shift_states & STATE_RSHIFT) { /* Num lock off and right shift pressed. */ adddata(0x36); } } break; default: adddata(val); break; } } static void kbd_adddata_ex(uint16_t val) { kbd_adddata_process(val, kbd_adddata); } static void kbd_write(uint16_t port, uint8_t val, void *priv) { xtkbd_t *kbd = (xtkbd_t *)priv; switch (port) { case 0x61: if (!(kbd->pb & 0x40) && (val & 0x40)) { key_queue_start = key_queue_end = 0; kbd->want_irq = 0; kbd->blocked = 0; kbd_adddata(0xaa); } kbd->pb = val; ppi.pb = val; speaker_update(); if ((kbd->type <= 1) && !(kbd->pb & 0x08)) speaker_gated = speaker_enable = 1; else { speaker_gated = val & 1; speaker_enable = val & 2; } if (speaker_enable) was_speaker_enable = 1; pit_ctr_set_gate(&pit->counters[2], val & 1); if (val & 0x80) { kbd->pa = 0; kbd->blocked = 0; picintc(2); } #ifdef ENABLE_KEYBOARD_XT_LOG if (kbd->type <= 1) kbd_log("Casette motor is %s\n", !(val & 0x08) ? "ON" : "OFF"); #endif break; #ifdef ENABLE_KEYBOARD_XT_LOG case 0x62: if (kbd->type <= 1) kbd_log("Casette IN is %i\n", !!(val & 0x10)); break; #endif } } static uint8_t kbd_read(uint16_t port, void *priv) { xtkbd_t *kbd = (xtkbd_t *)priv; uint8_t ret = 0xff; switch (port) { case 0x60: if ((kbd->type <= 1) && (kbd->pb & 0x80)) ret = (kbd->pd & ~0x02) | (hasfpu ? 0x02 : 0x00); else if (((kbd->type == 2) || (kbd->type == 3)) && (kbd->pb & 0x80)) ret = 0xff; /* According to Ruud on the PCem forum, this is supposed to return 0xFF on the XT. */ else ret = kbd->pa; break; case 0x61: ret = kbd->pb; break; case 0x62: if (kbd->type == 0) ret = 0x00; else if (kbd->type == 1) { if (kbd->pb & 0x04) ret = ((mem_size-64) / 32) & 0x0f; else ret = ((mem_size-64) / 32) >> 4; } else { if (kbd->pb & 0x08) ret = kbd->pd >> 4; else { /* LaserXT = Always 512k RAM; LaserXT/3 = Bit 0: set = 512k, clear = 256k. */ #if defined(DEV_BRANCH) && defined(USE_LASERXT) if (kbd->type == 6) ret = ((mem_size == 512) ? 0x0d : 0x0c) | (hasfpu ? 0x02 : 0x00); else #endif ret = (kbd->pd & 0x0d) | (hasfpu ? 0x02 : 0x00); } } ret |= (ppispeakon ? 0x20 : 0); /* This is needed to avoid error 131 (cassette error). This is serial read: bit 5 = clock, bit 4 = data, cassette header is 256 x 0xff. */ if (kbd->type <= 1) ret |= (ppispeakon ? 0x10 : 0); if (kbd->type == 5) ret |= (tandy1k_eeprom_read() ? 0x10 : 0); break; case 0x63: if ((kbd->type == 2) || (kbd->type == 3) || (kbd->type == 4) || (kbd->type == 6)) ret = kbd->pd; break; } return(ret); } static void kbd_reset(void *priv) { xtkbd_t *kbd = (xtkbd_t *)priv; kbd->want_irq = 0; kbd->blocked = 0; kbd->pa = 0x00; kbd->pb = 0x00; keyboard_scan = 1; key_queue_start = 0, key_queue_end = 0; } static void * kbd_init(const device_t *info) { int i, fdd_count = 0; xtkbd_t *kbd; kbd = (xtkbd_t *)malloc(sizeof(xtkbd_t)); memset(kbd, 0x00, sizeof(xtkbd_t)); io_sethandler(0x0060, 4, kbd_read, NULL, NULL, kbd_write, NULL, NULL, kbd); keyboard_send = kbd_adddata_ex; kbd_reset(kbd); kbd->type = info->local; key_queue_start = key_queue_end = 0; video_reset(gfxcard); if (kbd->type <= 3) { for (i = 0; i < FDD_NUM; i++) { if (fdd_get_flags(i)) fdd_count++; } /* DIP switch readout: bit set = OFF, clear = ON. */ /* Switches 7, 8 - floppy drives. */ if (!fdd_count) kbd->pd = 0x00; else kbd->pd = ((fdd_count - 1) << 6) | 0x01; /* Switches 5, 6 - video. */ if (video_is_mda()) kbd->pd |= 0x30; else if (video_is_cga()) kbd->pd |= 0x20; /* 0x10 would be 40x25 */ else kbd->pd |= 0x00; /* Switches 3, 4 - memory size. */ if ((kbd->type == 3) || (kbd->type == 4) || (kbd->type == 6)) { switch (mem_size) { case 256: kbd->pd |= 0x00; break; case 512: kbd->pd |= 0x04; break; case 576: kbd->pd |= 0x08; break; case 640: default: kbd->pd |= 0x0c; break; } } else if (kbd->type >= 1) { switch (mem_size) { case 64: kbd->pd |= 0x00; break; case 128: kbd->pd |= 0x04; break; case 192: kbd->pd |= 0x08; break; case 256: default: kbd->pd |= 0x0c; break; } } else { switch (mem_size) { case 16: kbd->pd |= 0x00; break; case 32: kbd->pd |= 0x04; break; case 48: kbd->pd |= 0x08; break; case 64: default: kbd->pd |= 0x0c; break; } } /* Switch 2 - 8087 FPU. */ if (hasfpu) kbd->pd |= 0x02; /* Switch 1 - always off. */ kbd->pd |= 0x01; } timer_add(&kbd->send_delay_timer, kbd_poll, kbd, 1); keyboard_set_table(scancode_xt); is_t1x00 = (kbd->type == 6); return(kbd); } static void kbd_close(void *priv) { xtkbd_t *kbd = (xtkbd_t *)priv; /* Stop the timer. */ timer_disable(&kbd->send_delay_timer); /* Disable scanning. */ keyboard_scan = 0; keyboard_send = NULL; io_removehandler(0x0060, 4, kbd_read, NULL, NULL, kbd_write, NULL, NULL, kbd); free(kbd); } const device_t keyboard_pc_device = { "IBM PC Keyboard (1981)", 0, 0, kbd_init, kbd_close, kbd_reset, NULL, NULL, NULL }; const device_t keyboard_pc82_device = { "IBM PC Keyboard (1982)", 0, 1, kbd_init, kbd_close, kbd_reset, NULL, NULL, NULL }; const device_t keyboard_xt_device = { "XT (1982) Keyboard", 0, 2, kbd_init, kbd_close, kbd_reset, NULL, NULL, NULL }; const device_t keyboard_xt86_device = { "XT (1986) Keyboard", 0, 3, kbd_init, kbd_close, kbd_reset, NULL, NULL, NULL }; const device_t keyboard_xt_compaq_device = { "Compaq Portable Keyboard", 0, 4, kbd_init, kbd_close, kbd_reset, NULL, NULL, NULL }; const device_t keyboard_tandy_device = { "Tandy 1000 Keyboard", 0, 5, kbd_init, kbd_close, kbd_reset, NULL, NULL, NULL }; const device_t keyboard_xt_t1x00_device = { "Toshiba T1x00 Keyboard", 0, 6, kbd_init, kbd_close, kbd_reset, NULL, NULL, NULL }; #if defined(DEV_BRANCH) && defined(USE_LASERXT) const device_t keyboard_xt_lxt3_device = { "VTech Laser XT3 Keyboard", 0, 7, kbd_init, kbd_close, kbd_reset, NULL, NULL, NULL }; #endif