in core/ms_block.c [473:579]
static int h_msb_write_block(struct memstick_dev *card,
struct memstick_request **out_mrq)
{
struct msb_data *msb = memstick_get_drvdata(card);
struct memstick_request *mrq = *out_mrq = &card->current_mrq;
struct scatterlist sg[2];
u8 intreg, command;
if (mrq->error)
return msb_exit_state_machine(msb, mrq->error);
again:
switch (msb->state) {
/* HACK: Jmicon handling of TPCs between 8 and
* sizeof(memstick_request.data) is broken due to hardware
* bug in PIO mode that is used for these TPCs
* Therefore split the write
*/
case MSB_WB_SEND_WRITE_PARAMS:
if (!msb_write_regs(msb,
offsetof(struct ms_register, param),
sizeof(struct ms_param_register),
&msb->regs.param))
return 0;
msb->state = MSB_WB_SEND_WRITE_OOB;
return 0;
case MSB_WB_SEND_WRITE_OOB:
if (!msb_write_regs(msb,
offsetof(struct ms_register, extra_data),
sizeof(struct ms_extra_data_register),
&msb->regs.extra_data))
return 0;
msb->state = MSB_WB_SEND_WRITE_COMMAND;
return 0;
case MSB_WB_SEND_WRITE_COMMAND:
command = MS_CMD_BLOCK_WRITE;
memstick_init_req(mrq, MS_TPC_SET_CMD, &command, 1);
msb->state = MSB_WB_SEND_INT_REQ;
return 0;
case MSB_WB_SEND_INT_REQ:
msb->state = MSB_WB_RECEIVE_INT_REQ;
if (msb_read_int_reg(msb, -1))
return 0;
fallthrough;
case MSB_WB_RECEIVE_INT_REQ:
intreg = mrq->data[0];
msb->regs.status.interrupt = intreg;
/* errors mean out of here, and fast... */
if (intreg & (MEMSTICK_INT_CMDNAK))
return msb_exit_state_machine(msb, -EIO);
if (intreg & MEMSTICK_INT_ERR)
return msb_exit_state_machine(msb, -EBADMSG);
/* for last page we need to poll CED */
if (msb->current_page == msb->pages_in_block) {
if (intreg & MEMSTICK_INT_CED)
return msb_exit_state_machine(msb, 0);
msb->state = MSB_WB_SEND_INT_REQ;
goto again;
}
/* for non-last page we need BREQ before writing next chunk */
if (!(intreg & MEMSTICK_INT_BREQ)) {
msb->state = MSB_WB_SEND_INT_REQ;
goto again;
}
msb->int_polling = false;
msb->state = MSB_WB_SEND_WRITE_DATA;
fallthrough;
case MSB_WB_SEND_WRITE_DATA:
sg_init_table(sg, ARRAY_SIZE(sg));
if (msb_sg_copy(msb->current_sg, sg, ARRAY_SIZE(sg),
msb->current_sg_offset,
msb->page_size) < msb->page_size)
return msb_exit_state_machine(msb, -EIO);
memstick_init_req_sg(mrq, MS_TPC_WRITE_LONG_DATA, sg);
mrq->need_card_int = 1;
msb->state = MSB_WB_RECEIVE_WRITE_CONFIRMATION;
return 0;
case MSB_WB_RECEIVE_WRITE_CONFIRMATION:
msb->current_page++;
msb->current_sg_offset += msb->page_size;
msb->state = MSB_WB_SEND_INT_REQ;
goto again;
default:
BUG();
}
return 0;
}