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.


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