lpc177x_8x_mmcard_sdio.c 28 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003
  1. /*
  2. * Copyright (C) 2012 by Rob van Lieshout (info@pragmalab.nl)
  3. * Copyright (C) 2012 by Ole Reinhardt (ole.reinhardt@embedded-it.de)
  4. * Copyright (C) 2008 by egnite GmbH.
  5. *
  6. * All rights reserved.
  7. *
  8. * Redistribution and use in source and binary forms, with or without
  9. * modification, are permitted provided that the following conditions
  10. * are met:
  11. *
  12. * 1. Redistributions of source code must retain the above copyright
  13. * notice, this list of conditions and the following disclaimer.
  14. * 2. Redistributions in binary form must reproduce the above copyright
  15. * notice, this list of conditions and the following disclaimer in the
  16. * documentation and/or other materials provided with the distribution.
  17. * 3. Neither the name of the copyright holders nor the names of
  18. * contributors may be used to endorse or promote products derived
  19. * from this software without specific prior written permission.
  20. *
  21. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  22. * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  23. * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
  24. * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
  25. * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
  26. * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
  27. * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
  28. * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
  29. * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
  30. * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
  31. * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  32. * SUCH DAMAGE.
  33. *
  34. * For additional information see http://www.ethernut.de/
  35. */
  36. /*!
  37. * \brief Basic block device driver for multimedia cards.
  38. *
  39. * The driver uses SDIO mode, 4-bit bus
  40. *
  41. */
  42. #include <cfg/mmci.h>
  43. #include <errno.h>
  44. #include <string.h>
  45. #include <stdlib.h>
  46. #include <sys/heap.h>
  47. #include <sys/timer.h>
  48. #include <sys/event.h>
  49. #include <fs/dospart.h>
  50. #include <fs/fs.h>
  51. #include <dev/blockdev.h>
  52. #include "arch/cm3/nxp/lpc177x_8x_mmcard_sdio.h"
  53. #include "arch/cm3/nxp/lpc177x_8x_mci.h"
  54. #ifdef NUTDEBUG
  55. #include <stdio.h>
  56. #endif
  57. /*!
  58. * \addtogroup Card
  59. */
  60. /*@{*/
  61. typedef struct _MCIFC
  62. {
  63. uint32_t ifc_config; /*! \brief Configuration flags. */
  64. uint32_t ifc_opcond; /*! \brief Operating conditions. */
  65. uint32_t ifc_reladdr; /*! \brief Relative card address. */
  66. uint8_t *ifc_buff; /*! \brief Pointer to sector buffer. */
  67. uint32_t ifc_csd[4]; /*! \brief Card Specific Data CSD. */
  68. //uint32_t ifc_cid[4]; /*! \brief Card identification. */
  69. uint8_t ifc_admode; /*! \brief adressing mode */
  70. } MCIFC;
  71. /*!
  72. * \brief Local multimedia card mount information.
  73. */
  74. typedef struct _MMCFCB
  75. {
  76. /*! \brief Attached file system device.
  77. */
  78. NUTDEVICE *fcb_fsdev;
  79. /*! \brief Partition table entry of the currently mounted partition.
  80. */
  81. DOSPART fcb_part;
  82. /*! \brief Next block number to read.
  83. *
  84. * The file system driver will send a NUTBLKDEV_SEEK control command
  85. * to set this value before calling the read or the write routine.
  86. *
  87. * The number is partition relative.
  88. */
  89. uint32_t fcb_blknum;
  90. /*! \brief Internal block buffer.
  91. *
  92. * A file system driver may use this one or optionally provide it's
  93. * own buffers.
  94. *
  95. * Minimal systems may share their external bus interface with
  96. * device I/O lines, in which case the buffer must be located
  97. * in internal memory.
  98. */
  99. u_char fcb_blkbuf[MMC_BLOCK_SIZE];
  100. } MMCFCB;
  101. /* Flags to check whether a partition table is present or not */
  102. #define MBR_P_TABLE_PRESENT 0
  103. #define MBR_P_TABLE_NOT_PRESENT 1
  104. /*
  105. * Several routines call NutSleep, which results in a context switch.
  106. * This mutual exclusion semaphore takes care, that multiple threads
  107. * do not interfere with each other.
  108. */
  109. static HANDLE mutex;
  110. static MCIFC mci0_ifc;
  111. static st_Mci_CardId cidval;
  112. /* local routines */
  113. static uint32_t Lpc177x_8x_MmcardWriteData(uint8_t*, int, int);
  114. static uint32_t Lpc177x_8x_MmcardReadData(uint8_t*, int, int);
  115. static int Lpc177x_8x_MmcardUnmount(NUTFILE * nfp);
  116. #ifdef NUTDEBUG
  117. static void Lpc177x_8x_MmcardShowStatusBits(uint32_t);
  118. #endif
  119. /*-------------------------------------------------------------------------*/
  120. /* start of code */
  121. /*-------------------------------------------------------------------------*/
  122. #ifdef NUTDEBUG
  123. /************************************************************************//**
  124. * \brief Show status bits for MCI_status word
  125. *
  126. * \param None
  127. *
  128. * \return None
  129. ****************************************************************************/
  130. static void Lpc177x_8x_MmcardShowStatusBits(uint32_t MCIStatus)
  131. {
  132. if (MCIStatus & MCI_CMD_CRC_FAIL)
  133. {
  134. printf("MCI_CMD_CRC_FAIL\n");
  135. }
  136. if (MCIStatus & MCI_DATA_CRC_FAIL)
  137. {
  138. printf("MCI_DATA_CRC_FAIL\n");
  139. }
  140. if (MCIStatus & MCI_CMD_TIMEOUT)
  141. {
  142. printf("MCI_CMD_TIMEOUT\n");
  143. }
  144. if (MCIStatus & MCI_DATA_TIMEOUT)
  145. {
  146. printf("MCI_DATA_TIMEOUT\n");
  147. }
  148. if (MCIStatus & MCI_TX_UNDERRUN)
  149. {
  150. printf("MCI_TX_UNDERRUN\n");
  151. }
  152. if (MCIStatus & MCI_RX_OVERRUN)
  153. {
  154. printf("MCI_RX_OVERRUN\n");
  155. }
  156. if (MCIStatus & MCI_CMD_RESP_END)
  157. {
  158. printf("MCI_CMD_RESP_END\n");
  159. }
  160. if (MCIStatus & MCI_CMD_SENT)
  161. {
  162. printf("MCI_CMD_SENT\n");
  163. }
  164. if (MCIStatus & MCI_DATA_END)
  165. {
  166. printf("MCI_DATA_END\n");
  167. }
  168. if (MCIStatus & MCI_START_BIT_ERR)
  169. {
  170. printf("MCI_START_BIT_ERR\n");
  171. }
  172. if (MCIStatus & MCI_DATA_BLK_END)
  173. {
  174. printf("MCI_DATA_BLK_END\n");
  175. }
  176. if (MCIStatus & MCI_CMD_ACTIVE)
  177. {
  178. printf("MCI_CMD_ACTIVE\n");
  179. }
  180. if (MCIStatus & MCI_TX_ACTIVE)
  181. {
  182. printf("MCI_TX_ACTIVE\n");
  183. }
  184. if (MCIStatus & MCI_RX_ACTIVE)
  185. {
  186. printf("MCI_RX_ACTIVE\n");
  187. }
  188. if (MCIStatus & MCI_TX_HALF_EMPTY)
  189. {
  190. printf("MCI_TX_HALF_EMPTY\n");
  191. }
  192. if (MCIStatus & MCI_RX_HALF_FULL)
  193. {
  194. printf("MCI_RX_HALF_FULL\n");
  195. }
  196. if (MCIStatus & MCI_TX_FIFO_FULL)
  197. {
  198. printf("MCI_TX_FIFO_FULL\n");
  199. }
  200. if (MCIStatus & MCI_RX_FIFO_FULL)
  201. {
  202. printf("MCI_RX_FIFO_FULL\n");
  203. }
  204. if (MCIStatus & MCI_TX_FIFO_EMPTY)
  205. {
  206. printf("MCI_TX_FIFO_EMPTY\n");
  207. }
  208. if (MCIStatus & MCI_RX_FIFO_EMPTY)
  209. {
  210. printf("MCI_RX_FIFO_EMPTY\n");
  211. }
  212. if (MCIStatus & MCI_TX_DATA_AVAIL)
  213. {
  214. printf("MCI_TX_DATA_AVAIL\n");
  215. }
  216. if (MCIStatus & MCI_RX_DATA_AVAIL)
  217. {
  218. printf("MCI_RX_DATA_AVAIL\n");
  219. }
  220. }
  221. #endif
  222. /*!
  223. * \brief read n-blocks of data, starting at blocknum. Wait for ending!
  224. *
  225. * \param buffer Pointer to the data buffer to fill.
  226. * \param blk first blocknumber to read
  227. * \param num Maximum number of blocks to write. Please note the buffer
  228. * should be able to contain the data. No boundery test is performed
  229. *
  230. * \return A return value of <0 indicates an error.
  231. */
  232. static uint32_t Lpc177x_8x_MmcardReadData(uint8_t* buffer, int blk, int num)
  233. {
  234. int32_t retVal;
  235. uint32_t errorState;
  236. /* Gain mutex access. */
  237. NutEventWait(&mutex, 0);
  238. retVal = Lpc177x_8x_MciReadBlock(buffer, blk, num);
  239. if (retVal == MCI_FUNC_OK)
  240. {
  241. /*
  242. * Reading blocks have started, now wait till this job is finished
  243. * Please note the driver uses 16 word FIFO in the background to
  244. * transfer the data under interrupt from the card
  245. */
  246. while (Lpc177x_8x_MciGetDataXferEndState() != 0);
  247. errorState = Lpc177x_8x_MciGetXferErrState();
  248. if ((num > 1) || errorState)
  249. {
  250. Lpc177x_8x_MciCmd_StopTransmission();
  251. }
  252. if (errorState)
  253. {
  254. #ifdef NUTDEBUG
  255. printf("%s() failed\n", __FUNCTION__);
  256. Lpc177x_8x_MmcardShowStatusBits(errorState);
  257. #endif
  258. // perform 1 retry in case of an error
  259. retVal = Lpc177x_8x_MciReadBlock(buffer, blk, num);
  260. if (retVal == MCI_FUNC_OK)
  261. {
  262. /*
  263. * Reading blocks have started, now wait till this job is finished
  264. * Please note the driver uses 16 word FIFO in the background to
  265. * transfer the data under interrupt from the card
  266. */
  267. while (Lpc177x_8x_MciGetDataXferEndState() != 0);
  268. errorState = Lpc177x_8x_MciGetXferErrState();
  269. if ((num > 1) || errorState)
  270. {
  271. Lpc177x_8x_MciCmd_StopTransmission();
  272. }
  273. if (errorState)
  274. {
  275. #ifdef NUTDEBUG
  276. printf("%s() failed again\n", __FUNCTION__);
  277. Lpc177x_8x_MmcardShowStatusBits(errorState);
  278. #endif
  279. retVal = MCI_FUNC_FAILED;
  280. }
  281. }
  282. }
  283. }
  284. /* Release mutex access. */
  285. NutEventPost(&mutex);
  286. return(retVal);
  287. }
  288. /*!
  289. * \brief write n-blocks of data, starting at blocknum. Wait for ending!
  290. *
  291. * \param buffer Pointer to the data buffer to write from.
  292. * \param blk first blocknumber to write
  293. * \param num Maximum number of blocks to write.
  294. *
  295. * \return A return value of <0 indicates an error.
  296. */
  297. static uint32_t Lpc177x_8x_MmcardWriteData(uint8_t* buffer, int blk, int num)
  298. {
  299. int32_t retVal;
  300. uint32_t errorState;
  301. /* Gain mutex access. */
  302. NutEventWait(&mutex, 0);
  303. retVal = Lpc177x_8x_MciWriteBlock(buffer, blk, num);
  304. if (retVal == MCI_FUNC_OK)
  305. {
  306. /*
  307. * Writing blocks have started, now wait till this job is finished
  308. * Please note the driver uses 16 word FIFO in the background to
  309. * transfer the data under interrupt to the card
  310. */
  311. while (Lpc177x_8x_MciGetDataXferEndState() != 0);
  312. errorState = Lpc177x_8x_MciGetXferErrState();
  313. if ((num > 1) || errorState)
  314. {
  315. Lpc177x_8x_MciCmd_StopTransmission();
  316. }
  317. if (errorState)
  318. {
  319. #ifdef NUTDEBUG
  320. printf("%s() failed\n", __FUNCTION__ );
  321. Lpc177x_8x_MmcardShowStatusBits(errorState);
  322. #endif
  323. retVal = MCI_FUNC_FAILED;
  324. }
  325. }
  326. /* Release mutex access. */
  327. NutEventPost(&mutex);
  328. return(retVal);
  329. }
  330. /*!
  331. * \brief Initialize the multimedia card.
  332. *
  333. *
  334. * \param ifc Specifies the hardware interface.
  335. *
  336. * \return 0 on success, -1 otherwise.
  337. */
  338. static int Lpc177x_8x_MmcardInit(NUTDEVICE * dev)
  339. {
  340. int32_t retVal;
  341. en_Mci_CardType cardType;
  342. uint32_t rcAddress;
  343. MCIFC *ifc = (MCIFC *) dev->dev_icb;
  344. /* set default for addressing mode */
  345. ifc->ifc_admode = MMC_BLOCK_MODE;
  346. /* reset card data */
  347. memset(ifc->ifc_csd, 0, sizeof(ifc->ifc_csd));
  348. memset(&cidval, 0, sizeof(st_Mci_CardId));
  349. /*********************************/
  350. /* Init */
  351. /*********************************/
  352. retVal = Lpc177x_8x_MciInit(BRD_MCI_POWERED_ACTIVE_LEVEL);
  353. if (retVal != MCI_FUNC_OK)
  354. {
  355. #ifdef NUTDEBUG
  356. printf("%s() MciInit failed\n", __FUNCTION__ );
  357. #endif
  358. return((int)retVal);
  359. }
  360. /*********************************/
  361. /* CardType */
  362. /*********************************/
  363. cardType = Lpc177x_8x_MciGetCardType();
  364. if (cardType == MCI_CARD_UNKNOWN)
  365. {
  366. #ifdef NUTDEBUG
  367. printf("%s() Get Card Type\n", __FUNCTION__ );
  368. #endif
  369. return(MCI_FUNC_FAILED);
  370. }
  371. else
  372. {
  373. // the cardtype will tell us if BLOCK or BYTE addressing whould be used
  374. if (cardType == MCI_SDHC_SDXC_CARD)
  375. {
  376. ifc->ifc_admode = MMC_BYTE_MODE;
  377. }
  378. }
  379. /*********************************/
  380. /* CID */
  381. /*********************************/
  382. retVal = Lpc177x_8x_MciGetCID(&cidval);
  383. if (retVal != MCI_FUNC_OK)
  384. {
  385. #ifdef NUTDEBUG
  386. printf("%s() Get CID failed\n", __FUNCTION__ );
  387. #endif
  388. return((int)retVal);
  389. }
  390. /*********************************/
  391. /* Card Address */
  392. /*********************************/
  393. retVal = Lpc177x_8x_MciSetCardAddress();
  394. if (retVal != MCI_FUNC_OK)
  395. {
  396. #ifdef NUTDEBUG
  397. printf("%s() Set card address failed\n", __FUNCTION__ );
  398. #endif
  399. return((int)retVal);
  400. }
  401. else
  402. {
  403. rcAddress = Lpc177x_8x_MciGetCardAddress();
  404. ifc->ifc_reladdr = rcAddress;
  405. }
  406. /*********************************/
  407. /* CSD */
  408. /*********************************/
  409. retVal = Lpc177x_8x_MciGetCSD(ifc->ifc_csd);
  410. if (retVal != MCI_FUNC_OK)
  411. {
  412. #ifdef NUTDEBUG
  413. printf("%s() GetCSD failed\n", __FUNCTION__ );
  414. #endif
  415. return((int)retVal);
  416. }
  417. /*********************************/
  418. /* Card Select */
  419. /*********************************/
  420. retVal = Lpc177x_8x_MciCmd_SelectCard();
  421. if (retVal != MCI_FUNC_OK)
  422. {
  423. #ifdef NUTDEBUG
  424. printf("%s() Card select CMD failed\n", __FUNCTION__ );
  425. #endif
  426. return((int)retVal);
  427. }
  428. /*********************************/
  429. /* Bandwidth */
  430. /*********************************/
  431. if (cardType == MCI_SDSC_V1_CARD || cardType == MCI_SDSC_V2_CARD || cardType == MCI_SDHC_SDXC_CARD)
  432. {
  433. Lpc177x_8x_MciSetClock( MCI_NORMAL_RATE );
  434. if (Lpc177x_8x_MciSetBusWidth( SD_4_BIT ) != MCI_FUNC_OK)
  435. {
  436. return((int)retVal);
  437. }
  438. }
  439. /*********************************/
  440. /* BlockLength */
  441. /*********************************/
  442. retVal = Lpc177x_8x_MciSetBlockLen(BLOCK_LENGTH);
  443. if (retVal != MCI_FUNC_OK)
  444. {
  445. return((int)retVal);
  446. }
  447. return(MCI_FUNC_OK);
  448. }
  449. /*!
  450. * \brief Read data blocks from a mounted partition.
  451. *
  452. * Applications should not call this function directly, but use the
  453. * stdio interface.
  454. *
  455. * \param nfp Pointer to a ::NUTFILE structure, obtained by a previous
  456. * call to MmCardMount().
  457. * \param buffer Pointer to the data buffer to fill.
  458. * \param num Maximum number of blocks to read. However, reading
  459. * multiple blocks is not yet supported by this driver.
  460. *
  461. * \return The number of blocks actually read. A return value of -1
  462. * indicates an error.
  463. */
  464. static int Lpc177x_8x_MmcardBlockRead(NUTFILE * nfp, void *buffer, int num)
  465. {
  466. MMCFCB *fcb = (MMCFCB *) nfp->nf_fcb;
  467. uint32_t blk = fcb->fcb_blknum;
  468. NUTDEVICE *dev = (NUTDEVICE *) nfp->nf_dev;
  469. MCIFC *ifc = (MCIFC *) dev->dev_icb;
  470. if (buffer == 0)
  471. {
  472. buffer = fcb->fcb_blkbuf;
  473. }
  474. /*
  475. * when using the filesystem, the sectornumbering is different then when
  476. * directly accesing the card. For example, the MBR can be found at the
  477. * sector 0 of the card, but the filesystem's first sector is the sector
  478. * where the start is of the FAT VolumeID (also called the BOOT SECTOR).
  479. * This position (or offset) is indicated by reading the partion-table,
  480. * more specific: by reading the LBA begin info.
  481. * This offset we need to add here to the sector# we get in as
  482. * parameter. This way we acces the real sector on the card.
  483. *
  484. */
  485. if ((ifc->ifc_config & MBR_P_TABLE_NOT_PRESENT) == 0)
  486. {
  487. // only add offset if a partition table was present, else, don't add anything
  488. blk += fcb->fcb_part.part_sect_offs;
  489. }
  490. if (ifc->ifc_admode == MMC_BLOCK_MODE)
  491. {
  492. // apply addressing mode here
  493. blk *= BLOCK_LENGTH;
  494. }
  495. if (Lpc177x_8x_MmcardReadData(fcb->fcb_blkbuf, blk, 1) == MCI_FUNC_OK)
  496. {
  497. // return the number of blocks that were succesfully read
  498. return(num);
  499. }
  500. #ifdef NUTDEBUG
  501. printf("%s() failed\n", __FUNCTION__ );
  502. #endif
  503. return(-1);
  504. }
  505. /*!
  506. * \brief Write data blocks to a mounted partition.
  507. *
  508. * Applications should not call this function directly, but use the
  509. * stdio interface.
  510. *
  511. * \param nfp Pointer to a \ref NUTFILE structure, obtained by a previous
  512. * call to MmCardMount().
  513. * \param buffer Pointer to the data to be written.
  514. * \param num Maximum number of blocks to write. However, writing
  515. * multiple blocks is not yet supported by this driver.
  516. *
  517. * \return The number of blocks written. A return value of -1 indicates an
  518. * error.
  519. */
  520. static int Lpc177x_8x_MmcardBlockWrite(NUTFILE * nfp, const void *buffer, int num)
  521. {
  522. MMCFCB *fcb = (MMCFCB *) nfp->nf_fcb;
  523. uint32_t blk = fcb->fcb_blknum;
  524. NUTDEVICE *dev = (NUTDEVICE *) nfp->nf_dev;
  525. MCIFC *ifc = (MCIFC *) dev->dev_icb;
  526. if (buffer == 0)
  527. {
  528. buffer = fcb->fcb_blkbuf;
  529. }
  530. /*
  531. * when using the filesystem, the sectornumbering is different then when
  532. * directly accesing the card. For example, the MBR can be found at the
  533. * sector 0 of the card, but the filesystem's first sector is the sector
  534. * where the start is of the FAT VolumeID (also called the BOOT SECTOR).
  535. * This position (or offset) is indicated by reading the partion-table,
  536. * more specific: by reading the LBA begin info.
  537. * This offset we need to add here to the sector# we get in as
  538. * parameter. This way we acces the real sector on the card.
  539. *
  540. */
  541. if ((ifc->ifc_config & MBR_P_TABLE_NOT_PRESENT) == 0)
  542. {
  543. // only add offset if a partition table was present, else, don't add anything
  544. blk += fcb->fcb_part.part_sect_offs;
  545. }
  546. if (ifc->ifc_admode == MMC_BLOCK_MODE)
  547. {
  548. // apply addressing mode here
  549. blk *= BLOCK_LENGTH;
  550. }
  551. if (Lpc177x_8x_MmcardWriteData((uint8_t*)buffer, blk, num) == MCI_FUNC_OK)
  552. {
  553. return(num);
  554. }
  555. #ifdef NUTDEBUG
  556. printf("%s() failed\n", __FUNCTION__ );
  557. #endif
  558. return(-1);
  559. }
  560. /*!
  561. * \brief Mount a partition.
  562. *
  563. * Nut/OS doesn't provide specific routines for mounting. Instead routines
  564. * for opening files are used.
  565. *
  566. * Applications should not directly call this function, but use the high
  567. * level stdio routines for opening a file.
  568. *
  569. * \param dev Pointer to the MMC device.
  570. * \param name Partition number followed by a slash followed by a name
  571. * of the file system device. Both items are optional. If no
  572. * file system driver name is given, the first file system
  573. * driver found in the list of registered devices will be
  574. * used. If no partition number is specified or if partition
  575. * zero is given, the first active primary partition will be
  576. * used.
  577. * \param mode Opening mode. Currently ignored, but
  578. * \code _O_RDWR | _O_BINARY \endcode should be used for
  579. * compatibility with future enhancements.
  580. * \param acc File attributes, ignored.
  581. *
  582. * \return Pointer to a newly created file pointer to the mounted
  583. * partition or NUTFILE_EOF in case of any error.
  584. */
  585. static NUTFILE *Lpc177x_8x_MmcardMount(NUTDEVICE * dev, const char *name, int mode, int acc)
  586. {
  587. int partno = 0;
  588. u_int i;
  589. NUTDEVICE *fsdev;
  590. NUTFILE *nfp;
  591. MMCFCB *fcb;
  592. DOSPART *part;
  593. MCIFC *ifc = (MCIFC *) dev->dev_icb;
  594. FSCP_VOL_MOUNT mparm;
  595. /* Set the card in SDIO mode and check for SD-HC cards. */
  596. if (Lpc177x_8x_MmcardInit(dev))
  597. {
  598. errno = ENODEV;
  599. #ifdef NUTDEBUG
  600. printf("%s() Card init failed\n", __FUNCTION__ );
  601. #endif
  602. return(NUTFILE_EOF);
  603. }
  604. ifc->ifc_config = 0; // make sure a default is set before adding new info later on
  605. /* Parse the name for a partition number and a file system driver. */
  606. if (*name)
  607. {
  608. partno = atoi(name);
  609. do
  610. {
  611. name++;
  612. } while (*name && *name != '/');
  613. if (*name == '/')
  614. {
  615. name++;
  616. }
  617. }
  618. /*
  619. * Check the list of registered devices for the given name of the
  620. * files system driver. If none has been specified, get the first
  621. * file system driver in the list. Hopefully the application
  622. * registered one only.
  623. */
  624. for (fsdev = nutDeviceList; fsdev; fsdev = fsdev->dev_next)
  625. {
  626. if (*name == 0)
  627. {
  628. if (fsdev->dev_type == IFTYP_FS)
  629. {
  630. break;
  631. }
  632. }
  633. else if (strcmp(fsdev->dev_name, name) == 0)
  634. {
  635. break;
  636. }
  637. }
  638. if (fsdev == 0)
  639. {
  640. #ifdef NUTDEBUG
  641. printf("%s() FS driver not found\n", __FUNCTION__ );
  642. #endif
  643. errno = ENODEV;
  644. return(NUTFILE_EOF);
  645. }
  646. if ((fcb = NutHeapAllocClear(sizeof(MMCFCB))) == 0)
  647. {
  648. errno = ENOMEM;
  649. #ifdef NUTDEBUG
  650. printf("%s() Out of memory\n", __FUNCTION__ );
  651. #endif
  652. return(NUTFILE_EOF);
  653. }
  654. // link this block-device driver with the file system device driver
  655. fcb->fcb_fsdev = fsdev;
  656. // Initialize MMC access mutex semaphore. */
  657. NutEventPost(&mutex);
  658. /* Read MBR. */
  659. if (Lpc177x_8x_MmcardReadData(fcb->fcb_blkbuf, 0, 1) != MCI_FUNC_OK)
  660. {
  661. NutHeapFree(fcb);
  662. #ifdef NUTDEBUG
  663. printf("%s() Reading MBR failed\n", __FUNCTION__);
  664. #endif
  665. return(NUTFILE_EOF);
  666. }
  667. // check sanity of MBR
  668. if ((fcb->fcb_blkbuf[510]!=0x55) || (fcb->fcb_blkbuf[511]!=0xAA))
  669. {
  670. #ifdef NUTDEBUG
  671. printf("%s() Invalid MBR\n", __FUNCTION__ );
  672. #endif
  673. NutHeapFree(fcb);
  674. return(NUTFILE_EOF);
  675. }
  676. /* Read partition table. */
  677. part = (DOSPART *) & fcb->fcb_blkbuf[DOSPART_SECTORPOS];
  678. for (i = 1; i <= 4; i++)
  679. {
  680. if (partno)
  681. {
  682. if (i == partno)
  683. {
  684. /* Found specified partition number. */
  685. fcb->fcb_part = *part;
  686. break;
  687. }
  688. }
  689. else if (part->part_state & 0x80)
  690. {
  691. /* Located first active partition. */
  692. fcb->fcb_part = *part;
  693. break;
  694. }
  695. part++;
  696. }
  697. if (fcb->fcb_part.part_type == PTYPE_EMPTY)
  698. {
  699. #ifdef NUTDEBUG
  700. printf("%s() Invalid partition type\n", __FUNCTION__ );
  701. #endif
  702. NutHeapFree(fcb);
  703. return(NUTFILE_EOF);
  704. }
  705. #ifdef NUTDEBUG
  706. printf("Number of sectors %lu\n", fcb->fcb_part.part_sects);
  707. printf("Starting LBA %lu\n", fcb->fcb_part.part_sect_offs);
  708. #endif
  709. if ((nfp = NutHeapAllocClear(sizeof(NUTFILE))) == 0)
  710. {
  711. NutHeapFree(fcb);
  712. errno = ENOMEM;
  713. #ifdef NUTDEBUG
  714. printf("%s() Out of memory\n", __FUNCTION__ );
  715. #endif
  716. return(NUTFILE_EOF);
  717. }
  718. nfp->nf_dev = dev;
  719. nfp->nf_fcb = fcb;
  720. /*
  721. * Mount the file system volume.
  722. */
  723. mparm.fscp_bmnt = nfp;
  724. mparm.fscp_part_type = fcb->fcb_part.part_type;
  725. if (fsdev->dev_ioctl(fsdev, FS_VOL_MOUNT, &mparm))
  726. {
  727. #ifdef NUTDEBUG
  728. printf("%s() Mounting failed, try without partition table\n", __FUNCTION__ );
  729. #endif
  730. // try again, this time leaving out the partition table offset
  731. ifc->ifc_config |= MBR_P_TABLE_NOT_PRESENT;
  732. if (fsdev->dev_ioctl(fsdev, FS_VOL_MOUNT, &mparm))
  733. {
  734. // failed again...
  735. // destroy allocated nfp block (and UNMOUNT the FS (again))
  736. Lpc177x_8x_MmcardUnmount(nfp);
  737. #ifdef NUTDEBUG
  738. printf("%s() No FAT filesystem found, mounting failed\n", __FUNCTION__ );
  739. #endif
  740. NutHeapFree(fcb);
  741. return(NUTFILE_EOF);
  742. }
  743. }
  744. return(nfp);
  745. }
  746. /*!
  747. * \brief Unmount a previously mounted partition.
  748. *
  749. * Applications should not directly call this function, but use the high
  750. * level stdio routines for closing a previously opened file.
  751. *
  752. * \return 0 on success, -1 otherwise.
  753. */
  754. static int Lpc177x_8x_MmcardUnmount(NUTFILE * nfp)
  755. {
  756. int rc = -1;
  757. if (nfp)
  758. {
  759. MMCFCB *fcb = (MMCFCB *) nfp->nf_fcb;
  760. if (fcb)
  761. {
  762. rc = fcb->fcb_fsdev->dev_ioctl(fcb->fcb_fsdev, FS_VOL_UNMOUNT, NULL);
  763. NutHeapFree(fcb);
  764. }
  765. NutHeapFree(nfp);
  766. }
  767. #ifdef NUTDEBUG
  768. if (rc != 0)
  769. {
  770. printf("%s() failed\n", __FUNCTION__ );
  771. }
  772. #endif
  773. return(rc);
  774. }
  775. /*!
  776. * \brief Perform MMC control functions.
  777. *
  778. * This function is called by the ioctl() function of the C runtime
  779. * library. Applications should not directly call this function.
  780. *
  781. * \todo Card change detection should verify the serial card number.
  782. *
  783. * \param dev Identifies the device that receives the device-control
  784. * function.
  785. * \param req Requested control function. May be set to one of the
  786. * following constants:
  787. * - \ref NUTBLKDEV_MEDIACHANGE
  788. * - \ref NUTBLKDEV_INFO
  789. * - \ref NUTBLKDEV_SEEK
  790. * - \ref MMCARD_GETCID
  791. * - \ref MMCARD_GETCSD
  792. *
  793. * \param conf Points to a buffer that contains any data required for
  794. * the given control function or receives data from that
  795. * function.
  796. * \return 0 on success, -1 otherwise.
  797. */
  798. static int Lpc177x_8x_MmcardIOCtl(NUTDEVICE * dev, int req, void *conf)
  799. {
  800. int rc = 0;
  801. switch (req)
  802. {
  803. case NUTBLKDEV_MEDIAAVAIL:
  804. {
  805. *((int *) conf) = 1;
  806. }
  807. break;
  808. case NUTBLKDEV_MEDIACHANGE:
  809. {
  810. *((int *) conf) = 0;
  811. }
  812. break;
  813. case NUTBLKDEV_INFO:
  814. {
  815. BLKPAR_INFO *par = (BLKPAR_INFO *) conf;
  816. MMCFCB *fcb = (MMCFCB *) par->par_nfp->nf_fcb;
  817. /*
  818. * note that we don't read the card's CSD-register for this info,
  819. * in stead, we use the info that we found in the partition table of
  820. * the formatted card.
  821. */
  822. //
  823. par->par_nblks = fcb->fcb_part.part_sects;
  824. par->par_blksz = MMC_BLOCK_SIZE;
  825. par->par_blkbp = fcb->fcb_blkbuf;
  826. }
  827. break;
  828. case NUTBLKDEV_SEEK:
  829. {
  830. BLKPAR_SEEK *par = (BLKPAR_SEEK *) conf;
  831. MMCFCB *fcb = (MMCFCB *) par->par_nfp->nf_fcb;
  832. fcb->fcb_blknum = par->par_blknum;
  833. }
  834. break;
  835. case MMCARD_GETSTATUS:
  836. rc = Lpc177x_8x_MciGetCardStatus((int32_t*) conf);
  837. break;
  838. case MMCARD_GETCID:
  839. // not possible to issue a single CID command here so return the
  840. // captured value from init
  841. memcpy((st_Mci_CardId*)conf, &cidval, sizeof(st_Mci_CardId));
  842. break;
  843. case MMCARD_GETCSD:
  844. // not possible to issue a single CSD command here so return the
  845. // captured value from init
  846. memcpy((st_Mci_CardId*)conf, &mci0_ifc.ifc_csd, sizeof(mci0_ifc.ifc_csd));
  847. break;
  848. default:
  849. rc = -1;
  850. break;
  851. }
  852. return(rc);
  853. }
  854. /*!
  855. * \brief Multimedia card device information structure.
  856. *
  857. * A pointer to this structure must be passed to NutRegisterDevice()
  858. * to bind this driver to the Nut/OS kernel. An application may then
  859. * call
  860. * /verbatim
  861. * _open("MMC0:", _O_RDWR | _O_BINARY);
  862. * /endverbatim
  863. * to mount the first active primary partition with any previously
  864. * registered file system driver (typically devPhat0).
  865. */
  866. NUTDEVICE devLpcMci0 = {
  867. 0, /*!< Pointer to next device, dev_next. */
  868. {'M', 'M', 'C', '0', 0, 0, 0, 0, 0}
  869. , /*!< Unique device name, dev_name. */
  870. 0, /*!< Type of device, dev_type. Obsolete. */
  871. 0, /*!< Base address, dev_base. Unused. */
  872. 0, /*!< First interrupt number, dev_irq. Unused. */
  873. &mci0_ifc, /*!< Interface control block, dev_icb. */
  874. 0, /*!< Driver control block used by the low level part, dev_dcb. */
  875. Lpc177x_8x_MmcardInit, /*!< Driver initialization routine, dev_init. */
  876. Lpc177x_8x_MmcardIOCtl, /*!< Driver specific control function, dev_ioctl. */
  877. Lpc177x_8x_MmcardBlockRead, /*!< Read data from a file, dev_read. */
  878. Lpc177x_8x_MmcardBlockWrite,/*!< Write data to a file, dev_write. */
  879. Lpc177x_8x_MmcardMount, /*!< Mount a file system, dev_open. */
  880. Lpc177x_8x_MmcardUnmount, /*!< Unmount a file system, dev_close. */
  881. 0, /*!< Return file size, dev_size. */
  882. 0, /*!< Select function, optional, not yet implemented */
  883. };
  884. /*@}*/