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.


hook F10 to state dumping
[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 <devices/keyboard.h>
21 #include <palacios/vmm.h>
22 #include <palacios/vmm_types.h>
23
24
25 #ifndef DEBUG_KEYBOARD
26 #undef PrintDebug
27 #define PrintDebug(fmt, args...)
28 #endif
29
30 #define KEYBOARD_DEBUG_80H   0
31
32
33
34 #define KEYBOARD_60H          0x60  // keyboard microcontroller
35 #define KEYBOARD_64H          0x64  // onboard microcontroller
36
37 #define KEYBOARD_DELAY_80H    0x80  // written for timing
38
39 #define KEYBOARD_IRQ          0x1
40 #define MOUSE_IRQ             0xc   
41
42
43 // extract bits for status byte
44 #define STATUS_OUTPUT_BUFFER_FULL   0x01  // 1=full (data for system)
45 #define STATUS_INPUT_BUFFER_FULL    0x02  // 1=full (data for 8042)
46 #define STATUS_SYSTEM               0x04  // 1=self-test-passed
47 #define STATUS_COMMAND_DATA_AVAIL   0x08  // internal: 0=data on 60h, 0=cmd on 64h
48 #define STATUS_ENABLED              0x10  // 1=keyboard is enabled
49 #define STATUS_MOUSE_BUFFER_FULL    0x20  // 1= mouse output buffer full
50 #define STATUS_TIMEOUT              0x40  // 1=timeout of keybd
51 #define STATUS_PARITY               0x80  // 1=parity error
52
53 // bits for cmd byte
54
55 #define CMD_INTR                0x01  // 1=interrupts enabled
56 #define CMD_MOUSE_INTR          0x02  // 1=interrupts enabled for mouse
57 #define CMD_SYSTEM              0x04  // 1= self test passed
58 #define CMD_OVERRIDE            0x08  // FORCE 0 for  PS2
59 #define CMD_DISABLE             0x10  // 1=disabled keyboard
60 #define CMD_MOUSE_DISABLE       0x20  // 1=disabled mouse
61 #define CMD_SCANCODE_XLATE      0x40  // 1=translate to set 1 scancodes
62 #define CMD_RESERVED            0x80  // should be zero
63
64 // bits for the output port 
65
66
67 #define OUTPUT_RESET        0x01  // System reset on 0
68 #define OUTPUT_A20          0x02  // A20 gate (1= A20 is gated)
69 #define OUTPUT_RES1         0x04  // reserved
70 #define OUTPUT_RES2         0x08  // reserved
71 #define OUTPUT_OUTPUT_FULL  0x10  // output buffer full
72 #define OUTPUT_INPUT_EMPTY  0x20  // input buffer empty
73 #define OUTPUT_KBD_CLOCK    0x40  // keyboard clock (?)
74 #define OUTPUT_KBD_DATA     0x80  // keyboard data
75
76 // bits for the input port
77
78 #define INPUT_RES0          0x01  // reserved
79 #define INPUT_RES1          0x02  // reserved
80 #define INPUT_RES2          0x04  // reserved
81 #define INPUT_RES3          0x08  // reserved
82 #define INPUT_RAM           0x10  // set to 1 if RAM exists?
83 #define INPUT_JUMPER        0x20  // manufacturing jumper?
84 #define INPUT_DISPLAY       0x40  // 0=color, 1=mono
85 #define INPUT_KBD_INHIBIT   0x80  // 1=inhibit keyboard ?
86
87
88 // for queue operations
89 #define QUEUE               0
90 #define OVERWRITE           1
91
92 // for queue operations - whether it's data or cmd waiting on 60h
93 #define DATA                0
94 #define COMMAND             1
95
96 // for queue operations - whether this is keyboard or mouse data on 60h
97 #define KEYBOARD            0
98 #define MOUSE               1
99
100
101
102 //#define QUEUE_SIZE          32
103
104
105 struct keyboard_internal {
106     // 
107     // 0x60 is the port for the keyboard microcontroller
108     //   writes are commands
109     //   reads from it usually return scancodes
110     //   however, it can also return other data 
111     //   depending on the state of the onboard microcontroller
112     //
113     // 0x64 is the port for the onboard microcontroller
114     //   writes are commands
115     //   reads are status
116     //
117
118     // state of the onboard microcontroller
119     // this is needed because sometimes 0x60 reads come
120     // from the onboard microcontroller
121     enum {// Normal mode measn we deliver keys
122         // to the vm and accept commands from it
123         NORMAL,
124         // after receiving cmd 0x60
125         // keybaord uC cmd will subsequently arrive
126         WRITING_CMD_BYTE,  
127         // after recieving 0xa5
128         // password arrives on data port, null terminated
129         TRANSMIT_PASSWD,
130         // after having reset sent to 0x60
131         // we immediately ack, and then
132         // push BAT success (0xaa) after the ack
133         RESET,
134         // after having a d1 sent to 64
135         // we wait for a new output byte on 60
136         WRITING_OUTPUT_PORT,
137         // after having a d2 sent to 64
138         // we wait for a new output byte on 60
139         // then make it available as a keystroke
140         INJECTING_KEY,
141         // after having a d3 sent to 64
142         // we wait for a new output byte on 60
143         // then make it available as a mouse event
144         INJECTING_MOUSE,
145         // after having a d4 sent to 64
146         // we wait for a new output byte on 60
147         // then send it to the mouse
148         IN_MOUSE,
149         // After the Keyboard LEDs are enabled
150         // we wait for the output byte on 64?
151         SET_LEDS,
152         // After the Keyboard SET_RATE is called
153         // we wait for the output byte on 64?
154         SET_RATE,
155         // The keyboard requests an ID which 
156         // generates 3 bytes of output...
157         KBD_ID1,
158         KBD_ID2,
159         
160         
161     } state;
162
163
164     enum {
165         // after receiving a mouse command 0f 0xff
166         // we return the ack and then the next thing will be the 
167         // bat code (aa - success)
168         RESET1,
169         // followed by the device id (00 - mouse)
170         RESET2, 
171         // Then it goes into stream mode
172         STREAM1,  //
173         STREAM2,  //
174         STREAM3,  // for each of the following bytes in mouse_packet
175         // this is used for setting sample rate
176         SAMPLE1,  
177         // this is used for getting device id
178         DEVICE1, 
179         // just like the stream moes
180         REMOTE1,
181         REMOTE2,
182         REMOTE3,
183         // For getting status info
184         STATUS1,
185         STATUS2,
186         STATUS3, 
187         // set resolution
188         SETRES1,
189     } mouse_state;
190
191
192     uchar_t wrap;             
193     uchar_t mouse_packet[3];  // byte 1: y over, xover, y sign, x sign, 1, middle, right, left
194     // byte 2: x movement
195     // byte 3: y movement
196
197     uchar_t mouse_needs_ack;  //
198     uchar_t mouse_done_after_ack; 
199
200     uchar_t cmd_byte;         //  for keyboard uC - read/written 
201     //     via read/write cmd byte command
202     uchar_t status_byte;      //  for on-board uC - read via 64h
203
204     uchar_t output_byte;      //  output port of onboard uC (e.g. A20)
205
206     uchar_t input_byte;       //  input port of onboard uC
207
208     // Data for system
209     uchar_t output_queue;     //  
210     uint_t  output_queue_len; //  
211     //uint_t  output_queue_read;
212     //uint_t  output_queue_write;
213
214
215 };
216
217
218 static int keyboard_interrupt(struct vm_device * dev, uint_t irq) {
219     struct keyboard_internal *state = (struct keyboard_internal *)(dev->private_data);
220
221     PrintDebug("keyboard: interrupt 0x%x\n", irq);
222
223     if (state->cmd_byte & CMD_INTR) { 
224         v3_raise_irq(dev->vm, irq);
225     }
226
227     return 0;
228 }
229
230
231
232 // 
233 // push item onto outputqueue, optionally overwriting if there is no room
234 // returns 0 if successful
235 //
236 static int PushToOutputQueue(struct vm_device * dev, uchar_t value, uchar_t overwrite, uchar_t cmd, uchar_t mouse) 
237 {
238     struct keyboard_internal *state = (struct keyboard_internal *)(dev->private_data);
239   
240     if ((state->output_queue_len == 0) || overwrite) { 
241     
242         state->output_queue = value;
243         state->output_queue_len = 1;
244     
245         if (cmd) {
246             state->status_byte |= STATUS_COMMAND_DATA_AVAIL;
247         } else {
248             state->status_byte &= ~STATUS_COMMAND_DATA_AVAIL;
249         }
250     
251         if (mouse) { 
252             state->status_byte |= STATUS_MOUSE_BUFFER_FULL;
253             keyboard_interrupt(dev, MOUSE_IRQ);
254         } else {
255             keyboard_interrupt(dev, KEYBOARD_IRQ);
256         }
257
258         state->status_byte |= STATUS_OUTPUT_BUFFER_FULL;
259
260         return 0;
261
262     } else {
263         PrintError("keyboard: PushToOutputQueue Failed - Queue Full\n");
264         return -1;
265     }
266 }
267
268
269 // 
270 // pull item from outputqueue 
271 // returns 0 if successful
272 //
273 static int PullFromOutputQueue(struct vm_device * dev, uchar_t * value) 
274 {
275     struct keyboard_internal *state = (struct keyboard_internal *)(dev->private_data);
276
277     if (1 || (state->output_queue_len == 1)) { 
278
279         *value = state->output_queue;
280         state->output_queue_len = 0;
281     
282         if (state->status_byte & STATUS_OUTPUT_BUFFER_FULL) { 
283             state->status_byte &= ~STATUS_OUTPUT_BUFFER_FULL;
284         } 
285     
286         if (state->status_byte & STATUS_MOUSE_BUFFER_FULL) { 
287             state->status_byte &= ~STATUS_MOUSE_BUFFER_FULL;
288         }
289     
290         if (state->status_byte & STATUS_COMMAND_DATA_AVAIL) { 
291             state->status_byte &= ~STATUS_COMMAND_DATA_AVAIL;
292         } // reset to data
293     
294     
295         return 0;
296     } else {
297         PrintError("keyboard: PullFromOutputQueue Failed - Queue Empty\n");
298         return -1;
299     }
300 }
301
302
303
304
305 static int key_event_handler(struct guest_info * info, 
306                              struct v3_keyboard_event * evt, 
307                              void * private_data) {
308     struct vm_device * dev = (struct vm_device *)private_data;
309     struct keyboard_internal *state = (struct keyboard_internal *)(dev->private_data);
310
311     PrintDebug("keyboard: injected status 0x%x, and scancode 0x%x\n", evt->status, evt->scan_code);
312
313
314     if (evt->scan_code == 0x44) { // F10 debug dump
315         v3_print_guest_state(info);
316         //      PrintGuestPageTables(info, info->shdw_pg_state.guest_cr3);
317     }
318
319     if ( (state->status_byte & STATUS_ENABLED)      // onboard is enabled
320          && (!(state->cmd_byte & CMD_DISABLE)) )  {   // keyboard is enabled
321     
322         PushToOutputQueue(dev, evt->scan_code, OVERWRITE, DATA, KEYBOARD);
323     }
324   
325     return 0;
326 }
327
328
329 static int mouse_event_handler(struct guest_info * info, 
330                                struct v3_mouse_event * evt, 
331                                void * private_data) {
332     struct vm_device * dev = (struct vm_device *)private_data;
333     struct keyboard_internal * state = (struct keyboard_internal *)(dev->private_data);
334
335     PrintDebug("keyboard: injected mouse packet 0x %x %x %x\n",
336                evt->data[0], evt->data[1], evt->data[2]);
337   
338     memcpy(state->mouse_packet, evt->data, 3);
339   
340     state->status_byte |= STATUS_MOUSE_BUFFER_FULL;
341   
342     
343     switch (state->mouse_state) { 
344         case STREAM1:
345         case STREAM2:
346         case STREAM3:
347             if (!(state->cmd_byte & CMD_MOUSE_DISABLE)) { 
348                 keyboard_interrupt(dev, MOUSE_IRQ);
349             }
350             break;
351         default:
352             return -1;
353             break;
354     }
355
356     return 0;
357 }
358
359
360 static int keyboard_reset_device(struct vm_device * dev)
361 {
362     struct keyboard_internal *data = (struct keyboard_internal *)(dev->private_data);
363   
364     memset(data, 0, sizeof(struct keyboard_internal));
365
366     data->state = NORMAL;
367     data->mouse_state = STREAM1;
368
369     data->cmd_byte =  
370         CMD_INTR          // interrupts on
371         | CMD_MOUSE_INTR  // mouse interupts on
372         | CMD_SYSTEM ;    // self test passed
373     // PS2, keyboard+mouse enabled, generic translation    
374   
375     data->status_byte = 
376         STATUS_SYSTEM       // self-tests passed
377         | STATUS_ENABLED ;  // keyboard ready
378     // buffers empty, no errors
379
380     data->output_byte = 0;  //  ?
381
382     data->input_byte = INPUT_RAM;  // we have some
383     // also display=color, jumper 0, keyboard enabled 
384
385   
386
387     PrintDebug("keyboard: reset device\n");
388  
389     return 0;
390
391 }
392
393
394
395 static int keyboard_start_device(struct vm_device *dev)
396 {
397     PrintDebug("keyboard: start device\n");
398     return 0;
399 }
400
401
402 static int keyboard_stop_device(struct vm_device *dev)
403 {
404     PrintDebug("keyboard: stop device\n");
405     return 0;
406 }
407
408
409 static int mouse_read_input(struct vm_device *dev)
410 {
411     struct keyboard_internal *state = (struct keyboard_internal *)(dev->private_data);
412
413     if (state->mouse_needs_ack) { 
414         state->mouse_needs_ack = 0;
415
416         // the ack has been stuffed previously
417         if (state->mouse_done_after_ack) { 
418             return 1;
419         } else {
420             return 0;
421         }
422     }
423
424     switch (state->mouse_state) { 
425
426         case RESET1: // requesting the BAT code
427             PushToOutputQueue(dev, 0xaa, OVERWRITE, DATA, MOUSE) ;  // BAT successful
428             PrintDebug(" mouse sent BAT code (sucesssful) ");
429             state->mouse_state = RESET2;
430
431             return 0;  // not done with mouse processing yet
432             break;
433
434         case RESET2: // requesting the device id
435             PushToOutputQueue(dev, 0x00, OVERWRITE, DATA, MOUSE) ;  // normal mouse type
436             PrintDebug(" mouse sent device id ");
437             state->mouse_state = STREAM1;
438
439             return 1;  // done with mouse processing 
440             break;
441
442         case STREAM1: // send data
443             PushToOutputQueue(dev, state->mouse_packet[0], OVERWRITE, DATA, MOUSE); 
444             PrintDebug(" mouse sent stream data1 ");
445             state->mouse_state = STREAM2;
446
447             return 0;
448             break;
449
450         case STREAM2: // send data
451             PushToOutputQueue(dev, state->mouse_packet[1], OVERWRITE, DATA, MOUSE); 
452             PrintDebug(" mouse sent stream data2 ");
453             state->mouse_state = STREAM3;
454
455             return 0;
456             break;
457
458         case STREAM3: // send data
459             PushToOutputQueue(dev, state->mouse_packet[2], OVERWRITE, DATA, MOUSE); 
460             PrintDebug(" mouse sent stream data3 ");
461             state->mouse_state = STREAM1;
462
463             return 1; // now done
464             break;
465
466         case REMOTE1: // send data
467             PushToOutputQueue(dev, state->mouse_packet[0], OVERWRITE, DATA, MOUSE); 
468             PrintDebug(" mouse sent remote data1 ");
469             state->mouse_state = REMOTE2;
470
471             return 0;
472             break;
473
474         case REMOTE2: // send data
475             PushToOutputQueue(dev, state->mouse_packet[1], OVERWRITE, DATA, MOUSE); 
476             PrintDebug(" mouse sent remote data2 ");
477             state->mouse_state = REMOTE3;
478
479             return 0;
480             break;
481
482         case REMOTE3: // send data
483             PushToOutputQueue(dev, state->mouse_packet[2], OVERWRITE, DATA, MOUSE); 
484             PrintDebug(" mouse sent remote data3 ");
485             state->mouse_state = REMOTE1;
486
487             return 1; // now done
488             break;
489
490         case STATUS1: // send data
491             PushToOutputQueue(dev, 0x0, OVERWRITE, DATA, MOUSE); 
492             PrintDebug(" mouse sent status data1 ");
493             state->mouse_state = STATUS2;
494
495             return 0;
496             break;
497
498         case STATUS2: // send data
499             PushToOutputQueue(dev, 0x0, OVERWRITE, DATA, MOUSE); 
500             PrintDebug(" mouse sent status data2 ");
501             state->mouse_state = STATUS3;
502
503             return 0;
504             break;
505
506         case STATUS3: // send data
507             PushToOutputQueue(dev, 0x0, OVERWRITE, DATA, MOUSE); 
508             PrintDebug(" mouse sent status data3 ");
509             state->mouse_state = STREAM1;
510
511             return 1; // now done
512             break;
513
514         case DEVICE1: // send device id
515             PushToOutputQueue(dev, 0x0, OVERWRITE, DATA, MOUSE); 
516             PrintDebug(" mouse sent device id ");
517             state->mouse_state = STREAM1;
518
519             return 1; // now done
520             break;
521
522         default:
523             PrintDebug(" mouse has no data ");
524             return 1; // done
525             break;
526     }
527 }
528
529 static int mouse_write_output(struct vm_device * dev, uchar_t data)
530 {
531     struct keyboard_internal * state = (struct keyboard_internal *)(dev->private_data);
532
533     switch (state->mouse_state) { 
534         case STREAM1:
535         case STREAM2:
536         case STREAM3:
537         case REMOTE1:
538         case REMOTE2:
539         case REMOTE3:
540             switch (data) {
541
542                 case 0xff: //reset
543                     PushToOutputQueue(dev, 0xfe, OVERWRITE, DATA, MOUSE) ;   // no mouse!
544                     PrintDebug(" mouse reset begins (no mouse) ");
545
546                     return 1;  // not done;
547                     break;
548
549                     /*
550                       case 0xff: //reset
551                       PushToOutputQueue(dev,0xfa,OVERWRITE,DATA,MOUSE) ; 
552                       PrintDebug(" mouse reset begins ");
553                       state->mouse_done_after_ack=0;
554                       state->mouse_needs_ack=1;
555                       state->mouse_state=RESET1;
556                       return 0;  // not done;
557                       break;
558                     */
559                 case 0xfe: //resend
560                     PushToOutputQueue(dev, 0xfa, OVERWRITE, DATA, MOUSE) ; 
561                     PrintDebug(" mouse resend begins ");
562                     state->mouse_done_after_ack = 0;
563                     state->mouse_needs_ack = 0;
564                     state->mouse_state = STREAM1;
565                     return 0;  // not done
566                     break;
567       
568                 case 0xf6: // set defaults
569                     PushToOutputQueue(dev, 0xfa, OVERWRITE, DATA, MOUSE) ; 
570                     PrintDebug(" mouse set defaults ");
571                     state->mouse_done_after_ack = 1;
572                     state->mouse_needs_ack = 1;
573                     state->mouse_state = STREAM1;
574                     return 0; // not done
575                     break;
576       
577                 case 0xf5: // disable data reporting 
578                     PushToOutputQueue(dev, 0xfa, OVERWRITE, DATA, MOUSE) ; 
579                     state->mouse_done_after_ack = 1;
580                     state->mouse_needs_ack = 1;
581                     PrintDebug(" mouse disable data reporting ");
582                     state->mouse_state = STREAM1;
583                     return 0; // not done
584                     break;
585       
586                 case 0xf4: // enable data reporting 
587                     PushToOutputQueue(dev, 0xfa, OVERWRITE, DATA, MOUSE) ; 
588                     state->mouse_done_after_ack = 1;
589                     state->mouse_needs_ack = 1;
590                     PrintDebug(" mouse enable data reporting ");
591                     state->mouse_state = STREAM1;
592                     return 0; // not done
593                     break;
594       
595                 case 0xf3: // set sample rate
596                     PushToOutputQueue(dev, 0xfa, OVERWRITE, DATA, MOUSE) ; 
597                     state->mouse_done_after_ack = 0;
598                     state->mouse_needs_ack = 1;
599                     PrintDebug(" mouse set sample rate begins ");
600                     state->mouse_state = SAMPLE1;
601                     return 0; // not done
602                     break;
603       
604                 case 0xf2: // get device id
605                     PushToOutputQueue(dev, 0xfa, OVERWRITE, DATA, MOUSE) ; 
606                     state->mouse_done_after_ack = 0;
607                     state->mouse_needs_ack = 1;
608                     PrintDebug(" mouse get device id begins ");
609                     state->mouse_state = DEVICE1;
610                     return 0; // not done
611                     break;
612       
613                 case 0xf0: // set remote mode
614                     PushToOutputQueue(dev, 0xfa, OVERWRITE, DATA, MOUSE) ; 
615                     state->mouse_done_after_ack = 1;
616                     state->mouse_needs_ack = 1;
617                     PrintDebug(" mouse set remote mode  ");
618                     state->mouse_state = REMOTE1;
619                     return 0; // not done
620                     break;
621
622                 case 0xee: // set wrap mode
623                     PushToOutputQueue(dev, 0xfa, OVERWRITE, DATA, MOUSE) ; 
624                     state->mouse_done_after_ack = 1;
625                     state->mouse_needs_ack = 1;
626                     PrintDebug(" mouse set wrap mode (ignored)  ");
627                     state->mouse_state = STREAM1;
628                     return 0; // not done
629                     break;
630
631                 case 0xec: // reset wrap mode
632                     PushToOutputQueue(dev, 0xfa, OVERWRITE, DATA, MOUSE) ; 
633                     state->mouse_done_after_ack = 1;
634                     state->mouse_needs_ack = 1;
635                     PrintDebug(" mouse reset wrap mode (ignored)  ");
636                     state->mouse_state = STREAM1;
637                     return 0; // done
638                     break;
639
640                 case 0xeb: // read data
641                     PushToOutputQueue(dev, 0xfa, OVERWRITE, DATA, MOUSE) ; 
642                     state->mouse_done_after_ack = 0;
643                     state->mouse_needs_ack = 1;
644                     PrintDebug(" mouse switch to wrap mode (ignored)  ");
645                     state->mouse_state = REMOTE1;
646                     return 0; // not done
647                     break;
648       
649                 case 0xea: // set stream mode
650                     PushToOutputQueue(dev, 0xfa, OVERWRITE, DATA, MOUSE) ; 
651                     state->mouse_done_after_ack = 1;
652                     state->mouse_needs_ack = 1;
653                     PrintDebug(" mouse set stream mode  ");
654                     state->mouse_state = STREAM1;
655                     return 0; // not done
656                     break;
657
658                 case 0xe9: // status request
659                     PushToOutputQueue(dev, 0xfa, OVERWRITE, DATA, MOUSE) ; 
660                     state->mouse_done_after_ack = 0;
661                     state->mouse_needs_ack = 1;
662                     PrintDebug(" mouse status request begins  ");
663                     state->mouse_state = STATUS1;
664                     return 0; // notdone
665                     break;
666
667                 case 0xe8: // set resolution
668                     PushToOutputQueue(dev, 0xfa, OVERWRITE, DATA, MOUSE) ; 
669                     state->mouse_done_after_ack = 0;
670                     state->mouse_needs_ack = 1;
671                     PrintDebug(" mouse set resolution begins  ");
672                     state->mouse_state = SETRES1;
673                     return 0; // notdone
674                     break;
675
676                 case 0xe7: // set scaling 2:1
677                     PushToOutputQueue(dev, 0xfa, OVERWRITE, DATA, MOUSE) ; 
678                     state->mouse_done_after_ack = 1;
679                     state->mouse_needs_ack = 1;
680                     PrintDebug(" mouse set scaling 2:1 ");
681                     state->mouse_state = STREAM1;
682                     return 0; // not done
683                     break;
684
685                 case 0xe6: // set scaling 1:1
686                     PushToOutputQueue(dev, 0xfa, OVERWRITE, DATA, MOUSE) ; 
687                     state->mouse_done_after_ack = 1;
688                     state->mouse_needs_ack = 1;
689                     PrintDebug(" mouse set scaling 1:1 ");
690                     state->mouse_state = STREAM1;
691                     return 0; // done
692                     break;
693       
694                 default:
695                     PrintDebug(" receiving unknown mouse command (0x%x) in acceptable state ", data);
696                     return 1; // done
697                     break;
698
699             }
700     
701         default:
702             PrintDebug(" receiving mouse output in unhandled state (0x%x) ", state->mouse_state);
703             break;
704             return 1; // done?
705             break;
706     }
707
708     PrintDebug(" HUH? ");
709     return 1; // done
710 }
711
712
713
714 #if KEYBOARD_DEBUG_80H
715 static int keyboard_write_delay(ushort_t port,
716                                 void * src, 
717                                 uint_t length,
718                                 struct vm_device * dev)
719 {
720
721     if (length == 1) { 
722         PrintDebug("keyboard: write of 0x%x to 80h\n", *((uchar_t*)src));
723
724         return 1;
725     } else {
726         PrintDebug("keyboard: write of >1 byte to 80h\n", *((uchar_t*)src));
727
728         return length;
729     }
730 }
731
732 static int keyboard_read_delay(ushort_t port,
733                                void * dest, 
734                                uint_t length,
735                                struct vm_device * dev)
736 {
737
738     if (length == 1) { 
739         *((uchar_t*)dest) = v3_inb(port);
740
741         PrintDebug("keyboard: read of 0x%x from 80h\n", *((uchar_t*)dest));
742
743         return 1;
744     } else {
745         PrintDebug("keyboard: read of >1 byte from 80h\n");
746
747         return length;
748     }
749 }
750 #endif
751     
752   
753
754
755
756 static int keyboard_write_command(ushort_t port,
757                                   void * src, 
758                                   uint_t length,
759                                   struct vm_device * dev)
760 {
761     struct keyboard_internal *state = (struct keyboard_internal *)(dev->private_data);
762     uchar_t cmd;
763
764     // Should always be single byte write
765
766     if (length != 1) { 
767         PrintError("keyboard: write of >1 bytes (%d) to 64h\n", length);
768         return -1;
769     }
770
771     cmd = *((uchar_t*)src); 
772
773     if (state->state != NORMAL) { 
774         PrintDebug("keyboard: warning - receiving command on 64h but state != NORMAL\n");
775     }
776   
777     PrintDebug("keyboard: command 0x%x on 64h\n", cmd);
778
779     switch (cmd) { 
780
781         case 0x20:  // READ COMMAND BYTE (returned in 60h)
782             PushToOutputQueue(dev, state->cmd_byte, OVERWRITE, COMMAND,KEYBOARD);
783             state->state = NORMAL;  // the next read on 0x60 will get the right data
784             PrintDebug("keyboard: command byte 0x%x returned\n", state->cmd_byte);
785             break;
786
787         case 0x60:  // WRITE COMMAND BYTE (read from 60h)
788             state->state = WRITING_CMD_BYTE; // we need to make sure we send the next 0x60 byte appropriately
789             PrintDebug("keyboard: prepare to write command byte\n");
790             break;
791
792             // case 0x90-9f - write to output port  (?)
793
794         case 0xa1: // Get version number
795             PushToOutputQueue(dev, 0, OVERWRITE, COMMAND, KEYBOARD);
796             state->state = NORMAL;
797             PrintDebug("keyboard: version number 0x0 returned\n");
798             break;
799
800         case 0xa4:  // is password installed?  send result to 0x60
801             // we don't support passwords
802             PushToOutputQueue(dev, 0xf1, OVERWRITE, COMMAND, KEYBOARD);
803             PrintDebug("keyboard: password not installed\n");
804             state->state = NORMAL;
805             break;
806
807         case 0xa5:  // new password will arrive on 0x60
808             state->state = TRANSMIT_PASSWD;
809             PrintDebug("keyboard: pepare to transmit password\n");
810             break;
811
812         case 0xa6:  // check passwd;
813             // since we do not support passwords, we will simply ignore this
814             // the implication is that any password check immediately succeeds 
815             // with a blank password
816             state->state = NORMAL;
817             PrintDebug("keyboard: password check succeeded\n");
818             break;
819
820         case 0xa7:  // disable mouse
821             state->cmd_byte |= CMD_MOUSE_DISABLE;
822             state->state = NORMAL;
823             PrintDebug("keyboard: mouse disabled\n");
824             break;
825
826         case 0xa8:  // enable mouse
827             state->cmd_byte &= ~CMD_MOUSE_DISABLE;
828             state->state = NORMAL;
829             PrintDebug("keyboard: mouse enabled\n");
830             break;
831
832         case 0xa9:  // mouse interface test  (always succeeds)
833             PushToOutputQueue(dev, 0, OVERWRITE, COMMAND, KEYBOARD);
834             PrintDebug("keyboard: mouse interface test succeeded\n");
835             state->state = NORMAL;
836             break;
837
838         case 0xaa:  // controller self test (always succeeds)
839             PushToOutputQueue(dev, 0x55, OVERWRITE, COMMAND, KEYBOARD);
840             PrintDebug("keyboard: controller self test succeeded\n");
841             state->state = NORMAL;
842             break;
843
844         case 0xab:  // keyboard interface test (always succeeds)
845             PushToOutputQueue(dev, 0, OVERWRITE, COMMAND, KEYBOARD);
846             state->state = NORMAL;
847             PrintDebug("keyboard: keyboard interface test succeeded\n");
848             break;
849
850         case 0xad:  // disable keyboard
851             state->cmd_byte |= CMD_DISABLE;
852             state->state = NORMAL;
853             PrintDebug("keyboard: keyboard disabled\n");
854             break;
855
856         case 0xae:  // enable keyboard
857             state->cmd_byte &= ~CMD_DISABLE;
858             state->state = NORMAL;
859             PrintDebug("keyboard: keyboard enabled\n");
860             break;
861
862         case 0xaf:  // get version
863             PushToOutputQueue(dev, 0x00, OVERWRITE, COMMAND, KEYBOARD);
864             state->state = NORMAL;
865             PrintDebug("keyboard: version 0 returned \n");
866             break;
867
868         case 0xd0: // return microcontroller output on 60h
869             PushToOutputQueue(dev, state->output_byte, OVERWRITE, COMMAND, KEYBOARD);
870             state->state = NORMAL;
871             PrintDebug("keyboard: output byte 0x%x returned\n", state->output_byte);
872             break;
873
874         case 0xd1: // request to write next byte on 60h to the microcontroller output port
875             state->state = WRITING_OUTPUT_PORT;
876             PrintDebug("keyboard: prepare to write output byte\n");
877             break;
878
879         case 0xd2:  //  write keyboard buffer (inject key)
880             state->state = INJECTING_KEY;
881             PrintDebug("keyboard: prepare to inject key\n");
882             break;
883
884         case 0xd3: //  write mouse buffer (inject mouse)
885             state->state = INJECTING_MOUSE;
886             PrintDebug("keyboard: prepare to inject mouse\n");
887             break;
888
889         case 0xd4: // write mouse device (command to mouse?)
890             state->state = IN_MOUSE;
891             PrintDebug("keyboard: prepare to inject mouse command\n");
892             break;
893
894         case 0xc0: //  read input port 
895             PushToOutputQueue(dev, state->input_byte, OVERWRITE, COMMAND, KEYBOARD);
896             state->state = NORMAL;
897             PrintDebug("keyboard: input byte 0x%x returned\n", state->input_byte);
898             break;
899
900         case 0xc1:  //copy input port lsn to status msn
901             state->status_byte &= 0x0f;
902             state->status_byte |= (state->input_byte & 0xf) << 4;
903             state->state = NORMAL;
904             PrintDebug("keyboard: copied input byte lsn to status msn\n");
905             break;
906
907         case 0xc2: // copy input port msn to status msn
908             state->status_byte &= 0x0f;
909             state->status_byte |= (state->input_byte & 0xf0);
910             state->state = NORMAL;
911             PrintDebug("keyboard: copied input byte msn to status msn\n");
912             break;
913     
914         case 0xe0: // read test port
915             PushToOutputQueue(dev, state->output_byte >> 6, OVERWRITE, COMMAND, KEYBOARD);
916             state->state = NORMAL;
917             PrintDebug("keyboard: read 0x%x from test port\n", state->output_byte >> 6);
918             break;
919
920    
921         case 0xf0:   // pulse output port
922         case 0xf1:   // this should pulse 0..3 of cmd_byte on output port 
923         case 0xf2:   // instead of what is currently in output_byte (I think)
924         case 0xf3:   // main effect is taht if bit zero is zero
925         case 0xf4:   // should cause reset
926         case 0xf5:   // I doubt anything more recent than a 286 running 
927         case 0xf6:   // OS2 with the penalty box will care
928         case 0xf7:
929         case 0xf8:
930         case 0xf9:
931         case 0xfa:
932         case 0xfb:
933         case 0xfc:
934         case 0xfd:
935         case 0xfe:
936         case 0xff:
937   
938             PrintDebug("keyboard: ignoring pulse of 0x%x (low=pulsed) on output port\n", (cmd & 0xf));
939             state->state = NORMAL;
940             break;
941    
942
943             // case ac  diagonstic - returns 16 bytes from keyboard microcontroler on 60h
944         default:
945             PrintDebug("keyboard: ignoring command (unimplemented)\n");
946             state->state = NORMAL;
947             break;
948     }
949
950     return 1;
951
952 }
953
954 static int keyboard_read_status(ushort_t port,
955                                 void * dest, 
956                                 uint_t length,
957                                 struct vm_device * dev)
958 {
959     struct keyboard_internal *state = (struct keyboard_internal *)(dev->private_data);
960
961     if (length == 1) { 
962
963         PrintDebug("keyboard: read status (64h): ");
964
965         *((uchar_t*)dest) = state->status_byte;
966
967         PrintDebug("0x%x\n", *((uchar_t*)dest));
968
969         return 1;
970     } else {
971         PrintError("keyboard: >1 byte read for status (64h)\n");
972         return -1;
973     }
974 }
975
976 static int keyboard_write_output(ushort_t port,
977                                  void * src, 
978                                  uint_t length,
979                                  struct vm_device * dev)
980 {
981     struct keyboard_internal *state = (struct keyboard_internal *)(dev->private_data);
982
983     if (length != 1) { 
984         PrintError("keyboard: write of 60h with >1 byte\n");
985         return -1;
986     }
987
988     uchar_t data = *((uchar_t*)src);
989   
990     PrintDebug("keyboard: output 0x%x on 60h\n", data);
991
992     switch (state->state) {
993         case WRITING_CMD_BYTE:
994             state->cmd_byte = data;
995             state->state = NORMAL;
996             PrintDebug("keyboard: wrote new command byte 0x%x\n", state->cmd_byte);
997             break;
998         case WRITING_OUTPUT_PORT:
999             state->output_byte = data;
1000             state->state = NORMAL;
1001             PrintDebug("keyboard: wrote new output byte 0x%x\n", state->output_byte);
1002             break;
1003         case INJECTING_KEY:
1004             PushToOutputQueue(dev, data, OVERWRITE, COMMAND, KEYBOARD);  // probably should be a call to deliver_key_to_vmm()
1005             state->state = NORMAL;
1006             PrintDebug("keyboard: injected key 0x%x\n", data);
1007             break;
1008         case INJECTING_MOUSE:
1009             PushToOutputQueue(dev, data, OVERWRITE, DATA, MOUSE);
1010             //      PrintDebug("keyboard: ignoring injected mouse event 0x%x\n", data);
1011             PrintDebug("keyboard: injected mouse event 0x%x\n", data);
1012             state->state = NORMAL;
1013             break;
1014         case IN_MOUSE:
1015             PrintDebug("keyboard: mouse action: ");
1016             if (mouse_write_output(dev, data)) { 
1017                 state->state = NORMAL;
1018             }
1019             PrintDebug("\n");
1020             break;
1021         case TRANSMIT_PASSWD:
1022             if (data) {
1023                 //ignore passwd
1024                 PrintDebug("keyboard: ignoring password character 0x%x\n",data);
1025             } else {
1026                 // end of password
1027                 state->state = NORMAL;
1028                 PrintDebug("keyboard: done with password\n");
1029             }
1030             break;
1031         case SET_LEDS:
1032             PrintDebug("Keyboard: LEDs being set...\n");
1033             PushToOutputQueue(dev, 0xfa, OVERWRITE, COMMAND, KEYBOARD);
1034             state->state = NORMAL;
1035             break;
1036         case SET_RATE:
1037             PrintDebug("Keyboard: Rate being set...\n");
1038             PushToOutputQueue(dev, 0xfa, OVERWRITE, COMMAND, KEYBOARD);
1039             state->state = NORMAL;
1040             break;
1041         default:
1042         case NORMAL:
1043             {
1044                 // command is being sent to keyboard controller
1045                 switch (data) { 
1046                     case 0xff: // reset
1047                         PushToOutputQueue(dev, 0xfa, OVERWRITE, COMMAND, KEYBOARD); // ack
1048                         state->state = RESET;
1049                         PrintDebug("keyboard: reset complete and acked\n");
1050                         break;
1051                     case 0xf5: // disable scanning
1052                     case 0xf4: // enable scanning
1053                         // ack
1054                         PushToOutputQueue(dev, 0xfa, OVERWRITE, COMMAND, KEYBOARD);
1055                         // should do something here... PAD
1056                         state->state = NORMAL;
1057                         PrintDebug("keyboard: %s scanning done and acked\n", (data == 0xf5) ? "disable" : "enable");
1058                         break;
1059                     case 0xf3:
1060                         PushToOutputQueue(dev, 0xfa, OVERWRITE, COMMAND, KEYBOARD);
1061                         state->state = SET_RATE;
1062                         break;
1063                     case 0xf2: // get keyboard ID
1064                         PushToOutputQueue(dev, 0xfa, OVERWRITE, COMMAND, KEYBOARD);
1065                         state->state = KBD_ID1;
1066                         PrintDebug("Keyboard: Requesting Keyboard ID\n");
1067
1068                         //PushToOutputQueue(dev, 0xab, OVERWRITE, COMMAND, KEYBOARD);
1069                         //state->state = KBD_ID2;
1070                         break;
1071                     case 0xed: // enable keyboard LEDs
1072                         PushToOutputQueue(dev, 0xfa, OVERWRITE, COMMAND, KEYBOARD);
1073                         state->state = SET_LEDS;
1074                         break;
1075                     case 0xfe: // resend
1076                     case 0xfd: // set key type make
1077                     case 0xfc: // set key typ make/break
1078                     case 0xfb: // set key type typematic
1079                     case 0xfa: // set all typematic make/break/typematic
1080                     case 0xf9: // set all make
1081                     case 0xf8: // set all make/break
1082                     case 0xf7: // set all typemaktic
1083                     case 0xf6: // set defaults
1084                         PrintDebug("keyboard: unhandled known command 0x%x on output buffer (60h)\n", data);
1085                         return -1;
1086                         break;
1087                     default:
1088                         PrintDebug("keyboard: unhandled unknown command 0x%x on output buffer (60h)\n", data);
1089                         state->status_byte |= 0x1;
1090                         return -1;
1091                         break;
1092                 }
1093                 break;
1094             }
1095
1096     }
1097   
1098     return 1;
1099 }
1100
1101 static int keyboard_read_input(ushort_t port,
1102                                void * dest, 
1103                                uint_t length,
1104                                struct vm_device * dev)
1105 {
1106     struct keyboard_internal *state = (struct keyboard_internal *)(dev->private_data);
1107
1108     if (length == 1) { 
1109         uchar_t data;
1110         int done_mouse;
1111
1112         PrintDebug("keyboard: read from input (60h): ");
1113
1114         if (state->state == IN_MOUSE) { 
1115             done_mouse = mouse_read_input(dev);
1116             if (done_mouse) { 
1117                 state->state = NORMAL;
1118             }
1119         } 
1120       
1121         PullFromOutputQueue(dev, &data);
1122       
1123         if (state->state == RESET) { 
1124             // We just delivered the ack for the reset
1125             // now we will ready ourselves to deliver the BAT code (success)
1126             PushToOutputQueue(dev, 0xaa, OVERWRITE, COMMAND, KEYBOARD);
1127             state->state = NORMAL;
1128             PrintDebug(" (in reset, pushing BAT test code 0xaa) ");
1129         } else if (state->state == KBD_ID1) {
1130             PushToOutputQueue(dev, 0xab, OVERWRITE, COMMAND, KEYBOARD);
1131             state->state = KBD_ID2;
1132             PrintDebug(" (in kbd id request, pushing 1st ID val) ");
1133         } else if (state->state == KBD_ID2) {
1134             PushToOutputQueue(dev, 0x83, OVERWRITE, COMMAND, KEYBOARD);
1135             state->state = NORMAL;
1136             PrintDebug(" (in kbd id request, pushing 2nd ID val) ");
1137         }
1138
1139         PrintDebug("0x%x\n", data);
1140
1141         *((uchar_t*)dest) = data;
1142     
1143         return 1;
1144     } else {
1145         PrintError("keyboard: unknown size read from input (60h)\n");
1146         return -1;
1147     }
1148 }
1149
1150
1151
1152
1153
1154 static int keyboard_init_device(struct vm_device * dev) 
1155 {
1156  
1157     //  struct keyboard_internal *data = (struct keyboard_internal *) dev->private_data;
1158
1159     PrintDebug("keyboard: init_device\n");
1160
1161     // Would read state here
1162
1163     keyboard_reset_device(dev);
1164
1165     // hook ports
1166     v3_dev_hook_io(dev, KEYBOARD_64H, &keyboard_read_status, &keyboard_write_command);
1167     v3_dev_hook_io(dev, KEYBOARD_60H, &keyboard_read_input, &keyboard_write_output);
1168
1169     v3_hook_host_event(dev->vm, HOST_KEYBOARD_EVT, V3_HOST_EVENT_HANDLER(key_event_handler), dev);
1170     v3_hook_host_event(dev->vm, HOST_MOUSE_EVT, V3_HOST_EVENT_HANDLER(mouse_event_handler), dev);
1171
1172
1173 #if KEYBOARD_DEBUG_80H
1174     v3_dev_hook_io(dev, KEYBOARD_DELAY_80H, &keyboard_read_delay, &keyboard_write_delay);
1175 #endif
1176
1177   
1178     //
1179     // We do not hook the IRQ here.  Instead, the underlying device driver
1180     // is responsible to call us back
1181     // 
1182
1183     return 0;
1184 }
1185
1186 static int keyboard_deinit_device(struct vm_device *dev)
1187 {
1188
1189     v3_dev_unhook_io(dev, KEYBOARD_60H);
1190     v3_dev_unhook_io(dev, KEYBOARD_64H);
1191 #if KEYBOARD_DEBUG_80H
1192     v3_dev_unhook_io(dev, KEYBOARD_DELAY_80H);
1193 #endif
1194     keyboard_reset_device(dev);
1195     return 0;
1196 }
1197
1198
1199
1200
1201
1202 static struct vm_device_ops dev_ops = { 
1203     .init = keyboard_init_device, 
1204     .deinit = keyboard_deinit_device,
1205     .reset = keyboard_reset_device,
1206     .start = keyboard_start_device,
1207     .stop = keyboard_stop_device,
1208 };
1209
1210
1211
1212
1213 struct vm_device * v3_create_keyboard() {
1214     struct keyboard_internal * keyboard_state = NULL;
1215
1216     keyboard_state = (struct keyboard_internal *)V3_Malloc(sizeof(struct keyboard_internal));
1217
1218     struct vm_device *device = v3_create_device("KEYBOARD", &dev_ops, keyboard_state);
1219
1220
1221     return device;
1222 }