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.


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