1 |
/* |
/* |
2 |
* Copyright (C) 2003-2005 Anders Gavare. All rights reserved. |
* Copyright (C) 2003-2006 Anders Gavare. All rights reserved. |
3 |
* |
* |
4 |
* Redistribution and use in source and binary forms, with or without |
* Redistribution and use in source and binary forms, with or without |
5 |
* modification, are permitted provided that the following conditions are met: |
* modification, are permitted provided that the following conditions are met: |
25 |
* SUCH DAMAGE. |
* SUCH DAMAGE. |
26 |
* |
* |
27 |
* |
* |
28 |
* $Id: dev_pckbc.c,v 1.53 2005/10/26 14:37:04 debug Exp $ |
* $Id: dev_pckbc.c,v 1.64 2006/01/01 13:17:16 debug Exp $ |
29 |
* |
* |
30 |
* Standard 8042 PC keyboard controller (and a 8242WB PS2 keyboard/mouse |
* Standard 8042 PC keyboard controller (and a 8242WB PS2 keyboard/mouse |
31 |
* controller), including the 8048 keyboard chip. |
* controller), including the 8048 keyboard chip. |
100 |
#define STATE_WAITING_FOR_TRANSLTABLE 3 |
#define STATE_WAITING_FOR_TRANSLTABLE 3 |
101 |
#define STATE_WAITING_FOR_F3 4 |
#define STATE_WAITING_FOR_F3 4 |
102 |
#define STATE_WAITING_FOR_FC 5 |
#define STATE_WAITING_FOR_FC 5 |
103 |
#define STATE_LDOUTPUT 6 |
#define STATE_WAITING_FOR_AUX 6 |
104 |
#define STATE_RDOUTPUT 7 |
#define STATE_WAITING_FOR_AUX_OUT 7 |
105 |
|
#define STATE_LDOUTPUT 8 |
106 |
|
#define STATE_RDOUTPUT 9 |
107 |
|
|
108 |
|
|
109 |
/* |
/* |
271 |
|
|
272 |
|
|
273 |
/* |
/* |
274 |
* ascii_to_scancodes(): |
* ascii_to_scancodes_type2(): |
275 |
* |
* |
276 |
* Conversion from ASCII codes to default (US) keyboard scancodes. |
* Conversion from ASCII codes to default (US) keyboard scancodes. |
277 |
* (See http://www.win.tue.nl/~aeb/linux/kbd/scancodes-1.html) |
* (See http://www.win.tue.nl/~aeb/linux/kbd/scancodes-1.html) |
278 |
|
* |
279 |
|
* NOTE/TODO: This seems to be type 2, not type 1. |
280 |
*/ |
*/ |
281 |
static void ascii_to_pc_scancodes(int a, struct pckbc_data *d) |
static void ascii_to_pc_scancodes_type2(int a, struct pckbc_data *d) |
282 |
{ |
{ |
283 |
int old_head; |
int old_head; |
284 |
int p = 0; /* port */ |
int p = 0; /* port */ |
289 |
return; |
return; |
290 |
} |
} |
291 |
|
|
292 |
if (d->translation_table != 1) { |
if (d->translation_table != 2) { |
293 |
fatal("[ ascii_to_pc_scancodes: unimplemented type! ]\n"); |
fatal("[ ascii_to_pc_scancodes: unimplemented type! ]\n"); |
294 |
return; |
return; |
295 |
} |
} |
444 |
if (d->in_use && console_charavail(d->console_handle)) { |
if (d->in_use && console_charavail(d->console_handle)) { |
445 |
ch = console_readchar(d->console_handle); |
ch = console_readchar(d->console_handle); |
446 |
if (ch >= 0) |
if (ch >= 0) |
447 |
ascii_to_pc_scancodes(ch, d); |
ascii_to_pc_scancodes_type2(ch, d); |
448 |
} |
} |
449 |
|
|
450 |
ints_enabled = d->rx_int_enable; |
ints_enabled = d->rx_int_enable; |
488 |
debug("[ pckbc: (port %i) switching to translation table " |
debug("[ pckbc: (port %i) switching to translation table " |
489 |
"0x%02x ]\n", port_nr, cmd); |
"0x%02x ]\n", port_nr, cmd); |
490 |
switch (cmd) { |
switch (cmd) { |
491 |
case 1: |
case 2: |
492 |
case 3: d->translation_table = cmd; |
case 3: d->translation_table = cmd; |
493 |
break; |
break; |
494 |
default:fatal("[ pckbc: (port %i) translation table " |
default:fatal("[ pckbc: (port %i) translation table " |
495 |
"0x%02x is NOT YET IMPLEMENTED ]\n", port_nr, cmd); |
"0x%02x is NOT YET IMPLEMENTED ]\n", |
496 |
|
port_nr, cmd); |
497 |
} |
} |
498 |
pckbc_add_code(d, KBR_ACK, port_nr); |
pckbc_add_code(d, KBR_ACK, port_nr); |
499 |
d->state = STATE_NORMAL; |
d->state = STATE_NORMAL; |
516 |
return; |
return; |
517 |
} |
} |
518 |
|
|
519 |
|
if (d->state == STATE_WAITING_FOR_AUX) { |
520 |
|
debug("[ pckbc: (port %i) received aux data: " |
521 |
|
"0x%02x ]\n", port_nr, cmd); |
522 |
|
/* Echo back. */ |
523 |
|
pckbc_add_code(d, cmd, port_nr); |
524 |
|
d->state = STATE_NORMAL; |
525 |
|
return; |
526 |
|
} |
527 |
|
|
528 |
|
if (d->state == STATE_WAITING_FOR_AUX_OUT) { |
529 |
|
debug("[ pckbc: (port %i) received aux out data: " |
530 |
|
"0x%02x ]\n", port_nr, cmd); |
531 |
|
/* Echo back. */ |
532 |
|
pckbc_add_code(d, cmd, port_nr); |
533 |
|
d->state = STATE_NORMAL; |
534 |
|
return; |
535 |
|
} |
536 |
|
|
537 |
switch (cmd) { |
switch (cmd) { |
538 |
case 0x00: |
case 0x00: |
539 |
pckbc_add_code(d, KBR_ACK, port_nr); |
pckbc_add_code(d, KBR_ACK, port_nr); |
582 |
/* |
/* |
583 |
* dev_pckbc_access(): |
* dev_pckbc_access(): |
584 |
*/ |
*/ |
585 |
int dev_pckbc_access(struct cpu *cpu, struct memory *mem, |
DEVICE_ACCESS(pckbc) |
|
uint64_t relative_addr, unsigned char *data, size_t len, |
|
|
int writeflag, void *extra) |
|
586 |
{ |
{ |
587 |
uint64_t idata = 0, odata = 0; |
uint64_t idata = 0, odata = 0; |
588 |
int i, port_nr = 0; |
int port_nr = 0; |
589 |
|
size_t i; |
590 |
struct pckbc_data *d = extra; |
struct pckbc_data *d = extra; |
591 |
|
|
592 |
if (writeflag == MEM_WRITE) |
if (writeflag == MEM_WRITE) |
663 |
} |
} |
664 |
} |
} |
665 |
/* debug("[ pckbc: read from DATA: 0x%02x ]\n", |
/* debug("[ pckbc: read from DATA: 0x%02x ]\n", |
666 |
odata); */ |
(int)odata); */ |
667 |
} else { |
} else { |
668 |
debug("[ pckbc: write to DATA:"); |
debug("[ pckbc: write to DATA:"); |
669 |
for (i=0; i<len; i++) |
for (i=0; i<len; i++) |
712 |
d->reg[relative_addr] = idata; |
d->reg[relative_addr] = idata; |
713 |
|
|
714 |
switch (idata) { |
switch (idata) { |
715 |
|
case 0x10: |
716 |
|
case 0x11: |
717 |
|
/* TODO: For now, don't print warnings about |
718 |
|
these. NetBSD sends these. */ |
719 |
|
break; |
720 |
case K_RDCMDBYTE: |
case K_RDCMDBYTE: |
721 |
d->state = STATE_RDCMDBYTE; |
d->state = STATE_RDCMDBYTE; |
722 |
break; |
break; |
735 |
case 0xaa: /* keyboard self-test */ |
case 0xaa: /* keyboard self-test */ |
736 |
pckbc_add_code(d, 0x55, port_nr); |
pckbc_add_code(d, 0x55, port_nr); |
737 |
break; |
break; |
738 |
|
case 0xab: /* keyboard interface self-test */ |
739 |
|
pckbc_add_code(d, 0x00, port_nr); |
740 |
|
break; |
741 |
case 0xad: |
case 0xad: |
742 |
d->cmdbyte |= KC8_KDISABLE; |
d->cmdbyte |= KC8_KDISABLE; |
743 |
break; |
break; |
750 |
case 0xd1: |
case 0xd1: |
751 |
d->state = STATE_LDOUTPUT; |
d->state = STATE_LDOUTPUT; |
752 |
break; |
break; |
753 |
|
case 0xd3: /* write to auxiliary device |
754 |
|
output buffer */ |
755 |
|
debug("[ pckbc: CONTROL 0xd3, TODO ]\n"); |
756 |
|
d->state = STATE_WAITING_FOR_AUX_OUT; |
757 |
|
break; |
758 |
case 0xd4: /* write to auxiliary port */ |
case 0xd4: /* write to auxiliary port */ |
759 |
debug("[ pckbc: CONTROL 0xd4, TODO ]\n"); |
debug("[ pckbc: CONTROL 0xd4, TODO ]\n"); |
760 |
|
d->state = STATE_WAITING_FOR_AUX; |
761 |
break; |
break; |
762 |
default: |
default: |
763 |
fatal("[ pckbc: unknown CONTROL 0x%x ]\n", |
fatal("[ pckbc: unknown CONTROL 0x%x ]\n", |
764 |
idata); |
(int)idata); |
765 |
d->state = STATE_NORMAL; |
d->state = STATE_NORMAL; |
766 |
} |
} |
767 |
} |
} |
847 |
} |
} |
848 |
} |
} |
849 |
|
|
850 |
/* SGI? */ |
/* SGI? TODO: fix */ |
851 |
if (len == 8) |
if (len == 8) |
852 |
odata |= (odata << 8) | (odata << 16) | (odata << 24) | |
odata |= (odata << 8) | (odata << 16) | (odata << 24) | |
853 |
(odata << 32) | (odata << 40) | (odata << 48) | |
(odata << 32) | (odata << 40) | (odata << 48) | |
882 |
memset(d, 0, sizeof(struct pckbc_data)); |
memset(d, 0, sizeof(struct pckbc_data)); |
883 |
|
|
884 |
if (type == PCKBC_8242) |
if (type == PCKBC_8242) |
885 |
len = 0x40; |
len = 0x18; |
886 |
|
|
887 |
if (type == PCKBC_JAZZ) { |
if (type == PCKBC_JAZZ) { |
888 |
type = PCKBC_8042; |
type = PCKBC_8042; |
894 |
d->mouse_irqnr = mouse_irqnr; |
d->mouse_irqnr = mouse_irqnr; |
895 |
d->in_use = in_use; |
d->in_use = in_use; |
896 |
d->pc_style_flag = pc_style_flag; |
d->pc_style_flag = pc_style_flag; |
897 |
d->console_handle = console_start_slave_inputonly(machine, "pckbc"); |
d->translation_table = 2; |
|
d->translation_table = 1; |
|
898 |
d->rx_int_enable = 1; |
d->rx_int_enable = 1; |
899 |
d->output_byte = 0x02; /* A20 enable on PCs */ |
d->output_byte = 0x02; /* A20 enable on PCs */ |
900 |
|
|
901 |
|
d->console_handle = console_start_slave_inputonly( |
902 |
|
machine, "pckbc", d->in_use); |
903 |
|
|
904 |
memory_device_register(mem, "pckbc", baseaddr, |
memory_device_register(mem, "pckbc", baseaddr, |
905 |
len, dev_pckbc_access, d, MEM_DEFAULT, NULL); |
len, dev_pckbc_access, d, DM_DEFAULT, NULL); |
906 |
machine_add_tickfunction(machine, dev_pckbc_tick, d, PCKBC_TICKSHIFT); |
machine_add_tickfunction(machine, dev_pckbc_tick, d, PCKBC_TICKSHIFT); |
907 |
|
|
908 |
return d->console_handle; |
return d->console_handle; |