Merge remote-tracking branch 'spice/spice.v41' into staging
diff --git a/hw/cris_pic_cpu.c b/hw/cris_pic_cpu.c
index a92d445..7f1e4ab 100644
--- a/hw/cris_pic_cpu.c
+++ b/hw/cris_pic_cpu.c
@@ -22,6 +22,7 @@
  * THE SOFTWARE.
  */
 
+#include "sysbus.h"
 #include "hw.h"
 #include "pc.h"
 #include "etraxfs.h"
diff --git a/hw/etraxfs.h b/hw/etraxfs.h
index 5c61f1b..1554b0b 100644
--- a/hw/etraxfs.h
+++ b/hw/etraxfs.h
@@ -25,6 +25,21 @@
 #include "etraxfs_dma.h"
 
 qemu_irq *cris_pic_init_cpu(CPUState *env);
-void etraxfs_eth_init(NICInfo *nd, target_phys_addr_t base, int phyaddr,
-                      struct etraxfs_dma_client *dma_out,
-                      struct etraxfs_dma_client *dma_in);
+
+/* Instantiate an ETRAXFS Ethernet MAC.  */
+static inline DeviceState *
+etraxfs_eth_init(NICInfo *nd, target_phys_addr_t base, int phyaddr,
+                 void *dma_out, void *dma_in)
+{
+    DeviceState *dev;
+    qemu_check_nic_model(nd, "fseth");
+
+    dev = qdev_create(NULL, "etraxfs-eth");
+    qdev_set_nic_properties(dev, nd);
+    qdev_prop_set_uint32(dev, "phyaddr", phyaddr);
+    qdev_prop_set_ptr(dev, "dma_out", dma_out);
+    qdev_prop_set_ptr(dev, "dma_in", dma_in);
+    qdev_init_nofail(dev);
+    sysbus_mmio_map(sysbus_from_qdev(dev), 0, base);
+    return dev;
+}
diff --git a/hw/etraxfs_eth.c b/hw/etraxfs_eth.c
index 6453077..92d4eca 100644
--- a/hw/etraxfs_eth.c
+++ b/hw/etraxfs_eth.c
@@ -23,7 +23,7 @@
  */
 
 #include <stdio.h>
-#include "hw.h"
+#include "sysbus.h"
 #include "net.h"
 #include "etraxfs.h"
 
@@ -319,6 +319,7 @@
 
 struct fs_eth
 {
+	SysBusDevice busdev;
 	NICState *nic;
 	NICConf conf;
 	int ethregs;
@@ -327,8 +328,14 @@
 	uint8_t macaddr[2][6];
 	uint32_t regs[FS_ETH_MAX_REGS];
 
-	struct etraxfs_dma_client *dma_out;
-	struct etraxfs_dma_client *dma_in;
+	union {
+		void *vdma_out;
+		struct etraxfs_dma_client *dma_out;
+	};
+	union {
+		void *vdma_in;
+		struct etraxfs_dma_client *dma_in;
+	};
 
 	/* MDIO bus.  */
 	struct qemu_mdio mdio_bus;
@@ -579,37 +586,50 @@
 	.link_status_changed = eth_set_link,
 };
 
