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.


added device checkpoint hooks
[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     } state;
192
193
194     enum {
195         // Normal mouse state
196         STREAM, 
197         // this is used for setting sample rate
198         SAMPLE,
199         // set resolution
200         SET_RES,
201     } mouse_state;
202
203
204
205     struct cmd_reg cmd;
206     struct status_reg status;
207
208     uint8_t output_byte;      //  output port of onboard uC (e.g. A20)
209     uint8_t input_byte;       //  input port of onboard uC
210
211     // Data for system
212     uint8_t wrap;     
213
214     int mouse_enabled;
215     int scancode_set;
216
217     struct queue kbd_queue;
218     struct queue mouse_queue;
219
220     struct v3_vm_info * vm;
221
222     v3_lock_t kb_lock;
223 };
224
225
226 static int update_kb_irq(struct keyboard_internal * state) {
227     int irq_num = 0;
228
229
230     state->status.out_buf_full = 0;
231     state->status.mouse_buf_full = 0;
232
233
234     // If there is pending Keyboard data then it overrides mouse data
235     if (state->kbd_queue.count > 0) {
236         irq_num = KEYBOARD_IRQ;
237     } else if (state->mouse_queue.count > 0) {
238         irq_num = MOUSE_IRQ;
239         state->status.mouse_buf_full = 1;
240     } 
241     
242     PrintDebug("keyboard: interrupt 0x%d\n", irq_num);
243     
244     if (irq_num) {
245         // Global output buffer flag (for both Keyboard and mouse)
246         state->status.out_buf_full = 1;
247         
248         if (state->cmd.irq_en == 1) { 
249             v3_raise_irq(state->vm, irq_num);
250         }
251     }
252
253     return 0;
254 }
255
256
257
258 /* Only one byte is read per irq 
259  * So if the queue is still full after a data read, we re-raise the irq
260  * If we keep reading an empty queue we return the last queue entry
261  */
262
263 static int push_to_output_queue(struct keyboard_internal * state, uint8_t value, uint8_t cmd, uint8_t mouse) {
264     struct queue * q = NULL;
265
266
267     if (mouse) {
268         q = &(state->mouse_queue);
269     } else {
270         q = &(state->kbd_queue);
271     }
272
273     if (q->count >= QUEUE_SIZE) {
274         return 0;
275     }
276
277     if (cmd) {
278         state->status.cmd = 1;
279     } else {
280         state->status.cmd = 0;
281     }
282
283     q->queue[q->end] = value;
284
285     if (q->end >= (QUEUE_SIZE - 1)) {
286         q->end = 0;
287     } else {
288         q->end++;
289     }
290
291     q->count++;
292
293
294     update_kb_irq(state);
295
296     return 0;
297 }
298
299
300
301 static int pull_from_output_queue(struct keyboard_internal * state, uint8_t * value) {
302     struct queue * q = NULL;
303
304     if (state->kbd_queue.count > 0) {
305         q = &(state->kbd_queue);
306         PrintDebug("Reading from Keyboard Queue\n");
307     } else if (state->mouse_queue.count > 0) {
308         q = &(state->mouse_queue);
309         PrintDebug("Reading from Mouse Queue\n");
310     } else {
311         uint8_t idx = state->kbd_queue.start - 1;
312         PrintDebug("No Data in any queue\n");
313         *value = state->kbd_queue.queue[idx];
314         return 0;
315     }
316
317     *value = q->queue[q->start];
318
319     if (q->start >= (QUEUE_SIZE - 1)) {
320         q->start = 0;
321     } else {
322         q->start++;
323     }
324
325     q->count--;
326
327
328     PrintDebug("Read from Queue: %x\n", *value);
329     PrintDebug("QStart=%d, QEnd=%d\n", q->start, q->end);
330
331     update_kb_irq(state);
332
333     return 0;
334 }
335
336
337 #include <palacios/vmm_telemetry.h>
338 #ifdef V3_CONFIG_SYMMOD
339 #include <palacios/vmm_symmod.h>
340 #endif
341
342 static int key_event_handler(struct v3_vm_info * vm, 
343                              struct v3_keyboard_event * evt, 
344                              void * private_data) {
345     struct keyboard_internal * state = (struct keyboard_internal *)private_data;
346
347     PrintDebug("keyboard: injected status 0x%x, and scancode 0x%x\n", evt->status, evt->scan_code);
348
349     if (evt->scan_code == 0x44) { // F10 debug dump
350         int i = 0;
351         for (i = 0; i < vm->num_cores; i++) {
352             v3_print_guest_state(&(vm->cores[i]));
353         }
354         //      PrintGuestPageTables(info, info->shdw_pg_state.guest_cr3);
355     } 
356 #ifdef V3_CONFIG_SYMCALL
357     else if (evt->scan_code == 0x43) { // F9 Sym test
358         struct guest_info * core = &(vm->cores[0]);
359         PrintDebug("Testing sym call\n");
360         sym_arg_t a0 = 0x1111;
361         sym_arg_t a1 = 0x2222;
362         sym_arg_t a2 = 0x3333;
363         sym_arg_t a3 = 0x4444;
364         sym_arg_t a4 = 0x5555;
365         uint64_t call_start = 0;
366         uint64_t call_end = 0;
367         
368         V3_Print("Exits before symcall: %d\n", (uint32_t)core->num_exits);
369
370         rdtscll(call_start);
371         v3_sym_call5(core, SYMCALL_TEST, &a0, &a1, &a2, &a3, &a4);
372         rdtscll(call_end);
373         
374         V3_Print("Symcall latency = %d cycles (%d exits)\n", (uint32_t)(call_end - call_start), (uint32_t)core->num_exits);
375
376         V3_Print("Symcall  Test Returned arg0=%x, arg1=%x, arg2=%x, arg3=%x, arg4=%x\n",
377                  (uint32_t)a0, (uint32_t)a1, (uint32_t)a2, (uint32_t)a3, (uint32_t)a4);
378
379     } 
380 #endif
381     else if (evt->scan_code == 0x42) { // F8 debug toggle
382         extern int v3_dbg_enable;
383         
384         PrintDebug("Toggling Debugging\n");     
385         v3_dbg_enable ^= 1;
386
387     } 
388 #ifdef V3_CONFIG_TELEMETRY
389
390     else if (evt->scan_code == 0x41) { // F7 telemetry dump
391         v3_print_telemetry(vm);
392     } 
393 #endif
394 #ifdef V3_CONFIG_SYMMOD
395     else if (evt->scan_code == 0x40) { // F6 Test symmod load
396         v3_load_sym_capsule(vm, "lnx_test");
397     }
398 #endif
399
400
401     addr_t irq_state = v3_lock_irqsave(state->kb_lock);
402
403     if ( (state->status.enabled == 1)      // onboard is enabled
404          && (state->cmd.disable == 0) )  {   // keyboard is enabled
405     
406         push_to_output_queue(state, evt->scan_code, DATA, KEYBOARD);
407     }
408
409     v3_unlock_irqrestore(state->kb_lock, irq_state);
410   
411     return 0;
412 }
413
414
415 static int mouse_event_handler(struct v3_vm_info * vm, 
416                                struct v3_mouse_event * evt, 
417                                void * private_data) {
418     struct keyboard_internal * kbd = (struct keyboard_internal *)private_data;
419     int ret = 0;
420
421     PrintDebug("keyboard: injected mouse packet 0x %x %x %x\n",
422                evt->data[0], evt->data[1], evt->data[2]);
423   
424     addr_t irq_state = v3_lock_irqsave(kbd->kb_lock);
425
426     switch (kbd->mouse_state) { 
427         case STREAM:
428
429             if (kbd->cmd.mouse_disable == 0) {
430                 push_to_output_queue(kbd, evt->data[0], DATA, MOUSE);
431                 push_to_output_queue(kbd, evt->data[1], DATA, MOUSE);
432                 push_to_output_queue(kbd, evt->data[2], DATA, MOUSE);
433             }
434             break;
435         default:
436             PrintError("Invalid mouse state\n");
437             ret = -1;
438             break;
439     }
440
441
442     v3_unlock_irqrestore(kbd->kb_lock, irq_state);
443
444     return ret;
445 }
446
447
448
449
450
451
452
453
454
455
456 static int mouse_write_output(struct keyboard_internal * kbd, uint8_t data) {
457     switch (kbd->mouse_state) { 
458         case NORMAL:
459             switch (data) {
460
461                 case 0xff: //reset
462                     if (kbd->mouse_enabled == 0) {
463                         push_to_output_queue(kbd, 0xfe, DATA, MOUSE) ;   // no mouse!
464                     } else {
465                         push_to_output_queue(kbd, MOUSE_ACK, DATA, MOUSE) ; 
466                         push_to_output_queue(kbd, 0xaa, DATA, MOUSE) ; 
467                         push_to_output_queue(kbd, 0x00, DATA, MOUSE) ; 
468                     }
469                     break;
470
471 /*              case 0xfe: //resend */
472 /*                  PushToOutputQueue(kbd, 0xfa, OVERWRITE, DATA, MOUSE) ;  */
473 /*                  PrintDebug(" mouse resend begins "); */
474 /*                  kbd->mouse_done_after_ack = 0; */
475 /*                  kbd->mouse_needs_ack = 0; */
476 /*                  kbd->mouse_state = STREAM1; */
477 /*                  return 0;  // not done */
478 /*                  break; */
479       
480                 case 0xf6: // set defaults
481                     push_to_output_queue(kbd, MOUSE_ACK, DATA, MOUSE) ; 
482                     PrintDebug(" mouse set defaults ");
483
484                     break;
485       
486                 case 0xf5: // disable data reporting 
487                     push_to_output_queue(kbd, MOUSE_ACK, DATA, MOUSE) ; 
488                     PrintDebug(" mouse disable data reporting ");
489                     break;
490       
491                 case 0xf4: // enable data reporting 
492                     push_to_output_queue(kbd, MOUSE_ACK, DATA, MOUSE) ; 
493                     PrintDebug(" mouse enable data reporting ");
494                     break;
495       
496                 case 0xf3: // set sample rate
497                     push_to_output_queue(kbd, MOUSE_ACK, DATA, MOUSE) ; 
498                     kbd->mouse_state = SAMPLE;
499                     PrintDebug(" mouse set sample rate begins ");
500                     break;
501       
502                 case 0xf2: // get device id
503                     push_to_output_queue(kbd, MOUSE_ACK, DATA, MOUSE) ; 
504                     push_to_output_queue(kbd, 0x0,  DATA, MOUSE); 
505                     PrintDebug(" mouse get device id begins ");
506                     break;
507       
508                 case 0xf0: // set remote mode
509                     push_to_output_queue(kbd, MOUSE_ACK, DATA, MOUSE) ; 
510                     PrintDebug(" mouse set remote mode  ");
511                     break;
512
513                 case 0xee: // set wrap mode
514                     push_to_output_queue(kbd, MOUSE_ACK, DATA, MOUSE) ; 
515                     PrintError(" mouse set wrap mode (ignored)  ");
516                     break;
517
518                 case 0xec: // reset wrap mode
519                     push_to_output_queue(kbd, MOUSE_ACK, DATA, MOUSE) ; 
520                     PrintError(" mouse reset wrap mode (ignored)  ");
521                     break;
522
523                 case 0xeb: // read data
524                     push_to_output_queue(kbd, MOUSE_ACK, DATA, MOUSE) ; 
525                     PrintError(" mouse switch to wrap mode (ignored)  ");
526                     break;
527       
528                 case 0xea: // set stream mode
529                     push_to_output_queue(kbd, MOUSE_ACK, DATA, MOUSE) ; 
530                     PrintDebug(" mouse set stream mode  ");
531                     break;
532
533                 case 0xe9: // status request
534                     push_to_output_queue(kbd, MOUSE_ACK, DATA, MOUSE) ; 
535                     push_to_output_queue(kbd, 0x00, DATA, MOUSE); 
536                     push_to_output_queue(kbd, 0x00, DATA, MOUSE);
537                     push_to_output_queue(kbd, 0x00, DATA, MOUSE); 
538                     PrintDebug(" mouse status request begins  ");
539                     break;
540
541                 case 0xe8: // set resolution
542                     push_to_output_queue(kbd, MOUSE_ACK,  DATA, MOUSE) ; 
543                     PrintDebug(" mouse set resolution begins  ");
544                     kbd->mouse_state = SET_RES;
545                     break;
546
547                 case 0xe7: // set scaling 2:1
548                     push_to_output_queue(kbd, MOUSE_ACK, DATA, MOUSE) ; 
549                     PrintDebug(" mouse set scaling 2:1 ");
550                     break;
551
552                 case 0xe6: // set scaling 1:1
553                     push_to_output_queue(kbd, MOUSE_ACK, DATA, MOUSE) ; 
554                     PrintDebug(" mouse set scaling 1:1 ");
555                     break;
556       
557                 default:
558                     PrintDebug(" receiving unknown mouse command (0x%x) in acceptable kbd ", data);
559                     break;
560             }
561
562             break;
563         case SAMPLE:
564         case SET_RES:
565         default:
566             PrintDebug(" receiving mouse output in unhandled kbd (0x%x) ", kbd->mouse_state);
567             return -1;
568     }
569
570     return 0;
571 }
572
573
574
575 #if KEYBOARD_DEBUG_80H
576 static int keyboard_write_delay(ushort_t port, void * src,  uint_t length, void * priv_data) {
577
578     if (length == 1) { 
579         PrintDebug("keyboard: write of 0x%x to 80h\n", *((uint8_t*)src));
580         return 1;
581     } else {
582         PrintDebug("keyboard: write of >1 byte to 80h\n", *((uint8_t*)src));
583         return length;
584     }
585 }
586
587 static int keyboard_read_delay(struct guest_info * core, ushort_t port, void * dest, uint_t length, void * priv_data) {
588
589     if (length == 1) { 
590         *(uint8_t *)dest = v3_inb(port);
591
592         PrintDebug("keyboard: read of 0x%x from 80h\n", *((uint8_t*)dest));
593
594         return 1;
595     } else {
596         PrintDebug("keyboard: read of >1 byte from 80h\n");
597
598         return length;
599     }
600 }
601 #endif
602     
603   
604
605
606
607 static int keyboard_write_command(struct guest_info * core, ushort_t port, void * src, uint_t length, void * priv_data) {
608     struct keyboard_internal * kbd = priv_data;
609     uint8_t cmd = *(uint8_t *)src;
610
611     // Should always be single byte write
612     if (length != 1) { 
613         PrintError("keyboard: write of >1 bytes (%d) to 64h\n", length);
614         return -1;
615     }
616
617
618     addr_t irq_state = v3_lock_irqsave(kbd->kb_lock);
619
620     if (kbd->state != NORMAL) { 
621         PrintDebug("keyboard: warning - receiving command on 64h but state != NORMAL\n");
622     }
623   
624     PrintDebug("keyboard: command 0x%x on 64h\n", cmd);
625
626     switch (cmd) { 
627         case 0x20:  // READ COMMAND BYTE (returned in 60h)
628             push_to_output_queue(kbd, kbd->cmd.val, COMMAND, KEYBOARD);
629             PrintDebug("keyboard: command byte 0x%x returned\n", kbd->cmd.val);
630             break;
631
632         case 0x60:  // WRITE COMMAND BYTE (read from 60h)
633             kbd->state = WRITING_CMD_BYTE; // we need to make sure we send the next 0x60 byte appropriately
634             PrintDebug("keyboard: prepare to write command byte\n");
635             break;
636
637             // case 0x90-9f - write to output port  (?)
638
639         case 0xa1: // Get version number
640             push_to_output_queue(kbd, 0x00, COMMAND, KEYBOARD);
641             PrintDebug("keyboard: version number 0x0 returned\n");
642             break;
643
644         case 0xa4:  // is password installed?  send result to 0x60
645             // we don't support passwords
646             push_to_output_queue(kbd, 0xf1, COMMAND, KEYBOARD);
647             PrintDebug("keyboard: password not installed\n");
648             break;
649
650         case 0xa5:  // new password will arrive on 0x60
651             kbd->state = TRANSMIT_PASSWD;
652             PrintDebug("keyboard: pepare to transmit password\n");
653             break;
654
655         case 0xa6:  // check passwd;
656             // since we do not support passwords, we will simply ignore this
657             // the implication is that any password check immediately succeeds 
658             // with a blank password
659             PrintDebug("keyboard: password check succeeded\n");
660             break;
661
662         case 0xa7:  // disable mouse
663             kbd->cmd.mouse_disable = 1;
664             PrintDebug("keyboard: mouse disabled\n");
665             break;
666
667         case 0xa8:  // enable mouse
668             kbd->cmd.mouse_disable = 0;
669             PrintDebug("keyboard: mouse enabled\n");
670             break;
671
672         case 0xa9:  // mouse interface test  (always succeeds)
673             push_to_output_queue(kbd, 0x00, COMMAND, KEYBOARD);
674             PrintDebug("keyboard: mouse interface test succeeded\n");
675             break;
676
677         case 0xaa:  // controller self test (always succeeds)
678             push_to_output_queue(kbd, 0x55, COMMAND, KEYBOARD);
679             PrintDebug("keyboard: controller self test succeeded\n");
680             break;
681
682         case 0xab:  // keyboard interface test (always succeeds)
683             push_to_output_queue(kbd, 0, COMMAND, KEYBOARD);
684             PrintDebug("keyboard: keyboard interface test succeeded\n");
685             break;
686
687         case 0xad:  // disable keyboard
688             kbd->cmd.disable = 1;
689             PrintDebug("keyboard: keyboard disabled\n");
690             break;
691
692         case 0xae:  // enable keyboard
693             kbd->cmd.disable = 0;
694             PrintDebug("keyboard: keyboard enabled\n");
695             break;
696
697         case 0xaf:  // get version
698             push_to_output_queue(kbd, 0x00, COMMAND, KEYBOARD);
699             PrintDebug("keyboard: version 0 returned \n");
700             break;
701
702         case 0xd0: // return microcontroller output on 60h
703             push_to_output_queue(kbd, kbd->output_byte, COMMAND, KEYBOARD);
704             PrintDebug("keyboard: output byte 0x%x returned\n", kbd->output_byte);
705             break;
706
707         case 0xd1: // request to write next byte on 60h to the microcontroller output port
708             kbd->state = WRITING_OUTPUT_PORT;
709             PrintDebug("keyboard: prepare to write output byte\n");
710             break;
711
712         case 0xd2:  //  write keyboard buffer (inject key)
713             kbd->state = INJECTING_KEY;
714             PrintDebug("keyboard: prepare to inject key\n");
715             break;
716
717         case 0xd3: //  write mouse buffer (inject mouse)
718             kbd->state = INJECTING_MOUSE;
719             PrintDebug("keyboard: prepare to inject mouse\n");
720             break;
721
722         case 0xd4: // write mouse device (command to mouse?)
723             kbd->state = IN_MOUSE;
724             PrintDebug("keyboard: prepare to inject mouse command\n");
725             break;
726
727         case 0xc0: //  read input port 
728             push_to_output_queue(kbd, kbd->input_byte, COMMAND, KEYBOARD);
729             PrintDebug("keyboard: input byte 0x%x returned\n", kbd->input_byte);
730             break;
731
732         case 0xc1:  //copy input port lsn to status msn
733             kbd->status.val &= 0x0f;
734             kbd->status.val |= (kbd->input_byte & 0xf) << 4;
735             PrintDebug("keyboard: copied input byte low 4 bits to status reg hi 4 bits\n");
736             break;
737
738         case 0xc2: // copy input port msn to status msn
739             kbd->status.val &= 0x0f;
740             kbd->status.val |= (kbd->input_byte & 0xf0);
741             PrintDebug("keyboard: copied input byte hi 4 bits to status reg hi 4 bits\n");
742             break;
743     
744         case 0xe0: // read test port
745             push_to_output_queue(kbd, kbd->output_byte >> 6, COMMAND, KEYBOARD);
746             PrintDebug("keyboard: read 0x%x from test port\n", kbd->output_byte >> 6);
747             break;
748
749    
750         case 0xf0:   // pulse output port
751         case 0xf1:   // this should pulse 0..3 of cmd_byte on output port 
752         case 0xf2:   // instead of what is currently in output_byte (I think)
753         case 0xf3:   // main effect is taht if bit zero is zero
754         case 0xf4:   // should cause reset
755         case 0xf5:   // I doubt anything more recent than a 286 running 
756         case 0xf6:   // OS2 with the penalty box will care
757         case 0xf7:
758         case 0xf8:
759         case 0xf9:
760         case 0xfa:
761         case 0xfb:
762         case 0xfc:
763         case 0xfd:
764         case 0xfe:
765         case 0xff:
766             PrintDebug("keyboard: ignoring pulse of 0x%x (low=pulsed) on output port\n", (cmd & 0xf));
767             break;
768    
769             // case ac  diagonstic - returns 16 bytes from keyboard microcontroler on 60h
770         default:
771             PrintDebug("keyboard: ignoring command (unimplemented)\n");
772             break;
773     }
774
775     v3_unlock_irqrestore(kbd->kb_lock, irq_state);
776
777     return length;
778 }
779
780 static int keyboard_read_status(struct guest_info * core, ushort_t port, void * dest, uint_t length, void * priv_data) {
781     struct keyboard_internal * kbd = priv_data;
782
783     if (length != 1) { 
784         PrintError("keyboard: >1 byte read for status (64h)\n");
785         return -1;
786     }
787
788     PrintDebug("keyboard: read status (64h): ");
789
790     addr_t irq_state = v3_lock_irqsave(kbd->kb_lock);
791
792     *(uint8_t *)dest = kbd->status.val;
793
794     v3_unlock_irqrestore(kbd->kb_lock, irq_state);
795     
796     PrintDebug("0x%x\n", *(uint8_t *)dest);
797     
798     return length;
799 }
800
801 static int keyboard_write_output(struct guest_info * core, ushort_t port, void * src, uint_t length, void * priv_data) {
802     struct keyboard_internal * kbd = priv_data;
803     int ret = length;
804
805     if (length != 1) { 
806         PrintError("keyboard: write of 60h with >1 byte\n");
807         return -1;
808     }
809
810     uint8_t data = *(uint8_t *)src;
811   
812     PrintDebug("keyboard: output 0x%x on 60h\n", data);
813
814     addr_t irq_state = v3_lock_irqsave(kbd->kb_lock);
815
816     switch (kbd->state) {
817         case WRITING_CMD_BYTE:
818             kbd->cmd.val = data;
819             kbd->state = NORMAL;
820             PrintDebug("keyboard: wrote new command byte 0x%x\n", kbd->cmd.val);
821             break;
822
823         case WRITING_OUTPUT_PORT:
824             kbd->output_byte = data;
825             kbd->state = NORMAL;
826             PrintDebug("keyboard: wrote new output byte 0x%x\n", kbd->output_byte);
827             break;
828
829         case INJECTING_KEY:
830             push_to_output_queue(kbd, data, COMMAND, KEYBOARD);  // probably should be a call to deliver_key_to_vmm()
831             kbd->state = NORMAL;
832             PrintDebug("keyboard: injected key 0x%x\n", data);
833             break;
834
835         case INJECTING_MOUSE:
836             push_to_output_queue(kbd, data, DATA, MOUSE);
837             //      PrintDebug("keyboard: ignoring injected mouse event 0x%x\n", data);
838             PrintDebug("keyboard: injected mouse event 0x%x\n", data);
839             kbd->state = NORMAL;
840             break;
841
842         case IN_MOUSE:
843             PrintDebug("keyboard: mouse action: ");
844             if (mouse_write_output(kbd, data)) { 
845                 kbd->state = NORMAL;
846             }
847             PrintDebug("\n");
848             break;
849
850         case TRANSMIT_PASSWD:
851             if (data) {
852                 //ignore passwd
853                 PrintDebug("keyboard: ignoring password character 0x%x\n",data);
854             } else {
855                 // end of password
856                 kbd->state = NORMAL;
857                 PrintDebug("keyboard: done with password\n");
858             }
859             break;
860
861         case SET_LEDS:
862             PrintDebug("Keyboard: LEDs being set...\n");
863             push_to_output_queue(kbd, 0xfa, COMMAND, KEYBOARD);
864             kbd->state = NORMAL;
865             break;
866
867         case SET_RATE:
868             PrintDebug("Keyboard: Rate being set...\n");
869             push_to_output_queue(kbd, 0xfa, COMMAND, KEYBOARD);
870             kbd->state = NORMAL;
871             break;
872
873         case GETSET_SCANCODES:
874             switch (data) {
875                 case 0:
876                     PrintDebug("Keyboard: scancode set being read\n");
877                     push_to_output_queue(kbd, 0x45 - 2 * kbd->scancode_set, COMMAND, KEYBOARD);
878                     break;
879                 case 1:
880                     PrintError("keyboard: unsupported scancode set %d selected\n", data);
881                     return -1;
882                 case 2:
883                     PrintDebug("Keyboard: scancode set being set to %d\n", data);
884                     kbd->scancode_set = data;
885                     push_to_output_queue(kbd, 0xfa, COMMAND, KEYBOARD);
886                     break;
887                 case 3:
888                     /* OpenBSD wants scancode set 3, but falls back to 2 if a
889                      * subsequent read reveals that the request was ignored
890                      */
891                     PrintError("keyboard: ignoring request for scancode set %d\n", data);
892                     break;
893                 default:
894                     PrintError("keyboard: unknown scancode set %d selected\n", data);
895                     return -1;
896   
897             }
898             kbd->state = NORMAL;
899             break;
900
901         default:
902         case NORMAL: {
903             // command is being sent to keyboard controller
904             switch (data) { 
905                 case 0xff: // reset
906                     push_to_output_queue(kbd, 0xfa, COMMAND, KEYBOARD); // ack
907                     push_to_output_queue(kbd, 0xaa, COMMAND, KEYBOARD);
908                     PrintDebug("keyboard: reset complete and acked\n");
909                     break;
910
911                 case 0xf5: // disable scanning
912                 case 0xf4: // enable scanning
913                     // ack
914                     push_to_output_queue(kbd, 0xfa, COMMAND, KEYBOARD);
915                     // should do something here... PAD
916                     PrintDebug("keyboard: %s scanning done and acked\n", (data == 0xf5) ? "disable" : "enable");
917                     break;
918
919                 case 0xf3:
920                     push_to_output_queue(kbd, 0xfa, COMMAND, KEYBOARD);
921                     kbd->state = SET_RATE;
922                     break;
923
924                 case 0xf2: // get keyboard ID
925                     push_to_output_queue(kbd, 0xfa, COMMAND, KEYBOARD);
926                     push_to_output_queue(kbd, 0xab, COMMAND, KEYBOARD);
927                     push_to_output_queue(kbd, 0x83, COMMAND, KEYBOARD);
928                     PrintDebug("Keyboard: Requesting Keyboard ID\n");
929                     break;
930
931                 case 0xed: // enable keyboard LEDs
932                     push_to_output_queue(kbd, 0xfa, COMMAND, KEYBOARD);
933                     kbd->state = SET_LEDS;
934                     break;
935
936                 case 0xee: // echo, used by FreeBSD to probe controller
937                     push_to_output_queue(kbd, 0xee, COMMAND, KEYBOARD);
938                     break;
939
940                 case 0xf0: // get/set scancode set
941                     push_to_output_queue(kbd, 0xfa, COMMAND, KEYBOARD);
942                     kbd->state = GETSET_SCANCODES;
943                     break;
944
945                 case 0xfe: // resend
946                 case 0xfd: // set key type make
947                 case 0xfc: // set key typ make/break
948                 case 0xfb: // set key type typematic
949                 case 0xfa: // set all typematic make/break/typematic
950                 case 0xf9: // set all make
951                 case 0xf8: // set all make/break
952                 case 0xf7: // set all typemaktic
953                 case 0xf6: // set defaults
954                     PrintError("keyboard: unhandled known command 0x%x on output buffer (60h)\n", data);
955                     ret = -1;
956                     break;
957
958                 default:
959                     PrintError("keyboard: unhandled unknown command 0x%x on output buffer (60h)\n", data);
960                     kbd->status.out_buf_full = 1;
961                     ret = -1;
962                     break;
963             }
964             break;
965         }
966     }
967   
968     v3_unlock_irqrestore(kbd->kb_lock, irq_state);
969
970     return ret;
971 }
972
973 static int keyboard_read_input(struct guest_info * core, ushort_t port, void * dest, uint_t length, void * priv_data) {
974     struct keyboard_internal * kbd = priv_data;
975
976     if (length != 1) {
977         PrintError("keyboard: unknown size read from input (60h)\n");
978         return -1;
979     }
980     
981     addr_t irq_state = v3_lock_irqsave(kbd->kb_lock);
982
983     pull_from_output_queue(kbd, (uint8_t *)dest);
984       
985     v3_unlock_irqrestore(kbd->kb_lock, irq_state);
986
987     PrintDebug("keyboard: read from input (60h): 0x%x\n", *(uint8_t *)dest);
988
989     return length;
990 }
991
992
993
994
995
996
997 static int keyboard_free(struct keyboard_internal * kbd) {
998     
999
1000     // unhook host events
1001
1002     V3_Free(kbd);
1003     return 0;
1004 }
1005
1006
1007
1008
1009 static int keyboard_reset_device(struct keyboard_internal * kbd) {
1010   
1011
1012     kbd->mouse_queue.start = 0;
1013     kbd->mouse_queue.end = 0;
1014     kbd->mouse_queue.count = 0;
1015
1016     kbd->kbd_queue.start = 0;
1017     kbd->kbd_queue.end = 0;
1018     kbd->kbd_queue.count = 0;
1019
1020     kbd->mouse_enabled = 0;
1021     kbd->scancode_set = 2;
1022
1023     kbd->state = NORMAL;
1024     kbd->mouse_state = STREAM;
1025
1026     // PS2, keyboard+mouse enabled, generic translation    
1027     kbd->cmd.val = 0;
1028
1029     kbd->cmd.irq_en = 1;
1030     kbd->cmd.mouse_irq_en = 1;
1031     kbd->cmd.self_test_ok = 1;
1032     /** **/
1033
1034
1035     // buffers empty, no errors
1036     kbd->status.val = 0; 
1037
1038     kbd->status.self_test_ok = 1; // self-tests passed
1039     kbd->status.enabled = 1;// keyboard ready
1040     /** **/
1041
1042     
1043     kbd->output_byte = 0;  //  ?
1044
1045     kbd->input_byte = INPUT_RAM;  // we have some
1046     // also display=color, jumper 0, keyboard enabled 
1047
1048     PrintDebug("keyboard: reset device\n");
1049  
1050     return 0;
1051
1052 }
1053
1054 #ifdef V3_CONFIG_CHECKPOINT
1055 static int keyboard_save(struct v3_chkpt_ctx * ctx, void * private_data) {
1056     return 0;
1057 }
1058
1059
1060 static int keyboard_load(struct v3_chkpt_ctx * ctx, void * private_data) {
1061     struct keyboard_internal * kbd = (struct keyboard_internal *)private_data;
1062     keyboard_reset_device(kbd);
1063     return 0;
1064 }
1065
1066 #endif
1067
1068
1069 static struct v3_device_ops dev_ops = { 
1070     .free = (int (*)(void *))keyboard_free,
1071 #ifdef V3_CONFIG_CHECKPOINT
1072     .save = keyboard_save,
1073     .load = keyboard_load
1074 #endif
1075 };
1076
1077
1078
1079
1080 static int keyboard_init(struct v3_vm_info * vm, v3_cfg_tree_t * cfg) {
1081     struct keyboard_internal * kbd = NULL;
1082     char * dev_id = v3_cfg_val(cfg, "ID");
1083     int ret = 0;
1084
1085     PrintDebug("keyboard: init_device\n");
1086
1087     kbd = (struct keyboard_internal *)V3_Malloc(sizeof(struct keyboard_internal));
1088
1089     memset(kbd, 0, sizeof(struct keyboard_internal));
1090
1091     kbd->vm = vm;
1092
1093     struct vm_device * dev = v3_add_device(vm, dev_id, &dev_ops, kbd);
1094
1095     if (dev == NULL) {
1096         PrintError("Could not attach device %s\n", dev_id);
1097         V3_Free(kbd);
1098         return -1;
1099     }
1100
1101     keyboard_reset_device(kbd);
1102
1103
1104     v3_lock_init(&(kbd->kb_lock));
1105
1106
1107     // hook ports
1108     ret |= v3_dev_hook_io(dev, KEYBOARD_64H, &keyboard_read_status, &keyboard_write_command);
1109     ret |= v3_dev_hook_io(dev, KEYBOARD_60H, &keyboard_read_input, &keyboard_write_output);
1110
1111     if (ret != 0) {
1112         PrintError("Error hooking keyboard IO ports\n");
1113         v3_remove_device(dev);
1114         return -1;
1115     }
1116
1117     v3_hook_host_event(vm, HOST_KEYBOARD_EVT, V3_HOST_EVENT_HANDLER(key_event_handler), kbd);
1118     v3_hook_host_event(vm, HOST_MOUSE_EVT, V3_HOST_EVENT_HANDLER(mouse_event_handler), kbd);
1119
1120
1121 #if KEYBOARD_DEBUG_80H
1122     v3_dev_hook_io(dev, KEYBOARD_DELAY_80H, &keyboard_read_delay, &keyboard_write_delay);
1123 #endif
1124
1125   
1126     //
1127     // We do not hook the IRQ here.  Instead, the underlying device driver
1128     // is responsible to call us back
1129     // 
1130
1131     return 0;
1132 }
1133
1134
1135 device_register("KEYBOARD", keyboard_init)