usb: bug fix collection, doc update.

-----BEGIN PGP SIGNATURE-----
 Version: GnuPG v2.0.22 (GNU/Linux)
 
 iQIcBAABAgAGBQJbH6QBAAoJEEy22O7T6HE4ZwMP/RHEknxR+tGKYfUxtVP24+ta
 tKMVuewqnDuIjUQsYj/tMvtGEvPd827Cy1X+ocqNq1Gk9aJez+DWWoDlrSXlLyiG
 r4EBMmOasFdmp1D9iQEDUF0pbnbXQv7kqhnM7XbyO+rjNe1rX7HElmRXtcjBcY2I
 QCIpekUBVGzFO97pVzB66gwYpJvmQu2YS2783NaujeS9VEEUFy6RFCFhfNwxhA4W
 C264zFVk68oK1fL+71Y3Kq0WKmetBwfW2ozcBAnqLB5z0hGd9bHJocaLwqgaaQWC
 uaGUJS70Q7iWZ8NwOYvrpK/2ZetjPAeU6ERXeR7tK6yfkjV9UmpPXQ0aqu1OSgEr
 VjuMPEDK0tL8pgcuhhxkJOD6S/HNyCe8y7WLeHKpd21Mv+R2yB1zs2xsWrdMqreZ
 2YXUpgvIaZJBycO8vzmzWwiSNInOGO/3Vu1kpUP4T/rdmFZ1q5f8tGgwMlq/JsU4
 Ce/p0BCcCXvcG+2x5uouffIuTur4DUPn93BCUmjy/TuyggtXVNoQHEVGrMDjiyO/
 9RFVUgJl32mTbIqfVaWkweTch/yXm4XVrlbcTW3VhCCVWyA9O0m+MwyjIoNeXn8L
 yPLF+3ndYgMoTJBFZ20HWEGhZ2+I54fhn/iRW6Nq7qtZ2rOP//K2CqyEp/CuQWis
 vxb796sHEPPUeTCoCiVY
 =sxQ0
 -----END PGP SIGNATURE-----

Merge remote-tracking branch 'remotes/kraxel/tags/usb-20180612-pull-request' into staging

usb: bug fix collection, doc update.

# gpg: Signature made Tue 12 Jun 2018 11:44:17 BST
# gpg:                using RSA key 4CB6D8EED3E87138
# gpg: Good signature from "Gerd Hoffmann (work) <kraxel@redhat.com>"
# gpg:                 aka "Gerd Hoffmann <gerd@kraxel.org>"
# gpg:                 aka "Gerd Hoffmann (private) <kraxel@gmail.com>"
# Primary key fingerprint: A032 8CFF B93A 17A7 9901  FE7D 4CB6 D8EE D3E8 7138

* remotes/kraxel/tags/usb-20180612-pull-request:
  usb-mtp: Return error on suspicious TYPE_DATA packet from initiator
  usb-hcd-xhci-test: add a test for ccid hotplug
  usb-ccid: fix bus leak
  object: fix OBJ_PROP_LINK_UNREF_ON_RELEASE ambivalence
  bus: do not unref the added child bus on realize
  usb/dev-mtp: Fix use of uninitialized values
  usb: correctly handle Zero Length Packets
  usb: update docs

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
Peter Maydell 2018-06-12 15:34:34 +01:00
commit 2ab09bf2f9
23 changed files with 109 additions and 71 deletions

View File

