diff options
author | Hans de Goede <hdegoede@redhat.com> | 2012-12-14 14:35:38 +0100 |
---|---|---|
committer | Gerd Hoffmann <kraxel@redhat.com> | 2013-01-07 12:57:24 +0100 |
commit | 027c03f7327faa696e1d876954a18b5214c18583 (patch) | |
tree | e3cf765c7fddf3304ec994ab0dead4e5fc665289 | |
parent | 9fdf70272702095f57efc51a80c79493fd0829b8 (diff) |
hid: Change idle handling to use a timer
This leads to cleaner code in usb-hid, and removes up to a 1000 calls / sec to
qemu_get_clock_ns(vm_clock) if idle-time is set to its default value of 0.
Signed-off-by: Hans de Goede <hdegoede@redhat.com>
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
-rw-r--r-- | hw/hid.c | 43 | ||||
-rw-r--r-- | hw/hid.h | 5 | ||||
-rw-r--r-- | hw/usb/dev-hid.c | 8 |
3 files changed, 43 insertions, 13 deletions
@@ -71,12 +71,38 @@ static const uint8_t hid_usage_keys[0x100] = { bool hid_has_events(HIDState *hs) { - return hs->n > 0; + return hs->n > 0 || hs->idle_pending; } -void hid_set_next_idle(HIDState *hs, int64_t curtime) +static void hid_idle_timer(void *opaque) { - hs->next_idle_clock = curtime + (get_ticks_per_sec() * hs->idle * 4) / 1000; + HIDState *hs = opaque; + + hs->idle_pending = true; + hs->event(hs); +} + +static void hid_del_idle_timer(HIDState *hs) +{ + if (hs->idle_timer) { + qemu_del_timer(hs->idle_timer); + qemu_free_timer(hs->idle_timer); + hs->idle_timer = NULL; + } +} + +void hid_set_next_idle(HIDState *hs) +{ + if (hs->idle) { + uint64_t expire_time = qemu_get_clock_ns(vm_clock) + + get_ticks_per_sec() * hs->idle * 4 / 1000; + if (!hs->idle_timer) { + hs->idle_timer = qemu_new_timer_ns(vm_clock, hid_idle_timer, hs); + } + qemu_mod_timer_ns(hs->idle_timer, expire_time); + } else { + hid_del_idle_timer(hs); + } } static void hid_pointer_event_clear(HIDPointerEvent *e, int buttons) @@ -232,6 +258,8 @@ int hid_pointer_poll(HIDState *hs, uint8_t *buf, int len) int index; HIDPointerEvent *e; + hs->idle_pending = false; + hid_pointer_activate(hs); /* When the buffer is empty, return the last event. Relative @@ -319,6 +347,8 @@ int hid_pointer_poll(HIDState *hs, uint8_t *buf, int len) int hid_keyboard_poll(HIDState *hs, uint8_t *buf, int len) { + hs->idle_pending = false; + if (len < 2) { return 0; } @@ -377,6 +407,8 @@ void hid_reset(HIDState *hs) hs->n = 0; hs->protocol = 1; hs->idle = 0; + hs->idle_pending = false; + hid_del_idle_timer(hs); } void hid_free(HIDState *hs) @@ -390,6 +422,7 @@ void hid_free(HIDState *hs) qemu_remove_mouse_event_handler(hs->ptr.eh_entry); break; } + hid_del_idle_timer(hs); } void hid_init(HIDState *hs, int kind, HIDEventFunc event) @@ -412,9 +445,7 @@ 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)); - } + hid_set_next_idle(s); return 0; } @@ -43,7 +43,8 @@ struct HIDState { int kind; int32_t protocol; uint8_t idle; - int64_t next_idle_clock; + bool idle_pending; + QEMUTimer *idle_timer; HIDEventFunc event; }; @@ -52,7 +53,7 @@ void hid_reset(HIDState *hs); void hid_free(HIDState *hs); bool hid_has_events(HIDState *hs); -void hid_set_next_idle(HIDState *hs, int64_t curtime); +void hid_set_next_idle(HIDState *hs); 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); diff --git a/hw/usb/dev-hid.c b/hw/usb/dev-hid.c index ce38fef9f6..b4ace04eef 100644 --- a/hw/usb/dev-hid.c +++ b/hw/usb/dev-hid.c @@ -501,7 +501,7 @@ static void usb_hid_handle_control(USBDevice *dev, USBPacket *p, break; case SET_IDLE: hs->idle = (uint8_t) (value >> 8); - hid_set_next_idle(hs, qemu_get_clock_ns(vm_clock)); + hid_set_next_idle(hs); if (hs->kind == HID_MOUSE || hs->kind == HID_TABLET) { hid_pointer_activate(hs); } @@ -523,16 +523,14 @@ static void usb_hid_handle_data(USBDevice *dev, USBPacket *p) switch (p->pid) { case USB_TOKEN_IN: if (p->ep->nr == 1) { - int64_t curtime = qemu_get_clock_ns(vm_clock); if (hs->kind == HID_MOUSE || hs->kind == HID_TABLET) { hid_pointer_activate(hs); } - if (!hid_has_events(hs) && - (!hs->idle || hs->next_idle_clock - curtime > 0)) { + if (!hid_has_events(hs)) { p->status = USB_RET_NAK; return; } - hid_set_next_idle(hs, curtime); + hid_set_next_idle(hs); if (hs->kind == HID_MOUSE || hs->kind == HID_TABLET) { len = hid_pointer_poll(hs, buf, p->iov.size); } else if (hs->kind == HID_KEYBOARD) { |