symbian-qemu-0.9.1-12/qemu-symbian-svp/hw/ssi-sd.c
changeset 1 2fb8b9db1c86
equal deleted inserted replaced
0:ffa851df0825 1:2fb8b9db1c86
       
     1 /*
       
     2  * SSI to SD card adapter.
       
     3  *
       
     4  * Copyright (c) 2007 CodeSourcery.
       
     5  * Written by Paul Brook
       
     6  *
       
     7  * This code is licenced under the GPL.
       
     8  */
       
     9 
       
    10 #include "hw.h"
       
    11 #include "sd.h"
       
    12 
       
    13 //#define DEBUG_SSI_SD 1
       
    14 
       
    15 #ifdef DEBUG_SSI_SD
       
    16 #define DPRINTF(fmt, args...) \
       
    17 do { printf("ssi_sd: " fmt , ##args); } while (0)
       
    18 #define BADF(fmt, args...) \
       
    19 do { fprintf(stderr, "ssi_sd: error: " fmt , ##args); exit(1);} while (0)
       
    20 #else
       
    21 #define DPRINTF(fmt, args...) do {} while(0)
       
    22 #define BADF(fmt, args...) \
       
    23 do { fprintf(stderr, "ssi_sd: error: " fmt , ##args);} while (0)
       
    24 #endif
       
    25 
       
    26 typedef enum {
       
    27     SSI_SD_CMD,
       
    28     SSI_SD_CMDARG,
       
    29     SSI_SD_RESPONSE,
       
    30     SSI_SD_DATA_START,
       
    31     SSI_SD_DATA_READ,
       
    32 } ssi_sd_mode;
       
    33 
       
    34 typedef struct {
       
    35     ssi_sd_mode mode;
       
    36     int cmd;
       
    37     uint8_t cmdarg[4];
       
    38     uint8_t response[5];
       
    39     int arglen;
       
    40     int response_pos;
       
    41     int stopping;
       
    42     SDState *sd;
       
    43 } ssi_sd_state;
       
    44 
       
    45 /* State word bits.  */
       
    46 #define SSI_SDR_LOCKED          0x0001
       
    47 #define SSI_SDR_WP_ERASE        0x0002
       
    48 #define SSI_SDR_ERROR           0x0004
       
    49 #define SSI_SDR_CC_ERROR        0x0008
       
    50 #define SSI_SDR_ECC_FAILED      0x0010
       
    51 #define SSI_SDR_WP_VIOLATION    0x0020
       
    52 #define SSI_SDR_ERASE_PARAM     0x0040
       
    53 #define SSI_SDR_OUT_OF_RANGE    0x0080
       
    54 #define SSI_SDR_IDLE            0x0100
       
    55 #define SSI_SDR_ERASE_RESET     0x0200
       
    56 #define SSI_SDR_ILLEGAL_COMMAND 0x0400
       
    57 #define SSI_SDR_COM_CRC_ERROR   0x0800
       
    58 #define SSI_SDR_ERASE_SEQ_ERROR 0x1000
       
    59 #define SSI_SDR_ADDRESS_ERROR   0x2000
       
    60 #define SSI_SDR_PARAMETER_ERROR 0x4000
       
    61 
       
    62 int ssi_sd_xfer(void *opaque, int val)
       
    63 {
       
    64     ssi_sd_state *s = (ssi_sd_state *)opaque;
       
    65 
       
    66     /* Special case: allow CMD12 (STOP TRANSMISSION) while reading data.  */
       
    67     if (s->mode == SSI_SD_DATA_READ && val == 0x4d) {
       
    68         s->mode = SSI_SD_CMD;
       
    69         /* There must be at least one byte delay before the card responds.  */
       
    70         s->stopping = 1;
       
    71     }
       
    72 
       
    73     switch (s->mode) {
       
    74     case SSI_SD_CMD:
       
    75         if (val == 0xff) {
       
    76             DPRINTF("NULL command\n");
       
    77             return 0xff;
       
    78         }
       
    79         s->cmd = val & 0x3f;
       
    80         s->mode = SSI_SD_CMDARG;
       
    81         s->arglen = 0;
       
    82         return 0xff;
       
    83     case SSI_SD_CMDARG:
       
    84         if (s->arglen == 4) {
       
    85             struct sd_request_s request;
       
    86             uint8_t longresp[16];
       
    87             /* FIXME: Check CRC.  */
       
    88             request.cmd = s->cmd;
       
    89             request.arg = (s->cmdarg[0] << 24) | (s->cmdarg[1] << 16)
       
    90                            | (s->cmdarg[2] << 8) | s->cmdarg[3];
       
    91             DPRINTF("CMD%d arg 0x%08x\n", s->cmd, request.arg);
       
    92             s->arglen = sd_do_command(s->sd, &request, longresp);
       
    93             if (s->arglen <= 0) {
       
    94                 s->arglen = 1;
       
    95                 s->response[0] = 4;
       
    96                 DPRINTF("SD command failed\n");
       
    97             } else if (s->cmd == 58) {
       
    98                 /* CMD58 returns R3 response (OCR)  */
       
    99                 DPRINTF("Returned OCR\n");
       
   100                 s->arglen = 5;
       
   101                 s->response[0] = 1;
       
   102                 memcpy(&s->response[1], longresp, 4);
       
   103             } else if (s->arglen != 4) {
       
   104                 BADF("Unexpected response to cmd %d\n", s->cmd);
       
   105                 /* Illegal command is about as near as we can get.  */
       
   106                 s->arglen = 1;
       
   107                 s->response[0] = 4;
       
   108             } else {
       
   109                 /* All other commands return status.  */
       
   110                 uint32_t cardstatus;
       
   111                 uint16_t status;
       
   112                 /* CMD13 returns a 2-byte statuse work. Other commands
       
   113                    only return the first byte.  */
       
   114                 s->arglen = (s->cmd == 13) ? 2 : 1;
       
   115                 cardstatus = (longresp[0] << 24) | (longresp[1] << 16)
       
   116                              | (longresp[2] << 8) | longresp[3];
       
   117                 status = 0;
       
   118                 if (((cardstatus >> 9) & 0xf) < 4)
       
   119                     status |= SSI_SDR_IDLE;
       
   120                 if (cardstatus & ERASE_RESET)
       
   121                     status |= SSI_SDR_ERASE_RESET;
       
   122                 if (cardstatus & ILLEGAL_COMMAND)
       
   123                     status |= SSI_SDR_ILLEGAL_COMMAND;
       
   124                 if (cardstatus & COM_CRC_ERROR)
       
   125                     status |= SSI_SDR_COM_CRC_ERROR;
       
   126                 if (cardstatus & ERASE_SEQ_ERROR)
       
   127                     status |= SSI_SDR_ERASE_SEQ_ERROR;
       
   128                 if (cardstatus & ADDRESS_ERROR)
       
   129                     status |= SSI_SDR_ADDRESS_ERROR;
       
   130                 if (cardstatus & CARD_IS_LOCKED)
       
   131                     status |= SSI_SDR_LOCKED;
       
   132                 if (cardstatus & (LOCK_UNLOCK_FAILED | WP_ERASE_SKIP))
       
   133                     status |= SSI_SDR_WP_ERASE;
       
   134                 if (cardstatus & SD_ERROR)
       
   135                     status |= SSI_SDR_ERROR;
       
   136                 if (cardstatus & CC_ERROR)
       
   137                     status |= SSI_SDR_CC_ERROR;
       
   138                 if (cardstatus & CARD_ECC_FAILED)
       
   139                     status |= SSI_SDR_ECC_FAILED;
       
   140                 if (cardstatus & WP_VIOLATION)
       
   141                     status |= SSI_SDR_WP_VIOLATION;
       
   142                 if (cardstatus & ERASE_PARAM)
       
   143                     status |= SSI_SDR_ERASE_PARAM;
       
   144                 if (cardstatus & (OUT_OF_RANGE | CID_CSD_OVERWRITE))
       
   145                     status |= SSI_SDR_OUT_OF_RANGE;
       
   146                 /* ??? Don't know what Parameter Error really means, so
       
   147                    assume it's set if the second byte is nonzero.  */
       
   148                 if (status & 0xff)
       
   149                     status |= SSI_SDR_PARAMETER_ERROR;
       
   150                 s->response[0] = status >> 8;
       
   151                 s->response[1] = status;
       
   152                 DPRINTF("Card status 0x%02x\n", status);
       
   153             }
       
   154             s->mode = SSI_SD_RESPONSE;
       
   155             s->response_pos = 0;
       
   156         } else {
       
   157             s->cmdarg[s->arglen++] = val;
       
   158         }
       
   159         return 0xff;
       
   160     case SSI_SD_RESPONSE:
       
   161         if (s->stopping) {
       
   162             s->stopping = 0;
       
   163             return 0xff;
       
   164         }
       
   165         if (s->response_pos < s->arglen) {
       
   166             DPRINTF("Response 0x%02x\n", s->response[s->response_pos]);
       
   167             return s->response[s->response_pos++];
       
   168         }
       
   169         if (sd_data_ready(s->sd)) {
       
   170             DPRINTF("Data read\n");
       
   171             s->mode = SSI_SD_DATA_START;
       
   172         } else {
       
   173             DPRINTF("End of command\n");
       
   174             s->mode = SSI_SD_CMD;
       
   175         }
       
   176         return 0xff;
       
   177     case SSI_SD_DATA_START:
       
   178         DPRINTF("Start read block\n");
       
   179         s->mode = SSI_SD_DATA_READ;
       
   180         return 0xfe;
       
   181     case SSI_SD_DATA_READ:
       
   182         val = sd_read_data(s->sd);
       
   183         if (!sd_data_ready(s->sd)) {
       
   184             DPRINTF("Data read end\n");
       
   185             s->mode = SSI_SD_CMD;
       
   186         }
       
   187         return val;
       
   188     }
       
   189     /* Should never happen.  */
       
   190     return 0xff;
       
   191 }
       
   192 
       
   193 static void ssi_sd_save(QEMUFile *f, void *opaque)
       
   194 {
       
   195     ssi_sd_state *s = (ssi_sd_state *)opaque;
       
   196     int i;
       
   197 
       
   198     qemu_put_be32(f, s->mode);
       
   199     qemu_put_be32(f, s->cmd);
       
   200     for (i = 0; i < 4; i++)
       
   201         qemu_put_be32(f, s->cmdarg[i]);
       
   202     for (i = 0; i < 5; i++)
       
   203         qemu_put_be32(f, s->response[i]);
       
   204     qemu_put_be32(f, s->arglen);
       
   205     qemu_put_be32(f, s->response_pos);
       
   206     qemu_put_be32(f, s->stopping);
       
   207 }
       
   208 
       
   209 static int ssi_sd_load(QEMUFile *f, void *opaque, int version_id)
       
   210 {
       
   211     ssi_sd_state *s = (ssi_sd_state *)opaque;
       
   212     int i;
       
   213 
       
   214     if (version_id != 1)
       
   215         return -EINVAL;
       
   216 
       
   217     s->mode = qemu_get_be32(f);
       
   218     s->cmd = qemu_get_be32(f);
       
   219     for (i = 0; i < 4; i++)
       
   220         s->cmdarg[i] = qemu_get_be32(f);
       
   221     for (i = 0; i < 5; i++)
       
   222         s->response[i] = qemu_get_be32(f);
       
   223     s->arglen = qemu_get_be32(f);
       
   224     s->response_pos = qemu_get_be32(f);
       
   225     s->stopping = qemu_get_be32(f);
       
   226 
       
   227     return 0;
       
   228 }
       
   229 
       
   230 void *ssi_sd_init(BlockDriverState *bs)
       
   231 {
       
   232     ssi_sd_state *s;
       
   233 
       
   234     s = (ssi_sd_state *)qemu_mallocz(sizeof(ssi_sd_state));
       
   235     s->mode = SSI_SD_CMD;
       
   236     s->sd = sd_init(bs, 1);
       
   237     register_savevm("ssi_sd", -1, 1, ssi_sd_save, ssi_sd_load, s);
       
   238     return s;
       
   239 }