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 "trace.h"
  26
  27static inline const char *sdbus_name(SDBus *sdbus)
  28{
  29    return sdbus->qbus.name;
  30}
  31
  32static SDState *get_card(SDBus *sdbus)
  33{
  34    /* We only ever have one child on the bus so just return it */
  35    BusChild *kid = QTAILQ_FIRST(&sdbus->qbus.children);
  36
  37    if (!kid) {
  38        return NULL;
  39    }
  40    return SD_CARD(kid->child);
  41}
  42
  43uint8_t sdbus_get_dat_lines(SDBus *sdbus)
  44{
  45    SDState *slave = get_card(sdbus);
  46    uint8_t dat_lines = 0b1111; /* 4 bit bus width */
  47
  48    if (slave) {
  49        SDCardClass *sc = SD_CARD_GET_CLASS(slave);
  50
  51        if (sc->get_dat_lines) {
  52            dat_lines = sc->get_dat_lines(slave);
  53        }
  54    }
  55    trace_sdbus_get_dat_lines(sdbus_name(sdbus), dat_lines);
  56
  57    return dat_lines;
  58}
  59
  60bool sdbus_get_cmd_line(SDBus *sdbus)
  61{
  62    SDState *slave = get_card(sdbus);
  63    bool cmd_line = true;
  64
  65    if (slave) {
  66        SDCardClass *sc = SD_CARD_GET_CLASS(slave);
  67
  68        if (sc->get_cmd_line) {
  69            cmd_line = sc->get_cmd_line(slave);
  70        }
  71    }
  72    trace_sdbus_get_cmd_line(sdbus_name(sdbus), cmd_line);
  73
  74    return cmd_line;
  75}
  76
  77void sdbus_set_voltage(SDBus *sdbus, uint16_t millivolts)
  78{
  79    SDState *card = get_card(sdbus);
  80
  81    trace_sdbus_set_voltage(sdbus_name(sdbus), millivolts);
  82    if (card) {
  83        SDCardClass *sc = SD_CARD_GET_CLASS(card);
  84
  85        assert(sc->set_voltage);
  86        sc->set_voltage(card, millivolts);
  87    }
  88}
  89
  90int sdbus_do_command(SDBus *sdbus, SDRequest *req, uint8_t *response)
  91{
  92    SDState *card = get_card(sdbus);
  93
  94    trace_sdbus_command(sdbus_name(sdbus), req->cmd, req->arg);
  95    if (card) {
  96        SDCardClass *sc = SD_CARD_GET_CLASS(card);
  97
  98        return sc->do_command(card, req, response);
  99    }
 100
 101    return 0;
 102}
 103
 104void sdbus_write_data(SDBus *sdbus, uint8_t value)
 105{
 106    SDState *card = get_card(sdbus);
 107
 108    trace_sdbus_write(sdbus_name(sdbus), value);
 109    if (card) {
 110        SDCardClass *sc = SD_CARD_GET_CLASS(card);
 111
 112        sc->write_data(card, value);
 113    }
 114}
 115
 116uint8_t sdbus_read_data(SDBus *sdbus)
 117{
 118    SDState *card = get_card(sdbus);
 119    uint8_t value = 0;
 120
 121    if (card) {
 122        SDCardClass *sc = SD_CARD_GET_CLASS(card);
 123
 124        value = sc->read_data(card);
 125    }
 126    trace_sdbus_read(sdbus_name(sdbus), value);
 127
 128    return value;
 129}
 130
 131bool sdbus_data_ready(SDBus *sdbus)
 132{
 133    SDState *card = get_card(sdbus);
 134
 135    if (card) {
 136        SDCardClass *sc = SD_CARD_GET_CLASS(card);
 137
 138        return sc->data_ready(card);
 139    }
 140
 141    return false;
 142}
 143
 144bool sdbus_get_inserted(SDBus *sdbus)
 145{
 146    SDState *card = get_card(sdbus);
 147
 148    if (card) {
 149        SDCardClass *sc = SD_CARD_GET_CLASS(card);
 150
 151        return sc->get_inserted(card);
 152    }
 153
 154    return false;
 155}
 156
 157bool sdbus_get_readonly(SDBus *sdbus)
 158{
 159    SDState *card = get_card(sdbus);
 160
 161    if (card) {
 162        SDCardClass *sc = SD_CARD_GET_CLASS(card);
 163
 164        return sc->get_readonly(card);
 165    }
 166
 167    return false;
 168}
 169
 170void sdbus_set_inserted(SDBus *sdbus, bool inserted)
 171{
 172    SDBusClass *sbc = SD_BUS_GET_CLASS(sdbus);
 173    BusState *qbus = BUS(sdbus);
 174
 175    if (sbc->set_inserted) {
 176        sbc->set_inserted(qbus->parent, inserted);
 177    }
 178}
 179
 180void sdbus_set_readonly(SDBus *sdbus, bool readonly)
 181{
 182    SDBusClass *sbc = SD_BUS_GET_CLASS(sdbus);
 183    BusState *qbus = BUS(sdbus);
 184
 185    if (sbc->set_readonly) {
 186        sbc->set_readonly(qbus->parent, readonly);
 187    }
 188}
 189
 190void sdbus_reparent_card(SDBus *from, SDBus *to)
 191{
 192    SDState *card = get_card(from);
 193    SDCardClass *sc;
 194    bool readonly;
 195
 196    /* We directly reparent the card object rather than implementing this
 197     * as a hotpluggable connection because we don't want to expose SD cards
 198     * to users as being hotpluggable, and we can get away with it in this
 199     * limited use case. This could perhaps be implemented more cleanly in
 200     * future by adding support to the hotplug infrastructure for "device
 201     * can be hotplugged only via code, not by user".
 202     */
 203
 204    if (!card) {
 205        return;
 206    }
 207
 208    sc = SD_CARD_GET_CLASS(card);
 209    readonly = sc->get_readonly(card);
 210
 211    sdbus_set_inserted(from, false);
 212    qdev_set_parent_bus(DEVICE(card), &to->qbus);
 213    sdbus_set_inserted(to, true);
 214    sdbus_set_readonly(to, readonly);
 215}
 216
 217static const TypeInfo sd_bus_info = {
 218    .name = TYPE_SD_BUS,
 219    .parent = TYPE_BUS,
 220    .instance_size = sizeof(SDBus),
 221    .class_size = sizeof(SDBusClass),
 222};
 223
 224static void sd_bus_register_types(void)
 225{
 226    type_register_static(&sd_bus_info);
 227}
 228
 229type_init(sd_bus_register_types)
 230