summaryrefslogtreecommitdiffstatshomepage
path: root/trunk/src/emu/machine/8042kbdc.c
diff options
context:
space:
mode:
Diffstat (limited to 'trunk/src/emu/machine/8042kbdc.c')
-rw-r--r--trunk/src/emu/machine/8042kbdc.c635
1 files changed, 635 insertions, 0 deletions
diff --git a/trunk/src/emu/machine/8042kbdc.c b/trunk/src/emu/machine/8042kbdc.c
new file mode 100644
index 00000000000..dc8fdf6dd34
--- /dev/null
+++ b/trunk/src/emu/machine/8042kbdc.c
@@ -0,0 +1,635 @@
+/*********************************************************************
+
+ 8042kbdc.c
+
+ Code specific to fun IBM AT stuff
+
+
+ PeT's notes about various Power On Self Tests (POSTs)
+
+ at post
+ -------
+ f81d2 01
+ f82e6 05
+ f8356 07
+ f83e5 0a
+ f847e 0e
+ f8e7c 10
+ f8f3a 13
+ f9058 1a
+ f913a 1e
+ fa8ba 30
+ fa96c 36
+ fa9d3 3c
+ fa9f4 3e
+ ff122 50
+ ff226 5b
+ ff29f 5f
+ f9228 70
+ f92b2 74 ide?
+
+ ibm at bios
+ -----------
+ f0101 after switch to real mode jump back!!!!!!!!!!
+ jumping table
+ f0123
+ f098e memory tests
+ f10b4 ???
+ not reached
+ f1050
+ f1617
+ f0119
+ f10d8
+ f10b7 system board error
+
+ f019f
+ f025b
+ f02e6
+ f0323
+ f03b3 0e
+ f03d7 0f
+ f058d
+ at8042 signal timing test
+ sets errorcode!
+
+ f0655
+ f06a3 postcode 15
+ f06ba 16
+ f0747 18
+ f0763 enter pm! (0x81, 0x85)
+ f0766 1a
+ f07b3 first 640kb memory test
+ f084c 1c
+ f086e extended memory test
+ f0928 1f
+ f097d 20
+ ???
+ f0ff4 34
+ ???
+ f1675 f0
+ f16cb f2
+ illegal access trap test!!!!
+ f16fe f3
+ task descriptor test!!!!
+ f174a f4
+ f17af f5
+ f1800 f6 writing to non write segment
+ f1852 f7 arpl
+ f1880 f8 lar, lsl
+ f18ca fa
+ f10d8
+ f10ec 35
+ f1106 36
+ f1137 !!!!!!!keyboard test fails
+
+ f11aa 3a
+ f1240 3c harddisk controller test!!!
+ f13f3 3b
+ f1a6d xthdd bios init
+ f1429
+ f1462
+ f1493 40
+ f1532
+ keyboard lock
+ f1 to unlock
+ f155c
+ jumps to f0050 (reset) without enabling of the a20 gate --> hangs
+ 0412 bit 5 must be set to reach f1579
+ f1579
+ f15c3 41
+ f1621 43
+
+ routines
+ f1945 read cmos ram
+ f195f write to cmos al value ah
+ f1a3a poll 0x61 bit 4
+ f1a49 sets something in cmos ram
+ f1d30 switch to protected mode
+
+ neat
+ ----
+ f80b9
+
+ at386
+ -----
+ fd28c fd
+ fd2c3 fc
+ f40dc
+ fd949
+ fd8e3
+ fd982
+ f4219 01
+ f4296 03
+ f42f3 04
+ f4377 05
+ f43ec 06
+ f4430 08
+ f6017 switches to PM
+ f4456 09
+ f55a2
+ f44ec 0d
+ f4557 20
+ f462d 27 my special friend, the keyboard controller once more
+ ed0a1
+ f4679 28
+ fa16a
+ f46d6
+ f4768 2c
+ f47f0 2e
+ f5081
+ fa16a
+ f9a83
+ Message: "Checksum Error on Extended CMOS"
+ f4840 34
+ f488c 35
+ reset
+ f48ee
+ f493e 3a
+ f49cd
+ f4fc7
+ fe842
+ f4a5a
+ f4b01 38
+ (Memory Test)
+ f4b41 3b
+ f4c0f
+ Message: "Invalid configuration information - please run SETUP program"
+ f4c5c
+ f86fc
+ f8838
+ f4c80
+ f4ca2
+ f4d4c
+ f4e15 (int 19h)
+
+ [f9a83 output text at return address!, return after text]
+
+
+ at486
+ -----
+ f81a5 03
+ f1096 0f 09 wbinvd i486 instruction
+
+*********************************************************************/
+
+
+#include "emu.h"
+#include "memconv.h"
+
+#include "machine/pckeybrd.h"
+#include "machine/8042kbdc.h"
+#include "machine/pcshare.h"
+
+
+/***************************************************************************
+
+ Constants & macros
+
+***************************************************************************/
+
+#define PS2_MOUSE_ON 1
+#define KEYBOARD_ON 1
+
+#define LOG_KEYBOARD 0
+#define LOG_ACCESSES 0
+
+
+
+/***************************************************************************
+
+ Type definitions
+
+***************************************************************************/
+
+static struct
+{
+ kbdc8042_type_t type;
+ void (*set_gate_a20)(running_machine &machine, int a20);
+ void (*keyboard_interrupt)(running_machine &machine, int state);
+ void (*set_spkr)(running_machine &machine, int speaker);
+ int (*get_out2)(running_machine &machine);
+
+ UINT8 inport, outport, data, command;
+
+ struct {
+ int received;
+ int on;
+ } keyboard;
+ struct {
+ int received;
+ int on;
+ } mouse;
+
+ int last_write_to_control;
+ int sending;
+ int send_to_mouse;
+
+ int operation_write_state;
+ int status_read_mode;
+
+ int speaker;
+
+ /* temporary hack */
+ int offset1;
+} kbdc8042;
+
+static int poll_delay;
+
+static void at_8042_check_keyboard(running_machine &machine);
+
+
+
+/***************************************************************************
+
+ Code
+
+***************************************************************************/
+
+static void at_8042_set_outport(running_machine &machine, UINT8 data, int initial)
+{
+ UINT8 change;
+ change = initial ? 0xFF : (kbdc8042.outport ^ data);
+ kbdc8042.outport = data;
+ if (change & 0x02)
+ {
+ if (kbdc8042.set_gate_a20)
+ kbdc8042.set_gate_a20(machine, data & 0x02 ? 1 : 0);
+ }
+}
+
+
+
+static TIMER_CALLBACK( kbdc8042_time )
+{
+ at_keyboard_polling();
+ at_8042_check_keyboard(machine);
+}
+
+static TIMER_CALLBACK( kbdc8042_clr_int )
+{
+ /* Lets 8952's timers do their job before clear the interrupt line, */
+ /* else Keyboard interrupt never happens. */
+ kbdc8042.keyboard_interrupt(machine, 0);
+}
+
+
+void kbdc8042_init(running_machine &machine, const struct kbdc8042_interface *intf)
+{
+ poll_delay = 10;
+ memset(&kbdc8042, 0, sizeof(kbdc8042));
+ kbdc8042.type = intf->type;
+ kbdc8042.set_gate_a20 = intf->set_gate_a20;
+ kbdc8042.keyboard_interrupt = intf->keyboard_interrupt;
+ kbdc8042.get_out2 = intf->get_out2;
+ kbdc8042.set_spkr = intf->set_spkr;
+
+ /* ibmat bios wants 0x20 set! (keyboard locked when not set) 0x80 */
+ kbdc8042.inport = 0xa0;
+ at_8042_set_outport(machine, 0xfe, 1);
+
+ machine.scheduler().timer_pulse(attotime::from_hz(60), FUNC(kbdc8042_time));
+}
+
+static void at_8042_receive(running_machine &machine, UINT8 data)
+{
+ if (LOG_KEYBOARD)
+ logerror("at_8042_receive Received 0x%02x\n", data);
+
+ kbdc8042.data = data;
+ kbdc8042.keyboard.received = 1;
+
+ if (kbdc8042.keyboard_interrupt)
+ {
+ kbdc8042.keyboard_interrupt(machine, 1);
+ /* Lets 8952's timers do their job before clear the interrupt line, */
+ /* else Keyboard interrupt never happens. */
+ machine.scheduler().timer_set( attotime::from_usec(2), FUNC(kbdc8042_clr_int),0,0 );
+ }
+}
+
+static void at_8042_check_keyboard(running_machine &machine)
+{
+ int data;
+
+ if (!kbdc8042.keyboard.received
+ && !kbdc8042.mouse.received)
+ {
+ if ( (data = at_keyboard_read())!=-1)
+ at_8042_receive(machine, data);
+ }
+}
+
+
+
+static void at_8042_clear_keyboard_received(void)
+{
+ if (kbdc8042.keyboard.received)
+ {
+ if (LOG_KEYBOARD)
+ logerror("kbdc8042_8_r(): Clearing kbdc8042.keyboard.received\n");
+ }
+
+ kbdc8042.keyboard.received = 0;
+ kbdc8042.mouse.received = 0;
+}
+
+
+
+/* **************************************************************************
+ * Port 0x60 Input and Output Buffer (keyboard and mouse data)
+ * Port 0x64 Read Status Register
+ * Write operation for controller
+ *
+ * Output port controller:
+ * 7: Keyboard data
+ * 6: Keyboard clock
+ * 5: Mouse buffer full
+ * 4: Keyboard buffer full
+ * 3: Mouse clock
+ * 2: Mouse data
+ * 1: 0 A20 cleared
+ * 0: 0 system reset
+ *
+ * Input port controller
+ * 7: 0=Keyboard Locked
+ * 6: 1 = Monochrome 0 = Color (true for real IBM, clones are undefined and use CMOS RAM data)
+ * 5..2: reserved
+ * 1: Mouse data in
+ * 0: Keyboard data in
+ */
+
+READ8_HANDLER(kbdc8042_8_r)
+{
+ UINT8 data = 0;
+
+ switch (offset) {
+ case 0:
+ data = kbdc8042.data;
+ if (kbdc8042.type != KBDC8042_AT386 || (data != 0x55))
+ {
+ /* at386 self test doesn't like this */
+ at_8042_clear_keyboard_received();
+ }
+ at_8042_check_keyboard(space->machine());
+ break;
+
+ case 1:
+ data = kbdc8042.speaker;
+ data &= ~0xc0; /* AT BIOS don't likes this being set */
+
+ /* needed for AMI BIOS, maybe only some keyboard controller revisions! */
+ at_8042_clear_keyboard_received();
+
+ /* polled for changes in ibmat bios */
+ if (--poll_delay < 0)
+ {
+ if (kbdc8042.type != KBDC8042_PS2)
+ poll_delay = 4; /* ibmat */
+ else
+ poll_delay = 8; /* ibm ps2m30 */
+ kbdc8042.offset1 ^= 0x10;
+ }
+ data = (data & ~0x10) | kbdc8042.offset1;
+
+ if (kbdc8042.speaker & 1)
+ data |= 0x20;
+ else
+ data &= ~0x20; /* ps2m30 wants this */
+ break;
+
+ case 2:
+ if (kbdc8042.get_out2(space->machine()))
+ data |= 0x20;
+ else
+ data &= ~0x20;
+ break;
+
+ case 4:
+ at_8042_check_keyboard(space->machine());
+
+ if (kbdc8042.keyboard.received || kbdc8042.mouse.received)
+ data |= 1;
+ if (kbdc8042.sending)
+ data |= 2;
+
+ kbdc8042.sending = 0; /* quicker than normal */
+ data |= 4; /* selftest ok */
+
+ if (kbdc8042.last_write_to_control)
+ data |= 8;
+
+ switch (kbdc8042.status_read_mode) {
+ case 0:
+ if (!kbdc8042.keyboard.on) data|=0x10;
+ if (kbdc8042.mouse.received) data|=0x20;
+ break;
+ case 1:
+ data |= kbdc8042.inport&0xf;
+ break;
+ case 2:
+ data |= kbdc8042.inport<<4;
+ break;
+ }
+ break;
+ }
+
+ if (LOG_ACCESSES)
+ logerror("kbdc8042_8_r(): offset=%d data=0x%02x\n", offset, (unsigned) data);
+ return data;
+}
+
+
+
+WRITE8_HANDLER(kbdc8042_8_w)
+{
+ switch (offset) {
+ case 0:
+ kbdc8042.last_write_to_control = 0;
+ kbdc8042.status_read_mode = 0;
+ switch (kbdc8042.operation_write_state) {
+ case 0:
+ /* normal case */
+ kbdc8042.data = data;
+ kbdc8042.sending=1;
+ at_keyboard_write(space->machine(), data);
+ break;
+
+ case 1:
+ /* preceded by writing 0xD1 to port 60h
+ * |7|6|5|4|3|2|1|0| 8042 Output Port
+ * | | | | | | | `---- system reset line
+ * | | | | | | `----- gate A20
+ * | | | | `-------- undefined
+ * | | | `--------- output buffer full
+ * | | `---------- input buffer empty
+ * | `----------- keyboard clock (output)
+ * `------------ keyboard data (output)
+ */
+ at_8042_set_outport(space->machine(), data, 0);
+ break;
+
+ case 2:
+ /* preceded by writing 0xD2 to port 60h */
+ kbdc8042.data = data;
+ kbdc8042.sending=1;
+ at_keyboard_write(space->machine(), data);
+ break;
+
+ case 3:
+ /* preceded by writing 0xD3 to port 60h */
+ kbdc8042.data = data;
+ break;
+
+ case 4:
+ /* preceded by writing 0xD4 to port 60h */
+ kbdc8042.data = data;
+ break;
+
+ case 5:
+ /* preceded by writing 0x60 to port 60h */
+ kbdc8042.command = data;
+ break;
+ }
+ kbdc8042.operation_write_state = 0;
+ break;
+
+ case 1:
+ kbdc8042.speaker = data;
+ if (kbdc8042.set_spkr)
+ kbdc8042.set_spkr(space->machine(), kbdc8042.speaker);
+
+ break;
+
+ case 4:
+ kbdc8042.last_write_to_control=0;
+
+ /* switch based on the command */
+ switch(data) {
+ case 0x20: /* current 8042 command byte is placed on port 60h */
+ kbdc8042.data = kbdc8042.command;
+ break;
+ case 0x60: /* next data byte is placed in 8042 command byte */
+ kbdc8042.operation_write_state = 5;
+ kbdc8042.send_to_mouse = 0;
+ break;
+ case 0xa7: /* disable auxilary interface */
+ kbdc8042.mouse.on = 0;
+ break;
+ case 0xa8: /* enable auxilary interface */
+ kbdc8042.mouse.on = 1;
+ break;
+ case 0xa9: /* test mouse */
+ at_8042_receive(space->machine(), PS2_MOUSE_ON ? 0x00 : 0xff);
+ break;
+ case 0xaa: /* selftest */
+ at_8042_receive(space->machine(), 0x55);
+ break;
+ case 0xab: /* test keyboard */
+ at_8042_receive(space->machine(), KEYBOARD_ON ? 0x00 : 0xff);
+ break;
+ case 0xad: /* disable keyboard interface */
+ kbdc8042.keyboard.on = 0;
+ break;
+ case 0xae: /* enable keyboard interface */
+ kbdc8042.keyboard.on = 1;
+ break;
+ case 0xc0: /* read input port */
+ /* |7|6|5|4|3 2 1 0| 8042 Input Port
+ * | | | | |
+ * | | | | `------- undefined
+ * | | | |
+ * | | | `--------- 1=enable 2nd 256k of Motherboard RAM
+ * | | `---------- 1=manufacturing jumper installed
+ * | `----------- 1=primary display is MDA, 0=CGA
+ * `------------ 1=keyboard not inhibited; 0=inhibited
+ */
+ at_8042_receive(space->machine(), kbdc8042.inport);
+ break;
+ case 0xc1: /* read input port 3..0 until write to 0x60 */
+ kbdc8042.status_read_mode = 1;
+ break;
+ case 0xc2: /* read input port 7..4 until write to 0x60 */
+ kbdc8042.status_read_mode = 2;
+ break;
+ case 0xd0: /* read output port */
+ at_8042_receive(space->machine(), kbdc8042.outport);
+ break;
+ case 0xd1:
+ /* write output port; next byte written to port 60h is placed on
+ * 8042 output port */
+ kbdc8042.operation_write_state = 1;
+ break;
+ case 0xd2:
+ /* write keyboard output register; on PS/2 systems next port 60h
+ * write is written to port 60h output register as if initiated
+ * by a device; invokes interrupt if enabled */
+ kbdc8042.operation_write_state = 2;
+ kbdc8042.send_to_mouse = 0;
+ break;
+ case 0xd3:
+ /* write auxillary output register; on PS/2 systems next port 60h
+ * write is written to port 60h input register as if initiated
+ * by a device; invokes interrupt if enabled */
+ kbdc8042.operation_write_state = 3;
+ kbdc8042.send_to_mouse = 1;
+ break;
+ case 0xd4:
+ /* write auxillary device; on PS/2 systems the next data byte
+ * written to input register a port at 60h is sent to the
+ * auxiliary device */
+ kbdc8042.operation_write_state = 4;
+ break;
+ case 0xe0:
+ /* read test inputs; read T1/T0 test inputs into bit 1/0 */
+ at_8042_receive(space->machine(), 0x00);
+ break;
+
+ case 0xf0:
+ case 0xf2:
+ case 0xf4:
+ case 0xf6:
+ case 0xf8:
+ case 0xfa:
+ case 0xfc:
+ case 0xfe:
+ /* Commands 0xF0...0xFF causes certain output lines to be pulsed
+ * low for six milliseconds. The bits pulsed low correspond to
+ * the bits low set in the command byte. The only pulse that has
+ * an effect currently is bit 0, which pulses the CPU's reset line
+ */
+ device_set_input_line(space->machine().firstcpu, INPUT_LINE_RESET, PULSE_LINE);
+ at_8042_set_outport(space->machine(), kbdc8042.outport | 0x02, 0);
+ break;
+ }
+ kbdc8042.sending = 1;
+ break;
+ }
+}
+
+
+
+READ32_HANDLER( kbdc8042_32le_r )
+{
+ return read32le_with_read8_handler(kbdc8042_8_r, space, offset, mem_mask);
+}
+
+
+
+WRITE32_HANDLER( kbdc8042_32le_w )
+{
+ write32le_with_write8_handler(kbdc8042_8_w, space, offset, data, mem_mask);
+}
+
+
+
+READ64_HANDLER( kbdc8042_64be_r )
+{
+ return read64be_with_read8_handler(kbdc8042_8_r, space, offset, mem_mask);
+}
+
+
+
+WRITE64_HANDLER( kbdc8042_64be_w )
+{
+ write64be_with_write8_handler(kbdc8042_8_w, space, offset, data, mem_mask);
+}