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 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)