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

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

unix.superglobalmegacorp.com

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