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.


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