|
|
1.1 ! root 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: void *ssi_sd_init(BlockDriverState *bs) ! 194: { ! 195: ssi_sd_state *s; ! 196: ! 197: s = (ssi_sd_state *)qemu_mallocz(sizeof(ssi_sd_state)); ! 198: s->mode = SSI_SD_CMD; ! 199: s->sd = sd_init(bs, 1); ! 200: return s; ! 201: } ! 202:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.