Compare commits
10 Commits
pull-usb-7
...
pull-input
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8977bd111f | ||
|
|
f85d28316a | ||
|
|
ee8c0b622c | ||
|
|
6f5943cf45 | ||
|
|
8b84286f4c | ||
|
|
1ff5eedd1d | ||
|
|
86846bfe64 | ||
|
|
2386a90730 | ||
|
|
11c7fa7fa6 | ||
|
|
f5c0ab1312 |
76
docs/multiseat.txt
Normal file
76
docs/multiseat.txt
Normal 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>
|
||||||
222
hw/input/hid.c
222
hw/input/hid.c
@@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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,
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
@@ -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,
|
||||||
|
|||||||
@@ -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"
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
@@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
49
ui/input.c
49
ui/input.c
@@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
21
ui/sdl2.c
21
ui/sdl2.c
@@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user