@ -1,16 +1,42 @@
USB 2.0 Quick Start USB Quick Start
=================== ===============
The QEMU EHCI Adapter can be used with and without companion XHCI controller support
controllers. See below for the companion controller mode. -----------------------
When not running in companion controller mode there are two completely QEMU has XHCI host adapter support. The XHCI hardware design is much
separate USB busses: One USB 1.1 bus driven by the UHCI controller and more virtualization-friendly when compared to EHCI and UHCI, thus XHCI
one USB 2.0 bus driven by the EHCI controller. Devices must be emulation uses less resources (especially cpu). So if your guest
attached to the correct controller manually. supports XHCI (which should be the case for any operating system
released around 2010 or later) we recommend using it:
The '-usb' switch will make qemu create the UHCI controller as part of qemu -device qemu-xhci
XHCI supports USB 1.1, USB 2.0 and USB 3.0 devices, so this is the
only controller you need. With only a single USB controller (and
therefore only a single USB bus) present in the system there is no
need to use the bus= parameter when adding USB devices.
EHCI controller support
-----------------------
The QEMU EHCI Adapter supports USB 2.0 devices. It can be used either
standalone or with companion controllers (UHCI, OHCI) for USB 1.1
devices. The companion controller setup is more convenient to use
because it provides a single USB bus supporting both USB 2.0 and USB
1.1 devices. See next section for details.
When running EHCI in standalone mode you can add UHCI or OHCI
controllers for USB 1.1 devices too. Each controller creates its own
bus though, so there are two completely separate USB buses: One USB
1.1 bus driven by the UHCI controller and one USB 2.0 bus driven by
the EHCI controller. Devices must be attached to the correct
controller manually.
The easiest way to add a UHCI controller to a 'pc' machine is the
'-usb' switch. QEMU will create the UHCI controller as function of
the PIIX3 chipset. The USB 1.1 bus will carry the name "usb-bus.0". the PIIX3 chipset. The USB 1.1 bus will carry the name "usb-bus.0".
You can use the standard -device switch to add a EHCI controller to You can use the standard -device switch to add a EHCI controller to
@ -19,9 +45,8 @@ the controller so the USB 2.0 bus gets a individual name, for example
'-device usb-ehci,id=ehci". This will give you a USB 2.0 bus named '-device usb-ehci,id=ehci". This will give you a USB 2.0 bus named
"ehci.0". "ehci.0".
I strongly recommend to also use -device to attach usb devices because When adding USB devices using the -device switch you can specify the
you can specify the bus they should be attached to this way. Here is bus they should be attached to. Here is a complete example:
a complete example:
qemu -M pc ${otheroptions} \ qemu -M pc ${otheroptions} \
-drive if=none,id=usbstick,file=/path/to/image \ -drive if=none,id=usbstick,file=/path/to/image \
@ -30,58 +55,44 @@ a complete example:
-device usb-tablet,bus=usb-bus.0 \ -device usb-tablet,bus=usb-bus.0 \
-device usb-storage,bus=ehci.0,drive=usbstick -device usb-storage,bus=ehci.0,drive=usbstick
This attaches a usb tablet to the UHCI adapter and a usb mass storage This attaches a USB tablet to the UHCI adapter and a USB mass storage
device to the EHCI adapter. device to the EHCI adapter.
Companion controller support Companion controller support
---------------------------- ----------------------------
Companion controller support has been added recently. The operational The UHCI and OHCI controllers can attach to a USB bus created by EHCI
model described above with two completely separate busses still works as companion controllers. This is done by specifying the masterbus
fine. Additionally the UHCI and OHCI controllers got the ability to and firstport properties. masterbus specifies the bus name the
attach to a usb bus created by EHCI as companion controllers. This is controller should attach to. firstport specifies the first port the
done by specifying the masterbus and firstport properties. masterbus controller should attach to, which is needed as usually one EHCI
specifies the bus name the controller should attach to. firstport controller with six ports has three UHCI companion controllers with
specifies the first port the controller should attach to, which is two ports each.
needed as usually one ehci controller with six ports has three uhci
companion controllers with two ports each.
There is a config file in docs which will do all this for you, just There is a config file in docs which will do all this for
try ... you, just try ...
qemu -readconfig docs/config/ich9-ehci-uhci.cfg qemu -readconfig docs/config/ich9-ehci-uhci.cfg
... then use "bus=ehci.0" to assign your usb devices to that bus. ... then use "bus=ehci.0" to assign your USB devices to that bus.
Using the '-usb' switch for 'q35' machines will create a similar
xhci controller support USB controller configuration.
-----------------------
There is also xhci host controller support available. It got a lot
less testing than ehci and there are a bunch of known limitations, so
ehci may work better for you. On the other hand the xhci hardware
design is much more virtualization-friendly, thus xhci emulation uses
less resources (especially cpu). If you want to give xhci a try
use this to add the host controller ...
qemu -device nec-usb-xhci,id=xhci
... then use "bus=xhci.0" when assigning usb devices.
More USB tips & tricks More USB tips & tricks
====================== ======================
Recently the usb pass through driver (also known as usb-host) and the Recently the USB pass through driver (also known as usb-host) and the
qemu usb subsystem gained a few capabilities which are available only QEMU USB subsystem gained a few capabilities which are available only
via qdev properties, i,e. when using '-device'. via qdev properties, i,e. when using '-device'.
physical port addressing physical port addressing
------------------------ ------------------------
First you can (for all usb devices) specify the physical port where First you can (for all USB devices) specify the physical port where
the device will show up in the guest. This can be done using the the device will show up in the guest. This can be done using the
"port" property. UHCI has two root ports (1,2). EHCI has four root "port" property. UHCI has two root ports (1,2). EHCI has four root
ports (1-4), the emulated (1.1) USB hub has eight ports. ports (1-4), the emulated (1.1) USB hub has eight ports.
@ -94,7 +105,7 @@ Plugging a hub into UHCI port 2 works like this:
-device usb-hub,bus=usb-bus.0,port=2 -device usb-hub,bus=usb-bus.0,port=2
Plugging a virtual usb stick into port 4 of the hub just plugged works Plugging a virtual USB stick into port 4 of the hub just plugged works
this way: this way:
-device usb-storage,bus=usb-bus.0,port=2.4,drive=... -device usb-storage,bus=usb-bus.0,port=2.4,drive=...
@ -143,7 +154,7 @@ practice only a few combinations are useful:
Note that USB 1.1 devices are handled by UHCI/OHCI and USB 2.0 by Note that USB 1.1 devices are handled by UHCI/OHCI and USB 2.0 by
EHCI. That means a device plugged into the very same physical port EHCI. That means a device plugged into the very same physical port
may show up on different busses depending on the speed. The port I'm may show up on different buses depending on the speed. The port I'm
using for testing is bus 1 + port 1 for 2.0 devices and bus 3 + port 1 using for testing is bus 1 + port 1 for 2.0 devices and bus 3 + port 1
for 1.1 devices. Passing through any device plugged into that port for 1.1 devices. Passing through any device plugged into that port
and also assign them to the correct bus can be done this way: and also assign them to the correct bus can be done this way:

