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.


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