Signed-off-by: Kristina Hanicova <khanicov(a)redhat.com>
---
docs/formatdomain.rst | 30 +++++++-----
docs/schemas/domaincommon.rng | 20 ++++++++
src/conf/domain_audit.c | 1 +
src/conf/domain_conf.c | 61 ++++++++++++++++++++----
src/conf/domain_conf.h | 12 +++++
src/conf/domain_validate.c | 8 ++++
src/libvirt_private.syms | 2 +
src/qemu/qemu_cgroup.c | 2 +
src/qemu/qemu_command.c | 1 +
src/qemu/qemu_domain_address.c | 1 +
src/qemu/qemu_hotplug.c | 1 +
src/qemu/qemu_validate.c | 6 +++
src/security/security_apparmor.c | 1 +
src/security/security_dac.c | 2 +
src/security/security_selinux.c | 2 +
src/security/virt-aa-helper.c | 3 +-
tests/qemuxml2argvdata/input-linux.xml | 24 ++++++++++
tests/qemuxml2xmloutdata/input-linux.xml | 1 +
18 files changed, 157 insertions(+), 21 deletions(-)
create mode 100644 tests/qemuxml2argvdata/input-linux.xml
create mode 120000 tests/qemuxml2xmloutdata/input-linux.xml
diff --git a/docs/formatdomain.rst b/docs/formatdomain.rst
index 282176c4f4..337d07dbfb 100644
--- a/docs/formatdomain.rst
+++ b/docs/formatdomain.rst
@@ -5728,26 +5728,34 @@ to provide a graphics tablet for absolute cursor movement.
<input type='passthrough' bus='virtio'>
<source evdev='/dev/input/event1'/>
</input>
+ <input type='linux'>
+ <source evdev='/dev/input/event1234' grab='all'
repeat='on'/>
+ </input>
</devices>
...
``input``
The ``input`` element has one mandatory attribute, the ``type`` whose value
- can be 'mouse', 'tablet', ( :since:`since 1.2.2` ) 'keyboard'
or (
- :since:`since 1.3.0` ) 'passthrough'. The tablet provides absolute cursor
- movement, while the mouse uses relative movement. The optional ``bus``
- attribute can be used to refine the exact device type. It takes values
"xen"
- (paravirtualized), "ps2" and "usb" or ( :since:`since 1.3.0` )
"virtio".
+ can be 'mouse', 'tablet', ( :since:`since 1.2.2` ) 'keyboard',
(
+ :since:`since 1.3.0` ) 'passthrough' or ( :since:`since 7.4.0` )
'linux'.
+ The tablet provides absolute cursor movement, while the mouse uses relative
+ movement. The optional ``bus`` attribute can be used to refine the exact
+ device type. It takes values "xen" (paravirtualized), "ps2" and
"usb" or (
+ :since:`since 1.3.0` ) "virtio".
The ``input`` element has an optional sub-element ``<address>`` which can tie
the device to a particular PCI slot, `documented above <#elementsAddress>`__. On
S390, ``address`` can be used to provide a CCW address for an input device (
-:since:`since 4.2.0` ). For type ``passthrough``, the mandatory sub-element
-``source`` must have an ``evdev`` attribute containing the absolute path to the
-event device passed through to guests. (KVM only) :since:`Since 5.2.0` , the
-``input`` element accepts a ``model`` attribute which has the values 'virtio',
-'virtio-transitional' and 'virtio-non-transitional'. See `Virtio
transitional
-devices <#elementsVirtioTransitional>`__ for more details.
+:since:`since 4.2.0` ). For types ``passthrough`` and ``linux``, the mandatory
+sub-element ``source`` must have an ``evdev`` attribute containing the absolute
+path to the event device passed through to guests. For type ``linux``,
+``sorce`` can have two optional attributes ``grab`` with value 'all' which when
+enabled grabs all input devices instead of just one and ``repeat`` with value
+'on' to enable auto-repeat events ( :since:`Since 7.4.0` ) (KVM only)
+:since:`Since 5.2.0` , the ``input`` element accepts a ``model`` attribute
+which has the values 'virtio', 'virtio-transitional' and
+'virtio-non-transitional'. See `Virtio transitional devices
+<#elementsVirtioTransitional>`__ for more details.
The subelement ``driver`` can be used to tune the virtio options of the device:
`Virtio-specific options <#elementsVirtio>`__ can also be set. ( :since:`Since
diff --git a/docs/schemas/domaincommon.rng b/docs/schemas/domaincommon.rng
index a2e5c50c1d..80b1961b5e 100644
--- a/docs/schemas/domaincommon.rng
+++ b/docs/schemas/domaincommon.rng
@@ -5443,6 +5443,26 @@
</attribute>
</element>
</group>
+ <group>
+ <attribute name="type">
+ <value>linux</value>
+ </attribute>
+ <element name="source">
+ <attribute name="evdev">
+ <ref name="absFilePath"/>
+ </attribute>
+ <optional>
+ <attribute name="grab">
+ <value>all</value>
+ </attribute>
+ </optional>
+ <optional>
+ <attribute name="repeat">
+ <value>on</value>
+ </attribute>
+ </optional>
+ </element>
+ </group>
</choice>
<optional>
<attribute name="model">
diff --git a/src/conf/domain_audit.c b/src/conf/domain_audit.c
index b1226fd5dc..ac8f59ec30 100644
--- a/src/conf/domain_audit.c
+++ b/src/conf/domain_audit.c
@@ -956,6 +956,7 @@ virDomainAuditInput(virDomainObj *vm,
break;
case VIR_DOMAIN_INPUT_TYPE_PASSTHROUGH:
+ case VIR_DOMAIN_INPUT_TYPE_LINUX:
VIR_AUDIT(VIR_AUDIT_RECORD_RESOURCE, success,
"virt=%s resrc=evdev reason=%s %s uuid=%s path=%s",
virt, reason, vmname, uuidstr, VIR_AUDIT_STR(input->source.evdev));
diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c
index 9d98f487ea..5709f5506c 100644
--- a/src/conf/domain_conf.c
+++ b/src/conf/domain_conf.c
@@ -864,6 +864,7 @@ VIR_ENUM_IMPL(virDomainInput,
"tablet",
"keyboard",
"passthrough",
+ "linux",
);
VIR_ENUM_IMPL(virDomainInputBus,
@@ -873,6 +874,7 @@ VIR_ENUM_IMPL(virDomainInputBus,
"xen",
"parallels",
"virtio",
+ "none",
);
VIR_ENUM_IMPL(virDomainInputModel,
@@ -883,6 +885,12 @@ VIR_ENUM_IMPL(virDomainInputModel,
"virtio-non-transitional",
);
+VIR_ENUM_IMPL(virDomainInputSourceGrab,
+ VIR_DOMAIN_INPUT_SOURCE_GRAB_LAST,
+ "default",
+ "all",
+);
+
VIR_ENUM_IMPL(virDomainGraphics,
VIR_DOMAIN_GRAPHICS_TYPE_LAST,
"sdl",
@@ -1898,6 +1906,7 @@ const char *virDomainInputDefGetPath(virDomainInputDef *input)
return NULL;
case VIR_DOMAIN_INPUT_TYPE_PASSTHROUGH:
+ case VIR_DOMAIN_INPUT_TYPE_LINUX:
return input->source.evdev;
}
return NULL;
@@ -12136,10 +12145,10 @@ virDomainInputDefParseXML(virDomainXMLOption *xmlopt,
{
VIR_XPATH_NODE_AUTORESTORE(ctxt)
virDomainInputDef *def;
- g_autofree char *evdev = NULL;
g_autofree char *type = NULL;
g_autofree char *bus = NULL;
g_autofree char *model = NULL;
+ xmlNodePtr source = NULL;
def = g_new0(virDomainInputDef, 1);
@@ -12241,6 +12250,8 @@ virDomainInputDefParseXML(virDomainXMLOption *xmlopt,
} else if (ARCH_IS_S390(dom->os.arch) ||
def->type == VIR_DOMAIN_INPUT_TYPE_PASSTHROUGH) {
def->bus = VIR_DOMAIN_INPUT_BUS_VIRTIO;
+ } else if (def->type == VIR_DOMAIN_INPUT_TYPE_LINUX) {
+ def->bus = VIR_DOMAIN_INPUT_BUS_NONE;
} else {
def->bus = VIR_DOMAIN_INPUT_BUS_USB;
}
@@ -12265,12 +12276,31 @@ virDomainInputDefParseXML(virDomainXMLOption *xmlopt,
goto error;
}
- if ((evdev = virXPathString("string(./source/@evdev)", ctxt)))
- def->source.evdev = virFileSanitizePath(evdev);
- if (def->type == VIR_DOMAIN_INPUT_TYPE_PASSTHROUGH &&
!def->source.evdev) {
- virReportError(VIR_ERR_XML_ERROR, "%s",
- _("Missing evdev path for input device passthrough"));
- goto error;
+ if ((source = virXPathNode("./source", ctxt))) {
+ g_autofree char *evdev = virXMLPropString(source, "evdev");
+
+ if (evdev)
+ def->source.evdev = virFileSanitizePath(evdev);
+
+ if (def->type == VIR_DOMAIN_INPUT_TYPE_PASSTHROUGH ||
+ def->type == VIR_DOMAIN_INPUT_TYPE_LINUX) {
+ if (!def->source.evdev) {
+ virReportError(VIR_ERR_XML_ERROR, "%s",
+ _("Missing evdev path for input device"));
+ goto error;
+ }
+ }
+
+ if (def->type == VIR_DOMAIN_INPUT_TYPE_LINUX) {
+ if (virXMLPropEnum(source, "grab",
+ virDomainInputSourceGrabTypeFromString,
+ VIR_XML_PROP_NONZERO, &def->source.grab) < 0)
+ goto error;
+
+ if (virXMLPropTristateSwitch(source, "repeat",
+ VIR_XML_PROP_NONE, &def->source.repeat)
< 0)
+ goto error;
+ }
}
if (virDomainVirtioOptionsParseXML(virXPathNode("./driver", ctxt),
@@ -26906,9 +26936,12 @@ virDomainInputDefFormat(virBuffer *buf,
{
const char *type = virDomainInputTypeToString(def->type);
const char *bus = virDomainInputBusTypeToString(def->bus);
+ const char *grab = virDomainInputSourceGrabTypeToString(def->source.grab);
+ const char *repeat = virTristateSwitchTypeToString(def->source.repeat);
g_auto(virBuffer) attrBuf = VIR_BUFFER_INITIALIZER;
g_auto(virBuffer) childBuf = VIR_BUFFER_INIT_CHILD(buf);
g_auto(virBuffer) driverAttrBuf = VIR_BUFFER_INITIALIZER;
+ g_auto(virBuffer) sourceAttrBuf = VIR_BUFFER_INITIALIZER;
/* don't format keyboard into migratable XML for backward compatibility */
if (flags & VIR_DOMAIN_DEF_FORMAT_MIGRATABLE &&
@@ -26928,7 +26961,9 @@ virDomainInputDefFormat(virBuffer *buf,
return -1;
}
- virBufferAsprintf(&attrBuf, " type='%s' bus='%s'",
type, bus);
+ virBufferAsprintf(&attrBuf, " type='%s'", type);
+ if (def->bus != VIR_DOMAIN_INPUT_BUS_NONE)
+ virBufferAsprintf(&attrBuf, " bus='%s'", bus);
if (def->model) {
const char *model = virDomainInputModelTypeToString(def->model);
@@ -26946,7 +26981,15 @@ virDomainInputDefFormat(virBuffer *buf,
virXMLFormatElement(&childBuf, "driver", &driverAttrBuf, NULL);
- virBufferEscapeString(&childBuf, "<source
evdev='%s'/>\n", def->source.evdev);
+ virBufferEscapeString(&sourceAttrBuf, " evdev='%s'",
def->source.evdev);
+
+ if (def->source.grab)
+ virBufferAsprintf(&sourceAttrBuf, " grab='%s'", grab);
+ if (def->source.repeat)
+ virBufferAsprintf(&sourceAttrBuf, " repeat='%s'", repeat);
+
+ virXMLFormatElement(&childBuf, "source", &sourceAttrBuf, NULL);
+
virDomainDeviceInfoFormat(&childBuf, &def->info, flags);
virXMLFormatElement(buf, "input", &attrBuf, &childBuf);
diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h
index 85c318d027..5107f0f3a1 100644
--- a/src/conf/domain_conf.h
+++ b/src/conf/domain_conf.h
@@ -1388,6 +1388,7 @@ typedef enum {
VIR_DOMAIN_INPUT_TYPE_TABLET,
VIR_DOMAIN_INPUT_TYPE_KBD,
VIR_DOMAIN_INPUT_TYPE_PASSTHROUGH,
+ VIR_DOMAIN_INPUT_TYPE_LINUX,
VIR_DOMAIN_INPUT_TYPE_LAST
} virDomainInputType;
@@ -1398,6 +1399,7 @@ typedef enum {
VIR_DOMAIN_INPUT_BUS_XEN,
VIR_DOMAIN_INPUT_BUS_PARALLELS, /* pseudo device for VNC in containers */
VIR_DOMAIN_INPUT_BUS_VIRTIO,
+ VIR_DOMAIN_INPUT_BUS_NONE,
VIR_DOMAIN_INPUT_BUS_LAST
} virDomainInputBus;
@@ -1411,12 +1413,21 @@ typedef enum {
VIR_DOMAIN_INPUT_MODEL_LAST
} virDomainInputModel;
+typedef enum {
+ VIR_DOMAIN_INPUT_SOURCE_GRAB_DEFAULT,
+ VIR_DOMAIN_INPUT_SOURCE_GRAB_ALL,
+
+ VIR_DOMAIN_INPUT_SOURCE_GRAB_LAST
+} virDomainInputSourceGrab;
+
struct _virDomainInputDef {
int type;
int bus;
int model; /* virDomainInputModel */
struct {
char *evdev;
+ virDomainInputSourceGrab grab;
+ virTristateSwitch repeat;
} source;
virDomainDeviceInfo info;
virDomainVirtioOptions *virtio;
@@ -3843,6 +3854,7 @@ VIR_ENUM_DECL(virDomainRedirdevBus);
VIR_ENUM_DECL(virDomainInput);
VIR_ENUM_DECL(virDomainInputBus);
VIR_ENUM_DECL(virDomainInputModel);
+VIR_ENUM_DECL(virDomainInputSourceGrab);
VIR_ENUM_DECL(virDomainGraphics);
VIR_ENUM_DECL(virDomainGraphicsListen);
VIR_ENUM_DECL(virDomainGraphicsAuthConnected);
diff --git a/src/conf/domain_validate.c b/src/conf/domain_validate.c
index 686b9e8d16..05286e91d6 100644
--- a/src/conf/domain_validate.c
+++ b/src/conf/domain_validate.c
@@ -1961,6 +1961,14 @@ virDomainInputDefValidate(const virDomainInputDef *input)
}
break;
+ case VIR_DOMAIN_INPUT_TYPE_LINUX:
+ if (input->bus != VIR_DOMAIN_INPUT_BUS_NONE) {
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+ _("input linux doesn't support bus
element"));
+ return -1;
+ }
+ break;
+
case VIR_DOMAIN_INPUT_TYPE_LAST:
default:
virReportEnumRangeError(virDomainInputType, input->type);
diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms
index 9f761c2c00..044f95494e 100644
--- a/src/libvirt_private.syms
+++ b/src/libvirt_private.syms
@@ -475,6 +475,8 @@ virDomainInputBusTypeToString;
virDomainInputDefFind;
virDomainInputDefFree;
virDomainInputDefGetPath;
+virDomainInputSourceGrabTypeFromString;
+virDomainInputSourceGrabTypeToString;
virDomainInputTypeToString;
virDomainIOMMUModelTypeFromString;
virDomainIOMMUModelTypeToString;
diff --git a/src/qemu/qemu_cgroup.c b/src/qemu/qemu_cgroup.c
index 0e8835fb86..7845d74376 100644
--- a/src/qemu/qemu_cgroup.c
+++ b/src/qemu/qemu_cgroup.c
@@ -362,6 +362,7 @@ qemuSetupInputCgroup(virDomainObj *vm,
switch (dev->type) {
case VIR_DOMAIN_INPUT_TYPE_PASSTHROUGH:
+ case VIR_DOMAIN_INPUT_TYPE_LINUX:
VIR_DEBUG("Process path '%s' for input device",
dev->source.evdev);
ret = virCgroupAllowDevicePath(priv->cgroup, dev->source.evdev,
VIR_CGROUP_DEVICE_RW, false);
@@ -385,6 +386,7 @@ qemuTeardownInputCgroup(virDomainObj *vm,
switch (dev->type) {
case VIR_DOMAIN_INPUT_TYPE_PASSTHROUGH:
+ case VIR_DOMAIN_INPUT_TYPE_LINUX:
VIR_DEBUG("Process path '%s' for input device",
dev->source.evdev);
ret = virCgroupDenyDevicePath(priv->cgroup, dev->source.evdev,
VIR_CGROUP_DEVICE_RWM, false);
diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c
index d7f1c715b6..1ca330b840 100644
--- a/src/qemu/qemu_command.c
+++ b/src/qemu/qemu_command.c
@@ -4018,6 +4018,7 @@ qemuBuildVirtioInputDevStr(const virDomainDef *def,
return NULL;
}
break;
+ case VIR_DOMAIN_INPUT_TYPE_LINUX:
case VIR_DOMAIN_INPUT_TYPE_LAST:
default:
virReportEnumRangeError(virDomainInputType, dev->type);
diff --git a/src/qemu/qemu_domain_address.c b/src/qemu/qemu_domain_address.c
index e66efb3d1f..5f76120943 100644
--- a/src/qemu/qemu_domain_address.c
+++ b/src/qemu/qemu_domain_address.c
@@ -973,6 +973,7 @@ qemuDomainDeviceCalculatePCIConnectFlags(virDomainDeviceDef *dev,
case VIR_DOMAIN_INPUT_BUS_USB:
case VIR_DOMAIN_INPUT_BUS_XEN:
case VIR_DOMAIN_INPUT_BUS_PARALLELS:
+ case VIR_DOMAIN_INPUT_BUS_NONE:
case VIR_DOMAIN_INPUT_BUS_LAST:
return 0;
}
diff --git a/src/qemu/qemu_hotplug.c b/src/qemu/qemu_hotplug.c
index 4344edc75b..860a9deb40 100644
--- a/src/qemu/qemu_hotplug.c
+++ b/src/qemu/qemu_hotplug.c
@@ -5805,6 +5805,7 @@ qemuDomainDetachPrepInput(virDomainObj *vm,
case VIR_DOMAIN_INPUT_BUS_LAST:
case VIR_DOMAIN_INPUT_BUS_USB:
case VIR_DOMAIN_INPUT_BUS_VIRTIO:
+ case VIR_DOMAIN_INPUT_BUS_NONE:
break;
}
diff --git a/src/qemu/qemu_validate.c b/src/qemu/qemu_validate.c
index 774426bceb..5229dff1a7 100644
--- a/src/qemu/qemu_validate.c
+++ b/src/qemu/qemu_validate.c
@@ -4605,6 +4605,7 @@ qemuValidateDomainDeviceDefInput(const virDomainInputDef *input,
case VIR_DOMAIN_INPUT_TYPE_MOUSE:
case VIR_DOMAIN_INPUT_TYPE_TABLET:
case VIR_DOMAIN_INPUT_TYPE_KBD:
+ case VIR_DOMAIN_INPUT_TYPE_LINUX:
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
_("virtio (non-)transitional models are not "
"supported for input type=%s"),
@@ -4650,6 +4651,11 @@ qemuValidateDomainDeviceDefInput(const virDomainInputDef *input,
cap = QEMU_CAPS_VIRTIO_INPUT_HOST;
ccwCap = QEMU_CAPS_LAST;
break;
+ case VIR_DOMAIN_INPUT_TYPE_LINUX:
+ baseName = "input-linux";
+ cap = QEMU_CAPS_INPUT_LINUX;
+ ccwCap = QEMU_CAPS_LAST;
+ break;
case VIR_DOMAIN_INPUT_TYPE_LAST:
default:
virReportEnumRangeError(virDomainInputType,
diff --git a/src/security/security_apparmor.c b/src/security/security_apparmor.c
index a2a8435fe4..80176837ce 100644
--- a/src/security/security_apparmor.c
+++ b/src/security/security_apparmor.c
@@ -720,6 +720,7 @@ AppArmorSetInputLabel(virSecurityManager *mgr,
switch ((virDomainInputType)input->type) {
case VIR_DOMAIN_INPUT_TYPE_PASSTHROUGH:
+ case VIR_DOMAIN_INPUT_TYPE_LINUX:
if (input->source.evdev == NULL) {
virReportError(VIR_ERR_INTERNAL_ERROR,
_("%s: passthrough input device has no source"),
diff --git a/src/security/security_dac.c b/src/security/security_dac.c
index e973964735..8e82c7f78d 100644
--- a/src/security/security_dac.c
+++ b/src/security/security_dac.c
@@ -1815,6 +1815,7 @@ virSecurityDACSetInputLabel(virSecurityManager *mgr,
switch ((virDomainInputType)input->type) {
case VIR_DOMAIN_INPUT_TYPE_PASSTHROUGH:
+ case VIR_DOMAIN_INPUT_TYPE_LINUX:
if (virSecurityDACGetIds(seclabel, priv, &user, &group, NULL, NULL) <
0)
return -1;
@@ -1843,6 +1844,7 @@ virSecurityDACRestoreInputLabel(virSecurityManager *mgr,
switch ((virDomainInputType)input->type) {
case VIR_DOMAIN_INPUT_TYPE_PASSTHROUGH:
+ case VIR_DOMAIN_INPUT_TYPE_LINUX:
ret = virSecurityDACRestoreFileLabel(mgr, input->source.evdev);
break;
diff --git a/src/security/security_selinux.c b/src/security/security_selinux.c
index 29628d8953..42de0d5a98 100644
--- a/src/security/security_selinux.c
+++ b/src/security/security_selinux.c
@@ -1513,6 +1513,7 @@ virSecuritySELinuxSetInputLabel(virSecurityManager *mgr,
switch ((virDomainInputType)input->type) {
case VIR_DOMAIN_INPUT_TYPE_PASSTHROUGH:
+ case VIR_DOMAIN_INPUT_TYPE_LINUX:
if (virSecuritySELinuxSetFilecon(mgr, input->source.evdev,
seclabel->imagelabel, true) < 0)
return -1;
@@ -1543,6 +1544,7 @@ virSecuritySELinuxRestoreInputLabel(virSecurityManager *mgr,
switch ((virDomainInputType)input->type) {
case VIR_DOMAIN_INPUT_TYPE_PASSTHROUGH:
+ case VIR_DOMAIN_INPUT_TYPE_LINUX:
rc = virSecuritySELinuxRestoreFileLabel(mgr, input->source.evdev, true);
break;
diff --git a/src/security/virt-aa-helper.c b/src/security/virt-aa-helper.c
index 2331cc6648..aa1e2cdacc 100644
--- a/src/security/virt-aa-helper.c
+++ b/src/security/virt-aa-helper.c
@@ -1149,7 +1149,8 @@ get_files(vahControl * ctl)
for (i = 0; i < ctl->def->ninputs; i++) {
if (ctl->def->inputs[i] &&
- ctl->def->inputs[i]->type == VIR_DOMAIN_INPUT_TYPE_PASSTHROUGH)
{
+ ctl->def->inputs[i]->type == VIR_DOMAIN_INPUT_TYPE_PASSTHROUGH
||
+ ctl->def->inputs[i]->type == VIR_DOMAIN_INPUT_TYPE_LINUX) {
if (vah_add_file(&buf, ctl->def->inputs[i]->source.evdev,
"rw") != 0)
goto cleanup;
}
diff --git a/tests/qemuxml2argvdata/input-linux.xml
b/tests/qemuxml2argvdata/input-linux.xml
new file mode 100644
index 0000000000..053557c19e
--- /dev/null
+++ b/tests/qemuxml2argvdata/input-linux.xml
@@ -0,0 +1,24 @@
+<domain type='qemu'>
+ <name>QEMUGuest1</name>
+ <uuid>c7a5fdbd-edaf-9455-926a-d65c16db1809</uuid>
+ <memory unit='KiB'>219100</memory>
+ <currentMemory unit='KiB'>219100</currentMemory>
+ <vcpu placement='static'>1</vcpu>
+ <os>
+ <type arch='i686' machine='pc'>hvm</type>
+ <boot dev='hd'/>
+ </os>
+ <clock offset='utc'/>
+ <on_poweroff>destroy</on_poweroff>
+ <on_reboot>restart</on_reboot>
+ <on_crash>destroy</on_crash>
+ <devices>
+ <emulator>/usr/bin/qemu-system-i386</emulator>
+ <controller type='pci' index='0' model='pci-root'/>
+ <input type='linux'>
+ <source evdev='/dev/input/event1234' grab='all'
repeat='on'/>
+ </input>
+ <input type='mouse' bus='ps2'/>
+ <input type='keyboard' bus='ps2'/>
+ </devices>
+</domain>
diff --git a/tests/qemuxml2xmloutdata/input-linux.xml
b/tests/qemuxml2xmloutdata/input-linux.xml
new file mode 120000
index 0000000000..84e1e79b51
--- /dev/null
+++ b/tests/qemuxml2xmloutdata/input-linux.xml
@@ -0,0 +1 @@
+../qemuxml2argvdata/input-linux.xml
\ No newline at end of file
--
2.30.2