--- trunk/src/devices/dev_pckbc.c 2007/10/08 16:18:00 4 +++ trunk/src/devices/dev_pckbc.c 2007/10/08 16:18:11 6 @@ -25,10 +25,10 @@ * SUCH DAMAGE. * * - * $Id: dev_pckbc.c,v 1.37 2005/02/22 06:26:10 debug Exp $ + * $Id: dev_pckbc.c,v 1.45 2005/06/02 15:42:49 debug Exp $ * - * Standard 8042 PC keyboard controller, and a 8242WB PS2 keyboard/mouse - * controller. + * Standard 8042 PC keyboard controller (and a 8242WB PS2 keyboard/mouse + * controller), including the 8048 keyboard chip. * * * TODO: Finish the rewrite for 8242. @@ -69,12 +69,12 @@ struct pckbc_data { int console_handle; int in_use; - int any_command_used; int reg[DEV_PCKBC_LENGTH]; int keyboard_irqnr; int mouse_irqnr; int type; + int pc_style_flag; /* TODO: one of these for each port? */ int clocksignal; @@ -84,6 +84,7 @@ int keyscanning_enabled; int state; int cmdbyte; + int output_byte; int last_scancode; unsigned key_queue[2][MAX_8042_QUEUELEN]; @@ -94,6 +95,8 @@ #define STATE_LDCMDBYTE 1 #define STATE_RDCMDBYTE 2 #define STATE_WAITING_FOR_TRANSLTABLE 3 +#define STATE_LDOUTPUT 4 +#define STATE_RDOUTPUT 5 /* @@ -121,8 +124,8 @@ { if (d->head[port] == d->tail[port]) fatal("[ pckbc: queue empty, port %i! ]\n", port); - - d->tail[port] = (d->tail[port]+1) % MAX_8042_QUEUELEN; + else + d->tail[port] = (d->tail[port]+1) % MAX_8042_QUEUELEN; return d->key_queue[port][d->tail[port]]; } @@ -135,6 +138,7 @@ */ static void ascii_to_pc_scancodes(int a, struct pckbc_data *d) { + int old_head; int p = 0; /* port */ int shift = 0, ctrl = 0; @@ -151,9 +155,16 @@ pckbc_add_code(d, 0x1d, p); /* - * TODO: Release for all of these? + * Note: The ugly hack used to add release codes for all of these + * keys is as follows: we remember how much of the kbd buf that + * is in use here, before we add any scancode. After we've added + * one or more scancodes (ie an optional shift + another key) + * then we duplicate the last scancode | 0x80 _if_ the kbd buf + * was altered. */ + old_head = d->head[p]; + if (a==27) pckbc_add_code(d, 0x01, p); if (a=='1') pckbc_add_code(d, 0x02, p); @@ -259,6 +270,12 @@ if (a==' ') pckbc_add_code(d, 0x39, p); + /* Add release code, if a key was pressed: */ + if (d->head[p] != old_head) { + int code = d->key_queue[p][d->head[p]] | 0x80; + pckbc_add_code(d, code, p); + } + /* Release ctrl: */ if (ctrl) pckbc_add_code(d, 0x1d + 0x80, p); @@ -271,22 +288,25 @@ void dev_pckbc_tick(struct cpu *cpu, void *extra) { struct pckbc_data *d = extra; - int port_nr; - int ch; + int port_nr, ch, ints_enabled; - if (d->in_use && d->any_command_used && - console_charavail(d->console_handle)) { + if (d->in_use && console_charavail(d->console_handle)) { ch = console_readchar(d->console_handle); if (ch >= 0) ascii_to_pc_scancodes(ch, d); } + ints_enabled = d->rx_int_enable; + /* TODO: mouse movements? */ + if (d->cmdbyte & KC8_KDISABLE) + ints_enabled = 0; + for (port_nr=0; port_nr<2; port_nr++) { - /* Cause receive interrupt, - if there's something in the receive buffer: */ - if (d->head[port_nr] != d->tail[port_nr] && d->rx_int_enable) { + /* Cause receive interrupt, if there's something in the + receive buffer: (Otherwise deassert the interrupt.) */ + if (d->head[port_nr] != d->tail[port_nr] && ints_enabled) { cpu_interrupt(cpu, port_nr==0? d->keyboard_irqnr : d->mouse_irqnr); } else { @@ -299,13 +319,13 @@ /* * dev_pckbc_command(): + * + * Handle commands to the 8048 in the emulated keyboard. */ static void dev_pckbc_command(struct pckbc_data *d, int port_nr) { int cmd = d->reg[PC_CMD]; - d->any_command_used = 1; - if (d->type == PCKBC_8242) cmd = d->reg[PS2_TXBUF]; @@ -345,7 +365,7 @@ pckbc_add_code(d, KBR_RSTDONE, port_nr); break; default: - fatal("[ pckbc: UNIMPLEMENTED command 0x%02x ]\n", cmd); + fatal("[ pckbc: UNIMPLEMENTED 8048 command 0x%02x ]\n", cmd); } } @@ -373,22 +393,38 @@ #endif /* For JAZZ-based machines: */ - if (relative_addr >= 0x60) + if (relative_addr >= 0x60) { relative_addr -= 0x60; - - /* 8242 PS2-style: */ - if (d->type == PCKBC_8242) { + if (relative_addr != 0) + relative_addr = 1; + } else if (d->type == PCKBC_8242) { + /* 8242 PS2-style: */ /* when using 8-byte alignment... */ relative_addr /= sizeof(uint64_t); /* port_nr = 0 for keyboard, 1 for mouse */ port_nr = (relative_addr >> 2); relative_addr &= 3; relative_addr += PS2; + } else if (d->pc_style_flag) { + /* PC-style: */ + if (relative_addr != 0 && relative_addr != 4) { + /* TODO (port 0x61) */ + odata = 0x21; +{ +static int x = 0; +x++; +if (x&1) + odata ^= 0x10; +} + if (writeflag == MEM_READ) + memory_writemax64(cpu, data, len, odata); + return 0; + } + if (relative_addr != 0) + relative_addr = 1; } else { - /* The relative_addr is either 0 or 1, - but some machines use longer registers than one byte - each, so this will make things simpler for us: */ - if (relative_addr) + /* Others... Non-Jazz ARC-based machines etc. */ + if (relative_addr != 0) relative_addr = 1; } @@ -400,11 +436,16 @@ case 0: /* data */ if (writeflag==MEM_READ) { - if (d->state == STATE_RDCMDBYTE) { + switch (d->state) { + case STATE_RDCMDBYTE: odata = d->cmdbyte; d->state = STATE_NORMAL; - } else { - if (d->head[0] != d->tail[0]) { + break; + case STATE_RDOUTPUT: + odata = d->output_byte; + d->state = STATE_NORMAL; + break; + default:if (d->head[0] != d->tail[0]) { odata = pckbc_get_code(d, 0); d->last_scancode = odata; } else { @@ -412,20 +453,26 @@ d->last_scancode |= 0x80; } } - debug("[ pckbc: read from DATA: 0x%02x ]\n", odata); + /* debug("[ pckbc: read from DATA: 0x%02x ]\n", + odata); */ } else { debug("[ pckbc: write to DATA:"); for (i=0; istate == STATE_LDCMDBYTE) { + switch (d->state) { + case STATE_LDCMDBYTE: d->cmdbyte = idata; d->rx_int_enable = d->cmdbyte & (KC8_KENABLE | KC8_MENABLE) ? 1 : 0; d->state = STATE_NORMAL; - } else { - d->reg[relative_addr] = idata; + break; + case STATE_LDOUTPUT: + d->output_byte = idata; + d->state = STATE_NORMAL; + break; + default:d->reg[relative_addr] = idata; dev_pckbc_command(d, port_nr); } } @@ -438,9 +485,14 @@ /* "Data in buffer" bit */ if (d->head[0] != d->tail[0] || - d->state == STATE_RDCMDBYTE) + d->state == STATE_RDCMDBYTE || + d->state == STATE_RDOUTPUT) odata |= KBS_DIB; - /* odata |= KBS_OCMD; */ + + if (d->state == STATE_RDCMDBYTE) + odata |= KBS_OCMD; + + odata |= KBS_NOSEC; /* debug("[ pckbc: read from CTL status port: " "0x%02x ]\n", (int)odata); */ } else { @@ -457,12 +509,30 @@ case K_LDCMDBYTE: d->state = STATE_LDCMDBYTE; break; + case 0xa7: + d->cmdbyte |= KC8_MDISABLE; + break; + case 0xa8: + d->cmdbyte &= ~KC8_MDISABLE; + break; case 0xa9: /* test auxiliary port */ debug("[ pckbc: CONTROL 0xa9, TODO ]\n"); break; case 0xaa: /* keyboard self-test */ pckbc_add_code(d, 0x55, port_nr); break; + case 0xad: + d->cmdbyte |= KC8_KDISABLE; + break; + case 0xae: + d->cmdbyte &= ~KC8_KDISABLE; + break; + case 0xd0: + d->state = STATE_RDOUTPUT; + break; + case 0xd1: + d->state = STATE_LDOUTPUT; + break; case 0xd4: /* write to auxiliary port */ debug("[ pckbc: CONTROL 0xd4, TODO ]\n"); break; @@ -633,7 +703,7 @@ */ int dev_pckbc_init(struct machine *machine, struct memory *mem, uint64_t baseaddr, int type, int keyboard_irqnr, int mouse_irqnr, - int in_use) + int in_use, int pc_style_flag) { struct pckbc_data *d; int len = DEV_PCKBC_LENGTH; @@ -654,7 +724,10 @@ d->keyboard_irqnr = keyboard_irqnr; d->mouse_irqnr = mouse_irqnr; d->in_use = in_use; + d->pc_style_flag = pc_style_flag; d->console_handle = console_start_slave_inputonly(machine, "pckbc"); + d->rx_int_enable = 1; + d->output_byte = 0x02; /* A20 enable on PCs */ memory_device_register(mem, "pckbc", baseaddr, len, dev_pckbc_access, d, MEM_DEFAULT, NULL);