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 locking operations to devices interfacing with host events
[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 #include <palacios/vmm_lock.h>
25
26
27 #ifndef DEBUG_KEYBOARD
28 #undef PrintDebug
29 #define PrintDebug(fmt, args...)
30 #endif
31
32 #define KEYBOARD_DEBUG_80H   0
33
34
35
36 #define KEYBOARD_60H          0x60  // keyboard microcontroller
37 #define KEYBOARD_64H          0x64  // onboard microcontroller
38
39 #define KEYBOARD_DELAY_80H    0x80  // written for timing
40
41 #define KEYBOARD_IRQ          0x1
42 #define MOUSE_IRQ             0xc   
43
44
45 // extract bits for status byte
46 #define STATUS_OUTPUT_BUFFER_FULL   0x01  // 1=full (data for system)
47 #define STATUS_INPUT_BUFFER_FULL    0x02  // 1=full (data for 8042)
48 #define STATUS_SYSTEM               0x04  // 1=self-test-passed
49 #define STATUS_COMMAND_DATA_AVAIL   0x08  // internal: 0=data on 60h, 0=cmd on 64h
50 #define STATUS_ENABLED              0x10  // 1=keyboard is enabled
51 #define STATUS_MOUSE_BUFFER_FULL    0x20  // 1= mouse output buffer full
52 #define STATUS_TIMEOUT              0x40  // 1=timeout of keybd
53 #define STATUS_PARITY               0x80  // 1=parity error
54
55 // bits for cmd byte
56
57 #define CMD_INTR                0x01  // 1=interrupts enabled
58 #define CMD_MOUSE_INTR          0x02  // 1=interrupts enabled for mouse
59 #define CMD_SYSTEM              0x04  // 1= self test passed
60 #define CMD_OVERRIDE            0x08  // FORCE 0 for  PS2
61 #define CMD_DISABLE             0x10  // 1=disabled keyboard
62 #define CMD_MOUSE_DISABLE       0x20  // 1=disabled mouse
63 #define CMD_SCANCODE_XLATE      0x40  // 1=translate to set 1 scancodes
64 #define CMD_RESERVED            0x80  // should be zero
65
66 // bits for the output port 
67
68
69 #define OUTPUT_RESET        0x01  // System reset on 0
70 #define OUTPUT_A20          0x02  // A20 gate (1= A20 is gated)
71 #define OUTPUT_RES1         0x04  // reserved
72 #define OUTPUT_RES2         0x08  // reserved
73 #define OUTPUT_OUTPUT_FULL  0x10  // output buffer full
74 #define OUTPUT_INPUT_EMPTY  0x20  // input buffer empty
75 #define OUTPUT_KBD_CLOCK    0x40  // keyboard clock (?)
76 #define OUTPUT_KBD_DATA     0x80  // keyboard data
77
78 // bits for the input port
79
80 #define INPUT_RES0          0x01  // reserved
81 #define INPUT_RES1          0x02  // reserved
82 #define INPUT_RES2          0x04  // reserved
83 #define INPUT_RES3          0x08  // reserved
84 #define INPUT_RAM           0x10  // set to 1 if RAM exists?
85 #define INPUT_JUMPER        0x20  // manufacturing jumper?
86 #define INPUT_DISPLAY       0x40  // 0=color, 1=mono
87 #define INPUT_KBD_INHIBIT   0x80  // 1=inhibit keyboard ?
88
89
90 // for queue operations
91 #define QUEUE               0
92 #define OVERWRITE           1
93
94 // for queue operations - whether it's data or cmd waiting on 60h
95 #define DATA                0
96 #define COMMAND             1
97
98 // for queue operations - whether this is keyboard or mouse data on 60h
99 #define KEYBOARD            0
100 #define MOUSE               1
101
102
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         // After the Keyboard LEDs are enabled
152         // we wait for the output byte on 64?
153         SET_LEDS,
154         // After the Keyboard SET_RATE is called
155         // we wait for the output byte on 64?
156         SET_RATE,
157         // The keyboard requests an ID which 
158         // generates 3 bytes of output...
159         KBD_ID1,
160         KBD_ID2,
161         
162         
163     } state;
164
165
166     enum {
167         // after receiving a mouse command 0f 0xff
168         // we return the ack and then the next thing will be the 
169         // bat code (aa - success)
170         RESET1,
171         // followed by the device id (00 - mouse)
172         RESET2, 
173         // Then it goes into stream mode
174         STREAM1,  //
175         STREAM2,  //
176         STREAM3,  // for each of the following bytes in mouse_packet
177         // this is used for setting sample rate
178         SAMPLE1,  
179         // this is used for getting device id
180         DEVICE1, 
181         // just like the stream moes
182         REMOTE1,
183         REMOTE2,
184         REMOTE3,
185         // For getting status info
186         STATUS1,
187         STATUS2,
188         STATUS3, 
189         // set resolution
190         SETRES1,
191     } mouse_state;
192
193
194     uchar_t wrap;             
195     uchar_t mouse_packet[3];  // byte 1: y over, xover, y sign, x sign, 1, middle, right, left
196     // byte 2: x movement
197     // byte 3: y movement
198
199     uchar_t mouse_needs_ack;  //
200     uchar_t mouse_done_after_ack; 
201
202     uchar_t cmd_byte;         //  for keyboard uC - read/written 
203     //     via read/write cmd byte command
204     uchar_t status_byte;      //  for on-board uC - read via 64h
205
206     uchar_t output_byte;      //  output port of onboard uC (e.g. A20)
207
208     uchar_t input_byte;       //  input port of onboard uC
209
210     // Data for system
211     uchar_t output_queue;     //  
212     uint_t  output_queue_len; //  
213     //uint_t  output_queue_read;
214     //uint_t  output_queue_write;
215
216     v3_lock_t kb_lock;
217
218 };
219
220
221 static int keyboard_interrupt(struct vm_device * dev, uint_t irq) {
222     struct keyboard_internal *state = (struct keyboard_internal *)(dev->private_data);
223
224     PrintDebug("keyboard: interrupt 0x%x\n", irq);
225
226     if (state->cmd_byte & CMD_INTR) { 
227         v3_raise_irq(dev->vm, irq);
228     }
229
230     return 0;
231 }
232
233
234
235 // 
236 // push item onto outputqueue, optionally overwriting if there is no room
237 // returns 0 if successful
238 //
239 static int PushToOutputQueue(struct vm_device * dev, uchar_t value, uchar_t overwrite, uchar_t cmd, uchar_t mouse) 
240 {
241     struct keyboard_internal *state = (struct keyboard_internal *)(dev->private_data);
242   
243     if ((state->output_queue_len == 0) || overwrite) { 
244     
245         state->output_queue = value;
246         state->output_queue_len = 1;
247     
248         if (cmd) {
249             state->status_byte |= STATUS_COMMAND_DATA_AVAIL;
250         } else {
251             state->status_byte &= ~STATUS_COMMAND_DATA_AVAIL;
252         }
253     
254         if (mouse) { 
255             state->status_byte |= STATUS_MOUSE_BUFFER_FULL;
256             keyboard_interrupt(dev, MOUSE_IRQ);
257         } else {
258             keyboard_interrupt(dev, KEYBOARD_IRQ);
259         }
260
261         state->status_byte |= STATUS_OUTPUT_BUFFER_FULL;
262
263         return 0;
264
265     } else {
266         PrintError("keyboard: PushToOutputQueue Failed - Queue Full\n");
267         return -1;
268     }
269 }
270
271
272 // 
273 // pull item from outputqueue 
274 // returns 0 if successful
275 //
276 static int PullFromOutputQueue(struct vm_device * dev, uchar_t * value) 
277 {
278     struct keyboard_internal *state = (struct keyboard_internal *)(dev->private_data);
279
280     if (1 || (state->output_queue_len == 1)) { 
281
282         *value = state->output_queue;
283         state->output_queue_len = 0;
284     
285         if (state->status_byte & STATUS_OUTPUT_BUFFER_FULL) { 
286             state->status_byte &= ~STATUS_OUTPUT_BUFFER_FULL;
287         } 
288     
289         if (state->status_byte & STATUS_MOUSE_BUFFER_FULL) { 
290             state->status_byte &= ~STATUS_MOUSE_BUFFER_FULL;
291         }
292     
293         if (state->status_byte & STATUS_COMMAND_DATA_AVAIL) { 
294             state->status_byte &= ~STATUS_COMMAND_DATA_AVAIL;
295         } // reset to data
296     
297     
298         return 0;
299     } else {
300         PrintError("keyboard: PullFromOutputQueue Failed - Queue Empty\n");
301         return -1;
302     }
303 }
304
305
306
307
308 static int key_event_handler(struct guest_info * info, 
309                              struct v3_keyboard_event * evt, 
310                              void * private_data) {
311     struct vm_device * dev = (struct vm_device *)private_data;
312     struct keyboard_internal *state = (struct keyboard_internal *)(dev->private_data);
313
314     PrintDebug("keyboard: injected status 0x%x, and scancode 0x%x\n", evt->status, evt->scan_code);
315
316     if (evt->scan_code == 0x44) { // F10 debug dump
317         v3_print_guest_state(info);
318         //      PrintGuestPageTables(info, info->shdw_pg_state.guest_cr3);
319     }
320
321     addr_t irq_state = v3_lock_irqsave(state->kb_lock);
322
323     if ( (state->status_byte & STATUS_ENABLED)      // onboard is enabled
324          && (!(state->cmd_byte & CMD_DISABLE)) )  {   // keyboard is enabled
325     
326         PushToOutputQueue(dev, evt->scan_code, OVERWRITE, DATA, KEYBOARD);
327     }
328
329     v3_unlock_irqrestore(state->kb_lock, irq_state);
330   
331     return 0;
332 }
333
334
335 static int mouse_event_handler(struct guest_info * info, 
336                                struct v3_mouse_event * evt, 
337                                void * private_data) {
338     struct vm_device * dev = (struct vm_device *)private_data;
339     struct keyboard_internal * state = (struct keyboard_internal *)(dev->private_data);
340     int ret = 0;
341     PrintDebug("keyboard: injected mouse packet 0x %x %x %x\n",
342                evt->data[0], evt->data[1], evt->data[2]);
343   
344     addr_t irq_state = v3_lock_irqsave(state->kb_lock);
345
346     memcpy(state->mouse_packet, evt->data, 3);
347   
348     state->status_byte |= STATUS_MOUSE_BUFFER_FULL;
349   
350     
351     switch (state->mouse_state) { 
352         case STREAM1:
353         case STREAM2:
354         case STREAM3:
355             if (!(state->cmd_byte & CMD_MOUSE_DISABLE)) { 
356                 keyboard_interrupt(dev, MOUSE_IRQ);
357             }
358             break;
359         default:
360             PrintError("Invalid mouse state\n");
361             ret = -1;
362             break;
363     }
364
365
366     v3_unlock_irqrestore(state->kb_lock, irq_state);
367
368     return ret;
369 }
370
371
372 static int keyboard_reset_device(struct vm_device * dev)
373 {
374     struct keyboard_internal *data = (struct keyboard_internal *)(dev->private_data);
375   
376     memset(data, 0, sizeof(struct keyboard_internal));
377
378     data->state = NORMAL;
379     data->mouse_state = STREAM1;
380
381     data->cmd_byte =  
382         CMD_INTR          // interrupts on
383         | CMD_MOUSE_INTR  // mouse interupts on
384         | CMD_SYSTEM ;    // self test passed
385     // PS2, keyboard+mouse enabled, generic translation    
386   
387     data->status_byte = 
388         STATUS_SYSTEM       // self-tests passed
389         | STATUS_ENABLED ;  // keyboard ready
390     // buffers empty, no errors
391
392     data->output_byte = 0;  //  ?
393
394     data->input_byte = INPUT_RAM;  // we have some
395     // also display=color, jumper 0, keyboard enabled 
396
397   
398
399     PrintDebug("keyboard: reset device\n");
400  
401     return 0;
402
403 }
404
405
406
407 static int keyboard_start_device(struct vm_device *dev)
408 {
409     PrintDebug("keyboard: start device\n");
410     return 0;
411 }
412
413
414 static int keyboard_stop_device(struct vm_device *dev)
415 {
416     PrintDebug("keyboard: stop device\n");
417     return 0;
418 }
419
420
421 static int mouse_read_input(struct vm_device *dev)
422 {
423     struct keyboard_internal *state = (struct keyboard_internal *)(dev->private_data);
424
425     if (state->mouse_needs_ack) { 
426         state->mouse_needs_ack = 0;
427
428         // the ack has been stuffed previously
429         if (state->mouse_done_after_ack) { 
430             return 1;
431         } else {
432             return 0;
433         }
434     }
435
436     switch (state->mouse_state) { 
437
438         case RESET1: // requesting the BAT code
439             PushToOutputQueue(dev, 0xaa, OVERWRITE, DATA, MOUSE) ;  // BAT successful
440             PrintDebug(" mouse sent BAT code (sucesssful) ");
441             state->mouse_state = RESET2;
442
443             return 0;  // not done with mouse processing yet
444             break;
445
446         case RESET2: // requesting the device id
447             PushToOutputQueue(dev, 0x00, OVERWRITE, DATA, MOUSE) ;  // normal mouse type
448             PrintDebug(" mouse sent device id ");
449             state->mouse_state = STREAM1;
450
451             return 1;  // done with mouse processing 
452             break;
453
454         case STREAM1: // send data
455             PushToOutputQueue(dev, state->mouse_packet[0], OVERWRITE, DATA, MOUSE); 
456             PrintDebug(" mouse sent stream data1 ");
457             state->mouse_state = STREAM2;
458
459             return 0;
460             break;
461
462         case STREAM2: // send data
463             PushToOutputQueue(dev, state->mouse_packet[1], OVERWRITE, DATA, MOUSE); 
464             PrintDebug(" mouse sent stream data2 ");
465             state->mouse_state = STREAM3;
466
467             return 0;
468             break;
469
470         case STREAM3: // send data
471             PushToOutputQueue(dev, state->mouse_packet[2], OVERWRITE, DATA, MOUSE); 
472             PrintDebug(" mouse sent stream data3 ");
473             state->mouse_state = STREAM1;
474
475             return 1; // now done
476             break;
477
478         case REMOTE1: // send data
479             PushToOutputQueue(dev, state->mouse_packet[0], OVERWRITE, DATA, MOUSE); 
480             PrintDebug(" mouse sent remote data1 ");
481             state->mouse_state = REMOTE2;
482
483             return 0;
484             break;
485
486         case REMOTE2: // send data
487             PushToOutputQueue(dev, state->mouse_packet[1], OVERWRITE, DATA, MOUSE); 
488             PrintDebug(" mouse sent remote data2 ");
489             state->mouse_state = REMOTE3;
490
491             return 0;
492             break;
493
494         case REMOTE3: // send data
495             PushToOutputQueue(dev, state->mouse_packet[2], OVERWRITE, DATA, MOUSE); 
496             PrintDebug(" mouse sent remote data3 ");
497             state->mouse_state = REMOTE1;
498
499             return 1; // now done
500             break;
501
502         case STATUS1: // send data
503             PushToOutputQueue(dev, 0x0, OVERWRITE, DATA, MOUSE); 
504             PrintDebug(" mouse sent status data1 ");
505             state->mouse_state = STATUS2;
506
507             return 0;
508             break;
509
510         case STATUS2: // send data
511             PushToOutputQueue(dev, 0x0, OVERWRITE, DATA, MOUSE); 
512             PrintDebug(" mouse sent status data2 ");
513             state->mouse_state = STATUS3;
514
515             return 0;
516             break;
517
518         case STATUS3: // send data
519             PushToOutputQueue(dev, 0x0, OVERWRITE, DATA, MOUSE); 
520             PrintDebug(" mouse sent status data3 ");
521             state->mouse_state = STREAM1;
522
523             return 1; // now done
524             break;
525
526         case DEVICE1: // send device id
527             PushToOutputQueue(dev, 0x0, OVERWRITE, DATA, MOUSE); 
528             PrintDebug(" mouse sent device id ");
529             state->mouse_state = STREAM1;
530
531             return 1; // now done
532             break;
533
534         default:
535             PrintDebug(" mouse has no data ");
536             return 1; // done
537             break;
538     }
539 }
540
541 static int mouse_write_output(struct vm_device * dev, uchar_t data)
542 {
543     struct keyboard_internal * state = (struct keyboard_internal *)(dev->private_data);
544
545     switch (state->mouse_state) { 
546         case STREAM1:
547         case STREAM2:
548         case STREAM3:
549         case REMOTE1:
550         case REMOTE2:
551         case REMOTE3:
552             switch (data) {
553
554                 case 0xff: //reset
555                     PushToOutputQueue(dev, 0xfe, OVERWRITE, DATA, MOUSE) ;   // no mouse!
556                     PrintDebug(" mouse reset begins (no mouse) ");
557
558                     return 1;  // not done;
559                     break;
560
561                     /*
562                       case 0xff: //reset
563                       PushToOutputQueue(dev,0xfa,OVERWRITE,DATA,MOUSE) ; 
564                       PrintDebug(" mouse reset begins ");
565                       state->mouse_done_after_ack=0;
566                       state->mouse_needs_ack=1;
567                       state->mouse_state=RESET1;
568                       return 0;  // not done;
569                       break;
570                     */
571                 case 0xfe: //resend
572                     PushToOutputQueue(dev, 0xfa, OVERWRITE, DATA, MOUSE) ; 
573                     PrintDebug(" mouse resend begins ");
574                     state->mouse_done_after_ack = 0;
575                     state->mouse_needs_ack = 0;
576                     state->mouse_state = STREAM1;
577                     return 0;  // not done
578                     break;
579       
580                 case 0xf6: // set defaults
581                     PushToOutputQueue(dev, 0xfa, OVERWRITE, DATA, MOUSE) ; 
582                     PrintDebug(" mouse set defaults ");
583                     state->mouse_done_after_ack = 1;
584                     state->mouse_needs_ack = 1;
585                     state->mouse_state = STREAM1;
586                     return 0; // not done
587                     break;
588       
589                 case 0xf5: // disable data reporting 
590                     PushToOutputQueue(dev, 0xfa, OVERWRITE, DATA, MOUSE) ; 
591                     state->mouse_done_after_ack = 1;
592                     state->mouse_needs_ack = 1;
593                     PrintDebug(" mouse disable data reporting ");
594                     state->mouse_state = STREAM1;
595                     return 0; // not done
596                     break;
597       
598                 case 0xf4: // enable data reporting 
599                     PushToOutputQueue(dev, 0xfa, OVERWRITE, DATA, MOUSE) ; 
600                     state->mouse_done_after_ack = 1;
601                     state->mouse_needs_ack = 1;
602                     PrintDebug(" mouse enable data reporting ");
603                     state->mouse_state = STREAM1;
604                     return 0; // not done
605                     break;
606       
607                 case 0xf3: // set sample rate
608                     PushToOutputQueue(dev, 0xfa, OVERWRITE, DATA, MOUSE) ; 
609                     state->mouse_done_after_ack = 0;
610                     state->mouse_needs_ack = 1;
611                     PrintDebug(" mouse set sample rate begins ");
612                     state->mouse_state = SAMPLE1;
613                     return 0; // not done
614                     break;
615       
616                 case 0xf2: // get device id
617                     PushToOutputQueue(dev, 0xfa, OVERWRITE, DATA, MOUSE) ; 
618                     state->mouse_done_after_ack = 0;
619                     state->mouse_needs_ack = 1;
620                     PrintDebug(" mouse get device id begins ");
621                     state->mouse_state = DEVICE1;
622                     return 0; // not done
623                     break;
624       
625                 case 0xf0: // set remote mode
626                     PushToOutputQueue(dev, 0xfa, OVERWRITE, DATA, MOUSE) ; 
627                     state->mouse_done_after_ack = 1;
628                     state->mouse_needs_ack = 1;
629                     PrintDebug(" mouse set remote mode  ");
630                     state->mouse_state = REMOTE1;
631                     return 0; // not done
632                     break;
633
634                 case 0xee: // set wrap mode
635                     PushToOutputQueue(dev, 0xfa, OVERWRITE, DATA, MOUSE) ; 
636                     state->mouse_done_after_ack = 1;
637                     state->mouse_needs_ack = 1;
638                     PrintDebug(" mouse set wrap mode (ignored)  ");
639                     state->mouse_state = STREAM1;
640                     return 0; // not done
641                     break;
642
643                 case 0xec: // reset wrap mode
644                     PushToOutputQueue(dev, 0xfa, OVERWRITE, DATA, MOUSE) ; 
645                     state->mouse_done_after_ack = 1;
646                     state->mouse_needs_ack = 1;
647                     PrintDebug(" mouse reset wrap mode (ignored)  ");
648                     state->mouse_state = STREAM1;
649                     return 0; // done
650                     break;
651
652                 case 0xeb: // read data
653                     PushToOutputQueue(dev, 0xfa, OVERWRITE, DATA, MOUSE) ; 
654                     state->mouse_done_after_ack = 0;
655                     state->mouse_needs_ack = 1;
656                     PrintDebug(" mouse switch to wrap mode (ignored)  ");
657                     state->mouse_state = REMOTE1;
658                     return 0; // not done
659                     break;
660       
661                 case 0xea: // set stream mode
662                     PushToOutputQueue(dev, 0xfa, OVERWRITE, DATA, MOUSE) ; 
663                     state->mouse_done_after_ack = 1;
664                     state->mouse_needs_ack = 1;
665                     PrintDebug(" mouse set stream mode  ");
666                     state->mouse_state = STREAM1;
667                     return 0; // not done
668                     break;
669
670                 case 0xe9: // status request
671                     PushToOutputQueue(dev, 0xfa, OVERWRITE, DATA, MOUSE) ; 
672                     state->mouse_done_after_ack = 0;
673                     state->mouse_needs_ack = 1;
674                     PrintDebug(" mouse status request begins  ");
675                     state->mouse_state = STATUS1;
676                     return 0; // notdone
677                     break;
678
679                 case 0xe8: // set resolution
680                     PushToOutputQueue(dev, 0xfa, OVERWRITE, DATA, MOUSE) ; 
681                     state->mouse_done_after_ack = 0;
682                     state->mouse_needs_ack = 1;
683                     PrintDebug(" mouse set resolution begins  ");
684                     state->mouse_state = SETRES1;
685                     return 0; // notdone
686                     break;
687
688                 case 0xe7: // set scaling 2:1
689                     PushToOutputQueue(dev, 0xfa, OVERWRITE, DATA, MOUSE) ; 
690                     state->mouse_done_after_ack = 1;
691                     state->mouse_needs_ack = 1;
692                     PrintDebug(" mouse set scaling 2:1 ");
693                     state->mouse_state = STREAM1;
694                     return 0; // not done
695                     break;
696
697                 case 0xe6: // set scaling 1:1
698                     PushToOutputQueue(dev, 0xfa, OVERWRITE, DATA, MOUSE) ; 
699                     state->mouse_done_after_ack = 1;
700                     state->mouse_needs_ack = 1;
701                     PrintDebug(" mouse set scaling 1:1 ");
702                     state->mouse_state = STREAM1;
703                     return 0; // done
704                     break;
705       
706                 default:
707                     PrintDebug(" receiving unknown mouse command (0x%x) in acceptable state ", data);
708                     return 1; // done
709                     break;
710
711             }
712     
713         default:
714             PrintDebug(" receiving mouse output in unhandled state (0x%x) ", state->mouse_state);
715             break;
716             return 1; // done?
717             break;
718     }
719
720     PrintDebug(" HUH? ");
721     return 1; // done
722 }
723
724
725
726 #if KEYBOARD_DEBUG_80H
727 static int keyboard_write_delay(ushort_t port,
728                                 void * src, 
729                                 uint_t length,
730                                 struct vm_device * dev)
731 {
732
733     if (length == 1) { 
734         PrintDebug("keyboard: write of 0x%x to 80h\n", *((uchar_t*)src));
735
736         return 1;
737     } else {
738         PrintDebug("keyboard: write of >1 byte to 80h\n", *((uchar_t*)src));
739
740         return length;
741     }
742 }
743
744 static int keyboard_read_delay(ushort_t port,
745                                void * dest, 
746                                uint_t length,
747                                struct vm_device * dev)
748 {
749
750     if (length == 1) { 
751         *((uchar_t*)dest) = v3_inb(port);
752
753         PrintDebug("keyboard: read of 0x%x from 80h\n", *((uchar_t*)dest));
754
755         return 1;
756     } else {
757         PrintDebug("keyboard: read of >1 byte from 80h\n");
758
759         return length;
760     }
761 }
762 #endif
763     
764   
765
766
767
768 static int keyboard_write_command(ushort_t port,
769                                   void * src, 
770                                   uint_t length,
771                                   struct vm_device * dev)
772 {
773     struct keyboard_internal *state = (struct keyboard_internal *)(dev->private_data);
774     uchar_t cmd;
775
776     // Should always be single byte write
777
778     if (length != 1) { 
779         PrintError("keyboard: write of >1 bytes (%d) to 64h\n", length);
780         return -1;
781     }
782
783     cmd = *((uchar_t*)src); 
784
785
786     addr_t irq_state = v3_lock_irqsave(state->kb_lock);
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     v3_unlock_irqrestore(state->kb_lock, irq_state);
966
967     return length;
968 }
969
970 static int keyboard_read_status(ushort_t port,
971                                 void * dest, 
972                                 uint_t length,
973                                 struct vm_device * dev)
974 {
975     struct keyboard_internal *state = (struct keyboard_internal *)(dev->private_data);
976
977     if (length != 1) { 
978         PrintError("keyboard: >1 byte read for status (64h)\n");
979         return -1;
980     }
981
982
983     PrintDebug("keyboard: read status (64h): ");
984
985     addr_t irq_state = v3_lock_irqsave(state->kb_lock);
986     *((uchar_t*)dest) = state->status_byte;
987     v3_unlock_irqrestore(state->kb_lock, irq_state);
988     
989     PrintDebug("0x%x\n", *((uchar_t*)dest));
990     
991     return length;
992 }
993
994 static int keyboard_write_output(ushort_t port,
995                                  void * src, 
996                                  uint_t length,
997                                  struct vm_device * dev)
998 {
999     struct keyboard_internal *state = (struct keyboard_internal *)(dev->private_data);
1000     int ret = 0;
1001
1002     if (length != 1) { 
1003         PrintError("keyboard: write of 60h with >1 byte\n");
1004         return -1;
1005     }
1006
1007     uchar_t data = *((uchar_t*)src);
1008   
1009     PrintDebug("keyboard: output 0x%x on 60h\n", data);
1010
1011     addr_t irq_state = v3_lock_irqsave(state->kb_lock);
1012
1013     switch (state->state) {
1014         case WRITING_CMD_BYTE:
1015             state->cmd_byte = data;
1016             state->state = NORMAL;
1017             PrintDebug("keyboard: wrote new command byte 0x%x\n", state->cmd_byte);
1018             break;
1019         case WRITING_OUTPUT_PORT:
1020             state->output_byte = data;
1021             state->state = NORMAL;
1022             PrintDebug("keyboard: wrote new output byte 0x%x\n", state->output_byte);
1023             break;
1024         case INJECTING_KEY:
1025             PushToOutputQueue(dev, data, OVERWRITE, COMMAND, KEYBOARD);  // probably should be a call to deliver_key_to_vmm()
1026             state->state = NORMAL;
1027             PrintDebug("keyboard: injected key 0x%x\n", data);
1028             break;
1029         case INJECTING_MOUSE:
1030             PushToOutputQueue(dev, data, OVERWRITE, DATA, MOUSE);
1031             //      PrintDebug("keyboard: ignoring injected mouse event 0x%x\n", data);
1032             PrintDebug("keyboard: injected mouse event 0x%x\n", data);
1033             state->state = NORMAL;
1034             break;
1035         case IN_MOUSE:
1036             PrintDebug("keyboard: mouse action: ");
1037             if (mouse_write_output(dev, data)) { 
1038                 state->state = NORMAL;
1039             }
1040             PrintDebug("\n");
1041             break;
1042         case TRANSMIT_PASSWD:
1043             if (data) {
1044                 //ignore passwd
1045                 PrintDebug("keyboard: ignoring password character 0x%x\n",data);
1046             } else {
1047                 // end of password
1048                 state->state = NORMAL;
1049                 PrintDebug("keyboard: done with password\n");
1050             }
1051             break;
1052         case SET_LEDS:
1053             PrintDebug("Keyboard: LEDs being set...\n");
1054             PushToOutputQueue(dev, 0xfa, OVERWRITE, COMMAND, KEYBOARD);
1055             state->state = NORMAL;
1056             break;
1057         case SET_RATE:
1058             PrintDebug("Keyboard: Rate being set...\n");
1059             PushToOutputQueue(dev, 0xfa, OVERWRITE, COMMAND, KEYBOARD);
1060             state->state = NORMAL;
1061             break;
1062         default:
1063         case NORMAL:
1064             {
1065                 // command is being sent to keyboard controller
1066                 switch (data) { 
1067                     case 0xff: // reset
1068                         PushToOutputQueue(dev, 0xfa, OVERWRITE, COMMAND, KEYBOARD); // ack
1069                         state->state = RESET;
1070                         PrintDebug("keyboard: reset complete and acked\n");
1071                         break;
1072                     case 0xf5: // disable scanning
1073                     case 0xf4: // enable scanning
1074                         // ack
1075                         PushToOutputQueue(dev, 0xfa, OVERWRITE, COMMAND, KEYBOARD);
1076                         // should do something here... PAD
1077                         state->state = NORMAL;
1078                         PrintDebug("keyboard: %s scanning done and acked\n", (data == 0xf5) ? "disable" : "enable");
1079                         break;
1080                     case 0xf3:
1081                         PushToOutputQueue(dev, 0xfa, OVERWRITE, COMMAND, KEYBOARD);
1082                         state->state = SET_RATE;
1083                         break;
1084                     case 0xf2: // get keyboard ID
1085                         PushToOutputQueue(dev, 0xfa, OVERWRITE, COMMAND, KEYBOARD);
1086                         state->state = KBD_ID1;
1087                         PrintDebug("Keyboard: Requesting Keyboard ID\n");
1088
1089                         //PushToOutputQueue(dev, 0xab, OVERWRITE, COMMAND, KEYBOARD);
1090                         //state->state = KBD_ID2;
1091                         break;
1092                     case 0xed: // enable keyboard LEDs
1093                         PushToOutputQueue(dev, 0xfa, OVERWRITE, COMMAND, KEYBOARD);
1094                         state->state = SET_LEDS;
1095                         break;
1096                     case 0xfe: // resend
1097                     case 0xfd: // set key type make
1098                     case 0xfc: // set key typ make/break
1099                     case 0xfb: // set key type typematic
1100                     case 0xfa: // set all typematic make/break/typematic
1101                     case 0xf9: // set all make
1102                     case 0xf8: // set all make/break
1103                     case 0xf7: // set all typemaktic
1104                     case 0xf6: // set defaults
1105                         PrintError("keyboard: unhandled known command 0x%x on output buffer (60h)\n", data);
1106
1107                         ret = -1;
1108                         break;
1109                     default:
1110                         PrintError("keyboard: unhandled unknown command 0x%x on output buffer (60h)\n", data);
1111                         state->status_byte |= 0x1;
1112
1113                         ret = -1;
1114                         break;
1115                 }
1116                 break;
1117             }
1118
1119     }
1120   
1121     v3_unlock_irqrestore(state->kb_lock, irq_state);
1122
1123     if (ret == -1) {
1124         return -1;
1125     }
1126
1127     return length;
1128 }
1129
1130 static int keyboard_read_input(ushort_t port,
1131                                void * dest, 
1132                                uint_t length,
1133                                struct vm_device * dev)
1134 {
1135
1136     uchar_t data;
1137     int done_mouse;
1138     struct keyboard_internal *state = (struct keyboard_internal *)(dev->private_data);
1139     
1140     if (length != 1) {
1141         PrintError("keyboard: unknown size read from input (60h)\n");
1142         return -1;
1143     }
1144     
1145     PrintDebug("keyboard: read from input (60h): ");
1146
1147     addr_t irq_state = v3_lock_irqsave(state->kb_lock);
1148
1149     if (state->state == IN_MOUSE) { 
1150         done_mouse = mouse_read_input(dev);
1151         if (done_mouse) { 
1152             state->state = NORMAL;
1153         }
1154     } 
1155       
1156     PullFromOutputQueue(dev, &data);
1157       
1158     if (state->state == RESET) { 
1159         // We just delivered the ack for the reset
1160         // now we will ready ourselves to deliver the BAT code (success)
1161         PushToOutputQueue(dev, 0xaa, OVERWRITE, COMMAND, KEYBOARD);
1162         state->state = NORMAL;
1163         PrintDebug(" (in reset, pushing BAT test code 0xaa) ");
1164     } else if (state->state == KBD_ID1) {
1165         PushToOutputQueue(dev, 0xab, OVERWRITE, COMMAND, KEYBOARD);
1166         state->state = KBD_ID2;
1167         PrintDebug(" (in kbd id request, pushing 1st ID val) ");
1168     } else if (state->state == KBD_ID2) {
1169         PushToOutputQueue(dev, 0x83, OVERWRITE, COMMAND, KEYBOARD);
1170         state->state = NORMAL;
1171         PrintDebug(" (in kbd id request, pushing 2nd ID val) ");
1172     }
1173
1174     v3_unlock_irqrestore(state->kb_lock, irq_state);
1175
1176     PrintDebug("0x%x\n", data);
1177
1178     *((uchar_t*)dest) = data;
1179
1180     return length;
1181
1182 }
1183
1184
1185
1186
1187
1188 static int keyboard_init_device(struct vm_device * dev) 
1189 {
1190  
1191     struct keyboard_internal *data = (struct keyboard_internal *) dev->private_data;
1192
1193     PrintDebug("keyboard: init_device\n");
1194
1195     keyboard_reset_device(dev);
1196
1197
1198     v3_lock_init(&(data->kb_lock));
1199
1200
1201     // hook ports
1202     v3_dev_hook_io(dev, KEYBOARD_64H, &keyboard_read_status, &keyboard_write_command);
1203     v3_dev_hook_io(dev, KEYBOARD_60H, &keyboard_read_input, &keyboard_write_output);
1204
1205     v3_hook_host_event(dev->vm, HOST_KEYBOARD_EVT, V3_HOST_EVENT_HANDLER(key_event_handler), dev);
1206     v3_hook_host_event(dev->vm, HOST_MOUSE_EVT, V3_HOST_EVENT_HANDLER(mouse_event_handler), dev);
1207
1208
1209 #if KEYBOARD_DEBUG_80H
1210     v3_dev_hook_io(dev, KEYBOARD_DELAY_80H, &keyboard_read_delay, &keyboard_write_delay);
1211 #endif
1212
1213   
1214     //
1215     // We do not hook the IRQ here.  Instead, the underlying device driver
1216     // is responsible to call us back
1217     // 
1218
1219     return 0;
1220 }
1221
1222 static int keyboard_deinit_device(struct vm_device *dev)
1223 {
1224
1225     v3_dev_unhook_io(dev, KEYBOARD_60H);
1226     v3_dev_unhook_io(dev, KEYBOARD_64H);
1227 #if KEYBOARD_DEBUG_80H
1228     v3_dev_unhook_io(dev, KEYBOARD_DELAY_80H);
1229 #endif
1230     keyboard_reset_device(dev);
1231     return 0;
1232 }
1233
1234
1235
1236
1237
1238 static struct vm_device_ops dev_ops = { 
1239     .init = keyboard_init_device, 
1240     .deinit = keyboard_deinit_device,
1241     .reset = keyboard_reset_device,
1242     .start = keyboard_start_device,
1243     .stop = keyboard_stop_device,
1244 };
1245
1246
1247
1248
1249 struct vm_device * v3_create_keyboard() {
1250     struct keyboard_internal * keyboard_state = NULL;
1251
1252     keyboard_state = (struct keyboard_internal *)V3_Malloc(sizeof(struct keyboard_internal));
1253
1254     struct vm_device *device = v3_create_device("KEYBOARD", &dev_ops, keyboard_state);
1255
1256
1257     return device;
1258 }