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>
master
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)
{
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;
}

View File

@ -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);

View File

@ -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) {