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