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.


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