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