Patchwork [2/7] usb keyboard: add event event queue

login
register
mail settings
Submitter Gerd Hoffmann
Date Jan. 14, 2011, 11:55 a.m.
Message ID <1295006132-29153-3-git-send-email-kraxel@redhat.com>
Download mbox | patch
Permalink /patch/78884/
State New
Headers show

Comments

Gerd Hoffmann - Jan. 14, 2011, 11:55 a.m.
This patch adds a event queue to the usb keyboard.  This makes sure the
guest will see all key events even if they come in bursts.  With this
patch applied sending Ctrl-Alt-Del using vncviewer's F8 menu works.
Also with autosuspend enabled the first keypress on a suspended keyboard
takes a little longer to be delivered to the guest because the usb bus
must be resumed first.  Without event queue this easily gets lost.

Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
---
 hw/usb-hid.c |   38 ++++++++++++++++++++++++++++++++------
 1 files changed, 32 insertions(+), 6 deletions(-)
Paolo Bonzini - Jan. 14, 2011, 4:30 p.m.
On 01/14/2011 12:55 PM, Gerd Hoffmann wrote:
> This patch adds a event queue to the usb keyboard.  This makes sure the
> guest will see all key events even if they come in bursts.  With this
> patch applied sending Ctrl-Alt-Del using vncviewer's F8 menu works.
> Also with autosuspend enabled the first keypress on a suspended keyboard
> takes a little longer to be delivered to the guest because the usb bus
> must be resumed first.  Without event queue this easily gets lost.
>
> Signed-off-by: Gerd Hoffmann<kraxel@redhat.com>
> ---
>   hw/usb-hid.c |   38 ++++++++++++++++++++++++++++++++------
>   1 files changed, 32 insertions(+), 6 deletions(-)

Nice elegant patch.

Acked-by: Paolo Bonzini <pbonzini@redhat.com>

Paolo

Patch

diff --git a/hw/usb-hid.c b/hw/usb-hid.c
index 8c5ed39..9444051 100644
--- a/hw/usb-hid.c
+++ b/hw/usb-hid.c
@@ -63,6 +63,9 @@  typedef struct USBMouseState {
 } USBMouseState;
 
 typedef struct USBKeyboardState {
+    uint32_t keycodes[QUEUE_LENGTH];
+    uint32_t head; /* index into circular queue */
+    uint32_t n;
     uint16_t modifiers;
     uint8_t leds;
     uint8_t key[16];
@@ -494,8 +497,27 @@  static void usb_keyboard_event(void *opaque, int keycode)
 {
     USBHIDState *hs = opaque;
     USBKeyboardState *s = &hs->kbd;
+    int slot;
+
+    if (s->n == QUEUE_LENGTH) {
+        fprintf(stderr, "usb-kbd: warning: key event queue full\n");
+        return;
+    }
+    slot = (s->head + s->n) & QUEUE_MASK; s->n++;
+    s->keycodes[slot] = keycode;
+    usb_hid_changed(hs);
+}
+
+static void usb_keyboard_process_keycode(USBKeyboardState *s)
+{
     uint8_t hid_code, key;
-    int i;
+    int i, keycode, slot;
+
+    if (s->n == 0) {
+        return;
+    }
+    slot = s->head & QUEUE_MASK; QUEUE_INCR(s->head); s->n--;
+    keycode = s->keycodes[slot];
 
     key = keycode & 0x7f;
     hid_code = usb_hid_usage_keys[key | ((s->modifiers >> 1) & (1 << 7))];
@@ -525,7 +547,6 @@  static void usb_keyboard_event(void *opaque, int keycode)
             if (s->key[i] == hid_code) {
                 s->key[i] = s->key[-- s->keys];
                 s->key[s->keys] = 0x00;
-                usb_hid_changed(hs);
                 break;
             }
         if (i < 0)
@@ -540,8 +561,6 @@  static void usb_keyboard_event(void *opaque, int keycode)
         } else
             return;
     }
-
-    usb_hid_changed(hs);
 }
 
 static inline int int_clamp(int val, int vmin, int vmax)
@@ -642,6 +661,8 @@  static int usb_keyboard_poll(USBHIDState *hs, uint8_t *buf, int len)
     if (len < 2)
         return 0;
 
+    usb_keyboard_process_keycode(s);
+
     buf[0] = s->modifiers & 0xff;
     buf[1] = 0;
     if (s->keys > 6)
@@ -677,7 +698,7 @@  static void usb_mouse_handle_reset(USBDevice *dev)
 {
     USBHIDState *s = (USBHIDState *)dev;
 
-    memset (s->ptr.queue, 0, sizeof (s->ptr.queue));
+    memset(s->ptr.queue, 0, sizeof (s->ptr.queue));
     s->ptr.head = 0;
     s->ptr.n = 0;
     s->protocol = 1;
@@ -688,6 +709,11 @@  static void usb_keyboard_handle_reset(USBDevice *dev)
     USBHIDState *s = (USBHIDState *)dev;
 
     qemu_add_kbd_event_handler(usb_keyboard_event, s);
+    memset(s->kbd.keycodes, 0, sizeof (s->kbd.keycodes));
+    s->kbd.head = 0;
+    s->kbd.n = 0;
+    memset(s->kbd.key, 0, sizeof (s->kbd.key));
+    s->kbd.keys = 0;
     s->protocol = 1;
 }
 
@@ -797,7 +823,7 @@  static int usb_hid_handle_data(USBDevice *dev, USBPacket *p)
             }
             else if (s->kind == USB_KEYBOARD) {
                 ret = usb_keyboard_poll(s, p->data, p->len);
-                s->changed = 0;
+                s->changed = s->kbd.n > 0;
             }
         } else {
             goto fail;