qemu-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Qemu-devel] [PATCH V2 2/3] hw/sd.c: add SD card save/load support


From: Mitsyanko Igor
Subject: [Qemu-devel] [PATCH V2 2/3] hw/sd.c: add SD card save/load support
Date: Wed, 28 Dec 2011 16:08:44 +0400

We couldn't properly implement save/restore functionality of SD host controllers
states without SD card's state VMStateDescription implementation. This patch
updates SD card emulation to support save/load of card's state. Update requires
changing of data type of several variables in SDState. Variables order 
rearranged
to ensure proper data alignment in SDState structure.
For consistency, because several variables now have bool datatype, API was 
modified
to use bool as well, 0 was changed to 'false' and 1 was changed to 'true' in 
those
places where it was appropriate.

Signed-off-by: Mitsyanko Igor <address@hidden>
---
 hw/sd.c |  130 ++++++++++++++++++++++++++++++++++++++++++---------------------
 hw/sd.h |    4 +-
 2 files changed, 89 insertions(+), 45 deletions(-)

diff --git a/hw/sd.c b/hw/sd.c
index 07eb263..4b5b538 100644
--- a/hw/sd.c
+++ b/hw/sd.c
@@ -54,49 +54,53 @@ typedef enum {
     sd_illegal = -2,
 } sd_rsp_type_t;
 
+enum {
+    sd_inactive,
+    sd_card_identification_mode,
+    sd_data_transfer_mode,
+};
+
+enum {
+    sd_inactive_state = -1,
+    sd_idle_state = 0,
+    sd_ready_state,
+    sd_identification_state,
+    sd_standby_state,
+    sd_transfer_state,
+    sd_sendingdata_state,
+    sd_receivingdata_state,
+    sd_programming_state,
+    sd_disconnect_state,
+};
+
 struct SDState {
-    enum {
-        sd_inactive,
-        sd_card_identification_mode,
-        sd_data_transfer_mode,
-    } mode;
-    enum {
-        sd_inactive_state = -1,
-        sd_idle_state = 0,
-        sd_ready_state,
-        sd_identification_state,
-        sd_standby_state,
-        sd_transfer_state,
-        sd_sendingdata_state,
-        sd_receivingdata_state,
-        sd_programming_state,
-        sd_disconnect_state,
-    } state;
+    int32_t state;
     uint32_t ocr;
     uint8_t scr[8];
     uint8_t cid[16];
     uint8_t csd[16];
-    uint16_t rca;
     uint32_t card_status;
     uint8_t sd_status[64];
     uint32_t vhs;
-    int wp_switch;
-    int *wp_groups;
     uint64_t size;
-    int blk_len;
+    uint32_t blk_len;
     uint32_t erase_start;
     uint32_t erase_end;
     uint8_t pwd[16];
-    int pwd_len;
-    int function_group[6];
-
-    int spi;
-    int current_cmd;
+    uint32_t pwd_len;
+    uint8_t function_group[6];
+    uint8_t mode;
+    uint8_t current_cmd;
     /* True if we will handle the next command as an ACMD. Note that this does
      * *not* track the APP_CMD status bit!
      */
-    int expecting_acmd;
-    int blk_written;
+    bool expecting_acmd;
+    bool spi;
+    bool enable;
+    bool wp_switch;
+    bool *wp_groups;
+
+    uint32_t blk_written;
     uint64_t data_start;
     uint32_t data_offset;
     uint8_t data[512];
@@ -104,8 +108,7 @@ struct SDState {
     qemu_irq inserted_cb;
     BlockDriverState *bdrv;
     uint8_t *buf;
-
-    int enable;
+    uint16_t rca;
 };
 
 static void sd_set_mode(SDState *sd)
@@ -415,14 +418,14 @@ static void sd_reset(SDState *sd, BlockDriverState *bdrv)
     if (sd->wp_groups)
         g_free(sd->wp_groups);
     sd->wp_switch = bdrv ? bdrv_is_read_only(bdrv) : 0;
-    sd->wp_groups = (int *) g_malloc0(sizeof(int) * sect);
-    memset(sd->function_group, 0, sizeof(int) * 6);
+    sd->wp_groups = (bool *)g_malloc0(sizeof(bool) * sect);
+    memset(sd->function_group, 0, sizeof(sd->function_group));
     sd->erase_start = 0;
     sd->erase_end = 0;
     sd->size = size;
     sd->blk_len = 0x200;
     sd->pwd_len = 0;
-    sd->expecting_acmd = 0;
+    sd->expecting_acmd = false;
 }
 
 static void sd_cardchange(void *opaque, bool load)
