|
|
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:
1.1.1.2 ! root 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:
1.1 root 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);
1.1.1.2 ! root 237: register_savevm("ssi_sd", -1, 1, ssi_sd_save, ssi_sd_load, s);
1.1 root 238: return s;
239: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.