/* Receive one block with DMA and bitswap it (chasing bitswap). */ static int receive_block(unsigned char *inbuf, long timeout) { unsigned long buf_end; if (poll_byte(timeout) != DT_START_BLOCK) { write_transfer(dummy, 1); return -1; /* not start of data */ } while (!(SSR1 & SCI_TEND)); /* wait for end of transfer */ SCR1 = 0; /* disable serial */ SSR1 = 0; /* clear all flags */ /* setup DMA channel 0 */ CHCR0 = 0; /* disable */ SAR0 = RDR1_ADDR; DAR0 = (unsigned long) inbuf; DTCR0 = BLOCK_SIZE; CHCR0 = 0x4601; /* fixed source address, RXI1, enable */ DMAOR = 0x0001; SCR1 = (SCI_RE|SCI_RIE); /* kick off DMA */ /* DMA receives 2 bytes more than DTCR2, but the last 2 bytes are not * stored. The first extra byte is available from RDR1 after the DMA ends, * the second one is lost because of the SCI overrun. However, this * behaviour conveniently discards the crc. */ yield(); /* be nice */ /* Bitswap received data, chasing the DMA pointer */ buf_end = (unsigned long)inbuf + BLOCK_SIZE; do { /* Call bitswap whenever (a multiple of) 8 bytes are * available (value optimised by experimentation). */ int swap_now = (DAR0 - (unsigned long)inbuf) & ~0x00000007; if (swap_now) { bitswap(inbuf, swap_now); inbuf += swap_now; } } while ((unsigned long)inbuf < buf_end); while (!(CHCR0 & 0x0002)); /* wait for end of DMA */ while (!(SSR1 & SCI_ORER)); /* wait for the trailing bytes */ SCR1 = 0; serial_mode = SER_DISABLED; write_transfer(dummy, 1); /* send trailer */ last_disk_activity = current_tick; return 0; }
/* Receive CID/ CSD data (16 bytes) */ static int receive_cxd(unsigned char *buf) { if (poll_byte(20) != DT_START_BLOCK) { write_transfer(dummy, 1); return -1; /* not start of data */ } read_transfer(buf, 16); write_transfer(dummy, 3); /* 2 bytes dontcare crc + 1 byte trailer */ return 0; }
static int select_card(int card_no) { mutex_lock(&mmc_mutex); led(true); last_disk_activity = current_tick; mmc_enable_int_flash_clock(card_no == 0); if (!card_info[card_no].initialized) { setup_sci1(7); /* Initial rate: 375 kbps (need <= 400 per mmc specs) */ write_transfer(dummy, 10); /* allow the card to synchronize */ while (!(SSR1 & SCI_TEND)); } if (card_no == 0) /* internal */ and_b(~0x04, &PADRH); /* assert CS */ else /* external */ and_b(~0x02, &PADRH); /* assert CS */ if (card_info[card_no].initialized) { setup_sci1(card_info[card_no].bitrate_register); return 0; } else { return initialize_card(card_no); } }
/* Send MMC command and get response. Returns R1 byte directly. * Returns further R2 or R3 bytes in *data (can be NULL for other commands) */ static unsigned char send_cmd(int cmd, unsigned long parameter, void *data) { static struct { unsigned char cmd; unsigned long parameter; const unsigned char crc7; /* fixed, valid for CMD0 only */ const unsigned char trailer; } __attribute__((packed)) command = {0x40, 0, 0x95, 0xFF}; unsigned char ret; command.cmd = cmd; command.parameter = htobe32(parameter); write_transfer((unsigned char *)&command, sizeof(command)); ret = poll_byte(20); switch (cmd) { case CMD_SEND_CSD: /* R1 response, leave open */ case CMD_SEND_CID: case CMD_READ_SINGLE_BLOCK: case CMD_READ_MULTIPLE_BLOCK: return ret; case CMD_SEND_STATUS: /* R2 response, close with dummy */ read_transfer(data, 1); break; case CMD_READ_OCR: /* R3 response, close with dummy */ read_transfer(data, 4); break; default: /* R1 response, close with dummy */ break; /* also catches block writes */ } write_transfer(dummy, 1); return ret; }
static void write_piece_readdition(output_plaintext_move_context_type *context, move_effect_journal_index_type curr) { if (move_effect_journal[curr].reason==move_effect_reason_volcanic_remember) (*context->engine->fprintf)(context->file,"%s","->v"); else { PieceIdType const id_added = GetPieceId(move_effect_journal[curr].u.piece_addition.added.flags); move_effect_journal_index_type const removal = find_piece_removal(context, curr, id_added); if (removal==move_effect_journal_index_null) write_piece_creation(context,curr); else write_transfer(context,removal,curr); } }
/* Send one block with DMA from the current write buffer, possibly preparing * the next block within the next write buffer in the background. */ static int send_block_send(unsigned char start_token, long timeout, bool prepare_next) { int rc = 0; unsigned char *curbuf = write_buffer[current_buffer]; curbuf[1] = fliptable[(signed char)start_token]; *(unsigned short *)(curbuf + BLOCK_SIZE + 2) = 0xFFFF; while (!(SSR1 & SCI_TEND)); /* wait for end of transfer */ SCR1 = 0; /* disable serial */ SSR1 = 0; /* clear all flags */ /* setup DMA channel 0 */ CHCR0 = 0; /* disable */ SAR0 = (unsigned long)(curbuf + 1); DAR0 = TDR1_ADDR; DTCR0 = BLOCK_SIZE + 3; /* start token + block + dummy crc */ CHCR0 = 0x1701; /* fixed dest. address, TXI1, enable */ DMAOR = 0x0001; SCR1 = (SCI_TE|SCI_TIE); /* kick off DMA */ if (prepare_next) send_block_prepare(); yield(); /* be nice */ while (!(CHCR0 & 0x0002)); /* wait for end of DMA */ while (!(SSR1 & SCI_TEND)); /* wait for end of transfer */ SCR1 = 0; serial_mode = SER_DISABLED; if ((poll_busy(timeout) & 0x1F) != 0x05) /* something went wrong */ rc = -1; write_transfer(dummy, 1); last_disk_activity = current_tick; return rc; }