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
index 82d4543..c5b5281 100644 (file)
@@ -26,9 +26,9 @@
 #include <palacios/vmm_intr.h>
 #include <palacios/vmm_host_events.h>
 #include <palacios/vm_guest.h>
+#include <palacios/vmm_debug.h>
 
-
-#ifndef CONFIG_DEBUG_KEYBOARD
+#ifndef V3_CONFIG_DEBUG_KEYBOARD
 #undef PrintDebug
 #define PrintDebug(fmt, args...)
 #endif
@@ -157,7 +157,7 @@ struct keyboard_internal {
     // from the onboard microcontroller
     enum {// Normal mode measn we deliver keys
         // to the vm and accept commands from it
-        NORMAL,
+        NORMAL=0,
        // after receiving cmd 0x60
        // keybaord uC cmd will subsequently arrive
        WRITING_CMD_BYTE,  
@@ -185,12 +185,18 @@ struct keyboard_internal {
        // After the Keyboard SET_RATE is called
        // we wait for the output byte on 64?
        SET_RATE,
+        // after having a f0 sent to 60
+       // we wait for a new output byte on 60
+       GETSET_SCANCODES,
+       // first send ACK (0xfa)
+       // then wait for reception, and reset kb state
+       SET_DEFAULTS,
     } state;
 
 
     enum {
        // Normal mouse state
-       STREAM, 
+       STREAM=0, 
        // this is used for setting sample rate
        SAMPLE,
        // set resolution
@@ -208,20 +214,34 @@ struct keyboard_internal {
     // Data for system
     uint8_t wrap;     
 
-    int mouse_enabled;
+    uint8_t mouse_enabled;
+    uint8_t scancode_set;
 
     struct queue kbd_queue;
     struct queue mouse_queue;
 
+    struct v3_vm_info * vm;
+
     v3_lock_t kb_lock;
 };
 
 
-static int update_kb_irq(struct vm_device * dev) {
-    struct keyboard_internal *state = (struct keyboard_internal *)(dev->private_data);
+static int keyboard_reset_device(struct keyboard_internal * kbd);
+
+
+static int update_kb_irq(struct keyboard_internal * state) {
     int irq_num = 0;
 
 
+    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);
+
+    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);
+
+
+    PrintDebug(VM_NONE, VCORE_NONE, "keyboard: update_kb_irq: kbd_queue.couunt = %u mouse_queue.count = %u\n", 
+              state->kbd_queue.count, state->mouse_queue.count);
+
+
     state->status.out_buf_full = 0;
     state->status.mouse_buf_full = 0;
 
@@ -234,14 +254,18 @@ static int update_kb_irq(struct vm_device * dev) {
        state->status.mouse_buf_full = 1;
     } 
     
-    PrintDebug("keyboard: interrupt 0x%d\n", irq_num);
+    PrintDebug(VM_NONE, VCORE_NONE, "keyboard: update_kb_irq: interrupt 0x%x\n", irq_num);
     
     if (irq_num) {
        // Global output buffer flag (for both Keyboard and mouse)
        state->status.out_buf_full = 1;
        
-       if (state->cmd.irq_en == 1) { 
-           v3_raise_irq(dev->vm, irq_num);
+       if ((irq_num==KEYBOARD_IRQ && state->cmd.irq_en == 1) || 
+           (irq_num==MOUSE_IRQ && state->cmd.mouse_irq_en == 1)) { 
+
+           PrintDebug(VM_NONE, VCORE_NONE, "keyboard: update_kb_irq: raising 0x%x\n", irq_num);
+
+           v3_raise_irq(state->vm, irq_num);
        }
     }
 
@@ -255,8 +279,7 @@ static int update_kb_irq(struct vm_device * dev) {
  * If we keep reading an empty queue we return the last queue entry
  */
 
-static int push_to_output_queue(struct vm_device * dev, uint8_t value, uint8_t cmd, uint8_t mouse) {
-    struct keyboard_internal * state = (struct keyboard_internal *)(dev->private_data);
+static int push_to_output_queue(struct keyboard_internal * state, uint8_t value, uint8_t cmd, uint8_t mouse) {
     struct queue * q = NULL;
 
 
@@ -266,7 +289,7 @@ static int push_to_output_queue(struct vm_device * dev, uint8_t value, uint8_t c
        q = &(state->kbd_queue);
     }
 
-    if (q->count == QUEUE_SIZE) {
+    if (q->count >= QUEUE_SIZE) {
        return 0;
     }
 
@@ -276,59 +299,71 @@ static int push_to_output_queue(struct vm_device * dev, uint8_t value, uint8_t c
        state->status.cmd = 0;
     }
 
-    q->queue[q->end++] = value;
+    q->queue[q->end] = value;
+
+    if (q->end >= (QUEUE_SIZE - 1)) {
+       q->end = 0;
+    } else {
+       q->end++;
+    }
+
     q->count++;
 
 
-    update_kb_irq(dev);
+    update_kb_irq(state);
 
     return 0;
 }
 
 
 
-static int pull_from_output_queue(struct vm_device * dev, uint8_t * value) {
-    struct keyboard_internal * state = (struct keyboard_internal *)(dev->private_data);
+static int pull_from_output_queue(struct keyboard_internal * state, uint8_t * value) {
     struct queue * q = NULL;
 
     if (state->kbd_queue.count > 0) {
        q = &(state->kbd_queue);
-       PrintDebug("Reading from Keyboard Queue\n");
+       PrintDebug(VM_NONE, VCORE_NONE, "Reading from Keyboard Queue\n");
     } else if (state->mouse_queue.count > 0) {
        q = &(state->mouse_queue);
-       PrintDebug("Reading from Mouse Queue\n");
+       PrintDebug(VM_NONE, VCORE_NONE, "Reading from Mouse Queue\n");
     } else {
        uint8_t idx = state->kbd_queue.start - 1;
-       PrintDebug("No Data in any queue\n");
+       PrintDebug(VM_NONE, VCORE_NONE, "No Data in any queue\n");
        *value = state->kbd_queue.queue[idx];
        return 0;
     }
 
-    *value = q->queue[q->start++];
+    *value = q->queue[q->start];
+
+    if (q->start >= (QUEUE_SIZE - 1)) {
+       q->start = 0;
+    } else {
+       q->start++;
+    }
+
     q->count--;
 
 
-    PrintDebug("Read from Queue: %x\n", *value);
-    PrintDebug("QStart=%d, QEnd=%d\n", q->start, q->end);
+    PrintDebug(VM_NONE, VCORE_NONE, "Read from Queue: %x\n", *value);
+    PrintDebug(VM_NONE, VCORE_NONE, "QStart=%d, QEnd=%d\n", q->start, q->end);
 
-    update_kb_irq(dev);
+    update_kb_irq(state);
 
     return 0;
 }
 
 
 #include <palacios/vmm_telemetry.h>
-#ifdef CONFIG_SYMMOD
+#ifdef V3_CONFIG_SYMMOD
 #include <palacios/vmm_symmod.h>
 #endif
 
 static int key_event_handler(struct v3_vm_info * vm, 
                             struct v3_keyboard_event * evt, 
                             void * private_data) {
-    struct vm_device * dev = (struct vm_device *)private_data;
-    struct keyboard_internal *state = (struct keyboard_internal *)(dev->private_data);
+    struct keyboard_internal * state = (struct keyboard_internal *)private_data;
 
-    PrintDebug("keyboard: injected status 0x%x, and scancode 0x%x\n", evt->status, evt->scan_code);
+    PrintDebug(vm, VCORE_NONE, "keyboard: injected status 0x%x, and scancode 0x%x\n", evt->status, evt->scan_code);
 
     if (evt->scan_code == 0x44) { // F10 debug dump
        int i = 0;
@@ -337,10 +372,10 @@ static int key_event_handler(struct v3_vm_info * vm,
        }
        //      PrintGuestPageTables(info, info->shdw_pg_state.guest_cr3);
     } 
-#ifdef CONFIG_SYMCALL
+#ifdef V3_CONFIG_SYMCALL
     else if (evt->scan_code == 0x43) { // F9 Sym test
        struct guest_info * core = &(vm->cores[0]);
-       PrintDebug("Testing sym call\n");
+       PrintDebug(vm, VCORE_NONE, "Testing sym call\n");
        sym_arg_t a0 = 0x1111;
        sym_arg_t a1 = 0x2222;
        sym_arg_t a2 = 0x3333;
@@ -349,15 +384,15 @@ static int key_event_handler(struct v3_vm_info * vm,
        uint64_t call_start = 0;
        uint64_t call_end = 0;
        
-       V3_Print("Exits before symcall: %d\n", (uint32_t)core->num_exits);
+       V3_Print(vm, VCORE_NONE, "Exits before symcall: %d\n", (uint32_t)core->num_exits);
 
        rdtscll(call_start);
        v3_sym_call5(core, SYMCALL_TEST, &a0, &a1, &a2, &a3, &a4);
        rdtscll(call_end);
        
-       V3_Print("Symcall latency = %d cycles (%d exits)\n", (uint32_t)(call_end - call_start), (uint32_t)core->num_exits);
+       V3_Print(vm, VCORE_NONE, "Symcall latency = %d cycles (%d exits)\n", (uint32_t)(call_end - call_start), (uint32_t)core->num_exits);
 
-       V3_Print("Symcall  Test Returned arg0=%x, arg1=%x, arg2=%x, arg3=%x, arg4=%x\n",
+       V3_Print(vm, VCORE_NONE, "Symcall  Test Returned arg0=%x, arg1=%x, arg2=%x, arg3=%x, arg4=%x\n",
                 (uint32_t)a0, (uint32_t)a1, (uint32_t)a2, (uint32_t)a3, (uint32_t)a4);
 
     } 
@@ -365,19 +400,19 @@ static int key_event_handler(struct v3_vm_info * vm,
     else if (evt->scan_code == 0x42) { // F8 debug toggle
        extern int v3_dbg_enable;
        
-       PrintDebug("Toggling Debugging\n");     
+       PrintDebug(vm, VCORE_NONE, "Toggling Debugging\n");     
        v3_dbg_enable ^= 1;
 
     } 
-#ifdef CONFIG_TELEMETRY
+#ifdef V3_CONFIG_TELEMETRY
 
     else if (evt->scan_code == 0x41) { // F7 telemetry dump
-       v3_print_telemetry(vm);
+       v3_print_global_telemetry(vm);
     } 
 #endif
-#ifdef CONFIG_SYMMOD
+#ifdef V3_CONFIG_SYMMOD
     else if (evt->scan_code == 0x40) { // F6 Test symmod load
-       v3_load_sym_module(vm, "test_32");
+       v3_load_sym_capsule(vm, "lnx_test");
     }
 #endif
 
@@ -387,7 +422,7 @@ static int key_event_handler(struct v3_vm_info * vm,
     if ( (state->status.enabled == 1)      // onboard is enabled
         && (state->cmd.disable == 0) )  {   // keyboard is enabled
     
-       push_to_output_queue(dev, evt->scan_code, DATA, KEYBOARD);
+       push_to_output_queue(state, evt->scan_code, DATA, KEYBOARD);
     }
 
     v3_unlock_irqrestore(state->kb_lock, irq_state);
@@ -399,202 +434,195 @@ static int key_event_handler(struct v3_vm_info * vm,
 static int mouse_event_handler(struct v3_vm_info * vm, 
                               struct v3_mouse_event * evt, 
                               void * private_data) {
-    struct vm_device * dev = (struct vm_device *)private_data;
-    struct keyboard_internal * state = (struct keyboard_internal *)(dev->private_data);
+    struct keyboard_internal * kbd = (struct keyboard_internal *)private_data;
     int ret = 0;
 
-    PrintDebug("keyboard: injected mouse packet 0x %x %x %x\n",
-              evt->data[0], evt->data[1], evt->data[2]);
+    PrintDebug(vm, VCORE_NONE, "keyboard: injected mouse packet sx=%u dx=%u sy=%u dy=%u buttons=0x%x\n",
+              evt->sx, evt->dx, evt->sy, evt->dy, evt->buttons);
   
-    addr_t irq_state = v3_lock_irqsave(state->kb_lock);
 
-    switch (state->mouse_state) { 
-       case STREAM:
+    PrintDebug(vm, VCORE_NONE, "keyboard: mouse state is %s\n", 
+              kbd->mouse_state==STREAM ? "STREAM" :
+              kbd->mouse_state==SAMPLE ? "SAMPLE" :
+              kbd->mouse_state==SET_RES ? "SET_RES" : "UNKNOWN");
+
+    addr_t irq_state = v3_lock_irqsave(kbd->kb_lock);
 
-           if (state->cmd.mouse_disable == 0) {
-               push_to_output_queue(dev, evt->data[0], DATA, MOUSE);
-               push_to_output_queue(dev, evt->data[1], DATA, MOUSE);
-               push_to_output_queue(dev, evt->data[2], DATA, MOUSE);
+    switch (kbd->mouse_state) { 
+       case STREAM:
+           // packet is 3 bytes of form
+           // YO | XO | YS | XS | 1 | MIDDLE | RIGHT | LEFT
+           // DX
+           // YY
+           if (kbd->cmd.mouse_disable == 0) {
+               uint8_t h;
+               // YO=0
+               // XO=0
+               // bit 3 set
+               h=0x08; 
+               // YS bit
+               h |= (!!(evt->sy)) << 5;
+               // XS bit
+               h |= (!!(evt->sx)) << 4;
+               // buttons
+               h |= (evt->buttons) & 0x7;
+               // header byte
+               push_to_output_queue(kbd, h, DATA, MOUSE);
+               // dx
+               push_to_output_queue(kbd, evt->dx, DATA, MOUSE);
+               // dy
+               push_to_output_queue(kbd, evt->dy, DATA, MOUSE);
+           } else {
+               PrintDebug(vm,VCORE_NONE, "Ignoring mouse event because mouse is disabled\n");
            }
            break;
        default:
-           PrintError("Invalid mouse state\n");
-           ret = -1;
+           PrintDebug(vm, VCORE_NONE, "Ignoring mouse event due to mouse not being in stream mode\n");
+           ret = 0;
            break;
     }
 
 
-    v3_unlock_irqrestore(state->kb_lock, irq_state);
+    v3_unlock_irqrestore(kbd->kb_lock, irq_state);
 
     return ret;
 }
 
 
-static int keyboard_reset_device(struct vm_device * dev) {
-    struct keyboard_internal * data = (struct keyboard_internal *)(dev->private_data);
-  
-    memset(data, 0, sizeof(struct keyboard_internal));
-
-    data->state = NORMAL;
-    data->mouse_state = STREAM;
 
 
-    // PS2, keyboard+mouse enabled, generic translation    
-    data->cmd.val = 0;
 
-    data->cmd.irq_en = 1;
-    data->cmd.mouse_irq_en = 1;
-    data->cmd.self_test_ok = 1;
-    /** **/
 
 
-    // buffers empty, no errors
-    data->status.val = 0; 
 
-    data->status.self_test_ok = 1; // self-tests passed
-    data->status.enabled = 1;// keyboard ready
-    /** **/
 
-    
-    data->output_byte = 0;  //  ?
 
-    data->input_byte = INPUT_RAM;  // we have some
-    // also display=color, jumper 0, keyboard enabled 
+static int mouse_write_output(struct keyboard_internal * kbd, uint8_t data) {
 
-    PrintDebug("keyboard: reset device\n");
-    return 0;
-
-}
-
-
-
-static int keyboard_start_device(struct vm_device * dev) {
-    PrintDebug("keyboard: start device\n");
-    return 0;
-}
-
-
-static int keyboard_stop_device(struct vm_device * dev) {
-    PrintDebug("keyboard: stop device\n");
-    return 0;
-}
-
-
-
-static int mouse_write_output(struct vm_device * dev, uint8_t data) {
-    struct keyboard_internal * state = (struct keyboard_internal *)(dev->private_data);
-
-    switch (state->mouse_state) { 
-       case NORMAL:
+    switch (kbd->mouse_state) { 
+       case STREAM: // NORMAL mode for mouse
            switch (data) {
 
                case 0xff: //reset
-                   if (state->mouse_enabled == 0) {
-                       push_to_output_queue(dev, 0xfe, DATA, MOUSE) ;   // no mouse!
+                   if (kbd->mouse_enabled == 0) {
+                       push_to_output_queue(kbd, 0xfe, DATA, MOUSE) ;   // no mouse!
                    } else {
-                       push_to_output_queue(dev, MOUSE_ACK, DATA, MOUSE) ; 
-                       push_to_output_queue(dev, 0xaa, DATA, MOUSE) ; 
-                       push_to_output_queue(dev, 0x00, DATA, MOUSE) ; 
+                       push_to_output_queue(kbd, MOUSE_ACK, DATA, MOUSE) ; 
+                       push_to_output_queue(kbd, 0xaa, DATA, MOUSE) ; 
+                       push_to_output_queue(kbd, 0x00, DATA, MOUSE) ; 
                    }
                    break;
 
 /*             case 0xfe: //resend */
-/*                 PushToOutputQueue(dev, 0xfa, OVERWRITE, DATA, MOUSE) ;  */
-/*                 PrintDebug(" mouse resend begins "); */
-/*                 state->mouse_done_after_ack = 0; */
-/*                 state->mouse_needs_ack = 0; */
-/*                 state->mouse_state = STREAM1; */
+/*                 PushToOutputQueue(kbd, 0xfa, OVERWRITE, DATA, MOUSE) ;  */
+/*                 PrintDebug(VM_NONE, VCORE_NONE, " mouse resend begins "); */
+/*                 kbd->mouse_done_after_ack = 0; */
+/*                 kbd->mouse_needs_ack = 0; */
+/*                 kbd->mouse_state = STREAM1; */
 /*                 return 0;  // not done */
 /*                 break; */
       
                case 0xf6: // set defaults
-                   push_to_output_queue(dev, MOUSE_ACK, DATA, MOUSE) ; 
-                   PrintDebug(" mouse set defaults ");
-
+                   push_to_output_queue(kbd, MOUSE_ACK, DATA, MOUSE) ; 
+                   PrintDebug(VM_NONE, VCORE_NONE, "keyboard: mouse set defaults mouse_state=%u\n", kbd->mouse_state);
                    break;
       
                case 0xf5: // disable data reporting 
-                   push_to_output_queue(dev, MOUSE_ACK, DATA, MOUSE) ; 
-                   PrintDebug(" mouse disable data reporting ");
+                   push_to_output_queue(kbd, MOUSE_ACK, DATA, MOUSE) ; 
+                   PrintDebug(VM_NONE, VCORE_NONE, "keyboard: mouse disable data reporting\n");
                    break;
       
                case 0xf4: // enable data reporting 
-                   push_to_output_queue(dev, MOUSE_ACK, DATA, MOUSE) ; 
-                   PrintDebug(" mouse enable data reporting ");
+                   push_to_output_queue(kbd, MOUSE_ACK, DATA, MOUSE) ; 
+                   PrintDebug(VM_NONE, VCORE_NONE, "keyboard: mouse enable data reporting\n");
                    break;
       
                case 0xf3: // set sample rate
-                   push_to_output_queue(dev, MOUSE_ACK, DATA, MOUSE) ; 
-                   state->mouse_state = SAMPLE;
-                   PrintDebug(" mouse set sample rate begins ");
+                   push_to_output_queue(kbd, MOUSE_ACK, DATA, MOUSE) ; 
+                   kbd->mouse_state = SAMPLE;
+                   PrintDebug(VM_NONE, VCORE_NONE, "keyboard:  mouse set sample rate begins\n");
                    break;
       
                case 0xf2: // get device id
-                   push_to_output_queue(dev, MOUSE_ACK, DATA, MOUSE) ; 
-                   push_to_output_queue(dev, 0x0,  DATA, MOUSE); 
-                   PrintDebug(" mouse get device id begins ");
+                   push_to_output_queue(kbd, MOUSE_ACK, DATA, MOUSE) ; 
+                   push_to_output_queue(kbd, 0x0,  DATA, MOUSE); 
+                   PrintDebug(VM_NONE, VCORE_NONE, "keyboard: mouse get device id begins\n");
                    break;
       
                case 0xf0: // set remote mode
-                   push_to_output_queue(dev, MOUSE_ACK, DATA, MOUSE) ; 
-                   PrintDebug(" mouse set remote mode  ");
+                   push_to_output_queue(kbd, MOUSE_ACK, DATA, MOUSE) ; 
+                   PrintDebug(VM_NONE, VCORE_NONE, "keyboard: mouse set remote mode (ignored)\n");
                    break;
 
                case 0xee: // set wrap mode
-                   push_to_output_queue(dev, MOUSE_ACK, DATA, MOUSE) ; 
-                   PrintError(" mouse set wrap mode (ignored)  ");
+                   push_to_output_queue(kbd, MOUSE_ACK, DATA, MOUSE) ; 
+                   PrintError(VM_NONE, VCORE_NONE, "keyboard: mouse set wrap mode (ignored)\n");
                    break;
 
                case 0xec: // reset wrap mode
-                   push_to_output_queue(dev, MOUSE_ACK, DATA, MOUSE) ; 
-                   PrintError(" mouse reset wrap mode (ignored)  ");
+                   push_to_output_queue(kbd, MOUSE_ACK, DATA, MOUSE) ; 
+                   PrintError(VM_NONE, VCORE_NONE, "keyboard:  mouse reset wrap mode (ignored)\n");
                    break;
 
                case 0xeb: // read data
-                   push_to_output_queue(dev, MOUSE_ACK, DATA, MOUSE) ; 
-                   PrintError(" mouse switch to wrap mode (ignored)  ");
+                   push_to_output_queue(kbd, MOUSE_ACK, DATA, MOUSE) ; 
+                   PrintError(VM_NONE, VCORE_NONE, "keyboard:  mouse switch to wrap mode (ignored)\n");
                    break;
       
                case 0xea: // set stream mode
-                   push_to_output_queue(dev, MOUSE_ACK, DATA, MOUSE) ; 
-                   PrintDebug(" mouse set stream mode  ");
+                   push_to_output_queue(kbd, MOUSE_ACK, DATA, MOUSE) ; 
+                   PrintDebug(VM_NONE, VCORE_NONE, "keyboard:  mouse set stream mode\n");
                    break;
 
                case 0xe9: // status request
-                   push_to_output_queue(dev, MOUSE_ACK, DATA, MOUSE) ; 
-                   push_to_output_queue(dev, 0x00, DATA, MOUSE); 
-                   push_to_output_queue(dev, 0x00, DATA, MOUSE);
-                   push_to_output_queue(dev, 0x00, DATA, MOUSE); 
-                   PrintDebug(" mouse status request begins  ");
+                   push_to_output_queue(kbd, MOUSE_ACK, DATA, MOUSE) ; 
+                   push_to_output_queue(kbd, 0x00, DATA, MOUSE); 
+                   push_to_output_queue(kbd, 0x00, DATA, MOUSE);
+                   push_to_output_queue(kbd, 0x00, DATA, MOUSE); 
+                   PrintDebug(VM_NONE, VCORE_NONE, "keyboard:  mouse status request begins\n");
                    break;
 
                case 0xe8: // set resolution
-                   push_to_output_queue(dev, MOUSE_ACK,  DATA, MOUSE) ; 
-                   PrintDebug(" mouse set resolution begins  ");
-                   state->mouse_state = SET_RES;
+                   push_to_output_queue(kbd, MOUSE_ACK,  DATA, MOUSE) ; 
+                   PrintDebug(VM_NONE, VCORE_NONE, "keyboard:  mouse set resolution begins\n");
+                   kbd->mouse_state = SET_RES;
                    break;
 
                case 0xe7: // set scaling 2:1
-                   push_to_output_queue(dev, MOUSE_ACK, DATA, MOUSE) ; 
-                   PrintDebug(" mouse set scaling 2:1 ");
+                   push_to_output_queue(kbd, MOUSE_ACK, DATA, MOUSE) ; 
+                   PrintDebug(VM_NONE, VCORE_NONE, "keyboard:  mouse set scaling 2:1\n");
                    break;
 
                case 0xe6: // set scaling 1:1
-                   push_to_output_queue(dev, MOUSE_ACK, DATA, MOUSE) ; 
-                   PrintDebug(" mouse set scaling 1:1 ");
+                   push_to_output_queue(kbd, MOUSE_ACK, DATA, MOUSE) ; 
+                   PrintDebug(VM_NONE, VCORE_NONE, "keyboard:  mouse set scaling 1:1\n");
+                   break;
+      
+
+               case 0xe1: // Read secondary ID
+                   push_to_output_queue(kbd, MOUSE_ACK, DATA, MOUSE) ;
+                   PrintDebug(VM_NONE, VCORE_NONE, "keyboard: mouse read secondary ID (ignored)\n");
                    break;
       
                default:
-                   PrintDebug(" receiving unknown mouse command (0x%x) in acceptable state ", data);
+                   PrintDebug(VM_NONE, VCORE_NONE, "keyboard:  receiving unknown mouse command (0x%x) in stream state\n", data);
                    break;
            }
 
            break;
+
        case SAMPLE:
+           PrintDebug(VM_NONE, VCORE_NONE, "keyboard: mouse setting sample rate to %u (ignored)", data);
+           kbd->mouse_state = STREAM;
+           break;
+
        case SET_RES:
+           PrintDebug(VM_NONE, VCORE_NONE, "keyboard: mouse setting resolution to %u (ignored)", data);
+           kbd->mouse_state = STREAM;
+           break;
+
        default:
-           PrintDebug(" receiving mouse output in unhandled state (0x%x) ", state->mouse_state);
+           PrintDebug(VM_NONE, VCORE_NONE, "keyboard: received mouse output in unknown state %u\n", kbd->mouse_state);
            return -1;
     }
 
@@ -604,27 +632,27 @@ static int mouse_write_output(struct vm_device * dev, uint8_t data) {
 
 
 #if KEYBOARD_DEBUG_80H
-static int keyboard_write_delay(ushort_t port, void * src,  uint_t length, struct vm_device * dev) {
+static int keyboard_write_delay(struct guest_info *core, ushort_t port, void * src,  uint_t length, void * priv_data) {
 
     if (length == 1) { 
-       PrintDebug("keyboard: write of 0x%x to 80h\n", *((uint8_t*)src));
+       PrintDebug(core->vm_info, core, "keyboard: write of 0x%x to 80h\n", *((uint8_t*)src));
        return 1;
     } else {
-       PrintDebug("keyboard: write of >1 byte to 80h\n", *((uint8_t*)src));
+       PrintDebug(core->vm_info, core, "keyboard: write of >1 byte to 80h\n", *((uint8_t*)src));
        return length;
     }
 }
 
-static int keyboard_read_delay(struct guest_info * core, ushort_t port, void * dest, uint_t length, struct vm_device * dev) {
+static int keyboard_read_delay(struct guest_info * core, ushort_t port, void * dest, uint_t length, void * priv_data) {
 
     if (length == 1) { 
        *(uint8_t *)dest = v3_inb(port);
 
-       PrintDebug("keyboard: read of 0x%x from 80h\n", *((uint8_t*)dest));
+       PrintDebug(core->vm_info, core, "keyboard: read of 0x%x from 80h\n", *((uint8_t*)dest));
 
        return 1;
     } else {
-       PrintDebug("keyboard: read of >1 byte from 80h\n");
+       PrintDebug(core->vm_info, core, "keyboard: read of >1 byte from 80h\n");
 
        return length;
     }
@@ -635,146 +663,147 @@ static int keyboard_read_delay(struct guest_info * core, ushort_t port, void * d
 
 
 
-static int keyboard_write_command(struct guest_info * core, ushort_t port, void * src, uint_t length, struct vm_device * dev) {
-    struct keyboard_internal * state = (struct keyboard_internal *)(dev->private_data);
+static int keyboard_write_command(struct guest_info * core, ushort_t port, void * src, uint_t length, void * priv_data) {
+    struct keyboard_internal * kbd = priv_data;
     uint8_t cmd = *(uint8_t *)src;
 
     // Should always be single byte write
     if (length != 1) { 
-       PrintError("keyboard: write of >1 bytes (%d) to 64h\n", length);
+       PrintError(core->vm_info, core, "keyboard: write of >1 bytes (%d) to 64h\n", length);
        return -1;
     }
 
 
-    addr_t irq_state = v3_lock_irqsave(state->kb_lock);
+    addr_t irq_state = v3_lock_irqsave(kbd->kb_lock);
 
-    if (state->state != NORMAL) { 
-       PrintDebug("keyboard: warning - receiving command on 64h but state != NORMAL\n");
+    if (kbd->state != NORMAL) { 
+       PrintDebug(core->vm_info, core, "keyboard: warning - receiving command on 64h but state != NORMAL\n");
     }
   
-    PrintDebug("keyboard: command 0x%x on 64h\n", cmd);
+    PrintDebug(core->vm_info, core, "keyboard: command 0x%x on 64h\n", cmd);
 
     switch (cmd) { 
        case 0x20:  // READ COMMAND BYTE (returned in 60h)
-           push_to_output_queue(dev, state->cmd.val, COMMAND, KEYBOARD);
-           PrintDebug("keyboard: command byte 0x%x returned\n", state->cmd.val);
+           push_to_output_queue(kbd, kbd->cmd.val, COMMAND, KEYBOARD);
+           PrintDebug(core->vm_info, core, "keyboard: command byte 0x%x returned\n", kbd->cmd.val);
            break;
 
        case 0x60:  // WRITE COMMAND BYTE (read from 60h)
-           state->state = WRITING_CMD_BYTE; // we need to make sure we send the next 0x60 byte appropriately
-           PrintDebug("keyboard: prepare to write command byte\n");
+           kbd->state = WRITING_CMD_BYTE; // we need to make sure we send the next 0x60 byte appropriately
+           PrintDebug(core->vm_info, core, "keyboard: prepare to write command byte\n");
            break;
 
            // case 0x90-9f - write to output port  (?)
 
        case 0xa1: // Get version number
-           push_to_output_queue(dev, 0x00, COMMAND, KEYBOARD);
-           PrintDebug("keyboard: version number 0x0 returned\n");
+           push_to_output_queue(kbd, 0x00, COMMAND, KEYBOARD);
+           PrintDebug(core->vm_info, core, "keyboard: version number 0x0 returned\n");
            break;
 
        case 0xa4:  // is password installed?  send result to 0x60
            // we don't support passwords
-           push_to_output_queue(dev, 0xf1, COMMAND, KEYBOARD);
-           PrintDebug("keyboard: password not installed\n");
+           push_to_output_queue(kbd, 0xf1, COMMAND, KEYBOARD);
+           PrintDebug(core->vm_info, core, "keyboard: password not installed\n");
            break;
 
        case 0xa5:  // new password will arrive on 0x60
-           state->state = TRANSMIT_PASSWD;
-           PrintDebug("keyboard: pepare to transmit password\n");
+           kbd->state = TRANSMIT_PASSWD;
+           PrintDebug(core->vm_info, core, "keyboard: pepare to transmit password\n");
            break;
 
        case 0xa6:  // check passwd;
            // since we do not support passwords, we will simply ignore this
            // the implication is that any password check immediately succeeds 
            // with a blank password
-           PrintDebug("keyboard: password check succeeded\n");
+           PrintDebug(core->vm_info, core, "keyboard: password check succeeded\n");
            break;
 
        case 0xa7:  // disable mouse
-           state->cmd.mouse_disable = 1;
-           PrintDebug("keyboard: mouse disabled\n");
+           kbd->cmd.mouse_disable = 1;
+           PrintDebug(core->vm_info, core, "keyboard: mouse disabled\n");
            break;
 
        case 0xa8:  // enable mouse
-           state->cmd.mouse_disable = 0;
-           PrintDebug("keyboard: mouse enabled\n");
+           kbd->cmd.mouse_disable = 0;
+           PrintDebug(core->vm_info, core, "keyboard: mouse enabled\n");
            break;
 
        case 0xa9:  // mouse interface test  (always succeeds)
-           push_to_output_queue(dev, 0x00, COMMAND, KEYBOARD);
-           PrintDebug("keyboard: mouse interface test succeeded\n");
+           push_to_output_queue(kbd, 0x00, COMMAND, KEYBOARD);
+           PrintDebug(core->vm_info, core, "keyboard: mouse interface test succeeded\n");
            break;
 
        case 0xaa:  // controller self test (always succeeds)
-           push_to_output_queue(dev, 0x55, COMMAND, KEYBOARD);
-           PrintDebug("keyboard: controller self test succeeded\n");
+           push_to_output_queue(kbd, 0x55, COMMAND, KEYBOARD);
+           PrintDebug(core->vm_info, core, "keyboard: controller self test succeeded\n");
            break;
 
        case 0xab:  // keyboard interface test (always succeeds)
-           push_to_output_queue(dev, 0, COMMAND, KEYBOARD);
-           PrintDebug("keyboard: keyboard interface test succeeded\n");
+           push_to_output_queue(kbd, 0, COMMAND, KEYBOARD);
+           PrintDebug(core->vm_info, core, "keyboard: keyboard interface test succeeded\n");
            break;
 
        case 0xad:  // disable keyboard
-           state->cmd.disable = 1;
-           PrintDebug("keyboard: keyboard disabled\n");
+           kbd->cmd.disable = 1;
+           PrintDebug(core->vm_info, core, "keyboard: keyboard disabled\n");
            break;
 
        case 0xae:  // enable keyboard
-           state->cmd.disable = 0;
-           PrintDebug("keyboard: keyboard enabled\n");
+           kbd->cmd.disable = 0;
+           PrintDebug(core->vm_info, core, "keyboard: keyboard enabled\n");
            break;
 
        case 0xaf:  // get version
-           push_to_output_queue(dev, 0x00, COMMAND, KEYBOARD);
-           PrintDebug("keyboard: version 0 returned \n");
+           push_to_output_queue(kbd, 0x00, COMMAND, KEYBOARD);
+           PrintDebug(core->vm_info, core, "keyboard: version 0 returned \n");
            break;
 
        case 0xd0: // return microcontroller output on 60h
-           push_to_output_queue(dev, state->output_byte, COMMAND, KEYBOARD);
-           PrintDebug("keyboard: output byte 0x%x returned\n", state->output_byte);
+           push_to_output_queue(kbd, kbd->output_byte, COMMAND, KEYBOARD);
+           PrintDebug(core->vm_info, core, "keyboard: output byte 0x%x returned\n", kbd->output_byte);
            break;
 
        case 0xd1: // request to write next byte on 60h to the microcontroller output port
-           state->state = WRITING_OUTPUT_PORT;
-           PrintDebug("keyboard: prepare to write output byte\n");
+           kbd->state = WRITING_OUTPUT_PORT;
+           PrintDebug(core->vm_info, core, "keyboard: prepare to write output byte\n");
            break;
 
        case 0xd2:  //  write keyboard buffer (inject key)
-           state->state = INJECTING_KEY;
-           PrintDebug("keyboard: prepare to inject key\n");
+           kbd->state = INJECTING_KEY;
+           PrintDebug(core->vm_info, core, "keyboard: prepare to inject key\n");
            break;
 
        case 0xd3: //  write mouse buffer (inject mouse)
-           state->state = INJECTING_MOUSE;
-           PrintDebug("keyboard: prepare to inject mouse\n");
+           kbd->state = INJECTING_MOUSE;
+           PrintDebug(core->vm_info, core, "keyboard: prepare to inject mouse\n");
            break;
 
-       case 0xd4: // write mouse device (command to mouse?)
-           state->state = IN_MOUSE;
-           PrintDebug("keyboard: prepare to inject mouse command\n");
+       case 0xd4: // write mouse device (command to mouse)
+           kbd->state = IN_MOUSE;
+           PrintDebug(core->vm_info, core, "keyboard: prepare to inject mouse command with mouse_state= %u \n", 
+                      kbd->mouse_state);
            break;
 
        case 0xc0: //  read input port 
-           push_to_output_queue(dev, state->input_byte, COMMAND, KEYBOARD);
-           PrintDebug("keyboard: input byte 0x%x returned\n", state->input_byte);
+           push_to_output_queue(kbd, kbd->input_byte, COMMAND, KEYBOARD);
+           PrintDebug(core->vm_info, core, "keyboard: input byte 0x%x returned\n", kbd->input_byte);
            break;
 
        case 0xc1:  //copy input port lsn to status msn
-           state->status.val &= 0x0f;
-           state->status.val |= (state->input_byte & 0xf) << 4;
-           PrintDebug("keyboard: copied input byte low 4 bits to status reg hi 4 bits\n");
+           kbd->status.val &= 0x0f;
+           kbd->status.val |= (kbd->input_byte & 0xf) << 4;
+           PrintDebug(core->vm_info, core, "keyboard: copied input byte low 4 bits to status reg hi 4 bits\n");
            break;
 
        case 0xc2: // copy input port msn to status msn
-           state->status.val &= 0x0f;
-           state->status.val |= (state->input_byte & 0xf0);
-           PrintDebug("keyboard: copied input byte hi 4 bits to status reg hi 4 bits\n");
+           kbd->status.val &= 0x0f;
+           kbd->status.val |= (kbd->input_byte & 0xf0);
+           PrintDebug(core->vm_info, core, "keyboard: copied input byte hi 4 bits to status reg hi 4 bits\n");
            break;
     
        case 0xe0: // read test port
-           push_to_output_queue(dev, state->output_byte >> 6, COMMAND, KEYBOARD);
-           PrintDebug("keyboard: read 0x%x from test port\n", state->output_byte >> 6);
+           push_to_output_queue(kbd, kbd->output_byte >> 6, COMMAND, KEYBOARD);
+           PrintDebug(core->vm_info, core, "keyboard: read 0x%x from test port\n", kbd->output_byte >> 6);
            break;
 
    
@@ -783,8 +812,8 @@ static int keyboard_write_command(struct guest_info * core, ushort_t port, void
        case 0xf2:   // instead of what is currently in output_byte (I think)
        case 0xf3:   // main effect is taht if bit zero is zero
        case 0xf4:   // should cause reset
-       case 0xf5:   // I doubt anything more recent than a 286 running 
-       case 0xf6:   // OS2 with the penalty box will care
+       case 0xf5:   
+       case 0xf6:   
        case 0xf7:
        case 0xf8:
        case 0xf9:
@@ -794,111 +823,151 @@ static int keyboard_write_command(struct guest_info * core, ushort_t port, void
        case 0xfd:
        case 0xfe:
        case 0xff:
-           PrintDebug("keyboard: ignoring pulse of 0x%x (low=pulsed) on output port\n", (cmd & 0xf));
+           if (!(cmd & 0x1)) { 
+               // general purpose reset
+               PrintDebug(core->vm_info, core, "keyboard: reseting VM\n");
+               v3_reset_vm(core->vm_info);
+
+           } else {
+               PrintDebug(core->vm_info, core, "keyboard: ignoring command 0x%x on output port\n", cmd);
+           }
            break;
    
            // case ac  diagonstic - returns 16 bytes from keyboard microcontroler on 60h
        default:
-           PrintDebug("keyboard: ignoring command (unimplemented)\n");
+           PrintDebug(core->vm_info, core, "keyboard: ignoring command (unimplemented)\n");
            break;
     }
 
-    v3_unlock_irqrestore(state->kb_lock, irq_state);
+    v3_unlock_irqrestore(kbd->kb_lock, irq_state);
 
     return length;
 }
 
-static int keyboard_read_status(struct guest_info * core, ushort_t port, void * dest, uint_t length, struct vm_device * dev) {
-    struct keyboard_internal *state = (struct keyboard_internal *)(dev->private_data);
+static int keyboard_read_status(struct guest_info * core, ushort_t port, void * dest, uint_t length, void * priv_data) {
+    struct keyboard_internal * kbd = priv_data;
 
     if (length != 1) { 
-       PrintError("keyboard: >1 byte read for status (64h)\n");
+       PrintError(core->vm_info, core, "keyboard: >1 byte read for status (64h)\n");
        return -1;
     }
 
-    PrintDebug("keyboard: read status (64h): ");
+    PrintDebug(core->vm_info, core, "keyboard: read status (64h): ");
 
-    addr_t irq_state = v3_lock_irqsave(state->kb_lock);
+    addr_t irq_state = v3_lock_irqsave(kbd->kb_lock);
 
-    *(uint8_t *)dest = state->status.val;
+    *(uint8_t *)dest = kbd->status.val;
 
-    v3_unlock_irqrestore(state->kb_lock, irq_state);
+    v3_unlock_irqrestore(kbd->kb_lock, irq_state);
     
-    PrintDebug("0x%x\n", *(uint8_t *)dest);
+    PrintDebug(core->vm_info, core, "0x%x\n", *(uint8_t *)dest);
     
     return length;
 }
 
-static int keyboard_write_output(struct guest_info * core, ushort_t port, void * src, uint_t length, struct vm_device * dev) {
-    struct keyboard_internal *state = (struct keyboard_internal *)(dev->private_data);
+static int keyboard_write_output(struct guest_info * core, ushort_t port, void * src, uint_t length, void * priv_data) {
+    struct keyboard_internal * kbd = priv_data;
     int ret = length;
 
     if (length != 1) { 
-       PrintError("keyboard: write of 60h with >1 byte\n");
+       PrintError(core->vm_info, core, "keyboard: write of 60h with >1 byte\n");
        return -1;
     }
 
     uint8_t data = *(uint8_t *)src;
   
-    PrintDebug("keyboard: output 0x%x on 60h\n", data);
+    PrintDebug(core->vm_info, core, "keyboard: output 0x%x on 60h with keyboard_state=%u\n", data,kbd->state);
 
-    addr_t irq_state = v3_lock_irqsave(state->kb_lock);
+    addr_t irq_state = v3_lock_irqsave(kbd->kb_lock);
 
-    switch (state->state) {
+    switch (kbd->state) {
        case WRITING_CMD_BYTE:
-           state->cmd.val = data;
-           state->state = NORMAL;
-           PrintDebug("keyboard: wrote new command byte 0x%x\n", state->cmd.val);
+           kbd->cmd.val = data;
+           kbd->state = NORMAL;
+           PrintDebug(core->vm_info, core, "keyboard: wrote new command byte 0x%x\n", kbd->cmd.val);
            break;
 
        case WRITING_OUTPUT_PORT:
-           state->output_byte = data;
-           state->state = NORMAL;
-           PrintDebug("keyboard: wrote new output byte 0x%x\n", state->output_byte);
+           kbd->output_byte = data;
+           kbd->state = NORMAL;
+           PrintDebug(core->vm_info, core, "keyboard: wrote new output byte 0x%x\n", kbd->output_byte);
            break;
 
        case INJECTING_KEY:
-           push_to_output_queue(dev, data, COMMAND, KEYBOARD);  // probably should be a call to deliver_key_to_vmm()
-           state->state = NORMAL;
-           PrintDebug("keyboard: injected key 0x%x\n", data);
+           push_to_output_queue(kbd, data, COMMAND, KEYBOARD);  // probably should be a call to deliver_key_to_vmm()
+           kbd->state = NORMAL;
+           PrintDebug(core->vm_info, core, "keyboard: injected key 0x%x\n", data);
            break;
 
        case INJECTING_MOUSE:
-           push_to_output_queue(dev, data, DATA, MOUSE);
-           //      PrintDebug("keyboard: ignoring injected mouse event 0x%x\n", data);
-           PrintDebug("keyboard: injected mouse event 0x%x\n", data);
-           state->state = NORMAL;
+           push_to_output_queue(kbd, data, DATA, MOUSE);
+           //      PrintDebug(core->vm_info, core, "keyboard: ignoring injected mouse event 0x%x\n", data);
+           PrintDebug(core->vm_info, core, "keyboard: injected mouse event 0x%x\n", data);
+           kbd->state = NORMAL;
            break;
 
        case IN_MOUSE:
-           PrintDebug("keyboard: mouse action: ");
-           if (mouse_write_output(dev, data)) { 
-               state->state = NORMAL;
+           PrintDebug(core->vm_info, core, "keyboard: mouse action\n");
+           if (mouse_write_output(kbd, data)) { 
+               kbd->state = NORMAL;
            }
-           PrintDebug("\n");
            break;
 
        case TRANSMIT_PASSWD:
            if (data) {
                //ignore passwd
-               PrintDebug("keyboard: ignoring password character 0x%x\n",data);
+               PrintDebug(core->vm_info, core, "keyboard: ignoring password character 0x%x\n",data);
            } else {
                // end of password
-               state->state = NORMAL;
-               PrintDebug("keyboard: done with password\n");
+               kbd->state = NORMAL;
+               PrintDebug(core->vm_info, core, "keyboard: done with password\n");
            }
            break;
 
        case SET_LEDS:
-           PrintDebug("Keyboard: LEDs being set...\n");
-           push_to_output_queue(dev, 0xfa, COMMAND, KEYBOARD);
-           state->state = NORMAL;
+           PrintDebug(core->vm_info, core, "Keyboard: LEDs being set...\n");
+           push_to_output_queue(kbd, 0xfa, COMMAND, KEYBOARD);
+           kbd->state = NORMAL;
            break;
 
        case SET_RATE:
-           PrintDebug("Keyboard: Rate being set...\n");
-           push_to_output_queue(dev, 0xfa, COMMAND, KEYBOARD);
-           state->state = NORMAL;
+           PrintDebug(core->vm_info, core, "Keyboard: Rate being set...\n");
+           push_to_output_queue(kbd, 0xfa, COMMAND, KEYBOARD);
+           kbd->state = NORMAL;
+           break;
+
+       case GETSET_SCANCODES:
+           switch (data) {
+               case 0:
+                   PrintDebug(core->vm_info, core, "Keyboard: scancode set being read\n");
+                   push_to_output_queue(kbd, 0x45 - 2 * kbd->scancode_set, COMMAND, KEYBOARD);
+                   break;
+               case 1:
+                   PrintError(core->vm_info, core, "keyboard: unsupported scancode set %d selected\n", data);
+                   return -1;
+               case 2:
+                   PrintDebug(core->vm_info, core, "Keyboard: scancode set being set to %d\n", data);
+                   kbd->scancode_set = data;
+                   push_to_output_queue(kbd, 0xfa, COMMAND, KEYBOARD);
+                   break;
+               case 3:
+                   /* OpenBSD wants scancode set 3, but falls back to 2 if a
+                    * subsequent read reveals that the request was ignored
+                    */
+                   PrintError(core->vm_info, core, "keyboard: ignoring request for scancode set %d\n", data);
+                   break;
+               default:
+                   PrintError(core->vm_info, core, "keyboard: unknown scancode set %d selected\n", data);
+                   ret = -1;
+                    break;
+  
+           }
+           kbd->state = NORMAL;
+           break;
+
+       case SET_DEFAULTS:
+           keyboard_reset_device(kbd);
+           kbd->state = NORMAL;
            break;
 
        default:
@@ -906,34 +975,52 @@ static int keyboard_write_output(struct guest_info * core, ushort_t port, void *
            // command is being sent to keyboard controller
            switch (data) { 
                case 0xff: // reset
-                   push_to_output_queue(dev, 0xfa, COMMAND, KEYBOARD); // ack
-                   push_to_output_queue(dev, 0xaa, COMMAND, KEYBOARD);
-                   PrintDebug("keyboard: reset complete and acked\n");
+                   push_to_output_queue(kbd, 0xfa, COMMAND, KEYBOARD); // ack
+                   push_to_output_queue(kbd, 0xaa, COMMAND, KEYBOARD);
+                   PrintDebug(core->vm_info, core, "keyboard: reset complete and acked\n");
                    break;
 
                case 0xf5: // disable scanning
                case 0xf4: // enable scanning
                    // ack
-                   push_to_output_queue(dev, 0xfa, COMMAND, KEYBOARD);
+                   push_to_output_queue(kbd, 0xfa, COMMAND, KEYBOARD);
                    // should do something here... PAD
-                   PrintDebug("keyboard: %s scanning done and acked\n", (data == 0xf5) ? "disable" : "enable");
+                   PrintDebug(core->vm_info, core, "keyboard: %s scanning done and acked\n", (data == 0xf5) ? "disable" : "enable");
                    break;
 
                case 0xf3:
-                   push_to_output_queue(dev, 0xfa, COMMAND, KEYBOARD);
-                   state->state = SET_RATE;
+                   push_to_output_queue(kbd, 0xfa, COMMAND, KEYBOARD);
+                   kbd->state = SET_RATE;
                    break;
 
                case 0xf2: // get keyboard ID
-                   push_to_output_queue(dev, 0xfa, COMMAND, KEYBOARD);
-                   push_to_output_queue(dev, 0xab, COMMAND, KEYBOARD);
-                   push_to_output_queue(dev, 0x83, COMMAND, KEYBOARD);
-                   PrintDebug("Keyboard: Requesting Keyboard ID\n");
+                   push_to_output_queue(kbd, 0xfa, COMMAND, KEYBOARD);
+                   push_to_output_queue(kbd, 0xab, COMMAND, KEYBOARD);
+                   push_to_output_queue(kbd, 0x83, COMMAND, KEYBOARD);
+                   PrintDebug(core->vm_info, core, "Keyboard: Requesting Keyboard ID\n");
                    break;
 
                case 0xed: // enable keyboard LEDs
-                   push_to_output_queue(dev, 0xfa, COMMAND, KEYBOARD);
-                   state->state = SET_LEDS;
+                   push_to_output_queue(kbd, 0xfa, COMMAND, KEYBOARD);
+                   kbd->state = SET_LEDS;
+                   break;
+
+               case 0xee: // echo, used by FreeBSD to probe controller
+                   push_to_output_queue(kbd, 0xee, COMMAND, KEYBOARD);
+                   break;
+
+               case 0xf0: // get/set scancode set
+                   push_to_output_queue(kbd, 0xfa, COMMAND, KEYBOARD);
+                   kbd->state = GETSET_SCANCODES;
+                   break;
+
+
+               case 0xf6: // set defaults
+                   // ACK command
+                   // clear output buffer
+                   // reset to init state
+                   push_to_output_queue(kbd, 0xfa, COMMAND, KEYBOARD);
+                   kbd->state = SET_DEFAULTS;
                    break;
 
                case 0xfe: // resend
@@ -944,14 +1031,14 @@ static int keyboard_write_output(struct guest_info * core, ushort_t port, void *
                case 0xf9: // set all make
                case 0xf8: // set all make/break
                case 0xf7: // set all typemaktic
-               case 0xf6: // set defaults
-                   PrintError("keyboard: unhandled known command 0x%x on output buffer (60h)\n", data);
+
+                   PrintError(core->vm_info, core, "keyboard: unhandled known command 0x%x on output buffer (60h)\n", data);
                    ret = -1;
                    break;
 
                default:
-                   PrintError("keyboard: unhandled unknown command 0x%x on output buffer (60h)\n", data);
-                   state->status.out_buf_full = 1;
+                   PrintError(core->vm_info, core, "keyboard: unhandled unknown command 0x%x on output buffer (60h)\n", data);
+                   kbd->status.out_buf_full = 1;
                    ret = -1;
                    break;
            }
@@ -959,26 +1046,26 @@ static int keyboard_write_output(struct guest_info * core, ushort_t port, void *
        }
     }
   
-    v3_unlock_irqrestore(state->kb_lock, irq_state);
+    v3_unlock_irqrestore(kbd->kb_lock, irq_state);
 
     return ret;
 }
 
-static int keyboard_read_input(struct guest_info * core, ushort_t port, void * dest, uint_t length, struct vm_device * dev) {
-    struct keyboard_internal * state = (struct keyboard_internal *)(dev->private_data);
+static int keyboard_read_input(struct guest_info * core, ushort_t port, void * dest, uint_t length, void * priv_data) {
+    struct keyboard_internal * kbd = priv_data;
 
     if (length != 1) {
-       PrintError("keyboard: unknown size read from input (60h)\n");
+       PrintError(core->vm_info, core, "keyboard: unknown size read from input (60h)\n");
        return -1;
     }
     
-    addr_t irq_state = v3_lock_irqsave(state->kb_lock);
+    addr_t irq_state = v3_lock_irqsave(kbd->kb_lock);
 
-    pull_from_output_queue(dev, (uint8_t *)dest);
+    pull_from_output_queue(kbd, (uint8_t *)dest);
       
-    v3_unlock_irqrestore(state->kb_lock, irq_state);
+    v3_unlock_irqrestore(kbd->kb_lock, irq_state);
 
-    PrintDebug("keyboard: read from input (60h): 0x%x\n", *(uint8_t *)dest);
+    PrintDebug(core->vm_info, core, "keyboard: read from input (60h): 0x%x\n", *(uint8_t *)dest);
 
     return length;
 }
@@ -988,69 +1075,168 @@ static int keyboard_read_input(struct guest_info * core, ushort_t port, void * d
 
 
 
-static int keyboard_free(struct vm_device * dev) {
+static int keyboard_free(struct keyboard_internal * kbd) {
+    
 
-    v3_dev_unhook_io(dev, KEYBOARD_60H);
-    v3_dev_unhook_io(dev, KEYBOARD_64H);
-#if KEYBOARD_DEBUG_80H
-    v3_dev_unhook_io(dev, KEYBOARD_DELAY_80H);
-#endif
-    keyboard_reset_device(dev);
+    // unhook host events
+
+    v3_lock_deinit(&(kbd->kb_lock));
+
+    V3_Free(kbd);
+    return 0;
+}
+
+
+
+
+static int keyboard_reset_device(struct keyboard_internal * kbd) {
+  
+
+    kbd->mouse_queue.start = 0;
+    kbd->mouse_queue.end = 0;
+    kbd->mouse_queue.count = 0;
+
+    kbd->kbd_queue.start = 0;
+    kbd->kbd_queue.end = 0;
+    kbd->kbd_queue.count = 0;
+
+    kbd->mouse_enabled = 0;
+    kbd->scancode_set = 2;
+
+    kbd->state = NORMAL;
+    kbd->mouse_state = STREAM;
+
+    // PS2, keyboard+mouse enabled, generic translation    
+    kbd->cmd.val = 0;
+
+    kbd->cmd.irq_en = 1;
+    kbd->cmd.mouse_irq_en = 1;
+    kbd->cmd.self_test_ok = 1;
+    /** **/
+
+
+    // buffers empty, no errors
+    kbd->status.val = 0; 
+
+    kbd->status.self_test_ok = 1; // self-tests passed
+    kbd->status.enabled = 1;// keyboard ready
+    /** **/
+
+    
+    kbd->output_byte = 0;  //  ?
+
+    kbd->input_byte = INPUT_RAM;  // we have some
+    // also display=color, jumper 0, keyboard enabled 
+
+    PrintDebug(VM_NONE, VCORE_NONE, "keyboard: reset device\n");
     return 0;
+
 }
 
+#ifdef V3_CONFIG_CHECKPOINT
+static int keyboard_save(struct v3_chkpt_ctx * ctx, void * private_data) {
+    struct keyboard_internal * kbd = (struct keyboard_internal *)private_data;
+
+    V3_CHKPT_SAVE(ctx, "CMD_REG", kbd->cmd.val, savefailout);
+    V3_CHKPT_SAVE(ctx, "STATUS_REG", kbd->status.val, savefailout);
+    V3_CHKPT_SAVE(ctx, "STATE", kbd->state, savefailout);
+    V3_CHKPT_SAVE(ctx, "MOUSE_STATE", kbd->mouse_state, savefailout);
+    V3_CHKPT_SAVE(ctx, "OUTPUT", kbd->output_byte, savefailout);
+    V3_CHKPT_SAVE(ctx, "INPUT", kbd->input_byte, savefailout);
+    V3_CHKPT_SAVE(ctx, "SCANCODE_SET", kbd->scancode_set, savefailout);
+    V3_CHKPT_SAVE(ctx, "MOUSE_ENABLED", kbd->mouse_enabled, savefailout);
+
 
+    return 0;
+
+ savefailout:
+    PrintError(VM_NONE, VCORE_NONE, "Failed to save keyboard\n");
+    return -1;
+
+}
 
 
+static int keyboard_load(struct v3_chkpt_ctx * ctx, void * private_data) {
+    struct keyboard_internal * kbd = (struct keyboard_internal *)private_data;
+    keyboard_reset_device(kbd);
+
+    V3_CHKPT_LOAD(ctx, "CMD_REG", kbd->cmd.val, loadfailout);
+    V3_CHKPT_LOAD(ctx, "STATUS_REG", kbd->status.val, loadfailout);
+    V3_CHKPT_LOAD(ctx, "STATE", kbd->state, loadfailout);
+    V3_CHKPT_LOAD(ctx, "MOUSE_STATE", kbd->mouse_state, loadfailout);
+    V3_CHKPT_LOAD(ctx, "OUTPUT", kbd->output_byte, loadfailout);
+    V3_CHKPT_LOAD(ctx, "INPUT", kbd->input_byte, loadfailout);
+    V3_CHKPT_LOAD(ctx, "SCANCODE_SET", kbd->scancode_set, loadfailout);
+    V3_CHKPT_LOAD(ctx, "MOUSE_ENABLED", kbd->mouse_enabled, loadfailout);
+
+
+    return 0;
+
+ loadfailout:
+    PrintError(VM_NONE, VCORE_NONE, "Failed to load keyboard\n");
+    return -1;
+}
+
+#endif
+
 
 static struct v3_device_ops dev_ops = { 
-    .free = keyboard_free,
-    .reset = keyboard_reset_device,
-    .start = keyboard_start_device,
-    .stop = keyboard_stop_device,
+    .free = (int (*)(void *))keyboard_free,
+#ifdef V3_CONFIG_CHECKPOINT
+    .save = keyboard_save,
+    .load = keyboard_load
+#endif
 };
 
 
 
 
 static int keyboard_init(struct v3_vm_info * vm, v3_cfg_tree_t * cfg) {
-    struct keyboard_internal * keyboard_state = NULL;
-    char * name = v3_cfg_val(cfg, "name");
+    struct keyboard_internal * kbd = NULL;
+    char * dev_id = v3_cfg_val(cfg, "ID");
+    int ret = 0;
 
-    PrintDebug("keyboard: init_device\n");
+    PrintDebug(vm, VCORE_NONE, "keyboard: init_device\n");
 
-    keyboard_state = (struct keyboard_internal *)V3_Malloc(sizeof(struct keyboard_internal));
+    kbd = (struct keyboard_internal *)V3_Malloc(sizeof(struct keyboard_internal));
 
-    keyboard_state->mouse_queue.start = 0;
-    keyboard_state->mouse_queue.end = 0;
-    keyboard_state->mouse_queue.count = 0;
+    if (!kbd) {
+       PrintError(vm, VCORE_NONE, "Cannot allocate in init\n");
+       return -1;
+    }
 
-    keyboard_state->kbd_queue.start = 0;
-    keyboard_state->kbd_queue.end = 0;
-    keyboard_state->kbd_queue.count = 0;
+    // Brings up keyboard in NORMAL and mouse in STREAM
+    memset(kbd, 0, sizeof(struct keyboard_internal));
 
-    keyboard_state->mouse_enabled = 0;
+    kbd->vm = vm;
 
-    struct vm_device * dev = v3_allocate_device(name, &dev_ops, keyboard_state);
+    struct vm_device * dev = v3_add_device(vm, dev_id, &dev_ops, kbd);
 
-    if (v3_attach_device(vm, dev) == -1) {
-       PrintError("Could not attach device %s\n", name);
+    if (dev == NULL) {
+       PrintError(vm, VCORE_NONE, "Could not attach device %s\n", dev_id);
+       V3_Free(kbd);
        return -1;
     }
 
+    keyboard_reset_device(kbd);
 
-    keyboard_reset_device(dev);
 
-
-    v3_lock_init(&(keyboard_state->kb_lock));
+    v3_lock_init(&(kbd->kb_lock));
 
 
     // hook ports
-    v3_dev_hook_io(dev, KEYBOARD_64H, &keyboard_read_status, &keyboard_write_command);
-    v3_dev_hook_io(dev, KEYBOARD_60H, &keyboard_read_input, &keyboard_write_output);
+    ret |= v3_dev_hook_io(dev, KEYBOARD_64H, &keyboard_read_status, &keyboard_write_command);
+    ret |= v3_dev_hook_io(dev, KEYBOARD_60H, &keyboard_read_input, &keyboard_write_output);
+
+    if (ret != 0) {
+       PrintError(vm, VCORE_NONE, "Error hooking keyboard IO ports\n");
+       v3_remove_device(dev);
+       return -1;
+    }
 
-    v3_hook_host_event(vm, HOST_KEYBOARD_EVT, V3_HOST_EVENT_HANDLER(key_event_handler), dev);
-    v3_hook_host_event(vm, HOST_MOUSE_EVT, V3_HOST_EVENT_HANDLER(mouse_event_handler), dev);
+    v3_hook_host_event(vm, HOST_KEYBOARD_EVT, V3_HOST_EVENT_HANDLER(key_event_handler), kbd);
+    v3_hook_host_event(vm, HOST_MOUSE_EVT, V3_HOST_EVENT_HANDLER(mouse_event_handler), kbd);
 
 
 #if KEYBOARD_DEBUG_80H