@@ -142,8 +142,10 @@ struct SDState {
*/
bool expecting_acmd;
uint32_t blk_written;
+
uint64_t data_start;
uint32_t data_offset;
+ size_t data_size;
uint8_t data[512];
uint8_t vendor_data[512];
@@ -1083,6 +1085,29 @@ static sd_rsp_type_t sd_cmd_unimplemented(SDState *sd, SDRequest req)
return sd_illegal;
}
+/* Configure fields for following sd_generic_read_byte() calls */
+__attribute__((unused))
+static sd_rsp_type_t sd_cmd_to_sendingdata(SDState *sd, SDRequest req,
+ uint64_t start,
+ const void *data, size_t size)
+{
+ if (sd->state != sd_transfer_state) {
+ sd_invalid_state_for_cmd(sd, req);
+ }
+
+ sd->state = sd_sendingdata_state;
+ sd->data_start = start;
+ sd->data_offset = 0;
+ if (data) {
+ assert(size);
+ memcpy(sd->data, data, size);
+ }
+ if (size) {
+ sd->data_size = size;
+ }
+ return sd_r1;
+}
+
/* CMD0 */
static sd_rsp_type_t sd_cmd_GO_IDLE_STATE(SDState *sd, SDRequest req)
{
@@ -1920,6 +1945,20 @@ send_response:
return rsplen;
}
+/* Return true when buffer is consumed. Configured by sd_cmd_to_sendingdata() */
+__attribute__((unused))
+static bool sd_generic_read_byte(SDState *sd, uint8_t *value)
+{
+ *value = sd->data[sd->data_offset];
+
+ if (++sd->data_offset >= sd->data_size) {
+ sd->state = sd_transfer_state;
+ return true;
+ }
+
+ return false;
+}
+
void sd_write_byte(SDState *sd, uint8_t value)
{
int i;
All commands switching from TRANSFER state to (sending)DATA do the same: send stream of data on the DAT lines. Instead of duplicating the same code many times, introduce 2 helpers: - sd_cmd_to_sendingdata() on the I/O line setup the data to be transferred, - sd_generic_read_byte() on the DAT lines to fetch the data. Signed-off-by: Philippe Mathieu-Daudé <philmd@linaro.org> --- hw/sd/sd.c | 39 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+)