-void etraxfs_eth_init(NICInfo *nd, target_phys_addr_t base, int phyaddr,
-                       struct etraxfs_dma_client *dma_out,
-                       struct etraxfs_dma_client *dma_in)
+static int fs_eth_init(SysBusDevice *dev)
 {
-	struct fs_eth *eth = NULL;
+	struct fs_eth *s = FROM_SYSBUS(typeof(*s), dev);
+	int eth_regs;
 
-	qemu_check_nic_model(nd, "fseth");
+	if (!s->dma_out || !s->dma_in) {
+		hw_error("Unconnected ETRAX-FS Ethernet MAC.\n");
+	}
 
-	eth = qemu_mallocz(sizeof *eth);
+	s->dma_out->client.push = eth_tx_push;
+	s->dma_out->client.opaque = s;
+	s->dma_in->client.opaque = s;
+	s->dma_in->client.pull = NULL;
 
-	dma_out->client.push = eth_tx_push;
-	dma_out->client.opaque = eth;
-	dma_in->client.opaque = eth;
-	dma_in->client.pull = NULL;
+	eth_regs = cpu_register_io_memory(eth_read, eth_write, s,
+					  DEVICE_LITTLE_ENDIAN);
+	sysbus_init_mmio(dev, 0x5c, eth_regs);
 
-	eth->dma_out = dma_out;
-	eth->dma_in = dma_in;
+	qemu_macaddr_default_if_unset(&s->conf.macaddr);
+	s->nic = qemu_new_nic(&net_etraxfs_info, &s->conf,
+			      dev->qdev.info->name, dev->qdev.id, s);
+	qemu_format_nic_info_str(&s->nic->nc, s->conf.macaddr.a);
 
-	/* Connect the phy.  */
-	eth->phyaddr = phyaddr & 0x1f;
-	tdk_init(&eth->phy);
-	mdio_attach(&eth->mdio_bus, &eth->phy, eth->phyaddr);
-
-	eth->ethregs = cpu_register_io_memory(eth_read, eth_write, eth,
-                                              DEVICE_NATIVE_ENDIAN);
-	cpu_register_physical_memory (base, 0x5c, eth->ethregs);
-
-	eth->conf.macaddr = nd->macaddr;
-	eth->conf.vlan = nd->vlan;
-	eth->conf.peer = nd->netdev;
-
-	eth->nic = qemu_new_nic(&net_etraxfs_info, &eth->conf,
-				nd->model, nd->name, eth);
+	tdk_init(&s->phy);
+	mdio_attach(&s->mdio_bus, &s->phy, s->phyaddr);
+	return 0;
 }
+
+static SysBusDeviceInfo etraxfs_eth_info = {
+	.init = fs_eth_init,
+	.qdev.name  = "etraxfs-eth",
+	.qdev.size  = sizeof(struct fs_eth),
+	.qdev.props = (Property[]) {
+		DEFINE_PROP_UINT32("phyaddr", struct fs_eth, phyaddr, 1),
+		DEFINE_PROP_PTR("dma_out", struct fs_eth, vdma_out),
+		DEFINE_PROP_PTR("dma_in", struct fs_eth, vdma_in),
+		DEFINE_NIC_PROPERTIES(struct fs_eth, conf),
+		DEFINE_PROP_END_OF_LIST(),
+	}
+};
+
+static void etraxfs_eth_register(void)
+{
+	sysbus_register_withprop(&etraxfs_eth_info);
+}
+
+device_init(etraxfs_eth_register)
diff --git a/hw/etraxfs_ser.c b/hw/etraxfs_ser.c
index b917d4d..28b86ea 100644
--- a/hw/etraxfs_ser.c
+++ b/hw/etraxfs_ser.c
@@ -24,6 +24,7 @@
 
 #include "sysbus.h"
 #include "qemu-char.h"
+#include "qemu-log.h"
 
 #define D(x)
 
@@ -100,7 +101,7 @@
             break;
         default:
             r = s->regs[addr];
-            D(printf ("%s " TARGET_FMT_plx "=%x\n", __func__, addr, r));
+            D(qemu_log("%s " TARGET_FMT_plx "=%x\n", __func__, addr, r));
             break;
     }
     return r;
@@ -113,7 +114,7 @@
     unsigned char ch = value;
     D(CPUState *env = s->env);
 
-    D(printf ("%s " TARGET_FMT_plx "=%x\n",  __func__, addr, value));
+    D(qemu_log("%s " TARGET_FMT_plx "=%x\n",  __func__, addr, value));
     addr >>= 2;
     switch (addr)
     {
@@ -127,7 +128,8 @@
             if (s->pending_tx) {
                 value &= ~1;
                 s->pending_tx = 0;
-                D(printf("fixedup value=%x r_intr=%x\n", value, s->regs[R_INTR]));
+                D(qemu_log("fixedup value=%x r_intr=%x\n",
+                           value, s->regs[R_INTR]));
             }
             s->regs[addr] = value;
             s->regs[R_INTR] &= ~value;
@@ -157,7 +159,7 @@
 
     /* Got a byte.  */
     if (s->rx_fifo_len >= 16) {
-        printf("WARNING: UART dropped char.\n");
+        qemu_log("WARNING: UART dropped char.\n");
         return;
     }
 
diff --git a/hw/hid.c b/hw/hid.c
index 7b5ef5f..ec066cf 100644
--- a/hw/hid.c
+++ b/hw/hid.c
@@ -218,16 +218,21 @@
     }
 }
 
