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>
This commit is contained in:
Hans de Goede 2012-12-14 14:35:38 +01:00 committed by Gerd Hoffmann
parent 9fdf702727
commit 027c03f732
3 changed files with 43 additions and 13 deletions

View File

@ -71,12 +71,38 @@ static const uint8_t hid_usage_keys[0x100] = {
bool hid_has_events(HIDState *hs) 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) 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; int index;
HIDPointerEvent *e; HIDPointerEvent *e;
hs->idle_pending = false;
hid_pointer_activate(hs); hid_pointer_activate(hs);
/* When the buffer is empty, return the last event. Relative /* 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) int hid_keyboard_poll(HIDState *hs, uint8_t *buf, int len)
{ {
hs->idle_pending = false;
if (len < 2) { if (len < 2) {
return 0; return 0;
} }
@ -377,6 +407,8 @@ void hid_reset(HIDState *hs)
hs->n = 0; hs->n = 0;
hs->protocol = 1; hs->protocol = 1;
hs->idle = 0; hs->idle = 0;
hs->idle_pending = false;
hid_del_idle_timer(hs);
} }
void hid_free(HIDState *hs) void hid_free(HIDState *hs)
@ -390,6 +422,7 @@ void hid_free(HIDState *hs)
qemu_remove_mouse_event_handler(hs->ptr.eh_entry); qemu_remove_mouse_event_handler(hs->ptr.eh_entry);
break; break;
} }
hid_del_idle_timer(hs);
} }
void hid_init(HIDState *hs, int kind, HIDEventFunc event) 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; HIDState *s = opaque;
if (s->idle) { hid_set_next_idle(s);
hid_set_next_idle(s, qemu_get_clock_ns(vm_clock));
}
return 0; return 0;
} }

View File

@ -43,7 +43,8 @@ struct HIDState {
int kind; int kind;
int32_t protocol; int32_t protocol;
uint8_t idle; uint8_t idle;
int64_t next_idle_clock; bool idle_pending;
QEMUTimer *idle_timer;
HIDEventFunc event; HIDEventFunc event;
}; };
@ -52,7 +53,7 @@ void hid_reset(HIDState *hs);
void hid_free(HIDState *hs); void hid_free(HIDState *hs);
bool hid_has_events(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); void hid_pointer_activate(HIDState *hs);
int hid_pointer_poll(HIDState *hs, uint8_t *buf, int len); 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_poll(HIDState *hs, uint8_t *buf, int len);

View File

@ -501,7 +501,7 @@ static void usb_hid_handle_control(USBDevice *dev, USBPacket *p,
break; break;
case SET_IDLE: case SET_IDLE:
hs->idle = (uint8_t) (value >> 8); 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) { if (hs->kind == HID_MOUSE || hs->kind == HID_TABLET) {
hid_pointer_activate(hs); hid_pointer_activate(hs);
} }
@ -523,16 +523,14 @@ static void usb_hid_handle_data(USBDevice *dev, USBPacket *p)
switch (p->pid) { switch (p->pid) {
case USB_TOKEN_IN: case USB_TOKEN_IN:
if (p->ep->nr == 1) { if (p->ep->nr == 1) {
int64_t curtime = qemu_get_clock_ns(vm_clock);
if (hs->kind == HID_MOUSE || hs->kind == HID_TABLET) { if (hs->kind == HID_MOUSE || hs->kind == HID_TABLET) {
hid_pointer_activate(hs); hid_pointer_activate(hs);
} }
if (!hid_has_events(hs) && if (!hid_has_events(hs)) {
(!hs->idle || hs->next_idle_clock - curtime > 0)) {
p->status = USB_RET_NAK; p->status = USB_RET_NAK;
return; return;
} }
hid_set_next_idle(hs, curtime); hid_set_next_idle(hs);
if (hs->kind == HID_MOUSE || hs->kind == HID_TABLET) { if (hs->kind == HID_MOUSE || hs->kind == HID_TABLET) {
len = hid_pointer_poll(hs, buf, p->iov.size); len = hid_pointer_poll(hs, buf, p->iov.size);
} else if (hs->kind == HID_KEYBOARD) { } else if (hs->kind == HID_KEYBOARD) {