View File

@ -102,7 +102,6 @@ static void qbus_realize(BusState *bus, DeviceState *parent, const char *name)
QLIST_INSERT_HEAD(&bus->parent->child_bus, bus, sibling); QLIST_INSERT_HEAD(&bus->parent->child_bus, bus, sibling);
bus->parent->num_child_bus++; bus->parent->num_child_bus++;
object_property_add_child(OBJECT(bus->parent), bus->name, OBJECT(bus), NULL); object_property_add_child(OBJECT(bus->parent), bus->name, OBJECT(bus), NULL);
object_unref(OBJECT(bus));
} else if (bus != sysbus_get_default()) { } else if (bus != sysbus_get_default()) {
/* TODO: once all bus devices are qdevified, /* TODO: once all bus devices are qdevified,
only reset handler for main_system_bus should be registered here. */ only reset handler for main_system_bus should be registered here. */

View File

@ -1308,7 +1308,7 @@ static void create_link_property(Object *obj, Property *prop, Error **errp)
object_property_add_link(obj, prop->name, prop->link_type, object_property_add_link(obj, prop->name, prop->link_type,
child, child,
qdev_prop_allow_set_link_before_realize, qdev_prop_allow_set_link_before_realize,
OBJ_PROP_LINK_UNREF_ON_RELEASE, OBJ_PROP_LINK_STRONG,
errp); errp);
} }

View File

@ -409,7 +409,7 @@ void qdev_init_gpio_out_named(DeviceState *dev, qemu_irq *pins,
object_property_add_link(OBJECT(dev), propname, TYPE_IRQ, object_property_add_link(OBJECT(dev), propname, TYPE_IRQ,
(Object **)&pins[i], (Object **)&pins[i],
object_property_allow_set_link, object_property_allow_set_link,
OBJ_PROP_LINK_UNREF_ON_RELEASE, OBJ_PROP_LINK_STRONG,
&error_abort); &error_abort);
g_free(propname); g_free(propname);
} }

View File

