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.


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