Palacios Public Git Repository

To checkout Palacios execute

  git clone http://v3vee.org/palacios/palacios.web/palacios.git
This will give you the master branch. You probably want the devel branch or one of the release branches. To switch to the devel branch, simply execute
  cd palacios
  git checkout --track -b devel origin/devel
The other branches are similar.


039db764b4a345c0956c800f45e1f965eee70819
[palacios.git] / palacios / src / devices / keyboard.c
1 /* 
2  * This file is part of the Palacios Virtual Machine Monitor developed
3  * by the V3VEE Project with funding from the United States National 
4  * Science Foundation and the Department of Energy.  
5  *
6  * The V3VEE Project is a joint project between Northwestern University
7  * and the University of New Mexico.  You can find out more at 
8  * http://www.v3vee.org
9  *
10  * Copyright (c) 2008, Peter Dinda <pdinda@northwestern.edu> 
11  * Copyright (c) 2008, The V3VEE Project <http://www.v3vee.org> 
12  * All rights reserved.
13  *
14  * Author: Peter Dinda <pdinda@northwestern.edu>
15  *
16  * This is free software.  You are permitted to use,
17  * redistribute, and modify it as specified in the file "V3VEE_LICENSE".
18  */
19
20 #include <palacios/vmm.h>
21 #include <palacios/vmm_dev_mgr.h>
22 #include <palacios/vmm_types.h>
23
24 #include <palacios/vmm_ringbuffer.h>
25 #include <palacios/vmm_lock.h>
26 #include <palacios/vmm_intr.h>
27 #include <palacios/vmm_host_events.h>
28 #include <palacios/vm_guest.h>
29
30
31 #ifndef V3_CONFIG_DEBUG_KEYBOARD
32 #undef PrintDebug
33 #define PrintDebug(fmt, args...)
34 #endif
35
36 #define KEYBOARD_DEBUG_80H   0
37
38
39
40 #define KEYBOARD_60H          0x60  // keyboard microcontroller
41 #define KEYBOARD_64H          0x64  // onboard microcontroller
42
43 #define KEYBOARD_DELAY_80H    0x80  // written for timing
44
45 #define KEYBOARD_IRQ          0x1
46 #define MOUSE_IRQ             0xc   
47
48
49
50 // bits for the output port 
51 #define OUTPUT_RESET        0x01  // System reset on 0
52 #define OUTPUT_A20          0x02  // A20 gate (1= A20 is gated)
53 #define OUTPUT_RES1         0x04  // reserved
54 #define OUTPUT_RES2         0x08  // reserved
55 #define OUTPUT_OUTPUT_FULL  0x10  // output buffer full
56 #define OUTPUT_INPUT_EMPTY  0x20  // input buffer empty
57 #define OUTPUT_KBD_CLOCK    0x40  // keyboard clock (?)
58 #define OUTPUT_KBD_DATA     0x80  // keyboard data
59
60 // bits for the input port
61
62 #define INPUT_RES0          0x01  // reserved
63 #define INPUT_RES1          0x02  // reserved
64 #define INPUT_RES2          0x04  // reserved
65 #define INPUT_RES3          0x08  // reserved
66 #define INPUT_RAM           0x10  // set to 1 if RAM exists?
67 #define INPUT_JUMPER        0x20  // manufacturing jumper?
68 #define INPUT_DISPLAY       0x40  // 0=color, 1=mono
69 #define INPUT_KBD_INHIBIT   0x80  // 1=inhibit keyboard ?
70
71
72 #define MOUSE_ACK           0xfa
73
74 // for queue operations
75 #define QUEUE               0
76 #define OVERWRITE           1
77
78 // for queue operations - whether it's data or cmd waiting on 60h
79 #define DATA                0
80 #define COMMAND             1
81
82 // for queue operations - whether this is keyboard or mouse data on 60h
83 #define KEYBOARD            0
84 #define MOUSE               1
85
86
87
88 struct cmd_reg {
89     union {
90         uint8_t val;
91         struct {
92             uint8_t irq_en        : 1;  // 1=interrupts enabled
93             uint8_t mouse_irq_en  : 1;  // 1=interrupts enabled for mouse
94             uint8_t self_test_ok  : 1;  // 1= self test passed
95             uint8_t override      : 1;  // MBZ for  PS2
96             uint8_t disable       : 1;  // 1=disabled keyboard
97             uint8_t mouse_disable : 1;  // 1=disabled mouse
98             uint8_t translate     : 1;  // 1=translate to set 1 scancodes (For PC Compatibility)
99             uint8_t rsvd          : 1;  // must be zero
100         } __attribute__((packed));
101     } __attribute__((packed));
102 } __attribute__((packed));
103
104
105
106
107 struct status_reg {
108     union {
109         uint8_t val;
110         struct {
111             uint8_t out_buf_full        : 1; // 1=full (data for system)
112             uint8_t in_buf_full         : 1; // 1=full (data for 8042)
113             uint8_t self_test_ok        : 1; // 1=self-test-passed
114             uint8_t cmd                 : 1; // 0=data on 60h, 1=cmd on 64h
115             uint8_t enabled             : 1; // 1=keyboard is enabled
116             uint8_t mouse_buf_full      : 1; // 1= mouse output buffer full
117             uint8_t timeout_err         : 1; // 1=timeout of keybd
118             uint8_t parity_err          : 1; // 1=parity error
119         } __attribute__((packed));
120     } __attribute__((packed));
121 } __attribute__((packed));
122
123
124
125
126
127
128 /* This QUEUE_SIZE must be 256 */
129 /* Its designed this way to cause the start/end index to automatically
130    wrap around (2^8 = 256) so an overrun will automatically readjust the 
131    indexes 
132 */
133 #define QUEUE_SIZE 256
134 struct queue {
135     uint8_t queue[QUEUE_SIZE];
136
137     uint8_t start;
138     uint8_t end;
139     int count;
140 };
141
142 struct keyboard_internal {
143     // 
144     // 0x60 is the port for the keyboard microcontroller
145     //   writes are commands
146     //   reads from it usually return scancodes
147     //   however, it can also return other data 
148     //   depending on the state of the onboard microcontroller
149     //
150     // 0x64 is the port for the onboard microcontroller
151     //   writes are commands
152     //   reads are status
153     //
154
155     // state of the onboard microcontroller
156     // this is needed because sometimes 0x60 reads come
157     // from the onboard microcontroller
158     enum {// Normal mode measn we deliver keys
159         // to the vm and accept commands from it
160         NORMAL,
161         // after receiving cmd 0x60
162         // keybaord uC cmd will subsequently arrive
163         WRITING_CMD_BYTE,  
164         // after recieving 0xa5
165         // password arrives on data port, null terminated
166         TRANSMIT_PASSWD,
167         // after having a d1 sent to 64
168         // we wait for a new output byte on 60
169         WRITING_OUTPUT_PORT,
170         // after having a d2 sent to 64
171         // we wait for a new output byte on 60
172         // then make it available as a keystroke
173         INJECTING_KEY,
174         // after having a d3 sent to 64
175         // we wait for a new output byte on 60
176         // then make it available as a mouse event
177         INJECTING_MOUSE,
178         // after having a d4 sent to 64
179         // we wait for a new output byte on 60
180         // then send it to the mouse
181         IN_MOUSE,
182         // After the Keyboard LEDs are enabled
183         // we wait for the output byte on 64?
184         SET_LEDS,
185         // After the Keyboard SET_RATE is called
186         // we wait for the output byte on 64?
187         SET_RATE,
188         // after having a f0 sent to 60
189         // we wait for a new output byte on 60
190         GETSET_SCANCODES,
191         // first send ACK (0xfa)
192         // then wait for reception, and reset kb state
193         SET_DEFAULTS,
194     } state;
195
196
197     enum {
198         // Normal mouse state
199         STREAM, 
200         // this is used for setting sample rate
201         SAMPLE,
202         // set resolution
203         SET_RES,
204     } mouse_state;
205
206
207
208     struct cmd_reg cmd;
209     struct status_reg status;
210
211     uint8_t output_byte;      //  output port of onboard uC (e.g. A20)
212     uint8_t input_byte;       //  input port of onboard uC
213
214     // Data for system
215     uint8_t wrap;     
216
217     uint8_t mouse_enabled;
218     uint8_t scancode_set;
219
220     struct queue kbd_queue;
221     struct queue mouse_queue;
222
223     struct v3_vm_info * vm;
224
225     v3_lock_t kb_lock;
226 };
227
228
229 static int keyboard_reset_device(struct keyboard_internal * kbd);
230
231
232 static int update_kb_irq(struct keyboard_internal * state) {
233     int irq_num = 0;
234
235
236     state->status.out_buf_full = 0;
237     state->status.mouse_buf_full = 0;
238
239
240     // If there is pending Keyboard data then it overrides mouse data
241     if (state->kbd_queue.count > 0) {
242         irq_num = KEYBOARD_IRQ;
243     } else if (state->mouse_queue.count > 0) {
244         irq_num = MOUSE_IRQ;
245         state->status.mouse_buf_full = 1;
246     } 
247     
248     PrintDebug("keyboard: interrupt 0x%d\n", irq_num);
249     
250     if (irq_num) {
251         // Global output buffer flag (for both Keyboard and mouse)
252         state->status.out_buf_full = 1;
253         
254         if (state->cmd.irq_en == 1) { 
255             v3_raise_irq(state->vm, irq_num);
256         }
257     }
258
259     return 0;
260 }
261
262
263
264 /* Only one byte is read per irq 
265  * So if the queue is still full after a data read, we re-raise the irq
266  * If we keep reading an empty queue we return the last queue entry
267  */
268
269 static int push_to_output_queue(struct keyboard_internal * state, uint8_t value, uint8_t cmd, uint8_t mouse) {
270     struct queue * q = NULL;
271
272
273     if (mouse) {
274         q = &(state->mouse_queue);
275     } else {
276         q = &(state->kbd_queue);
277     }
278
279     if (q->count >= QUEUE_SIZE) {
280         return 0;
281     }
282
283     if (cmd) {
284         state->status.cmd = 1;
285     } else {
286         state->status.cmd = 0;
287     }
288
289     q->queue[q->end] = value;
290
291     if (q->end >= (QUEUE_SIZE - 1)) {
292         q->end = 0;
293     } else {
294         q->end++;
295     }
296
297     q->count++;
298
299
300     update_kb_irq(state);
301
302     return 0;
303 }
304
305
306
307 static int pull_from_output_queue(struct keyboard_internal * state, uint8_t * value) {
308     struct queue * q = NULL;
309
310     if (state->kbd_queue.count > 0) {
311         q = &(state->kbd_queue);
312         PrintDebug("Reading from Keyboard Queue\n");
313     } else if (state->mouse_queue.count > 0) {
314         q = &(state->mouse_queue);
315         PrintDebug("Reading from Mouse Queue\n");
316     } else {
317         uint8_t idx = state->kbd_queue.start - 1;
318         PrintDebug("No Data in any queue\n");
319         *value = state->kbd_queue.queue[idx];
320         return 0;
321     }
322
323     *value = q->queue[q->start];
324
325     if (q->start >= (QUEUE_SIZE - 1)) {
326         q->start = 0;
327     } else {
328         q->start++;
329     }
330
331     q->count--;
332
333
334     PrintDebug("Read from Queue: %x\n", *value);
335     PrintDebug("QStart=%d, QEnd=%d\n", q->start, q->end);
336
337     update_kb_irq(state);
338
339     return 0;
340 }
341
342
343 #include <palacios/vmm_telemetry.h>
344 #ifdef V3_CONFIG_SYMMOD
345 #include <palacios/vmm_symmod.h>
346 #endif
347
348 static int key_event_handler(struct v3_vm_info * vm, 
349                              struct v3_keyboard_event * evt, 
350                              void * private_data) {
351     struct keyboard_internal * state = (struct keyboard_internal *)private_data;
352
353     PrintDebug("keyboard: injected status 0x%x, and scancode 0x%x\n", evt->status, evt->scan_code);
354
355     if (evt->scan_code == 0x44) { // F10 debug dump
356         int i = 0;
357         for (i = 0; i < vm->num_cores; i++) {
358             v3_print_guest_state(&(vm->cores[i]));
359         }
360         //      PrintGuestPageTables(info, info->shdw_pg_state.guest_cr3);
361     } 
362 #ifdef V3_CONFIG_SYMCALL
363     else if (evt->scan_code == 0x43) { // F9 Sym test
364         struct guest_info * core = &(vm->cores[0]);
365         PrintDebug("Testing sym call\n");
366         sym_arg_t a0 = 0x1111;
367         sym_arg_t a1 = 0x2222;
368         sym_arg_t a2 = 0x3333;
369         sym_arg_t a3 = 0x4444;
370         sym_arg_t a4 = 0x5555;
371         uint64_t call_start = 0;
372         uint64_t call_end = 0;
373         
374         V3_Print("Exits before symcall: %d\n", (uint32_t)core->num_exits);
375
376         rdtscll(call_start);
377         v3_sym_call5(core, SYMCALL_TEST, &a0, &a1, &a2, &a3, &a4);
378         rdtscll(call_end);
379         
380         V3_Print("Symcall latency = %d cycles (%d exits)\n", (uint32_t)(call_end - call_start), (uint32_t)core->num_exits);
381
382         V3_Print("Symcall  Test Returned arg0=%x, arg1=%x, arg2=%x, arg3=%x, arg4=%x\n",
383                  (uint32_t)a0, (uint32_t)a1, (uint32_t)a2, (uint32_t)a3, (uint32_t)a4);
384
385     } 
386 #endif
387     else if (evt->scan_code == 0x42) { // F8 debug toggle
388         extern int v3_dbg_enable;
389         
390         PrintDebug("Toggling Debugging\n");     
391         v3_dbg_enable ^= 1;
392
393     } 
394 #ifdef V3_CONFIG_TELEMETRY
395
396     else if (evt->scan_code == 0x41) { // F7 telemetry dump
397         v3_print_global_telemetry(vm);
398     } 
399 #endif
400 #ifdef V3_CONFIG_SYMMOD
401     else if (evt->scan_code == 0x40) { // F6 Test symmod load
402         v3_load_sym_capsule(vm, "lnx_test");
403     }
404 #endif
405
406
407     addr_t irq_state = v3_lock_irqsave(state->kb_lock);
408
409     if ( (state->status.enabled == 1)      // onboard is enabled
410          && (state->cmd.disable == 0) )  {   // keyboard is enabled
411     
412         push_to_output_queue(state, evt->scan_code, DATA, KEYBOARD);
413     }
414
415     v3_unlock_irqrestore(state->kb_lock, irq_state);
416   
417     return 0;
418 }
419
420
421 static int mouse_event_handler(struct v3_vm_info * vm, 
422                                struct v3_mouse_event * evt, 
423                                void * private_data) {
424     struct keyboard_internal * kbd = (struct keyboard_internal *)private_data;
425     int ret = 0;
426
427     PrintDebug("keyboard: injected mouse packet 0x %x %x %x\n",
428                evt->data[0], evt->data[1], evt->data[2]);
429   
430     addr_t irq_state = v3_lock_irqsave(kbd->kb_lock);
431
432     switch (kbd->mouse_state) { 
433         case STREAM:
434
435             if (kbd->cmd.mouse_disable == 0) {
436                 push_to_output_queue(kbd, evt->data[0], DATA, MOUSE);
437                 push_to_output_queue(kbd, evt->data[1], DATA, MOUSE);
438                 push_to_output_queue(kbd, evt->data[2], DATA, MOUSE);
439             }
440             break;
441         default:
442             PrintError("Invalid mouse state\n");
443             ret = -1;
444             break;
445     }
446
447
448     v3_unlock_irqrestore(kbd->kb_lock, irq_state);
449
450     return ret;
451 }
452
453
454
455
456
457
458
459
460
461
462 static int mouse_write_output(struct keyboard_internal * kbd, uint8_t data) {
463     switch (kbd->mouse_state) { 
464         case NORMAL:
465             switch (data) {
466
467                 case 0xff: //reset
468                     if (kbd->mouse_enabled == 0) {
469                         push_to_output_queue(kbd, 0xfe, DATA, MOUSE) ;   // no mouse!
470                     } else {
471                         push_to_output_queue(kbd, MOUSE_ACK, DATA, MOUSE) ; 
472                         push_to_output_queue(kbd, 0xaa, DATA, MOUSE) ; 
473                         push_to_output_queue(kbd, 0x00, DATA, MOUSE) ; 
474                     }
475                     break;
476
477 /*              case 0xfe: //resend */
478 /*                  PushToOutputQueue(kbd, 0xfa, OVERWRITE, DATA, MOUSE) ;  */
479 /*                  PrintDebug(" mouse resend begins "); */
480 /*                  kbd->mouse_done_after_ack = 0; */
481 /*                  kbd->mouse_needs_ack = 0; */
482 /*                  kbd->mouse_state = STREAM1; */
483 /*                  return 0;  // not done */
484 /*                  break; */
485       
486                 case 0xf6: // set defaults
487                     push_to_output_queue(kbd, MOUSE_ACK, DATA, MOUSE) ; 
488                     PrintDebug(" mouse set defaults ");
489
490                     break;
491       
492                 case 0xf5: // disable data reporting 
493                     push_to_output_queue(kbd, MOUSE_ACK, DATA, MOUSE) ; 
494                     PrintDebug(" mouse disable data reporting ");
495                     break;
496       
497                 case 0xf4: // enable data reporting 
498                     push_to_output_queue(kbd, MOUSE_ACK, DATA, MOUSE) ; 
499                     PrintDebug(" mouse enable data reporting ");
500                     break;
501       
502                 case 0xf3: // set sample rate
503                     push_to_output_queue(kbd, MOUSE_ACK, DATA, MOUSE) ; 
504                     kbd->mouse_state = SAMPLE;
505                     PrintDebug(" mouse set sample rate begins ");
506                     break;
507       
508                 case 0xf2: // get device id
509                     push_to_output_queue(kbd, MOUSE_ACK, DATA, MOUSE) ; 
510                     push_to_output_queue(kbd, 0x0,  DATA, MOUSE); 
511                     PrintDebug(" mouse get device id begins ");
512                     break;
513       
514                 case 0xf0: // set remote mode
515                     push_to_output_queue(kbd, MOUSE_ACK, DATA, MOUSE) ; 
516                     PrintDebug(" mouse set remote mode  ");
517                     break;
518
519                 case 0xee: // set wrap mode
520                     push_to_output_queue(kbd, MOUSE_ACK, DATA, MOUSE) ; 
521                     PrintError(" mouse set wrap mode (ignored)  ");
522                     break;
523
524                 case 0xec: // reset wrap mode
525                     push_to_output_queue(kbd, MOUSE_ACK, DATA, MOUSE) ; 
526                     PrintError(" mouse reset wrap mode (ignored)  ");
527                     break;
528
529                 case 0xeb: // read data
530                     push_to_output_queue(kbd, MOUSE_ACK, DATA, MOUSE) ; 
531                     PrintError(" mouse switch to wrap mode (ignored)  ");
532                     break;
533       
534                 case 0xea: // set stream mode
535                     push_to_output_queue(kbd, MOUSE_ACK, DATA, MOUSE) ; 
536                     PrintDebug(" mouse set stream mode  ");
537                     break;
538
539                 case 0xe9: // status request
540                     push_to_output_queue(kbd, MOUSE_ACK, DATA, MOUSE) ; 
541                     push_to_output_queue(kbd, 0x00, DATA, MOUSE); 
542                     push_to_output_queue(kbd, 0x00, DATA, MOUSE);
543                     push_to_output_queue(kbd, 0x00, DATA, MOUSE); 
544                     PrintDebug(" mouse status request begins  ");
545                     break;
546
547                 case 0xe8: // set resolution
548                     push_to_output_queue(kbd, MOUSE_ACK,  DATA, MOUSE) ; 
549                     PrintDebug(" mouse set resolution begins  ");
550                     kbd->mouse_state = SET_RES;
551                     break;
552
553                 case 0xe7: // set scaling 2:1
554                     push_to_output_queue(kbd, MOUSE_ACK, DATA, MOUSE) ; 
555                     PrintDebug(" mouse set scaling 2:1 ");
556                     break;
557
558                 case 0xe6: // set scaling 1:1
559                     push_to_output_queue(kbd, MOUSE_ACK, DATA, MOUSE) ; 
560                     PrintDebug(" mouse set scaling 1:1 ");
561                     break;
562       
563                 default:
564                     PrintDebug(" receiving unknown mouse command (0x%x) in acceptable kbd ", data);
565                     break;
566             }
567
568             break;
569         case SAMPLE:
570         case SET_RES:
571         default:
572             PrintDebug(" receiving mouse output in unhandled kbd (0x%x) ", kbd->mouse_state);
573             return -1;
574     }
575
576     return 0;
577 }
578
579
580
581 #if KEYBOARD_DEBUG_80H
582 static int keyboard_write_delay(struct guest_info *core, ushort_t port, void * src,  uint_t length, void * priv_data) {
583
584     if (length == 1) { 
585         PrintDebug("keyboard: write of 0x%x to 80h\n", *((uint8_t*)src));
586         return 1;
587     } else {
588         PrintDebug("keyboard: write of >1 byte to 80h\n", *((uint8_t*)src));
589         return length;
590     }
591 }
592
593 static int keyboard_read_delay(struct guest_info * core, ushort_t port, void * dest, uint_t length, void * priv_data) {
594
595     if (length == 1) { 
596         *(uint8_t *)dest = v3_inb(port);
597
598         PrintDebug("keyboard: read of 0x%x from 80h\n", *((uint8_t*)dest));
599
600         return 1;
601     } else {
602         PrintDebug("keyboard: read of >1 byte from 80h\n");
603
604         return length;
605     }
606 }
607 #endif
608     
609   
610
611
612
613 static int keyboard_write_command(struct guest_info * core, ushort_t port, void * src, uint_t length, void * priv_data) {
614     struct keyboard_internal * kbd = priv_data;
615     uint8_t cmd = *(uint8_t *)src;
616
617     // Should always be single byte write
618     if (length != 1) { 
619         PrintError("keyboard: write of >1 bytes (%d) to 64h\n", length);
620         return -1;
621     }
622
623
624     addr_t irq_state = v3_lock_irqsave(kbd->kb_lock);
625
626     if (kbd->state != NORMAL) { 
627         PrintDebug("keyboard: warning - receiving command on 64h but state != NORMAL\n");
628     }
629   
630     PrintDebug("keyboard: command 0x%x on 64h\n", cmd);
631
632     switch (cmd) { 
633         case 0x20:  // READ COMMAND BYTE (returned in 60h)
634             push_to_output_queue(kbd, kbd->cmd.val, COMMAND, KEYBOARD);
635             PrintDebug("keyboard: command byte 0x%x returned\n", kbd->cmd.val);
636             break;
637
638         case 0x60:  // WRITE COMMAND BYTE (read from 60h)
639             kbd->state = WRITING_CMD_BYTE; // we need to make sure we send the next 0x60 byte appropriately
640             PrintDebug("keyboard: prepare to write command byte\n");
641             break;
642
643             // case 0x90-9f - write to output port  (?)
644
645         case 0xa1: // Get version number
646             push_to_output_queue(kbd, 0x00, COMMAND, KEYBOARD);
647             PrintDebug("keyboard: version number 0x0 returned\n");
648             break;
649
650         case 0xa4:  // is password installed?  send result to 0x60
651             // we don't support passwords
652             push_to_output_queue(kbd, 0xf1, COMMAND, KEYBOARD);
653             PrintDebug("keyboard: password not installed\n");
654             break;
655
656         case 0xa5:  // new password will arrive on 0x60
657             kbd->state = TRANSMIT_PASSWD;
658             PrintDebug("keyboard: pepare to transmit password\n");
659             break;
660
661         case 0xa6:  // check passwd;
662             // since we do not support passwords, we will simply ignore this
663             // the implication is that any password check immediately succeeds 
664             // with a blank password
665             PrintDebug("keyboard: password check succeeded\n");
666             break;
667
668         case 0xa7:  // disable mouse
669             kbd->cmd.mouse_disable = 1;
670             PrintDebug("keyboard: mouse disabled\n");
671             break;
672
673         case 0xa8:  // enable mouse
674             kbd->cmd.mouse_disable = 0;
675             PrintDebug("keyboard: mouse enabled\n");
676             break;
677
678         case 0xa9:  // mouse interface test  (always succeeds)
679             push_to_output_queue(kbd, 0x00, COMMAND, KEYBOARD);
680             PrintDebug("keyboard: mouse interface test succeeded\n");
681             break;
682
683         case 0xaa:  // controller self test (always succeeds)
684             push_to_output_queue(kbd, 0x55, COMMAND, KEYBOARD);
685             PrintDebug("keyboard: controller self test succeeded\n");
686             break;
687
688         case 0xab:  // keyboard interface test (always succeeds)
689             push_to_output_queue(kbd, 0, COMMAND, KEYBOARD);
690             PrintDebug("keyboard: keyboard interface test succeeded\n");
691             break;
692
693         case 0xad:  // disable keyboard
694             kbd->cmd.disable = 1;
695             PrintDebug("keyboard: keyboard disabled\n");
696             break;
697
698         case 0xae:  // enable keyboard
699             kbd->cmd.disable = 0;
700             PrintDebug("keyboard: keyboard enabled\n");
701             break;
702
703         case 0xaf:  // get version
704             push_to_output_queue(kbd, 0x00, COMMAND, KEYBOARD);
705             PrintDebug("keyboard: version 0 returned \n");
706             break;
707
708         case 0xd0: // return microcontroller output on 60h
709             push_to_output_queue(kbd, kbd->output_byte, COMMAND, KEYBOARD);
710             PrintDebug("keyboard: output byte 0x%x returned\n", kbd->output_byte);
711             break;
712
713         case 0xd1: // request to write next byte on 60h to the microcontroller output port
714             kbd->state = WRITING_OUTPUT_PORT;
715             PrintDebug("keyboard: prepare to write output byte\n");
716             break;
717
718         case 0xd2:  //  write keyboard buffer (inject key)
719             kbd->state = INJECTING_KEY;
720             PrintDebug("keyboard: prepare to inject key\n");
721             break;
722
723         case 0xd3: //  write mouse buffer (inject mouse)
724             kbd->state = INJECTING_MOUSE;
725             PrintDebug("keyboard: prepare to inject mouse\n");
726             break;
727
728         case 0xd4: // write mouse device (command to mouse?)
729             kbd->state = IN_MOUSE;
730             PrintDebug("keyboard: prepare to inject mouse command\n");
731             break;
732
733         case 0xc0: //  read input port 
734             push_to_output_queue(kbd, kbd->input_byte, COMMAND, KEYBOARD);
735             PrintDebug("keyboard: input byte 0x%x returned\n", kbd->input_byte);
736             break;
737
738         case 0xc1:  //copy input port lsn to status msn
739             kbd->status.val &= 0x0f;
740             kbd->status.val |= (kbd->input_byte & 0xf) << 4;
741             PrintDebug("keyboard: copied input byte low 4 bits to status reg hi 4 bits\n");
742             break;
743
744         case 0xc2: // copy input port msn to status msn
745             kbd->status.val &= 0x0f;
746             kbd->status.val |= (kbd->input_byte & 0xf0);
747             PrintDebug("keyboard: copied input byte hi 4 bits to status reg hi 4 bits\n");
748             break;
749     
750         case 0xe0: // read test port
751             push_to_output_queue(kbd, kbd->output_byte >> 6, COMMAND, KEYBOARD);
752             PrintDebug("keyboard: read 0x%x from test port\n", kbd->output_byte >> 6);
753             break;
754
755    
756         case 0xf0:   // pulse output port
757         case 0xf1:   // this should pulse 0..3 of cmd_byte on output port 
758         case 0xf2:   // instead of what is currently in output_byte (I think)
759         case 0xf3:   // main effect is taht if bit zero is zero
760         case 0xf4:   // should cause reset
761         case 0xf5:   // I doubt anything more recent than a 286 running 
762         case 0xf6:   // OS2 with the penalty box will care
763         case 0xf7:
764         case 0xf8:
765         case 0xf9:
766         case 0xfa:
767         case 0xfb:
768         case 0xfc:
769         case 0xfd:
770         case 0xfe:
771         case 0xff:
772             PrintDebug("keyboard: ignoring pulse of 0x%x (low=pulsed) on output port\n", (cmd & 0xf));
773             break;
774    
775             // case ac  diagonstic - returns 16 bytes from keyboard microcontroler on 60h
776         default:
777             PrintDebug("keyboard: ignoring command (unimplemented)\n");
778             break;
779     }
780
781     v3_unlock_irqrestore(kbd->kb_lock, irq_state);
782
783     return length;
784 }
785
786 static int keyboard_read_status(struct guest_info * core, ushort_t port, void * dest, uint_t length, void * priv_data) {
787     struct keyboard_internal * kbd = priv_data;
788
789     if (length != 1) { 
790         PrintError("keyboard: >1 byte read for status (64h)\n");
791         return -1;
792     }
793
794     PrintDebug("keyboard: read status (64h): ");
795
796     addr_t irq_state = v3_lock_irqsave(kbd->kb_lock);
797
798     *(uint8_t *)dest = kbd->status.val;
799
800     v3_unlock_irqrestore(kbd->kb_lock, irq_state);
801     
802     PrintDebug("0x%x\n", *(uint8_t *)dest);
803     
804     return length;
805 }
806
807 static int keyboard_write_output(struct guest_info * core, ushort_t port, void * src, uint_t length, void * priv_data) {
808     struct keyboard_internal * kbd = priv_data;
809     int ret = length;
810
811     if (length != 1) { 
812         PrintError("keyboard: write of 60h with >1 byte\n");
813         return -1;
814     }
815
816     uint8_t data = *(uint8_t *)src;
817   
818     PrintDebug("keyboard: output 0x%x on 60h\n", data);
819
820     addr_t irq_state = v3_lock_irqsave(kbd->kb_lock);
821
822     switch (kbd->state) {
823         case WRITING_CMD_BYTE:
824             kbd->cmd.val = data;
825             kbd->state = NORMAL;
826             PrintDebug("keyboard: wrote new command byte 0x%x\n", kbd->cmd.val);
827             break;
828
829         case WRITING_OUTPUT_PORT:
830             kbd->output_byte = data;
831             kbd->state = NORMAL;
832             PrintDebug("keyboard: wrote new output byte 0x%x\n", kbd->output_byte);
833             break;
834
835         case INJECTING_KEY:
836             push_to_output_queue(kbd, data, COMMAND, KEYBOARD);  // probably should be a call to deliver_key_to_vmm()
837             kbd->state = NORMAL;
838             PrintDebug("keyboard: injected key 0x%x\n", data);
839             break;
840
841         case INJECTING_MOUSE:
842             push_to_output_queue(kbd, data, DATA, MOUSE);
843             //      PrintDebug("keyboard: ignoring injected mouse event 0x%x\n", data);
844             PrintDebug("keyboard: injected mouse event 0x%x\n", data);
845             kbd->state = NORMAL;
846             break;
847
848         case IN_MOUSE:
849             PrintDebug("keyboard: mouse action: ");
850             if (mouse_write_output(kbd, data)) { 
851                 kbd->state = NORMAL;
852             }
853             PrintDebug("\n");
854             break;
855
856         case TRANSMIT_PASSWD:
857             if (data) {
858                 //ignore passwd
859                 PrintDebug("keyboard: ignoring password character 0x%x\n",data);
860             } else {
861                 // end of password
862                 kbd->state = NORMAL;
863                 PrintDebug("keyboard: done with password\n");
864             }
865             break;
866
867         case SET_LEDS:
868             PrintDebug("Keyboard: LEDs being set...\n");
869             push_to_output_queue(kbd, 0xfa, COMMAND, KEYBOARD);
870             kbd->state = NORMAL;
871             break;
872
873         case SET_RATE:
874             PrintDebug("Keyboard: Rate being set...\n");
875             push_to_output_queue(kbd, 0xfa, COMMAND, KEYBOARD);
876             kbd->state = NORMAL;
877             break;
878
879         case GETSET_SCANCODES:
880             switch (data) {
881                 case 0:
882                     PrintDebug("Keyboard: scancode set being read\n");
883                     push_to_output_queue(kbd, 0x45 - 2 * kbd->scancode_set, COMMAND, KEYBOARD);
884                     break;
885                 case 1:
886                     PrintError("keyboard: unsupported scancode set %d selected\n", data);
887                     return -1;
888                 case 2:
889                     PrintDebug("Keyboard: scancode set being set to %d\n", data);
890                     kbd->scancode_set = data;
891                     push_to_output_queue(kbd, 0xfa, COMMAND, KEYBOARD);
892                     break;
893                 case 3:
894                     /* OpenBSD wants scancode set 3, but falls back to 2 if a
895                      * subsequent read reveals that the request was ignored
896                      */
897                     PrintError("keyboard: ignoring request for scancode set %d\n", data);
898                     break;
899                 default:
900                     PrintError("keyboard: unknown scancode set %d selected\n", data);
901                     ret = -1;
902                     break;
903   
904             }
905             kbd->state = NORMAL;
906             break;
907
908         case SET_DEFAULTS:
909             keyboard_reset_device(kbd);
910             kbd->state = NORMAL;
911             break;
912
913         default:
914         case NORMAL: {
915             // command is being sent to keyboard controller
916             switch (data) { 
917                 case 0xff: // reset
918                     push_to_output_queue(kbd, 0xfa, COMMAND, KEYBOARD); // ack
919                     push_to_output_queue(kbd, 0xaa, COMMAND, KEYBOARD);
920                     PrintDebug("keyboard: reset complete and acked\n");
921                     break;
922
923                 case 0xf5: // disable scanning
924                 case 0xf4: // enable scanning
925                     // ack
926                     push_to_output_queue(kbd, 0xfa, COMMAND, KEYBOARD);
927                     // should do something here... PAD
928                     PrintDebug("keyboard: %s scanning done and acked\n", (data == 0xf5) ? "disable" : "enable");
929                     break;
930
931                 case 0xf3:
932                     push_to_output_queue(kbd, 0xfa, COMMAND, KEYBOARD);
933                     kbd->state = SET_RATE;
934                     break;
935
936                 case 0xf2: // get keyboard ID
937                     push_to_output_queue(kbd, 0xfa, COMMAND, KEYBOARD);
938                     push_to_output_queue(kbd, 0xab, COMMAND, KEYBOARD);
939                     push_to_output_queue(kbd, 0x83, COMMAND, KEYBOARD);
940                     PrintDebug("Keyboard: Requesting Keyboard ID\n");
941                     break;
942
943                 case 0xed: // enable keyboard LEDs
944                     push_to_output_queue(kbd, 0xfa, COMMAND, KEYBOARD);
945                     kbd->state = SET_LEDS;
946                     break;
947
948                 case 0xee: // echo, used by FreeBSD to probe controller
949                     push_to_output_queue(kbd, 0xee, COMMAND, KEYBOARD);
950                     break;
951
952                 case 0xf0: // get/set scancode set
953                     push_to_output_queue(kbd, 0xfa, COMMAND, KEYBOARD);
954                     kbd->state = GETSET_SCANCODES;
955                     break;
956
957
958                 case 0xf6: // set defaults
959                     // ACK command
960                     // clear output buffer
961                     // reset to init state
962                     push_to_output_queue(kbd, 0xfa, COMMAND, KEYBOARD);
963                     kbd->state = SET_DEFAULTS;
964                     break;
965
966                 case 0xfe: // resend
967                 case 0xfd: // set key type make
968                 case 0xfc: // set key typ make/break
969                 case 0xfb: // set key type typematic
970                 case 0xfa: // set all typematic make/break/typematic
971                 case 0xf9: // set all make
972                 case 0xf8: // set all make/break
973                 case 0xf7: // set all typemaktic
974
975                     PrintError("keyboard: unhandled known command 0x%x on output buffer (60h)\n", data);
976                     ret = -1;
977                     break;
978
979                 default:
980                     PrintError("keyboard: unhandled unknown command 0x%x on output buffer (60h)\n", data);
981                     kbd->status.out_buf_full = 1;
982                     ret = -1;
983                     break;
984             }
985             break;
986         }
987     }
988   
989     v3_unlock_irqrestore(kbd->kb_lock, irq_state);
990
991     return ret;
992 }
993
994 static int keyboard_read_input(struct guest_info * core, ushort_t port, void * dest, uint_t length, void * priv_data) {
995     struct keyboard_internal * kbd = priv_data;
996
997     if (length != 1) {
998         PrintError("keyboard: unknown size read from input (60h)\n");
999         return -1;
1000     }
1001     
1002     addr_t irq_state = v3_lock_irqsave(kbd->kb_lock);
1003
1004     pull_from_output_queue(kbd, (uint8_t *)dest);
1005       
1006     v3_unlock_irqrestore(kbd->kb_lock, irq_state);
1007
1008     PrintDebug("keyboard: read from input (60h): 0x%x\n", *(uint8_t *)dest);
1009
1010     return length;
1011 }
1012
1013
1014
1015
1016
1017
1018 static int keyboard_free(struct keyboard_internal * kbd) {
1019     
1020
1021     // unhook host events
1022
1023     V3_Free(kbd);
1024     return 0;
1025 }
1026
1027
1028
1029
1030 static int keyboard_reset_device(struct keyboard_internal * kbd) {
1031   
1032
1033     kbd->mouse_queue.start = 0;
1034     kbd->mouse_queue.end = 0;
1035     kbd->mouse_queue.count = 0;
1036
1037     kbd->kbd_queue.start = 0;
1038     kbd->kbd_queue.end = 0;
1039     kbd->kbd_queue.count = 0;
1040
1041     kbd->mouse_enabled = 0;
1042     kbd->scancode_set = 2;
1043
1044     kbd->state = NORMAL;
1045     kbd->mouse_state = STREAM;
1046
1047     // PS2, keyboard+mouse enabled, generic translation    
1048     kbd->cmd.val = 0;
1049
1050     kbd->cmd.irq_en = 1;
1051     kbd->cmd.mouse_irq_en = 1;
1052     kbd->cmd.self_test_ok = 1;
1053     /** **/
1054
1055
1056     // buffers empty, no errors
1057     kbd->status.val = 0; 
1058
1059     kbd->status.self_test_ok = 1; // self-tests passed
1060     kbd->status.enabled = 1;// keyboard ready
1061     /** **/
1062
1063     
1064     kbd->output_byte = 0;  //  ?
1065
1066     kbd->input_byte = INPUT_RAM;  // we have some
1067     // also display=color, jumper 0, keyboard enabled 
1068
1069     PrintDebug("keyboard: reset device\n");
1070  
1071     return 0;
1072
1073 }
1074
1075 #ifdef V3_CONFIG_CHECKPOINT
1076 static int keyboard_save(struct v3_chkpt_ctx * ctx, void * private_data) {
1077     struct keyboard_internal * kbd = (struct keyboard_internal *)private_data;
1078
1079     v3_chkpt_save_8(ctx, "CMD_REG", &(kbd->cmd.val));
1080     v3_chkpt_save_8(ctx, "STATUS_REG", &(kbd->status.val));
1081     v3_chkpt_save_8(ctx, "STATE", &(kbd->state));
1082     v3_chkpt_save_8(ctx, "MOUSE_STATE", &(kbd->mouse_state));
1083     v3_chkpt_save_8(ctx, "OUTPUT", &(kbd->output_byte));
1084     v3_chkpt_save_8(ctx, "INPUT", &(kbd->input_byte));
1085     v3_chkpt_save_8(ctx, "SCANCODE_SET", &(kbd->scancode_set));
1086     v3_chkpt_save_8(ctx, "MOUSE_ENABLED", &(kbd->mouse_enabled));
1087
1088
1089     return 0;
1090 }
1091
1092
1093 static int keyboard_load(struct v3_chkpt_ctx * ctx, void * private_data) {
1094     struct keyboard_internal * kbd = (struct keyboard_internal *)private_data;
1095     keyboard_reset_device(kbd);
1096
1097     v3_chkpt_load_8(ctx, "CMD_REG", &(kbd->cmd.val));
1098     v3_chkpt_load_8(ctx, "STATUS_REG", &(kbd->status.val));
1099     v3_chkpt_load_8(ctx, "STATE", &(kbd->state));
1100     v3_chkpt_load_8(ctx, "MOUSE_STATE", &(kbd->mouse_state));
1101     v3_chkpt_load_8(ctx, "OUTPUT", &(kbd->output_byte));
1102     v3_chkpt_load_8(ctx, "INPUT", &(kbd->input_byte));
1103     v3_chkpt_load_8(ctx, "SCANCODE_SET", &(kbd->scancode_set));
1104     v3_chkpt_load_8(ctx, "MOUSE_ENABLED", &(kbd->mouse_enabled));
1105
1106
1107     return 0;
1108 }
1109
1110 #endif
1111
1112
1113 static struct v3_device_ops dev_ops = { 
1114     .free = (int (*)(void *))keyboard_free,
1115 #ifdef V3_CONFIG_CHECKPOINT
1116     .save = keyboard_save,
1117     .load = keyboard_load
1118 #endif
1119 };
1120
1121
1122
1123
1124 static int keyboard_init(struct v3_vm_info * vm, v3_cfg_tree_t * cfg) {
1125     struct keyboard_internal * kbd = NULL;
1126     char * dev_id = v3_cfg_val(cfg, "ID");
1127     int ret = 0;
1128
1129     PrintDebug("keyboard: init_device\n");
1130
1131     kbd = (struct keyboard_internal *)V3_Malloc(sizeof(struct keyboard_internal));
1132
1133     memset(kbd, 0, sizeof(struct keyboard_internal));
1134
1135     kbd->vm = vm;
1136
1137     struct vm_device * dev = v3_add_device(vm, dev_id, &dev_ops, kbd);
1138
1139     if (dev == NULL) {
1140         PrintError("Could not attach device %s\n", dev_id);
1141         V3_Free(kbd);
1142         return -1;
1143     }
1144
1145     keyboard_reset_device(kbd);
1146
1147
1148     v3_lock_init(&(kbd->kb_lock));
1149
1150
1151     // hook ports
1152     ret |= v3_dev_hook_io(dev, KEYBOARD_64H, &keyboard_read_status, &keyboard_write_command);
1153     ret |= v3_dev_hook_io(dev, KEYBOARD_60H, &keyboard_read_input, &keyboard_write_output);
1154
1155     if (ret != 0) {
1156         PrintError("Error hooking keyboard IO ports\n");
1157         v3_remove_device(dev);
1158         return -1;
1159     }
1160
1161     v3_hook_host_event(vm, HOST_KEYBOARD_EVT, V3_HOST_EVENT_HANDLER(key_event_handler), kbd);
1162     v3_hook_host_event(vm, HOST_MOUSE_EVT, V3_HOST_EVENT_HANDLER(mouse_event_handler), kbd);
1163
1164
1165 #if KEYBOARD_DEBUG_80H
1166     v3_dev_hook_io(dev, KEYBOARD_DELAY_80H, &keyboard_read_delay, &keyboard_write_delay);
1167 #endif
1168
1169   
1170     //
1171     // We do not hook the IRQ here.  Instead, the underlying device driver
1172     // is responsible to call us back
1173     // 
1174
1175     return 0;
1176 }
1177
1178
1179 device_register("KEYBOARD", keyboard_init)