qemu

FORK: QEMU emulator
git clone https://git.neptards.moe/neptards/qemu.git
Log | Files | Refs | Submodules | LICENSE

core.c (6299B)


      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 
     29 static inline const char *sdbus_name(SDBus *sdbus)
     30 {
     31     return sdbus->qbus.name;
     32 }
     33 
     34 static 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 
     45 uint8_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 
     62 bool 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 
     79 void 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 
     92 int 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 
    106 void 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 
    118 void 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 
    133 uint8_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 
    148 void 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 
    163 bool 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 
    176 bool 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 
    189 bool 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 
    202 bool 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 
    215 void 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 
    225 void 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 
    235 void 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 
    262 static 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 
    269 static void sd_bus_register_types(void)
    270 {
    271     type_register_static(&sd_bus_info);
    272 }
    273 
    274 type_init(sd_bus_register_types)