diff --git a/cpu/lpc2387/Jamfile b/cpu/lpc2387/Jamfile index 888272e82..bacd10a74 100644 --- a/cpu/lpc2387/Jamfile +++ b/cpu/lpc2387/Jamfile @@ -27,11 +27,13 @@ SubDir TOP cpu lpc2387 ; -Module cpu : cpu.c lpc2387-lpm.c lpc23xx-iap.c ; +Module cpu : cpu.c lpc2387-lpm.c ; UseModule cpu ; Module rtc : lpc2387-rtc.c ; Module gpioint : lpc2387-gpioint.c ; +Module adc : lpc2387-adc.c ; +Module mci : lpc2387-mci.c asmfunc.s ; Objects startup.s ; diff --git a/cpu/lpc2387/asmfunc.s b/cpu/lpc2387/asmfunc.s new file mode 100644 index 000000000..4bdb45468 --- /dev/null +++ b/cpu/lpc2387/asmfunc.s @@ -0,0 +1,96 @@ +@-----------------------------------------------------------@ +@ Fast Block Copy (declared in diskio.h) +@-----------------------------------------------------------@ + +.global Copy_un2al +.arm +Copy_un2al: + STMFD SP!, {R4-R8} + ANDS IP, R1, #3 + BEQ lb_align + + BIC R1, #3 + MOV IP, IP, LSL #3 + RSB R8, IP, #32 + LDMIA R1!, {R7} +lb_l1: MOV R3, R7 + LDMIA R1!, {R4-R7} + MOV R3, R3, LSR IP + ORR R3, R3, R4, LSL R8 + MOV R4, R4, LSR IP + ORR R4, R4, R5, LSL R8 + MOV R5, R5, LSR IP + ORR R5, R5, R6, LSL R8 + MOV R6, R6, LSR IP + ORR R6, R6, R7, LSL R8 + SUBS R2, R2, #16 + STMIA R0!, {R3-R6} + BNE lb_l1 + LDMFD SP!, {R4-R8} + BX LR + +lb_align: + LDMIA R1!, {R3-R6} + SUBS R2, R2, #16 + STMIA R0!, {R3-R6} + BNE lb_align + LDMFD SP!, {R4-R8} + BX LR + + +.global Copy_al2un +.arm +Copy_al2un: + STMFD SP!, {R4-R8} + ANDS IP, R0, #3 + BEQ sb_align + + MOV IP, IP, LSL #3 + RSB R8, IP, #32 + + LDMIA R1!, {R4-R7} +sb_p1: STRB R4, [R0], #1 + MOV R4, R4, LSR #8 + TST R0, #3 + BNE sb_p1 + ORR R4, R4, R5, LSL IP + MOV R5, R5, LSR R8 + ORR R5, R5, R6, LSL IP + MOV R6, R6, LSR R8 + ORR R6, R6, R7, LSL IP + SUBS R2, R2, #16 + STMIA R0!, {R4-R6} + +sb_l1: MOV R3, R7 + LDMIA R1!, {R4-R7} + MOV R3, R3, LSR R8 + ORR R3, R3, R4, LSL IP + MOV R4, R4, LSR R8 + ORR R4, R4, R5, LSL IP + MOV R5, R5, LSR R8 + ORR R5, R5, R6, LSL IP + MOV R6, R6, LSR R8 + ORR R6, R6, R7, LSL IP + SUBS R2, R2, #16 + STMIA R0!, {R3-R6} + BNE sb_l1 + + MOV R7, R7, LSR R8 +sb_p2: SUBS IP, IP, #8 + STRB R7, [R0], #1 + MOV R7, R7, LSR #8 + BNE sb_p2 + + LDMFD SP!, {R4-R8} + BX LR + +sb_align: + LDMIA R1!, {R3-R6} + SUBS R2, #16 + STMIA R0!, {R3-R6} + BNE sb_align + LDMFD SP!, {R4-R8} + BX LR + +.end + diff --git a/cpu/lpc2387/lpc2387-mci.c b/cpu/lpc2387/lpc2387-mci.c new file mode 100644 index 000000000..f94174d13 --- /dev/null +++ b/cpu/lpc2387/lpc2387-mci.c @@ -0,0 +1,890 @@ +/*-----------------------------------------------------------------------*/ +/* MMCv3/SDv1/SDv2 (in native mode via MCI) control module (C)ChaN, 2010 */ +/*-----------------------------------------------------------------------*/ +/* This program is opened under license policy of following trems. +/ +/ Copyright (C) 2010, ChaN, all right reserved. +/ +/ * This program is a free software and there is NO WARRANTY. +/ * No restriction on use. You can use, modify and redistribute it for +/ personal, non-profit or commercial use UNDER YOUR RESPONSIBILITY. +/ * Redistributions of source code must retain the above copyright notice. +/ +/---------------------------------------------------------------------------*/ + +#include +#include "lpc23xx.h" +#include "VIC.h" +#include "hwtimer.h" +#include "diskio.h" + +#define ENABLE_DEBUG +#include "debug.h" + +extern unsigned long hwtimer_now(void); + +/* --- MCI configurations --- */ +#define N_BUF 4 /* Block transfer FIFO depth (>= 2) */ +#define USE_4BIT 1 /* Use wide bus mode if SDC is detected */ +#define PCLK 36000000UL /* PCLK supplied to MCI module */ +#define MCLK_ID 400000UL /* MCICLK for ID state (100k-400k) */ +#define MCLK_RW 18000000UL /* MCICLK for data transfer (PCLK divided by even number) */ + +/* This MCI driver assumes that MCLK_RW is CCLK/4 or slower. If block buffer underrun/overrun +/ occured due to any interrupt by higher priority process or slow external memory, increasing +/ N_BUF or decreasing MCLK_RW will solve it. */ + + +/* ----- Port definitions ----- */ +#define SOCKINS !(FIO0PIN2 & 0x20) /* Card detect switch */ +#define SOCKWP (FIO0PIN2 & 0x04) /* Write protect switch */ + + +/* ----- MMC/SDC command ----- */ +#define CMD0 (0) /* GO_IDLE_STATE */ +#define CMD1 (1) /* SEND_OP_COND (MMC) */ +#define CMD2 (2) /* ALL_SEND_CID */ +#define CMD3 (3) /* SEND_RELATIVE_ADDR */ +#define ACMD6 (6|0x80) /* SET_BUS_WIDTH (SDC) */ +#define CMD7 (7) /* SELECT_CARD */ +#define CMD8 (8) /* SEND_IF_COND */ +#define CMD9 (9) /* SEND_CSD */ +#define CMD10 (10) /* SEND_CID */ +#define CMD12 (12) /* STOP_TRANSMISSION */ +#define CMD13 (13) /* SEND_STATUS */ +#define ACMD13 (13|0x80) /* SD_STATUS (SDC) */ +#define CMD16 (16) /* SET_BLOCKLEN */ +#define CMD17 (17) /* READ_SINGLE_BLOCK */ +#define CMD18 (18) /* READ_MULTIPLE_BLOCK */ +#define CMD23 (23) /* SET_BLK_COUNT (MMC) */ +#define ACMD23 (23|0x80) /* SET_WR_BLK_ERASE_COUNT (SDC) */ +#define CMD24 (24) /* WRITE_BLOCK */ +#define CMD25 (25) /* WRITE_MULTIPLE_BLOCK */ +#define CMD32 (32) /* ERASE_ER_BLK_START */ +#define CMD33 (33) /* ERASE_ER_BLK_END */ +#define CMD38 (38) /* ERASE */ +#define ACMD41 (41|0x80) /* SEND_OP_COND (SDC) */ +#define CMD55 (55) /* APP_CMD */ + +/* Card type flags (CardType) */ +#define CT_MMC 0x01 /* MMC ver 3 */ +#define CT_SD1 0x02 /* SD ver 1 */ +#define CT_SD2 0x04 /* SD ver 2 */ +#define CT_SDC (CT_SD1|CT_SD2) /* SD */ +#define CT_BLOCK 0x08 /* Block addressing */ + + +/*-------------------------------------------------------------------------- + + Module Private Functions + +---------------------------------------------------------------------------*/ + +static volatile DSTATUS Stat = STA_NOINIT; /* Disk status */ + +static unsigned short CardRCA; /* Assigned RCA */ +static unsigned char CardType, /* Card type flag */ + CardInfo[16+16+4]; /* CSD(16), CID(16), OCR(4) */ + +static volatile unsigned char XferStat, /* b3:MCI error, b2:Overrun, b1:Write, b0:Read */ + XferWc, /* Write block counter */ + XferWp, XferRp; /* R/W index of block FIFO */ + +static unsigned long DmaBuff[N_BUF][128] __attribute__ ((section(".usbdata"))); /* Block transfer FIFO */ +static unsigned long LinkList [N_BUF][4] __attribute__ ((section(".usbdata"))); /* DMA link list */ + +void Isr_MCI (void) __attribute__ ((interrupt("IRQ"))); +void Isr_GPDMA (void) __attribute__ ((interrupt("IRQ"))); + +/*-----------------------------------------------------------------------*/ +/* Interrupt service routine for data transfer */ +/*-----------------------------------------------------------------------*/ + +void Isr_MCI (void) { + unsigned long ms; + unsigned char n, xs; + + ms = MCI_STATUS & 0x073A; /* Clear MCI interrupt status */ + MCI_CLEAR = ms; + + xs = XferStat; + if (ms & 0x400) { /* A block transfer completed (DataBlockEnd) */ + if (xs & 1) { /* In card read operation */ + if (ms & 0x100) /* When last block is received (DataEnd), */ + GPDMA_SOFT_BREQ = 0x10; /* Pop off remaining data in the MCIFIFO */ + n = (XferWp + 1) % N_BUF; /* Next write buffer */ + XferWp = n; + if (n == XferRp) xs |= 4; /* Check block overrun */ + } + else { /* In card write operation */ + n = (XferRp + 1) % N_BUF; /* Next read buffer */ + XferRp = n; + if (n == XferWp) xs |= 4; /* Check block underrun */ + } + } + else { /* An MCI error occured (not DataBlockEnd) */ + xs |= 8; + } + + XferStat = xs; + + VICVectAddr = 0; +} + +void Isr_GPDMA (void) { + if(GPDMA_INT_TCSTAT & BIT0) + { + GPDMA_INT_TCCLR = 0x01; /* Clear GPDMA interrupt flag */ + if (XferStat & 2) + { + /* In write operation */ + if (--XferWc == N_BUF) /* Terminate LLI */ + { + LinkList[XferRp % N_BUF][2] = 0; + } + } + } + else + { + GPDMA_INT_TCCLR = 0x3; + } + + VICVectAddr = 0; +} + + +/*-----------------------------------------------------------------------*/ +/* Ready for data reception */ +/*-----------------------------------------------------------------------*/ + +/** + * @param blks Number of blocks to receive (1..127) + * @param bs Block size (64 or 512) + * */ +static void ready_reception (unsigned int blks, unsigned int bs) { + unsigned int n; + unsigned long dma_ctrl; + + /* ------ Setting up GPDMA Ch-0 ------ */ + GPDMA_CH0_CFG &= 0xFFF80420; /* Disable ch-0 */ + GPDMA_INT_TCCLR = 0x01; /* Clear interrupt flag */ + dma_ctrl = 0x88492000 | (bs / 4); /* 1_000_1_0_00_010_010_010_010_************ */ + + /* Create link list */ + for (n = 0; n < N_BUF; n++) { + LinkList[n][0] = (unsigned long)&MCI_FIFO; + LinkList[n][1] = (unsigned long)DmaBuff[n]; + LinkList[n][2] = (unsigned long)LinkList[(n + 1) % N_BUF]; + LinkList[n][3] = dma_ctrl; + } + + /* Load first LLI */ + GPDMA_CH0_SRC = LinkList[0][0]; + GPDMA_CH0_DEST = LinkList[0][1]; + GPDMA_CH0_LLI = LinkList[0][2]; + GPDMA_CH0_CTRL = LinkList[0][3]; + + /* Enable ch-0 */ + GPDMA_CH0_CFG |= 0x19009; /* *************_0_0_1_1_0_010_*_0000_*_0100_1 */ + + /* --------- Setting up MCI ---------- */ + + XferRp = 0; XferWp = 0; /* Block FIFO R/W index */ + XferStat = 1; /* Transfer status: MCI --> Memory */ + + MCI_DATA_LEN = bs * blks; /* Set total data length */ + MCI_DATA_TMR = (unsigned long)(MCLK_RW * 0.2); /* Data timer: 0.2sec */ + MCI_CLEAR = 0x72A; /* Clear status flags */ + MCI_MASK0 = 0x72A; /* DataBlockEnd StartBitErr DataEnd RxOverrun DataTimeOut DataCrcFail */ + for (n = 0; bs > 1; bs >>= 1, n += 0x10); + MCI_DATA_CTRL = n | 0xB; /* Start to receive data blocks */ +} + + +/*-----------------------------------------------------------------------*/ +/* Start to transmit a data block */ +/*-----------------------------------------------------------------------*/ + +#if _READONLY == 0 +/* + * @param blks Number of blocks to be transmitted (1..127) + * */ +static void start_transmission ( unsigned char blks) { + unsigned int n; + unsigned long dma_ctrl; + + + /* ------ Setting up GPDMA Ch-0 ------ */ + + GPDMA_CH0_CFG &= 0xFFF80420; /* Disable ch-0 */ + GPDMA_INT_TCCLR = 0x01; /* Clear interrupt flag */ + dma_ctrl = 0x84492080; /* 1_000_0_1_00_010_010_010_010_000010000000 */ + + /* Create link list */ + for (n = 0; n < N_BUF; n++) { + LinkList[n][0] = (unsigned long)DmaBuff[n]; + LinkList[n][1] = (unsigned long)&MCI_FIFO; + LinkList[n][2] = (n == blks - 1) ? 0 : (unsigned long)LinkList[(n + 1) % N_BUF]; + LinkList[n][3] = dma_ctrl; + } + + /* Load first LLI */ + GPDMA_CH0_SRC = LinkList[0][0]; + GPDMA_CH0_DEST = LinkList[0][1]; + GPDMA_CH0_LLI = LinkList[0][2]; + GPDMA_CH0_CTRL = LinkList[0][3]; + + /* Enable ch-0 */ + GPDMA_CH0_CFG |= 0x18901; /* *************_0_0_1_1_0_001_*_0100_*_0000_1 */ + + /* --------- Setting up MCI ---------- */ + + XferRp = 0; /* Block FIFO read index */ + XferWc = blks; + XferStat = 2; /* Transfer status: Memroy --> MCI */ + + MCI_DATA_LEN = 512 * (blks + 1); /* Set total data length */ + MCI_DATA_TMR = (unsigned long)(MCLK_RW * 0.5); /* Data timer: 0.5sec */ + MCI_CLEAR = 0x51A; /* Clear status flags */ + MCI_MASK0 = 0x51A; /* DataBlockEnd DataEnd TxUnderrun DataTimeOut DataCrcFail */ + MCI_DATA_CTRL = (9 << 4) | 0x9; /* Start to transmit data blocks */ +} +#endif /* _READONLY */ + + + + +/*-----------------------------------------------------------------------*/ +/* Stop data transfer */ +/*-----------------------------------------------------------------------*/ + +static void stop_transfer (void) { + MCI_MASK0 = 0; /* Disable MCI interrupt */ + MCI_DATA_CTRL = 0; /* Stop MCI data transfer */ + + GPDMA_CH0_CFG &= 0xFFF80420; /* Disable DMA ch-0 */ +} + + + + +/*-----------------------------------------------------------------------*/ +/* Power Control (Device dependent) */ +/*-----------------------------------------------------------------------*/ + +static int power_status (void) { + return (MCI_POWER & 3) ? 1 : 0; +} + + +static void power_on (void) { + /* Enable MCI and GPDMA clock */ + PCONP |= (3 << 28); + + /* Enable GPDMA controller with little-endian */ + GPDMA_CH0_CFG &= 0xFFF80000; /* Disable DMA ch-0 */ + GPDMA_CONFIG = 0x01; + + /* Select PCLK for MCI, CCLK/2 = 36MHz */ + PCLKSEL1 = (PCLKSEL1 & 0xFCFFFFFF) | 0x02000000; + + //0.19 0.20 0.21 0.22 + PINMODE1 &= ~( (BIT6 | BIT7) | (BIT8 | BIT9) | (BIT10 | BIT11) | (BIT12 | BIT13) ); + PINMODE1 |= (BIT7) | (BIT9) | (BIT11) | (BIT13); // no resistors + //2.11 2.12 2.13 + PINMODE4 &= ~( (BIT22 | BIT23) | (BIT24 | BIT25) | (BIT26 | BIT27) ); + PINMODE4 |= (BIT23) | (BIT25) | (BIT27); // no resistors + /* Attach MCI unit to I/O pad */ + PINSEL1 = (PINSEL1 & 0xFFFFC03F) | 0x00002A80; /* MCICLK, MCICMD, MCIDATA0, MCIPWR */ +#if USE_4BIT + PINSEL4 = (PINSEL4 & 0xF03FFFFF) | 0x0A800000; /* MCIDATA1-3 */ +#endif + MCI_MASK0 = 0; + MCI_COMMAND = 0; + MCI_DATA_CTRL = 0; + + // pin 0.21 high active + SCS |= 0x08; + + /* Register interrupt handlers for MCI,DMA event */ + //RegisterIrq(MCI_INT, Isr_MCI, PRI_LOWEST-1); + install_irq( MCI_INT, (void *)Isr_MCI, 5 ); + + //RegisterIrq(GPDMA_INT, Isr_GPDMA, PRI_LOWEST-1); + install_irq( GPDMA_INT, (void *)Isr_GPDMA, 5 ); + + + /* Power-on (VCC is always tied to the socket on this board) */ + MCI_POWER = 0x01; /* Power on */ + + //for (Timer[0] = 10; Timer[0]; ) ; /* 10ms */ + hwtimer_wait(1000); + + MCI_POWER = 0x03; /* Enable signals */ +} + + +static void power_off (void) { + MCI_MASK0 = 0; + MCI_COMMAND = 0; + MCI_DATA_CTRL = 0; + + MCI_POWER = 0; /* Power-off */ + MCI_CLOCK = 0; + + // pin 0.21 low inactive + SCS &= ~0x08; + + //0.21 MCI led Pin (turns sd card off, too) + //0.19 0.20 0.21 0.22 with pull-down + PINMODE1 |= (BIT6 | BIT7) | (BIT8 | BIT9) | (BIT10 | BIT11) | (BIT12 | BIT13); + PINSEL1 &= ~( (BIT6 | BIT7) | (BIT8 | BIT9) | (BIT10 | BIT11) | (BIT12 | BIT13) ); +// Pins should be now configured as standard input (see board_init.c if you accidentally reconfigured them) + + //2.11 2.12 2.13 with pull-down + PINMODE4 |= (BIT22 | BIT23) | (BIT24 | BIT25) | (BIT26 | BIT27); + PINSEL4 &= ~( (BIT22 | BIT23) | (BIT24 | BIT25) | (BIT26 | BIT27) ); +// Pins should be now configured as standard input (see board_init.c if you accidentally reconfigured them) + + Stat |= STA_NOINIT; +} + + +/*-----------------------------------------------------------------------*/ +/* Send a command packet to the card and receive a response */ +/*-----------------------------------------------------------------------*/ + +/* + * @param idx Command index (bit[5..0]), ACMD flag (bit7) + * @param arg Command argument + * @param rt Expected response type. None(0), Short(1) or Long(2) + * @param *buff Response return buffer + * @return 1 when function succeeded otherwise returns 0 + * */ +static int send_cmd (unsigned int idx, unsigned long arg, unsigned int rt, unsigned long *buff) { + unsigned int s, mc; + + if (idx & 0x80) { /* Send a CMD55 prior to the specified command if it is ACMD class */ + if (!send_cmd(CMD55, (unsigned long)CardRCA << 16, 1, buff) /* When CMD55 is faild, */ + || !(buff[0] & 0x00000020)) return 0; /* exit with error */ + } + idx &= 0x3F; /* Mask out ACMD flag */ + + do { /* Wait while CmdActive bit is set */ + MCI_COMMAND = 0; /* Cancel to transmit command */ + MCI_CLEAR = 0x0C5; /* Clear status flags */ + for (s = 0; s < 10; s++) MCI_STATUS; /* Skip lock out time of command reg. */ + } while (MCI_STATUS & 0x00800); + + MCI_ARGUMENT = arg; /* Set the argument into argument register */ + mc = 0x400 | idx; /* Enable bit + index */ + if (rt == 1) mc |= 0x040; /* Set Response bit to reveice short resp */ + if (rt > 1) mc |= 0x0C0; /* Set Response and LongResp bit to receive long resp */ + MCI_COMMAND = mc; /* Initiate command transaction */ + + //Timer[1] = 100; + uint32_t timerstart = hwtimer_now(); + + for (;;) { /* Wait for end of the cmd/resp transaction */ + + //if (!Timer[1]) return 0; + if(hwtimer_now() - timerstart > 10000) + { + return 0; + } + + s = MCI_STATUS; /* Get the transaction status */ + + if (rt == 0) + { + if (s & 0x080) + return 1; /* CmdSent */ + } + else + { + if (s & 0x040) + break; /* CmdRespEnd */ + if (s & 0x001) + { /* CmdCrcFail */ + if (idx == 1 || idx == 12 || idx == 41) /* Ignore CRC error on CMD1/12/41 */ + break; + return 0; + } + if (s & 0x004) + return 0; /* CmdTimeOut */ + } + } + + buff[0] = MCI_RESP0; /* Read the response words */ + if (rt == 2) { + buff[1] = MCI_RESP1; + buff[2] = MCI_RESP2; + buff[3] = MCI_RESP3; + } + + return 1; /* Return with success */ +} + + + + +/*-----------------------------------------------------------------------*/ +/* Wait card ready */ +/*-----------------------------------------------------------------------*/ + +/** + * @param tmr Timeout in unit of 1ms + * @returns 1 when card is tran state, otherwise returns 0 + */ +static int wait_ready (unsigned short tmr) { + unsigned long rc; + + uint32_t stoppoll = hwtimer_now() + tmr * 100; + bool bBreak = false; + while (hwtimer_now() < stoppoll/*Timer[0]*/) + { + if (send_cmd(CMD13, (unsigned long) CardRCA << 16, 1, &rc) && ((rc & 0x01E00) == 0x00800)) + { + bBreak = true; + break; + } + /* This loop will take a time. Insert rot_rdq() here for multitask envilonment. */ + } + return bBreak;//Timer[0] ? 1 : 0; +} + + + + +/*-----------------------------------------------------------------------*/ +/* Swap byte order */ +/*-----------------------------------------------------------------------*/ +static void bswap_cp (unsigned char *dst, const unsigned long *src) { + unsigned long d; + + + d = *src; + *dst++ = (unsigned char)(d >> 24); + *dst++ = (unsigned char)(d >> 16); + *dst++ = (unsigned char)(d >> 8); + *dst++ = (unsigned char)(d >> 0); +} + + + + +/*-------------------------------------------------------------------------- + + Public Functions + +---------------------------------------------------------------------------*/ + + +/*-----------------------------------------------------------------------*/ +/* Initialize Disk Drive */ +/*-----------------------------------------------------------------------*/ +DSTATUS MCI_initialize (void) { + unsigned int cmd, n; + unsigned long resp[4]; + unsigned char ty; + + if (Stat & STA_NODISK) return Stat; /* No card in the socket */ + + power_off(); + + hwtimer_wait(HWTIMER_TICKS(1000)); + + power_on(); /* Force socket power on */ + MCI_CLOCK = 0x100 | (PCLK/MCLK_ID/2-1); /* Set MCICLK = MCLK_ID */ + //for (Timer[0] = 2; Timer[0]; ); + hwtimer_wait(250); + + send_cmd(CMD0, 0, 0, NULL); /* Enter idle state */ + CardRCA = 0; + + /*---- Card is 'idle' state ----*/ + + /* Initialization timeout of 1000 msec */ + uint32_t start = hwtimer_now(); + + /* SDC Ver2 */ + if (send_cmd(CMD8, 0x1AA, 1, resp) && (resp[0] & 0xFFF) == 0x1AA) { + /* The card can work at vdd range of 2.7-3.6V */ + DEBUG("SDC Ver. 2\n"); + + do { /* Wait while card is busy state (use ACMD41 with HCS bit) */ + /* This loop will take a time. Insert wai_tsk(1) here for multitask envilonment. */ + if (hwtimer_now() > start + 1000000/*!Timer[0]*/) { + DEBUG("%s, %d: Timeout #1\n", __FILE__, __LINE__); + goto di_fail; + } + } while (!send_cmd(ACMD41, 0x40FF8000, 1, resp) || !(resp[0] & 0x80000000)); + + ty = (resp[0] & 0x40000000) ? CT_SD2|CT_BLOCK : CT_SD2; /* Check CCS bit in the OCR */ + } + else { /* SDC Ver1 or MMC */ + if (send_cmd(ACMD41, 0x00FF8000, 1, resp)) { + DEBUG("SDC Ver. 1\n"); + ty = CT_SD1; + cmd = ACMD41; /* ACMD41 is accepted -> SDC Ver1 */ + } + else { + DEBUG("MMC\n"); + ty = CT_MMC; + cmd = CMD1; /* ACMD41 is rejected -> MMC */ + } + do { /* Wait while card is busy state (use ACMD41 or CMD1) */ + DEBUG("%s, %d: %lX\n", __FILE__, __LINE__, resp[0]); + /* This loop will take a time. Insert wai_tsk(1) here for multitask envilonment. */ + if (hwtimer_now() > start + 1000000/*!Timer[0]*/) { + DEBUG("now: %lu, started at: %lu\n", hwtimer_now(), start); + DEBUG("%s, %d: Timeout #2\n", __FILE__, __LINE__); + goto di_fail; + } + } while (!send_cmd(cmd, 0x00FF8000, 1, resp) || !(resp[0] & 0x80000000)); + } + + CardType = ty; /* Save card type */ + bswap_cp(&CardInfo[32], resp); /* Save OCR */ + + /*---- Card is 'ready' state ----*/ + + if (!send_cmd(CMD2, 0, 2, resp)) { + DEBUG("%s, %d: Failed entering ident state", __FILE__, __LINE__); + goto di_fail; /* Enter ident state */ + } + for (n = 0; n < 4; n++) bswap_cp(&CardInfo[n * 4 + 16], &resp[n]); /* Save CID */ + + /*---- Card is 'ident' state ----*/ + + if (ty & CT_SDC) { /* SDC: Get generated RCA and save it */ + if (!send_cmd(CMD3, 0, 1, resp)) { + DEBUG("%s, %d: Failed generating RCA\n", __FILE__, __LINE__); + goto di_fail; + } + CardRCA = (unsigned short)(resp[0] >> 16); + } else { /* MMC: Assign RCA to the card */ + if (!send_cmd(CMD3, 1 << 16, 1, resp)) goto di_fail; + CardRCA = 1; + } + + /*---- Card is 'stby' state ----*/ + + if (!send_cmd(CMD9, (unsigned long)CardRCA << 16, 2, resp)) /* Get CSD and save it */ + { + //printf("MCI CMD9 fail\n"); + goto di_fail; + } + for (n = 0; n < 4; n++) bswap_cp(&CardInfo[n * 4], &resp[n]); + + if (!send_cmd(CMD7, (unsigned long)CardRCA << 16, 1, resp)) /* Select card */ + { + //printf("MCI CMD7 fail\n"); + goto di_fail; + } + + /*---- Card is 'tran' state ----*/ + + if (!(ty & CT_BLOCK)) { /* Set data block length to 512 (for byte addressing cards) */ + if (!send_cmd(CMD16, 512, 1, resp) || (resp[0] & 0xFDF90000)) + { + //printf("MCI CMD16 fail\n"); + goto di_fail; + } + } + +#if USE_4BIT + if (ty & CT_SDC) { /* Set wide bus mode (for SDCs) */ + if (!send_cmd(ACMD6, 2, 1, resp) /* Set bus mode of SDC */ + || (resp[0] & 0xFDF90000)) + { + //printf("MCI ACMD6 fail\n"); + goto di_fail; + } + MCI_CLOCK |= 0x800; /* Set bus mode of MCI */ + } +#endif + + MCI_CLOCK = (MCI_CLOCK & 0xF00) | 0x200 | (PCLK/MCLK_RW/2-1); /* Set MCICLK = MCLK_RW, power-save mode */ + + Stat &= ~STA_NOINIT; /* Clear STA_NOINIT */ + return Stat; + +di_fail: + power_off(); + Stat |= STA_NOINIT; /* Set STA_NOINIT */ + return Stat; +} + + + + +/*-----------------------------------------------------------------------*/ +/* Get Disk Status */ +/*-----------------------------------------------------------------------*/ + +DSTATUS MCI_status (void) { + return Stat; +} + + + + +/*-----------------------------------------------------------------------*/ +/* Read Sector(s) */ +/*-----------------------------------------------------------------------*/ + +/** + * @param buff Pointer to the data buffer to store read data + * @param sector Start sector number (LBA) + * @param count Sector count (1..127) + */ +DRESULT MCI_read (unsigned char *buff, unsigned long sector, unsigned char count) { + unsigned long resp; + unsigned int cmd; + unsigned char rp; + + + if (count < 1 || count > 127) return RES_PARERR; /* Check parameter */ + if (Stat & STA_NOINIT) return RES_NOTRDY; /* Check drive status */ + + if (!(CardType & CT_BLOCK)) sector *= 512; /* Convert LBA to byte address if needed */ + if (!wait_ready(500)) return RES_ERROR; /* Make sure that card is tran state */ + + ready_reception(count, 512); /* Ready to receive data blocks */ + + cmd = (count > 1) ? CMD18 : CMD17; /* Transfer type: Single block or Multiple block */ + + if (send_cmd(cmd, sector, 1, &resp) /* Start to read */ + && !(resp & 0xC0580000)) + { + rp = 0; + do + { + while ((rp == XferWp) && !(XferStat & 0xC)) + { /* Wait for block arrival */ + /* This loop will take a time. Replace it with sync process for multitask envilonment. */ + } + if (XferStat & 0xC) + { + break; /* Abort if any error has occured */ + } + + Copy_al2un(buff, DmaBuff[rp], 512); /* Pop an block */ + + XferRp = rp = (rp + 1) % N_BUF; /* Next DMA buffer */ + if (XferStat & 0xC) + { + break; /* Abort if overrun has occured */ + } + buff += 512; /* Next user buffer address */ + } + while (--count); + if (cmd == CMD18) /* Terminate to read (MB) */ + send_cmd(CMD12, 0, 1, &resp); + } + + stop_transfer(); /* Close data path */ + + return count ? RES_ERROR : RES_OK; +} + + +/*-----------------------------------------------------------------------*/ +/* Write Sector(s) */ +/*-----------------------------------------------------------------------*/ + +#if _READONLY == 0 + +/** + * @param buff Pointer to the data to be written + * @param sector Start sector number (LBA) + * @param count Sector count (1..127) + * */ +DRESULT MCI_write (const unsigned char *buff, unsigned long sector, unsigned char count) { + unsigned long rc; + unsigned int cmd; + unsigned char wp, xc; + + if (count < 1 || count > 127) return RES_PARERR; /* Check parameter */ + if (Stat & STA_NOINIT) return RES_NOTRDY; /* Check drive status */ + if (Stat & STA_PROTECT) return RES_WRPRT; /* Check write protection */ + + if (!(CardType & CT_BLOCK)) sector *= 512; /* Convert LBA to byte address if needed */ + if (!wait_ready(500)) return RES_ERROR; /* Make sure that card is tran state */ + + if (count == 1) { /* Single block write */ + cmd = CMD24; + } + else { /* Multiple block write */ + cmd = (CardType & CT_SDC) ? ACMD23 : CMD23; + if (!send_cmd(cmd, count, 1, &rc) /* Preset number of blocks to write */ + || (rc & 0xC0580000)) { + return RES_ERROR; + } + cmd = CMD25; + } + + if (!send_cmd(cmd, sector, 1, &rc) /* Send a write command */ + || (rc & 0xC0580000)) { + return RES_ERROR; + } + + wp = 0; + xc = count; + do { /* Fill block FIFO */ + Copy_un2al(DmaBuff[wp], (unsigned char*)(unsigned int)buff, 512); /* Push a block */ + wp++; /* Next DMA buffer */ + count--; + buff += 512; /* Next user buffer address */ + } while (count && wp < N_BUF); + XferWp = wp = wp % N_BUF; + start_transmission(xc); /* Start transmission */ + + while (count) { + while((wp == XferRp) && !(XferStat & 0xC)) { /* Wait for block FIFO not full */ + /* This loop will take a time. Replace it with sync process for multitask envilonment. */ + } + if (XferStat & 0xC) break; /* Abort if block underrun or any MCI error has occured */ + Copy_un2al(DmaBuff[wp], (unsigned char*)(unsigned int)buff, 512); /* Push a block */ + XferWp = wp = (wp + 1) % N_BUF; /* Next DMA buffer */ + if (XferStat & 0xC) break; /* Abort if block underrun has occured */ + count--; + buff += 512; /* Next user buffer address */ + } + + while (!(XferStat & 0xC)); /* Wait for all blocks sent (block underrun) */ + if (XferStat & 0x8) count = 1; /* Abort if any MCI error has occured */ + + stop_transfer(); /* Close data path */ + if (cmd == CMD25 && (CardType & CT_SDC)) /* Terminate to write (SDC w/MB) */ + send_cmd(CMD12, 0, 1, &rc); + + return count ? RES_ERROR : RES_OK; +} +#endif /* _READONLY */ + + + + +/*-----------------------------------------------------------------------*/ +/* Miscellaneous Functions */ +/*-----------------------------------------------------------------------*/ + +DRESULT MCI_ioctl ( + unsigned char ctrl, /* Control code */ + void *buff /* Buffer to send/receive data block */ +) +{ + DRESULT res; + unsigned char b, *ptr = buff; + unsigned long resp[4], d, *dp, st, ed; + + + if (Stat & STA_NOINIT) return RES_NOTRDY; + + res = RES_ERROR; + + switch (ctrl) { + case CTRL_SYNC : /* Make sure that all data has been written on the media */ + if (wait_ready(500)) /* Wait for card enters tarn state */ + res = RES_OK; + break; + + case GET_SECTOR_COUNT : /* Get number of sectors on the disk (unsigned long) */ + if ((CardInfo[0] >> 6) == 1) { /* SDC CSD v2.0 */ + d = ((unsigned short)CardInfo[8] << 8) + CardInfo[9] + 1; + *(unsigned long*)buff = d << 10; + } else { /* MMC or SDC CSD v1.0 */ + b = (CardInfo[5] & 15) + ((CardInfo[10] & 128) >> 7) + ((CardInfo[9] & 3) << 1) + 2; + d = (CardInfo[8] >> 6) + ((unsigned short)CardInfo[7] << 2) + ((unsigned short)(CardInfo[6] & 3) << 10) + 1; + *(unsigned long*)buff = d << (b - 9); + } + res = RES_OK; + break; + + case GET_SECTOR_SIZE : /* Get sectors on the disk (unsigned short) */ + *(unsigned short*)buff = 512; + res = RES_OK; + break; + + case GET_BLOCK_SIZE : /* Get erase block size in unit of sectors (unsigned long) */ + if (CardType & CT_SD2) { /* SDC ver 2.00 */ + *(unsigned long*)buff = 16UL << (CardInfo[10] >> 4); + } else { /* SDC ver 1.XX or MMC */ + if (CardType & CT_SD1) /* SDC v1 */ + *(unsigned long*)buff = (((CardInfo[10] & 63) << 1) + ((unsigned short)(CardInfo[11] & 128) >> 7) + 1) << ((CardInfo[13] >> 6) - 1); + else /* MMC */ + *(unsigned long*)buff = ((unsigned short)((CardInfo[10] & 124) >> 2) + 1) * (((CardInfo[11] & 3) << 3) + ((CardInfo[11] & 224) >> 5) + 1); + } + res = RES_OK; + break; + + case CTRL_ERASE_SECTOR : /* Erase a block of sectors */ + if (!(CardType & CT_SDC) || (!(CardInfo[0] >> 6) && !(CardInfo[10] & 0x40))) break; /* Check if sector erase can be applied to the card */ + dp = buff; st = dp[0]; ed = dp[1]; + if (!(CardType & CT_BLOCK)) { + st *= 512; ed *= 512; + } + if (send_cmd(CMD32, st, 1, resp) && send_cmd(CMD33, ed, 1, resp) && send_cmd(CMD38, 0, 1, resp) && wait_ready(30000)) + res = RES_OK; + break; + + case CTRL_POWER : + switch (ptr[0]) { + case 0: /* Sub control code == 0 (POWER_OFF) */ + power_off(); /* Power off */ + res = RES_OK; + break; + case 1: /* Sub control code == 1 (POWER_GET) */ + ptr[1] = (unsigned char)power_status(); + res = RES_OK; + break; + default : + res = RES_PARERR; + } + break; + + case MMC_GET_TYPE : /* Get card type flags (1 byte) */ + *ptr = CardType; + res = RES_OK; + break; + + case MMC_GET_CSD : /* Get CSD (16 bytes) */ + memcpy(buff, &CardInfo[0], 16); + res = RES_OK; + break; + + case MMC_GET_CID : /* Get CID (16 bytes) */ + memcpy(buff, &CardInfo[16], 16); + res = RES_OK; + break; + + case MMC_GET_OCR : /* Get OCR (4 bytes) */ + memcpy(buff, &CardInfo[32], 4); + res = RES_OK; + break; + + case MMC_GET_SDSTAT : /* Receive SD status as a data block (64 bytes) */ + if (CardType & CT_SDC) { /* SDC */ + if (wait_ready(500)) { + ready_reception(1, 64); /* Ready to receive data blocks */ + if (send_cmd(ACMD13, 0, 1, resp) /* Start to read */ + && !(resp[0] & 0xC0580000)) { + while ((XferWp == 0) && !(XferStat & 0xC)); + if (!(XferStat & 0xC)) { + Copy_al2un(buff, DmaBuff[0], 64); + res = RES_OK; + } + } + } + stop_transfer(); /* Close data path */ + } + break; + + default: + res = RES_PARERR; + } + + return res; +} diff --git a/drivers/include/diskio.h b/drivers/include/diskio.h new file mode 100644 index 000000000..2dc672dfe --- /dev/null +++ b/drivers/include/diskio.h @@ -0,0 +1,107 @@ +/*----------------------------------------------------------------------- +/ Low level disk interface modlue include file (C)ChaN, 2010 +/-----------------------------------------------------------------------*/ + +#ifndef DEF_DISKIO +#define DEF_DISKIO + +#include + +#define DN_MCI 0 /* Physical drive number for MCI */ +#define DN_NAND 1 /* Physical drive number for NAND flash */ + +/** + * @def MCI_PWRSAVE + * @ingroup conf + * @brief Powerdown mode to use between mci operations + */ +#ifndef MCI_PWRSAVE +#define MCI_PWRSAVE 0 +#endif + +/* These functions are defined in asmfunc.S */ +void Copy_al2un (unsigned char *dst, const unsigned long *src, int count); /* Copy aligned to unaligned. */ +void Copy_un2al (unsigned long *dst, const unsigned char *src, int count); /* Copy unaligned to aligned. */ + + +/* Status of Disk Functions */ +typedef unsigned char DSTATUS; + +/* Results of Disk Functions */ +typedef enum { + RES_OK = 0, /* 0: Successful */ + RES_ERROR, /* 1: R/W Error */ + RES_WRPRT, /* 2: Write Protected */ + RES_NOTRDY, /* 3: Not Ready */ + RES_PARERR /* 4: Invalid Parameter */ +} DRESULT; + + +/*---------------------------------------*/ +/* Prototypes for disk control functions */ + +DSTATUS disk_initialize (unsigned char); +DSTATUS disk_status (unsigned char); +DRESULT disk_read (unsigned char, unsigned char*, unsigned long, unsigned char); +DRESULT disk_write (unsigned char, const unsigned char*, unsigned long, unsigned char); +DRESULT disk_ioctl (unsigned char, unsigned char, void*); + + + +/* Disk Status Bits (DSTATUS) */ + +#define STA_NOINIT 0x01 /* Drive not initialized */ +#define STA_NODISK 0x02 /* No medium in the drive */ +#define STA_PROTECT 0x04 /* Write protected */ + + +/* Command code for disk_ioctrl fucntion */ + +/* Generic ioctl command (defined for FatFs) */ +#define CTRL_SYNC 0 /* Flush disk cache (for write functions) */ +#define GET_SECTOR_COUNT 1 /* Get media size (for only f_mkfs()) */ +#define GET_SECTOR_SIZE 2 /* Get sector size (for multiple sector size (_MAX_SS >= 1024)) */ +#define GET_BLOCK_SIZE 3 /* Get erase block size (for only f_mkfs()) */ +#define CTRL_ERASE_SECTOR 4 /* Force erased a block of sectors (for only _USE_ERASE) */ + +/* Generic ioctl command */ +#define CTRL_POWER 5 /* Get/Set power status */ +#define CTRL_LOCK 6 /* Lock/Unlock media removal */ +#define CTRL_EJECT 7 /* Eject media */ + +/* MMC/SDC specific ioctl command */ +#define MMC_GET_TYPE 10 /* Get card type */ +#define MMC_GET_CSD 11 /* Get CSD */ +#define MMC_GET_CID 12 /* Get CID */ +#define MMC_GET_OCR 13 /* Get OCR */ +#define MMC_GET_SDSTAT 14 /* Get SD status */ + +/* ATA/CF specific ioctl command */ +#define ATA_GET_REV 20 /* Get F/W revision */ +#define ATA_GET_MODEL 21 /* Get model name */ +#define ATA_GET_SN 22 /* Get serial number */ + +/* NAND specific ioctl command */ +#define NAND_FORMAT 30 /* Create physical format */ + + + +/*---------------------------------------------*/ +/* Prototypes for each physical disk functions */ + + +DSTATUS NAND_initialize (void); +DSTATUS NAND_status (void); +DRESULT NAND_read (unsigned char*, unsigned long, unsigned char); +DRESULT NAND_write (const unsigned char*, unsigned long, unsigned char); +DRESULT NAND_ioctl (unsigned char, void*); + +DSTATUS MCI_initialize (void); +DSTATUS MCI_status (void); +DRESULT MCI_read (unsigned char*, unsigned long, unsigned char); +DRESULT MCI_write (const unsigned char*, unsigned long, unsigned char); +DRESULT MCI_ioctl (unsigned char, void*); +void MCI_timerproc (void); + + +#endif diff --git a/projects/default/Jamfile b/projects/default/Jamfile index a428e7211..bdbee91b6 100644 --- a/projects/default/Jamfile +++ b/projects/default/Jamfile @@ -6,6 +6,6 @@ SubDir TOP projects default ; -Module default_project : main.c : shell posix_io uart0 shell_commands ps rtc sht11 ltc4150 cc110x_ng transceiver gpioint auto_init config ; +Module default_project : main.c : shell posix_io uart0 shell_commands ps rtc sht11 ltc4150 cc110x_ng transceiver gpioint auto_init config mci ; UseModule default_project ; diff --git a/sys/auto_init.c b/sys/auto_init.c index c142d7ef3..49d1f3f2a 100644 --- a/sys/auto_init.c +++ b/sys/auto_init.c @@ -1,7 +1,8 @@ #include #include -#include -#include +#include "board_uart0.h" +#include "rtc.h" +#include "diskio.h" #include #define ENABLE_DEBUG @@ -53,6 +54,10 @@ void auto_init(void) { DEBUG("Auto init ltc4150 module.\n"); ltc4150_init(); #endif +#ifdef MODULE_MCI + DEBUG("Auto init mci module.\n"); + MCI_initialize(); +#endif #ifdef MODULE_PROFILING extern void profiling_init(void); profiling_init(); diff --git a/sys/include/shell_commands.h b/sys/include/shell_commands.h index 1e0ec8575..22efd8dfb 100644 --- a/sys/include/shell_commands.h +++ b/sys/include/shell_commands.h @@ -3,6 +3,12 @@ #include +#define DISK_GET_SECTOR_SIZE "dget_ssize" +#define DISK_GET_SECTOR_COUNT "dget_scount" +#define DISK_GET_BLOCK_SIZE "dget_bsize" +#define DISK_READ_SECTOR_CMD "dread_sec" +#define DISK_READ_BYTES_CMD "dread" + extern const shell_command_t _shell_command_list[]; #endif /* __SHELL_COMMANDS_H */ diff --git a/sys/shell/Jamfile b/sys/shell/Jamfile index a93dc23f3..c91c6d86a 100644 --- a/sys/shell/Jamfile +++ b/sys/shell/Jamfile @@ -28,7 +28,7 @@ SubDir TOP sys shell ; Module shell : shell.c ; -Module shell_commands : shell_commands.c id.c rtc.c sht11.c ltc4150.c cc1100.c cc110x_ng.c : shell ; +Module shell_commands : shell_commands.c id.c rtc.c sht11.c ltc4150.c cc1100.c cc110x_ng.c disk.c : shell ; Module ps : ps.c ; diff --git a/sys/shell/disk.c b/sys/shell/disk.c new file mode 100644 index 000000000..b8bd95f29 --- /dev/null +++ b/sys/shell/disk.c @@ -0,0 +1,123 @@ +#include +#include +#include + +#include "shell_commands.h" +#include "diskio.h" + +static inline uint8_t sector_read(unsigned char *read_buf, unsigned long sector, unsigned long length, unsigned long offset) { + unsigned long i; + if (MCI_read(read_buf, sector, 1) == RES_OK) { + printf("[disk] Read sector %lu (%lu):\n", sector, offset); + for (i = offset + 1; i <= offset + length; i++) { + printf(" %u", read_buf[i-1]); + if (!(i % 16)) { + puts(""); + } + } + puts(""); + return 1; + } + return 0; +} + +void _get_sectorsize(char *unused) { + unsigned short ssize; + if (MCI_ioctl(GET_SECTOR_SIZE, &ssize) == RES_OK) { + printf("[disk] sector size is %u\n", ssize); + } + else { + puts("[disk] Failed to fetch sector size. Card inserted?"); + } +} + +void _get_blocksize(char *unused) { + unsigned long bsize; + if (MCI_ioctl(GET_BLOCK_SIZE, &bsize) == RES_OK) { + printf("[disk] block size is %lu\n", bsize); + } + else { + puts("[disk] Failed to fetch block size. Card inserted?"); + } +} + +void _get_sectorcount(char *unused) { + unsigned long scount; + if (MCI_ioctl(GET_SECTOR_COUNT, &scount) == RES_OK) { + printf("[disk] sector count is %lu\n", scount); + } + else { + puts("[disk] Failed to fetch sector count. Card inserted?"); + } +} + +void _read_sector(char *sector) { + unsigned long sectornr, scount; + unsigned short ssize; + + if (strlen(sector) > strlen(DISK_READ_SECTOR_CMD) + 1) { + + sectornr = (unsigned short) atol(sector + strlen(DISK_READ_SECTOR_CMD) + 1); + if ((MCI_ioctl(GET_SECTOR_COUNT, &scount) == RES_OK) && (MCI_ioctl(GET_SECTOR_SIZE, &ssize) == RES_OK)) { + unsigned char read_buf[ssize]; + if (sector_read(read_buf, sectornr, ssize, 0)) { + return; + } + } + printf("[disk] Error while reading sector %lu\n", sectornr); + } + else { + printf("[disk] Usage:\n%s \n", DISK_READ_SECTOR_CMD); + return; + } +} + +void _read_bytes(char *bytes) { + unsigned long sector = 1, scount, offset; + unsigned short ssize, length; + char *tok; + + /* tokenize user input */ + tok = strtok(bytes + strlen(DISK_READ_BYTES_CMD) + 1, " "); + if (tok) { + offset = atol(tok); + tok = strtok(NULL, " "); + if (tok) { + length = atoi(tok); + if (length) { + /* get card info */ + if ((MCI_ioctl(GET_SECTOR_COUNT, &scount) == RES_OK) && (MCI_ioctl(GET_SECTOR_SIZE, &ssize) == RES_OK)) { + /* calculate sector and offset position */ + sector = (offset / ssize) + 1; + offset = (offset % ssize); + /* preapre buffer (size must be a multiple of sector size) */ + unsigned char read_buf[((length / ssize) + 1) * 512]; + /* read from several sectors */ + if (length > (ssize - offset)) { + /* buffer offset */ + unsigned long j = 0; + /* chunk from current sector */ + unsigned short tmp = ssize - offset; + while (length) { + sector_read(read_buf + j, sector++, tmp, offset); + /* decrease length and recalculate chunk */ + length -= tmp; + tmp = (length >= ssize) ? ssize : length; + } + + return; + } /* length > (ssize - offset) */ + /* read only one sector */ + else { + if (sector_read(read_buf, sector, length, offset)) { + return; + } + } /* length < (ssize - offset) */ + } /* ioctl */ + printf("[disk] Error while reading sector %lu\n", sector); + return; + } /* length */ + } /* strtok #2 */ + } /* strtok #1 */ + printf("[disk] Usage:\n%s \n", DISK_READ_BYTES_CMD); +} diff --git a/sys/shell/shell_commands.c b/sys/shell/shell_commands.c index 6023faf2a..e739f723a 100644 --- a/sys/shell/shell_commands.c +++ b/sys/shell/shell_commands.c @@ -37,6 +37,15 @@ extern void _cc110x_ng_monitor_handler(char *mode); #endif #endif +#ifdef MODULE_MCI +extern void _get_sectorsize(char *unused); +extern void _get_blocksize(char* unused); +extern void _get_sectorcount(char* unused); +extern void _read_sector(char* sector); +extern void _read_bytes(char* bytes); +extern void _write_bytes(char* bytes); +#endif + const shell_command_t _shell_command_list[] = { {"id", "Gets or sets the node's id.", _id_handler}, #ifdef MODULE_PS @@ -66,6 +75,13 @@ const shell_command_t _shell_command_list[] = { {"txtsnd", "Sends a text message to a given node via the CC1100 transceiver", _cc110x_ng_send_handler}, {"monitor", "Enables or disables address checking for the CC1100 transceiver", _cc110x_ng_monitor_handler}, #endif +#endif +#ifdef MODULE_MCI + {DISK_READ_SECTOR_CMD, "Reads the specified sector of inserted memory card", _read_sector}, + {DISK_READ_BYTES_CMD, "Reads the specified bytes from inserted memory card", _read_bytes}, + {DISK_GET_SECTOR_SIZE, "Get the sector size of inserted memory card", _get_sectorsize}, + {DISK_GET_SECTOR_COUNT, "Get the sector count of inserted memory card", _get_sectorcount}, + {DISK_GET_BLOCK_SIZE, "Get the block size of inserted memory card", _get_blocksize}, #endif {NULL, NULL, NULL} };