Compare commits

..

10 Commits

Author SHA1 Message Date
Gerd Hoffmann
8977bd111f docs: add multiseat.txt
Howto on setting up multiseat for guests.

Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
2014-05-26 08:42:43 +02:00
Gerd Hoffmann
f85d28316a usb: add input routing support for tablet and keyboard
Add display property to the keyboard.
Add display and head properties to the tablet.

If properties are set bind device to the display specified to
setup input routing.

Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
2014-05-26 08:42:43 +02:00
Gerd Hoffmann
ee8c0b622c sdl: pass key event source to input layer
So the input layer knows where the input is coming from
and input routing works correctly.

Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
2014-05-26 08:42:43 +02:00
Gerd Hoffmann
6f5943cf45 input: bind devices and input routing
Add function to bind input devices to display devices.  Implementing
input routing on top of this:  Events coming from the display device in
question are routed to the input device bound to it (if there is one).

Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
2014-05-26 08:42:43 +02:00
Gerd Hoffmann
8b84286f4c input: switch hid mouse and tablet to the new input layer api.
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
2014-05-26 08:42:43 +02:00
Gerd Hoffmann
1ff5eedd1d input: switch hid keyboard to new input layer api.
Minimal patch to get the switchover done.  We continue processing ps/2
scancodes for now as they are part of the live migration stream.  Fixing
that, then mapping directly from QKeyValue to HID keycodes is left as
excercise for another day.

Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
2014-05-26 08:42:43 +02:00
Gerd Hoffmann
86846bfe64 input: keymap: add meta keys
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
2014-05-26 08:42:43 +02:00
Gerd Hoffmann
2386a90730 input: add name to input_event_key_number
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
2014-05-26 08:42:42 +02:00
Gerd Hoffmann
11c7fa7fa6 input: add qemu_input_key_number_to_qcode
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
2014-05-26 08:42:42 +02:00
Andrew Oates
f5c0ab1312 input (curses): mask keycodes to remove modifier bits
Without the mask, control bits are passed on in the keycode, generating
incorrect PS/2 sequences when SHIFT, ALT, etc are held down.

Cc: qemu-stable@nongnu.org
Signed-off-by: Andrew Oates <andrew@aoates.org>
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
2014-05-26 08:42:42 +02:00
14 changed files with 332 additions and 341 deletions

76
docs/multiseat.txt Normal file
View File

@@ -0,0 +1,76 @@
multiseat howto (with some multihead coverage)
==============================================
host side
---------
First you must compile qemu with a user interface supporting
multihead/multiseat and input event routing. Right now this list is
pretty short: sdl2.
./configure --enable-sdl --with-sdlabi=2.0
Next put together the qemu command line:
qemu -enable-kvm -usb $memory $disk $whatever \
-display sdl \
-vga std \
-device usb-tablet
That is it for the first head, which will use the standard vga, the
standard ps/2 keyboard (implicitly there) and the usb-tablet. Now the
additional switches for the second head:
-device pci-bridge,addr=12.0,chassis_nr=2,id=head.2 \
-device secondary-vga,bus=head.2,addr=02.0,id=video.2 \
-device nec-usb-xhci,bus=head.2,addr=0f.0,id=usb.2 \
-device usb-kbd,bus=usb.2.0,port=1,display=video.2 \
-device usb-tablet,bus=usb.2.0,port=2,display=video.2
This places a pci bridge in slot 12, connects a display adapter and
xhci (usb) controller to the bridge. Then it adds a usb keyboard and
usb mouse, both connected to the xhci and linked to the display.
The "display=video2" sets up the input routing. Any input coming from
the window which belongs to the video.2 display adapter will be routed
to these input devices.
guest side
----------
You need a pretty recent linux guest. systemd with loginctl. kernel
3.14+ with CONFIG_DRM_BOCHS enabled. Fedora 20 will do. Must be
fully updated for the new kernel though, i.e. the live iso doesn't cut
it.
Now we'll have to configure the guest. Boot and login. By default
all devices belong to seat0. You can use "loginctl seat-status seat0"
to list them all (and to get the sysfs paths for cut+paste). Now
we'll go assign all pci devices connected the pci bridge in slot 12 to
a new head:
loginctl attach seat-qemu \
/sys/devices/pci0000:00/0000:00:12.0/0000:01:02.0/drm/card1
loginctl attach seat-qemu \
/sys/devices/pci0000:00/0000:00:12.0/0000:01:02.0/graphics/fb1
loginctl attach seat-qemu \
/sys/devices/pci0000:00/0000:00:12.0/0000:01:0f.0/usb2
Use "loginctl seat-status seat-qemu" to check the result. It isn't
needed to assign the usb devices to the head individually, assigning a
usb (root) hub will automatically assign all usb devices connected to
it too.
BTW: loginctl writes udev rules to /etc/udev/rules.d to make these
device assignments permanent, so you need to do this only once.
Now simply restart gdm (rebooting will do too), and a login screen
should show up on the second head.
Enjoy!
--
Gerd Hoffmann <kraxel@redhat.com>

View File

