diff options
Diffstat (limited to 'hw/sd')
-rw-r--r-- | hw/sd/Makefile.objs | 2 | ||||
-rw-r--r-- | hw/sd/core.c | 146 | ||||
-rw-r--r-- | hw/sd/sd.c | 47 |
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, }; |