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 // The currently targetted keyboard
47 static struct vm_device *thekeyboard = NULL;
50 struct keyboard_internal {
52 // 0x60 is the port for the keyboard microcontroller
53 // writes are commands
54 // reads from it usually return scancodes
55 // however, it can also return other data
56 // depending on the state of the onboard microcontroller
58 // 0x64 is the port for the onboard microcontroller
59 // writes are commands
63 // state of the onboard microcontroller
64 // this is needed because sometimes 0x60 reads come
65 // from the onboard microcontroller
66 enum {// Normal mode measn we deliver keys
67 // to the vm and accept commands from it
69 // after receiving cmd 0x60
70 // keybaord uC cmd will subsequently arrive
72 // after recieving 0xa5
73 // password arrives on data port, null terminated
75 // after having reset sent to 0x60
76 // we immediately ack, and then
77 // push BAT success (0xaa) after the ack
83 uchar_t cmd_byte; // for keyboard uC - read/written
84 // via read/write cmd byte command
85 uchar_t status_byte; // for on-board uC - read via 64h
88 uchar_t input_queue; //
89 uint_t input_queue_len; //
91 uchar_t output_queue; //
92 uint_t output_queue_len; //
97 // push item onto outputqueue, optionally overwriting if there is no room
98 // returns 0 if successful
100 static int PushToOutputQueue(struct vm_device *dev, uchar_t value, uchar_t overwrite)
102 struct keyboard_internal *state = (struct keyboard_internal *)(dev->private_data);
104 if ((state->output_queue_len == 0) || overwrite) {
106 state->output_queue = value;
107 state->output_queue_len = 1;
108 state->status_byte |= STATUS_OUTPUT_BUFFER_FULL;
112 KEYBOARD_DEBUG_PRINT("keyboard: PushToOutputQueue Failed - Queue Full\n");
119 // pull item from outputqueue
120 // returns 0 if successful
122 static int PullFromOutputQueue(struct vm_device *dev, uchar_t *value)
124 struct keyboard_internal *state = (struct keyboard_internal *)(dev->private_data);
126 if (state->output_queue_len == 1) {
128 *value = state->output_queue;
129 state->output_queue_len = 0;
130 state->status_byte &= ~STATUS_OUTPUT_BUFFER_FULL;
134 KEYBOARD_DEBUG_PRINT("keyboard: PullFromOutputQueue Failed - Queue Empty\n");
142 // push item onto inputqueue, optionally overwriting if there is no room
143 // returns 0 if successful
145 static int PushToInputQueue(struct vm_device *dev, uchar_t value, uchar_t overwrite)
147 struct keyboard_internal *state = (struct keyboard_internal *)(dev->private_data);
149 if ((state->input_queue_len == 0) || overwrite) {
151 state->input_queue = value;
152 state->input_queue_len = 1;
153 state->status_byte |= STATUS_INPUT_BUFFER_FULL;
157 KEYBOARD_DEBUG_PRINT("keyboard: PushToOutputQueue Failed - Queue Full\n");
163 // pull item from inputqueue
164 // returns 0 if successful
166 static int PullFromInputQueue(struct vm_device *dev, uchar_t *value)
168 struct keyboard_internal *state = (struct keyboard_internal *)(dev->private_data);
170 if (state->input_queue_len == 1) {
172 *value = state->input_queue;
173 state->input_queue_len = 0;
174 state->status_byte &= ~STATUS_INPUT_BUFFER_FULL;
178 KEYBOARD_DEBUG_PRINT("keyboard: PullFromInputQueue Failed - Queue Empty\n");
186 static struct vm_device *demultiplex_injected_key(uchar_t status, uchar_t scancode)
188 // this currently does nothing
192 int keyboard_interrupt(uint_t irq, struct vm_device * dev);
194 void deliver_key_to_vmm(uchar_t status, uchar_t scancode)
196 struct vm_device *dev = demultiplex_injected_key(status, scancode);
197 struct keyboard_internal *state = (struct keyboard_internal *)(dev->private_data);
199 KEYBOARD_DEBUG_PRINT("keyboard: injected status 0x%x, and scancode 0x%x\n", status, scancode);
201 if ( (state->status_byte & STATUS_ENABLED) // onboard is enabled
202 && (!(state->cmd_byte & CMD_DISABLE)) ) { // keyboard is enabled
204 PushToOutputQueue(dev, scancode, 1);
206 if (state->cmd_byte & CMD_INTR) {
207 keyboard_interrupt(KEYBOARD_IRQ, dev);
213 int keyboard_reset_device(struct vm_device * dev)
215 struct keyboard_internal *data = (struct keyboard_internal *)(dev->private_data);
217 memset(data, 0, sizeof(struct keyboard_internal));
220 CMD_INTR // interrupts on
221 | CMD_MOUSE_INTR // mouse interupts on
222 | CMD_SYSTEM ; // self test passed
223 // PS2, keyboard+mouse enabled, generic translation
226 STATUS_SYSTEM // self-tests passed
227 | STATUS_ENABLED ; // keyboard ready
228 // buffers empty, no errors
230 KEYBOARD_DEBUG_PRINT("keyboard: reset device\n");
238 int keyboard_start_device(struct vm_device *dev)
240 KEYBOARD_DEBUG_PRINT("keyboard: start device\n");
245 int keyboard_stop_device(struct vm_device *dev)
247 KEYBOARD_DEBUG_PRINT("keyboard: stop device\n");
252 #if KEYBOARD_DEBUG_80H
253 int keyboard_write_delay(ushort_t port,
256 struct vm_device * dev)
260 KEYBOARD_DEBUG_PRINT("keyboard: write of 0x%x to 80h\n", *((uchar_t*)src));
264 KEYBOARD_DEBUG_PRINT("keyboard: write of >1 byte to 80h\n", *((uchar_t*)src));
270 int keyboard_read_delay(ushort_t port,
273 struct vm_device * dev)
277 *((uchar_t*)dest) = In_Byte(port);
279 KEYBOARD_DEBUG_PRINT("keyboard: read of 0x%x from 80h\n", *((uchar_t*)dest));
283 KEYBOARD_DEBUG_PRINT("keyboard: read of >1 byte from 80h\n");
294 int keyboard_write_command(ushort_t port,
297 struct vm_device * dev)
299 struct keyboard_internal *state = (struct keyboard_internal *)(dev->private_data);
302 // Should always be single byte write
305 KEYBOARD_DEBUG_PRINT("keyboard: write of >1 bytes (%d) to 64h\n", length);
309 cmd = *((uchar_t*)src);
311 if (state->state != NORMAL) {
312 KEYBOARD_DEBUG_PRINT("keyboard: warning - receiving command on 64h but state != NORMAL\n");
315 KEYBOARD_DEBUG_PRINT("keyboard: command 0x%x on 64h\n", cmd);
319 case 0x20: // READ COMMAND BYTE (returned in 60h)
320 PushToOutputQueue(dev, state->cmd_byte, 1);
321 state->state = NORMAL; // the next read on 0x60 will get the right data
324 case 0x60: // WRITE COMMAND BYTE (read from 60h)
325 state->state = WRITING_CMD_BYTE; // we need to make sure we send the next 0x60 byte appropriately
328 // case 0x90-9f - write to output port (?)
330 case 0xa1: // Get version number
331 PushToOutputQueue(dev, 0, 1);
332 state->state = NORMAL;
335 case 0xa4: // is password installed? send result to 0x60
336 // we don't support passwords
337 PushToOutputQueue(dev, 0xf1, 1);
338 state->state = NORMAL;
341 case 0xa5: // new password will arrive on 0x60
342 state->state = TRANSMIT_PASSWD;
345 case 0xa6: // check passwd;
346 // since we do not support passwords, we will simply ignore this
347 // the implication is that any password check immediately succeeds
348 // with a blank password
349 state->state = NORMAL;
352 case 0xa7: // disable mouse
353 state->cmd_byte |= CMD_MOUSE_DISABLE;
354 state->state = NORMAL;
357 case 0xa8: // enable mouse
358 state->cmd_byte &= ~CMD_MOUSE_DISABLE;
359 state->state = NORMAL;
362 case 0xa9: // mouse interface test (always succeeds)
363 PushToOutputQueue(dev, 0, 1);
364 state->state = NORMAL;
367 case 0xaa: // controller self test (always succeeds)
368 PushToOutputQueue(dev, 0x55, 1);
369 state->state = NORMAL;
372 case 0xab: // keyboard interface test (always succeeds)
373 PushToOutputQueue(dev, 0, 1);
374 state->state = NORMAL;
377 case 0xad: // disable keyboard
378 state->cmd_byte |= CMD_DISABLE;
379 state->state = NORMAL;
382 case 0xae: // enable keyboard
383 state->cmd_byte &= ~CMD_DISABLE;
384 state->state = NORMAL;
387 case 0xaf: // get version
388 PushToOutputQueue(dev, 0x00, 1);
389 state->state = NORMAL;
392 // case c0 read input port ?
393 // case c1 copy input port lsn to status
394 // case c2 copy input port msn to status
396 // case d0 read output port
397 // case d1 write output port
398 // case d2 write keyboard buffer (inject key)
399 // case d3 write mouse buffer (inject mouse)
400 // case d4 write mouse device (command to mouse?)
402 // case e0 read test port
404 // case f0..ff pulse output port ?
408 KEYBOARD_DEBUG_PRINT("keyboard: ignoring command (unimplemented)\n");
409 state->state = NORMAL;
417 int keyboard_read_status(ushort_t port,
420 struct vm_device * dev)
422 struct keyboard_internal *state = (struct keyboard_internal *)(dev->private_data);
426 KEYBOARD_DEBUG_PRINT("keyboard: read status (64h): ");
428 *((uchar_t*)dest) = state->status_byte;
430 KEYBOARD_DEBUG_PRINT("0x%x\n", *((uchar_t*)dest));
434 KEYBOARD_DEBUG_PRINT("keyboard: >1 byte read for status (64h)\n");
439 int keyboard_write_output(ushort_t port,
442 struct vm_device * dev)
444 struct keyboard_internal *state = (struct keyboard_internal *)(dev->private_data);
447 KEYBOARD_DEBUG_PRINT("keyboard: write of 60h with >1 byte\n");
451 uchar_t data = *((uchar_t*)src);
453 switch (state->state) {
454 case WRITING_CMD_BYTE:
455 state->cmd_byte = data;
456 state->state = NORMAL;
458 case TRANSMIT_PASSWD:
463 state->state = NORMAL;
468 // command is being sent to keyboard controller
471 PushToOutputQueue(dev, 0xfa, 1); // ack
472 state->state = RESET;
474 case 0xf5: // disable scanning
475 case 0xf4: // enable scanning
477 PushToOutputQueue(dev, 0xfa, 1);
478 // should do something here... PAD
479 state->state = NORMAL;
482 case 0xfd: // set key type make
483 case 0xfc: // set key typ make/break
484 case 0xfb: // set key type typematic
485 case 0xfa: // set all typematic make/break/typematic
486 case 0xf9: // set all make
487 case 0xf8: // set all make/break
488 case 0xf7: // set all typemaktic
489 case 0xf6: // set defaults
490 case 0xf3: // set typematic delay/rate
492 KEYBOARD_DEBUG_PRINT("keyboard: unhandled command 0x%x on output buffer (60h)\n", data);
498 KEYBOARD_DEBUG_PRINT("keyboard: unknown state %x on command 0x%x on output buffer (60h)\n", state->state, data);
504 int keyboard_read_input(ushort_t port,
507 struct vm_device * dev)
509 struct keyboard_internal *state = (struct keyboard_internal *)(dev->private_data);
514 KEYBOARD_DEBUG_PRINT("keyboard: read from input (60h): ");
516 PullFromOutputQueue(dev, &data);
518 if (state->state == RESET) {
519 // We just delivered the ack for the reset
520 // now we will ready ourselves to deliver the BAT code (success)
521 PushToOutputQueue(dev, 0xaa, 1);
522 state->state = NORMAL;
525 KEYBOARD_DEBUG_PRINT("0x%x\n", data);
527 *((uchar_t*)dest) = data;
531 KEYBOARD_DEBUG_PRINT("keyboard: unknown size read from input (60h)\n");
537 int keyboard_interrupt(uint_t irq, struct vm_device * dev)
539 KEYBOARD_DEBUG_PRINT("keyboard: interrupt\n");
541 dev->vm->vm_ops.raise_irq(dev->vm, irq);
548 int keyboard_init_device(struct vm_device * dev)
551 // struct keyboard_internal *data = (struct keyboard_internal *) dev->private_data;
553 KEYBOARD_DEBUG_PRINT("keyboard: init_device\n");
555 // Would read state here
557 keyboard_reset_device(dev);
560 dev_hook_io(dev, KEYBOARD_64H, &keyboard_read_status, &keyboard_write_command);
561 dev_hook_io(dev, KEYBOARD_60H, &keyboard_read_input, &keyboard_write_output);
563 #if KEYBOARD_DEBUG_80H
564 dev_hook_io(dev, KEYBOARD_DELAY_80H, &keyboard_read_delay, &keyboard_write_delay);
569 // We do not hook the IRQ here. Instead, the underlying device driver
570 // is responsible to call us back
576 int keyboard_deinit_device(struct vm_device *dev)
579 dev_unhook_io(dev, KEYBOARD_60H);
580 dev_unhook_io(dev, KEYBOARD_64H);
581 #if KEYBOARD_DEBUG_80H
582 dev_unhook_io(dev, KEYBOARD_DELAY_80H);
584 keyboard_reset_device(dev);
592 static struct vm_device_ops dev_ops = {
593 .init = keyboard_init_device,
594 .deinit = keyboard_deinit_device,
595 .reset = keyboard_reset_device,
596 .start = keyboard_start_device,
597 .stop = keyboard_stop_device,
603 struct vm_device *create_keyboard() {
605 if (thekeyboard != NULL) {
606 KEYBOARD_DEBUG_PRINT("keyboard: creating >1 keyboard device. This will probably fail!\n");
609 struct keyboard_internal * keyboard_state = (struct keyboard_internal *)V3_Malloc(sizeof(struct keyboard_internal));
611 struct vm_device *device = create_device("KEYBOARD", &dev_ops, keyboard_state);
613 thekeyboard = device;