Annotation of qemu/hw/ssi-sd.c, revision 1.1.1.4

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

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.