+void hid_pointer_activate(HIDState *hs)
+{
+    if (!hs->ptr.mouse_grabbed) {
+        qemu_activate_mouse_event_handler(hs->ptr.eh_entry);
+        hs->ptr.mouse_grabbed = 1;
+    }
+}
+
 int hid_pointer_poll(HIDState *hs, uint8_t *buf, int len)
 {
     int dx, dy, dz, b, l;
     int index;
     HIDPointerEvent *e;
 
-    if (!hs->ptr.mouse_grabbed) {
-        qemu_activate_mouse_event_handler(hs->ptr.eh_entry);
-        hs->ptr.mouse_grabbed = 1;
-    }
+    hid_pointer_activate(hs);
 
     /* When the buffer is empty, return the last event.  Relative
        movements will all be zero.  */
@@ -359,7 +364,6 @@
 {
     switch (hs->kind) {
     case HID_KEYBOARD:
-        qemu_add_kbd_event_handler(hid_keyboard_event, hs);
         memset(hs->kbd.keycodes, 0, sizeof(hs->kbd.keycodes));
         memset(hs->kbd.key, 0, sizeof(hs->kbd.key));
         hs->kbd.keys = 0;
@@ -393,7 +397,9 @@
     hs->kind = kind;
     hs->event = event;
 
-    if (hs->kind == HID_MOUSE) {
+    if (hs->kind == HID_KEYBOARD) {
+        qemu_add_kbd_event_handler(hid_keyboard_event, hs);
+    } else if (hs->kind == HID_MOUSE) {
         hs->ptr.eh_entry = qemu_add_mouse_event_handler(hid_pointer_event, hs,
                                                         0, "QEMU HID Mouse");
     } else if (hs->kind == HID_TABLET) {
@@ -401,3 +407,61 @@
                                                         1, "QEMU HID Tablet");
     }
 }
+
+static int hid_post_load(void *opaque, int version_id)
+{
+    HIDState *s = opaque;
+
+    if (s->idle) {
+        hid_set_next_idle(s, qemu_get_clock_ns(vm_clock));
+    }
+    return 0;
+}
+
+static const VMStateDescription vmstate_hid_ptr_queue = {
+    .name = "HIDPointerEventQueue",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .fields = (VMStateField[]) {
+        VMSTATE_INT32(xdx, HIDPointerEvent),
+        VMSTATE_INT32(ydy, HIDPointerEvent),
+        VMSTATE_INT32(dz, HIDPointerEvent),
+        VMSTATE_INT32(buttons_state, HIDPointerEvent),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+const VMStateDescription vmstate_hid_ptr_device = {
+    .name = "HIDPointerDevice",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .post_load = hid_post_load,
+    .fields = (VMStateField[]) {
+        VMSTATE_STRUCT_ARRAY(ptr.queue, HIDState, QUEUE_LENGTH, 0,
+                             vmstate_hid_ptr_queue, HIDPointerEvent),
+        VMSTATE_UINT32(head, HIDState),
+        VMSTATE_UINT32(n, HIDState),
+        VMSTATE_INT32(protocol, HIDState),
+        VMSTATE_UINT8(idle, HIDState),
+        VMSTATE_END_OF_LIST(),
+    }
+};
+
+const VMStateDescription vmstate_hid_keyboard_device = {
+    .name = "HIDKeyboardDevice",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .post_load = hid_post_load,
+    .fields = (VMStateField[]) {
+        VMSTATE_UINT32_ARRAY(kbd.keycodes, HIDState, QUEUE_LENGTH),
+        VMSTATE_UINT32(head, HIDState),
+        VMSTATE_UINT32(n, HIDState),
+        VMSTATE_UINT16(kbd.modifiers, HIDState),
+        VMSTATE_UINT8(kbd.leds, HIDState),
+        VMSTATE_UINT8_ARRAY(kbd.key, HIDState, 16),
+        VMSTATE_INT32(kbd.keys, HIDState),
+        VMSTATE_INT32(protocol, HIDState),
+        VMSTATE_UINT8(idle, HIDState),
+        VMSTATE_END_OF_LIST(),
+    }
+};
diff --git a/hw/hid.h b/hw/hid.h
index 4a8fa5b..9ce03b1 100644
--- a/hw/hid.h
+++ b/hw/hid.h
@@ -51,6 +51,7 @@
 
 bool hid_has_events(HIDState *hs);
 void hid_set_next_idle(HIDState *hs, int64_t curtime);
+void hid_pointer_activate(HIDState *hs);
 int hid_pointer_poll(HIDState *hs, uint8_t *buf, int len);
 int hid_keyboard_poll(HIDState *hs, uint8_t *buf, int len);
 int hid_keyboard_write(HIDState *hs, uint8_t *buf, int len);
diff --git a/hw/hw.h b/hw/hw.h
index df6ca65..a124da9 100644
--- a/hw/hw.h
+++ b/hw/hw.h
@@ -701,6 +701,26 @@
     .offset     = vmstate_offset_pointer(_state, _field, ptimer_state), \
 }
 
+extern const VMStateDescription vmstate_hid_keyboard_device;
+
+#define VMSTATE_HID_KEYBOARD_DEVICE(_field, _state) {                \
+    .name       = (stringify(_field)),                               \
+    .size       = sizeof(HIDState),                                  \
+    .vmsd       = &vmstate_hid_keyboard_device,                      \
+    .flags      = VMS_STRUCT,                                        \
+    .offset     = vmstate_offset_value(_state, _field, HIDState),    \
+}
+
+extern const VMStateDescription vmstate_hid_ptr_device;
+
+#define VMSTATE_HID_POINTER_DEVICE(_field, _state) {                 \
+    .name       = (stringify(_field)),                               \
+    .size       = sizeof(HIDState),                                  \
+    .vmsd       = &vmstate_hid_ptr_device,                           \
+    .flags      = VMS_STRUCT,                                        \
+    .offset     = vmstate_offset_value(_state, _field, HIDState),    \
+}
+
 /* _f : field name
    _f_n : num of elements field_name
    _n : num of elements
diff --git a/hw/milkymist-softusb.c b/hw/milkymist-softusb.c
index 75c85ae..fe4eedb 100644
--- a/hw/milkymist-softusb.c
+++ b/hw/milkymist-softusb.c
@@ -25,7 +25,7 @@
 #include "sysbus.h"
 #include "trace.h"
 #include "console.h"
-#include "usb.h"
+#include "hid.h"
 #include "qemu-error.h"
 
 enum {
@@ -46,9 +46,8 @@
 
 struct MilkymistSoftUsbState {
     SysBusDevice busdev;
-    USBBus usbbus;
-    USBPort usbport[2];
-    USBDevice *usbdev;
+    HIDState hid_kbd;
+    HIDState hid_mouse;
 
     qemu_irq irq;
 
@@ -62,13 +61,10 @@
     uint32_t regs[R_MAX];
 
     /* mouse state */
-    int mouse_dx;
-    int mouse_dy;
-    int mouse_dz;
-    uint8_t mouse_buttons_state;
+    uint8_t mouse_hid_buffer[4];
 
     /* keyboard state */
-    uint8_t kbd_usb_buffer[8];
+    uint8_t kbd_hid_buffer[8];
 };
 typedef struct MilkymistSoftUsbState MilkymistSoftUsbState;
 
