int pwd_len;
int function_group[6];
+ int spi;
int current_cmd;
int blk_written;
uint32_t data_start;
return sd_crc7(buffer, 5) != req->crc; /* TODO */
}
-void sd_response_r1_make(SDState *sd,
- uint8_t *response, uint32_t last_status)
+static void sd_response_r1_make(SDState *sd,
+ uint8_t *response, uint32_t last_status)
{
uint32_t mask = CARD_STATUS_B ^ ILLEGAL_COMMAND;
uint32_t status;
response[3] = (status >> 0) & 0xff;
}
-void sd_response_r3_make(SDState *sd, uint8_t *response)
+static void sd_response_r3_make(SDState *sd, uint8_t *response)
{
response[0] = (sd->ocr >> 24) & 0xff;
response[1] = (sd->ocr >> 16) & 0xff;
response[3] = (sd->ocr >> 0) & 0xff;
}
-void sd_response_r6_make(SDState *sd, uint8_t *response)
+static void sd_response_r6_make(SDState *sd, uint8_t *response)
{
uint16_t arg;
uint16_t status;
qemu_free(sd->wp_groups);
sd->wp_switch = bdrv_is_read_only(bdrv);
sd->wp_groups = (int *) qemu_mallocz(sizeof(int) * sect);
- memset(sd->wp_groups, 0, sizeof(int) * sect);
memset(sd->function_group, 0, sizeof(int) * 6);
sd->erase_start = 0;
sd->erase_end = 0;
}
}
-SDState *sd_init(BlockDriverState *bs)
+/* We do not model the chip select pin, so allow the board to select
+ whether card should be in SSI or MMC/SD mode. It is also up to the
+ board to ensure that ssi transfers only occur when the chip select
+ is asserted. */
+SDState *sd_init(BlockDriverState *bs, int is_spi)
{
SDState *sd;
sd = (SDState *) qemu_mallocz(sizeof(SDState));
+ sd->spi = is_spi;
sd_reset(sd, bs);
bdrv_set_change_cb(sd->bdrv, sd_cardchange, sd);
return sd;
case 0: /* CMD0: GO_IDLE_STATE */
switch (sd->state) {
case sd_inactive_state:
- return sd_r0;
+ return sd->spi ? sd_r1 : sd_r0;
default:
sd->state = sd_idle_state;
sd_reset(sd, sd->bdrv);
- return sd_r0;
+ return sd->spi ? sd_r1 : sd_r0;
}
break;
+ case 1: /* CMD1: SEND_OP_CMD */
+ if (!sd->spi)
+ goto bad_cmd;
+
+ sd->state = sd_transfer_state;
+ return sd_r1;
+
case 2: /* CMD2: ALL_SEND_CID */
+ if (sd->spi)
+ goto bad_cmd;
switch (sd->state) {
case sd_ready_state:
sd->state = sd_identification_state;
break;
case 3: /* CMD3: SEND_RELATIVE_ADDR */
+ if (sd->spi)
+ goto bad_cmd;
switch (sd->state) {
case sd_identification_state:
case sd_standby_state:
break;
case 4: /* CMD4: SEND_DSR */
+ if (sd->spi)
+ goto bad_cmd;
switch (sd->state) {
case sd_standby_state:
break;
break;
case 6: /* CMD6: SWITCH_FUNCTION */
+ if (sd->spi)
+ goto bad_cmd;
switch (sd->mode) {
case sd_data_transfer_mode:
sd_function_switch(sd, req.arg);
break;
case 7: /* CMD7: SELECT/DESELECT_CARD */
+ if (sd->spi)
+ goto bad_cmd;
switch (sd->state) {
case sd_standby_state:
if (sd->rca != rca)
return sd_r2_s;
+ case sd_transfer_state:
+ if (!sd->spi)
+ break;
+ sd->state = sd_sendingdata_state;
+ memcpy(sd->data, sd->csd, 16);
+ sd->data_start = req.arg;
+ sd->data_offset = 0;
+ return sd_r1;
+
default:
break;
}
return sd_r2_i;
+ case sd_transfer_state:
+ if (!sd->spi)
+ break;
+ sd->state = sd_sendingdata_state;
+ memcpy(sd->data, sd->cid, 16);
+ sd->data_start = req.arg;
+ sd->data_offset = 0;
+ return sd_r1;
+
default:
break;
}
break;
case 11: /* CMD11: READ_DAT_UNTIL_STOP */
+ if (sd->spi)
+ goto bad_cmd;
switch (sd->state) {
case sd_transfer_state:
sd->state = sd_sendingdata_state;
break;
case 15: /* CMD15: GO_INACTIVE_STATE */
+ if (sd->spi)
+ goto bad_cmd;
switch (sd->mode) {
case sd_data_transfer_mode:
if (sd->rca != rca)
/* Block write commands (Class 4) */
case 24: /* CMD24: WRITE_SINGLE_BLOCK */
+ if (sd->spi)
+ goto unimplemented_cmd;
switch (sd->state) {
case sd_transfer_state:
+ /* Writing in SPI mode not implemented. */
+ if (sd->spi)
+ break;
sd->state = sd_receivingdata_state;
sd->data_start = req.arg;
sd->data_offset = 0;
break;
case 25: /* CMD25: WRITE_MULTIPLE_BLOCK */
+ if (sd->spi)
+ goto unimplemented_cmd;
switch (sd->state) {
case sd_transfer_state:
+ /* Writing in SPI mode not implemented. */
+ if (sd->spi)
+ break;
sd->state = sd_receivingdata_state;
sd->data_start = req.arg;
sd->data_offset = 0;
break;
case 26: /* CMD26: PROGRAM_CID */
+ if (sd->spi)
+ goto bad_cmd;
switch (sd->state) {
case sd_transfer_state:
sd->state = sd_receivingdata_state;
break;
case 27: /* CMD27: PROGRAM_CSD */
+ if (sd->spi)
+ goto unimplemented_cmd;
switch (sd->state) {
case sd_transfer_state:
sd->state = sd_receivingdata_state;
/* Lock card commands (Class 7) */
case 42: /* CMD42: LOCK_UNLOCK */
+ if (sd->spi)
+ goto unimplemented_cmd;
switch (sd->state) {
case sd_transfer_state:
sd->state = sd_receivingdata_state;
break;
default:
+ bad_cmd:
sd->card_status |= ILLEGAL_COMMAND;
printf("SD: Unknown CMD%i\n", req.cmd);
return sd_r0;
+
+ unimplemented_cmd:
+ /* Commands that are recognised but not yet implemented in SPI mode. */
+ sd->card_status |= ILLEGAL_COMMAND;
+ printf ("SD: CMD%i not implemented in SPI mode\n", req.cmd);
+ return sd_r0;
}
sd->card_status |= ILLEGAL_COMMAND;
break;
case 41: /* ACMD41: SD_APP_OP_COND */
+ if (sd->spi) {
+ /* SEND_OP_CMD */
+ sd->state = sd_transfer_state;
+ return sd_r1;
+ }
switch (sd->state) {
case sd_idle_state:
/* We accept any voltage. 10000 V is nothing. */
sd->state = sd_transfer_state;
break;
+ case 9: /* CMD9: SEND_CSD */
+ case 10: /* CMD10: SEND_CID */
+ ret = sd->data[sd->data_offset ++];
+
+ if (sd->data_offset >= 16)
+ sd->state = sd_transfer_state;
+ break;
+
case 11: /* CMD11: READ_DAT_UNTIL_STOP */
if (sd->data_offset == 0)
BLK_READ_BLOCK(sd->data_start, sd->blk_len);