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.


large scale namespace changes
[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", data);
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", data);
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 }