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