@@ -177,16 +173,10 @@
 static void softusb_mouse_changed(MilkymistSoftUsbState *s)
 {
     uint8_t m;
-    uint8_t buf[4];
-
-    buf[0] = s->mouse_buttons_state;
-    buf[1] = s->mouse_dx;
-    buf[2] = s->mouse_dy;
-    buf[3] = s->mouse_dz;
 
     softusb_read_dmem(s, COMLOC_MEVT_PRODUCE, &m, 1);
     trace_milkymist_softusb_mevt(m);
-    softusb_write_dmem(s, COMLOC_MEVT_BASE + 4 * m, buf, 4);
+    softusb_write_dmem(s, COMLOC_MEVT_BASE + 4 * m, s->mouse_hid_buffer, 4);
     m = (m + 1) & 0xf;
     softusb_write_dmem(s, COMLOC_MEVT_PRODUCE, &m, 1);
 
@@ -200,7 +190,7 @@
 
     softusb_read_dmem(s, COMLOC_KEVT_PRODUCE, &m, 1);
     trace_milkymist_softusb_kevt(m);
-    softusb_write_dmem(s, COMLOC_KEVT_BASE + 8 * m, s->kbd_usb_buffer, 8);
+    softusb_write_dmem(s, COMLOC_KEVT_BASE + 8 * m, s->kbd_hid_buffer, 8);
     m = (m + 1) & 0x7;
     softusb_write_dmem(s, COMLOC_KEVT_PRODUCE, &m, 1);
 
@@ -208,62 +198,42 @@
     qemu_irq_pulse(s->irq);
 }
 
