1 #include <devices/keyboard.h>
3 #include <palacios/vmm.h>
4 #include <palacios/vmm_types.h>
6 #define KEYBOARD_DEBUG 1
8 #define KEYBOARD_DEBUG_80H 1
11 #define KEYBOARD_DEBUG_PRINT(first, rest...) PrintDebug(first, ##rest)
13 #define KEYBOARD_DEBUG_PRINT(first, rest...)
17 #define KEYBOARD_60H 0x60 // keyboard microcontroller
18 #define KEYBOARD_64H 0x64 // onboard microcontroller
20 #define KEYBOARD_DELAY_80H 0x80 // written for timing
22 #define KEYBOARD_IRQ 0x1
25 // extract bits for status byte
26 #define STATUS_OUTPUT_BUFFER_FULL 0x01 // 1=full (data for system)
27 #define STATUS_INPUT_BUFFER_FULL 0x02 // 1=full (data for 8042)
28 #define STATUS_SYSTEM 0x04 // 1=self-test-passed
29 #define STATUS_COMMAND_DATA_AVAIL 0x08 // internal: 0=data on 60h, 0=cmd on 64h
30 #define STATUS_ENABLED 0x10 // 1=keyboard is enabled
31 #define STATUS_MOUSE_BUFFER_FULL 0x20 // 1= mouse output buffer full
32 #define STATUS_TIMEOUT 0x40 // 1=timeout of keybd
33 #define STATUS_PARITY 0x80 // 1=parity error
37 #define CMD_INTR 0x01 // 1=interrupts enabled
38 #define CMD_MOUSE_INTR 0x02 // 1=interrupts enabled for mouse
39 #define CMD_SYSTEM 0x04 // 1= self test passed
40 #define CMD_OVERRIDE 0x08 // FORCE 0 for PS2
41 #define CMD_DISABLE 0x10 // 1=disabled keyboard
42 #define CMD_MOUSE_DISABLE 0x20 // 1=disabled mouse
43 #define CMD_SCANCODE_XLATE 0x40 // 1=translate to set 1 scancodes
44 #define CMD_RESERVED 0x80 // should be zero
46 // bits for the output port
49 #define OUTPUT_RESET 0x01 // System reset on 0
50 #define OUTPUT_A20 0x02 // A20 gate (1= A20 is gated)
51 #define OUTPUT_RES1 0x04 // reserved
52 #define OUTPUT_RES2 0x08 // reserved
53 #define OUTPUT_OUTPUT_FULL 0x10 // output buffer full
54 #define OUTPUT_INPUT_EMPTY 0x20 // input buffer empty
55 #define OUTPUT_KBD_CLOCK 0x40 // keyboard clock (?)
56 #define OUTPUT_KBD_DATA 0x80 // keyboard data
58 // bits for the input port
60 #define INPUT_RES0 0x01 // reserved
61 #define INPUT_RES1 0x02 // reserved
62 #define INPUT_RES2 0x04 // reserved
63 #define INPUT_RES3 0x08 // reserved
64 #define INPUT_RAM 0x10 // set to 1 if RAM exists?
65 #define INPUT_JUMPER 0x20 // manufacturing jumper?
66 #define INPUT_DISPLAY 0x40 // 0=color, 1=mono
67 #define INPUT_KBD_INHIBIT 0x80 // 1=inhibit keyboard ?
76 // The currently targetted keyboard
77 static struct vm_device *thekeyboard = NULL;
80 struct keyboard_internal {
82 // 0x60 is the port for the keyboard microcontroller
83 // writes are commands
84 // reads from it usually return scancodes
85 // however, it can also return other data
86 // depending on the state of the onboard microcontroller
88 // 0x64 is the port for the onboard microcontroller
89 // writes are commands
93 // state of the onboard microcontroller
94 // this is needed because sometimes 0x60 reads come
95 // from the onboard microcontroller
96 enum {// Normal mode measn we deliver keys
97 // to the vm and accept commands from it
99 // after receiving cmd 0x60
100 // keybaord uC cmd will subsequently arrive
102 // after recieving 0xa5
103 // password arrives on data port, null terminated
105 // after having reset sent to 0x60
106 // we immediately ack, and then
107 // push BAT success (0xaa) after the ack
109 // after having a d1 sent to 64
110 // we wait for a new output byte on 60
112 // after having a d2 sent to 64
113 // we wait for a new output byte on 60
114 // then make it available as a keystroke
116 // after having a d3 sent to 64
117 // we wait for a new output byte on 60
118 // then make it available as a mouse event
120 // after having a d4 sent to 64
121 // we wait for a new output byte on 60
122 // then send it to the mouse
128 uchar_t cmd_byte; // for keyboard uC - read/written
129 // via read/write cmd byte command
130 uchar_t status_byte; // for on-board uC - read via 64h
132 uchar_t output_byte; // output port of onboard uC (e.g. A20)
134 uchar_t input_byte; // input port of onboard uC
137 uchar_t input_queue; //
138 uint_t input_queue_len; //
140 uchar_t output_queue; //
141 uint_t output_queue_len; //
146 // push item onto outputqueue, optionally overwriting if there is no room
147 // returns 0 if successful
149 static int PushToOutputQueue(struct vm_device *dev, uchar_t value, uchar_t overwrite, uchar_t cmd)
151 struct keyboard_internal *state = (struct keyboard_internal *)(dev->private_data);
153 if ((state->output_queue_len == 0) || overwrite) {
155 state->output_queue = value;
156 state->output_queue_len = 1;
157 state->status_byte |= STATUS_OUTPUT_BUFFER_FULL;
160 state->status_byte |= STATUS_COMMAND_DATA_AVAIL;
162 state->status_byte &= ~STATUS_COMMAND_DATA_AVAIL;
167 KEYBOARD_DEBUG_PRINT("keyboard: PushToOutputQueue Failed - Queue Full\n");
174 // pull item from outputqueue
175 // returns 0 if successful
177 static int PullFromOutputQueue(struct vm_device *dev, uchar_t *value)
179 struct keyboard_internal *state = (struct keyboard_internal *)(dev->private_data);
181 if (state->output_queue_len == 1) {
183 *value = state->output_queue;
184 state->output_queue_len = 0;
185 state->status_byte &= ~STATUS_OUTPUT_BUFFER_FULL;
187 if (state->status_byte & STATUS_COMMAND_DATA_AVAIL) {
188 state->status_byte &= ~STATUS_COMMAND_DATA_AVAIL;
193 KEYBOARD_DEBUG_PRINT("keyboard: PullFromOutputQueue Failed - Queue Empty\n");
201 // push item onto inputqueue, optionally overwriting if there is no room
202 // returns 0 if successful
204 static int PushToInputQueue(struct vm_device *dev, uchar_t value, uchar_t overwrite)
206 struct keyboard_internal *state = (struct keyboard_internal *)(dev->private_data);
208 if ((state->input_queue_len == 0) || overwrite) {
210 state->input_queue = value;
211 state->input_queue_len = 1;
212 state->status_byte |= STATUS_INPUT_BUFFER_FULL;
216 KEYBOARD_DEBUG_PRINT("keyboard: PushToOutputQueue Failed - Queue Full\n");
222 // pull item from inputqueue
223 // returns 0 if successful
225 static int PullFromInputQueue(struct vm_device *dev, uchar_t *value)
227 struct keyboard_internal *state = (struct keyboard_internal *)(dev->private_data);
229 if (state->input_queue_len == 1) {
231 *value = state->input_queue;
232 state->input_queue_len = 0;
233 state->status_byte &= ~STATUS_INPUT_BUFFER_FULL;
237 KEYBOARD_DEBUG_PRINT("keyboard: PullFromInputQueue Failed - Queue Empty\n");
245 static struct vm_device *demultiplex_injected_key(uchar_t status, uchar_t scancode)
247 // this currently does nothing
251 int keyboard_interrupt(uint_t irq, struct vm_device * dev);
253 void deliver_key_to_vmm(uchar_t status, uchar_t scancode)
255 struct vm_device *dev = demultiplex_injected_key(status, scancode);
256 struct keyboard_internal *state = (struct keyboard_internal *)(dev->private_data);
258 KEYBOARD_DEBUG_PRINT("keyboard: injected status 0x%x, and scancode 0x%x\n", status, scancode);
260 if ( (state->status_byte & STATUS_ENABLED) // onboard is enabled
261 && (!(state->cmd_byte & CMD_DISABLE)) ) { // keyboard is enabled
263 PushToOutputQueue(dev, scancode, OVERWRITE, DATA);
265 if (state->cmd_byte & CMD_INTR) {
266 keyboard_interrupt(KEYBOARD_IRQ, dev);
272 int keyboard_reset_device(struct vm_device * dev)
274 struct keyboard_internal *data = (struct keyboard_internal *)(dev->private_data);
276 memset(data, 0, sizeof(struct keyboard_internal));
279 CMD_INTR // interrupts on
280 | CMD_MOUSE_INTR // mouse interupts on
281 | CMD_SYSTEM ; // self test passed
282 // PS2, keyboard+mouse enabled, generic translation
285 STATUS_SYSTEM // self-tests passed
286 | STATUS_ENABLED ; // keyboard ready
287 // buffers empty, no errors
289 data->output_byte = 0; // ?
292 INPUT_RAM ; // we have some
293 // also display=color, jumper 0, keyboard enabled
295 KEYBOARD_DEBUG_PRINT("keyboard: reset device\n");
303 int keyboard_start_device(struct vm_device *dev)
305 KEYBOARD_DEBUG_PRINT("keyboard: start device\n");
310 int keyboard_stop_device(struct vm_device *dev)
312 KEYBOARD_DEBUG_PRINT("keyboard: stop device\n");
317 #if KEYBOARD_DEBUG_80H
318 int keyboard_write_delay(ushort_t port,
321 struct vm_device * dev)
325 KEYBOARD_DEBUG_PRINT("keyboard: write of 0x%x to 80h\n", *((uchar_t*)src));
329 KEYBOARD_DEBUG_PRINT("keyboard: write of >1 byte to 80h\n", *((uchar_t*)src));
335 int keyboard_read_delay(ushort_t port,
338 struct vm_device * dev)
342 *((uchar_t*)dest) = In_Byte(port);
344 KEYBOARD_DEBUG_PRINT("keyboard: read of 0x%x from 80h\n", *((uchar_t*)dest));
348 KEYBOARD_DEBUG_PRINT("keyboard: read of >1 byte from 80h\n");
359 int keyboard_write_command(ushort_t port,
362 struct vm_device * dev)
364 struct keyboard_internal *state = (struct keyboard_internal *)(dev->private_data);
367 // Should always be single byte write
370 KEYBOARD_DEBUG_PRINT("keyboard: write of >1 bytes (%d) to 64h\n", length);
374 cmd = *((uchar_t*)src);
376 if (state->state != NORMAL) {
377 KEYBOARD_DEBUG_PRINT("keyboard: warning - receiving command on 64h but state != NORMAL\n");
380 KEYBOARD_DEBUG_PRINT("keyboard: command 0x%x on 64h\n", cmd);
384 case 0x20: // READ COMMAND BYTE (returned in 60h)
385 PushToOutputQueue(dev, state->cmd_byte, OVERWRITE, COMMAND);
386 state->state = NORMAL; // the next read on 0x60 will get the right data
387 KEYBOARD_DEBUG_PRINT("keyboard: command byte 0x%x returned\n",state->cmd_byte);
390 case 0x60: // WRITE COMMAND BYTE (read from 60h)
391 state->state = WRITING_CMD_BYTE; // we need to make sure we send the next 0x60 byte appropriately
392 KEYBOARD_DEBUG_PRINT("keyboard: prepare to write command byte\n");
395 // case 0x90-9f - write to output port (?)
397 case 0xa1: // Get version number
398 PushToOutputQueue(dev, 0, OVERWRITE, COMMAND);
399 state->state = NORMAL;
400 KEYBOARD_DEBUG_PRINT("keyboard: version number 0x0 returned\n");
403 case 0xa4: // is password installed? send result to 0x60
404 // we don't support passwords
405 PushToOutputQueue(dev, 0xf1, OVERWRITE, COMMAND);
406 KEYBOARD_DEBUG_PRINT("keyboard: password not installed\n");
407 state->state = NORMAL;
410 case 0xa5: // new password will arrive on 0x60
411 state->state = TRANSMIT_PASSWD;
412 KEYBOARD_DEBUG_PRINT("keyboard: pepare to transmit password\n");
415 case 0xa6: // check passwd;
416 // since we do not support passwords, we will simply ignore this
417 // the implication is that any password check immediately succeeds
418 // with a blank password
419 state->state = NORMAL;
420 KEYBOARD_DEBUG_PRINT("keyboard: password check succeeded\n");
423 case 0xa7: // disable mouse
424 state->cmd_byte |= CMD_MOUSE_DISABLE;
425 state->state = NORMAL;
426 KEYBOARD_DEBUG_PRINT("keyboard: mouse disabled\n");
429 case 0xa8: // enable mouse
430 state->cmd_byte &= ~CMD_MOUSE_DISABLE;
431 state->state = NORMAL;
432 KEYBOARD_DEBUG_PRINT("keyboard: mouse enabled\n");
435 case 0xa9: // mouse interface test (always succeeds)
436 PushToOutputQueue(dev, 0, OVERWRITE,COMMAND);
437 KEYBOARD_DEBUG_PRINT("keyboard: mouse interface test succeeded\n");
438 state->state = NORMAL;
441 case 0xaa: // controller self test (always succeeds)
442 PushToOutputQueue(dev, 0x55, OVERWRITE, COMMAND);
443 KEYBOARD_DEBUG_PRINT("keyboard: controller self test succeeded\n");
444 state->state = NORMAL;
447 case 0xab: // keyboard interface test (always succeeds)
448 PushToOutputQueue(dev, 0, OVERWRITE, COMMAND);
449 state->state = NORMAL;
450 KEYBOARD_DEBUG_PRINT("keyboard: keyboard interface test succeeded\n");
453 case 0xad: // disable keyboard
454 state->cmd_byte |= CMD_DISABLE;
455 state->state = NORMAL;
456 KEYBOARD_DEBUG_PRINT("keyboard: keyboard disabled\n");
459 case 0xae: // enable keyboard
460 state->cmd_byte &= ~CMD_DISABLE;
461 state->state = NORMAL;
462 KEYBOARD_DEBUG_PRINT("keyboard: keyboard enabled\n");
465 case 0xaf: // get version
466 PushToOutputQueue(dev, 0x00, OVERWRITE, COMMAND);
467 state->state = NORMAL;
468 KEYBOARD_DEBUG_PRINT("keyboard: version 0 returned \n");
471 case 0xd0: // return microcontroller output on 60h
472 PushToOutputQueue(dev,state->output_byte,OVERWRITE,COMMAND);
473 state->state = NORMAL;
474 KEYBOARD_DEBUG_PRINT("keyboard: output byte 0x%x returned\n",state->output_byte);
477 case 0xd1: // request to write next byte on 60h to the microcontroller output port
478 state->state = WRITING_OUTPUT_PORT;
479 KEYBOARD_DEBUG_PRINT("keyboard: prepare to write output byte\n");
482 case 0xd2: // write keyboard buffer (inject key)
483 state->state = INJECTING_KEY;
484 KEYBOARD_DEBUG_PRINT("keyboard: prepare to inject key\n");
487 case 0xd3: // write mouse buffer (inject mouse)
488 state->state = INJECTING_MOUSE;
489 KEYBOARD_DEBUG_PRINT("keyboard: prepare to inject mouse\n");
492 case 0xd4: // write mouse device (command to mouse?)
493 state->state = WRITING_MOUSE_CMD;
494 KEYBOARD_DEBUG_PRINT("keyboard: prepare to inject mouse command\n");
497 case 0xc0: // read input port
498 PushToOutputQueue(dev,state->input_byte,OVERWRITE,COMMAND);
500 KEYBOARD_DEBUG_PRINT("keyboard: input byte 0x%x returned\n",state->input_byte);
503 case 0xc1: //copy input port lsn to status msn
504 state->status_byte &= 0x0f;
505 state->status_byte |= (state->input_byte & 0xf)<<4;
507 KEYBOARD_DEBUG_PRINT("keyboard: copied input byte lsn to status msn\n");
510 case 0xc2: // copy input port msn to status msn
511 state->status_byte &= 0x0f;
512 state->status_byte |= (state->input_byte & 0xf0);
514 KEYBOARD_DEBUG_PRINT("keyboard: copied input byte msn to status msn\n");
517 case 0xe0: // read test port
518 PushToOutputQueue(dev,state->output_byte>>6,OVERWRITE,COMMAND);
520 KEYBOARD_DEBUG_PRINT("keyboard: read 0x%x from test port\n",state->output_byte>>6);
523 case 0xf0: // pulse output port
524 case 0xf1: // this should pulse 0..3 of cmd_byte on output port
525 case 0xf2: // instead of what is currently in output_byte (I think)
526 case 0xf3: // main effect is taht if bit zero is zero
527 case 0xf4: // should cause reset
528 case 0xf5: // I doubt anything more recent than a 286 running
529 case 0xf6: // OS2 with the penalty box will care
539 KEYBOARD_DEBUG_PRINT("keyboard: ignoring pulse of 0x%x (low=pulsed) on output port\n",cmd&0xf);
544 // case ac diagonstic - returns 16 bytes from keyboard microcontroler on 60h
546 KEYBOARD_DEBUG_PRINT("keyboard: ignoring command (unimplemented)\n");
547 state->state = NORMAL;
555 int keyboard_read_status(ushort_t port,
558 struct vm_device * dev)
560 struct keyboard_internal *state = (struct keyboard_internal *)(dev->private_data);
564 KEYBOARD_DEBUG_PRINT("keyboard: read status (64h): ");
566 *((uchar_t*)dest) = state->status_byte;
568 KEYBOARD_DEBUG_PRINT("0x%x\n", *((uchar_t*)dest));
572 KEYBOARD_DEBUG_PRINT("keyboard: >1 byte read for status (64h)\n");
577 int keyboard_write_output(ushort_t port,
580 struct vm_device * dev)
582 struct keyboard_internal *state = (struct keyboard_internal *)(dev->private_data);
585 KEYBOARD_DEBUG_PRINT("keyboard: write of 60h with >1 byte\n");
589 uchar_t data = *((uchar_t*)src);
591 KEYBOARD_DEBUG_PRINT("keyboard: output 0x%x on 60h\n", data);
593 switch (state->state) {
594 case WRITING_CMD_BYTE:
595 state->cmd_byte = data;
596 state->state = NORMAL;
597 KEYBOARD_DEBUG_PRINT("keyboard: wrote new command byte 0x%x\n",state->cmd_byte);
599 case WRITING_OUTPUT_PORT:
600 state->output_byte = data;
601 state->state = NORMAL;
602 KEYBOARD_DEBUG_PRINT("keyboard: wrote new output byte 0x%x\n",state->output_byte);
605 PushToOutputQueue(dev,data,OVERWRITE,DATA); // probably should be a call to deliver_key_to_vmm()
606 state->state = NORMAL;
607 KEYBOARD_DEBUG_PRINT("keyboard: injected key 0x%x\n",data);
609 case INJECTING_MOUSE:
610 KEYBOARD_DEBUG_PRINT("keyboard: ignoring injected mouse event 0x%x\n",data);
611 state->state = NORMAL;
613 case WRITING_MOUSE_CMD:
614 KEYBOARD_DEBUG_PRINT("keyboard: ignoring injected mouse command 0x%x\n",data);
615 state->state = NORMAL;
617 case TRANSMIT_PASSWD:
620 KEYBOARD_DEBUG_PRINT("keyboard: ignoring password character 0x%x\n",data);
623 state->state = NORMAL;
624 KEYBOARD_DEBUG_PRINT("keyboard: done with password\n");
629 // command is being sent to keyboard controller
632 PushToOutputQueue(dev, 0xfa, OVERWRITE, COMMAND); // ack
633 state->state = RESET;
634 KEYBOARD_DEBUG_PRINT("keyboard: reset complete and acked\n",data);
636 case 0xf5: // disable scanning
637 case 0xf4: // enable scanning
639 PushToOutputQueue(dev, 0xfa, OVERWRITE, COMMAND);
640 // should do something here... PAD
641 state->state = NORMAL;
642 KEYBOARD_DEBUG_PRINT("keyboard: %s scanning done and acked\n",data==0xf5 ? "disable" : "enable", data);
645 case 0xfd: // set key type make
646 case 0xfc: // set key typ make/break
647 case 0xfb: // set key type typematic
648 case 0xfa: // set all typematic make/break/typematic
649 case 0xf9: // set all make
650 case 0xf8: // set all make/break
651 case 0xf7: // set all typemaktic
652 case 0xf6: // set defaults
653 case 0xf3: // set typematic delay/rate
654 KEYBOARD_DEBUG_PRINT("keyboard: unhandled known command 0x%x on output buffer (60h)\n", data);
657 KEYBOARD_DEBUG_PRINT("keyboard: unhandled unknown command 0x%x on output buffer (60h)\n", data);
663 KEYBOARD_DEBUG_PRINT("keyboard: unknown state %x on command 0x%x on output buffer (60h)\n", state->state, data);
669 int keyboard_read_input(ushort_t port,
672 struct vm_device * dev)
674 struct keyboard_internal *state = (struct keyboard_internal *)(dev->private_data);
679 KEYBOARD_DEBUG_PRINT("keyboard: read from input (60h): ");
681 PullFromOutputQueue(dev, &data);
683 if (state->state == RESET) {
684 // We just delivered the ack for the reset
685 // now we will ready ourselves to deliver the BAT code (success)
686 PushToOutputQueue(dev, 0xaa, OVERWRITE,COMMAND);
687 state->state = NORMAL;
688 KEYBOARD_DEBUG_PRINT(" (in reset, pushing BAT test code 0xaa) ");
691 KEYBOARD_DEBUG_PRINT("0x%x\n", data);
693 *((uchar_t*)dest) = data;
697 KEYBOARD_DEBUG_PRINT("keyboard: unknown size read from input (60h)\n");
703 int keyboard_interrupt(uint_t irq, struct vm_device * dev)
705 KEYBOARD_DEBUG_PRINT("keyboard: interrupt\n");
707 dev->vm->vm_ops.raise_irq(dev->vm, irq);
714 int keyboard_init_device(struct vm_device * dev)
717 // struct keyboard_internal *data = (struct keyboard_internal *) dev->private_data;
719 KEYBOARD_DEBUG_PRINT("keyboard: init_device\n");
721 // Would read state here
723 keyboard_reset_device(dev);
726 dev_hook_io(dev, KEYBOARD_64H, &keyboard_read_status, &keyboard_write_command);
727 dev_hook_io(dev, KEYBOARD_60H, &keyboard_read_input, &keyboard_write_output);
729 #if KEYBOARD_DEBUG_80H
730 dev_hook_io(dev, KEYBOARD_DELAY_80H, &keyboard_read_delay, &keyboard_write_delay);
735 // We do not hook the IRQ here. Instead, the underlying device driver
736 // is responsible to call us back
742 int keyboard_deinit_device(struct vm_device *dev)
745 dev_unhook_io(dev, KEYBOARD_60H);
746 dev_unhook_io(dev, KEYBOARD_64H);
747 #if KEYBOARD_DEBUG_80H
748 dev_unhook_io(dev, KEYBOARD_DELAY_80H);
750 keyboard_reset_device(dev);
758 static struct vm_device_ops dev_ops = {
759 .init = keyboard_init_device,
760 .deinit = keyboard_deinit_device,
761 .reset = keyboard_reset_device,
762 .start = keyboard_start_device,
763 .stop = keyboard_stop_device,
769 struct vm_device *create_keyboard() {
771 if (thekeyboard != NULL) {
772 KEYBOARD_DEBUG_PRINT("keyboard: creating >1 keyboard device. This will probably fail!\n");
775 struct keyboard_internal * keyboard_state = (struct keyboard_internal *)V3_Malloc(sizeof(struct keyboard_internal));
777 struct vm_device *device = create_device("KEYBOARD", &dev_ops, keyboard_state);
779 thekeyboard = device;