diff options
Diffstat (limited to 'trunk/src/emu/machine/8042kbdc.c')
-rw-r--r-- | trunk/src/emu/machine/8042kbdc.c | 635 |
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); +} |