-static void softusb_mouse_event(void *opaque,
-       int dx, int dy, int dz, int buttons_state)
+static void softusb_kbd_hid_datain(HIDState *hs)
 {
-    MilkymistSoftUsbState *s = opaque;
+    MilkymistSoftUsbState *s = container_of(hs, MilkymistSoftUsbState, hid_kbd);
+    int len;
 
     /* if device is in reset, do nothing */
     if (s->regs[R_CTRL] & CTRL_RESET) {
         return;
     }
 
-    trace_milkymist_softusb_mouse_event(dx, dy, dz, buttons_state);
+    len = hid_keyboard_poll(hs, s->kbd_hid_buffer, sizeof(s->kbd_hid_buffer));
 
-    s->mouse_dx = dx;
-    s->mouse_dy = dy;
-    s->mouse_dz = dz;
-    s->mouse_buttons_state = buttons_state;
-
-    softusb_mouse_changed(s);
+    if (len == 8) {
+        softusb_kbd_changed(s);
+    }
 }
 
-static void softusb_usbdev_datain(void *opaque)
+static void softusb_mouse_hid_datain(HIDState *hs)
 {
-    MilkymistSoftUsbState *s = opaque;
+    MilkymistSoftUsbState *s =
+            container_of(hs, MilkymistSoftUsbState, hid_mouse);
+    int len;
 
-    USBPacket p;
+    /* if device is in reset, do nothing */
+    if (s->regs[R_CTRL] & CTRL_RESET) {
+        return;
+    }
 
-    usb_packet_init(&p);
-    usb_packet_setup(&p, USB_TOKEN_IN, 0, 1);
-    usb_packet_addbuf(&p, s->kbd_usb_buffer, sizeof(s->kbd_usb_buffer));
-    s->usbdev->info->handle_data(s->usbdev, &p);
-    usb_packet_cleanup(&p);
+    len = hid_pointer_poll(hs, s->mouse_hid_buffer,
+            sizeof(s->mouse_hid_buffer));
 
-    softusb_kbd_changed(s);
+    if (len == 4) {
+        softusb_mouse_changed(s);
+    }
 }
 
