It will only be used if start bit and databusy callbacks were initialized by user of SD card model.
Signed-off-by: Igor Mitsyanko <i.mitsya...@gmail.com> --- hw/sd/sd.c | 85 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 77 insertions(+), 8 deletions(-) diff --git a/hw/sd/sd.c b/hw/sd/sd.c index a0bbbaa..659ec56 100644 --- a/hw/sd/sd.c +++ b/hw/sd/sd.c @@ -685,6 +685,44 @@ static void sd_lock_command(SDState *sd) sd->card_status &= ~CARD_IS_LOCKED; } +static void sd_bdrv_read_done(void *opaque, int ret) +{ + SDState *sd = opaque; + uint32_t io_len, offset; + uint64_t end_sector; + + DPRINTF("sd_bdrv_read_done ret = %d, \n", ret); + sd->aiocb = NULL; + + if (ret != 0) { + return; + } + + if (sd->state != sd_sendingdata_state) { + DPRINTF("Transfer was aborted\n"); + return; + } + + io_len = (sd->ocr & (1 << 30)) ? 512 : sd->blk_len; + end_sector = (sd->data_start + io_len - 1) >> BDRV_SECTOR_BITS; + offset = (sd->data_start + sd->transf_cnt) & ~BDRV_SECTOR_MASK; + + if (end_sector > + (sd->data_start + sd->transf_cnt) >> BDRV_SECTOR_BITS) { + memcpy(sd->data, sd->buf + offset, BDRV_SECTOR_SIZE - offset); + sd->transf_cnt += BDRV_SECTOR_SIZE - offset; + sd->aiocb = bdrv_aio_readv(sd->bdrv, end_sector, &sd->qiov, 1, + sd_bdrv_read_done, sd); + return; + } else { + memcpy(sd->data + sd->transf_cnt, sd->buf + offset, + io_len - sd->transf_cnt); + sd->transf_cnt += io_len - sd->transf_cnt; + } + + qemu_irq_raise(sd->start_bit_cb); +} + static sd_rsp_type_t sd_normal_command(SDState *sd, SDRequest req) { @@ -891,8 +929,13 @@ static sd_rsp_type_t sd_normal_command(SDState *sd, sd->data_start = req.arg; sd->data_offset = 0; - if (sd->data_start + sd->blk_len > sd->size) + if (sd->data_start + sd->blk_len > sd->size) { sd->card_status |= ADDRESS_ERROR; + } else if (sd->iov.iov_base) { + sd->aiocb = bdrv_aio_readv(sd->bdrv, + sd->data_start >> BDRV_SECTOR_BITS, + &sd->qiov, 1, sd_bdrv_read_done, sd); + } return sd_r0; default: @@ -904,6 +947,11 @@ static sd_rsp_type_t sd_normal_command(SDState *sd, switch (sd->state) { case sd_sendingdata_state: sd->state = sd_transfer_state; + sd->transf_cnt = 0; + if (sd->aiocb) { + bdrv_aio_cancel(sd->aiocb); + sd->aiocb = NULL; + } return sd_r1b; case sd_receivingdata_state: @@ -969,8 +1017,13 @@ static sd_rsp_type_t sd_normal_command(SDState *sd, sd->data_start = addr; sd->data_offset = 0; - if (sd->data_start + sd->blk_len > sd->size) + if (sd->data_start + sd->blk_len > sd->size) { sd->card_status |= ADDRESS_ERROR; + } else { + sd->aiocb = bdrv_aio_readv(sd->bdrv, + sd->data_start >> BDRV_SECTOR_BITS, + &sd->qiov, 1, sd_bdrv_read_done, sd); + } return sd_r1; default: @@ -985,8 +1038,13 @@ static sd_rsp_type_t sd_normal_command(SDState *sd, sd->data_start = addr; sd->data_offset = 0; - if (sd->data_start + sd->blk_len > sd->size) + if (sd->data_start + sd->blk_len > sd->size) { sd->card_status |= ADDRESS_ERROR; + } else { + sd->aiocb = bdrv_aio_readv(sd->bdrv, + sd->data_start >> BDRV_SECTOR_BITS, + &sd->qiov, 1, sd_bdrv_read_done, sd); + } return sd_r1; default: @@ -1706,16 +1764,21 @@ uint8_t sd_read_data(SDState *sd) break; case 11: /* CMD11: READ_DAT_UNTIL_STOP */ - if (sd->data_offset == 0) + if (sd->data_offset == 0 && sd->iov.iov_base == NULL) { BLK_READ_BLOCK(sd->data_start, io_len); + } ret = sd->data[sd->data_offset ++]; if (sd->data_offset >= io_len) { sd->data_start += io_len; sd->data_offset = 0; + sd->transf_cnt = 0; if (sd->data_start + io_len > sd->size) { sd->card_status |= ADDRESS_ERROR; - break; + } else if (sd->iov.iov_base) { + sd->aiocb = bdrv_aio_readv(sd->bdrv, + sd->data_start >> BDRV_SECTOR_BITS, + &sd->qiov, 1, sd_bdrv_read_done, sd); } } break; @@ -1728,8 +1791,9 @@ uint8_t sd_read_data(SDState *sd) break; case 17: /* CMD17: READ_SINGLE_BLOCK */ - if (sd->data_offset == 0) + if (sd->data_offset == 0 && sd->iov.iov_base == NULL) { BLK_READ_BLOCK(sd->data_start, io_len); + } ret = sd->data[sd->data_offset ++]; if (sd->data_offset >= io_len) @@ -1737,16 +1801,21 @@ uint8_t sd_read_data(SDState *sd) break; case 18: /* CMD18: READ_MULTIPLE_BLOCK */ - if (sd->data_offset == 0) + if (sd->data_offset == 0 && sd->iov.iov_base == NULL) { BLK_READ_BLOCK(sd->data_start, io_len); + } ret = sd->data[sd->data_offset ++]; if (sd->data_offset >= io_len) { sd->data_start += io_len; sd->data_offset = 0; + sd->transf_cnt = 0; if (sd->data_start + io_len > sd->size) { sd->card_status |= ADDRESS_ERROR; - break; + } else if (sd->iov.iov_base) { + sd->aiocb = bdrv_aio_readv(sd->bdrv, + sd->data_start >> BDRV_SECTOR_BITS, + &sd->qiov, 1, sd_bdrv_read_done, sd); } } break; -- 1.8.1.4