/* 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;
}
示例#5
0
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;
}