aboutsummaryrefslogtreecommitdiff
path: root/hw/sd
diff options
context:
space:
mode:
Diffstat (limited to 'hw/sd')
-rw-r--r--hw/sd/Makefile.objs2
-rw-r--r--hw/sd/core.c146
-rw-r--r--hw/sd/sd.c47
3 files changed, 190 insertions, 5 deletions
diff --git a/hw/sd/Makefile.objs b/hw/sd/Makefile.objs
index f1aed83d9d..31c83308f2 100644
--- a/hw/sd/Makefile.objs
+++ b/hw/sd/Makefile.objs
@@ -1,6 +1,6 @@
common-obj-$(CONFIG_PL181) += pl181.o
common-obj-$(CONFIG_SSI_SD) += ssi-sd.o
-common-obj-$(CONFIG_SD) += sd.o
+common-obj-$(CONFIG_SD) += sd.o core.o
common-obj-$(CONFIG_SDHCI) += sdhci.o
obj-$(CONFIG_MILKYMIST) += milkymist-memcard.o
diff --git a/hw/sd/core.c b/hw/sd/core.c
new file mode 100644
index 0000000000..14c2bdf27b
--- /dev/null
+++ b/hw/sd/core.c
@@ -0,0 +1,146 @@
+/*
+ * SD card bus interface code.
+ *
+ * Copyright (c) 2015 Linaro Limited
+ *
+ * Author:
+ * Peter Maydell <peter.maydell@linaro.org>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2 or later, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "qemu/osdep.h"
+#include "hw/qdev-core.h"
+#include "sysemu/block-backend.h"
+#include "hw/sd/sd.h"
+
+static SDState *get_card(SDBus *sdbus)
+{
+ /* We only ever have one child on the bus so just return it */
+ BusChild *kid = QTAILQ_FIRST(&sdbus->qbus.children);
+
+ if (!kid) {
+ return NULL;
+ }
+ return SD_CARD(kid->child);
+}
+
+int sdbus_do_command(SDBus *sdbus, SDRequest *req, uint8_t *response)
+{
+ SDState *card = get_card(sdbus);
+
+ if (card) {
+ SDCardClass *sc = SD_CARD_GET_CLASS(card);
+
+ return sc->do_command(card, req, response);
+ }
+
+ return 0;
+}
+
+void sdbus_write_data(SDBus *sdbus, uint8_t value)
+{
+ SDState *card = get_card(sdbus);
+
+ if (card) {
+ SDCardClass *sc = SD_CARD_GET_CLASS(card);
+
+ sc->write_data(card, value);
+ }
+}
+
+uint8_t sdbus_read_data(SDBus *sdbus)
+{
+ SDState *card = get_card(sdbus);
+
+ if (card) {
+ SDCardClass *sc = SD_CARD_GET_CLASS(card);
+
+ return sc->read_data(card);
+ }
+
+ return 0;
+}
+
+bool sdbus_data_ready(SDBus *sdbus)
+{
+ SDState *card = get_card(sdbus);
+
+ if (card) {
+ SDCardClass *sc = SD_CARD_GET_CLASS(card);
+
+ return sc->data_ready(card);
+ }
+
+ return false;
+}
+
+bool sdbus_get_inserted(SDBus *sdbus)
+{
+ SDState *card = get_card(sdbus);
+
+ if (card) {
+ SDCardClass *sc = SD_CARD_GET_CLASS(card);
+
+ return sc->get_inserted(card);
+ }
+
+ return false;
+}
+
+bool sdbus_get_readonly(SDBus *sdbus)
+{
+ SDState *card = get_card(sdbus);
+
+ if (card) {
+ SDCardClass *sc = SD_CARD_GET_CLASS(card);
+
+ return sc->get_readonly(card);
+ }
+
+ return false;
+}
+
+void sdbus_set_inserted(SDBus *sdbus, bool inserted)
+{
+ SDBusClass *sbc = SD_BUS_GET_CLASS(sdbus);
+ BusState *qbus = BUS(sdbus);
+
+ if (sbc->set_inserted) {
+ sbc->set_inserted(qbus->parent, inserted);
+ }
+}
+
+void sdbus_set_readonly(SDBus *sdbus, bool readonly)
+{
+ SDBusClass *sbc = SD_BUS_GET_CLASS(sdbus);
+ BusState *qbus = BUS(sdbus);
+
+ if (sbc->set_readonly) {
+ sbc->set_readonly(qbus->parent, readonly);
+ }
+}
+
+static const TypeInfo sd_bus_info = {
+ .name = TYPE_SD_BUS,
+ .parent = TYPE_BUS,
+ .instance_size = sizeof(SDBus),
+ .class_size = sizeof(SDBusClass),
+};
+
+static void sd_bus_register_types(void)
+{
+ type_register_static(&sd_bus_info);
+}
+
+type_init(sd_bus_register_types)
diff --git a/hw/sd/sd.c b/hw/sd/sd.c
index edd4c82f6f..8902cd818d 100644
--- a/hw/sd/sd.c
+++ b/hw/sd/sd.c
@@ -30,6 +30,7 @@
*/
#include "qemu/osdep.h"
+#include "hw/qdev.h"
#include "hw/hw.h"
#include "sysemu/block-backend.h"
#include "hw/sd/sd.h"
@@ -431,14 +432,41 @@ static void sd_reset(DeviceState *dev)
sd->expecting_acmd = false;
}
+static bool sd_get_inserted(SDState *sd)
+{
+ return blk_is_inserted(sd->blk);
+}
+
+static bool sd_get_readonly(SDState *sd)
+{
+ return sd->wp_switch;
+}
+
static void sd_cardchange(void *opaque, bool load)
{
SDState *sd = opaque;
+ DeviceState *dev = DEVICE(sd);
+ SDBus *sdbus = SD_BUS(qdev_get_parent_bus(dev));
+ bool inserted = sd_get_inserted(sd);
+ bool readonly = sd_get_readonly(sd);
- qemu_set_irq(sd->inserted_cb, blk_is_inserted(sd->blk));
- if (blk_is_inserted(sd->blk)) {
- sd_reset(DEVICE(sd));
- qemu_set_irq(sd->readonly_cb, sd->wp_switch);
+ if (inserted) {
+ sd_reset(dev);
+ }
+
+ /* The IRQ notification is for legacy non-QOM SD controller devices;
+ * QOMified controllers use the SDBus APIs.
+ */
+ if (sdbus) {
+ sdbus_set_inserted(sdbus, inserted);
+ if (inserted) {
+ sdbus_set_readonly(sdbus, readonly);
+ }
+ } else {
+ qemu_set_irq(sd->inserted_cb, inserted);
+ if (inserted) {
+ qemu_set_irq(sd->readonly_cb, readonly);
+ }
}
}
@@ -1803,17 +1831,28 @@ static Property sd_properties[] = {
static void sd_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
+ SDCardClass *sc = SD_CARD_CLASS(klass);
dc->realize = sd_realize;
dc->props = sd_properties;
dc->vmsd = &sd_vmstate;
dc->reset = sd_reset;
+ dc->bus_type = TYPE_SD_BUS;
+
+ sc->do_command = sd_do_command;
+ sc->write_data = sd_write_data;
+ sc->read_data = sd_read_data;
+ sc->data_ready = sd_data_ready;
+ sc->enable = sd_enable;
+ sc->get_inserted = sd_get_inserted;
+ sc->get_readonly = sd_get_readonly;
}
static const TypeInfo sd_info = {
.name = TYPE_SD_CARD,
.parent = TYPE_DEVICE,
.instance_size = sizeof(SDState),
+ .class_size = sizeof(SDCardClass),
.class_init = sd_class_init,
.instance_init = sd_instance_init,
};