Commit 117b3ae6e6d27ea31e85ffe1820437d91269ed4e
1 parent
ead9360e
Implement HID idle mode (avoids flooding guest with useless updates).
Fix UHCI NACK bug. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3157 c046a42c-6fe2-441c-8c8c-71466251a162
Showing
2 changed files
with
33 additions
and
12 deletions
hw/usb-hid.c
@@ -64,6 +64,7 @@ typedef struct USBHIDState { | @@ -64,6 +64,7 @@ typedef struct USBHIDState { | ||
64 | int kind; | 64 | int kind; |
65 | int protocol; | 65 | int protocol; |
66 | int idle; | 66 | int idle; |
67 | + int changed; | ||
67 | } USBHIDState; | 68 | } USBHIDState; |
68 | 69 | ||
69 | /* mostly the same values as the Bochs USB Mouse device */ | 70 | /* mostly the same values as the Bochs USB Mouse device */ |
@@ -382,28 +383,33 @@ static const uint8_t usb_hid_usage_keys[0x100] = { | @@ -382,28 +383,33 @@ static const uint8_t usb_hid_usage_keys[0x100] = { | ||
382 | static void usb_mouse_event(void *opaque, | 383 | static void usb_mouse_event(void *opaque, |
383 | int dx1, int dy1, int dz1, int buttons_state) | 384 | int dx1, int dy1, int dz1, int buttons_state) |
384 | { | 385 | { |
385 | - USBMouseState *s = opaque; | 386 | + USBHIDState *hs = opaque; |
387 | + USBMouseState *s = &hs->ptr; | ||
386 | 388 | ||
387 | s->dx += dx1; | 389 | s->dx += dx1; |
388 | s->dy += dy1; | 390 | s->dy += dy1; |
389 | s->dz += dz1; | 391 | s->dz += dz1; |
390 | s->buttons_state = buttons_state; | 392 | s->buttons_state = buttons_state; |
393 | + hs->changed = 1; | ||
391 | } | 394 | } |
392 | 395 | ||
393 | static void usb_tablet_event(void *opaque, | 396 | static void usb_tablet_event(void *opaque, |
394 | int x, int y, int dz, int buttons_state) | 397 | int x, int y, int dz, int buttons_state) |
395 | { | 398 | { |
396 | - USBMouseState *s = opaque; | 399 | + USBHIDState *hs = opaque; |
400 | + USBMouseState *s = &hs->ptr; | ||
397 | 401 | ||
398 | s->x = x; | 402 | s->x = x; |
399 | s->y = y; | 403 | s->y = y; |
400 | s->dz += dz; | 404 | s->dz += dz; |
401 | s->buttons_state = buttons_state; | 405 | s->buttons_state = buttons_state; |
406 | + hs->changed = 1; | ||
402 | } | 407 | } |
403 | 408 | ||
404 | static void usb_keyboard_event(void *opaque, int keycode) | 409 | static void usb_keyboard_event(void *opaque, int keycode) |
405 | { | 410 | { |
406 | - USBKeyboardState *s = opaque; | 411 | + USBHIDState *hs = opaque; |
412 | + USBKeyboardState *s = &hs->kbd; | ||
407 | uint8_t hid_code, key; | 413 | uint8_t hid_code, key; |
408 | int i; | 414 | int i; |
409 | 415 | ||
@@ -411,6 +417,8 @@ static void usb_keyboard_event(void *opaque, int keycode) | @@ -411,6 +417,8 @@ static void usb_keyboard_event(void *opaque, int keycode) | ||
411 | hid_code = usb_hid_usage_keys[key | ((s->modifiers >> 1) & (1 << 7))]; | 417 | hid_code = usb_hid_usage_keys[key | ((s->modifiers >> 1) & (1 << 7))]; |
412 | s->modifiers &= ~(1 << 8); | 418 | s->modifiers &= ~(1 << 8); |
413 | 419 | ||
420 | + hs->changed = 1; | ||
421 | + | ||
414 | switch (hid_code) { | 422 | switch (hid_code) { |
415 | case 0x00: | 423 | case 0x00: |
416 | return; | 424 | return; |
@@ -456,12 +464,13 @@ static inline int int_clamp(int val, int vmin, int vmax) | @@ -456,12 +464,13 @@ static inline int int_clamp(int val, int vmin, int vmax) | ||
456 | return val; | 464 | return val; |
457 | } | 465 | } |
458 | 466 | ||
459 | -static int usb_mouse_poll(USBMouseState *s, uint8_t *buf, int len) | 467 | +static int usb_mouse_poll(USBHIDState *hs, uint8_t *buf, int len) |
460 | { | 468 | { |
461 | int dx, dy, dz, b, l; | 469 | int dx, dy, dz, b, l; |
470 | + USBMouseState *s = &hs->ptr; | ||
462 | 471 | ||
463 | if (!s->mouse_grabbed) { | 472 | if (!s->mouse_grabbed) { |
464 | - s->eh_entry = qemu_add_mouse_event_handler(usb_mouse_event, s, | 473 | + s->eh_entry = qemu_add_mouse_event_handler(usb_mouse_event, hs, |
465 | 0, "QEMU USB Mouse"); | 474 | 0, "QEMU USB Mouse"); |
466 | s->mouse_grabbed = 1; | 475 | s->mouse_grabbed = 1; |
467 | } | 476 | } |
@@ -493,12 +502,13 @@ static int usb_mouse_poll(USBMouseState *s, uint8_t *buf, int len) | @@ -493,12 +502,13 @@ static int usb_mouse_poll(USBMouseState *s, uint8_t *buf, int len) | ||
493 | return l; | 502 | return l; |
494 | } | 503 | } |
495 | 504 | ||
496 | -static int usb_tablet_poll(USBMouseState *s, uint8_t *buf, int len) | 505 | +static int usb_tablet_poll(USBHIDState *hs, uint8_t *buf, int len) |
497 | { | 506 | { |
498 | int dz, b, l; | 507 | int dz, b, l; |
508 | + USBMouseState *s = &hs->ptr; | ||
499 | 509 | ||
500 | if (!s->mouse_grabbed) { | 510 | if (!s->mouse_grabbed) { |
501 | - s->eh_entry = qemu_add_mouse_event_handler(usb_tablet_event, s, | 511 | + s->eh_entry = qemu_add_mouse_event_handler(usb_tablet_event, hs, |
502 | 1, "QEMU USB Tablet"); | 512 | 1, "QEMU USB Tablet"); |
503 | s->mouse_grabbed = 1; | 513 | s->mouse_grabbed = 1; |
504 | } | 514 | } |
@@ -711,9 +721,9 @@ static int usb_hid_handle_control(USBDevice *dev, int request, int value, | @@ -711,9 +721,9 @@ static int usb_hid_handle_control(USBDevice *dev, int request, int value, | ||
711 | break; | 721 | break; |
712 | case GET_REPORT: | 722 | case GET_REPORT: |
713 | if (s->kind == USB_MOUSE) | 723 | if (s->kind == USB_MOUSE) |
714 | - ret = usb_mouse_poll(&s->ptr, data, length); | 724 | + ret = usb_mouse_poll(s, data, length); |
715 | else if (s->kind == USB_TABLET) | 725 | else if (s->kind == USB_TABLET) |
716 | - ret = usb_tablet_poll(&s->ptr, data, length); | 726 | + ret = usb_tablet_poll(s, data, length); |
717 | else if (s->kind == USB_KEYBOARD) | 727 | else if (s->kind == USB_KEYBOARD) |
718 | ret = usb_keyboard_poll(&s->kbd, data, length); | 728 | ret = usb_keyboard_poll(&s->kbd, data, length); |
719 | break; | 729 | break; |
@@ -759,10 +769,14 @@ static int usb_hid_handle_data(USBDevice *dev, USBPacket *p) | @@ -759,10 +769,14 @@ static int usb_hid_handle_data(USBDevice *dev, USBPacket *p) | ||
759 | switch(p->pid) { | 769 | switch(p->pid) { |
760 | case USB_TOKEN_IN: | 770 | case USB_TOKEN_IN: |
761 | if (p->devep == 1) { | 771 | if (p->devep == 1) { |
772 | + /* TODO: Implement finite idle delays. */ | ||
773 | + if (!(s->changed || s->idle)) | ||
774 | + return USB_RET_NAK; | ||
775 | + s->changed = 0; | ||
762 | if (s->kind == USB_MOUSE) | 776 | if (s->kind == USB_MOUSE) |
763 | - ret = usb_mouse_poll(&s->ptr, p->data, p->len); | 777 | + ret = usb_mouse_poll(s, p->data, p->len); |
764 | else if (s->kind == USB_TABLET) | 778 | else if (s->kind == USB_TABLET) |
765 | - ret = usb_tablet_poll(&s->ptr, p->data, p->len); | 779 | + ret = usb_tablet_poll(s, p->data, p->len); |
766 | else if (s->kind == USB_KEYBOARD) | 780 | else if (s->kind == USB_KEYBOARD) |
767 | ret = usb_keyboard_poll(&s->kbd, p->data, p->len); | 781 | ret = usb_keyboard_poll(&s->kbd, p->data, p->len); |
768 | } else { | 782 | } else { |
@@ -803,6 +817,8 @@ USBDevice *usb_tablet_init(void) | @@ -803,6 +817,8 @@ USBDevice *usb_tablet_init(void) | ||
803 | s->dev.handle_data = usb_hid_handle_data; | 817 | s->dev.handle_data = usb_hid_handle_data; |
804 | s->dev.handle_destroy = usb_hid_handle_destroy; | 818 | s->dev.handle_destroy = usb_hid_handle_destroy; |
805 | s->kind = USB_TABLET; | 819 | s->kind = USB_TABLET; |
820 | + /* Force poll routine to be run and grab input the first time. */ | ||
821 | + s->changed = 1; | ||
806 | 822 | ||
807 | pstrcpy(s->dev.devname, sizeof(s->dev.devname), "QEMU USB Tablet"); | 823 | pstrcpy(s->dev.devname, sizeof(s->dev.devname), "QEMU USB Tablet"); |
808 | 824 | ||
@@ -824,6 +840,8 @@ USBDevice *usb_mouse_init(void) | @@ -824,6 +840,8 @@ USBDevice *usb_mouse_init(void) | ||
824 | s->dev.handle_data = usb_hid_handle_data; | 840 | s->dev.handle_data = usb_hid_handle_data; |
825 | s->dev.handle_destroy = usb_hid_handle_destroy; | 841 | s->dev.handle_destroy = usb_hid_handle_destroy; |
826 | s->kind = USB_MOUSE; | 842 | s->kind = USB_MOUSE; |
843 | + /* Force poll routine to be run and grab input the first time. */ | ||
844 | + s->changed = 1; | ||
827 | 845 | ||
828 | pstrcpy(s->dev.devname, sizeof(s->dev.devname), "QEMU USB Mouse"); | 846 | pstrcpy(s->dev.devname, sizeof(s->dev.devname), "QEMU USB Mouse"); |
829 | 847 |
hw/usb-uhci.c
@@ -526,7 +526,10 @@ static int uhci_handle_td(UHCIState *s, UHCI_TD *td, int *int_mask) | @@ -526,7 +526,10 @@ static int uhci_handle_td(UHCIState *s, UHCI_TD *td, int *int_mask) | ||
526 | td->ctrl &= ~TD_CTRL_ACTIVE; | 526 | td->ctrl &= ~TD_CTRL_ACTIVE; |
527 | if (ret >= 0) { | 527 | if (ret >= 0) { |
528 | td->ctrl = (td->ctrl & ~0x7ff) | ((len - 1) & 0x7ff); | 528 | td->ctrl = (td->ctrl & ~0x7ff) | ((len - 1) & 0x7ff); |
529 | - td->ctrl &= ~TD_CTRL_ACTIVE; | 529 | + /* The NAK bit may have been set by a previous frame, so clear it |
530 | + here. The docs are somewhat unclear, but win2k relies on this | ||
531 | + behavior. */ | ||
532 | + td->ctrl &= ~(TD_CTRL_ACTIVE | TD_CTRL_NAK); | ||
530 | if (pid == USB_TOKEN_IN && | 533 | if (pid == USB_TOKEN_IN && |
531 | (td->ctrl & TD_CTRL_SPD) && | 534 | (td->ctrl & TD_CTRL_SPD) && |
532 | len < max_len) { | 535 | len < max_len) { |