-static void softusb_attach(USBPort *port)
-{
-}
-
-static void softusb_detach(USBPort *port)
-{
-}
-
-static void softusb_child_detach(USBPort *port, USBDevice *child)
-{
-}
-
-static USBPortOps softusb_ops = {
-    .attach = softusb_attach,
-    .detach = softusb_detach,
-    .child_detach = softusb_child_detach,
-};
-
-static USBBusOps softusb_bus_ops = {
-};
-
 static void milkymist_softusb_reset(DeviceState *d)
 {
     MilkymistSoftUsbState *s =
@@ -273,11 +243,11 @@
     for (i = 0; i < R_MAX; i++) {
         s->regs[i] = 0;
     }
-    s->mouse_dx = 0;
-    s->mouse_dy = 0;
-    s->mouse_dz = 0;
-    s->mouse_buttons_state = 0;
-    memset(s->kbd_usb_buffer, 0, sizeof(s->kbd_usb_buffer));
+    memset(s->kbd_hid_buffer, 0, sizeof(s->kbd_hid_buffer));
+    memset(s->mouse_hid_buffer, 0, sizeof(s->mouse_hid_buffer));
+
+    hid_reset(&s->hid_kbd);
+    hid_reset(&s->hid_mouse);
 
     /* defaults */
     s->regs[R_CTRL] = CTRL_RESET;
@@ -304,23 +274,8 @@
     cpu_register_physical_memory(s->dmem_base, s->dmem_size,
             dmem_ram | IO_MEM_RAM);
 
-    qemu_add_mouse_event_handler(softusb_mouse_event, s, 0, "Milkymist Mouse");
-
-    /* create our usb bus */
-    usb_bus_new(&s->usbbus, &softusb_bus_ops, NULL);
-
-    /* our two ports */
-    /* FIXME: claim to support full speed devices. qemu mouse and keyboard
-     * report themselves as full speed devices. */
-    usb_register_port(&s->usbbus, &s->usbport[0], NULL, 0, &softusb_ops,
-            USB_SPEED_MASK_LOW | USB_SPEED_MASK_FULL);
-    usb_register_port(&s->usbbus, &s->usbport[1], NULL, 1, &softusb_ops,
-            USB_SPEED_MASK_LOW | USB_SPEED_MASK_FULL);
-
-    /* and finally create an usb keyboard */
-    s->usbdev = usb_create_simple(&s->usbbus, "usb-kbd");
-    usb_hid_datain_cb(s->usbdev, s, softusb_usbdev_datain);
-    s->usbdev->info->handle_reset(s->usbdev);
+    hid_init(&s->hid_kbd, HID_KEYBOARD, softusb_kbd_hid_datain);
+    hid_init(&s->hid_mouse, HID_MOUSE, softusb_mouse_hid_datain);
 
     return 0;
 }
@@ -332,11 +287,10 @@
     .minimum_version_id_old = 1,
     .fields      = (VMStateField[]) {
         VMSTATE_UINT32_ARRAY(regs, MilkymistSoftUsbState, R_MAX),
-        VMSTATE_INT32(mouse_dx, MilkymistSoftUsbState),
-        VMSTATE_INT32(mouse_dy, MilkymistSoftUsbState),
-        VMSTATE_INT32(mouse_dz, MilkymistSoftUsbState),
-        VMSTATE_UINT8(mouse_buttons_state, MilkymistSoftUsbState),
-        VMSTATE_BUFFER(kbd_usb_buffer, MilkymistSoftUsbState),
+        VMSTATE_HID_KEYBOARD_DEVICE(hid_kbd, MilkymistSoftUsbState),
+        VMSTATE_HID_POINTER_DEVICE(hid_mouse, MilkymistSoftUsbState),
+        VMSTATE_BUFFER(kbd_hid_buffer, MilkymistSoftUsbState),
+        VMSTATE_BUFFER(mouse_hid_buffer, MilkymistSoftUsbState),
         VMSTATE_END_OF_LIST()
     }
 };
diff --git a/hw/usb-hid.c b/hw/usb-hid.c
index e5d57de..ba79466 100644
--- a/hw/usb-hid.c
+++ b/hw/usb-hid.c
@@ -45,8 +45,6 @@
 typedef struct USBHIDState {
     USBDevice dev;
     HIDState hid;
-    void *datain_opaque;
-    void (*datain)(void *);
 } USBHIDState;
 
 enum {
@@ -362,10 +360,6 @@
 {
     USBHIDState *us = container_of(hs, USBHIDState, hid);
 
-    if (us->datain) {
-        us->datain(us->datain_opaque);
-    }
-
     usb_wakeup(&us->dev);
 }
 
@@ -454,6 +448,9 @@
     case SET_IDLE:
         hs->idle = (uint8_t) (value >> 8);
         hid_set_next_idle(hs, qemu_get_clock_ns(vm_clock));
+        if (hs->kind == HID_MOUSE || hs->kind == HID_TABLET) {
+            hid_pointer_activate(hs);
+        }
         ret = 0;
         break;
     default:
@@ -530,49 +527,13 @@
     return usb_hid_initfn(dev, HID_KEYBOARD);
 }
 
