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.


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