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.


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