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.


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