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.


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