-void usb_hid_datain_cb(USBDevice *dev, void *opaque, void (*datain)(void *))
-{
-    USBHIDState *s = (USBHIDState *)dev;
-
-    s->datain_opaque = opaque;
-    s->datain = datain;
-}
-
-static int usb_hid_post_load(void *opaque, int version_id)
-{
-    USBHIDState *s = opaque;
-
-    if (s->hid.idle) {
-        hid_set_next_idle(&s->hid, qemu_get_clock_ns(vm_clock));
-    }
-    return 0;
-}
-
-static const VMStateDescription vmstate_usb_ptr_queue = {
-    .name = "usb-ptr-queue",
-    .version_id = 1,
-    .minimum_version_id = 1,
-    .fields = (VMStateField []) {
-        VMSTATE_INT32(xdx, HIDPointerEvent),
-        VMSTATE_INT32(ydy, HIDPointerEvent),
-        VMSTATE_INT32(dz, HIDPointerEvent),
-        VMSTATE_INT32(buttons_state, HIDPointerEvent),
-        VMSTATE_END_OF_LIST()
-    }
-};
 static const VMStateDescription vmstate_usb_ptr = {
     .name = "usb-ptr",
     .version_id = 1,
     .minimum_version_id = 1,
-    .post_load = usb_hid_post_load,
     .fields = (VMStateField []) {
         VMSTATE_USB_DEVICE(dev, USBHIDState),
-        VMSTATE_STRUCT_ARRAY(hid.ptr.queue, USBHIDState, QUEUE_LENGTH, 0,
-                             vmstate_usb_ptr_queue, HIDPointerEvent),
-        VMSTATE_UINT32(hid.head, USBHIDState),
-        VMSTATE_UINT32(hid.n, USBHIDState),
-        VMSTATE_INT32(hid.protocol, USBHIDState),
-        VMSTATE_UINT8(hid.idle, USBHIDState),
+        VMSTATE_HID_POINTER_DEVICE(hid, USBHIDState),
         VMSTATE_END_OF_LIST()
     }
 };
@@ -581,18 +542,9 @@
     .name = "usb-kbd",
     .version_id = 1,
     .minimum_version_id = 1,
-    .post_load = usb_hid_post_load,
     .fields = (VMStateField []) {
         VMSTATE_USB_DEVICE(dev, USBHIDState),
-        VMSTATE_UINT32_ARRAY(hid.kbd.keycodes, USBHIDState, QUEUE_LENGTH),
-        VMSTATE_UINT32(hid.head, USBHIDState),
-        VMSTATE_UINT32(hid.n, USBHIDState),
-        VMSTATE_UINT16(hid.kbd.modifiers, USBHIDState),
-        VMSTATE_UINT8(hid.kbd.leds, USBHIDState),
-        VMSTATE_UINT8_ARRAY(hid.kbd.key, USBHIDState, 16),
-        VMSTATE_INT32(hid.kbd.keys, USBHIDState),
-        VMSTATE_INT32(hid.protocol, USBHIDState),
-        VMSTATE_UINT8(hid.idle, USBHIDState),
+        VMSTATE_HID_KEYBOARD_DEVICE(hid, USBHIDState),
         VMSTATE_END_OF_LIST()
     }
 };
diff --git a/hw/usb.h b/hw/usb.h
index 84d04df..d784448 100644
--- a/hw/usb.h
+++ b/hw/usb.h
@@ -316,9 +316,6 @@
 int usb_host_device_close(const char *devname);
 void usb_host_info(Monitor *mon);
 
-/* usb-hid.c */
-void usb_hid_datain_cb(USBDevice *dev, void *opaque, void (*datain)(void *));
-
 /* usb-bt.c */
 USBDevice *usb_bt_init(HCIInfo *hci);
 
diff --git a/pc-bios/bios.bin b/pc-bios/bios.bin
index bdb4831..bd9ad0e 100644
--- a/pc-bios/bios.bin
+++ b/pc-bios/bios.bin
Binary files differ
diff --git a/roms/seabios b/roms/seabios
index cc97564..8e30147 160000
--- a/roms/seabios
+++ b/roms/seabios
@@ -1 +1 @@
-Subproject commit cc975646af69f279396d4d5e1379ac6af80ee637
+Subproject commit 8e301472e324b6d6496d8b4ffc66863e99d7a505