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.


VM Reset Bugfixes
[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 #include <palacios/vmm_debug.h>
30
31 #ifndef V3_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=0,
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         // after having a f0 sent to 60
189         // we wait for a new output byte on 60
190         GETSET_SCANCODES,
191         // first send ACK (0xfa)
192         // then wait for reception, and reset kb state
193         SET_DEFAULTS,
194     } state;
195
196
197     enum {
198         // Normal mouse state
199         STREAM=0, 
200         // this is used for setting sample rate
201         SAMPLE,
202         // set resolution
203         SET_RES,
204     } mouse_state;
205
206
207
208     struct cmd_reg cmd;
209     struct status_reg status;
210
211     uint8_t output_byte;      //  output port of onboard uC (e.g. A20)
212     uint8_t input_byte;       //  input port of onboard uC
213
214     // Data for system
215     uint8_t wrap;     
216
217     uint8_t mouse_enabled;
218     uint8_t scancode_set;
219
220     struct queue kbd_queue;
221     struct queue mouse_queue;
222
223     struct v3_vm_info * vm;
224
225     v3_lock_t kb_lock;
226 };
227
228
229 static int keyboard_reset_device(struct keyboard_internal * kbd);
230
231
232 static int update_kb_irq(struct keyboard_internal * state) {
233     int irq_num = 0;
234
235
236     PrintDebug(VM_NONE, VCORE_NONE, "keyboard: update_kb_irq: status = 0x%x parity_err = %d timeout_err = %d mouse_buf_full = %d enabled = %d cmd = %d self_test_ok = %d in_buf_full = %d out_buf_full = %d", state->status.val, state->status.parity_err, state->status.timeout_err, state->status.mouse_buf_full, state->status.enabled, state->status.cmd, state->status.self_test_ok, state->status.in_buf_full, state->status.out_buf_full);
237
238     PrintDebug(VM_NONE, VCORE_NONE, "keyboard: update_kb_irq: cmd= 0x%x rsvd = %d translate = %d mouse_disable = %d disable = %d override = %d self_test_ok = %d mouse_irq_en = %d irq_en = %d", state->cmd.val, state->cmd.rsvd, state->cmd.translate, state->cmd.mouse_disable, state->cmd.disable, state->cmd.override, state->cmd.self_test_ok, state->cmd.mouse_irq_en, state->cmd.irq_en);
239
240
241     PrintDebug(VM_NONE, VCORE_NONE, "keyboard: update_kb_irq: kbd_queue.couunt = %u mouse_queue.count = %u\n", 
242                state->kbd_queue.count, state->mouse_queue.count);
243
244
245     state->status.out_buf_full = 0;
246     state->status.mouse_buf_full = 0;
247
248
249     // If there is pending Keyboard data then it overrides mouse data
250     if (state->kbd_queue.count > 0) {
251         irq_num = KEYBOARD_IRQ;
252     } else if (state->mouse_queue.count > 0) {
253         irq_num = MOUSE_IRQ;
254         state->status.mouse_buf_full = 1;
255     } 
256     
257     PrintDebug(VM_NONE, VCORE_NONE, "keyboard: update_kb_irq: interrupt 0x%x\n", irq_num);
258     
259     if (irq_num) {
260         // Global output buffer flag (for both Keyboard and mouse)
261         state->status.out_buf_full = 1;
262         
263         if ((irq_num==KEYBOARD_IRQ && state->cmd.irq_en == 1) || 
264             (irq_num==MOUSE_IRQ && state->cmd.mouse_irq_en == 1)) { 
265
266             PrintDebug(VM_NONE, VCORE_NONE, "keyboard: update_kb_irq: raising 0x%x\n", irq_num);
267
268             v3_raise_irq(state->vm, irq_num);
269         }
270     }
271
272     return 0;
273 }
274
275
276
277 /* Only one byte is read per irq 
278  * So if the queue is still full after a data read, we re-raise the irq
279  * If we keep reading an empty queue we return the last queue entry
280  */
281
282 static int push_to_output_queue(struct keyboard_internal * state, uint8_t value, uint8_t cmd, uint8_t mouse) {
283     struct queue * q = NULL;
284
285
286     if (mouse) {
287         q = &(state->mouse_queue);
288     } else {
289         q = &(state->kbd_queue);
290     }
291
292     if (q->count >= QUEUE_SIZE) {
293         return 0;
294     }
295
296     if (cmd) {
297         state->status.cmd = 1;
298     } else {
299         state->status.cmd = 0;
300     }
301
302     q->queue[q->end] = value;
303
304     if (q->end >= (QUEUE_SIZE - 1)) {
305         q->end = 0;
306     } else {
307         q->end++;
308     }
309
310     q->count++;
311
312
313     update_kb_irq(state);
314
315     return 0;
316 }
317
318
319
320 static int pull_from_output_queue(struct keyboard_internal * state, uint8_t * value) {
321     struct queue * q = NULL;
322
323     if (state->kbd_queue.count > 0) {
324         q = &(state->kbd_queue);
325         PrintDebug(VM_NONE, VCORE_NONE, "Reading from Keyboard Queue\n");
326     } else if (state->mouse_queue.count > 0) {
327         q = &(state->mouse_queue);
328         PrintDebug(VM_NONE, VCORE_NONE, "Reading from Mouse Queue\n");
329     } else {
330         uint8_t idx = state->kbd_queue.start - 1;
331         PrintDebug(VM_NONE, VCORE_NONE, "No Data in any queue\n");
332         *value = state->kbd_queue.queue[idx];
333         return 0;
334     }
335
336     *value = q->queue[q->start];
337
338     if (q->start >= (QUEUE_SIZE - 1)) {
339         q->start = 0;
340     } else {
341         q->start++;
342     }
343
344     q->count--;
345
346
347     PrintDebug(VM_NONE, VCORE_NONE, "Read from Queue: %x\n", *value);
348     PrintDebug(VM_NONE, VCORE_NONE, "QStart=%d, QEnd=%d\n", q->start, q->end);
349
350     update_kb_irq(state);
351
352     return 0;
353 }
354
355
356 #include <palacios/vmm_telemetry.h>
357 #ifdef V3_CONFIG_SYMMOD
358 #include <palacios/vmm_symmod.h>
359 #endif
360
361 static int key_event_handler(struct v3_vm_info * vm, 
362                              struct v3_keyboard_event * evt, 
363                              void * private_data) {
364     struct keyboard_internal * state = (struct keyboard_internal *)private_data;
365
366     PrintDebug(vm, VCORE_NONE, "keyboard: injected status 0x%x, and scancode 0x%x\n", evt->status, evt->scan_code);
367
368     if (evt->scan_code == 0x44) { // F10 debug dump
369         int i = 0;
370         for (i = 0; i < vm->num_cores; i++) {
371             v3_print_guest_state(&(vm->cores[i]));
372         }
373         //      PrintGuestPageTables(info, info->shdw_pg_state.guest_cr3);
374     } 
375 #ifdef V3_CONFIG_SYMCALL
376     else if (evt->scan_code == 0x43) { // F9 Sym test
377         struct guest_info * core = &(vm->cores[0]);
378         PrintDebug(vm, VCORE_NONE, "Testing sym call\n");
379         sym_arg_t a0 = 0x1111;
380         sym_arg_t a1 = 0x2222;
381         sym_arg_t a2 = 0x3333;
382         sym_arg_t a3 = 0x4444;
383         sym_arg_t a4 = 0x5555;
384         uint64_t call_start = 0;
385         uint64_t call_end = 0;
386         
387         V3_Print(vm, VCORE_NONE, "Exits before symcall: %d\n", (uint32_t)core->num_exits);
388
389         rdtscll(call_start);
390         v3_sym_call5(core, SYMCALL_TEST, &a0, &a1, &a2, &a3, &a4);
391         rdtscll(call_end);
392         
393         V3_Print(vm, VCORE_NONE, "Symcall latency = %d cycles (%d exits)\n", (uint32_t)(call_end - call_start), (uint32_t)core->num_exits);
394
395         V3_Print(vm, VCORE_NONE, "Symcall  Test Returned arg0=%x, arg1=%x, arg2=%x, arg3=%x, arg4=%x\n",
396                  (uint32_t)a0, (uint32_t)a1, (uint32_t)a2, (uint32_t)a3, (uint32_t)a4);
397
398     } 
399 #endif
400     else if (evt->scan_code == 0x42) { // F8 debug toggle
401         extern int v3_dbg_enable;
402         
403         PrintDebug(vm, VCORE_NONE, "Toggling Debugging\n");     
404         v3_dbg_enable ^= 1;
405
406     } 
407 #ifdef V3_CONFIG_TELEMETRY
408
409     else if (evt->scan_code == 0x41) { // F7 telemetry dump
410         v3_print_global_telemetry(vm);
411     } 
412 #endif
413 #ifdef V3_CONFIG_SYMMOD
414     else if (evt->scan_code == 0x40) { // F6 Test symmod load
415         v3_load_sym_capsule(vm, "lnx_test");
416     }
417 #endif
418
419
420     addr_t irq_state = v3_lock_irqsave(state->kb_lock);
421
422     if ( (state->status.enabled == 1)      // onboard is enabled
423          && (state->cmd.disable == 0) )  {   // keyboard is enabled
424     
425         push_to_output_queue(state, evt->scan_code, DATA, KEYBOARD);
426     }
427
428     v3_unlock_irqrestore(state->kb_lock, irq_state);
429   
430     return 0;
431 }
432
433
434 static int mouse_event_handler(struct v3_vm_info * vm, 
435                                struct v3_mouse_event * evt, 
436                                void * private_data) {
437     struct keyboard_internal * kbd = (struct keyboard_internal *)private_data;
438     int ret = 0;
439
440     PrintDebug(vm, VCORE_NONE, "keyboard: injected mouse packet sx=%u dx=%u sy=%u dy=%u buttons=0x%x\n",
441                evt->sx, evt->dx, evt->sy, evt->dy, evt->buttons);
442   
443
444     PrintDebug(vm, VCORE_NONE, "keyboard: mouse state is %s\n", 
445                kbd->mouse_state==STREAM ? "STREAM" :
446                kbd->mouse_state==SAMPLE ? "SAMPLE" :
447                kbd->mouse_state==SET_RES ? "SET_RES" : "UNKNOWN");
448
449     addr_t irq_state = v3_lock_irqsave(kbd->kb_lock);
450
451     switch (kbd->mouse_state) { 
452         case STREAM:
453             // packet is 3 bytes of form
454             // YO | XO | YS | XS | 1 | MIDDLE | RIGHT | LEFT
455             // DX
456             // YY
457             if (kbd->cmd.mouse_disable == 0) {
458                 uint8_t h;
459                 // YO=0
460                 // XO=0
461                 // bit 3 set
462                 h=0x08; 
463                 // YS bit
464                 h |= (!!(evt->sy)) << 5;
465                 // XS bit
466                 h |= (!!(evt->sx)) << 4;
467                 // buttons
468                 h |= (evt->buttons) & 0x7;
469                 // header byte
470                 push_to_output_queue(kbd, h, DATA, MOUSE);
471                 // dx
472                 push_to_output_queue(kbd, evt->dx, DATA, MOUSE);
473                 // dy
474                 push_to_output_queue(kbd, evt->dy, DATA, MOUSE);
475             } else {
476                 PrintDebug(vm,VCORE_NONE, "Ignoring mouse event because mouse is disabled\n");
477             }
478             break;
479         default:
480             PrintDebug(vm, VCORE_NONE, "Ignoring mouse event due to mouse not being in stream mode\n");
481             ret = 0;
482             break;
483     }
484
485
486     v3_unlock_irqrestore(kbd->kb_lock, irq_state);
487
488     return ret;
489 }
490
491
492
493
494
495
496
497
498
499
500 static int mouse_write_output(struct keyboard_internal * kbd, uint8_t data) {
501
502     switch (kbd->mouse_state) { 
503        case STREAM: // NORMAL mode for mouse
504             switch (data) {
505
506                 case 0xff: //reset
507                     if (kbd->mouse_enabled == 0) {
508                         push_to_output_queue(kbd, 0xfe, DATA, MOUSE) ;   // no mouse!
509                     } else {
510                         push_to_output_queue(kbd, MOUSE_ACK, DATA, MOUSE) ; 
511                         push_to_output_queue(kbd, 0xaa, DATA, MOUSE) ; 
512                         push_to_output_queue(kbd, 0x00, DATA, MOUSE) ; 
513                     }
514                     break;
515
516 /*              case 0xfe: //resend */
517 /*                  PushToOutputQueue(kbd, 0xfa, OVERWRITE, DATA, MOUSE) ;  */
518 /*                  PrintDebug(VM_NONE, VCORE_NONE, " mouse resend begins "); */
519 /*                  kbd->mouse_done_after_ack = 0; */
520 /*                  kbd->mouse_needs_ack = 0; */
521 /*                  kbd->mouse_state = STREAM1; */
522 /*                  return 0;  // not done */
523 /*                  break; */
524       
525                 case 0xf6: // set defaults
526                     push_to_output_queue(kbd, MOUSE_ACK, DATA, MOUSE) ; 
527                     PrintDebug(VM_NONE, VCORE_NONE, "keyboard: mouse set defaults mouse_state=%u\n", kbd->mouse_state);
528                     break;
529       
530                 case 0xf5: // disable data reporting 
531                     push_to_output_queue(kbd, MOUSE_ACK, DATA, MOUSE) ; 
532                     PrintDebug(VM_NONE, VCORE_NONE, "keyboard: mouse disable data reporting\n");
533                     break;
534       
535                 case 0xf4: // enable data reporting 
536                     push_to_output_queue(kbd, MOUSE_ACK, DATA, MOUSE) ; 
537                     PrintDebug(VM_NONE, VCORE_NONE, "keyboard: mouse enable data reporting\n");
538                     break;
539       
540                 case 0xf3: // set sample rate
541                     push_to_output_queue(kbd, MOUSE_ACK, DATA, MOUSE) ; 
542                     kbd->mouse_state = SAMPLE;
543                     PrintDebug(VM_NONE, VCORE_NONE, "keyboard:  mouse set sample rate begins\n");
544                     break;
545       
546                 case 0xf2: // get device id
547                     push_to_output_queue(kbd, MOUSE_ACK, DATA, MOUSE) ; 
548                     push_to_output_queue(kbd, 0x0,  DATA, MOUSE); 
549                     PrintDebug(VM_NONE, VCORE_NONE, "keyboard: mouse get device id begins\n");
550                     break;
551       
552                 case 0xf0: // set remote mode
553                     push_to_output_queue(kbd, MOUSE_ACK, DATA, MOUSE) ; 
554                     PrintDebug(VM_NONE, VCORE_NONE, "keyboard: mouse set remote mode (ignored)\n");
555                     break;
556
557                 case 0xee: // set wrap mode
558                     push_to_output_queue(kbd, MOUSE_ACK, DATA, MOUSE) ; 
559                     PrintError(VM_NONE, VCORE_NONE, "keyboard: mouse set wrap mode (ignored)\n");
560                     break;
561
562                 case 0xec: // reset wrap mode
563                     push_to_output_queue(kbd, MOUSE_ACK, DATA, MOUSE) ; 
564                     PrintError(VM_NONE, VCORE_NONE, "keyboard:  mouse reset wrap mode (ignored)\n");
565                     break;
566
567                 case 0xeb: // read data
568                     push_to_output_queue(kbd, MOUSE_ACK, DATA, MOUSE) ; 
569                     PrintError(VM_NONE, VCORE_NONE, "keyboard:  mouse switch to wrap mode (ignored)\n");
570                     break;
571       
572                 case 0xea: // set stream mode
573                     push_to_output_queue(kbd, MOUSE_ACK, DATA, MOUSE) ; 
574                     PrintDebug(VM_NONE, VCORE_NONE, "keyboard:  mouse set stream mode\n");
575                     break;
576
577                 case 0xe9: // status request
578                     push_to_output_queue(kbd, MOUSE_ACK, DATA, MOUSE) ; 
579                     push_to_output_queue(kbd, 0x00, DATA, MOUSE); 
580                     push_to_output_queue(kbd, 0x00, DATA, MOUSE);
581                     push_to_output_queue(kbd, 0x00, DATA, MOUSE); 
582                     PrintDebug(VM_NONE, VCORE_NONE, "keyboard:  mouse status request begins\n");
583                     break;
584
585                 case 0xe8: // set resolution
586                     push_to_output_queue(kbd, MOUSE_ACK,  DATA, MOUSE) ; 
587                     PrintDebug(VM_NONE, VCORE_NONE, "keyboard:  mouse set resolution begins\n");
588                     kbd->mouse_state = SET_RES;
589                     break;
590
591                 case 0xe7: // set scaling 2:1
592                     push_to_output_queue(kbd, MOUSE_ACK, DATA, MOUSE) ; 
593                     PrintDebug(VM_NONE, VCORE_NONE, "keyboard:  mouse set scaling 2:1\n");
594                     break;
595
596                 case 0xe6: // set scaling 1:1
597                     push_to_output_queue(kbd, MOUSE_ACK, DATA, MOUSE) ; 
598                     PrintDebug(VM_NONE, VCORE_NONE, "keyboard:  mouse set scaling 1:1\n");
599                     break;
600       
601
602                 case 0xe1: // Read secondary ID
603                     push_to_output_queue(kbd, MOUSE_ACK, DATA, MOUSE) ;
604                     PrintDebug(VM_NONE, VCORE_NONE, "keyboard: mouse read secondary ID (ignored)\n");
605                     break;
606       
607                 default:
608                     PrintDebug(VM_NONE, VCORE_NONE, "keyboard:  receiving unknown mouse command (0x%x) in stream state\n", data);
609                     break;
610             }
611
612             break;
613
614         case SAMPLE:
615             PrintDebug(VM_NONE, VCORE_NONE, "keyboard: mouse setting sample rate to %u (ignored)", data);
616             kbd->mouse_state = STREAM;
617             break;
618
619         case SET_RES:
620             PrintDebug(VM_NONE, VCORE_NONE, "keyboard: mouse setting resolution to %u (ignored)", data);
621             kbd->mouse_state = STREAM;
622             break;
623
624         default:
625             PrintDebug(VM_NONE, VCORE_NONE, "keyboard: received mouse output in unknown state %u\n", kbd->mouse_state);
626             return -1;
627     }
628
629     return 0;
630 }
631
632
633
634 #if KEYBOARD_DEBUG_80H
635 static int keyboard_write_delay(struct guest_info *core, ushort_t port, void * src,  uint_t length, void * priv_data) {
636
637     if (length == 1) { 
638         PrintDebug(core->vm_info, core, "keyboard: write of 0x%x to 80h\n", *((uint8_t*)src));
639         return 1;
640     } else {
641         PrintDebug(core->vm_info, core, "keyboard: write of >1 byte to 80h\n", *((uint8_t*)src));
642         return length;
643     }
644 }
645
646 static int keyboard_read_delay(struct guest_info * core, ushort_t port, void * dest, uint_t length, void * priv_data) {
647
648     if (length == 1) { 
649         *(uint8_t *)dest = v3_inb(port);
650
651         PrintDebug(core->vm_info, core, "keyboard: read of 0x%x from 80h\n", *((uint8_t*)dest));
652
653         return 1;
654     } else {
655         PrintDebug(core->vm_info, core, "keyboard: read of >1 byte from 80h\n");
656
657         return length;
658     }
659 }
660 #endif
661     
662   
663
664
665
666 static int keyboard_write_command(struct guest_info * core, ushort_t port, void * src, uint_t length, void * priv_data) {
667     struct keyboard_internal * kbd = priv_data;
668     uint8_t cmd = *(uint8_t *)src;
669
670     // Should always be single byte write
671     if (length != 1) { 
672         PrintError(core->vm_info, core, "keyboard: write of >1 bytes (%d) to 64h\n", length);
673         return -1;
674     }
675
676
677     addr_t irq_state = v3_lock_irqsave(kbd->kb_lock);
678
679     if (kbd->state != NORMAL) { 
680         PrintDebug(core->vm_info, core, "keyboard: warning - receiving command on 64h but state != NORMAL\n");
681     }
682   
683     PrintDebug(core->vm_info, core, "keyboard: command 0x%x on 64h\n", cmd);
684
685     switch (cmd) { 
686         case 0x20:  // READ COMMAND BYTE (returned in 60h)
687             push_to_output_queue(kbd, kbd->cmd.val, COMMAND, KEYBOARD);
688             PrintDebug(core->vm_info, core, "keyboard: command byte 0x%x returned\n", kbd->cmd.val);
689             break;
690
691         case 0x60:  // WRITE COMMAND BYTE (read from 60h)
692             kbd->state = WRITING_CMD_BYTE; // we need to make sure we send the next 0x60 byte appropriately
693             PrintDebug(core->vm_info, core, "keyboard: prepare to write command byte\n");
694             break;
695
696             // case 0x90-9f - write to output port  (?)
697
698         case 0xa1: // Get version number
699             push_to_output_queue(kbd, 0x00, COMMAND, KEYBOARD);
700             PrintDebug(core->vm_info, core, "keyboard: version number 0x0 returned\n");
701             break;
702
703         case 0xa4:  // is password installed?  send result to 0x60
704             // we don't support passwords
705             push_to_output_queue(kbd, 0xf1, COMMAND, KEYBOARD);
706             PrintDebug(core->vm_info, core, "keyboard: password not installed\n");
707             break;
708
709         case 0xa5:  // new password will arrive on 0x60
710             kbd->state = TRANSMIT_PASSWD;
711             PrintDebug(core->vm_info, core, "keyboard: pepare to transmit password\n");
712             break;
713
714         case 0xa6:  // check passwd;
715             // since we do not support passwords, we will simply ignore this
716             // the implication is that any password check immediately succeeds 
717             // with a blank password
718             PrintDebug(core->vm_info, core, "keyboard: password check succeeded\n");
719             break;
720
721         case 0xa7:  // disable mouse
722             kbd->cmd.mouse_disable = 1;
723             PrintDebug(core->vm_info, core, "keyboard: mouse disabled\n");
724             break;
725
726         case 0xa8:  // enable mouse
727             kbd->cmd.mouse_disable = 0;
728             PrintDebug(core->vm_info, core, "keyboard: mouse enabled\n");
729             break;
730
731         case 0xa9:  // mouse interface test  (always succeeds)
732             push_to_output_queue(kbd, 0x00, COMMAND, KEYBOARD);
733             PrintDebug(core->vm_info, core, "keyboard: mouse interface test succeeded\n");
734             break;
735
736         case 0xaa:  // controller self test (always succeeds)
737             push_to_output_queue(kbd, 0x55, COMMAND, KEYBOARD);
738             PrintDebug(core->vm_info, core, "keyboard: controller self test succeeded\n");
739             break;
740
741         case 0xab:  // keyboard interface test (always succeeds)
742             push_to_output_queue(kbd, 0, COMMAND, KEYBOARD);
743             PrintDebug(core->vm_info, core, "keyboard: keyboard interface test succeeded\n");
744             break;
745
746         case 0xad:  // disable keyboard
747             kbd->cmd.disable = 1;
748             PrintDebug(core->vm_info, core, "keyboard: keyboard disabled\n");
749             break;
750
751         case 0xae:  // enable keyboard
752             kbd->cmd.disable = 0;
753             PrintDebug(core->vm_info, core, "keyboard: keyboard enabled\n");
754             break;
755
756         case 0xaf:  // get version
757             push_to_output_queue(kbd, 0x00, COMMAND, KEYBOARD);
758             PrintDebug(core->vm_info, core, "keyboard: version 0 returned \n");
759             break;
760
761         case 0xd0: // return microcontroller output on 60h
762             push_to_output_queue(kbd, kbd->output_byte, COMMAND, KEYBOARD);
763             PrintDebug(core->vm_info, core, "keyboard: output byte 0x%x returned\n", kbd->output_byte);
764             break;
765
766         case 0xd1: // request to write next byte on 60h to the microcontroller output port
767             kbd->state = WRITING_OUTPUT_PORT;
768             PrintDebug(core->vm_info, core, "keyboard: prepare to write output byte\n");
769             break;
770
771         case 0xd2:  //  write keyboard buffer (inject key)
772             kbd->state = INJECTING_KEY;
773             PrintDebug(core->vm_info, core, "keyboard: prepare to inject key\n");
774             break;
775
776         case 0xd3: //  write mouse buffer (inject mouse)
777             kbd->state = INJECTING_MOUSE;
778             PrintDebug(core->vm_info, core, "keyboard: prepare to inject mouse\n");
779             break;
780
781         case 0xd4: // write mouse device (command to mouse)
782             kbd->state = IN_MOUSE;
783             PrintDebug(core->vm_info, core, "keyboard: prepare to inject mouse command with mouse_state= %u \n", 
784                        kbd->mouse_state);
785             break;
786
787         case 0xc0: //  read input port 
788             push_to_output_queue(kbd, kbd->input_byte, COMMAND, KEYBOARD);
789             PrintDebug(core->vm_info, core, "keyboard: input byte 0x%x returned\n", kbd->input_byte);
790             break;
791
792         case 0xc1:  //copy input port lsn to status msn
793             kbd->status.val &= 0x0f;
794             kbd->status.val |= (kbd->input_byte & 0xf) << 4;
795             PrintDebug(core->vm_info, core, "keyboard: copied input byte low 4 bits to status reg hi 4 bits\n");
796             break;
797
798         case 0xc2: // copy input port msn to status msn
799             kbd->status.val &= 0x0f;
800             kbd->status.val |= (kbd->input_byte & 0xf0);
801             PrintDebug(core->vm_info, core, "keyboard: copied input byte hi 4 bits to status reg hi 4 bits\n");
802             break;
803     
804         case 0xe0: // read test port
805             push_to_output_queue(kbd, kbd->output_byte >> 6, COMMAND, KEYBOARD);
806             PrintDebug(core->vm_info, core, "keyboard: read 0x%x from test port\n", kbd->output_byte >> 6);
807             break;
808
809    
810         case 0xf0:   // pulse output port
811         case 0xf1:   // this should pulse 0..3 of cmd_byte on output port 
812         case 0xf2:   // instead of what is currently in output_byte (I think)
813         case 0xf3:   // main effect is taht if bit zero is zero
814         case 0xf4:   // should cause reset
815         case 0xf5:   
816         case 0xf6:   
817         case 0xf7:
818         case 0xf8:
819         case 0xf9:
820         case 0xfa:
821         case 0xfb:
822         case 0xfc:
823         case 0xfd:
824         case 0xfe:
825         case 0xff:
826             if (!(cmd & 0x1)) { 
827                 // general purpose reset
828                 PrintDebug(core->vm_info, core, "keyboard: reseting VM\n");
829                 v3_reset_vm(core->vm_info);
830
831             } else {
832                 PrintDebug(core->vm_info, core, "keyboard: ignoring command 0x%x on output port\n", cmd);
833             }
834             break;
835    
836             // case ac  diagonstic - returns 16 bytes from keyboard microcontroler on 60h
837         default:
838             PrintDebug(core->vm_info, core, "keyboard: ignoring command (unimplemented)\n");
839             break;
840     }
841
842     v3_unlock_irqrestore(kbd->kb_lock, irq_state);
843
844     return length;
845 }
846
847 static int keyboard_read_status(struct guest_info * core, ushort_t port, void * dest, uint_t length, void * priv_data) {
848     struct keyboard_internal * kbd = priv_data;
849
850     if (length != 1) { 
851         PrintError(core->vm_info, core, "keyboard: >1 byte read for status (64h)\n");
852         return -1;
853     }
854
855     PrintDebug(core->vm_info, core, "keyboard: read status (64h): ");
856
857     addr_t irq_state = v3_lock_irqsave(kbd->kb_lock);
858
859     *(uint8_t *)dest = kbd->status.val;
860
861     v3_unlock_irqrestore(kbd->kb_lock, irq_state);
862     
863     PrintDebug(core->vm_info, core, "0x%x\n", *(uint8_t *)dest);
864     
865     return length;
866 }
867
868 static int keyboard_write_output(struct guest_info * core, ushort_t port, void * src, uint_t length, void * priv_data) {
869     struct keyboard_internal * kbd = priv_data;
870     int ret = length;
871
872     if (length != 1) { 
873         PrintError(core->vm_info, core, "keyboard: write of 60h with >1 byte\n");
874         return -1;
875     }
876
877     uint8_t data = *(uint8_t *)src;
878   
879     PrintDebug(core->vm_info, core, "keyboard: output 0x%x on 60h with keyboard_state=%u\n", data,kbd->state);
880
881     addr_t irq_state = v3_lock_irqsave(kbd->kb_lock);
882
883     switch (kbd->state) {
884         case WRITING_CMD_BYTE:
885             kbd->cmd.val = data;
886             kbd->state = NORMAL;
887             PrintDebug(core->vm_info, core, "keyboard: wrote new command byte 0x%x\n", kbd->cmd.val);
888             break;
889
890         case WRITING_OUTPUT_PORT:
891             kbd->output_byte = data;
892             kbd->state = NORMAL;
893             PrintDebug(core->vm_info, core, "keyboard: wrote new output byte 0x%x\n", kbd->output_byte);
894             break;
895
896         case INJECTING_KEY:
897             push_to_output_queue(kbd, data, COMMAND, KEYBOARD);  // probably should be a call to deliver_key_to_vmm()
898             kbd->state = NORMAL;
899             PrintDebug(core->vm_info, core, "keyboard: injected key 0x%x\n", data);
900             break;
901
902         case INJECTING_MOUSE:
903             push_to_output_queue(kbd, data, DATA, MOUSE);
904             //      PrintDebug(core->vm_info, core, "keyboard: ignoring injected mouse event 0x%x\n", data);
905             PrintDebug(core->vm_info, core, "keyboard: injected mouse event 0x%x\n", data);
906             kbd->state = NORMAL;
907             break;
908
909         case IN_MOUSE:
910             PrintDebug(core->vm_info, core, "keyboard: mouse action\n");
911             if (mouse_write_output(kbd, data)) { 
912                 kbd->state = NORMAL;
913             }
914             break;
915
916         case TRANSMIT_PASSWD:
917             if (data) {
918                 //ignore passwd
919                 PrintDebug(core->vm_info, core, "keyboard: ignoring password character 0x%x\n",data);
920             } else {
921                 // end of password
922                 kbd->state = NORMAL;
923                 PrintDebug(core->vm_info, core, "keyboard: done with password\n");
924             }
925             break;
926
927         case SET_LEDS:
928             PrintDebug(core->vm_info, core, "Keyboard: LEDs being set...\n");
929             push_to_output_queue(kbd, 0xfa, COMMAND, KEYBOARD);
930             kbd->state = NORMAL;
931             break;
932
933         case SET_RATE:
934             PrintDebug(core->vm_info, core, "Keyboard: Rate being set...\n");
935             push_to_output_queue(kbd, 0xfa, COMMAND, KEYBOARD);
936             kbd->state = NORMAL;
937             break;
938
939         case GETSET_SCANCODES:
940             switch (data) {
941                 case 0:
942                     PrintDebug(core->vm_info, core, "Keyboard: scancode set being read\n");
943                     push_to_output_queue(kbd, 0x45 - 2 * kbd->scancode_set, COMMAND, KEYBOARD);
944                     break;
945                 case 1:
946                     PrintError(core->vm_info, core, "keyboard: unsupported scancode set %d selected\n", data);
947                     return -1;
948                 case 2:
949                     PrintDebug(core->vm_info, core, "Keyboard: scancode set being set to %d\n", data);
950                     kbd->scancode_set = data;
951                     push_to_output_queue(kbd, 0xfa, COMMAND, KEYBOARD);
952                     break;
953                 case 3:
954                     /* OpenBSD wants scancode set 3, but falls back to 2 if a
955                      * subsequent read reveals that the request was ignored
956                      */
957                     PrintError(core->vm_info, core, "keyboard: ignoring request for scancode set %d\n", data);
958                     break;
959                 default:
960                     PrintError(core->vm_info, core, "keyboard: unknown scancode set %d selected\n", data);
961                     ret = -1;
962                     break;
963   
964             }
965             kbd->state = NORMAL;
966             break;
967
968         case SET_DEFAULTS:
969             keyboard_reset_device(kbd);
970             kbd->state = NORMAL;
971             break;
972
973         default:
974         case NORMAL: {
975             // command is being sent to keyboard controller
976             switch (data) { 
977                 case 0xff: // reset
978                     push_to_output_queue(kbd, 0xfa, COMMAND, KEYBOARD); // ack
979                     push_to_output_queue(kbd, 0xaa, COMMAND, KEYBOARD);
980                     PrintDebug(core->vm_info, core, "keyboard: reset complete and acked\n");
981                     break;
982
983                 case 0xf5: // disable scanning
984                 case 0xf4: // enable scanning
985                     // ack
986                     push_to_output_queue(kbd, 0xfa, COMMAND, KEYBOARD);
987                     // should do something here... PAD
988                     PrintDebug(core->vm_info, core, "keyboard: %s scanning done and acked\n", (data == 0xf5) ? "disable" : "enable");
989                     break;
990
991                 case 0xf3:
992                     push_to_output_queue(kbd, 0xfa, COMMAND, KEYBOARD);
993                     kbd->state = SET_RATE;
994                     break;
995
996                 case 0xf2: // get keyboard ID
997                     push_to_output_queue(kbd, 0xfa, COMMAND, KEYBOARD);
998                     push_to_output_queue(kbd, 0xab, COMMAND, KEYBOARD);
999                     push_to_output_queue(kbd, 0x83, COMMAND, KEYBOARD);
1000                     PrintDebug(core->vm_info, core, "Keyboard: Requesting Keyboard ID\n");
1001                     break;
1002
1003                 case 0xed: // enable keyboard LEDs
1004                     push_to_output_queue(kbd, 0xfa, COMMAND, KEYBOARD);
1005                     kbd->state = SET_LEDS;
1006                     break;
1007
1008                 case 0xee: // echo, used by FreeBSD to probe controller
1009                     push_to_output_queue(kbd, 0xee, COMMAND, KEYBOARD);
1010                     break;
1011
1012                 case 0xf0: // get/set scancode set
1013                     push_to_output_queue(kbd, 0xfa, COMMAND, KEYBOARD);
1014                     kbd->state = GETSET_SCANCODES;
1015                     break;
1016
1017
1018                 case 0xf6: // set defaults
1019                     // ACK command
1020                     // clear output buffer
1021                     // reset to init state
1022                     push_to_output_queue(kbd, 0xfa, COMMAND, KEYBOARD);
1023                     kbd->state = SET_DEFAULTS;
1024                     break;
1025
1026                 case 0xfe: // resend
1027                 case 0xfd: // set key type make
1028                 case 0xfc: // set key typ make/break
1029                 case 0xfb: // set key type typematic
1030                 case 0xfa: // set all typematic make/break/typematic
1031                 case 0xf9: // set all make
1032                 case 0xf8: // set all make/break
1033                 case 0xf7: // set all typemaktic
1034
1035                     PrintError(core->vm_info, core, "keyboard: unhandled known command 0x%x on output buffer (60h)\n", data);
1036                     ret = -1;
1037                     break;
1038
1039                 default:
1040                     PrintError(core->vm_info, core, "keyboard: unhandled unknown command 0x%x on output buffer (60h)\n", data);
1041                     kbd->status.out_buf_full = 1;
1042                     ret = -1;
1043                     break;
1044             }
1045             break;
1046         }
1047     }
1048   
1049     v3_unlock_irqrestore(kbd->kb_lock, irq_state);
1050
1051     return ret;
1052 }
1053
1054 static int keyboard_read_input(struct guest_info * core, ushort_t port, void * dest, uint_t length, void * priv_data) {
1055     struct keyboard_internal * kbd = priv_data;
1056
1057     if (length != 1) {
1058         PrintError(core->vm_info, core, "keyboard: unknown size read from input (60h)\n");
1059         return -1;
1060     }
1061     
1062     addr_t irq_state = v3_lock_irqsave(kbd->kb_lock);
1063
1064     pull_from_output_queue(kbd, (uint8_t *)dest);
1065       
1066     v3_unlock_irqrestore(kbd->kb_lock, irq_state);
1067
1068     PrintDebug(core->vm_info, core, "keyboard: read from input (60h): 0x%x\n", *(uint8_t *)dest);
1069
1070     return length;
1071 }
1072
1073
1074
1075
1076
1077
1078 static int keyboard_free(struct keyboard_internal * kbd) {
1079     
1080
1081     // unhook host events
1082
1083     v3_lock_deinit(&(kbd->kb_lock));
1084
1085     V3_Free(kbd);
1086     return 0;
1087 }
1088
1089
1090
1091
1092 static int keyboard_reset_device(struct keyboard_internal * kbd) {
1093   
1094
1095     kbd->mouse_queue.start = 0;
1096     kbd->mouse_queue.end = 0;
1097     kbd->mouse_queue.count = 0;
1098
1099     kbd->kbd_queue.start = 0;
1100     kbd->kbd_queue.end = 0;
1101     kbd->kbd_queue.count = 0;
1102
1103     kbd->mouse_enabled = 0;
1104     kbd->scancode_set = 2;
1105
1106     kbd->state = NORMAL;
1107     kbd->mouse_state = STREAM;
1108
1109     // PS2, keyboard+mouse enabled, generic translation    
1110     kbd->cmd.val = 0;
1111
1112     kbd->cmd.irq_en = 1;
1113     kbd->cmd.mouse_irq_en = 1;
1114     kbd->cmd.self_test_ok = 1;
1115     /** **/
1116
1117
1118     // buffers empty, no errors
1119     kbd->status.val = 0; 
1120
1121     kbd->status.self_test_ok = 1; // self-tests passed
1122     kbd->status.enabled = 1;// keyboard ready
1123     /** **/
1124
1125     
1126     kbd->output_byte = 0;  //  ?
1127
1128     kbd->input_byte = INPUT_RAM;  // we have some
1129     // also display=color, jumper 0, keyboard enabled 
1130
1131     PrintDebug(VM_NONE, VCORE_NONE, "keyboard: reset device\n");
1132  
1133     return 0;
1134
1135 }
1136
1137 #ifdef V3_CONFIG_CHECKPOINT
1138 static int keyboard_save(struct v3_chkpt_ctx * ctx, void * private_data) {
1139     struct keyboard_internal * kbd = (struct keyboard_internal *)private_data;
1140
1141     V3_CHKPT_SAVE(ctx, "CMD_REG", kbd->cmd.val, savefailout);
1142     V3_CHKPT_SAVE(ctx, "STATUS_REG", kbd->status.val, savefailout);
1143     V3_CHKPT_SAVE(ctx, "STATE", kbd->state, savefailout);
1144     V3_CHKPT_SAVE(ctx, "MOUSE_STATE", kbd->mouse_state, savefailout);
1145     V3_CHKPT_SAVE(ctx, "OUTPUT", kbd->output_byte, savefailout);
1146     V3_CHKPT_SAVE(ctx, "INPUT", kbd->input_byte, savefailout);
1147     V3_CHKPT_SAVE(ctx, "SCANCODE_SET", kbd->scancode_set, savefailout);
1148     V3_CHKPT_SAVE(ctx, "MOUSE_ENABLED", kbd->mouse_enabled, savefailout);
1149
1150
1151     return 0;
1152
1153  savefailout:
1154     PrintError(VM_NONE, VCORE_NONE, "Failed to save keyboard\n");
1155     return -1;
1156
1157 }
1158
1159
1160 static int keyboard_load(struct v3_chkpt_ctx * ctx, void * private_data) {
1161     struct keyboard_internal * kbd = (struct keyboard_internal *)private_data;
1162     keyboard_reset_device(kbd);
1163
1164     V3_CHKPT_LOAD(ctx, "CMD_REG", kbd->cmd.val, loadfailout);
1165     V3_CHKPT_LOAD(ctx, "STATUS_REG", kbd->status.val, loadfailout);
1166     V3_CHKPT_LOAD(ctx, "STATE", kbd->state, loadfailout);
1167     V3_CHKPT_LOAD(ctx, "MOUSE_STATE", kbd->mouse_state, loadfailout);
1168     V3_CHKPT_LOAD(ctx, "OUTPUT", kbd->output_byte, loadfailout);
1169     V3_CHKPT_LOAD(ctx, "INPUT", kbd->input_byte, loadfailout);
1170     V3_CHKPT_LOAD(ctx, "SCANCODE_SET", kbd->scancode_set, loadfailout);
1171     V3_CHKPT_LOAD(ctx, "MOUSE_ENABLED", kbd->mouse_enabled, loadfailout);
1172
1173
1174     return 0;
1175
1176  loadfailout:
1177     PrintError(VM_NONE, VCORE_NONE, "Failed to load keyboard\n");
1178     return -1;
1179 }
1180
1181 #endif
1182
1183
1184 static struct v3_device_ops dev_ops = { 
1185     .free = (int (*)(void *))keyboard_free,
1186 #ifdef V3_CONFIG_CHECKPOINT
1187     .save = keyboard_save,
1188     .load = keyboard_load
1189 #endif
1190 };
1191
1192
1193
1194
1195 static int keyboard_init(struct v3_vm_info * vm, v3_cfg_tree_t * cfg) {
1196     struct keyboard_internal * kbd = NULL;
1197     char * dev_id = v3_cfg_val(cfg, "ID");
1198     int ret = 0;
1199
1200     PrintDebug(vm, VCORE_NONE, "keyboard: init_device\n");
1201
1202     kbd = (struct keyboard_internal *)V3_Malloc(sizeof(struct keyboard_internal));
1203
1204     if (!kbd) {
1205         PrintError(vm, VCORE_NONE, "Cannot allocate in init\n");
1206         return -1;
1207     }
1208
1209     // Brings up keyboard in NORMAL and mouse in STREAM
1210     memset(kbd, 0, sizeof(struct keyboard_internal));
1211
1212     kbd->vm = vm;
1213
1214     struct vm_device * dev = v3_add_device(vm, dev_id, &dev_ops, kbd);
1215
1216     if (dev == NULL) {
1217         PrintError(vm, VCORE_NONE, "Could not attach device %s\n", dev_id);
1218         V3_Free(kbd);
1219         return -1;
1220     }
1221
1222     keyboard_reset_device(kbd);
1223
1224
1225     v3_lock_init(&(kbd->kb_lock));
1226
1227
1228     // hook ports
1229     ret |= v3_dev_hook_io(dev, KEYBOARD_64H, &keyboard_read_status, &keyboard_write_command);
1230     ret |= v3_dev_hook_io(dev, KEYBOARD_60H, &keyboard_read_input, &keyboard_write_output);
1231
1232     if (ret != 0) {
1233         PrintError(vm, VCORE_NONE, "Error hooking keyboard IO ports\n");
1234         v3_remove_device(dev);
1235         return -1;
1236     }
1237
1238     v3_hook_host_event(vm, HOST_KEYBOARD_EVT, V3_HOST_EVENT_HANDLER(key_event_handler), kbd);
1239     v3_hook_host_event(vm, HOST_MOUSE_EVT, V3_HOST_EVENT_HANDLER(mouse_event_handler), kbd);
1240
1241
1242 #if KEYBOARD_DEBUG_80H
1243     v3_dev_hook_io(dev, KEYBOARD_DELAY_80H, &keyboard_read_delay, &keyboard_write_delay);
1244 #endif
1245
1246   
1247     //
1248     // We do not hook the IRQ here.  Instead, the underlying device driver
1249     // is responsible to call us back
1250     // 
1251
1252     return 0;
1253 }
1254
1255
1256 device_register("KEYBOARD", keyboard_init)