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.69 2006/07/25 18:58:02 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> |
101 |
#define STATE_LDCMDBYTE 1 |
#define STATE_LDCMDBYTE 1 |
102 |
#define STATE_RDCMDBYTE 2 |
#define STATE_RDCMDBYTE 2 |
103 |
#define STATE_WAITING_FOR_TRANSLTABLE 3 |
#define STATE_WAITING_FOR_TRANSLTABLE 3 |
104 |
#define STATE_WAITING_FOR_F3 4 |
#define STATE_WAITING_FOR_RATE 4 |
105 |
#define STATE_WAITING_FOR_FC 5 |
#define STATE_WAITING_FOR_ONEKEY_MB 5 |
106 |
#define STATE_WAITING_FOR_AUX 6 |
#define STATE_WAITING_FOR_AUX 6 |
107 |
#define STATE_WAITING_FOR_AUX_OUT 7 |
#define STATE_WAITING_FOR_AUX_OUT 7 |
108 |
#define STATE_LDOUTPUT 8 |
#define STATE_LDOUTPUT 8 |
460 |
for (port_nr=0; port_nr<2; port_nr++) { |
for (port_nr=0; port_nr<2; port_nr++) { |
461 |
/* Cause receive interrupt, if there's something in the |
/* Cause receive interrupt, if there's something in the |
462 |
receive buffer: (Otherwise deassert the interrupt.) */ |
receive buffer: (Otherwise deassert the interrupt.) */ |
463 |
|
int irq = port_nr==0? d->keyboard_irqnr : d->mouse_irqnr; |
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 |
cpu_interrupt(cpu, irq); |
|
: d->mouse_irqnr); |
|
468 |
d->currently_asserted[port_nr] = 1; |
d->currently_asserted[port_nr] = 1; |
469 |
} else { |
} else { |
470 |
if (d->currently_asserted[port_nr]) |
if (d->currently_asserted[port_nr]) |
471 |
cpu_interrupt_ack(cpu, port_nr==0? |
cpu_interrupt_ack(cpu, irq); |
|
d->keyboard_irqnr : d->mouse_irqnr); |
|
472 |
d->currently_asserted[port_nr] = 0; |
d->currently_asserted[port_nr] = 0; |
473 |
} |
} |
474 |
} |
} |
503 |
return; |
return; |
504 |
} |
} |
505 |
|
|
506 |
if (d->state == STATE_WAITING_FOR_F3) { |
if (d->state == STATE_WAITING_FOR_RATE) { |
507 |
debug("[ pckbc: (port %i) received '0xf3' data: " |
debug("[ pckbc: (port %i) received Typematic Rate data: " |
508 |
"0x%02x ]\n", port_nr, cmd); |
"0x%02x ]\n", port_nr, cmd); |
509 |
pckbc_add_code(d, KBR_ACK, port_nr); |
pckbc_add_code(d, KBR_ACK, port_nr); |
510 |
d->state = STATE_NORMAL; |
d->state = STATE_NORMAL; |
511 |
return; |
return; |
512 |
} |
} |
513 |
|
|
514 |
if (d->state == STATE_WAITING_FOR_FC) { |
if (d->state == STATE_WAITING_FOR_ONEKEY_MB) { |
515 |
debug("[ pckbc: (port %i) received '0xfc' data: " |
debug("[ pckbc: (port %i) received One-key make/break data: " |
516 |
"0x%02x ]\n", port_nr, cmd); |
"0x%02x ]\n", port_nr, cmd); |
517 |
pckbc_add_code(d, KBR_ACK, port_nr); |
pckbc_add_code(d, KBR_ACK, port_nr); |
518 |
d->state = STATE_NORMAL; |
d->state = STATE_NORMAL; |
538 |
} |
} |
539 |
|
|
540 |
switch (cmd) { |
switch (cmd) { |
541 |
|
|
542 |
case 0x00: |
case 0x00: |
543 |
|
/* |
544 |
|
* TODO: What does this do? This is possibly due to an |
545 |
|
* error in the handling of some other command code. |
546 |
|
*/ |
547 |
pckbc_add_code(d, KBR_ACK, port_nr); |
pckbc_add_code(d, KBR_ACK, port_nr); |
548 |
break; |
break; |
549 |
|
|
550 |
case KBC_MODEIND: /* Set LEDs */ |
case KBC_MODEIND: /* Set LEDs */ |
551 |
/* Just ACK, no LEDs are actually set. */ |
/* Just ACK, no LEDs are actually set. */ |
552 |
pckbc_add_code(d, KBR_ACK, port_nr); |
pckbc_add_code(d, KBR_ACK, port_nr); |
553 |
break; |
break; |
554 |
|
|
555 |
case KBC_SETTABLE: |
case KBC_SETTABLE: |
556 |
pckbc_add_code(d, KBR_ACK, port_nr); |
pckbc_add_code(d, KBR_ACK, port_nr); |
557 |
d->state = STATE_WAITING_FOR_TRANSLTABLE; |
d->state = STATE_WAITING_FOR_TRANSLTABLE; |
558 |
break; |
break; |
559 |
|
|
560 |
case KBC_ENABLE: |
case KBC_ENABLE: |
561 |
d->keyscanning_enabled = 1; |
d->keyscanning_enabled = 1; |
562 |
pckbc_add_code(d, KBR_ACK, port_nr); |
pckbc_add_code(d, KBR_ACK, port_nr); |
563 |
break; |
break; |
564 |
|
|
565 |
case KBC_DISABLE: |
case KBC_DISABLE: |
566 |
d->keyscanning_enabled = 0; |
d->keyscanning_enabled = 0; |
567 |
pckbc_add_code(d, KBR_ACK, port_nr); |
pckbc_add_code(d, KBR_ACK, port_nr); |
568 |
break; |
break; |
569 |
|
|
570 |
case KBC_SETDEFAULT: |
case KBC_SETDEFAULT: |
571 |
pckbc_add_code(d, KBR_ACK, port_nr); |
pckbc_add_code(d, KBR_ACK, port_nr); |
572 |
break; |
break; |
573 |
case 0xf3: |
|
574 |
|
case KBC_GETID: |
575 |
|
/* Get keyboard ID. NOTE/TODO: Ugly hardcoded answer. */ |
576 |
|
pckbc_add_code(d, KBR_ACK, port_nr); |
577 |
|
pckbc_add_code(d, 0xab, port_nr); |
578 |
|
pckbc_add_code(d, 0x41, port_nr); |
579 |
|
break; |
580 |
|
|
581 |
|
case KBC_TYPEMATIC: |
582 |
|
/* Set typematic (auto-repeat) delay/speed: */ |
583 |
pckbc_add_code(d, KBR_ACK, port_nr); |
pckbc_add_code(d, KBR_ACK, port_nr); |
584 |
d->state = STATE_WAITING_FOR_F3; |
d->state = STATE_WAITING_FOR_RATE; |
585 |
break; |
break; |
586 |
case 0xfa: /* Just ack? */ |
|
587 |
|
case KBC_ALLKEYS_TMB: |
588 |
|
/* "Make all keys typematic/make/break" */ |
589 |
pckbc_add_code(d, KBR_ACK, port_nr); |
pckbc_add_code(d, KBR_ACK, port_nr); |
590 |
break; |
break; |
591 |
case 0xfc: |
|
592 |
|
case KBC_ONEKEY_MB: |
593 |
|
/* "Make one key typematic/make/break" */ |
594 |
pckbc_add_code(d, KBR_ACK, port_nr); |
pckbc_add_code(d, KBR_ACK, port_nr); |
595 |
d->state = STATE_WAITING_FOR_FC; |
d->state = STATE_WAITING_FOR_ONEKEY_MB; |
596 |
break; |
break; |
597 |
|
|
598 |
case KBC_RESET: |
case KBC_RESET: |
599 |
pckbc_add_code(d, KBR_ACK, port_nr); |
pckbc_add_code(d, KBR_ACK, port_nr); |
600 |
pckbc_add_code(d, KBR_RSTDONE, port_nr); |
pckbc_add_code(d, KBR_RSTDONE, port_nr); |
601 |
|
/* |
602 |
|
* Disable interrupts during reset, or Linux 2.6 |
603 |
|
* prints warnings about spurious interrupts. |
604 |
|
*/ |
605 |
|
d->rx_int_enable = 0; |
606 |
break; |
break; |
607 |
|
|
608 |
default: |
default: |
609 |
fatal("[ pckbc: (port %i) UNIMPLEMENTED 8048 command" |
fatal("[ pckbc: (port %i) UNIMPLEMENTED 8048 command" |
610 |
" 0x%02x ]\n", port_nr, cmd); |
" 0x%02x ]\n", port_nr, cmd); |
611 |
|
exit(1); |
612 |
} |
} |
613 |
} |
} |
614 |
|
|
615 |
|
|
|
/* |
|
|
* dev_pckbc_access(): |
|
|
*/ |
|
616 |
DEVICE_ACCESS(pckbc) |
DEVICE_ACCESS(pckbc) |
617 |
{ |
{ |
618 |
uint64_t idata = 0, odata = 0; |
uint64_t idata = 0, odata = 0; |