@ -1223,7 +1223,7 @@ static void xlnx_dp_init(Object *obj)
object_property_add_link(obj, "dpdma", TYPE_XLNX_DPDMA, object_property_add_link(obj, "dpdma", TYPE_XLNX_DPDMA,
(Object **) &s->dpdma, (Object **) &s->dpdma,
xlnx_dp_set_dpdma, xlnx_dp_set_dpdma,
OBJ_PROP_LINK_UNREF_ON_RELEASE, OBJ_PROP_LINK_STRONG,
&error_abort); &error_abort);
/* /*

View File

@ -525,12 +525,12 @@ static void xilinx_axidma_realize(DeviceState *dev, Error **errp)
object_property_add_link(OBJECT(ds), "dma", TYPE_XILINX_AXI_DMA, object_property_add_link(OBJECT(ds), "dma", TYPE_XILINX_AXI_DMA,
(Object **)&ds->dma, (Object **)&ds->dma,
object_property_allow_set_link, object_property_allow_set_link,
OBJ_PROP_LINK_UNREF_ON_RELEASE, OBJ_PROP_LINK_STRONG,
&local_err); &local_err);
object_property_add_link(OBJECT(cs), "dma", TYPE_XILINX_AXI_DMA, object_property_add_link(OBJECT(cs), "dma", TYPE_XILINX_AXI_DMA,
(Object **)&cs->dma, (Object **)&cs->dma,
object_property_allow_set_link, object_property_allow_set_link,
OBJ_PROP_LINK_UNREF_ON_RELEASE, OBJ_PROP_LINK_STRONG,
&local_err); &local_err);
if (local_err) { if (local_err) {
goto xilinx_axidma_realize_fail; goto xilinx_axidma_realize_fail;

View File

@ -787,7 +787,7 @@ static void zdma_init(Object *obj)
object_property_add_link(obj, "dma", TYPE_MEMORY_REGION, object_property_add_link(obj, "dma", TYPE_MEMORY_REGION,
(Object **)&s->dma_mr, (Object **)&s->dma_mr,
qdev_prop_allow_set_link_before_realize, qdev_prop_allow_set_link_before_realize,
OBJ_PROP_LINK_UNREF_ON_RELEASE, OBJ_PROP_LINK_STRONG,
&error_abort); &error_abort);
} }

View File

@ -483,7 +483,7 @@ void pc_cmos_init(PCMachineState *pcms,
TYPE_ISA_DEVICE, TYPE_ISA_DEVICE,
(Object **)&pcms->rtc, (Object **)&pcms->rtc,
object_property_allow_set_link, object_property_allow_set_link,
OBJ_PROP_LINK_UNREF_ON_RELEASE, &error_abort); OBJ_PROP_LINK_STRONG, &error_abort);
object_property_set_link(OBJECT(pcms), OBJECT(s), object_property_set_link(OBJECT(pcms), OBJECT(s),
"rtc_state", &error_abort); "rtc_state", &error_abort);

View File

@ -289,7 +289,7 @@ static void pc_init1(MachineState *machine,
TYPE_HOTPLUG_HANDLER, TYPE_HOTPLUG_HANDLER,
(Object **)&pcms->acpi_dev, (Object **)&pcms->acpi_dev,
object_property_allow_set_link, object_property_allow_set_link,
OBJ_PROP_LINK_UNREF_ON_RELEASE, &error_abort); OBJ_PROP_LINK_STRONG, &error_abort);
object_property_set_link(OBJECT(machine), OBJECT(piix4_pm), object_property_set_link(OBJECT(machine), OBJECT(piix4_pm),
PC_MACHINE_ACPI_DEVICE_PROP, &error_abort); PC_MACHINE_ACPI_DEVICE_PROP, &error_abort);
} }

View File

@ -194,7 +194,7 @@ static void pc_q35_init(MachineState *machine)
TYPE_HOTPLUG_HANDLER, TYPE_HOTPLUG_HANDLER,
(Object **)&pcms->acpi_dev, (Object **)&pcms->acpi_dev,
object_property_allow_set_link, object_property_allow_set_link,
OBJ_PROP_LINK_UNREF_ON_RELEASE, &error_abort); OBJ_PROP_LINK_STRONG, &error_abort);
object_property_set_link(OBJECT(machine), OBJECT(lpc), object_property_set_link(OBJECT(machine), OBJECT(lpc),
PC_MACHINE_ACPI_DEVICE_PROP, &error_abort); PC_MACHINE_ACPI_DEVICE_PROP, &error_abort);

View File

@ -104,7 +104,7 @@ void ipmi_bmc_find_and_link(Object *obj, Object **bmc)
{ {
object_property_add_link(obj, "bmc", TYPE_IPMI_BMC, bmc, object_property_add_link(obj, "bmc", TYPE_IPMI_BMC, bmc,
isa_ipmi_bmc_check, isa_ipmi_bmc_check,
OBJ_PROP_LINK_UNREF_ON_RELEASE, OBJ_PROP_LINK_STRONG,
&error_abort); &error_abort);
} }

View File

@ -951,12 +951,12 @@ static void xilinx_enet_realize(DeviceState *dev, Error **errp)
object_property_add_link(OBJECT(ds), "enet", "xlnx.axi-ethernet", object_property_add_link(OBJECT(ds), "enet", "xlnx.axi-ethernet",
(Object **) &ds->enet, (Object **) &ds->enet,
object_property_allow_set_link, object_property_allow_set_link,
OBJ_PROP_LINK_UNREF_ON_RELEASE, OBJ_PROP_LINK_STRONG,
&local_err); &local_err);
object_property_add_link(OBJECT(cs), "enet", "xlnx.axi-ethernet", object_property_add_link(OBJECT(cs), "enet", "xlnx.axi-ethernet",
(Object **) &cs->enet, (Object **) &cs->enet,
object_property_allow_set_link, object_property_allow_set_link,
OBJ_PROP_LINK_UNREF_ON_RELEASE, OBJ_PROP_LINK_STRONG,
&local_err); &local_err);
if (local_err) { if (local_err) {
goto xilinx_enet_realize_fail; goto xilinx_enet_realize_fail;

View File

@ -1346,7 +1346,7 @@ static void xlnx_zynqmp_qspips_init(Object *obj)
object_property_add_link(obj, "stream-connected-dma", TYPE_STREAM_SLAVE, object_property_add_link(obj, "stream-connected-dma", TYPE_STREAM_SLAVE,
(Object **)&rq->dma, (Object **)&rq->dma,
object_property_allow_set_link, object_property_allow_set_link,
OBJ_PROP_LINK_UNREF_ON_RELEASE, OBJ_PROP_LINK_STRONG,
NULL); NULL);
} }

View File

@ -1017,12 +1017,16 @@ static MTPData *usb_mtp_get_object(MTPState *s, MTPControl *c,
static MTPData *usb_mtp_get_partial_object(MTPState *s, MTPControl *c, static MTPData *usb_mtp_get_partial_object(MTPState *s, MTPControl *c,
MTPObject *o) MTPObject *o)
{ {
MTPData *d = usb_mtp_data_alloc(c); MTPData *d;
off_t offset; off_t offset;
if (c->argc <= 2) {
return NULL;
}
trace_usb_mtp_op_get_partial_object(s->dev.addr, o->handle, o->path, trace_usb_mtp_op_get_partial_object(s->dev.addr, o->handle, o->path,
c->argv[1], c->argv[2]); c->argv[1], c->argv[2]);
d = usb_mtp_data_alloc(c);
d->fd = open(o->path, O_RDONLY); d->fd = open(o->path, O_RDONLY);
if (d->fd == -1) { if (d->fd == -1) {
usb_mtp_data_free(d); usb_mtp_data_free(d);
@ -1696,6 +1700,11 @@ static void usb_mtp_get_data(MTPState *s, mtp_container *container,
uint64_t dlen; uint64_t dlen;
uint32_t data_len = p->iov.size; uint32_t data_len = p->iov.size;
if (!d) {
usb_mtp_queue_result(s, RES_INVALID_OBJECTINFO, 0,
0, 0, 0, 0);
return;
}
if (d->first) { if (d->first) {
/* Total length of incoming data */ /* Total length of incoming data */
d->length = cpu_to_le32(container->length) - sizeof(mtp_container); d->length = cpu_to_le32(container->length) - sizeof(mtp_container);

