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.


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