@@ -440,23 +443,64 @@ static const BlockDevOps sd_block_ops = {
     .change_media_cb = sd_cardchange,
 };
 
+
+static int sd_get_wpgroups_size(void *opaque, int version_id)
+{
+    SDState *sd = (SDState *)opaque;
+    return sizeof(bool) * (sd->size >> (HWBLOCK_SHIFT + SECTOR_SHIFT +
+            WPGROUP_SHIFT));
+}
+
+static const VMStateDescription sd_vmstate = {
+    .name = "sd_card",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .fields      = (VMStateField[]) {
+        VMSTATE_INT32(state, SDState),
+        VMSTATE_UINT8_ARRAY(cid, SDState, 16),
+        VMSTATE_UINT8_ARRAY(csd, SDState, 16),
+        VMSTATE_UINT32(card_status, SDState),
+        VMSTATE_PARTIAL_BUFFER(sd_status, SDState, 1),
+        VMSTATE_UINT32(vhs, SDState),
+        VMSTATE_UINT32(blk_len, SDState),
+        VMSTATE_UINT32(erase_start, SDState),
+        VMSTATE_UINT32(erase_end, SDState),
+        VMSTATE_UINT8_ARRAY(pwd, SDState, 16),
+        VMSTATE_UINT32(pwd_len, SDState),
+        VMSTATE_UINT8_ARRAY(function_group, SDState, 6),
+        VMSTATE_UINT8(mode, SDState),
+        VMSTATE_UINT8(current_cmd, SDState),
+        VMSTATE_BOOL(expecting_acmd, SDState),
+        VMSTATE_BOOL(enable, SDState),
+        VMSTATE_VBUFFER(wp_groups, SDState, 1, NULL, 0, sd_get_wpgroups_size),
+        VMSTATE_UINT32(blk_written, SDState),
+        VMSTATE_UINT64(data_start, SDState),
+        VMSTATE_UINT32(data_offset, SDState),
+        VMSTATE_UINT8_ARRAY(data, SDState, 512),
+        VMSTATE_BUFFER_UNSAFE(buf, SDState, 1, 512),
+        VMSTATE_UINT16(rca, SDState),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
 /* We do not model the chip select pin, so allow the board to select
    whether card should be in SSI or MMC/SD mode.  It is also up to the
    board to ensure that ssi transfers only occur when the chip select
    is asserted.  */
-SDState *sd_init(BlockDriverState *bs, int is_spi)
+SDState *sd_init(BlockDriverState *bs, bool is_spi)
 {
     SDState *sd;
 
     sd = (SDState *) g_malloc0(sizeof(SDState));
     sd->buf = qemu_blockalign(bs, 512);
     sd->spi = is_spi;
-    sd->enable = 1;
+    sd->enable = true;
     sd_reset(sd, bs);
     if (sd->bdrv) {
         bdrv_attach_dev_nofail(sd->bdrv, sd);
         bdrv_set_dev_ops(sd->bdrv, &sd_block_ops, sd);
     }
+    vmstate_register(NULL, -1, &sd_vmstate, sd);
     return sd;
 }
 
@@ -534,7 +578,7 @@ static void sd_function_switch(SDState *sd, uint32_t arg)
     sd->data[66] = crc & 0xff;
 }
 
-static inline int sd_wp_addr(SDState *sd, uint32_t addr)
+static inline bool sd_wp_addr(SDState *sd, uint32_t addr)
 {
     return sd->wp_groups[addr >>
             (HWBLOCK_SHIFT + SECTOR_SHIFT + WPGROUP_SHIFT)];
@@ -560,7 +604,7 @@ static void sd_lock_command(SDState *sd)
             sd->card_status |= LOCK_UNLOCK_FAILED;
             return;
         }
-        memset(sd->wp_groups, 0, sizeof(int) * (sd->size >>
+        memset(sd->wp_groups, 0, sizeof(bool) * (sd->size >>
                         (HWBLOCK_SHIFT + SECTOR_SHIFT + WPGROUP_SHIFT)));
         sd->csd[14] &= ~0x10;
         sd->card_status &= ~CARD_IS_LOCKED;
@@ -1008,7 +1052,7 @@ static sd_rsp_type_t sd_normal_command(SDState *sd,
 
             sd->state = sd_programming_state;
             sd->wp_groups[addr >> (HWBLOCK_SHIFT +
-                            SECTOR_SHIFT + WPGROUP_SHIFT)] = 1;
+                            SECTOR_SHIFT + WPGROUP_SHIFT)] = true;
             /* Bzzzzzzztt .... Operation complete.  */
             sd->state = sd_transfer_state;
             return sd_r1b;
@@ -1028,7 +1072,7 @@ static sd_rsp_type_t sd_normal_command(SDState *sd,
 
             sd->state = sd_programming_state;
             sd->wp_groups[addr >> (HWBLOCK_SHIFT +
-                            SECTOR_SHIFT + WPGROUP_SHIFT)] = 0;
+                            SECTOR_SHIFT + WPGROUP_SHIFT)] = false;
             /* Bzzzzzzztt .... Operation complete.  */
             sd->state = sd_transfer_state;
             return sd_r1b;
@@ -1125,7 +1169,7 @@ static sd_rsp_type_t sd_normal_command(SDState *sd,
         if (sd->rca != rca)
             return sd_r0;
 
-        sd->expecting_acmd = 1;
+        sd->expecting_acmd = true;
         sd->card_status |= APP_CMD;
         return sd_r1;
 
@@ -1307,7 +1351,7 @@ int sd_do_command(SDState *sd, SDRequest *req,
     if (sd->card_status & CARD_IS_LOCKED) {
         if (!cmd_valid_while_locked(sd, req)) {
             sd->card_status |= ILLEGAL_COMMAND;
-            sd->expecting_acmd = 0;
+            sd->expecting_acmd = false;
             fprintf(stderr, "SD: Card is locked\n");
             rtype = sd_illegal;
             goto send_response;
@@ -1318,7 +1362,7 @@ int sd_do_command(SDState *sd, SDRequest *req,
     sd_set_mode(sd);
 
     if (sd->expecting_acmd) {
-        sd->expecting_acmd = 0;
+        sd->expecting_acmd = false;
         rtype = sd_app_command(sd, *req);
     } else {
         rtype = sd_normal_command(sd, *req);
@@ -1704,7 +1748,7 @@ int sd_data_ready(SDState *sd)
     return sd->state == sd_sendingdata_state;
 }
 
-void sd_enable(SDState *sd, int enable)
+void sd_enable(SDState *sd, bool enable)
 {
     sd->enable = enable;
 }
diff --git a/hw/sd.h b/hw/sd.h
index ac4b7c4..d25342f 100644
--- a/hw/sd.h
+++ b/hw/sd.h
@@ -67,13 +67,13 @@ typedef struct {
 
 typedef struct SDState SDState;
 
-SDState *sd_init(BlockDriverState *bs, int is_spi);
+SDState *sd_init(BlockDriverState *bs, bool is_spi);
 int sd_do_command(SDState *sd, SDRequest *req,
                   uint8_t *response);
 void sd_write_data(SDState *sd, uint8_t value);
 uint8_t sd_read_data(SDState *sd);
 void sd_set_cb(SDState *sd, qemu_irq readonly, qemu_irq insert);
 int sd_data_ready(SDState *sd);
-void sd_enable(SDState *sd, int enable);
+void sd_enable(SDState *sd, bool enable);
 
 #endif /* __hw_sd_h */
-- 
1.7.4.1




reply via email to

[Prev in Thread] Current Thread [Next in Thread]