git-svn-id: svn://svn.code.sf.net/p/chibios/svn/trunk@4349 35acf78f-673a-0410-8e92-d51de3d6d3f4

master
gdisirio 2012-06-26 18:18:14 +00:00
parent 853b0fd51c
commit 9492ff4976
5 changed files with 92 additions and 119 deletions

View File

@ -34,8 +34,8 @@
/* Card insertion monitor. */ /* Card insertion monitor. */
/*===========================================================================*/ /*===========================================================================*/
#define SDC_POLLING_INTERVAL 10 #define POLLING_INTERVAL 10
#define SDC_POLLING_DELAY 10 #define POLLING_DELAY 10
/** /**
* @brief Card monitor timer. * @brief Card monitor timer.
@ -55,47 +55,55 @@ static EventSource inserted_event, removed_event;
/** /**
* @brief Insertion monitor timer callback function. * @brief Insertion monitor timer callback function.
* *
* @param[in] p pointer to the @p SDCDriver object * @param[in] p pointer to the @p BaseBlockDevice object
* *
* @notapi * @notapi
*/ */
static void tmrfunc(void *p) { static void tmrfunc(void *p) {
SDCDriver *sdcp = p; BaseBlockDevice *bbdp = p;
/* The presence check is performed only while the driver is not in a
transfer state because it is often performed by changing the mode of
the pin connected to the CS/D3 contact of the card, this could disturb
the transfer.*/
blkstate_t state = blkGetDriverState(bbdp);
chSysLockFromIsr(); chSysLockFromIsr();
if (cnt > 0) { if ((state != BLK_READING) && (state != BLK_WRITING)) {
if (sdcIsCardInserted(sdcp)) { /* Safe to perform the check.*/
if (--cnt == 0) { if (cnt > 0) {
chEvtBroadcastI(&inserted_event); if (blkIsInserted(bbdp)) {
if (--cnt == 0) {
chEvtBroadcastI(&inserted_event);
}
}
else
cnt = POLLING_INTERVAL;
}
else {
if (!blkIsInserted(bbdp)) {
cnt = POLLING_INTERVAL;
chEvtBroadcastI(&removed_event);
} }
} }
else
cnt = SDC_POLLING_INTERVAL;
} }
else { chVTSetI(&tmr, MS2ST(POLLING_DELAY), tmrfunc, bbdp);
if (!sdcIsCardInserted(sdcp)) {
cnt = SDC_POLLING_INTERVAL;
chEvtBroadcastI(&removed_event);
}
}
chVTSetI(&tmr, MS2ST(SDC_POLLING_DELAY), tmrfunc, sdcp);
chSysUnlockFromIsr(); chSysUnlockFromIsr();
} }
/** /**
* @brief Polling monitor start. * @brief Polling monitor start.
* *
* @param[in] sdcp pointer to the @p SDCDriver object * @param[in] p pointer to an object implementing @p BaseBlockDevice
* *
* @notapi * @notapi
*/ */
static void tmr_init(SDCDriver *sdcp) { static void tmr_init(void *p) {
chEvtInit(&inserted_event); chEvtInit(&inserted_event);
chEvtInit(&removed_event); chEvtInit(&removed_event);
chSysLock(); chSysLock();
cnt = SDC_POLLING_INTERVAL; cnt = POLLING_INTERVAL;
chVTSetI(&tmr, MS2ST(SDC_POLLING_DELAY), tmrfunc, sdcp); chVTSetI(&tmr, MS2ST(POLLING_DELAY), tmrfunc, p);
chSysUnlock(); chSysUnlock();
} }
@ -276,8 +284,6 @@ static void InsertHandler(eventid_t id) {
static void RemoveHandler(eventid_t id) { static void RemoveHandler(eventid_t id) {
(void)id; (void)id;
if (sdcGetDriverState(&SDCD1) == SDC_ACTIVE)
sdcDisconnect(&SDCD1);
fs_ready = FALSE; fs_ready = FALSE;
} }

View File

@ -106,20 +106,6 @@
/* Driver data structures and types. */ /* Driver data structures and types. */
/*===========================================================================*/ /*===========================================================================*/
/**
* @brief Driver state machine possible states.
*/
typedef enum {
SDC_UNINIT = 0, /**< Not initialized. */
SDC_STOP = 1, /**< Stopped. */
SDC_READY = 2, /**< Ready. */
SDC_CONNECTING = 3, /**< Card connection in progress. */
SDC_DISCONNECTING = 4, /**< Card disconnection in progress. */
SDC_ACTIVE = 5, /**< Cart initialized. */
SDC_READING = 6, /**< Read operation in progress. */
SDC_WRITING = 7, /**< Write operation in progress. */
} sdcstate_t;
#include "sdc_lld.h" #include "sdc_lld.h"
/*===========================================================================*/ /*===========================================================================*/
@ -130,16 +116,6 @@ typedef enum {
* @name Macro Functions * @name Macro Functions
* @{ * @{
*/ */
/**
* @brief Returns the driver state.
*
* @param[in] sdcp pointer to the @p SDCDriver object
* @return The driver state.
*
* @api
*/
#define sdcGetDriverState(sdcp) ((sdcp)->state)
/** /**
* @brief Returns the card insertion status. * @brief Returns the card insertion status.
* @note This macro wraps a low level function named * @note This macro wraps a low level function named
@ -171,16 +147,6 @@ typedef enum {
* @api * @api
*/ */
#define sdcIsWriteProtected(sdcp) (sdc_lld_is_write_protected(sdcp)) #define sdcIsWriteProtected(sdcp) (sdc_lld_is_write_protected(sdcp))
/**
* @brief Returns the card capacity in blocks.
*
* @param[in] sdcp pointer to the @p SDCDriver object
* @return The card capacity.
*
* @api
*/
#define sdcGetCardCapacity(sdcp) ((sdcp)->capacity)
/** @} */ /** @} */
/*===========================================================================*/ /*===========================================================================*/

View File

@ -41,8 +41,8 @@
/* Driver local definitions. */ /* Driver local definitions. */
/*===========================================================================*/ /*===========================================================================*/
#define DMA_CHANNEL \ #define DMA_CHANNEL \
STM32_DMA_GETCHANNEL(STM32_SDC_SDIO_DMA_STREAM, \ STM32_DMA_GETCHANNEL(STM32_SDC_SDIO_DMA_STREAM, \
STM32_SDC_SDIO_DMA_CHN) STM32_SDC_SDIO_DMA_CHN)
/*===========================================================================*/ /*===========================================================================*/
@ -346,7 +346,7 @@ void sdc_lld_start(SDCDriver *sdcp) {
STM32_DMA_CR_MBURST_INCR4; STM32_DMA_CR_MBURST_INCR4;
#endif #endif
if (sdcp->state == SDC_STOP) { if (sdcp->state == BLK_STOP) {
/* Note, the DMA must be enabled before the IRQs.*/ /* Note, the DMA must be enabled before the IRQs.*/
bool_t b; bool_t b;
b = dmaStreamAllocate(sdcp->dma, STM32_SDC_SDIO_IRQ_PRIORITY, NULL, NULL); b = dmaStreamAllocate(sdcp->dma, STM32_SDC_SDIO_IRQ_PRIORITY, NULL, NULL);
@ -376,7 +376,9 @@ void sdc_lld_start(SDCDriver *sdcp) {
*/ */
void sdc_lld_stop(SDCDriver *sdcp) { void sdc_lld_stop(SDCDriver *sdcp) {
if ((sdcp->state == SDC_READY) || (sdcp->state == SDC_ACTIVE)) { if (sdcp->state != BLK_STOP) {
/* SDIO deactivation.*/
SDIO->POWER = 0; SDIO->POWER = 0;
SDIO->CLKCR = 0; SDIO->CLKCR = 0;
SDIO->DCTRL = 0; SDIO->DCTRL = 0;

View File

@ -229,10 +229,6 @@ struct SDCDriver {
*/ */
const struct SDCDriverVMT *vmt; const struct SDCDriverVMT *vmt;
_mmcsd_block_device_data _mmcsd_block_device_data
/**
* @brief Driver state.
*/
sdcstate_t state;
/** /**
* @brief Current configuration data. * @brief Current configuration data.
*/ */

View File

@ -125,10 +125,10 @@ void sdcInit(void) {
*/ */
void sdcObjectInit(SDCDriver *sdcp) { void sdcObjectInit(SDCDriver *sdcp) {
sdcp->vmt = &sdc_vmt; sdcp->vmt = &sdc_vmt;
sdcp->state = SDC_STOP; sdcp->state = BLK_STOP;
sdcp->errors = SDC_NO_ERROR; sdcp->errors = SDC_NO_ERROR;
sdcp->config = NULL; sdcp->config = NULL;
sdcp->capacity = 0; sdcp->capacity = 0;
} }
@ -147,11 +147,11 @@ void sdcStart(SDCDriver *sdcp, const SDCConfig *config) {
chDbgCheck(sdcp != NULL, "sdcStart"); chDbgCheck(sdcp != NULL, "sdcStart");
chSysLock(); chSysLock();
chDbgAssert((sdcp->state == SDC_STOP) || (sdcp->state == SDC_READY), chDbgAssert((sdcp->state == BLK_STOP) || (sdcp->state == BLK_ACTIVE),
"sdcStart(), #1", "invalid state"); "sdcStart(), #1", "invalid state");
sdcp->config = config; sdcp->config = config;
sdc_lld_start(sdcp); sdc_lld_start(sdcp);
sdcp->state = SDC_READY; sdcp->state = BLK_ACTIVE;
chSysUnlock(); chSysUnlock();
} }
@ -167,17 +167,17 @@ void sdcStop(SDCDriver *sdcp) {
chDbgCheck(sdcp != NULL, "sdcStop"); chDbgCheck(sdcp != NULL, "sdcStop");
chSysLock(); chSysLock();
chDbgAssert((sdcp->state == SDC_STOP) || (sdcp->state == SDC_READY), chDbgAssert((sdcp->state == BLK_STOP) || (sdcp->state == BLK_ACTIVE),
"sdcStop(), #1", "invalid state"); "sdcStop(), #1", "invalid state");
sdc_lld_stop(sdcp); sdc_lld_stop(sdcp);
sdcp->state = SDC_STOP; sdcp->state = BLK_STOP;
chSysUnlock(); chSysUnlock();
} }
/** /**
* @brief Performs the initialization procedure on the inserted card. * @brief Performs the initialization procedure on the inserted card.
* @details This function should be invoked when a card is inserted and * @details This function should be invoked when a card is inserted and
* brings the driver in the @p SDC_ACTIVE state where it is possible * brings the driver in the @p BLK_READY state where it is possible
* to perform read and write operations. * to perform read and write operations.
* *
* @param[in] sdcp pointer to the @p SDCDriver object * @param[in] sdcp pointer to the @p SDCDriver object
@ -192,12 +192,11 @@ bool_t sdcConnect(SDCDriver *sdcp) {
uint32_t resp[1]; uint32_t resp[1];
chDbgCheck(sdcp != NULL, "sdcConnect"); chDbgCheck(sdcp != NULL, "sdcConnect");
chDbgAssert((sdcp->state == BLK_ACTIVE) || (sdcp->state == BLK_READY),
chSysLock();
chDbgAssert((sdcp->state == SDC_READY) || (sdcp->state == SDC_ACTIVE),
"mmcConnect(), #1", "invalid state"); "mmcConnect(), #1", "invalid state");
sdcp->state = SDC_CONNECTING;
chSysUnlock(); /* Connection procedure in progress.*/
sdcp->state = BLK_CONNECTING;
/* Card clock initialization.*/ /* Card clock initialization.*/
sdc_lld_start_clk(sdcp); sdc_lld_start_clk(sdcp);
@ -228,7 +227,7 @@ bool_t sdcConnect(SDCDriver *sdcp) {
} }
#if SDC_MMC_SUPPORT #if SDC_MMC_SUPPORT
if ((sdcp->cardmode & SDC_MODE_CARDTYPE_MASK) == SDC_MODE_CARDTYPE_MMC) { if ((sdcp->cardmode & SDC_MODE_CARDTYPE_MASK) == SDC_MODE_CARDTYPE_MMC) {
/* TODO: MMC initialization.*/ /* TODO: MMC initialization.*/
goto failed; goto failed;
} }
@ -311,13 +310,13 @@ bool_t sdcConnect(SDCDriver *sdcp) {
goto failed; goto failed;
/* Initialization complete.*/ /* Initialization complete.*/
sdcp->state = SDC_ACTIVE; sdcp->state = BLK_READY;
return CH_SUCCESS; return CH_SUCCESS;
/* Initialization failed.*/ /* Connection failed, state reset to BLK_ACTIVE.*/
failed: failed:
sdc_lld_stop_clk(sdcp); sdc_lld_stop_clk(sdcp);
sdcp->state = SDC_READY; sdcp->state = BLK_ACTIVE;
return CH_FAILED; return CH_FAILED;
} }
@ -337,29 +336,31 @@ bool_t sdcDisconnect(SDCDriver *sdcp) {
chDbgCheck(sdcp != NULL, "sdcDisconnect"); chDbgCheck(sdcp != NULL, "sdcDisconnect");
chSysLock(); chSysLock();
chDbgAssert((sdcp->state == SDC_READY) || (sdcp->state == SDC_ACTIVE), chDbgAssert((sdcp->state == BLK_ACTIVE) || (sdcp->state == BLK_READY),
"sdcDisconnect(), #1", "invalid state"); "sdcDisconnect(), #1", "invalid state");
if (sdcp->state == SDC_READY) { if (sdcp->state == BLK_ACTIVE) {
chSysUnlock(); chSysUnlock();
return CH_SUCCESS; return CH_SUCCESS;
} }
sdcp->state = SDC_DISCONNECTING; sdcp->state = BLK_DISCONNECTING;
chSysUnlock(); chSysUnlock();
/* Waits for eventual pending operations completion.*/ /* Waits for eventual pending operations completion.*/
if (_sdc_wait_for_transfer_state(sdcp)) if (_sdc_wait_for_transfer_state(sdcp)) {
sdc_lld_stop_clk(sdcp);
sdcp->state = BLK_ACTIVE;
return CH_FAILED; return CH_FAILED;
}
/* Card clock stopped.*/ /* Card clock stopped.*/
sdc_lld_stop_clk(sdcp); sdc_lld_stop_clk(sdcp);
sdcp->state = BLK_ACTIVE;
sdcp->state = SDC_READY;
return CH_SUCCESS; return CH_SUCCESS;
} }
/** /**
* @brief Reads one or more blocks. * @brief Reads one or more blocks.
* @pre The driver must be in the @p SDC_ACTIVE state after a successful * @pre The driver must be in the @p BLK_READY state after a successful
* sdcConnect() invocation. * sdcConnect() invocation.
* *
* @param[in] sdcp pointer to the @p SDCDriver object * @param[in] sdcp pointer to the @p SDCDriver object
@ -378,25 +379,26 @@ bool_t sdcRead(SDCDriver *sdcp, uint32_t startblk,
bool_t status; bool_t status;
chDbgCheck((sdcp != NULL) && (buf != NULL) && (n > 0), "sdcRead"); chDbgCheck((sdcp != NULL) && (buf != NULL) && (n > 0), "sdcRead");
chDbgAssert(sdcp->state == BLK_READY, "sdcRead(), #1", "invalid state");
if ((startblk + n - 1) > sdcp->capacity){ if ((startblk + n - 1) > sdcp->capacity){
sdcp->errors |= SDC_OVERFLOW_ERROR; sdcp->errors |= SDC_OVERFLOW_ERROR;
return CH_FAILED; return CH_FAILED;
} }
chSysLock(); /* Read operation in progress.*/
chDbgAssert(sdcp->state == SDC_ACTIVE, "sdcRead(), #1", "invalid state"); sdcp->state = BLK_READING;
sdcp->state = SDC_READING;
chSysUnlock();
status = sdc_lld_read(sdcp, startblk, buf, n); status = sdc_lld_read(sdcp, startblk, buf, n);
sdcp->state = SDC_ACTIVE;
/* Read operation finished.*/
sdcp->state = BLK_READY;
return status; return status;
} }
/** /**
* @brief Writes one or more blocks. * @brief Writes one or more blocks.
* @pre The driver must be in the @p SDC_ACTIVE state after a successful * @pre The driver must be in the @p BLK_READY state after a successful
* sdcConnect() invocation. * sdcConnect() invocation.
* *
* @param[in] sdcp pointer to the @p SDCDriver object * @param[in] sdcp pointer to the @p SDCDriver object
@ -415,19 +417,20 @@ bool_t sdcWrite(SDCDriver *sdcp, uint32_t startblk,
bool_t status; bool_t status;
chDbgCheck((sdcp != NULL) && (buf != NULL) && (n > 0), "sdcWrite"); chDbgCheck((sdcp != NULL) && (buf != NULL) && (n > 0), "sdcWrite");
chDbgAssert(sdcp->state == BLK_READY, "sdcWrite(), #1", "invalid state");
if ((startblk + n - 1) > sdcp->capacity){ if ((startblk + n - 1) > sdcp->capacity){
sdcp->errors |= SDC_OVERFLOW_ERROR; sdcp->errors |= SDC_OVERFLOW_ERROR;
return CH_FAILED; return CH_FAILED;
} }
chSysLock(); /* Write operation in progress.*/
chDbgAssert(sdcp->state == SDC_ACTIVE, "sdcWrite(), #1", "invalid state"); sdcp->state = BLK_WRITING;
sdcp->state = SDC_WRITING;
chSysUnlock();
status = sdc_lld_write(sdcp, startblk, buf, n); status = sdc_lld_write(sdcp, startblk, buf, n);
sdcp->state = SDC_ACTIVE;
/* Write operation finished.*/
sdcp->state = BLK_READY;
return status; return status;
} }
@ -442,6 +445,8 @@ bool_t sdcWrite(SDCDriver *sdcp, uint32_t startblk,
sdcflags_t sdcGetAndClearErrors(SDCDriver *sdcp) { sdcflags_t sdcGetAndClearErrors(SDCDriver *sdcp) {
chDbgCheck(sdcp != NULL, "sdcGetAndClearErrors"); chDbgCheck(sdcp != NULL, "sdcGetAndClearErrors");
chDbgAssert(sdcp->state == BLK_READY,
"sdcGetAndClearErrors(), #1", "invalid state");
chSysLock(); chSysLock();
sdcflags_t flags = sdcp->errors; sdcflags_t flags = sdcp->errors;
@ -465,12 +470,8 @@ bool_t sdcSync(SDCDriver *sdcp) {
chDbgCheck(sdcp != NULL, "sdcSync"); chDbgCheck(sdcp != NULL, "sdcSync");
chSysLock(); if (sdcp->state != BLK_READY)
if (sdcp->state != SDC_READY) {
chSysUnlock();
return CH_FAILED; return CH_FAILED;
}
chSysUnlock();
return sdc_lld_sync(sdcp); return sdc_lld_sync(sdcp);
} }
@ -489,15 +490,10 @@ bool_t sdcSync(SDCDriver *sdcp) {
*/ */
bool_t sdcGetInfo(SDCDriver *sdcp, BlockDeviceInfo *bdip) { bool_t sdcGetInfo(SDCDriver *sdcp, BlockDeviceInfo *bdip) {
chDbgCheck((sdcp != NULL) && (bdip != NULL), "sdcGetInfo"); chDbgCheck((sdcp != NULL) && (bdip != NULL), "sdcGetInfo");
chSysLock(); if (sdcp->state != BLK_READY)
if (sdcp->state != SDC_READY) {
chSysUnlock();
return CH_FAILED; return CH_FAILED;
}
chSysUnlock();
bdip->blk_num = sdcp->capacity; bdip->blk_num = sdcp->capacity;
bdip->blk_size = MMCSD_BLOCK_SIZE; bdip->blk_size = MMCSD_BLOCK_SIZE;
@ -523,29 +519,36 @@ bool_t sdcErase(SDCDriver *sdcp, uint32_t startblk, uint32_t endblk) {
uint32_t resp[1]; uint32_t resp[1];
chDbgCheck((sdcp != NULL), "sdcErase"); chDbgCheck((sdcp != NULL), "sdcErase");
chDbgAssert(sdcp->state == BLK_READY, "sdcErase(), #1", "invalid state");
/* Driver handles data in 512 bytes blocks (just like HC cards). But if we /* Handling command differences between HC and normal cards.*/
have not HC card than we must convert address from blocks to bytes.*/
if (!(sdcp->cardmode & SDC_MODE_HIGH_CAPACITY)) { if (!(sdcp->cardmode & SDC_MODE_HIGH_CAPACITY)) {
startblk *= MMCSD_BLOCK_SIZE; startblk *= MMCSD_BLOCK_SIZE;
endblk *= MMCSD_BLOCK_SIZE; endblk *= MMCSD_BLOCK_SIZE;
} }
_sdc_wait_for_transfer_state( sdcp ); _sdc_wait_for_transfer_state(sdcp);
if (sdc_lld_send_cmd_short_crc(sdcp, MMCSD_CMD_ERASE_RW_BLK_START, startblk, resp) != CH_SUCCESS || MMCSD_R1_ERROR(resp[0])) if ((sdc_lld_send_cmd_short_crc(sdcp, MMCSD_CMD_ERASE_RW_BLK_START,
startblk, resp) != CH_SUCCESS) ||
MMCSD_R1_ERROR(resp[0]))
return CH_FAILED; return CH_FAILED;
if (sdc_lld_send_cmd_short_crc(sdcp, MMCSD_CMD_ERASE_RW_BLK_END, endblk, resp) != CH_SUCCESS || MMCSD_R1_ERROR(resp[0])) if ((sdc_lld_send_cmd_short_crc(sdcp, MMCSD_CMD_ERASE_RW_BLK_END,
endblk, resp) != CH_SUCCESS) ||
MMCSD_R1_ERROR(resp[0]))
return CH_FAILED; return CH_FAILED;
if (sdc_lld_send_cmd_short_crc(sdcp, MMCSD_CMD_ERASE, 0, resp) != CH_SUCCESS || MMCSD_R1_ERROR(resp[0])) if ((sdc_lld_send_cmd_short_crc(sdcp, MMCSD_CMD_ERASE,
0, resp) != CH_SUCCESS) ||
MMCSD_R1_ERROR(resp[0]))
return CH_FAILED; return CH_FAILED;
/* Quick sleep to allow it to transition to programming or receiving state */ /* Quick sleep to allow it to transition to programming or receiving state */
/* TODO: ??????????????????????????? */
/* Wait for it to return to transfer state to indicate it has finished erasing */ /* Wait for it to return to transfer state to indicate it has finished erasing */
_sdc_wait_for_transfer_state( sdcp ); _sdc_wait_for_transfer_state(sdcp);
return CH_SUCCESS; return CH_SUCCESS;
} }