1 |
/* |
/* |
2 |
* Copyright (C) 2003-2006 Anders Gavare. All rights reserved. |
* Copyright (C) 2003-2007 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.65 2006/03/04 12:38:48 debug Exp $ |
* $Id: dev_pckbc.c,v 1.72 2006/12/30 13:30:58 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. |
32 |
* |
* |
33 |
|
* Quick source of good info: http://my.execpc.com/~geezer/osd/kbd/kbd.txt |
34 |
* |
* |
35 |
* TODO: Finish the rewrite for 8242. |
* |
36 |
|
* TODOs: |
37 |
|
* Finish the rewrite for 8242. |
38 |
*/ |
*/ |
39 |
|
|
40 |
#include <stdio.h> |
#include <stdio.h> |
75 |
int in_use; |
int in_use; |
76 |
|
|
77 |
int reg[DEV_PCKBC_LENGTH]; |
int reg[DEV_PCKBC_LENGTH]; |
78 |
int keyboard_irqnr; |
|
79 |
int mouse_irqnr; |
struct interrupt irq_keyboard; |
80 |
|
struct interrupt irq_mouse; |
81 |
int currently_asserted[2]; |
int currently_asserted[2]; |
82 |
int type; |
int type; |
83 |
int pc_style_flag; |
int pc_style_flag; |
102 |
#define STATE_LDCMDBYTE 1 |
#define STATE_LDCMDBYTE 1 |
103 |
#define STATE_RDCMDBYTE 2 |
#define STATE_RDCMDBYTE 2 |
104 |
#define STATE_WAITING_FOR_TRANSLTABLE 3 |
#define STATE_WAITING_FOR_TRANSLTABLE 3 |
105 |
#define STATE_WAITING_FOR_F3 4 |
#define STATE_WAITING_FOR_RATE 4 |
106 |
#define STATE_WAITING_FOR_FC 5 |
#define STATE_WAITING_FOR_ONEKEY_MB 5 |
107 |
#define STATE_WAITING_FOR_AUX 6 |
#define STATE_WAITING_FOR_AUX 6 |
108 |
#define STATE_WAITING_FOR_AUX_OUT 7 |
#define STATE_WAITING_FOR_AUX_OUT 7 |
109 |
#define STATE_LDOUTPUT 8 |
#define STATE_LDOUTPUT 8 |
461 |
for (port_nr=0; port_nr<2; port_nr++) { |
for (port_nr=0; port_nr<2; port_nr++) { |
462 |
/* Cause receive interrupt, if there's something in the |
/* Cause receive interrupt, if there's something in the |
463 |
receive buffer: (Otherwise deassert the interrupt.) */ |
receive buffer: (Otherwise deassert the interrupt.) */ |
464 |
|
|
465 |
if (d->head[port_nr] != d->tail[port_nr] && ints_enabled) { |
if (d->head[port_nr] != d->tail[port_nr] && ints_enabled) { |
466 |
debug("[ pckbc: interrupt port %i ]\n", port_nr); |
debug("[ pckbc: interrupt port %i ]\n", port_nr); |
467 |
cpu_interrupt(cpu, port_nr==0? d->keyboard_irqnr |
if (port_nr == 0) |
468 |
: d->mouse_irqnr); |
INTERRUPT_ASSERT(d->irq_keyboard); |
469 |
|
else |
470 |
|
INTERRUPT_ASSERT(d->irq_mouse); |
471 |
d->currently_asserted[port_nr] = 1; |
d->currently_asserted[port_nr] = 1; |
472 |
} else { |
} else { |
473 |
if (d->currently_asserted[port_nr]) |
if (d->currently_asserted[port_nr]) { |
474 |
cpu_interrupt_ack(cpu, port_nr==0? |
if (port_nr == 0) |
475 |
d->keyboard_irqnr : d->mouse_irqnr); |
INTERRUPT_DEASSERT(d->irq_keyboard); |
476 |
|
else |
477 |
|
INTERRUPT_DEASSERT(d->irq_mouse); |
478 |
|
} |
479 |
d->currently_asserted[port_nr] = 0; |
d->currently_asserted[port_nr] = 0; |
480 |
} |
} |
481 |
} |
} |
510 |
return; |
return; |
511 |
} |
} |
512 |
|
|
513 |
if (d->state == STATE_WAITING_FOR_F3) { |
if (d->state == STATE_WAITING_FOR_RATE) { |
514 |
debug("[ pckbc: (port %i) received '0xf3' data: " |
debug("[ pckbc: (port %i) received Typematic Rate data: " |
515 |
"0x%02x ]\n", port_nr, cmd); |
"0x%02x ]\n", port_nr, cmd); |
516 |
pckbc_add_code(d, KBR_ACK, port_nr); |
pckbc_add_code(d, KBR_ACK, port_nr); |
517 |
d->state = STATE_NORMAL; |
d->state = STATE_NORMAL; |
518 |
return; |
return; |
519 |
} |
} |
520 |
|
|
521 |
if (d->state == STATE_WAITING_FOR_FC) { |
if (d->state == STATE_WAITING_FOR_ONEKEY_MB) { |
522 |
debug("[ pckbc: (port %i) received '0xfc' data: " |
debug("[ pckbc: (port %i) received One-key make/break data: " |
523 |
"0x%02x ]\n", port_nr, cmd); |
"0x%02x ]\n", port_nr, cmd); |
524 |
pckbc_add_code(d, KBR_ACK, port_nr); |
pckbc_add_code(d, KBR_ACK, port_nr); |
525 |
d->state = STATE_NORMAL; |
d->state = STATE_NORMAL; |
545 |
} |
} |
546 |
|
|
547 |
switch (cmd) { |
switch (cmd) { |
548 |
|
|
549 |
case 0x00: |
case 0x00: |
550 |
|
/* |
551 |
|
* TODO: What does this do? This is possibly due to an |
552 |
|
* error in the handling of some other command code. |
553 |
|
*/ |
554 |
pckbc_add_code(d, KBR_ACK, port_nr); |
pckbc_add_code(d, KBR_ACK, port_nr); |
555 |
break; |
break; |
556 |
|
|
557 |
case KBC_MODEIND: /* Set LEDs */ |
case KBC_MODEIND: /* Set LEDs */ |
558 |
/* Just ACK, no LEDs are actually set. */ |
/* Just ACK, no LEDs are actually set. */ |
559 |
pckbc_add_code(d, KBR_ACK, port_nr); |
pckbc_add_code(d, KBR_ACK, port_nr); |
560 |
break; |
break; |
561 |
|
|
562 |
case KBC_SETTABLE: |
case KBC_SETTABLE: |
563 |
pckbc_add_code(d, KBR_ACK, port_nr); |
pckbc_add_code(d, KBR_ACK, port_nr); |
564 |
d->state = STATE_WAITING_FOR_TRANSLTABLE; |
d->state = STATE_WAITING_FOR_TRANSLTABLE; |
565 |
break; |
break; |
566 |
|
|
567 |
case KBC_ENABLE: |
case KBC_ENABLE: |
568 |
d->keyscanning_enabled = 1; |
d->keyscanning_enabled = 1; |
569 |
pckbc_add_code(d, KBR_ACK, port_nr); |
pckbc_add_code(d, KBR_ACK, port_nr); |
570 |
break; |
break; |
571 |
|
|
572 |
case KBC_DISABLE: |
case KBC_DISABLE: |
573 |
d->keyscanning_enabled = 0; |
d->keyscanning_enabled = 0; |
574 |
pckbc_add_code(d, KBR_ACK, port_nr); |
pckbc_add_code(d, KBR_ACK, port_nr); |
575 |
break; |
break; |
576 |
|
|
577 |
case KBC_SETDEFAULT: |
case KBC_SETDEFAULT: |
578 |
pckbc_add_code(d, KBR_ACK, port_nr); |
pckbc_add_code(d, KBR_ACK, port_nr); |
579 |
break; |
break; |
580 |
case 0xf3: |
|
581 |
|
case KBC_GETID: |
582 |
|
/* Get keyboard ID. NOTE/TODO: Ugly hardcoded answer. */ |
583 |
|
pckbc_add_code(d, KBR_ACK, port_nr); |
584 |
|
pckbc_add_code(d, 0xab, port_nr); |
585 |
|
pckbc_add_code(d, 0x41, port_nr); |
586 |
|
break; |
587 |
|
|
588 |
|
case KBC_TYPEMATIC: |
589 |
|
/* Set typematic (auto-repeat) delay/speed: */ |
590 |
pckbc_add_code(d, KBR_ACK, port_nr); |
pckbc_add_code(d, KBR_ACK, port_nr); |
591 |
d->state = STATE_WAITING_FOR_F3; |
d->state = STATE_WAITING_FOR_RATE; |
592 |
break; |
break; |
593 |
case 0xfa: /* Just ack? */ |
|
594 |
|
case KBC_ALLKEYS_TMB: |
595 |
|
/* "Make all keys typematic/make/break" */ |
596 |
pckbc_add_code(d, KBR_ACK, port_nr); |
pckbc_add_code(d, KBR_ACK, port_nr); |
597 |
break; |
break; |
598 |
case 0xfc: |
|
599 |
|
case KBC_ONEKEY_MB: |
600 |
|
/* "Make one key typematic/make/break" */ |
601 |
pckbc_add_code(d, KBR_ACK, port_nr); |
pckbc_add_code(d, KBR_ACK, port_nr); |
602 |
d->state = STATE_WAITING_FOR_FC; |
d->state = STATE_WAITING_FOR_ONEKEY_MB; |
603 |
break; |
break; |
604 |
|
|
605 |
case KBC_RESET: |
case KBC_RESET: |
606 |
pckbc_add_code(d, KBR_ACK, port_nr); |
pckbc_add_code(d, KBR_ACK, port_nr); |
607 |
pckbc_add_code(d, KBR_RSTDONE, port_nr); |
pckbc_add_code(d, KBR_RSTDONE, port_nr); |
608 |
|
/* |
609 |
|
* Disable interrupts during reset, or Linux 2.6 |
610 |
|
* prints warnings about spurious interrupts. |
611 |
|
*/ |
612 |
|
d->rx_int_enable = 0; |
613 |
break; |
break; |
614 |
|
|
615 |
default: |
default: |
616 |
fatal("[ pckbc: (port %i) UNIMPLEMENTED 8048 command" |
fatal("[ pckbc: (port %i) UNIMPLEMENTED 8048 command" |
617 |
" 0x%02x ]\n", port_nr, cmd); |
" 0x%02x ]\n", port_nr, cmd); |
618 |
|
exit(1); |
619 |
} |
} |
620 |
} |
} |
621 |
|
|
622 |
|
|
|
/* |
|
|
* dev_pckbc_access(): |
|
|
*/ |
|
623 |
DEVICE_ACCESS(pckbc) |
DEVICE_ACCESS(pckbc) |
624 |
{ |
{ |
625 |
uint64_t idata = 0, odata = 0; |
uint64_t idata = 0, odata = 0; |
665 |
} |
} |
666 |
if (writeflag == MEM_READ) |
if (writeflag == MEM_READ) |
667 |
memory_writemax64(cpu, data, len, odata); |
memory_writemax64(cpu, data, len, odata); |
668 |
return 0; |
return 1; |
669 |
} |
} |
670 |
if (relative_addr != 0) |
if (relative_addr != 0) |
671 |
relative_addr = 1; |
relative_addr = 1; |
906 |
* Type should be PCKBC_8042 or PCKBC_8242. |
* Type should be PCKBC_8042 or PCKBC_8242. |
907 |
*/ |
*/ |
908 |
int dev_pckbc_init(struct machine *machine, struct memory *mem, |
int dev_pckbc_init(struct machine *machine, struct memory *mem, |
909 |
uint64_t baseaddr, int type, int keyboard_irqnr, int mouse_irqnr, |
uint64_t baseaddr, int type, char *keyboard_irqpath, |
910 |
int in_use, int pc_style_flag) |
char *mouse_irqpath, int in_use, int pc_style_flag) |
911 |
{ |
{ |
912 |
struct pckbc_data *d; |
struct pckbc_data *d; |
913 |
int len = DEV_PCKBC_LENGTH; |
int len = DEV_PCKBC_LENGTH; |
927 |
len = DEV_PCKBC_LENGTH + 0x60; |
len = DEV_PCKBC_LENGTH + 0x60; |
928 |
} |
} |
929 |
|
|
930 |
|
INTERRUPT_CONNECT(keyboard_irqpath, d->irq_keyboard); |
931 |
|
INTERRUPT_CONNECT(mouse_irqpath, d->irq_mouse); |
932 |
|
|
933 |
d->type = type; |
d->type = type; |
|
d->keyboard_irqnr = keyboard_irqnr; |
|
|
d->mouse_irqnr = mouse_irqnr; |
|
934 |
d->in_use = in_use; |
d->in_use = in_use; |
935 |
d->pc_style_flag = pc_style_flag; |
d->pc_style_flag = pc_style_flag; |
936 |
d->translation_table = 2; |
d->translation_table = 2; |