@@ -105,70 +105,135 @@ void hid_set_next_idle(HIDState *hs)
} }
} }
static void hid_pointer_event_clear(HIDPointerEvent *e, int buttons) static void hid_pointer_event(DeviceState *dev, QemuConsole *src,
InputEvent *evt)
{ {
e->xdx = e->ydy = e->dz = 0; static const int bmap[INPUT_BUTTON_MAX] = {
e->buttons_state = buttons; [INPUT_BUTTON_LEFT] = 0x01,
[INPUT_BUTTON_RIGHT] = 0x02,
[INPUT_BUTTON_MIDDLE] = 0x04,
};
HIDState *hs = (HIDState *)dev;
HIDPointerEvent *e;
assert(hs->n < QUEUE_LENGTH);
e = &hs->ptr.queue[(hs->head + hs->n) & QUEUE_MASK];
switch (evt->kind) {
case INPUT_EVENT_KIND_REL:
if (evt->rel->axis == INPUT_AXIS_X) {
e->xdx += evt->rel->value;
} else if (evt->rel->axis == INPUT_AXIS_Y) {
e->ydy -= evt->rel->value;
}
break;
case INPUT_EVENT_KIND_ABS:
if (evt->rel->axis == INPUT_AXIS_X) {
e->xdx = evt->rel->value;
} else if (evt->rel->axis == INPUT_AXIS_Y) {
e->ydy = evt->rel->value;
}
break;
case INPUT_EVENT_KIND_BTN:
if (evt->btn->down) {
e->buttons_state |= bmap[evt->btn->button];
if (evt->btn->button == INPUT_BUTTON_WHEEL_UP) {
e->dz--;
} else if (evt->btn->button == INPUT_BUTTON_WHEEL_DOWN) {
e->dz++;
}
} else {
e->buttons_state &= ~bmap[evt->btn->button];
}
break;
default:
/* keep gcc happy */
break;
}
} }
static void hid_pointer_event_combine(HIDPointerEvent *e, int xyrel, static void hid_pointer_sync(DeviceState *dev)
int x1, int y1, int z1) { {
if (xyrel) { HIDState *hs = (HIDState *)dev;
e->xdx += x1; HIDPointerEvent *prev, *curr, *next;
e->ydy += y1; bool event_compression = false;
} else {
e->xdx = x1; if (hs->n == QUEUE_LENGTH-1) {
e->ydy = y1; /*
/* Windows drivers do not like the 0/0 position and ignore such * Queue full. We are loosing information, but we at least
* events. */ * keep track of most recent button state.
if (!(x1 | y1)) { */
e->xdx = 1; return;
}
prev = &hs->ptr.queue[(hs->head + hs->n - 1) & QUEUE_MASK];
curr = &hs->ptr.queue[(hs->head + hs->n) & QUEUE_MASK];
next = &hs->ptr.queue[(hs->head + hs->n + 1) & QUEUE_MASK];
if (hs->n > 0) {
/*
* No button state change between previous and current event
* (and previous wasn't seen by the guest yet), so there is
* motion information only and we can combine the two event
* into one.
*/
if (curr->buttons_state == prev->buttons_state) {
event_compression = true;
} }
} }
e->dz += z1;
}
static void hid_pointer_event(void *opaque, if (event_compression) {
int x1, int y1, int z1, int buttons_state) /* add current motion to previous, clear current */
{ if (hs->kind == HID_MOUSE) {
HIDState *hs = opaque; prev->xdx += curr->xdx;
unsigned use_slot = (hs->head + hs->n - 1) & QUEUE_MASK; curr->xdx = 0;
unsigned previous_slot = (use_slot - 1) & QUEUE_MASK; prev->ydy -= curr->ydy;
curr->ydy = 0;
/* We combine events where feasible to keep the queue small. We shouldn't } else {
* combine anything with the first event of a particular button state, as prev->xdx = curr->xdx;
* that would change the location of the button state change. When the prev->ydy = curr->ydy;
* queue is empty, a second event is needed because we don't know if }
* the first event changed the button state. */ prev->dz += curr->dz;
if (hs->n == QUEUE_LENGTH) { curr->dz = 0;
/* Queue full. Discard old button state, combine motion normally. */ } else {
hs->ptr.queue[use_slot].buttons_state = buttons_state; /* prepate next (clear rel, copy abs + btns) */
} else if (hs->n < 2 || if (hs->kind == HID_MOUSE) {
hs->ptr.queue[use_slot].buttons_state != buttons_state || next->xdx = 0;
hs->ptr.queue[previous_slot].buttons_state != next->ydy = 0;
hs->ptr.queue[use_slot].buttons_state) { } else {
/* Cannot or should not combine, so add an empty item to the queue. */ next->xdx = curr->xdx;
QUEUE_INCR(use_slot); next->ydy = curr->ydy;
}
next->dz = 0;
next->buttons_state = curr->buttons_state;
/* make current guest visible, notify guest */
hs->n++; hs->n++;
hid_pointer_event_clear(&hs->ptr.queue[use_slot], buttons_state); hs->event(hs);
} }
hid_pointer_event_combine(&hs->ptr.queue[use_slot],
hs->kind == HID_MOUSE,
x1, y1, z1);
hs->event(hs);
} }
static void hid_keyboard_event(void *opaque, int keycode) static void hid_keyboard_event(DeviceState *dev, QemuConsole *src,
InputEvent *evt)
{ {
HIDState *hs = opaque; HIDState *hs = (HIDState *)dev;
int scancodes[3], i, count;
int slot; int slot;
if (hs->n == QUEUE_LENGTH) { count = qemu_input_key_value_to_scancode(evt->key->key,
evt->key->down,
scancodes);
if (hs->n + count > QUEUE_LENGTH) {
fprintf(stderr, "usb-kbd: warning: key event queue full\n"); fprintf(stderr, "usb-kbd: warning: key event queue full\n");
return; return;
} }
slot = (hs->head + hs->n) & QUEUE_MASK; hs->n++; for (i = 0; i < count; i++) {
hs->kbd.keycodes[slot] = keycode; slot = (hs->head + hs->n) & QUEUE_MASK; hs->n++;
hs->kbd.keycodes[slot] = scancodes[i];
}
hs->event(hs); hs->event(hs);
} }
@@ -247,14 +312,14 @@ static inline int int_clamp(int val, int vmin, int vmax)
void hid_pointer_activate(HIDState *hs) void hid_pointer_activate(HIDState *hs)
{ {
if (!hs->ptr.mouse_grabbed) { if (!hs->ptr.mouse_grabbed) {
qemu_activate_mouse_event_handler(hs->ptr.eh_entry); qemu_input_handler_activate(hs->s);
hs->ptr.mouse_grabbed = 1; hs->ptr.mouse_grabbed = 1;
} }
} }
int hid_pointer_poll(HIDState *hs, uint8_t *buf, int len) int hid_pointer_poll(HIDState *hs, uint8_t *buf, int len)
{ {
int dx, dy, dz, b, l; int dx, dy, dz, l;
int index; int index;
HIDPointerEvent *e; HIDPointerEvent *e;
@@ -279,17 +344,6 @@ int hid_pointer_poll(HIDState *hs, uint8_t *buf, int len)
dz = int_clamp(e->dz, -127, 127); dz = int_clamp(e->dz, -127, 127);
e->dz -= dz; e->dz -= dz;
b = 0;
if (e->buttons_state & MOUSE_EVENT_LBUTTON) {
b |= 0x01;
}
if (e->buttons_state & MOUSE_EVENT_RBUTTON) {
b |= 0x02;
}
if (e->buttons_state & MOUSE_EVENT_MBUTTON) {
b |= 0x04;
}
if (hs->n && if (hs->n &&
!e->dz && !e->dz &&
(hs->kind == HID_TABLET || (!e->xdx && !e->ydy))) { (hs->kind == HID_TABLET || (!e->xdx && !e->ydy))) {
@@ -304,7 +358,7 @@ int hid_pointer_poll(HIDState *hs, uint8_t *buf, int len)
switch (hs->kind) { switch (hs->kind) {
case HID_MOUSE: case HID_MOUSE:
if (len > l) { if (len > l) {
buf[l++] = b; buf[l++] = e->buttons_state;
} }
if (len > l) { if (len > l) {
buf[l++] = dx; buf[l++] = dx;
@@ -319,7 +373,7 @@ int hid_pointer_poll(HIDState *hs, uint8_t *buf, int len)
case HID_TABLET: case HID_TABLET:
if (len > l) { if (len > l) {
buf[l++] = b; buf[l++] = e->buttons_state;
} }
if (len > l) { if (len > l) {
buf[l++] = dx & 0xff; buf[l++] = dx & 0xff;
@@ -413,31 +467,45 @@ void hid_reset(HIDState *hs)
void hid_free(HIDState *hs) void hid_free(HIDState *hs)
{ {
switch (hs->kind) { qemu_input_handler_unregister(hs->s);
case HID_KEYBOARD:
qemu_remove_kbd_event_handler(hs->kbd.eh_entry);
break;
case HID_MOUSE:
case HID_TABLET:
qemu_remove_mouse_event_handler(hs->ptr.eh_entry);
break;
}
hid_del_idle_timer(hs); hid_del_idle_timer(hs);
} }
static QemuInputHandler hid_keyboard_handler = {
.name = "QEMU HID Keyboard",
.mask = INPUT_EVENT_MASK_KEY,
.event = hid_keyboard_event,
};
static QemuInputHandler hid_mouse_handler = {
.name = "QEMU HID Mouse",
.mask = INPUT_EVENT_MASK_BTN | INPUT_EVENT_MASK_REL,
.event = hid_pointer_event,
.sync = hid_pointer_sync,
};
static QemuInputHandler hid_tablet_handler = {
.name = "QEMU HID Tablet",
.mask = INPUT_EVENT_MASK_BTN | INPUT_EVENT_MASK_ABS,
.event = hid_pointer_event,
.sync = hid_pointer_sync,
};
void hid_init(HIDState *hs, int kind, HIDEventFunc event) void hid_init(HIDState *hs, int kind, HIDEventFunc event)
{ {
hs->kind = kind; hs->kind = kind;
hs->event = event; hs->event = event;
if (hs->kind == HID_KEYBOARD) { if (hs->kind == HID_KEYBOARD) {
hs->kbd.eh_entry = qemu_add_kbd_event_handler(hid_keyboard_event, hs); hs->s = qemu_input_handler_register((DeviceState *)hs,
&hid_keyboard_handler);
qemu_input_handler_activate(hs->s);
} else if (hs->kind == HID_MOUSE) { } else if (hs->kind == HID_MOUSE) {
hs->ptr.eh_entry = qemu_add_mouse_event_handler(hid_pointer_event, hs, hs->s = qemu_input_handler_register((DeviceState *)hs,
0, "QEMU HID Mouse"); &hid_mouse_handler);
} else if (hs->kind == HID_TABLET) { } else if (hs->kind == HID_TABLET) {
hs->ptr.eh_entry = qemu_add_mouse_event_handler(hid_pointer_event, hs, hs->s = qemu_input_handler_register((DeviceState *)hs,
1, "QEMU HID Tablet"); &hid_tablet_handler);
} }
} }

View File

@@ -47,6 +47,8 @@ typedef struct USBHIDState {
USBEndpoint *intr; USBEndpoint *intr;
HIDState hid; HIDState hid;
uint32_t usb_version; uint32_t usb_version;
char *display;
uint32_t head;
} USBHIDState; } USBHIDState;
enum { enum {
@@ -574,6 +576,9 @@ static int usb_hid_initfn(USBDevice *dev, int kind)
usb_desc_init(dev); usb_desc_init(dev);
us->intr = usb_ep_get(dev, USB_TOKEN_IN, 1); us->intr = usb_ep_get(dev, USB_TOKEN_IN, 1);
hid_init(&us->hid, kind, usb_hid_changed); hid_init(&us->hid, kind, usb_hid_changed);
if (us->display && us->hid.s) {
qemu_input_handler_bind(us->hid.s, us->display, us->head, NULL);
}
return 0; return 0;
} }
@@ -653,6 +658,8 @@ static void usb_hid_class_initfn(ObjectClass *klass, void *data)
static Property usb_tablet_properties[] = { static Property usb_tablet_properties[] = {
DEFINE_PROP_UINT32("usb_version", USBHIDState, usb_version, 2), DEFINE_PROP_UINT32("usb_version", USBHIDState, usb_version, 2),
DEFINE_PROP_STRING("display", USBHIDState, display),
DEFINE_PROP_UINT32("head", USBHIDState, head, 0),
DEFINE_PROP_END_OF_LIST(), DEFINE_PROP_END_OF_LIST(),
}; };
@@ -696,6 +703,11 @@ static const TypeInfo usb_mouse_info = {
.class_init = usb_mouse_class_initfn, .class_init = usb_mouse_class_initfn,
}; };
static Property usb_keyboard_properties[] = {
DEFINE_PROP_STRING("display", USBHIDState, display),
DEFINE_PROP_END_OF_LIST(),
};
static void usb_keyboard_class_initfn(ObjectClass *klass, void *data) static void usb_keyboard_class_initfn(ObjectClass *klass, void *data)
{ {
DeviceClass *dc = DEVICE_CLASS(klass); DeviceClass *dc = DEVICE_CLASS(klass);
@@ -706,6 +718,7 @@ static void usb_keyboard_class_initfn(ObjectClass *klass, void *data)
uc->product_desc = "QEMU USB Keyboard"; uc->product_desc = "QEMU USB Keyboard";
uc->usb_desc = &desc_keyboard; uc->usb_desc = &desc_keyboard;
dc->vmsd = &vmstate_usb_kbd; dc->vmsd = &vmstate_usb_kbd;
dc->props = usb_keyboard_properties;
set_bit(DEVICE_CATEGORY_INPUT, dc->categories); set_bit(DEVICE_CATEGORY_INPUT, dc->categories);
} }

View File

@@ -46,7 +46,6 @@ enum mtp_code {
/* response codes */ /* response codes */
RES_OK = 0x2001, RES_OK = 0x2001,
RES_GENERAL_ERROR = 0x2002,
RES_SESSION_NOT_OPEN = 0x2003, RES_SESSION_NOT_OPEN = 0x2003,
RES_INVALID_TRANSACTION_ID = 0x2004, RES_INVALID_TRANSACTION_ID = 0x2004,
RES_OPERATION_NOT_SUPPORTED = 0x2005, RES_OPERATION_NOT_SUPPORTED = 0x2005,
@@ -110,8 +109,7 @@ struct MTPObject {
struct stat stat; struct stat stat;
MTPObject *parent; MTPObject *parent;
MTPObject **children; MTPObject **children;
uint32_t nchildren; int32_t nchildren;
bool have_children;
QTAILQ_ENTRY(MTPObject) next; QTAILQ_ENTRY(MTPObject) next;
}; };
@@ -275,6 +273,7 @@ static MTPObject *usb_mtp_object_alloc(MTPState *s, uint32_t handle,
o->handle = handle; o->handle = handle;
o->parent = parent; o->parent = parent;
o->name = g_strdup(name); o->name = g_strdup(name);
o->nchildren = -1;
if (parent == NULL) { if (parent == NULL) {
o->path = g_strdup(name); o->path = g_strdup(name);
} else { } else {
@@ -341,11 +340,7 @@ static void usb_mtp_object_readdir(MTPState *s, MTPObject *o)
struct dirent *entry; struct dirent *entry;
DIR *dir; DIR *dir;
if (o->have_children) { o->nchildren = 0;
return;
}
o->have_children = true;
dir = opendir(o->path); dir = opendir(o->path);
if (!dir) { if (!dir) {
return; return;
@@ -703,10 +698,7 @@ static MTPData *usb_mtp_get_partial_object(MTPState *s, MTPControl *c,
if (offset > o->stat.st_size) { if (offset > o->stat.st_size) {
offset = o->stat.st_size; offset = o->stat.st_size;
} }
if (lseek(d->fd, offset, SEEK_SET) < 0) { lseek(d->fd, offset, SEEK_SET);
usb_mtp_data_free(d);
return NULL;
}
d->length = c->argv[2]; d->length = c->argv[2];
if (d->length > o->stat.st_size - offset) { if (d->length > o->stat.st_size - offset) {
@@ -797,7 +789,9 @@ static void usb_mtp_command(MTPState *s, MTPControl *c)
c->trans, 0, 0, 0); c->trans, 0, 0, 0);
return; return;
} }
usb_mtp_object_readdir(s, o); if (o->nchildren == -1) {
usb_mtp_object_readdir(s, o);
}
if (c->code == CMD_GET_NUM_OBJECTS) { if (c->code == CMD_GET_NUM_OBJECTS) {
trace_usb_mtp_op_get_num_objects(s->dev.addr, o->handle, o->path); trace_usb_mtp_op_get_num_objects(s->dev.addr, o->handle, o->path);
nres = 1; nres = 1;
@@ -829,9 +823,7 @@ static void usb_mtp_command(MTPState *s, MTPControl *c)
} }
data_in = usb_mtp_get_object(s, c, o); data_in = usb_mtp_get_object(s, c, o);
if (NULL == data_in) { if (NULL == data_in) {
usb_mtp_queue_result(s, RES_GENERAL_ERROR, fprintf(stderr, "%s: TODO: handle error\n", __func__);
c->trans, 0, 0, 0);
return;
} }
break; break;
case CMD_GET_PARTIAL_OBJECT: case CMD_GET_PARTIAL_OBJECT:
@@ -848,9 +840,7 @@ static void usb_mtp_command(MTPState *s, MTPControl *c)
} }
data_in = usb_mtp_get_partial_object(s, c, o); data_in = usb_mtp_get_partial_object(s, c, o);
if (NULL == data_in) { if (NULL == data_in) {
usb_mtp_queue_result(s, RES_GENERAL_ERROR, fprintf(stderr, "%s: TODO: handle error\n", __func__);
c->trans, 0, 0, 0);
return;
} }
nres = 1; nres = 1;
res0 = data_in->length; res0 = data_in->length;

View File

@@ -621,11 +621,6 @@ static const char *ep_state_name(uint32_t state)
ARRAY_SIZE(ep_state_names)); ARRAY_SIZE(ep_state_names));
} }
static bool xhci_get_flag(XHCIState *xhci, enum xhci_flags bit)
{
return xhci->flags & (1 << bit);
}
static uint64_t xhci_mfindex_get(XHCIState *xhci) static uint64_t xhci_mfindex_get(XHCIState *xhci)
{ {
int64_t now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); int64_t now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
@@ -3440,7 +3435,7 @@ static void xhci_child_detach(USBPort *uport, USBDevice *child)
USBBus *bus = usb_bus_from_device(child); USBBus *bus = usb_bus_from_device(child);
XHCIState *xhci = container_of(bus, XHCIState, bus); XHCIState *xhci = container_of(bus, XHCIState, bus);
xhci_detach_slot(xhci, child->port); xhci_detach_slot(xhci, uport);
} }
static USBPortOps xhci_uport_ops = { static USBPortOps xhci_uport_ops = {
@@ -3599,15 +3594,13 @@ static int usb_xhci_initfn(struct PCIDevice *dev)
PCI_BASE_ADDRESS_SPACE_MEMORY|PCI_BASE_ADDRESS_MEM_TYPE_64, PCI_BASE_ADDRESS_SPACE_MEMORY|PCI_BASE_ADDRESS_MEM_TYPE_64,
&xhci->mem); &xhci->mem);
if (pci_bus_is_express(dev->bus)) { ret = pcie_endpoint_cap_init(dev, 0xa0);
ret = pcie_endpoint_cap_init(dev, 0xa0); assert(ret >= 0);
assert(ret >= 0);
}
if (xhci_get_flag(xhci, XHCI_FLAG_USE_MSI)) { if (xhci->flags & (1 << XHCI_FLAG_USE_MSI)) {
msi_init(dev, 0x70, xhci->numintrs, true, false); msi_init(dev, 0x70, xhci->numintrs, true, false);
} }
if (xhci_get_flag(xhci, XHCI_FLAG_USE_MSI_X)) { if (xhci->flags & (1 << XHCI_FLAG_USE_MSI_X)) {
msix_init(dev, xhci->numintrs, msix_init(dev, xhci->numintrs,
&xhci->mem, 0, OFF_MSIX_TABLE, &xhci->mem, 0, OFF_MSIX_TABLE,
&xhci->mem, 0, OFF_MSIX_PBA, &xhci->mem, 0, OFF_MSIX_PBA,

View File

@@ -720,9 +720,6 @@ static void usb_host_ep_update(USBHostDevice *s)
struct libusb_config_descriptor *conf; struct libusb_config_descriptor *conf;
const struct libusb_interface_descriptor *intf; const struct libusb_interface_descriptor *intf;
const struct libusb_endpoint_descriptor *endp; const struct libusb_endpoint_descriptor *endp;
#if LIBUSBX_API_VERSION >= 0x01000103
struct libusb_ss_endpoint_companion_descriptor *endp_ss_comp;
#endif
uint8_t devep, type; uint8_t devep, type;
int pid, ep; int pid, ep;
int rc, i, e; int rc, i, e;
@@ -768,15 +765,6 @@ static void usb_host_ep_update(USBHostDevice *s)
usb_ep_set_type(udev, pid, ep, type); usb_ep_set_type(udev, pid, ep, type);
usb_ep_set_ifnum(udev, pid, ep, i); usb_ep_set_ifnum(udev, pid, ep, i);
usb_ep_set_halted(udev, pid, ep, 0); usb_ep_set_halted(udev, pid, ep, 0);
#if LIBUSBX_API_VERSION >= 0x01000103
if (type == LIBUSB_TRANSFER_TYPE_BULK &&
libusb_get_ss_endpoint_companion_descriptor(ctx, endp,
&endp_ss_comp) == LIBUSB_SUCCESS) {
usb_ep_set_max_streams(udev, pid, ep,
endp_ss_comp->bmAttributes);
libusb_free_ss_endpoint_companion_descriptor(endp_ss_comp);
}
#endif
} }
} }
@@ -1214,23 +1202,10 @@ static void usb_host_handle_data(USBDevice *udev, USBPacket *p)
usb_packet_copy(p, r->buffer, size); usb_packet_copy(p, r->buffer, size);
} }
ep = p->ep->nr | (r->in ? USB_DIR_IN : 0); ep = p->ep->nr | (r->in ? USB_DIR_IN : 0);
if (p->stream) { libusb_fill_bulk_transfer(r->xfer, s->dh, ep,
#if LIBUSBX_API_VERSION >= 0x01000103 r->buffer, size,
libusb_fill_bulk_stream_transfer(r->xfer, s->dh, ep, p->stream, usb_host_req_complete_data, r,
r->buffer, size, BULK_TIMEOUT);
usb_host_req_complete_data, r,
BULK_TIMEOUT);
#else
usb_host_req_free(r);
p->status = USB_RET_STALL;
return;
#endif
} else {
libusb_fill_bulk_transfer(r->xfer, s->dh, ep,
r->buffer, size,
usb_host_req_complete_data, r,
BULK_TIMEOUT);
}
break; break;
case USB_ENDPOINT_XFER_INT: case USB_ENDPOINT_XFER_INT:
r = usb_host_req_alloc(s, p, p->pid == USB_TOKEN_IN, p->iov.size); r = usb_host_req_alloc(s, p, p->pid == USB_TOKEN_IN, p->iov.size);
@@ -1293,54 +1268,6 @@ static void usb_host_handle_reset(USBDevice *udev)
} }
} }
static int usb_host_alloc_streams(USBDevice *udev, USBEndpoint **eps,
int nr_eps, int streams)
{
#if LIBUSBX_API_VERSION >= 0x01000103
USBHostDevice *s = USB_HOST_DEVICE(udev);
unsigned char endpoints[30];
int i, rc;
for (i = 0; i < nr_eps; i++) {
endpoints[i] = eps[i]->nr;
if (eps[i]->pid == USB_TOKEN_IN) {
endpoints[i] |= 0x80;
}
}
rc = libusb_alloc_streams(s->dh, streams, endpoints, nr_eps);
if (rc < 0) {
usb_host_libusb_error("libusb_alloc_streams", rc);
} else if (rc != streams) {
fprintf(stderr,
"libusb_alloc_streams: got less streams then requested %d < %d\n",
rc, streams);
}
return (rc == streams) ? 0 : -1;
#else
fprintf(stderr, "libusb_alloc_streams: error not implemented\n");
return -1;
#endif
}
static void usb_host_free_streams(USBDevice *udev, USBEndpoint **eps,
int nr_eps)
{
#if LIBUSBX_API_VERSION >= 0x01000103
USBHostDevice *s = USB_HOST_DEVICE(udev);
unsigned char endpoints[30];
int i;
for (i = 0; i < nr_eps; i++) {
endpoints[i] = eps[i]->nr;
if (eps[i]->pid == USB_TOKEN_IN) {
endpoints[i] |= 0x80;
}
}
libusb_free_streams(s->dh, endpoints, nr_eps);
#endif
}
/* /*
* This is *NOT* about restoring state. We have absolutely no idea * This is *NOT* about restoring state. We have absolutely no idea
* what state the host device is in at the moment and whenever it is * what state the host device is in at the moment and whenever it is
@@ -1422,8 +1349,6 @@ static void usb_host_class_initfn(ObjectClass *klass, void *data)
uc->handle_reset = usb_host_handle_reset; uc->handle_reset = usb_host_handle_reset;
uc->handle_destroy = usb_host_handle_destroy; uc->handle_destroy = usb_host_handle_destroy;
uc->flush_ep_queue = usb_host_flush_ep_queue; uc->flush_ep_queue = usb_host_flush_ep_queue;
uc->alloc_streams = usb_host_alloc_streams;
uc->free_streams = usb_host_free_streams;
dc->vmsd = &vmstate_usb_host; dc->vmsd = &vmstate_usb_host;
dc->props = usb_host_dev_properties; dc->props = usb_host_dev_properties;
set_bit(DEVICE_CATEGORY_BRIDGE, dc->categories); set_bit(DEVICE_CATEGORY_BRIDGE, dc->categories);

View File

@@ -50,10 +50,6 @@
((i) & 0x10) ? USB_TOKEN_IN : USB_TOKEN_OUT, \ ((i) & 0x10) ? USB_TOKEN_IN : USB_TOKEN_OUT, \
(i) & 0x0f)) (i) & 0x0f))
#ifndef USBREDIR_VERSION /* This is not defined in older usbredir versions */
#define USBREDIR_VERSION 0
#endif
typedef struct USBRedirDevice USBRedirDevice; typedef struct USBRedirDevice USBRedirDevice;
/* Struct to hold buffered packets */ /* Struct to hold buffered packets */
@@ -72,7 +68,6 @@ struct endp_data {
uint8_t interval; uint8_t interval;
uint8_t interface; /* bInterfaceNumber this ep belongs to */ uint8_t interface; /* bInterfaceNumber this ep belongs to */
uint16_t max_packet_size; /* In bytes, not wMaxPacketSize format !! */ uint16_t max_packet_size; /* In bytes, not wMaxPacketSize format !! */
uint32_t max_streams;
uint8_t iso_started; uint8_t iso_started;
uint8_t iso_error; /* For reporting iso errors to the HC */ uint8_t iso_error; /* For reporting iso errors to the HC */
uint8_t interrupt_started; uint8_t interrupt_started;
@@ -111,9 +106,8 @@ struct USBRedirDevice {
int read_buf_size; int read_buf_size;
/* Active chardev-watch-tag */ /* Active chardev-watch-tag */
guint watch; guint watch;
/* For async handling of close / reject */ /* For async handling of close */
QEMUBH *chardev_close_bh; QEMUBH *chardev_close_bh;
QEMUBH *device_reject_bh;
/* To delay the usb attach in case of quick chardev close + open */ /* To delay the usb attach in case of quick chardev close + open */
QEMUTimer *attach_timer; QEMUTimer *attach_timer;
int64_t next_attach_time; int64_t next_attach_time;
@@ -786,12 +780,11 @@ static void usbredir_handle_bulk_data(USBRedirDevice *dev, USBPacket *p,
dev->endpoint[EP2I(ep)].bulk_receiving_enabled = 0; dev->endpoint[EP2I(ep)].bulk_receiving_enabled = 0;
} }
DPRINTF("bulk-out ep %02X stream %u len %zd id %"PRIu64"\n", DPRINTF("bulk-out ep %02X len %zd id %"PRIu64"\n", ep, size, p->id);
ep, p->stream, size, p->id);
bulk_packet.endpoint = ep; bulk_packet.endpoint = ep;
bulk_packet.length = size; bulk_packet.length = size;
bulk_packet.stream_id = p->stream; bulk_packet.stream_id = 0;
bulk_packet.length_high = size >> 16; bulk_packet.length_high = size >> 16;
assert(bulk_packet.length_high == 0 || assert(bulk_packet.length_high == 0 ||
usbredirparser_peer_has_cap(dev->parser, usbredirparser_peer_has_cap(dev->parser,
@@ -1098,66 +1091,6 @@ static void usbredir_handle_control(USBDevice *udev, USBPacket *p,
p->status = USB_RET_ASYNC; p->status = USB_RET_ASYNC;
} }
static int usbredir_alloc_streams(USBDevice *udev, USBEndpoint **eps,
int nr_eps, int streams)
{
USBRedirDevice *dev = DO_UPCAST(USBRedirDevice, dev, udev);
#if USBREDIR_VERSION >= 0x000700
struct usb_redir_alloc_bulk_streams_header alloc_streams;
int i;
if (!usbredirparser_peer_has_cap(dev->parser,
usb_redir_cap_bulk_streams)) {
ERROR("peer does not support streams\n");
goto reject;
}
if (streams == 0) {
ERROR("request to allocate 0 streams\n");
return -1;
}
alloc_streams.no_streams = streams;
alloc_streams.endpoints = 0;
for (i = 0; i < nr_eps; i++) {
alloc_streams.endpoints |= 1 << USBEP2I(eps[i]);
}
usbredirparser_send_alloc_bulk_streams(dev->parser, 0, &alloc_streams);
usbredirparser_do_write(dev->parser);
return 0;
#else
ERROR("usbredir_alloc_streams not implemented\n");
goto reject;
#endif
reject:
ERROR("streams are not available, disconnecting\n");
qemu_bh_schedule(dev->device_reject_bh);
return -1;
}
static void usbredir_free_streams(USBDevice *udev, USBEndpoint **eps,
int nr_eps)
{
#if USBREDIR_VERSION >= 0x000700
USBRedirDevice *dev = DO_UPCAST(USBRedirDevice, dev, udev);
struct usb_redir_free_bulk_streams_header free_streams;
int i;
if (!usbredirparser_peer_has_cap(dev->parser,
usb_redir_cap_bulk_streams)) {
return;
}
free_streams.endpoints = 0;
for (i = 0; i < nr_eps; i++) {
free_streams.endpoints |= 1 << USBEP2I(eps[i]);
}
usbredirparser_send_free_bulk_streams(dev->parser, 0, &free_streams);
usbredirparser_do_write(dev->parser);
#endif
}
/* /*
* Close events can be triggered by usbredirparser_do_write which gets called * Close events can be triggered by usbredirparser_do_write which gets called
* from within the USBDevice data / control packet callbacks and doing a * from within the USBDevice data / control packet callbacks and doing a
@@ -1169,7 +1102,6 @@ static void usbredir_chardev_close_bh(void *opaque)
{ {
USBRedirDevice *dev = opaque; USBRedirDevice *dev = opaque;
qemu_bh_cancel(dev->device_reject_bh);
usbredir_device_disconnect(dev); usbredir_device_disconnect(dev);
if (dev->parser) { if (dev->parser) {
@@ -1221,9 +1153,6 @@ static void usbredir_create_parser(USBRedirDevice *dev)
usbredirparser_caps_set_cap(caps, usb_redir_cap_64bits_ids); usbredirparser_caps_set_cap(caps, usb_redir_cap_64bits_ids);
usbredirparser_caps_set_cap(caps, usb_redir_cap_32bits_bulk_length); usbredirparser_caps_set_cap(caps, usb_redir_cap_32bits_bulk_length);
usbredirparser_caps_set_cap(caps, usb_redir_cap_bulk_receiving); usbredirparser_caps_set_cap(caps, usb_redir_cap_bulk_receiving);
#if USBREDIR_VERSION >= 0x000700
usbredirparser_caps_set_cap(caps, usb_redir_cap_bulk_streams);
#endif
if (runstate_check(RUN_STATE_INMIGRATE)) { if (runstate_check(RUN_STATE_INMIGRATE)) {
flags |= usbredirparser_fl_no_hello; flags |= usbredirparser_fl_no_hello;
@@ -1242,17 +1171,6 @@ static void usbredir_reject_device(USBRedirDevice *dev)
} }
} }
/*
* We may need to reject the device when the hcd calls alloc_streams, doing
* an usb_detach from within a hcd call is not a good idea, hence this bh.
*/
static void usbredir_device_reject_bh(void *opaque)
{
USBRedirDevice *dev = opaque;
usbredir_reject_device(dev);
}
static void usbredir_do_attach(void *opaque) static void usbredir_do_attach(void *opaque)
{ {
USBRedirDevice *dev = opaque; USBRedirDevice *dev = opaque;
@@ -1379,7 +1297,6 @@ static int usbredir_initfn(USBDevice *udev)
} }
dev->chardev_close_bh = qemu_bh_new(usbredir_chardev_close_bh, dev); dev->chardev_close_bh = qemu_bh_new(usbredir_chardev_close_bh, dev);
dev->device_reject_bh = qemu_bh_new(usbredir_device_reject_bh, dev);
dev->attach_timer = timer_new_ms(QEMU_CLOCK_VIRTUAL, usbredir_do_attach, dev); dev->attach_timer = timer_new_ms(QEMU_CLOCK_VIRTUAL, usbredir_do_attach, dev);
packet_id_queue_init(&dev->cancelled, dev, "cancelled"); packet_id_queue_init(&dev->cancelled, dev, "cancelled");
@@ -1420,7 +1337,6 @@ static void usbredir_handle_destroy(USBDevice *udev)
dev->cs = NULL; dev->cs = NULL;
/* Note must be done after qemu_chr_close, as that causes a close event */ /* Note must be done after qemu_chr_close, as that causes a close event */
qemu_bh_delete(dev->chardev_close_bh); qemu_bh_delete(dev->chardev_close_bh);
qemu_bh_delete(dev->device_reject_bh);
timer_del(dev->attach_timer); timer_del(dev->attach_timer);
timer_free(dev->attach_timer); timer_free(dev->attach_timer);
@@ -1712,7 +1628,6 @@ static void usbredir_setup_usb_eps(USBRedirDevice *dev)
usb_ep->type = dev->endpoint[i].type; usb_ep->type = dev->endpoint[i].type;
usb_ep->ifnum = dev->endpoint[i].interface; usb_ep->ifnum = dev->endpoint[i].interface;
usb_ep->max_packet_size = dev->endpoint[i].max_packet_size; usb_ep->max_packet_size = dev->endpoint[i].max_packet_size;
usb_ep->max_streams = dev->endpoint[i].max_streams;
usbredir_set_pipeline(dev, usb_ep); usbredir_set_pipeline(dev, usb_ep);
} }
} }
@@ -1731,12 +1646,6 @@ static void usbredir_ep_info(void *priv,
usb_redir_cap_ep_info_max_packet_size)) { usb_redir_cap_ep_info_max_packet_size)) {
dev->endpoint[i].max_packet_size = ep_info->max_packet_size[i]; dev->endpoint[i].max_packet_size = ep_info->max_packet_size[i];
} }
#if USBREDIR_VERSION >= 0x000700
if (usbredirparser_peer_has_cap(dev->parser,
usb_redir_cap_bulk_streams)) {
dev->endpoint[i].max_streams = ep_info->max_streams[i];
}
#endif
switch (dev->endpoint[i].type) { switch (dev->endpoint[i].type) {
case usb_redir_type_invalid: case usb_redir_type_invalid:
break; break;
@@ -1870,20 +1779,6 @@ static void usbredir_interrupt_receiving_status(void *priv, uint64_t id,
static void usbredir_bulk_streams_status(void *priv, uint64_t id, static void usbredir_bulk_streams_status(void *priv, uint64_t id,
struct usb_redir_bulk_streams_status_header *bulk_streams_status) struct usb_redir_bulk_streams_status_header *bulk_streams_status)
{ {
#if USBREDIR_VERSION >= 0x000700
USBRedirDevice *dev = priv;
if (bulk_streams_status->status == usb_redir_success) {
DPRINTF("bulk streams status %d eps %08x\n",
bulk_streams_status->status, bulk_streams_status->endpoints);
} else {
ERROR("bulk streams %s failed status %d eps %08x\n",
(bulk_streams_status->no_streams == 0) ? "free" : "alloc",
bulk_streams_status->status, bulk_streams_status->endpoints);
ERROR("usb-redir-host does not provide streams, disconnecting\n");
usbredir_reject_device(dev);
}
#endif
} }
static void usbredir_bulk_receiving_status(void *priv, uint64_t id, static void usbredir_bulk_receiving_status(void *priv, uint64_t id,
@@ -1955,8 +1850,8 @@ static void usbredir_bulk_packet(void *priv, uint64_t id,
int len = (bulk_packet->length_high << 16) | bulk_packet->length; int len = (bulk_packet->length_high << 16) | bulk_packet->length;
USBPacket *p; USBPacket *p;
DPRINTF("bulk-in status %d ep %02X stream %u len %d id %"PRIu64"\n", DPRINTF("bulk-in status %d ep %02X len %d id %"PRIu64"\n",
bulk_packet->status, ep, bulk_packet->stream_id, len, id); bulk_packet->status, ep, len, id);
p = usbredir_find_packet_by_id(dev, ep, id); p = usbredir_find_packet_by_id(dev, ep, id);
if (p) { if (p) {
@@ -2270,23 +2165,6 @@ static bool usbredir_bulk_receiving_needed(void *priv)
return endp->bulk_receiving_started; return endp->bulk_receiving_started;
} }
static const VMStateDescription usbredir_stream_vmstate = {
.name = "usb-redir-ep/stream-state",
.version_id = 1,
.minimum_version_id = 1,
.fields = (VMStateField[]) {
VMSTATE_UINT32(max_streams, struct endp_data),
VMSTATE_END_OF_LIST()
}
};
static bool usbredir_stream_needed(void *priv)
{
struct endp_data *endp = priv;
return endp->max_streams;
}
static const VMStateDescription usbredir_ep_vmstate = { static const VMStateDescription usbredir_ep_vmstate = {
.name = "usb-redir-ep", .name = "usb-redir-ep",
.version_id = 1, .version_id = 1,
@@ -2318,9 +2196,6 @@ static const VMStateDescription usbredir_ep_vmstate = {
{ {
.vmsd = &usbredir_bulk_receiving_vmstate, .vmsd = &usbredir_bulk_receiving_vmstate,
.needed = usbredir_bulk_receiving_needed, .needed = usbredir_bulk_receiving_needed,
}, {
.vmsd = &usbredir_stream_vmstate,
.needed = usbredir_stream_needed,
}, { }, {
/* empty */ /* empty */
} }
@@ -2486,8 +2361,6 @@ static void usbredir_class_initfn(ObjectClass *klass, void *data)
uc->handle_control = usbredir_handle_control; uc->handle_control = usbredir_handle_control;
uc->flush_ep_queue = usbredir_flush_ep_queue; uc->flush_ep_queue = usbredir_flush_ep_queue;
uc->ep_stopped = usbredir_ep_stopped; uc->ep_stopped = usbredir_ep_stopped;
uc->alloc_streams = usbredir_alloc_streams;
uc->free_streams = usbredir_free_streams;
dc->vmsd = &usbredir_vmstate; dc->vmsd = &usbredir_vmstate;
dc->props = usbredir_properties; dc->props = usbredir_properties;
set_bit(DEVICE_CATEGORY_MISC, dc->categories); set_bit(DEVICE_CATEGORY_MISC, dc->categories);

View File

@@ -2,6 +2,7 @@
#define QEMU_HID_H #define QEMU_HID_H
#include "migration/vmstate.h" #include "migration/vmstate.h"
#include "ui/input.h"
#define HID_MOUSE 1 #define HID_MOUSE 1
#define HID_TABLET 2 #define HID_TABLET 2
@@ -22,7 +23,6 @@ typedef void (*HIDEventFunc)(HIDState *s);
typedef struct HIDMouseState { typedef struct HIDMouseState {
HIDPointerEvent queue[QUEUE_LENGTH]; HIDPointerEvent queue[QUEUE_LENGTH];
int mouse_grabbed; int mouse_grabbed;
QEMUPutMouseEntry *eh_entry;
} HIDMouseState; } HIDMouseState;
typedef struct HIDKeyboardState { typedef struct HIDKeyboardState {
@@ -31,7 +31,6 @@ typedef struct HIDKeyboardState {
uint8_t leds; uint8_t leds;
uint8_t key[16]; uint8_t key[16];
int32_t keys; int32_t keys;
QEMUPutKbdEntry *eh_entry;
} HIDKeyboardState; } HIDKeyboardState;
struct HIDState { struct HIDState {
@@ -47,6 +46,7 @@ struct HIDState {
bool idle_pending; bool idle_pending;
QEMUTimer *idle_timer; QEMUTimer *idle_timer;
HIDEventFunc event; HIDEventFunc event;
QemuInputHandlerState *s;
}; };
void hid_init(HIDState *hs, int kind, HIDEventFunc event); void hid_init(HIDState *hs, int kind, HIDEventFunc event);

View File

@@ -29,6 +29,9 @@ QemuInputHandlerState *qemu_input_handler_register(DeviceState *dev,
void qemu_input_handler_activate(QemuInputHandlerState *s); void qemu_input_handler_activate(QemuInputHandlerState *s);
void qemu_input_handler_deactivate(QemuInputHandlerState *s); void qemu_input_handler_deactivate(QemuInputHandlerState *s);
void qemu_input_handler_unregister(QemuInputHandlerState *s); void qemu_input_handler_unregister(QemuInputHandlerState *s);
void qemu_input_handler_bind(QemuInputHandlerState *s,
const char *device_id, int head,
Error **errp);
void qemu_input_event_send(QemuConsole *src, InputEvent *evt); void qemu_input_event_send(QemuConsole *src, InputEvent *evt);
void qemu_input_event_sync(void); void qemu_input_event_sync(void);
@@ -36,6 +39,7 @@ InputEvent *qemu_input_event_new_key(KeyValue *key, bool down);
void qemu_input_event_send_key(QemuConsole *src, KeyValue *key, bool down); void qemu_input_event_send_key(QemuConsole *src, KeyValue *key, bool down);
void qemu_input_event_send_key_number(QemuConsole *src, int num, bool down); void qemu_input_event_send_key_number(QemuConsole *src, int num, bool down);
void qemu_input_event_send_key_qcode(QemuConsole *src, QKeyCode q, bool down); void qemu_input_event_send_key_qcode(QemuConsole *src, QKeyCode q, bool down);
int qemu_input_key_number_to_qcode(uint8_t nr);
int qemu_input_key_value_to_number(const KeyValue *value); int qemu_input_key_value_to_number(const KeyValue *value);
int qemu_input_key_value_to_qcode(const KeyValue *value); int qemu_input_key_value_to_qcode(const KeyValue *value);
int qemu_input_key_value_to_scancode(const KeyValue *value, bool down, int qemu_input_key_value_to_scancode(const KeyValue *value, bool down,

View File

@@ -1050,7 +1050,7 @@ gd_update(int x, int y, int w, int h) "x=%d, y=%d, w=%d, h=%d"
gd_key_event(int gdk_keycode, int qemu_keycode, const char *action) "translated GDK keycode %d to QEMU keycode %d (%s)" gd_key_event(int gdk_keycode, int qemu_keycode, const char *action) "translated GDK keycode %d to QEMU keycode %d (%s)"
# ui/input.c # ui/input.c
input_event_key_number(int conidx, int number, bool down) "con %d, key number 0x%x, down %d" input_event_key_number(int conidx, int number, const char *qcode, bool down) "con %d, key number 0x%x [%s], down %d"
input_event_key_qcode(int conidx, const char *qcode, bool down) "con %d, key qcode %s, down %d" input_event_key_qcode(int conidx, const char *qcode, bool down) "con %d, key qcode %s, down %d"
input_event_btn(int conidx, const char *btn, bool down) "con %d, button %s, down %d" input_event_btn(int conidx, const char *btn, bool down) "con %d, button %s, down %d"
input_event_rel(int conidx, const char *axis, int value) "con %d, axis %s, value %d" input_event_rel(int conidx, const char *axis, int value) "con %d, axis %s, value %d"

View File

@@ -288,8 +288,8 @@ static void curses_refresh(DisplayChangeListener *dcl)
qemu_input_event_send_key_number(NULL, GREY | ALT_CODE, true); qemu_input_event_send_key_number(NULL, GREY | ALT_CODE, true);
} }
qemu_input_event_send_key_number(NULL, keycode, true); qemu_input_event_send_key_number(NULL, keycode & KEY_MASK, true);
qemu_input_event_send_key_number(NULL, keycode, false); qemu_input_event_send_key_number(NULL, keycode & KEY_MASK, false);
if (keycode & ALTGR) { if (keycode & ALTGR) {
qemu_input_event_send_key_number(NULL, GREY | ALT_CODE, false); qemu_input_event_send_key_number(NULL, GREY | ALT_CODE, false);

View File

@@ -13,6 +13,8 @@ static const int qcode_to_number[] = {
[Q_KEY_CODE_CTRL] = 0x1d, [Q_KEY_CODE_CTRL] = 0x1d,
[Q_KEY_CODE_CTRL_R] = 0x9d, [Q_KEY_CODE_CTRL_R] = 0x9d,
[Q_KEY_CODE_META_L] = 0xdb,
[Q_KEY_CODE_META_R] = 0xdc,
[Q_KEY_CODE_MENU] = 0xdd, [Q_KEY_CODE_MENU] = 0xdd,
[Q_KEY_CODE_ESC] = 0x01, [Q_KEY_CODE_ESC] = 0x01,
@@ -129,7 +131,7 @@ static const int qcode_to_number[] = {
[Q_KEY_CODE_MAX] = 0, [Q_KEY_CODE_MAX] = 0,
}; };
static int number_to_qcode[0xff]; static int number_to_qcode[0x100];
int qemu_input_key_value_to_number(const KeyValue *value) int qemu_input_key_value_to_number(const KeyValue *value)
{ {
@@ -141,7 +143,7 @@ int qemu_input_key_value_to_number(const KeyValue *value)
} }
} }
int qemu_input_key_value_to_qcode(const KeyValue *value) int qemu_input_key_number_to_qcode(uint8_t nr)
{ {
static int first = true; static int first = true;
@@ -155,11 +157,16 @@ int qemu_input_key_value_to_qcode(const KeyValue *value)
} }
} }
return number_to_qcode[nr];
}
int qemu_input_key_value_to_qcode(const KeyValue *value)
{
if (value->kind == KEY_VALUE_KIND_QCODE) { if (value->kind == KEY_VALUE_KIND_QCODE) {
return value->qcode; return value->qcode;
} else { } else {
assert(value->kind == KEY_VALUE_KIND_NUMBER); assert(value->kind == KEY_VALUE_KIND_NUMBER);
return number_to_qcode[value->number]; return qemu_input_key_number_to_qcode(value->number);
} }
} }

View File

@@ -1,3 +1,4 @@
#include "hw/qdev.h"
#include "sysemu/sysemu.h" #include "sysemu/sysemu.h"
#include "qapi-types.h" #include "qapi-types.h"
#include "qmp-commands.h" #include "qmp-commands.h"
@@ -10,6 +11,7 @@ struct QemuInputHandlerState {
QemuInputHandler *handler; QemuInputHandler *handler;
int id; int id;
int events; int events;
QemuConsole *con;
QTAILQ_ENTRY(QemuInputHandlerState) node; QTAILQ_ENTRY(QemuInputHandlerState) node;
}; };
static QTAILQ_HEAD(, QemuInputHandlerState) handlers = static QTAILQ_HEAD(, QemuInputHandlerState) handlers =
@@ -53,12 +55,46 @@ void qemu_input_handler_unregister(QemuInputHandlerState *s)
qemu_input_check_mode_change(); qemu_input_check_mode_change();
} }
void qemu_input_handler_bind(QemuInputHandlerState *s,
const char *device_id, int head,
Error **errp)
{
DeviceState *dev;
QemuConsole *con;
dev = qdev_find_recursive(sysbus_get_default(), device_id);
if (dev == NULL) {
error_set(errp, QERR_DEVICE_NOT_FOUND, device_id);
return;
}
con = qemu_console_lookup_by_device(dev, head);
if (con == NULL) {
error_setg(errp, "Device %s is not bound to a QemuConsole", device_id);
return;
}
s->con = con;
}
static QemuInputHandlerState* static QemuInputHandlerState*
qemu_input_find_handler(uint32_t mask) qemu_input_find_handler(uint32_t mask, QemuConsole *con)
{ {
QemuInputHandlerState *s; QemuInputHandlerState *s;
QTAILQ_FOREACH(s, &handlers, node) { QTAILQ_FOREACH(s, &handlers, node) {
if (s->con == NULL || s->con != con) {
continue;
}
if (mask & s->handler->mask) {
return s;
}
}
QTAILQ_FOREACH(s, &handlers, node) {
if (s->con != NULL) {
continue;
}
if (mask & s->handler->mask) { if (mask & s->handler->mask) {
return s; return s;
} }
@@ -94,7 +130,7 @@ static void qemu_input_transform_abs_rotate(InputEvent *evt)
static void qemu_input_event_trace(QemuConsole *src, InputEvent *evt) static void qemu_input_event_trace(QemuConsole *src, InputEvent *evt)
{ {
const char *name; const char *name;
int idx = -1; int qcode, idx = -1;
if (src) { if (src) {
idx = qemu_console_get_index(src); idx = qemu_console_get_index(src);
@@ -103,8 +139,10 @@ static void qemu_input_event_trace(QemuConsole *src, InputEvent *evt)
case INPUT_EVENT_KIND_KEY: case INPUT_EVENT_KIND_KEY:
switch (evt->key->key->kind) { switch (evt->key->key->kind) {
case KEY_VALUE_KIND_NUMBER: case KEY_VALUE_KIND_NUMBER:
qcode = qemu_input_key_number_to_qcode(evt->key->key->number);
name = QKeyCode_lookup[qcode];
trace_input_event_key_number(idx, evt->key->key->number, trace_input_event_key_number(idx, evt->key->key->number,
evt->key->down); name, evt->key->down);
break; break;
case KEY_VALUE_KIND_QCODE: case KEY_VALUE_KIND_QCODE:
name = QKeyCode_lookup[evt->key->key->qcode]; name = QKeyCode_lookup[evt->key->key->qcode];
@@ -149,7 +187,7 @@ void qemu_input_event_send(QemuConsole *src, InputEvent *evt)
} }
/* send event */ /* send event */
s = qemu_input_find_handler(1 << evt->kind); s = qemu_input_find_handler(1 << evt->kind, src);
if (!s) { if (!s) {
return; return;
} }
@@ -250,7 +288,8 @@ bool qemu_input_is_absolute(void)
{ {
QemuInputHandlerState *s; QemuInputHandlerState *s;
s = qemu_input_find_handler(INPUT_EVENT_MASK_REL | INPUT_EVENT_MASK_ABS); s = qemu_input_find_handler(INPUT_EVENT_MASK_REL | INPUT_EVENT_MASK_ABS,
NULL);
return (s != NULL) && (s->handler->mask & INPUT_EVENT_MASK_ABS); return (s != NULL) && (s->handler->mask & INPUT_EVENT_MASK_ABS);
} }

View File

@@ -190,30 +190,33 @@ static void sdl_switch(DisplayChangeListener *dcl,
} }
} }
static void reset_keys(void) static void reset_keys(struct sdl2_state *scon)
{ {
QemuConsole *con = scon ? scon->dcl.con : NULL;
int i; int i;
for (i = 0; i < 256; i++) { for (i = 0; i < 256; i++) {
if (modifiers_state[i]) { if (modifiers_state[i]) {
int qcode = sdl2_scancode_to_qcode[i]; int qcode = sdl2_scancode_to_qcode[i];
qemu_input_event_send_key_qcode(NULL, qcode, false); qemu_input_event_send_key_qcode(con, qcode, false);
modifiers_state[i] = 0; modifiers_state[i] = 0;
} }
} }
} }
static void sdl_process_key(SDL_KeyboardEvent *ev) static void sdl_process_key(struct sdl2_state *scon,
SDL_KeyboardEvent *ev)
{ {
int qcode = sdl2_scancode_to_qcode[ev->keysym.scancode]; int qcode = sdl2_scancode_to_qcode[ev->keysym.scancode];
QemuConsole *con = scon ? scon->dcl.con : NULL;
switch (ev->keysym.scancode) { switch (ev->keysym.scancode) {
#if 0 #if 0
case SDL_SCANCODE_NUMLOCKCLEAR: case SDL_SCANCODE_NUMLOCKCLEAR:
case SDL_SCANCODE_CAPSLOCK: case SDL_SCANCODE_CAPSLOCK:
/* SDL does not send the key up event, so we generate it */ /* SDL does not send the key up event, so we generate it */
qemu_input_event_send_key_qcode(NULL, qcode, true); qemu_input_event_send_key_qcode(con, qcode, true);
qemu_input_event_send_key_qcode(NULL, qcode, false); qemu_input_event_send_key_qcode(con, qcode, false);
return; return;
#endif #endif
case SDL_SCANCODE_LCTRL: case SDL_SCANCODE_LCTRL:
@@ -231,7 +234,7 @@ static void sdl_process_key(SDL_KeyboardEvent *ev)
} }
/* fall though */ /* fall though */
default: default:
qemu_input_event_send_key_qcode(NULL, qcode, qemu_input_event_send_key_qcode(con, qcode,
ev->type == SDL_KEYDOWN); ev->type == SDL_KEYDOWN);
} }
} }
@@ -506,7 +509,7 @@ static void handle_keydown(SDL_Event *ev)
} }
} }
if (!gui_keysym) { if (!gui_keysym) {
sdl_process_key(&ev->key); sdl_process_key(scon, &ev->key);
} }
} }
@@ -531,13 +534,13 @@ static void handle_keyup(SDL_Event *ev)
} }
/* SDL does not send back all the modifiers key, so we must /* SDL does not send back all the modifiers key, so we must
* correct it. */ * correct it. */
reset_keys(); reset_keys(scon);
return; return;
} }
gui_keysym = 0; gui_keysym = 0;
} }
if (!gui_keysym) { if (!gui_keysym) {
sdl_process_key(&ev->key); sdl_process_key(scon, &ev->key);
} }
} }