View File

@ -1147,6 +1147,7 @@ static void ccid_unrealize(USBDevice *dev, Error **errp)
USBCCIDState *s = USB_CCID_DEV(dev); USBCCIDState *s = USB_CCID_DEV(dev);
ccid_bulk_in_clear(s); ccid_bulk_in_clear(s);
object_unref(OBJECT(&s->bus));
} }
static void ccid_flush_pending_answers(USBCCIDState *s) static void ccid_flush_pending_answers(USBCCIDState *s)

View File

@ -795,7 +795,7 @@ static void usbredir_handle_bulk_data(USBRedirDevice *dev, USBPacket *p,
usbredirparser_peer_has_cap(dev->parser, usbredirparser_peer_has_cap(dev->parser,
usb_redir_cap_32bits_bulk_length)); usb_redir_cap_32bits_bulk_length));
if (ep & USB_DIR_IN) { if (ep & USB_DIR_IN || size == 0) {
usbredirparser_send_bulk_packet(dev->parser, p->id, usbredirparser_send_bulk_packet(dev->parser, p->id,
&bulk_packet, NULL, 0); &bulk_packet, NULL, 0);
} else { } else {

View File

@ -1103,6 +1103,11 @@ char *object_property_get_str(Object *obj, const char *name,
* @errp: returns an error if this function fails * @errp: returns an error if this function fails
* *
* Writes an object's canonical path to a property. * Writes an object's canonical path to a property.
*
* If the link property was created with
* <code>OBJ_PROP_LINK_STRONG</code> bit, the old target object is
* unreferenced, and a reference is added to the new target object.
*
*/ */
void object_property_set_link(Object *obj, Object *value, void object_property_set_link(Object *obj, Object *value,
const char *name, Error **errp); const char *name, Error **errp);
@ -1394,7 +1399,7 @@ void object_property_add_child(Object *obj, const char *name,
typedef enum { typedef enum {
/* Unref the link pointer when the property is deleted */ /* Unref the link pointer when the property is deleted */
OBJ_PROP_LINK_UNREF_ON_RELEASE = 0x1, OBJ_PROP_LINK_STRONG = 0x1,
} ObjectPropertyLinkFlags; } ObjectPropertyLinkFlags;
/** /**
@ -1432,8 +1437,9 @@ void object_property_allow_set_link(const Object *, const char *,
* link property. The reference count for <code>*@child</code> is * link property. The reference count for <code>*@child</code> is
* managed by the property from after the function returns till the * managed by the property from after the function returns till the
* property is deleted with object_property_del(). If the * property is deleted with object_property_del(). If the
* <code>@flags</code> <code>OBJ_PROP_LINK_UNREF_ON_RELEASE</code> bit is set, * <code>@flags</code> <code>OBJ_PROP_LINK_STRONG</code> bit is set,
* the reference count is decremented when the property is deleted. * the reference count is decremented when the property is deleted or
* modified.
*/ */
void object_property_add_link(Object *obj, const char *name, void object_property_add_link(Object *obj, const char *name,
const char *type, Object **child, const char *type, Object **child,

View File

@ -77,7 +77,7 @@ static void can_host_instance_init(Object *obj)
object_property_add_link(obj, "canbus", TYPE_CAN_BUS, object_property_add_link(obj, "canbus", TYPE_CAN_BUS,
(Object **)&ch->bus, (Object **)&ch->bus,
object_property_allow_set_link, object_property_allow_set_link,
OBJ_PROP_LINK_UNREF_ON_RELEASE, OBJ_PROP_LINK_STRONG,
&error_abort); &error_abort);
} }

View File

@ -980,7 +980,7 @@ static void colo_compare_init(Object *obj)
object_property_add_link(obj, "iothread", TYPE_IOTHREAD, object_property_add_link(obj, "iothread", TYPE_IOTHREAD,
(Object **)&s->iothread, (Object **)&s->iothread,
object_property_allow_set_link, object_property_allow_set_link,
OBJ_PROP_LINK_UNREF_ON_RELEASE, NULL); OBJ_PROP_LINK_STRONG, NULL);
s->vnet_hdr = false; s->vnet_hdr = false;
object_property_add_bool(obj, "vnet_hdr_support", compare_get_vnet_hdr, object_property_add_bool(obj, "vnet_hdr_support", compare_get_vnet_hdr,

View File

@ -1564,9 +1564,11 @@ static void object_set_link_property(Object *obj, Visitor *v,
return; return;
} }
object_ref(new_target);
*child = new_target; *child = new_target;
object_unref(old_target); if (prop->flags == OBJ_PROP_LINK_STRONG) {
object_ref(new_target);
object_unref(old_target);
}
} }
static Object *object_resolve_link_property(Object *parent, void *opaque, const gchar *part) static Object *object_resolve_link_property(Object *parent, void *opaque, const gchar *part)
@ -1581,7 +1583,7 @@ static void object_release_link_property(Object *obj, const char *name,
{ {
LinkProperty *prop = opaque; LinkProperty *prop = opaque;
if ((prop->flags & OBJ_PROP_LINK_UNREF_ON_RELEASE) && *prop->child) { if ((prop->flags & OBJ_PROP_LINK_STRONG) && *prop->child) {
object_unref(*prop->child); object_unref(*prop->child);
} }
g_free(prop); g_free(prop);

View File

@ -690,7 +690,7 @@ static void arm_cpu_post_init(Object *obj)
TYPE_MEMORY_REGION, TYPE_MEMORY_REGION,
(Object **)&cpu->secure_memory, (Object **)&cpu->secure_memory,
qdev_prop_allow_set_link_before_realize, qdev_prop_allow_set_link_before_realize,
OBJ_PROP_LINK_UNREF_ON_RELEASE, OBJ_PROP_LINK_STRONG,
&error_abort); &error_abort);
#endif #endif
} }
@ -718,7 +718,7 @@ static void arm_cpu_post_init(Object *obj)
if (arm_feature(&cpu->env, ARM_FEATURE_M_SECURITY)) { if (arm_feature(&cpu->env, ARM_FEATURE_M_SECURITY)) {
object_property_add_link(obj, "idau", TYPE_IDAU_INTERFACE, &cpu->idau, object_property_add_link(obj, "idau", TYPE_IDAU_INTERFACE, &cpu->idau,
qdev_prop_allow_set_link_before_realize, qdev_prop_allow_set_link_before_realize,
OBJ_PROP_LINK_UNREF_ON_RELEASE, OBJ_PROP_LINK_STRONG,
&error_abort); &error_abort);
qdev_property_add_static(DEVICE(obj), &arm_cpu_initsvtor_property, qdev_property_add_static(DEVICE(obj), &arm_cpu_initsvtor_property,
&error_abort); &error_abort);

View File

@ -35,6 +35,15 @@ static void test_usb_uas_hotplug(void)
qtest_qmp_device_del("uas"); qtest_qmp_device_del("uas");
} }
static void test_usb_ccid_hotplug(void)
{
qtest_qmp_device_add("usb-ccid", "ccid", NULL);
qtest_qmp_device_del("ccid");
/* check the device can be added again */
qtest_qmp_device_add("usb-ccid", "ccid", NULL);
qtest_qmp_device_del("ccid");
}
int main(int argc, char **argv) int main(int argc, char **argv)
{ {
int ret; int ret;
@ -44,6 +53,7 @@ int main(int argc, char **argv)
qtest_add_func("/xhci/pci/init", test_xhci_init); qtest_add_func("/xhci/pci/init", test_xhci_init);
qtest_add_func("/xhci/pci/hotplug", test_xhci_hotplug); qtest_add_func("/xhci/pci/hotplug", test_xhci_hotplug);
qtest_add_func("/xhci/pci/hotplug/usb-uas", test_usb_uas_hotplug); qtest_add_func("/xhci/pci/hotplug/usb-uas", test_usb_uas_hotplug);
qtest_add_func("/xhci/pci/hotplug/usb-ccid", test_usb_ccid_hotplug);
qtest_start("-device nec-usb-xhci,id=xhci" qtest_start("-device nec-usb-xhci,id=xhci"
" -drive id=drive0,if=none,file=null-co://,format=raw"); " -drive id=drive0,if=none,file=null-co://,format=raw");

View File

@ -1287,7 +1287,7 @@ static QemuConsole *new_console(DisplayState *ds, console_type_t console_type,
object_property_add_link(obj, "device", TYPE_DEVICE, object_property_add_link(obj, "device", TYPE_DEVICE,
(Object **)&s->device, (Object **)&s->device,
object_property_allow_set_link, object_property_allow_set_link,
OBJ_PROP_LINK_UNREF_ON_RELEASE, OBJ_PROP_LINK_STRONG,
&error_abort); &error_abort);
object_property_add_uint32_ptr(obj, "head", object_property_add_uint32_ptr(obj, "head",
&s->head, &error_abort); &s->head, &error_abort);