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.


Phils updates to fix xml warnings and telemetry warnings (from devel->Release 1.2)
[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 <palacios/vmm.h>
21 #include <palacios/vmm_dev_mgr.h>
22 #include <palacios/vmm_types.h>
23
24 #include <palacios/vmm_ringbuffer.h>
25 #include <palacios/vmm_lock.h>
26 #include <palacios/vmm_intr.h>
27 #include <palacios/vmm_host_events.h>
28 #include <palacios/vm_guest.h>
29
30
31 #ifndef CONFIG_DEBUG_KEYBOARD
32 #undef PrintDebug
33 #define PrintDebug(fmt, args...)
34 #endif
35
36 #define KEYBOARD_DEBUG_80H   0
37
38
39
40 #define KEYBOARD_60H          0x60  // keyboard microcontroller
41 #define KEYBOARD_64H          0x64  // onboard microcontroller
42
43 #define KEYBOARD_DELAY_80H    0x80  // written for timing
44
45 #define KEYBOARD_IRQ          0x1
46 #define MOUSE_IRQ             0xc   
47
48
49
50 // bits for the output port 
51 #define OUTPUT_RESET        0x01  // System reset on 0
52 #define OUTPUT_A20          0x02  // A20 gate (1= A20 is gated)
53 #define OUTPUT_RES1         0x04  // reserved
54 #define OUTPUT_RES2         0x08  // reserved
55 #define OUTPUT_OUTPUT_FULL  0x10  // output buffer full
56 #define OUTPUT_INPUT_EMPTY  0x20  // input buffer empty
57 #define OUTPUT_KBD_CLOCK    0x40  // keyboard clock (?)
58 #define OUTPUT_KBD_DATA     0x80  // keyboard data
59
60 // bits for the input port
61
62 #define INPUT_RES0          0x01  // reserved
63 #define INPUT_RES1          0x02  // reserved
64 #define INPUT_RES2          0x04  // reserved
65 #define INPUT_RES3          0x08  // reserved
66 #define INPUT_RAM           0x10  // set to 1 if RAM exists?
67 #define INPUT_JUMPER        0x20  // manufacturing jumper?
68 #define INPUT_DISPLAY       0x40  // 0=color, 1=mono
69 #define INPUT_KBD_INHIBIT   0x80  // 1=inhibit keyboard ?
70
71
72 #define MOUSE_ACK           0xfa
73
74 // for queue operations
75 #define QUEUE               0
76 #define OVERWRITE           1
77
78 // for queue operations - whether it's data or cmd waiting on 60h
79 #define DATA                0
80 #define COMMAND             1
81
82 // for queue operations - whether this is keyboard or mouse data on 60h
83 #define KEYBOARD            0
84 #define MOUSE               1
85
86
87
88 struct cmd_reg {
89     union {
90         uint8_t val;
91         struct {
92             uint8_t irq_en        : 1;  // 1=interrupts enabled
93             uint8_t mouse_irq_en  : 1;  // 1=interrupts enabled for mouse
94             uint8_t self_test_ok  : 1;  // 1= self test passed
95             uint8_t override      : 1;  // MBZ for  PS2
96             uint8_t disable       : 1;  // 1=disabled keyboard
97             uint8_t mouse_disable : 1;  // 1=disabled mouse
98             uint8_t translate     : 1;  // 1=translate to set 1 scancodes (For PC Compatibility)
99             uint8_t rsvd          : 1;  // must be zero
100         } __attribute__((packed));
101     } __attribute__((packed));
102 } __attribute__((packed));
103
104
105
106
107 struct status_reg {
108     union {
109         uint8_t val;
110         struct {
111             uint8_t out_buf_full        : 1; // 1=full (data for system)
112             uint8_t in_buf_full         : 1; // 1=full (data for 8042)
113             uint8_t self_test_ok        : 1; // 1=self-test-passed
114             uint8_t cmd                 : 1; // 0=data on 60h, 1=cmd on 64h
115             uint8_t enabled             : 1; // 1=keyboard is enabled
116             uint8_t mouse_buf_full      : 1; // 1= mouse output buffer full
117             uint8_t timeout_err         : 1; // 1=timeout of keybd
118             uint8_t parity_err          : 1; // 1=parity error
119         } __attribute__((packed));
120     } __attribute__((packed));
121 } __attribute__((packed));
122
123
124
125
126
127
128 /* This QUEUE_SIZE must be 256 */
129 /* Its designed this way to cause the start/end index to automatically
130    wrap around (2^8 = 256) so an overrun will automatically readjust the 
131    indexes 
132 */
133 #define QUEUE_SIZE 256
134 struct queue {
135     uint8_t queue[QUEUE_SIZE];
136
137     uint8_t start;
138     uint8_t end;
139     int count;
140 };
141
142 struct keyboard_internal {
143     // 
144     // 0x60 is the port for the keyboard microcontroller
145     //   writes are commands
146     //   reads from it usually return scancodes
147     //   however, it can also return other data 
148     //   depending on the state of the onboard microcontroller
149     //
150     // 0x64 is the port for the onboard microcontroller
151     //   writes are commands
152     //   reads are status
153     //
154
155     // state of the onboard microcontroller
156     // this is needed because sometimes 0x60 reads come
157     // from the onboard microcontroller
158     enum {// Normal mode measn we deliver keys
159         // to the vm and accept commands from it
160         NORMAL,
161         // after receiving cmd 0x60
162         // keybaord uC cmd will subsequently arrive
163         WRITING_CMD_BYTE,  
164         // after recieving 0xa5
165         // password arrives on data port, null terminated
166         TRANSMIT_PASSWD,
167         // after having a d1 sent to 64
168         // we wait for a new output byte on 60
169         WRITING_OUTPUT_PORT,
170         // after having a d2 sent to 64
171         // we wait for a new output byte on 60
172         // then make it available as a keystroke
173         INJECTING_KEY,
174         // after having a d3 sent to 64
175         // we wait for a new output byte on 60
176         // then make it available as a mouse event
177         INJECTING_MOUSE,
178         // after having a d4 sent to 64
179         // we wait for a new output byte on 60
180         // then send it to the mouse
181         IN_MOUSE,
182         // After the Keyboard LEDs are enabled
183         // we wait for the output byte on 64?
184         SET_LEDS,
185         // After the Keyboard SET_RATE is called
186         // we wait for the output byte on 64?
187         SET_RATE,
188     } state;
189
190
191     enum {
192         // Normal mouse state
193         STREAM, 
194         // this is used for setting sample rate
195         SAMPLE,
196         // set resolution
197         SET_RES,
198     } mouse_state;
199
200
201
202     struct cmd_reg cmd;
203     struct status_reg status;
204
205     uint8_t output_byte;      //  output port of onboard uC (e.g. A20)
206     uint8_t input_byte;       //  input port of onboard uC
207
208     // Data for system
209     uint8_t wrap;     
210
211     int mouse_enabled;
212
213     struct queue kbd_queue;
214     struct queue mouse_queue;
215
216     v3_lock_t kb_lock;
217 };
218
219
220 static int update_kb_irq(struct vm_device * dev) {
221     struct keyboard_internal *state = (struct keyboard_internal *)(dev->private_data);
222     int irq_num = 0;
223
224
225     state->status.out_buf_full = 0;
226     state->status.mouse_buf_full = 0;
227
228
229     // If there is pending Keyboard data then it overrides mouse data
230     if (state->kbd_queue.count > 0) {
231         irq_num = KEYBOARD_IRQ;
232     } else if (state->mouse_queue.count > 0) {
233         irq_num = MOUSE_IRQ;
234         state->status.mouse_buf_full = 1;
235     } 
236     
237     PrintDebug("keyboard: interrupt 0x%d\n", irq_num);
238     
239     if (irq_num) {
240         // Global output buffer flag (for both Keyboard and mouse)
241         state->status.out_buf_full = 1;
242         
243         if (state->cmd.irq_en == 1) { 
244             v3_raise_irq(dev->vm, irq_num);
245         }
246     }
247
248     return 0;
249 }
250
251
252
253 /* Only one byte is read per irq 
254  * So if the queue is still full after a data read, we re-raise the irq
255  * If we keep reading an empty queue we return the last queue entry
256  */
257
258 static int push_to_output_queue(struct vm_device * dev, uint8_t value, uint8_t cmd, uint8_t mouse) {
259     struct keyboard_internal * state = (struct keyboard_internal *)(dev->private_data);
260     struct queue * q = NULL;
261
262
263     if (mouse) {
264         q = &(state->mouse_queue);
265     } else {
266         q = &(state->kbd_queue);
267     }
268
269     if (q->count == QUEUE_SIZE) {
270         return 0;
271     }
272
273     if (cmd) {
274         state->status.cmd = 1;
275     } else {
276         state->status.cmd = 0;
277     }
278
279     q->queue[q->end++] = value;
280     q->count++;
281
282
283     update_kb_irq(dev);
284
285     return 0;
286 }
287
288
289
290 static int pull_from_output_queue(struct vm_device * dev, uint8_t * value) {
291     struct keyboard_internal * state = (struct keyboard_internal *)(dev->private_data);
292     struct queue * q = NULL;
293
294     if (state->kbd_queue.count > 0) {
295         q = &(state->kbd_queue);
296         PrintDebug("Reading from Keyboard Queue\n");
297     } else if (state->mouse_queue.count > 0) {
298         q = &(state->mouse_queue);
299         PrintDebug("Reading from Mouse Queue\n");
300     } else {
301         uint8_t idx = state->kbd_queue.start - 1;
302         PrintDebug("No Data in any queue\n");
303         *value = state->kbd_queue.queue[idx];
304         return 0;
305     }
306
307     *value = q->queue[q->start++];
308     q->count--;
309
310
311     PrintDebug("Read from Queue: %x\n", *value);
312     PrintDebug("QStart=%d, QEnd=%d\n", q->start, q->end);
313
314     update_kb_irq(dev);
315
316     return 0;
317 }
318
319
320 #include <palacios/vmm_telemetry.h>
321
322
323 static int key_event_handler(struct guest_info * info, 
324                              struct v3_keyboard_event * evt, 
325                              void * private_data) {
326     struct vm_device * dev = (struct vm_device *)private_data;
327     struct keyboard_internal *state = (struct keyboard_internal *)(dev->private_data);
328
329     PrintDebug("keyboard: injected status 0x%x, and scancode 0x%x\n", evt->status, evt->scan_code);
330
331     if (evt->scan_code == 0x44) { // F10 debug dump
332         v3_print_guest_state(info);
333         //      PrintGuestPageTables(info, info->shdw_pg_state.guest_cr3);
334     } 
335 #ifdef CONFIG_SYMBIOTIC
336     else if (evt->scan_code == 0x43) { // F9 Sym test
337         PrintDebug("Testing sym call\n");
338         sym_arg_t a0 = 0x1111;
339         sym_arg_t a1 = 0x2222;
340         sym_arg_t a2 = 0x3333;
341         sym_arg_t a3 = 0x4444;
342         sym_arg_t a4 = 0x5555;
343
344         v3_sym_call5(info, SYMCALL_TEST, &a0, &a1, &a2, &a3, &a4);
345
346         V3_Print("Symcall  Test Returned arg0=%x, arg1=%x, arg2=%x, arg3=%x, arg4=%x\n",
347                  (uint32_t)a0, (uint32_t)a1, (uint32_t)a2, (uint32_t)a3, (uint32_t)a4);
348
349     } 
350 #endif
351     else if (evt->scan_code == 0x42) { // F8 debug toggle
352         extern int v3_dbg_enable;
353         
354         PrintDebug("Toggling Debugging\n");     
355         v3_dbg_enable ^= 1;
356     } else if (evt->scan_code == 0x41) { // F7 telemetry dump
357 #ifdef CONFIG_TELEMETRY
358     v3_print_telemetry(info);
359 #endif // CONFIG_TELEMTRY
360
361     }
362
363
364
365     addr_t irq_state = v3_lock_irqsave(state->kb_lock);
366
367     if ( (state->status.enabled == 1)      // onboard is enabled
368          && (state->cmd.disable == 0) )  {   // keyboard is enabled
369     
370         push_to_output_queue(dev, evt->scan_code, DATA, KEYBOARD);
371     }
372
373     v3_unlock_irqrestore(state->kb_lock, irq_state);
374   
375     return 0;
376 }
377
378
379 static int mouse_event_handler(struct guest_info * info, 
380                                struct v3_mouse_event * evt, 
381                                void * private_data) {
382     struct vm_device * dev = (struct vm_device *)private_data;
383     struct keyboard_internal * state = (struct keyboard_internal *)(dev->private_data);
384     int ret = 0;
385
386     PrintDebug("keyboard: injected mouse packet 0x %x %x %x\n",
387                evt->data[0], evt->data[1], evt->data[2]);
388   
389     addr_t irq_state = v3_lock_irqsave(state->kb_lock);
390
391     switch (state->mouse_state) { 
392         case STREAM:
393
394             if (state->cmd.mouse_disable == 0) {
395                 push_to_output_queue(dev, evt->data[0], DATA, MOUSE);
396                 push_to_output_queue(dev, evt->data[1], DATA, MOUSE);
397                 push_to_output_queue(dev, evt->data[2], DATA, MOUSE);
398             }
399             break;
400         default:
401             PrintError("Invalid mouse state\n");
402             ret = -1;
403             break;
404     }
405
406
407     v3_unlock_irqrestore(state->kb_lock, irq_state);
408
409     return ret;
410 }
411
412
413 static int keyboard_reset_device(struct vm_device * dev) {
414     struct keyboard_internal * data = (struct keyboard_internal *)(dev->private_data);
415   
416     memset(data, 0, sizeof(struct keyboard_internal));
417
418     data->state = NORMAL;
419     data->mouse_state = STREAM;
420
421
422     // PS2, keyboard+mouse enabled, generic translation    
423     data->cmd.val = 0;
424
425     data->cmd.irq_en = 1;
426     data->cmd.mouse_irq_en = 1;
427     data->cmd.self_test_ok = 1;
428     /** **/
429
430
431     // buffers empty, no errors
432     data->status.val = 0; 
433
434     data->status.self_test_ok = 1; // self-tests passed
435     data->status.enabled = 1;// keyboard ready
436     /** **/
437
438     
439     data->output_byte = 0;  //  ?
440
441     data->input_byte = INPUT_RAM;  // we have some
442     // also display=color, jumper 0, keyboard enabled 
443
444     PrintDebug("keyboard: reset device\n");
445  
446     return 0;
447
448 }
449
450
451
452 static int keyboard_start_device(struct vm_device * dev) {
453     PrintDebug("keyboard: start device\n");
454     return 0;
455 }
456
457
458 static int keyboard_stop_device(struct vm_device * dev) {
459     PrintDebug("keyboard: stop device\n");
460     return 0;
461 }
462
463
464
465 static int mouse_write_output(struct vm_device * dev, uint8_t data) {
466     struct keyboard_internal * state = (struct keyboard_internal *)(dev->private_data);
467
468     switch (state->mouse_state) { 
469         case NORMAL:
470             switch (data) {
471
472                 case 0xff: //reset
473                     if (state->mouse_enabled == 0) {
474                         push_to_output_queue(dev, 0xfe, DATA, MOUSE) ;   // no mouse!
475                     } else {
476                         push_to_output_queue(dev, MOUSE_ACK, DATA, MOUSE) ; 
477                         push_to_output_queue(dev, 0xaa, DATA, MOUSE) ; 
478                         push_to_output_queue(dev, 0x00, DATA, MOUSE) ; 
479                     }
480                     break;
481
482 /*              case 0xfe: //resend */
483 /*                  PushToOutputQueue(dev, 0xfa, OVERWRITE, DATA, MOUSE) ;  */
484 /*                  PrintDebug(" mouse resend begins "); */
485 /*                  state->mouse_done_after_ack = 0; */
486 /*                  state->mouse_needs_ack = 0; */
487 /*                  state->mouse_state = STREAM1; */
488 /*                  return 0;  // not done */
489 /*                  break; */
490       
491                 case 0xf6: // set defaults
492                     push_to_output_queue(dev, MOUSE_ACK, DATA, MOUSE) ; 
493                     PrintDebug(" mouse set defaults ");
494
495                     break;
496       
497                 case 0xf5: // disable data reporting 
498                     push_to_output_queue(dev, MOUSE_ACK, DATA, MOUSE) ; 
499                     PrintDebug(" mouse disable data reporting ");
500                     break;
501       
502                 case 0xf4: // enable data reporting 
503                     push_to_output_queue(dev, MOUSE_ACK, DATA, MOUSE) ; 
504                     PrintDebug(" mouse enable data reporting ");
505                     break;
506       
507                 case 0xf3: // set sample rate
508                     push_to_output_queue(dev, MOUSE_ACK, DATA, MOUSE) ; 
509                     state->mouse_state = SAMPLE;
510                     PrintDebug(" mouse set sample rate begins ");
511                     break;
512       
513                 case 0xf2: // get device id
514                     push_to_output_queue(dev, MOUSE_ACK, DATA, MOUSE) ; 
515                     push_to_output_queue(dev, 0x0,  DATA, MOUSE); 
516                     PrintDebug(" mouse get device id begins ");
517                     break;
518       
519                 case 0xf0: // set remote mode
520                     push_to_output_queue(dev, MOUSE_ACK, DATA, MOUSE) ; 
521                     PrintDebug(" mouse set remote mode  ");
522                     break;
523
524                 case 0xee: // set wrap mode
525                     push_to_output_queue(dev, MOUSE_ACK, DATA, MOUSE) ; 
526                     PrintError(" mouse set wrap mode (ignored)  ");
527                     break;
528
529                 case 0xec: // reset wrap mode
530                     push_to_output_queue(dev, MOUSE_ACK, DATA, MOUSE) ; 
531                     PrintError(" mouse reset wrap mode (ignored)  ");
532                     break;
533
534                 case 0xeb: // read data
535                     push_to_output_queue(dev, MOUSE_ACK, DATA, MOUSE) ; 
536                     PrintError(" mouse switch to wrap mode (ignored)  ");
537                     break;
538       
539                 case 0xea: // set stream mode
540                     push_to_output_queue(dev, MOUSE_ACK, DATA, MOUSE) ; 
541                     PrintDebug(" mouse set stream mode  ");
542                     break;
543
544                 case 0xe9: // status request
545                     push_to_output_queue(dev, MOUSE_ACK, DATA, MOUSE) ; 
546                     push_to_output_queue(dev, 0x00, DATA, MOUSE); 
547                     push_to_output_queue(dev, 0x00, DATA, MOUSE);
548                     push_to_output_queue(dev, 0x00, DATA, MOUSE); 
549                     PrintDebug(" mouse status request begins  ");
550                     break;
551
552                 case 0xe8: // set resolution
553                     push_to_output_queue(dev, MOUSE_ACK,  DATA, MOUSE) ; 
554                     PrintDebug(" mouse set resolution begins  ");
555                     state->mouse_state = SET_RES;
556                     break;
557
558                 case 0xe7: // set scaling 2:1
559                     push_to_output_queue(dev, MOUSE_ACK, DATA, MOUSE) ; 
560                     PrintDebug(" mouse set scaling 2:1 ");
561                     break;
562
563                 case 0xe6: // set scaling 1:1
564                     push_to_output_queue(dev, MOUSE_ACK, DATA, MOUSE) ; 
565                     PrintDebug(" mouse set scaling 1:1 ");
566                     break;
567       
568                 default:
569                     PrintDebug(" receiving unknown mouse command (0x%x) in acceptable state ", data);
570                     break;
571             }
572
573             break;
574         case SAMPLE:
575         case SET_RES:
576         default:
577             PrintDebug(" receiving mouse output in unhandled state (0x%x) ", state->mouse_state);
578             return -1;
579     }
580
581     return 0;
582 }
583
584
585
586 #if KEYBOARD_DEBUG_80H
587 static int keyboard_write_delay(ushort_t port, void * src,  uint_t length, struct vm_device * dev) {
588
589     if (length == 1) { 
590         PrintDebug("keyboard: write of 0x%x to 80h\n", *((uint8_t*)src));
591         return 1;
592     } else {
593         PrintDebug("keyboard: write of >1 byte to 80h\n", *((uint8_t*)src));
594         return length;
595     }
596 }
597
598 static int keyboard_read_delay(ushort_t port, void * dest, uint_t length, struct vm_device * dev) {
599
600     if (length == 1) { 
601         *(uint8_t *)dest = v3_inb(port);
602
603         PrintDebug("keyboard: read of 0x%x from 80h\n", *((uint8_t*)dest));
604
605         return 1;
606     } else {
607         PrintDebug("keyboard: read of >1 byte from 80h\n");
608
609         return length;
610     }
611 }
612 #endif
613     
614   
615
616
617
618 static int keyboard_write_command(ushort_t port, void * src, uint_t length, struct vm_device * dev) {
619     struct keyboard_internal * state = (struct keyboard_internal *)(dev->private_data);
620     uint8_t cmd = *(uint8_t *)src;
621
622     // Should always be single byte write
623     if (length != 1) { 
624         PrintError("keyboard: write of >1 bytes (%d) to 64h\n", length);
625         return -1;
626     }
627
628
629     addr_t irq_state = v3_lock_irqsave(state->kb_lock);
630
631     if (state->state != NORMAL) { 
632         PrintDebug("keyboard: warning - receiving command on 64h but state != NORMAL\n");
633     }
634   
635     PrintDebug("keyboard: command 0x%x on 64h\n", cmd);
636
637     switch (cmd) { 
638         case 0x20:  // READ COMMAND BYTE (returned in 60h)
639             push_to_output_queue(dev, state->cmd.val, COMMAND, KEYBOARD);
640             PrintDebug("keyboard: command byte 0x%x returned\n", state->cmd.val);
641             break;
642
643         case 0x60:  // WRITE COMMAND BYTE (read from 60h)
644             state->state = WRITING_CMD_BYTE; // we need to make sure we send the next 0x60 byte appropriately
645             PrintDebug("keyboard: prepare to write command byte\n");
646             break;
647
648             // case 0x90-9f - write to output port  (?)
649
650         case 0xa1: // Get version number
651             push_to_output_queue(dev, 0x00, COMMAND, KEYBOARD);
652             PrintDebug("keyboard: version number 0x0 returned\n");
653             break;
654
655         case 0xa4:  // is password installed?  send result to 0x60
656             // we don't support passwords
657             push_to_output_queue(dev, 0xf1, COMMAND, KEYBOARD);
658             PrintDebug("keyboard: password not installed\n");
659             break;
660
661         case 0xa5:  // new password will arrive on 0x60
662             state->state = TRANSMIT_PASSWD;
663             PrintDebug("keyboard: pepare to transmit password\n");
664             break;
665
666         case 0xa6:  // check passwd;
667             // since we do not support passwords, we will simply ignore this
668             // the implication is that any password check immediately succeeds 
669             // with a blank password
670             PrintDebug("keyboard: password check succeeded\n");
671             break;
672
673         case 0xa7:  // disable mouse
674             state->cmd.mouse_disable = 1;
675             PrintDebug("keyboard: mouse disabled\n");
676             break;
677
678         case 0xa8:  // enable mouse
679             state->cmd.mouse_disable = 0;
680             PrintDebug("keyboard: mouse enabled\n");
681             break;
682
683         case 0xa9:  // mouse interface test  (always succeeds)
684             push_to_output_queue(dev, 0x00, COMMAND, KEYBOARD);
685             PrintDebug("keyboard: mouse interface test succeeded\n");
686             break;
687
688         case 0xaa:  // controller self test (always succeeds)
689             push_to_output_queue(dev, 0x55, COMMAND, KEYBOARD);
690             PrintDebug("keyboard: controller self test succeeded\n");
691             break;
692
693         case 0xab:  // keyboard interface test (always succeeds)
694             push_to_output_queue(dev, 0, COMMAND, KEYBOARD);
695             PrintDebug("keyboard: keyboard interface test succeeded\n");
696             break;
697
698         case 0xad:  // disable keyboard
699             state->cmd.disable = 1;
700             PrintDebug("keyboard: keyboard disabled\n");
701             break;
702
703         case 0xae:  // enable keyboard
704             state->cmd.disable = 0;
705             PrintDebug("keyboard: keyboard enabled\n");
706             break;
707
708         case 0xaf:  // get version
709             push_to_output_queue(dev, 0x00, COMMAND, KEYBOARD);
710             PrintDebug("keyboard: version 0 returned \n");
711             break;
712
713         case 0xd0: // return microcontroller output on 60h
714             push_to_output_queue(dev, state->output_byte, COMMAND, KEYBOARD);
715             PrintDebug("keyboard: output byte 0x%x returned\n", state->output_byte);
716             break;
717
718         case 0xd1: // request to write next byte on 60h to the microcontroller output port
719             state->state = WRITING_OUTPUT_PORT;
720             PrintDebug("keyboard: prepare to write output byte\n");
721             break;
722
723         case 0xd2:  //  write keyboard buffer (inject key)
724             state->state = INJECTING_KEY;
725             PrintDebug("keyboard: prepare to inject key\n");
726             break;
727
728         case 0xd3: //  write mouse buffer (inject mouse)
729             state->state = INJECTING_MOUSE;
730             PrintDebug("keyboard: prepare to inject mouse\n");
731             break;
732
733         case 0xd4: // write mouse device (command to mouse?)
734             state->state = IN_MOUSE;
735             PrintDebug("keyboard: prepare to inject mouse command\n");
736             break;
737
738         case 0xc0: //  read input port 
739             push_to_output_queue(dev, state->input_byte, COMMAND, KEYBOARD);
740             PrintDebug("keyboard: input byte 0x%x returned\n", state->input_byte);
741             break;
742
743         case 0xc1:  //copy input port lsn to status msn
744             state->status.val &= 0x0f;
745             state->status.val |= (state->input_byte & 0xf) << 4;
746             PrintDebug("keyboard: copied input byte low 4 bits to status reg hi 4 bits\n");
747             break;
748
749         case 0xc2: // copy input port msn to status msn
750             state->status.val &= 0x0f;
751             state->status.val |= (state->input_byte & 0xf0);
752             PrintDebug("keyboard: copied input byte hi 4 bits to status reg hi 4 bits\n");
753             break;
754     
755         case 0xe0: // read test port
756             push_to_output_queue(dev, state->output_byte >> 6, COMMAND, KEYBOARD);
757             PrintDebug("keyboard: read 0x%x from test port\n", state->output_byte >> 6);
758             break;
759
760    
761         case 0xf0:   // pulse output port
762         case 0xf1:   // this should pulse 0..3 of cmd_byte on output port 
763         case 0xf2:   // instead of what is currently in output_byte (I think)
764         case 0xf3:   // main effect is taht if bit zero is zero
765         case 0xf4:   // should cause reset
766         case 0xf5:   // I doubt anything more recent than a 286 running 
767         case 0xf6:   // OS2 with the penalty box will care
768         case 0xf7:
769         case 0xf8:
770         case 0xf9:
771         case 0xfa:
772         case 0xfb:
773         case 0xfc:
774         case 0xfd:
775         case 0xfe:
776         case 0xff:
777             PrintDebug("keyboard: ignoring pulse of 0x%x (low=pulsed) on output port\n", (cmd & 0xf));
778             break;
779    
780             // case ac  diagonstic - returns 16 bytes from keyboard microcontroler on 60h
781         default:
782             PrintDebug("keyboard: ignoring command (unimplemented)\n");
783             break;
784     }
785
786     v3_unlock_irqrestore(state->kb_lock, irq_state);
787
788     return length;
789 }
790
791 static int keyboard_read_status(ushort_t port, void * dest, uint_t length, struct vm_device * dev) {
792     struct keyboard_internal *state = (struct keyboard_internal *)(dev->private_data);
793
794     if (length != 1) { 
795         PrintError("keyboard: >1 byte read for status (64h)\n");
796         return -1;
797     }
798
799     PrintDebug("keyboard: read status (64h): ");
800
801     addr_t irq_state = v3_lock_irqsave(state->kb_lock);
802
803     *(uint8_t *)dest = state->status.val;
804
805     v3_unlock_irqrestore(state->kb_lock, irq_state);
806     
807     PrintDebug("0x%x\n", *(uint8_t *)dest);
808     
809     return length;
810 }
811
812 static int keyboard_write_output(ushort_t port, void * src, uint_t length, struct vm_device * dev) {
813     struct keyboard_internal *state = (struct keyboard_internal *)(dev->private_data);
814     int ret = length;
815
816     if (length != 1) { 
817         PrintError("keyboard: write of 60h with >1 byte\n");
818         return -1;
819     }
820
821     uint8_t data = *(uint8_t *)src;
822   
823     PrintDebug("keyboard: output 0x%x on 60h\n", data);
824
825     addr_t irq_state = v3_lock_irqsave(state->kb_lock);
826
827     switch (state->state) {
828         case WRITING_CMD_BYTE:
829             state->cmd.val = data;
830             state->state = NORMAL;
831             PrintDebug("keyboard: wrote new command byte 0x%x\n", state->cmd.val);
832             break;
833
834         case WRITING_OUTPUT_PORT:
835             state->output_byte = data;
836             state->state = NORMAL;
837             PrintDebug("keyboard: wrote new output byte 0x%x\n", state->output_byte);
838             break;
839
840         case INJECTING_KEY:
841             push_to_output_queue(dev, data, COMMAND, KEYBOARD);  // probably should be a call to deliver_key_to_vmm()
842             state->state = NORMAL;
843             PrintDebug("keyboard: injected key 0x%x\n", data);
844             break;
845
846         case INJECTING_MOUSE:
847             push_to_output_queue(dev, data, DATA, MOUSE);
848             //      PrintDebug("keyboard: ignoring injected mouse event 0x%x\n", data);
849             PrintDebug("keyboard: injected mouse event 0x%x\n", data);
850             state->state = NORMAL;
851             break;
852
853         case IN_MOUSE:
854             PrintDebug("keyboard: mouse action: ");
855             if (mouse_write_output(dev, data)) { 
856                 state->state = NORMAL;
857             }
858             PrintDebug("\n");
859             break;
860
861         case TRANSMIT_PASSWD:
862             if (data) {
863                 //ignore passwd
864                 PrintDebug("keyboard: ignoring password character 0x%x\n",data);
865             } else {
866                 // end of password
867                 state->state = NORMAL;
868                 PrintDebug("keyboard: done with password\n");
869             }
870             break;
871
872         case SET_LEDS:
873             PrintDebug("Keyboard: LEDs being set...\n");
874             push_to_output_queue(dev, 0xfa, COMMAND, KEYBOARD);
875             state->state = NORMAL;
876             break;
877
878         case SET_RATE:
879             PrintDebug("Keyboard: Rate being set...\n");
880             push_to_output_queue(dev, 0xfa, COMMAND, KEYBOARD);
881             state->state = NORMAL;
882             break;
883
884         default:
885         case NORMAL: {
886             // command is being sent to keyboard controller
887             switch (data) { 
888                 case 0xff: // reset
889                     push_to_output_queue(dev, 0xfa, COMMAND, KEYBOARD); // ack
890                     push_to_output_queue(dev, 0xaa, COMMAND, KEYBOARD);
891                     PrintDebug("keyboard: reset complete and acked\n");
892                     break;
893
894                 case 0xf5: // disable scanning
895                 case 0xf4: // enable scanning
896                     // ack
897                     push_to_output_queue(dev, 0xfa, COMMAND, KEYBOARD);
898                     // should do something here... PAD
899                     PrintDebug("keyboard: %s scanning done and acked\n", (data == 0xf5) ? "disable" : "enable");
900                     break;
901
902                 case 0xf3:
903                     push_to_output_queue(dev, 0xfa, COMMAND, KEYBOARD);
904                     state->state = SET_RATE;
905                     break;
906
907                 case 0xf2: // get keyboard ID
908                     push_to_output_queue(dev, 0xfa, COMMAND, KEYBOARD);
909                     push_to_output_queue(dev, 0xab, COMMAND, KEYBOARD);
910                     push_to_output_queue(dev, 0x83, COMMAND, KEYBOARD);
911                     PrintDebug("Keyboard: Requesting Keyboard ID\n");
912                     break;
913
914                 case 0xed: // enable keyboard LEDs
915                     push_to_output_queue(dev, 0xfa, COMMAND, KEYBOARD);
916                     state->state = SET_LEDS;
917                     break;
918
919                 case 0xfe: // resend
920                 case 0xfd: // set key type make
921                 case 0xfc: // set key typ make/break
922                 case 0xfb: // set key type typematic
923                 case 0xfa: // set all typematic make/break/typematic
924                 case 0xf9: // set all make
925                 case 0xf8: // set all make/break
926                 case 0xf7: // set all typemaktic
927                 case 0xf6: // set defaults
928                     PrintError("keyboard: unhandled known command 0x%x on output buffer (60h)\n", data);
929                     ret = -1;
930                     break;
931
932                 default:
933                     PrintError("keyboard: unhandled unknown command 0x%x on output buffer (60h)\n", data);
934                     state->status.out_buf_full = 1;
935                     ret = -1;
936                     break;
937             }
938             break;
939         }
940     }
941   
942     v3_unlock_irqrestore(state->kb_lock, irq_state);
943
944     return ret;
945 }
946
947 static int keyboard_read_input(ushort_t port, void * dest, uint_t length, struct vm_device * dev) {
948     struct keyboard_internal * state = (struct keyboard_internal *)(dev->private_data);
949
950     if (length != 1) {
951         PrintError("keyboard: unknown size read from input (60h)\n");
952         return -1;
953     }
954     
955     addr_t irq_state = v3_lock_irqsave(state->kb_lock);
956
957     pull_from_output_queue(dev, (uint8_t *)dest);
958       
959     v3_unlock_irqrestore(state->kb_lock, irq_state);
960
961     PrintDebug("keyboard: read from input (60h): 0x%x\n", *(uint8_t *)dest);
962
963     return length;
964 }
965
966
967
968
969
970
971 static int keyboard_free(struct vm_device * dev) {
972
973     v3_dev_unhook_io(dev, KEYBOARD_60H);
974     v3_dev_unhook_io(dev, KEYBOARD_64H);
975 #if KEYBOARD_DEBUG_80H
976     v3_dev_unhook_io(dev, KEYBOARD_DELAY_80H);
977 #endif
978     keyboard_reset_device(dev);
979     return 0;
980 }
981
982
983
984
985
986 static struct v3_device_ops dev_ops = { 
987     .free = keyboard_free,
988     .reset = keyboard_reset_device,
989     .start = keyboard_start_device,
990     .stop = keyboard_stop_device,
991 };
992
993
994
995
996 static int keyboard_init(struct guest_info * vm, v3_cfg_tree_t * cfg) {
997     struct keyboard_internal * keyboard_state = NULL;
998     char * name = v3_cfg_val(cfg, "name");
999
1000     PrintDebug("keyboard: init_device\n");
1001
1002     keyboard_state = (struct keyboard_internal *)V3_Malloc(sizeof(struct keyboard_internal));
1003
1004     keyboard_state->mouse_queue.start = 0;
1005     keyboard_state->mouse_queue.end = 0;
1006     keyboard_state->mouse_queue.count = 0;
1007
1008     keyboard_state->kbd_queue.start = 0;
1009     keyboard_state->kbd_queue.end = 0;
1010     keyboard_state->kbd_queue.count = 0;
1011
1012     keyboard_state->mouse_enabled = 0;
1013
1014     struct vm_device * dev = v3_allocate_device(name, &dev_ops, keyboard_state);
1015
1016     if (v3_attach_device(vm, dev) == -1) {
1017         PrintError("Could not attach device %s\n", name);
1018         return -1;
1019     }
1020
1021
1022     keyboard_reset_device(dev);
1023
1024
1025     v3_lock_init(&(keyboard_state->kb_lock));
1026
1027
1028     // hook ports
1029     v3_dev_hook_io(dev, KEYBOARD_64H, &keyboard_read_status, &keyboard_write_command);
1030     v3_dev_hook_io(dev, KEYBOARD_60H, &keyboard_read_input, &keyboard_write_output);
1031
1032     v3_hook_host_event(vm, HOST_KEYBOARD_EVT, V3_HOST_EVENT_HANDLER(key_event_handler), dev);
1033     v3_hook_host_event(vm, HOST_MOUSE_EVT, V3_HOST_EVENT_HANDLER(mouse_event_handler), dev);
1034
1035
1036 #if KEYBOARD_DEBUG_80H
1037     v3_dev_hook_io(dev, KEYBOARD_DELAY_80H, &keyboard_read_delay, &keyboard_write_delay);
1038 #endif
1039
1040   
1041     //
1042     // We do not hook the IRQ here.  Instead, the underlying device driver
1043     // is responsible to call us back
1044     // 
1045
1046     return 0;
1047 }
1048
1049
1050 device_register("KEYBOARD", keyboard_init)