2007-04-30 01:48:07 +00:00
|
|
|
/*
|
|
|
|
* Intel XScale PXA255/270 PC Card and CompactFlash Interface.
|
|
|
|
*
|
|
|
|
* Copyright (c) 2006 Openedhand Ltd.
|
|
|
|
* Written by Andrzej Zaborowski <balrog@zabor.org>
|
|
|
|
*
|
|
|
|
* This code is licensed under the GPLv2.
|
2012-01-13 16:44:23 +00:00
|
|
|
*
|
|
|
|
* Contributions after 2012-01-13 are licensed under the terms of the
|
|
|
|
* GNU GPL, version 2 or (at your option) any later version.
|
2007-04-30 01:48:07 +00:00
|
|
|
*/
|
|
|
|
|
2013-02-04 14:40:22 +00:00
|
|
|
#include "hw/hw.h"
|
2013-08-03 10:23:05 +00:00
|
|
|
#include "hw/sysbus.h"
|
2013-02-04 14:40:22 +00:00
|
|
|
#include "hw/pcmcia.h"
|
2013-02-05 16:06:20 +00:00
|
|
|
#include "hw/arm/pxa.h"
|
2007-04-30 01:48:07 +00:00
|
|
|
|
2013-08-03 10:23:05 +00:00
|
|
|
#define TYPE_PXA2XX_PCMCIA "pxa2xx-pcmcia"
|
|
|
|
#define PXA2XX_PCMCIA(obj) \
|
|
|
|
OBJECT_CHECK(PXA2xxPCMCIAState, obj, TYPE_PXA2XX_PCMCIA)
|
2011-10-30 13:50:13 +00:00
|
|
|
|
2009-05-10 00:44:56 +00:00
|
|
|
struct PXA2xxPCMCIAState {
|
2013-08-03 10:23:05 +00:00
|
|
|
SysBusDevice parent_obj;
|
|
|
|
|
2009-05-10 00:44:56 +00:00
|
|
|
PCMCIASocket slot;
|
2013-08-03 10:23:05 +00:00
|
|
|
MemoryRegion container_mem;
|
2011-10-30 13:50:12 +00:00
|
|
|
MemoryRegion common_iomem;
|
2011-10-30 13:50:13 +00:00
|
|
|
MemoryRegion attr_iomem;
|
2011-10-30 13:50:14 +00:00
|
|
|
MemoryRegion iomem;
|
2007-04-30 01:48:07 +00:00
|
|
|
|
|
|
|
qemu_irq irq;
|
|
|
|
qemu_irq cd_irq;
|
2013-08-03 10:23:05 +00:00
|
|
|
|
|
|
|
PCMCIACardState *card;
|
2007-04-30 01:48:07 +00:00
|
|
|
};
|
|
|
|
|
2011-10-30 13:50:12 +00:00
|
|
|
static uint64_t pxa2xx_pcmcia_common_read(void *opaque,
|
2012-10-23 10:30:10 +00:00
|
|
|
hwaddr offset, unsigned size)
|
2007-04-30 01:48:07 +00:00
|
|
|
{
|
2009-05-10 00:44:56 +00:00
|
|
|
PXA2xxPCMCIAState *s = (PXA2xxPCMCIAState *) opaque;
|
2013-07-17 17:46:16 +00:00
|
|
|
PCMCIACardClass *pcc;
|
2007-04-30 01:48:07 +00:00
|
|
|
|
|
|
|
if (s->slot.attached) {
|
2013-07-17 17:46:16 +00:00
|
|
|
pcc = PCMCIA_CARD_GET_CLASS(s->card);
|
|
|
|
return pcc->common_read(s->card, offset);
|
2007-04-30 01:48:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2012-10-23 10:30:10 +00:00
|
|
|
static void pxa2xx_pcmcia_common_write(void *opaque, hwaddr offset,
|
2011-10-30 13:50:12 +00:00
|
|
|
uint64_t value, unsigned size)
|
2007-04-30 01:48:07 +00:00
|
|
|
{
|
2009-05-10 00:44:56 +00:00
|
|
|
PXA2xxPCMCIAState *s = (PXA2xxPCMCIAState *) opaque;
|
2013-07-17 17:46:16 +00:00
|
|
|
PCMCIACardClass *pcc;
|
2007-04-30 01:48:07 +00:00
|
|
|
|
|
|
|
if (s->slot.attached) {
|
2013-07-17 17:46:16 +00:00
|
|
|
pcc = PCMCIA_CARD_GET_CLASS(s->card);
|
|
|
|
pcc->common_write(s->card, offset, value);
|
2007-04-30 01:48:07 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-10-30 13:50:13 +00:00
|
|
|
static uint64_t pxa2xx_pcmcia_attr_read(void *opaque,
|
2012-10-23 10:30:10 +00:00
|
|
|
hwaddr offset, unsigned size)
|
2007-04-30 01:48:07 +00:00
|
|
|
{
|
2009-05-10 00:44:56 +00:00
|
|
|
PXA2xxPCMCIAState *s = (PXA2xxPCMCIAState *) opaque;
|
2013-07-17 17:46:16 +00:00
|
|
|
PCMCIACardClass *pcc;
|
2007-04-30 01:48:07 +00:00
|
|
|
|
|
|
|
if (s->slot.attached) {
|
2013-07-17 17:46:16 +00:00
|
|
|
pcc = PCMCIA_CARD_GET_CLASS(s->card);
|
|
|
|
return pcc->attr_read(s->card, offset);
|
2007-04-30 01:48:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2012-10-23 10:30:10 +00:00
|
|
|
static void pxa2xx_pcmcia_attr_write(void *opaque, hwaddr offset,
|
2011-10-30 13:50:13 +00:00
|
|
|
uint64_t value, unsigned size)
|
2007-04-30 01:48:07 +00:00
|
|
|
{
|
2009-05-10 00:44:56 +00:00
|
|
|
PXA2xxPCMCIAState *s = (PXA2xxPCMCIAState *) opaque;
|
2013-07-17 17:46:16 +00:00
|
|
|
PCMCIACardClass *pcc;
|
2007-04-30 01:48:07 +00:00
|
|
|
|
|
|
|
if (s->slot.attached) {
|
2013-07-17 17:46:16 +00:00
|
|
|
pcc = PCMCIA_CARD_GET_CLASS(s->card);
|
|
|
|
pcc->attr_write(s->card, offset, value);
|
2007-04-30 01:48:07 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-10-30 13:50:14 +00:00
|
|
|
static uint64_t pxa2xx_pcmcia_io_read(void *opaque,
|
2012-10-23 10:30:10 +00:00
|
|
|
hwaddr offset, unsigned size)
|
2007-04-30 01:48:07 +00:00
|
|
|
{
|
2009-05-10 00:44:56 +00:00
|
|
|
PXA2xxPCMCIAState *s = (PXA2xxPCMCIAState *) opaque;
|
2013-07-17 17:46:16 +00:00
|
|
|
PCMCIACardClass *pcc;
|
2007-04-30 01:48:07 +00:00
|
|
|
|
|
|
|
if (s->slot.attached) {
|
2013-07-17 17:46:16 +00:00
|
|
|
pcc = PCMCIA_CARD_GET_CLASS(s->card);
|
|
|
|
return pcc->io_read(s->card, offset);
|
2007-04-30 01:48:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2012-10-23 10:30:10 +00:00
|
|
|
static void pxa2xx_pcmcia_io_write(void *opaque, hwaddr offset,
|
2011-10-30 13:50:14 +00:00
|
|
|
uint64_t value, unsigned size)
|
2007-04-30 01:48:07 +00:00
|
|
|
{
|
2009-05-10 00:44:56 +00:00
|
|
|
PXA2xxPCMCIAState *s = (PXA2xxPCMCIAState *) opaque;
|
2013-07-17 17:46:16 +00:00
|
|
|
PCMCIACardClass *pcc;
|
2007-04-30 01:48:07 +00:00
|
|
|
|
|
|
|
if (s->slot.attached) {
|
2013-07-17 17:46:16 +00:00
|
|
|
pcc = PCMCIA_CARD_GET_CLASS(s->card);
|
|
|
|
pcc->io_write(s->card, offset, value);
|
2007-04-30 01:48:07 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-10-30 13:50:12 +00:00
|
|
|
static const MemoryRegionOps pxa2xx_pcmcia_common_ops = {
|
|
|
|
.read = pxa2xx_pcmcia_common_read,
|
|
|
|
.write = pxa2xx_pcmcia_common_write,
|
|
|
|
.endianness = DEVICE_NATIVE_ENDIAN
|
2007-04-30 01:48:07 +00:00
|
|
|
};
|
|
|
|
|
2011-10-30 13:50:13 +00:00
|
|
|
static const MemoryRegionOps pxa2xx_pcmcia_attr_ops = {
|
|
|
|
.read = pxa2xx_pcmcia_attr_read,
|
|
|
|
.write = pxa2xx_pcmcia_attr_write,
|
|
|
|
.endianness = DEVICE_NATIVE_ENDIAN
|
2007-04-30 01:48:07 +00:00
|
|
|
};
|
|
|
|
|
2011-10-30 13:50:14 +00:00
|
|
|
static const MemoryRegionOps pxa2xx_pcmcia_io_ops = {
|
|
|
|
.read = pxa2xx_pcmcia_io_read,
|
|
|
|
.write = pxa2xx_pcmcia_io_write,
|
|
|
|
.endianness = DEVICE_NATIVE_ENDIAN
|
2007-04-30 01:48:07 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
static void pxa2xx_pcmcia_set_irq(void *opaque, int line, int level)
|
|
|
|
{
|
2009-05-10 00:44:56 +00:00
|
|
|
PXA2xxPCMCIAState *s = (PXA2xxPCMCIAState *) opaque;
|
2007-04-30 01:48:07 +00:00
|
|
|
if (!s->irq)
|
|
|
|
return;
|
|
|
|
|
|
|
|
qemu_set_irq(s->irq, level);
|
|
|
|
}
|
|
|
|
|
2011-10-30 13:50:12 +00:00
|
|
|
PXA2xxPCMCIAState *pxa2xx_pcmcia_init(MemoryRegion *sysmem,
|
2012-10-23 10:30:10 +00:00
|
|
|
hwaddr base)
|
2007-04-30 01:48:07 +00:00
|
|
|
{
|
2013-08-03 10:23:05 +00:00
|
|
|
DeviceState *dev;
|
2009-05-10 00:44:56 +00:00
|
|
|
PXA2xxPCMCIAState *s;
|
2007-04-30 01:48:07 +00:00
|
|
|
|
2013-08-03 10:23:05 +00:00
|
|
|
dev = qdev_create(NULL, TYPE_PXA2XX_PCMCIA);
|
|
|
|
sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, base);
|
|
|
|
s = PXA2XX_PCMCIA(dev);
|
|
|
|
|
|
|
|
if (base == 0x30000000) {
|
|
|
|
s->slot.slot_string = "PXA PC Card Socket 1";
|
|
|
|
} else {
|
|
|
|
s->slot.slot_string = "PXA PC Card Socket 0";
|
|
|
|
}
|
|
|
|
|
|
|
|
qdev_init_nofail(dev);
|
|
|
|
|
|
|
|
return s;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void pxa2xx_pcmcia_realize(DeviceState *dev, Error **errp)
|
|
|
|
{
|
|
|
|
PXA2xxPCMCIAState *s = PXA2XX_PCMCIA(dev);
|
|
|
|
|
|
|
|
pcmcia_socket_register(&s->slot);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void pxa2xx_pcmcia_initfn(Object *obj)
|
|
|
|
{
|
|
|
|
SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
|
|
|
|
PXA2xxPCMCIAState *s = PXA2XX_PCMCIA(obj);
|
|
|
|
|
|
|
|
memory_region_init(&s->container_mem, obj, "container", 0x10000000);
|
|
|
|
sysbus_init_mmio(sbd, &s->container_mem);
|
2007-04-30 01:48:07 +00:00
|
|
|
|
|
|
|
/* Socket I/O Memory Space */
|
2013-06-06 09:41:28 +00:00
|
|
|
memory_region_init_io(&s->iomem, NULL, &pxa2xx_pcmcia_io_ops, s,
|
2011-10-30 13:50:14 +00:00
|
|
|
"pxa2xx-pcmcia-io", 0x04000000);
|
2013-08-03 10:23:05 +00:00
|
|
|
memory_region_add_subregion(&s->container_mem, 0x00000000,
|
2011-10-30 13:50:14 +00:00
|
|
|
&s->iomem);
|
2007-04-30 01:48:07 +00:00
|
|
|
|
|
|
|
/* Then next 64 MB is reserved */
|
|
|
|
|
|
|
|
/* Socket Attribute Memory Space */
|
2013-06-06 09:41:28 +00:00
|
|
|
memory_region_init_io(&s->attr_iomem, NULL, &pxa2xx_pcmcia_attr_ops, s,
|
2011-10-30 13:50:13 +00:00
|
|
|
"pxa2xx-pcmcia-attribute", 0x04000000);
|
2013-08-03 10:23:05 +00:00
|
|
|
memory_region_add_subregion(&s->container_mem, 0x08000000,
|
2011-10-30 13:50:13 +00:00
|
|
|
&s->attr_iomem);
|
2007-04-30 01:48:07 +00:00
|
|
|
|
|
|
|
/* Socket Common Memory Space */
|
2013-06-06 09:41:28 +00:00
|
|
|
memory_region_init_io(&s->common_iomem, NULL, &pxa2xx_pcmcia_common_ops, s,
|
2011-10-30 13:50:12 +00:00
|
|
|
"pxa2xx-pcmcia-common", 0x04000000);
|
2013-08-03 10:23:05 +00:00
|
|
|
memory_region_add_subregion(&s->container_mem, 0x0c000000,
|
2011-10-30 13:50:12 +00:00
|
|
|
&s->common_iomem);
|
2007-04-30 01:48:07 +00:00
|
|
|
|
|
|
|
s->slot.irq = qemu_allocate_irqs(pxa2xx_pcmcia_set_irq, s, 1)[0];
|
2007-05-23 21:47:51 +00:00
|
|
|
|
2013-08-03 10:23:05 +00:00
|
|
|
object_property_add_link(obj, "card", TYPE_PCMCIA_CARD,
|
qom: Make QOM link property unref optional
Some object_property_add_link() callers expect property deletion to
unref the link property object. Other callers expect to manage the
refcount themselves. The former are currently broken and therefore leak
the link property object.
This patch adds a flags argument to object_property_add_link() so the
caller can specify which refcount behavior they require. The new
OBJ_PROP_LINK_UNREF_ON_RELEASE flag causes the link pointer to be
unreferenced when the property is deleted.
This fixes refcount leaks in qdev.c, xilinx_axidma.c, xilinx_axienet.c,
s390-virtio-bus.c, virtio-pci.c, virtio-rng.c, and ui/console.c.
Rationale for refcount behavior:
* hw/core/qdev.c
- bus children are explicitly unreferenced, don't interfere
- parent_bus is essentially a read-only property that doesn't hold a
refcount, don't unref
- hotplug_handler is leaked, do unref
* hw/dma/xilinx_axidma.c
- rx stream "dma" links are set using set_link, therefore they
need unref
- tx streams are set using set_link, therefore they need unref
* hw/net/xilinx_axienet.c
- same reasoning as hw/dma/xilinx_axidma.c
* hw/pcmcia/pxa2xx.c
- pxa2xx bypasses set_link and therefore does not use refcounts
* hw/s390x/s390-virtio-bus.c
* hw/virtio/virtio-pci.c
* hw/virtio/virtio-rng.c
* ui/console.c
- set_link is used and there is no explicit unref, do unref
Cc: Peter Crosthwaite <peter.crosthwaite@petalogix.com>
Cc: Alexander Graf <agraf@suse.de>
Cc: Anthony Liguori <aliguori@amazon.com>
Cc: "Michael S. Tsirkin" <mst@redhat.com>
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
Reviewed-by: Paolo Bonzini <pbonzini@redhat.com>
Signed-off-by: Andreas Färber <afaerber@suse.de>
2014-03-19 07:58:55 +00:00
|
|
|
(Object **)&s->card, 0, NULL);
|
2007-04-30 01:48:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Insert a new card into a slot */
|
2009-05-10 00:44:56 +00:00
|
|
|
int pxa2xx_pcmcia_attach(void *opaque, PCMCIACardState *card)
|
2007-04-30 01:48:07 +00:00
|
|
|
{
|
2009-05-10 00:44:56 +00:00
|
|
|
PXA2xxPCMCIAState *s = (PXA2xxPCMCIAState *) opaque;
|
2013-07-17 17:46:16 +00:00
|
|
|
PCMCIACardClass *pcc;
|
|
|
|
|
|
|
|
if (s->slot.attached) {
|
2007-04-30 01:48:07 +00:00
|
|
|
return -EEXIST;
|
2013-07-17 17:46:16 +00:00
|
|
|
}
|
2007-04-30 01:48:07 +00:00
|
|
|
|
|
|
|
if (s->cd_irq) {
|
|
|
|
qemu_irq_raise(s->cd_irq);
|
|
|
|
}
|
|
|
|
|
|
|
|
s->card = card;
|
2013-07-17 17:46:16 +00:00
|
|
|
pcc = PCMCIA_CARD_GET_CLASS(s->card);
|
2007-04-30 01:48:07 +00:00
|
|
|
|
2013-07-17 17:46:16 +00:00
|
|
|
s->slot.attached = true;
|
2007-04-30 01:48:07 +00:00
|
|
|
s->card->slot = &s->slot;
|
2013-07-17 17:46:16 +00:00
|
|
|
pcc->attach(s->card);
|
2007-04-30 01:48:07 +00:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Eject card from the slot */
|
2013-07-17 17:06:47 +00:00
|
|
|
int pxa2xx_pcmcia_detach(void *opaque)
|
2007-04-30 01:48:07 +00:00
|
|
|
{
|
2009-05-10 00:44:56 +00:00
|
|
|
PXA2xxPCMCIAState *s = (PXA2xxPCMCIAState *) opaque;
|
2013-07-17 17:46:16 +00:00
|
|
|
PCMCIACardClass *pcc;
|
|
|
|
|
|
|
|
if (!s->slot.attached) {
|
2007-04-30 01:48:07 +00:00
|
|
|
return -ENOENT;
|
2013-07-17 17:46:16 +00:00
|
|
|
}
|
2007-04-30 01:48:07 +00:00
|
|
|
|
2013-07-17 17:46:16 +00:00
|
|
|
pcc = PCMCIA_CARD_GET_CLASS(s->card);
|
|
|
|
pcc->detach(s->card);
|
2009-09-21 18:11:34 +00:00
|
|
|
s->card->slot = NULL;
|
|
|
|
s->card = NULL;
|
2007-04-30 01:48:07 +00:00
|
|
|
|
2013-07-17 17:46:16 +00:00
|
|
|
s->slot.attached = false;
|
2007-04-30 01:48:07 +00:00
|
|
|
|
2013-07-17 17:46:16 +00:00
|
|
|
if (s->irq) {
|
2007-04-30 01:48:07 +00:00
|
|
|
qemu_irq_lower(s->irq);
|
2013-07-17 17:46:16 +00:00
|
|
|
}
|
|
|
|
if (s->cd_irq) {
|
2007-04-30 01:48:07 +00:00
|
|
|
qemu_irq_lower(s->cd_irq);
|
2013-07-17 17:46:16 +00:00
|
|
|
}
|
2007-04-30 01:48:07 +00:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Who to notify on card events */
|
|
|
|
void pxa2xx_pcmcia_set_irq_cb(void *opaque, qemu_irq irq, qemu_irq cd_irq)
|
|
|
|
{
|
2009-05-10 00:44:56 +00:00
|
|
|
PXA2xxPCMCIAState *s = (PXA2xxPCMCIAState *) opaque;
|
2007-04-30 01:48:07 +00:00
|
|
|
s->irq = irq;
|
|
|
|
s->cd_irq = cd_irq;
|
|
|
|
}
|
2013-08-03 10:23:05 +00:00
|
|
|
|
|
|
|
static void pxa2xx_pcmcia_class_init(ObjectClass *oc, void *data)
|
|
|
|
{
|
|
|
|
DeviceClass *dc = DEVICE_CLASS(oc);
|
|
|
|
|
|
|
|
dc->realize = pxa2xx_pcmcia_realize;
|
|
|
|
}
|
|
|
|
|
|
|
|
static const TypeInfo pxa2xx_pcmcia_type_info = {
|
|
|
|
.name = TYPE_PXA2XX_PCMCIA,
|
|
|
|
.parent = TYPE_SYS_BUS_DEVICE,
|
|
|
|
.instance_size = sizeof(PXA2xxPCMCIAState),
|
|
|
|
.instance_init = pxa2xx_pcmcia_initfn,
|
|
|
|
.class_init = pxa2xx_pcmcia_class_init,
|
|
|
|
};
|
|
|
|
|
|
|
|
static void pxa2xx_pcmcia_register_types(void)
|
|
|
|
{
|
|
|
|
type_register_static(&pxa2xx_pcmcia_type_info);
|
|
|
|
}
|
|
|
|
|
|
|
|
type_init(pxa2xx_pcmcia_register_types)
|