qemu/hw/sd/core.c
<<
>>
Prefs
   1/*
   2 * SD card bus interface code.
   3 *
   4 * Copyright (c) 2015 Linaro Limited
   5 *
   6 * Author:
   7 *  Peter Maydell <peter.maydell@linaro.org>
   8 *
   9 * This program is free software; you can redistribute it and/or modify it
  10 * under the terms and conditions of the GNU General Public License,
  11 * version 2 or later, as published by the Free Software Foundation.
  12 *
  13 * This program is distributed in the hope it will be useful, but WITHOUT
  14 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  15 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
  16 * more details.
  17 *
  18 * You should have received a copy of the GNU General Public License along with
  19 * this program.  If not, see <http://www.gnu.org/licenses/>.
  20 */
  21
  22#include "qemu/osdep.h"
  23#include "hw/qdev-core.h"
  24#include "hw/sd/sd.h"
  25#include "qemu/module.h"
  26#include "trace.h"
  27
  28static inline const char *sdbus_name(SDBus *sdbus)
  29{
  30    return sdbus->qbus.name;
  31}
  32
  33static SDState *get_card(SDBus *sdbus)
  34{
  35    /* We only ever have one child on the bus so just return it */
  36    BusChild *kid = QTAILQ_FIRST(&sdbus->qbus.children);
  37
  38    if (!kid) {
  39        return NULL;
  40    }
  41    return SD_CARD(kid->child);
  42}
  43
  44uint8_t sdbus_get_dat_lines(SDBus *sdbus)
  45{
  46    SDState *slave = get_card(sdbus);
  47    uint8_t dat_lines = 0b1111; /* 4 bit bus width */
  48
  49    if (slave) {
  50        SDCardClass *sc = SD_CARD_GET_CLASS(slave);
  51
  52        if (sc->get_dat_lines) {
  53            dat_lines = sc->get_dat_lines(slave);
  54        }
  55    }
  56    trace_sdbus_get_dat_lines(sdbus_name(sdbus), dat_lines);
  57
  58    return dat_lines;
  59}
  60
  61bool sdbus_get_cmd_line(SDBus *sdbus)
  62{
  63    SDState *slave = get_card(sdbus);
  64    bool cmd_line = true;
  65
  66    if (slave) {
  67        SDCardClass *sc = SD_CARD_GET_CLASS(slave);
  68
  69        if (sc->get_cmd_line) {
  70            cmd_line = sc->get_cmd_line(slave);
  71        }
  72    }
  73    trace_sdbus_get_cmd_line(sdbus_name(sdbus), cmd_line);
  74
  75    return cmd_line;
  76}
  77
  78void sdbus_set_voltage(SDBus *sdbus, uint16_t millivolts)
  79{
  80    SDState *card = get_card(sdbus);
  81
  82    trace_sdbus_set_voltage(sdbus_name(sdbus), millivolts);
  83    if (card) {
  84        SDCardClass *sc = SD_CARD_GET_CLASS(card);
  85
  86        assert(sc->set_voltage);
  87        sc->set_voltage(card, millivolts);
  88    }
  89}
  90
  91int sdbus_do_command(SDBus *sdbus, SDRequest *req, uint8_t *response)
  92{
  93    SDState *card = get_card(sdbus);
  94
  95    trace_sdbus_command(sdbus_name(sdbus), req->cmd, req->arg);
  96    if (card) {
  97        SDCardClass *sc = SD_CARD_GET_CLASS(card);
  98
  99        return sc->do_command(card, req, response);
 100    }
 101
 102    return 0;
 103}
 104
 105void sdbus_write_data(SDBus *sdbus, uint8_t value)
 106{
 107    SDState *card = get_card(sdbus);
 108
 109    trace_sdbus_write(sdbus_name(sdbus), value);
 110    if (card) {
 111        SDCardClass *sc = SD_CARD_GET_CLASS(card);
 112
 113        sc->write_data(card, value);
 114    }
 115}
 116
 117uint8_t sdbus_read_data(SDBus *sdbus)
 118{
 119    SDState *card = get_card(sdbus);
 120    uint8_t value = 0;
 121
 122    if (card) {
 123        SDCardClass *sc = SD_CARD_GET_CLASS(card);
 124
 125        value = sc->read_data(card);
 126    }
 127    trace_sdbus_read(sdbus_name(sdbus), value);
 128
 129    return value;
 130}
 131
 132bool sdbus_data_ready(SDBus *sdbus)
 133{
 134    SDState *card = get_card(sdbus);
 135
 136    if (card) {
 137        SDCardClass *sc = SD_CARD_GET_CLASS(card);
 138
 139        return sc->data_ready(card);
 140    }
 141
 142    return false;
 143}
 144
 145bool sdbus_get_inserted(SDBus *sdbus)
 146{
 147    SDState *card = get_card(sdbus);
 148
 149    if (card) {
 150        SDCardClass *sc = SD_CARD_GET_CLASS(card);
 151
 152        return sc->get_inserted(card);
 153    }
 154
 155    return false;
 156}
 157
 158bool sdbus_get_readonly(SDBus *sdbus)
 159{
 160    SDState *card = get_card(sdbus);
 161
 162    if (card) {
 163        SDCardClass *sc = SD_CARD_GET_CLASS(card);
 164
 165        return sc->get_readonly(card);
 166    }
 167
 168    return false;
 169}
 170
 171void sdbus_set_inserted(SDBus *sdbus, bool inserted)
 172{
 173    SDBusClass *sbc = SD_BUS_GET_CLASS(sdbus);
 174    BusState *qbus = BUS(sdbus);
 175
 176    if (sbc->set_inserted) {
 177        sbc->set_inserted(qbus->parent, inserted);
 178    }
 179}
 180
 181void sdbus_set_readonly(SDBus *sdbus, bool readonly)
 182{
 183    SDBusClass *sbc = SD_BUS_GET_CLASS(sdbus);
 184    BusState *qbus = BUS(sdbus);
 185
 186    if (sbc->set_readonly) {
 187        sbc->set_readonly(qbus->parent, readonly);
 188    }
 189}
 190
 191void sdbus_reparent_card(SDBus *from, SDBus *to)
 192{
 193    SDState *card = get_card(from);
 194    SDCardClass *sc;
 195    bool readonly;
 196
 197    /* We directly reparent the card object rather than implementing this
 198     * as a hotpluggable connection because we don't want to expose SD cards
 199     * to users as being hotpluggable, and we can get away with it in this
 200     * limited use case. This could perhaps be implemented more cleanly in
 201     * future by adding support to the hotplug infrastructure for "device
 202     * can be hotplugged only via code, not by user".
 203     */
 204
 205    if (!card) {
 206        return;
 207    }
 208
 209    sc = SD_CARD_GET_CLASS(card);
 210    readonly = sc->get_readonly(card);
 211
 212    sdbus_set_inserted(from, false);
 213    qdev_set_parent_bus(DEVICE(card), &to->qbus);
 214    sdbus_set_inserted(to, true);
 215    sdbus_set_readonly(to, readonly);
 216}
 217
 218static const TypeInfo sd_bus_info = {
 219    .name = TYPE_SD_BUS,
 220    .parent = TYPE_BUS,
 221    .instance_size = sizeof(SDBus),
 222    .class_size = sizeof(SDBusClass),
 223};
 224
 225static void sd_bus_register_types(void)
 226{
 227    type_register_static(&sd_bus_info);
 228}
 229
 230type_init(sd_bus_register_types)
 231