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.


refactoring to the point of compilation
[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 v3_vm_info * vm, 
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         int i = 0;
333         for (i = 0; i < vm->num_cores; i++) {
334             v3_print_guest_state(&(vm->cores[i]));
335         }
336         //      PrintGuestPageTables(info, info->shdw_pg_state.guest_cr3);
337     } 
338 #ifdef CONFIG_SYMBIOTIC
339     else if (evt->scan_code == 0x43) { // F9 Sym test
340         PrintDebug("Testing sym call\n");
341         sym_arg_t a0 = 0x1111;
342         sym_arg_t a1 = 0x2222;
343         sym_arg_t a2 = 0x3333;
344         sym_arg_t a3 = 0x4444;
345         sym_arg_t a4 = 0x5555;
346         uint64_t call_start = 0;
347         uint64_t call_end = 0;
348         
349         V3_Print("Exits before symcall: %d\n", (uint32_t)info->num_exits);
350
351         rdtscll(call_start);
352         v3_sym_call5(info, SYMCALL_TEST, &a0, &a1, &a2, &a3, &a4);
353         rdtscll(call_end);
354         
355         V3_Print("Symcall latency = %d cycles (%d exits)\n", (uint32_t)(call_end - call_start), (uint32_t)info->num_exits);
356
357         V3_Print("Symcall  Test Returned arg0=%x, arg1=%x, arg2=%x, arg3=%x, arg4=%x\n",
358                  (uint32_t)a0, (uint32_t)a1, (uint32_t)a2, (uint32_t)a3, (uint32_t)a4);
359
360     } 
361 #endif
362     else if (evt->scan_code == 0x42) { // F8 debug toggle
363         extern int v3_dbg_enable;
364         
365         PrintDebug("Toggling Debugging\n");     
366         v3_dbg_enable ^= 1;
367     } else if (evt->scan_code == 0x41) { // F7 telemetry dump
368 #ifdef CONFIG_TELEMETRY
369         v3_print_telemetry(info);
370 #endif
371     }
372
373
374
375     addr_t irq_state = v3_lock_irqsave(state->kb_lock);
376
377     if ( (state->status.enabled == 1)      // onboard is enabled
378          && (state->cmd.disable == 0) )  {   // keyboard is enabled
379     
380         push_to_output_queue(dev, evt->scan_code, DATA, KEYBOARD);
381     }
382
383     v3_unlock_irqrestore(state->kb_lock, irq_state);
384   
385     return 0;
386 }
387
388
389 static int mouse_event_handler(struct v3_vm_info * vm, 
390                                struct v3_mouse_event * evt, 
391                                void * private_data) {
392     struct vm_device * dev = (struct vm_device *)private_data;
393     struct keyboard_internal * state = (struct keyboard_internal *)(dev->private_data);
394     int ret = 0;
395
396     PrintDebug("keyboard: injected mouse packet 0x %x %x %x\n",
397                evt->data[0], evt->data[1], evt->data[2]);
398   
399     addr_t irq_state = v3_lock_irqsave(state->kb_lock);
400
401     switch (state->mouse_state) { 
402         case STREAM:
403
404             if (state->cmd.mouse_disable == 0) {
405                 push_to_output_queue(dev, evt->data[0], DATA, MOUSE);
406                 push_to_output_queue(dev, evt->data[1], DATA, MOUSE);
407                 push_to_output_queue(dev, evt->data[2], DATA, MOUSE);
408             }
409             break;
410         default:
411             PrintError("Invalid mouse state\n");
412             ret = -1;
413             break;
414     }
415
416
417     v3_unlock_irqrestore(state->kb_lock, irq_state);
418
419     return ret;
420 }
421
422
423 static int keyboard_reset_device(struct vm_device * dev) {
424     struct keyboard_internal * data = (struct keyboard_internal *)(dev->private_data);
425   
426     memset(data, 0, sizeof(struct keyboard_internal));
427
428     data->state = NORMAL;
429     data->mouse_state = STREAM;
430
431
432     // PS2, keyboard+mouse enabled, generic translation    
433     data->cmd.val = 0;
434
435     data->cmd.irq_en = 1;
436     data->cmd.mouse_irq_en = 1;
437     data->cmd.self_test_ok = 1;
438     /** **/
439
440
441     // buffers empty, no errors
442     data->status.val = 0; 
443
444     data->status.self_test_ok = 1; // self-tests passed
445     data->status.enabled = 1;// keyboard ready
446     /** **/
447
448     
449     data->output_byte = 0;  //  ?
450
451     data->input_byte = INPUT_RAM;  // we have some
452     // also display=color, jumper 0, keyboard enabled 
453
454     PrintDebug("keyboard: reset device\n");
455  
456     return 0;
457
458 }
459
460
461
462 static int keyboard_start_device(struct vm_device * dev) {
463     PrintDebug("keyboard: start device\n");
464     return 0;
465 }
466
467
468 static int keyboard_stop_device(struct vm_device * dev) {
469     PrintDebug("keyboard: stop device\n");
470     return 0;
471 }
472
473
474
475 static int mouse_write_output(struct vm_device * dev, uint8_t data) {
476     struct keyboard_internal * state = (struct keyboard_internal *)(dev->private_data);
477
478     switch (state->mouse_state) { 
479         case NORMAL:
480             switch (data) {
481
482                 case 0xff: //reset
483                     if (state->mouse_enabled == 0) {
484                         push_to_output_queue(dev, 0xfe, DATA, MOUSE) ;   // no mouse!
485                     } else {
486                         push_to_output_queue(dev, MOUSE_ACK, DATA, MOUSE) ; 
487                         push_to_output_queue(dev, 0xaa, DATA, MOUSE) ; 
488                         push_to_output_queue(dev, 0x00, DATA, MOUSE) ; 
489                     }
490                     break;
491
492 /*              case 0xfe: //resend */
493 /*                  PushToOutputQueue(dev, 0xfa, OVERWRITE, DATA, MOUSE) ;  */
494 /*                  PrintDebug(" mouse resend begins "); */
495 /*                  state->mouse_done_after_ack = 0; */
496 /*                  state->mouse_needs_ack = 0; */
497 /*                  state->mouse_state = STREAM1; */
498 /*                  return 0;  // not done */
499 /*                  break; */
500       
501                 case 0xf6: // set defaults
502                     push_to_output_queue(dev, MOUSE_ACK, DATA, MOUSE) ; 
503                     PrintDebug(" mouse set defaults ");
504
505                     break;
506       
507                 case 0xf5: // disable data reporting 
508                     push_to_output_queue(dev, MOUSE_ACK, DATA, MOUSE) ; 
509                     PrintDebug(" mouse disable data reporting ");
510                     break;
511       
512                 case 0xf4: // enable data reporting 
513                     push_to_output_queue(dev, MOUSE_ACK, DATA, MOUSE) ; 
514                     PrintDebug(" mouse enable data reporting ");
515                     break;
516       
517                 case 0xf3: // set sample rate
518                     push_to_output_queue(dev, MOUSE_ACK, DATA, MOUSE) ; 
519                     state->mouse_state = SAMPLE;
520                     PrintDebug(" mouse set sample rate begins ");
521                     break;
522       
523                 case 0xf2: // get device id
524                     push_to_output_queue(dev, MOUSE_ACK, DATA, MOUSE) ; 
525                     push_to_output_queue(dev, 0x0,  DATA, MOUSE); 
526                     PrintDebug(" mouse get device id begins ");
527                     break;
528       
529                 case 0xf0: // set remote mode
530                     push_to_output_queue(dev, MOUSE_ACK, DATA, MOUSE) ; 
531                     PrintDebug(" mouse set remote mode  ");
532                     break;
533
534                 case 0xee: // set wrap mode
535                     push_to_output_queue(dev, MOUSE_ACK, DATA, MOUSE) ; 
536                     PrintError(" mouse set wrap mode (ignored)  ");
537                     break;
538
539                 case 0xec: // reset wrap mode
540                     push_to_output_queue(dev, MOUSE_ACK, DATA, MOUSE) ; 
541                     PrintError(" mouse reset wrap mode (ignored)  ");
542                     break;
543
544                 case 0xeb: // read data
545                     push_to_output_queue(dev, MOUSE_ACK, DATA, MOUSE) ; 
546                     PrintError(" mouse switch to wrap mode (ignored)  ");
547                     break;
548       
549                 case 0xea: // set stream mode
550                     push_to_output_queue(dev, MOUSE_ACK, DATA, MOUSE) ; 
551                     PrintDebug(" mouse set stream mode  ");
552                     break;
553
554                 case 0xe9: // status request
555                     push_to_output_queue(dev, MOUSE_ACK, DATA, MOUSE) ; 
556                     push_to_output_queue(dev, 0x00, DATA, MOUSE); 
557                     push_to_output_queue(dev, 0x00, DATA, MOUSE);
558                     push_to_output_queue(dev, 0x00, DATA, MOUSE); 
559                     PrintDebug(" mouse status request begins  ");
560                     break;
561
562                 case 0xe8: // set resolution
563                     push_to_output_queue(dev, MOUSE_ACK,  DATA, MOUSE) ; 
564                     PrintDebug(" mouse set resolution begins  ");
565                     state->mouse_state = SET_RES;
566                     break;
567
568                 case 0xe7: // set scaling 2:1
569                     push_to_output_queue(dev, MOUSE_ACK, DATA, MOUSE) ; 
570                     PrintDebug(" mouse set scaling 2:1 ");
571                     break;
572
573                 case 0xe6: // set scaling 1:1
574                     push_to_output_queue(dev, MOUSE_ACK, DATA, MOUSE) ; 
575                     PrintDebug(" mouse set scaling 1:1 ");
576                     break;
577       
578                 default:
579                     PrintDebug(" receiving unknown mouse command (0x%x) in acceptable state ", data);
580                     break;
581             }
582
583             break;
584         case SAMPLE:
585         case SET_RES:
586         default:
587             PrintDebug(" receiving mouse output in unhandled state (0x%x) ", state->mouse_state);
588             return -1;
589     }
590
591     return 0;
592 }
593
594
595
596 #if KEYBOARD_DEBUG_80H
597 static int keyboard_write_delay(ushort_t port, void * src,  uint_t length, struct vm_device * dev) {
598
599     if (length == 1) { 
600         PrintDebug("keyboard: write of 0x%x to 80h\n", *((uint8_t*)src));
601         return 1;
602     } else {
603         PrintDebug("keyboard: write of >1 byte to 80h\n", *((uint8_t*)src));
604         return length;
605     }
606 }
607
608 static int keyboard_read_delay(struct guest_info * core, ushort_t port, void * dest, uint_t length, struct vm_device * dev) {
609
610     if (length == 1) { 
611         *(uint8_t *)dest = v3_inb(port);
612
613         PrintDebug("keyboard: read of 0x%x from 80h\n", *((uint8_t*)dest));
614
615         return 1;
616     } else {
617         PrintDebug("keyboard: read of >1 byte from 80h\n");
618
619         return length;
620     }
621 }
622 #endif
623     
624   
625
626
627
628 static int keyboard_write_command(struct guest_info * core, ushort_t port, void * src, uint_t length, struct vm_device * dev) {
629     struct keyboard_internal * state = (struct keyboard_internal *)(dev->private_data);
630     uint8_t cmd = *(uint8_t *)src;
631
632     // Should always be single byte write
633     if (length != 1) { 
634         PrintError("keyboard: write of >1 bytes (%d) to 64h\n", length);
635         return -1;
636     }
637
638
639     addr_t irq_state = v3_lock_irqsave(state->kb_lock);
640
641     if (state->state != NORMAL) { 
642         PrintDebug("keyboard: warning - receiving command on 64h but state != NORMAL\n");
643     }
644   
645     PrintDebug("keyboard: command 0x%x on 64h\n", cmd);
646
647     switch (cmd) { 
648         case 0x20:  // READ COMMAND BYTE (returned in 60h)
649             push_to_output_queue(dev, state->cmd.val, COMMAND, KEYBOARD);
650             PrintDebug("keyboard: command byte 0x%x returned\n", state->cmd.val);
651             break;
652
653         case 0x60:  // WRITE COMMAND BYTE (read from 60h)
654             state->state = WRITING_CMD_BYTE; // we need to make sure we send the next 0x60 byte appropriately
655             PrintDebug("keyboard: prepare to write command byte\n");
656             break;
657
658             // case 0x90-9f - write to output port  (?)
659
660         case 0xa1: // Get version number
661             push_to_output_queue(dev, 0x00, COMMAND, KEYBOARD);
662             PrintDebug("keyboard: version number 0x0 returned\n");
663             break;
664
665         case 0xa4:  // is password installed?  send result to 0x60
666             // we don't support passwords
667             push_to_output_queue(dev, 0xf1, COMMAND, KEYBOARD);
668             PrintDebug("keyboard: password not installed\n");
669             break;
670
671         case 0xa5:  // new password will arrive on 0x60
672             state->state = TRANSMIT_PASSWD;
673             PrintDebug("keyboard: pepare to transmit password\n");
674             break;
675
676         case 0xa6:  // check passwd;
677             // since we do not support passwords, we will simply ignore this
678             // the implication is that any password check immediately succeeds 
679             // with a blank password
680             PrintDebug("keyboard: password check succeeded\n");
681             break;
682
683         case 0xa7:  // disable mouse
684             state->cmd.mouse_disable = 1;
685             PrintDebug("keyboard: mouse disabled\n");
686             break;
687
688         case 0xa8:  // enable mouse
689             state->cmd.mouse_disable = 0;
690             PrintDebug("keyboard: mouse enabled\n");
691             break;
692
693         case 0xa9:  // mouse interface test  (always succeeds)
694             push_to_output_queue(dev, 0x00, COMMAND, KEYBOARD);
695             PrintDebug("keyboard: mouse interface test succeeded\n");
696             break;
697
698         case 0xaa:  // controller self test (always succeeds)
699             push_to_output_queue(dev, 0x55, COMMAND, KEYBOARD);
700             PrintDebug("keyboard: controller self test succeeded\n");
701             break;
702
703         case 0xab:  // keyboard interface test (always succeeds)
704             push_to_output_queue(dev, 0, COMMAND, KEYBOARD);
705             PrintDebug("keyboard: keyboard interface test succeeded\n");
706             break;
707
708         case 0xad:  // disable keyboard
709             state->cmd.disable = 1;
710             PrintDebug("keyboard: keyboard disabled\n");
711             break;
712
713         case 0xae:  // enable keyboard
714             state->cmd.disable = 0;
715             PrintDebug("keyboard: keyboard enabled\n");
716             break;
717
718         case 0xaf:  // get version
719             push_to_output_queue(dev, 0x00, COMMAND, KEYBOARD);
720             PrintDebug("keyboard: version 0 returned \n");
721             break;
722
723         case 0xd0: // return microcontroller output on 60h
724             push_to_output_queue(dev, state->output_byte, COMMAND, KEYBOARD);
725             PrintDebug("keyboard: output byte 0x%x returned\n", state->output_byte);
726             break;
727
728         case 0xd1: // request to write next byte on 60h to the microcontroller output port
729             state->state = WRITING_OUTPUT_PORT;
730             PrintDebug("keyboard: prepare to write output byte\n");
731             break;
732
733         case 0xd2:  //  write keyboard buffer (inject key)
734             state->state = INJECTING_KEY;
735             PrintDebug("keyboard: prepare to inject key\n");
736             break;
737
738         case 0xd3: //  write mouse buffer (inject mouse)
739             state->state = INJECTING_MOUSE;
740             PrintDebug("keyboard: prepare to inject mouse\n");
741             break;
742
743         case 0xd4: // write mouse device (command to mouse?)
744             state->state = IN_MOUSE;
745             PrintDebug("keyboard: prepare to inject mouse command\n");
746             break;
747
748         case 0xc0: //  read input port 
749             push_to_output_queue(dev, state->input_byte, COMMAND, KEYBOARD);
750             PrintDebug("keyboard: input byte 0x%x returned\n", state->input_byte);
751             break;
752
753         case 0xc1:  //copy input port lsn to status msn
754             state->status.val &= 0x0f;
755             state->status.val |= (state->input_byte & 0xf) << 4;
756             PrintDebug("keyboard: copied input byte low 4 bits to status reg hi 4 bits\n");
757             break;
758
759         case 0xc2: // copy input port msn to status msn
760             state->status.val &= 0x0f;
761             state->status.val |= (state->input_byte & 0xf0);
762             PrintDebug("keyboard: copied input byte hi 4 bits to status reg hi 4 bits\n");
763             break;
764     
765         case 0xe0: // read test port
766             push_to_output_queue(dev, state->output_byte >> 6, COMMAND, KEYBOARD);
767             PrintDebug("keyboard: read 0x%x from test port\n", state->output_byte >> 6);
768             break;
769
770    
771         case 0xf0:   // pulse output port
772         case 0xf1:   // this should pulse 0..3 of cmd_byte on output port 
773         case 0xf2:   // instead of what is currently in output_byte (I think)
774         case 0xf3:   // main effect is taht if bit zero is zero
775         case 0xf4:   // should cause reset
776         case 0xf5:   // I doubt anything more recent than a 286 running 
777         case 0xf6:   // OS2 with the penalty box will care
778         case 0xf7:
779         case 0xf8:
780         case 0xf9:
781         case 0xfa:
782         case 0xfb:
783         case 0xfc:
784         case 0xfd:
785         case 0xfe:
786         case 0xff:
787             PrintDebug("keyboard: ignoring pulse of 0x%x (low=pulsed) on output port\n", (cmd & 0xf));
788             break;
789    
790             // case ac  diagonstic - returns 16 bytes from keyboard microcontroler on 60h
791         default:
792             PrintDebug("keyboard: ignoring command (unimplemented)\n");
793             break;
794     }
795
796     v3_unlock_irqrestore(state->kb_lock, irq_state);
797
798     return length;
799 }
800
801 static int keyboard_read_status(struct guest_info * core, ushort_t port, void * dest, uint_t length, struct vm_device * dev) {
802     struct keyboard_internal *state = (struct keyboard_internal *)(dev->private_data);
803
804     if (length != 1) { 
805         PrintError("keyboard: >1 byte read for status (64h)\n");
806         return -1;
807     }
808
809     PrintDebug("keyboard: read status (64h): ");
810
811     addr_t irq_state = v3_lock_irqsave(state->kb_lock);
812
813     *(uint8_t *)dest = state->status.val;
814
815     v3_unlock_irqrestore(state->kb_lock, irq_state);
816     
817     PrintDebug("0x%x\n", *(uint8_t *)dest);
818     
819     return length;
820 }
821
822 static int keyboard_write_output(struct guest_info * core, ushort_t port, void * src, uint_t length, struct vm_device * dev) {
823     struct keyboard_internal *state = (struct keyboard_internal *)(dev->private_data);
824     int ret = length;
825
826     if (length != 1) { 
827         PrintError("keyboard: write of 60h with >1 byte\n");
828         return -1;
829     }
830
831     uint8_t data = *(uint8_t *)src;
832   
833     PrintDebug("keyboard: output 0x%x on 60h\n", data);
834
835     addr_t irq_state = v3_lock_irqsave(state->kb_lock);
836
837     switch (state->state) {
838         case WRITING_CMD_BYTE:
839             state->cmd.val = data;
840             state->state = NORMAL;
841             PrintDebug("keyboard: wrote new command byte 0x%x\n", state->cmd.val);
842             break;
843
844         case WRITING_OUTPUT_PORT:
845             state->output_byte = data;
846             state->state = NORMAL;
847             PrintDebug("keyboard: wrote new output byte 0x%x\n", state->output_byte);
848             break;
849
850         case INJECTING_KEY:
851             push_to_output_queue(dev, data, COMMAND, KEYBOARD);  // probably should be a call to deliver_key_to_vmm()
852             state->state = NORMAL;
853             PrintDebug("keyboard: injected key 0x%x\n", data);
854             break;
855
856         case INJECTING_MOUSE:
857             push_to_output_queue(dev, data, DATA, MOUSE);
858             //      PrintDebug("keyboard: ignoring injected mouse event 0x%x\n", data);
859             PrintDebug("keyboard: injected mouse event 0x%x\n", data);
860             state->state = NORMAL;
861             break;
862
863         case IN_MOUSE:
864             PrintDebug("keyboard: mouse action: ");
865             if (mouse_write_output(dev, data)) { 
866                 state->state = NORMAL;
867             }
868             PrintDebug("\n");
869             break;
870
871         case TRANSMIT_PASSWD:
872             if (data) {
873                 //ignore passwd
874                 PrintDebug("keyboard: ignoring password character 0x%x\n",data);
875             } else {
876                 // end of password
877                 state->state = NORMAL;
878                 PrintDebug("keyboard: done with password\n");
879             }
880             break;
881
882         case SET_LEDS:
883             PrintDebug("Keyboard: LEDs being set...\n");
884             push_to_output_queue(dev, 0xfa, COMMAND, KEYBOARD);
885             state->state = NORMAL;
886             break;
887
888         case SET_RATE:
889             PrintDebug("Keyboard: Rate being set...\n");
890             push_to_output_queue(dev, 0xfa, COMMAND, KEYBOARD);
891             state->state = NORMAL;
892             break;
893
894         default:
895         case NORMAL: {
896             // command is being sent to keyboard controller
897             switch (data) { 
898                 case 0xff: // reset
899                     push_to_output_queue(dev, 0xfa, COMMAND, KEYBOARD); // ack
900                     push_to_output_queue(dev, 0xaa, COMMAND, KEYBOARD);
901                     PrintDebug("keyboard: reset complete and acked\n");
902                     break;
903
904                 case 0xf5: // disable scanning
905                 case 0xf4: // enable scanning
906                     // ack
907                     push_to_output_queue(dev, 0xfa, COMMAND, KEYBOARD);
908                     // should do something here... PAD
909                     PrintDebug("keyboard: %s scanning done and acked\n", (data == 0xf5) ? "disable" : "enable");
910                     break;
911
912                 case 0xf3:
913                     push_to_output_queue(dev, 0xfa, COMMAND, KEYBOARD);
914                     state->state = SET_RATE;
915                     break;
916
917                 case 0xf2: // get keyboard ID
918                     push_to_output_queue(dev, 0xfa, COMMAND, KEYBOARD);
919                     push_to_output_queue(dev, 0xab, COMMAND, KEYBOARD);
920                     push_to_output_queue(dev, 0x83, COMMAND, KEYBOARD);
921                     PrintDebug("Keyboard: Requesting Keyboard ID\n");
922                     break;
923
924                 case 0xed: // enable keyboard LEDs
925                     push_to_output_queue(dev, 0xfa, COMMAND, KEYBOARD);
926                     state->state = SET_LEDS;
927                     break;
928
929                 case 0xfe: // resend
930                 case 0xfd: // set key type make
931                 case 0xfc: // set key typ make/break
932                 case 0xfb: // set key type typematic
933                 case 0xfa: // set all typematic make/break/typematic
934                 case 0xf9: // set all make
935                 case 0xf8: // set all make/break
936                 case 0xf7: // set all typemaktic
937                 case 0xf6: // set defaults
938                     PrintError("keyboard: unhandled known command 0x%x on output buffer (60h)\n", data);
939                     ret = -1;
940                     break;
941
942                 default:
943                     PrintError("keyboard: unhandled unknown command 0x%x on output buffer (60h)\n", data);
944                     state->status.out_buf_full = 1;
945                     ret = -1;
946                     break;
947             }
948             break;
949         }
950     }
951   
952     v3_unlock_irqrestore(state->kb_lock, irq_state);
953
954     return ret;
955 }
956
957 static int keyboard_read_input(struct guest_info * core, ushort_t port, void * dest, uint_t length, struct vm_device * dev) {
958     struct keyboard_internal * state = (struct keyboard_internal *)(dev->private_data);
959
960     if (length != 1) {
961         PrintError("keyboard: unknown size read from input (60h)\n");
962         return -1;
963     }
964     
965     addr_t irq_state = v3_lock_irqsave(state->kb_lock);
966
967     pull_from_output_queue(dev, (uint8_t *)dest);
968       
969     v3_unlock_irqrestore(state->kb_lock, irq_state);
970
971     PrintDebug("keyboard: read from input (60h): 0x%x\n", *(uint8_t *)dest);
972
973     return length;
974 }
975
976
977
978
979
980
981 static int keyboard_free(struct vm_device * dev) {
982
983     v3_dev_unhook_io(dev, KEYBOARD_60H);
984     v3_dev_unhook_io(dev, KEYBOARD_64H);
985 #if KEYBOARD_DEBUG_80H
986     v3_dev_unhook_io(dev, KEYBOARD_DELAY_80H);
987 #endif
988     keyboard_reset_device(dev);
989     return 0;
990 }
991
992
993
994
995
996 static struct v3_device_ops dev_ops = { 
997     .free = keyboard_free,
998     .reset = keyboard_reset_device,
999     .start = keyboard_start_device,
1000     .stop = keyboard_stop_device,
1001 };
1002
1003
1004
1005
1006 static int keyboard_init(struct v3_vm_info * vm, v3_cfg_tree_t * cfg) {
1007     struct keyboard_internal * keyboard_state = NULL;
1008     char * name = v3_cfg_val(cfg, "name");
1009
1010     PrintDebug("keyboard: init_device\n");
1011
1012     keyboard_state = (struct keyboard_internal *)V3_Malloc(sizeof(struct keyboard_internal));
1013
1014     keyboard_state->mouse_queue.start = 0;
1015     keyboard_state->mouse_queue.end = 0;
1016     keyboard_state->mouse_queue.count = 0;
1017
1018     keyboard_state->kbd_queue.start = 0;
1019     keyboard_state->kbd_queue.end = 0;
1020     keyboard_state->kbd_queue.count = 0;
1021
1022     keyboard_state->mouse_enabled = 0;
1023
1024     struct vm_device * dev = v3_allocate_device(name, &dev_ops, keyboard_state);
1025
1026     if (v3_attach_device(vm, dev) == -1) {
1027         PrintError("Could not attach device %s\n", name);
1028         return -1;
1029     }
1030
1031
1032     keyboard_reset_device(dev);
1033
1034
1035     v3_lock_init(&(keyboard_state->kb_lock));
1036
1037
1038     // hook ports
1039     v3_dev_hook_io(dev, KEYBOARD_64H, &keyboard_read_status, &keyboard_write_command);
1040     v3_dev_hook_io(dev, KEYBOARD_60H, &keyboard_read_input, &keyboard_write_output);
1041
1042     v3_hook_host_event(vm, HOST_KEYBOARD_EVT, V3_HOST_EVENT_HANDLER(key_event_handler), dev);
1043     v3_hook_host_event(vm, HOST_MOUSE_EVT, V3_HOST_EVENT_HANDLER(mouse_event_handler), dev);
1044
1045
1046 #if KEYBOARD_DEBUG_80H
1047     v3_dev_hook_io(dev, KEYBOARD_DELAY_80H, &keyboard_read_delay, &keyboard_write_delay);
1048 #endif
1049
1050   
1051     //
1052     // We do not hook the IRQ here.  Instead, the underlying device driver
1053     // is responsible to call us back
1054     // 
1055
1056     return 0;
1057 }
1058
1059
1060 device_register("KEYBOARD", keyboard_init)