spi_mmc.c 31 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035
  1. /*
  2. * Copyright (C) 2010 by egnite GmbH
  3. *
  4. * All rights reserved.
  5. *
  6. * Redistribution and use in source and binary forms, with or without
  7. * modification, are permitted provided that the following conditions
  8. * are met:
  9. *
  10. * 1. Redistributions of source code must retain the above copyright
  11. * notice, this list of conditions and the following disclaimer.
  12. * 2. Redistributions in binary form must reproduce the above copyright
  13. * notice, this list of conditions and the following disclaimer in the
  14. * documentation and/or other materials provided with the distribution.
  15. * 3. Neither the name of the copyright holders nor the names of
  16. * contributors may be used to endorse or promote products derived
  17. * from this software without specific prior written permission.
  18. *
  19. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  20. * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  21. * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
  22. * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
  23. * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
  24. * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
  25. * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
  26. * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
  27. * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
  28. * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
  29. * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  30. * SUCH DAMAGE.
  31. *
  32. * For additional information see http://www.ethernut.de/
  33. */
  34. /*!
  35. * \brief Basic SPI bus block device driver for multimedia cards.
  36. *
  37. * The driver provides generic memory card access, but doesn't include
  38. * low level hardware support like card detection. This must be provided
  39. * by a hardware specific support module.
  40. *
  41. * \verbatim
  42. *
  43. * $Id$
  44. *
  45. * \endverbatim
  46. */
  47. #include <cfg/mmci.h>
  48. #include <sys/nutdebug.h>
  49. #if defined (NUTDEBUG)
  50. #include <stdio.h>
  51. #endif
  52. #include <errno.h>
  53. #include <string.h>
  54. #include <stdlib.h>
  55. #include <memdebug.h>
  56. #include <sys/heap.h>
  57. #include <sys/timer.h>
  58. #include <sys/event.h>
  59. #include <fs/dospart.h>
  60. #include <fs/fs.h>
  61. #include <dev/blockdev.h>
  62. #include <dev/spibus.h>
  63. #include <dev/mmcard.h>
  64. /*!
  65. * \addtogroup xgMmCard
  66. */
  67. /*@{*/
  68. #ifndef MMC_BLOCK_SIZE
  69. /*!
  70. * \brief Block size.
  71. *
  72. * Block size in bytes. Do not change unless you are sure that both,
  73. * the file system and the hardware support it.
  74. */
  75. #define MMC_BLOCK_SIZE 512
  76. #endif
  77. #ifndef MMC_MAX_INIT_POLLS
  78. /*!
  79. * \brief Card init timeout.
  80. *
  81. * Max. number of loops waiting for card's idle mode after initialization.
  82. * An additional delay of 1 ms is added to each loop after one quarter of
  83. * this value elapsed.
  84. */
  85. #define MMC_MAX_INIT_POLLS 512
  86. #endif
  87. #ifndef MMC_MAX_RESET_RETRIES
  88. /*!
  89. * \brief Card reset timeout.
  90. *
  91. * Max. number of loops waiting for card's idle mode after resetting it.
  92. */
  93. #define MMC_MAX_RESET_RETRIES 2
  94. #endif
  95. #ifndef MMC_MAX_WRITE_RETRIES
  96. /*!
  97. * \brief Card write retries.
  98. *
  99. * Max. number of retries while writing.
  100. */
  101. #define MMC_MAX_WRITE_RETRIES 2
  102. #endif
  103. #ifndef MMC_MAX_READ_RETRIES
  104. /*!
  105. * \brief Card read retries.
  106. *
  107. * Max. number of retries while reading.
  108. */
  109. #define MMC_MAX_READ_RETRIES MMC_MAX_WRITE_RETRIES
  110. #endif
  111. #ifndef MMC_MAX_CMDACK_POLLS
  112. /*!
  113. * \brief Command acknowledge timeout.
  114. *
  115. * Max. number of loops waiting for card's acknowledge of a command.
  116. * An additional delay of 1 ms is added to each loop after three quarter
  117. * of this value elapsed.
  118. */
  119. #define MMC_MAX_CMDACK_POLLS 1024
  120. #endif
  121. #ifndef MMC_MAX_READY_POLLS
  122. /*!
  123. * \brief Card busy timeout.
  124. *
  125. * Max. number of loops waiting for card's ready state.
  126. * An additional delay of 1 ms is added to each loop after one quarter
  127. * of this value elapsed.
  128. */
  129. #define MMC_MAX_READY_POLLS 800
  130. #endif
  131. /* HACK!!!
  132. Some SPI hardware just shift around data read from MISO pin to the MOSI pin if the SPI data register
  133. is not set manually. At least on the AT91 platform it is impossible to use DMA transfers just for reading
  134. and to hold the MOSI line at high level if no tx data is send out at the same time. So we declare a buffer
  135. filled with 0xFF here, to make sure the MOSI pin is held at high level (0xFF) all the time during a
  136. read only transfer. This buffer is used in CardRXData and several other places too. The buffer is read only.
  137. This is a very very nasty hack and waists 512 Bytes of ram, but I don't see a better solution right now!
  138. */
  139. #ifndef ELEKTOR_IR1
  140. /* The EIR uses SPI over SSC with PDC, which requires buffer copying
  141. into internal SRAM anyway. Another possibility to rid of this buffer
  142. would be to switch the output line to GPIO and set it high during
  143. read transfers. This needs to be tested. */
  144. static uint8_t dummy_tx_buf[MMC_BLOCK_SIZE];
  145. #else
  146. #define dummy_tx_buf NULL
  147. #endif
  148. /*!
  149. * \brief Local multimedia card status information.
  150. */
  151. typedef struct _MMCFCB {
  152. /*! \brief Attached file system device.
  153. */
  154. NUTDEVICE *fcb_fsdev;
  155. /*! \brief Partition table entry of the currently mounted partition.
  156. */
  157. DOSPART fcb_part;
  158. /*! \brief Next block number to read.
  159. *
  160. * The file system driver will send a NUTBLKDEV_SEEK control command
  161. * to set this value before calling the read or the write routine.
  162. *
  163. * The number is partition relative.
  164. */
  165. uint32_t fcb_address;
  166. /*! \brief Internal block buffer.
  167. *
  168. * A file system driver may use this one or optionally provide it's
  169. * own buffers.
  170. *
  171. * Minimal systems may share their external bus interface with
  172. * device I/O lines, in which case the buffer must be located
  173. * in internal memory.
  174. */
  175. uint8_t fcb_blkbuf[MMC_BLOCK_SIZE];
  176. } MMCFCB;
  177. #ifdef NUTDEBUG
  178. static void DumpData(uint8_t *buf, size_t len)
  179. {
  180. int i;
  181. int j;
  182. for (i = 0; i < len; i += 16) {
  183. printf("\n%03x ", i);
  184. for (j = 0; j < 16; j++) {
  185. if (i + j < len) {
  186. printf("%02x ", buf[i + j]);
  187. } else {
  188. printf(" ");
  189. }
  190. }
  191. for (j = 0; j < 16; j++) {
  192. if (i + j < len) {
  193. if (buf[i + j] >= 32 && buf[i + j] < 127) {
  194. putchar(buf[i + j]);
  195. } else {
  196. putchar('.');
  197. }
  198. } else {
  199. break;
  200. }
  201. }
  202. }
  203. putchar('\n');
  204. }
  205. #endif
  206. static uint8_t CardWaitRdy(NUTSPINODE * node)
  207. {
  208. int poll = MMC_MAX_READY_POLLS;
  209. uint8_t b;
  210. NUTSPIBUS *bus;
  211. NUTASSERT(node->node_bus != NULL);
  212. bus = (NUTSPIBUS *) node->node_bus;
  213. do {
  214. (*bus->bus_transfer) (node, dummy_tx_buf, &b, 1);
  215. if (b && b != 0xFF) {
  216. return b;
  217. }
  218. if (poll < MMC_MAX_READY_POLLS / 4) {
  219. NutSleep(1);
  220. }
  221. } while (poll--);
  222. return 0;
  223. }
  224. static NUTSPIBUS *CardAllocate(NUTSPINODE * node)
  225. {
  226. int poll = MMC_MAX_READY_POLLS;
  227. uint8_t b;
  228. NUTSPIBUS *bus;
  229. NUTASSERT(node->node_bus != NULL);
  230. bus = (NUTSPIBUS *) node->node_bus;
  231. if ((*bus->bus_alloc) (node, 1000) == 0) {
  232. do {
  233. (*bus->bus_transfer) (node, dummy_tx_buf, &b, 1);
  234. if (b == 0xFF) {
  235. return bus;
  236. }
  237. if (poll < MMC_MAX_READY_POLLS / 4) {
  238. NutSleep(1);
  239. }
  240. } while (poll--);
  241. (*bus->bus_release) (node);
  242. }
  243. return NULL;
  244. }
  245. /*!
  246. * \brief Get next token from a multimedia card.
  247. *
  248. * \param node Specifies the SPI node.
  249. *
  250. * \return The token received or 0xFF if timed out.
  251. */
  252. static uint8_t CardRxTkn(NUTSPINODE * node)
  253. {
  254. uint8_t rc;
  255. int poll = MMC_MAX_CMDACK_POLLS;
  256. NUTSPIBUS *bus = (NUTSPIBUS *) node->node_bus;
  257. do {
  258. (*bus->bus_transfer) (node, dummy_tx_buf, &rc, 1);
  259. if (rc != 0xFF) {
  260. break;
  261. }
  262. #ifdef NUTDEBUG
  263. putchar('w');
  264. #endif
  265. if (poll < 3 * MMC_MAX_CMDACK_POLLS / 4) {
  266. NutSleep(10);
  267. }
  268. } while (poll--);
  269. #ifdef NUTDEBUG
  270. printf("[R%02x]", rc);
  271. #endif
  272. return rc;
  273. }
  274. /*!
  275. * \brief Send command to a multimedia card.
  276. *
  277. * Allocates the bus, transmits the command with the command parameter
  278. * set to zero and receives a one or two byte response. Before returning
  279. * to the caller, the bus is typically released. However, if len is
  280. * neither 1 nor 2, the bus will not be released.
  281. *
  282. * In SPI mode, the card sends a 1 byte response after every command
  283. * except after SEND_STATUS and READ_OCR commands, where 2 or 5 bytes
  284. * are returned resp.
  285. *
  286. * \param node Specifies the SPI node.
  287. * \param cmd Command code. See MMCMD_ macros.
  288. * \param len Length of the expected response, either 1, 2 or 0. If 0,
  289. * then the first byte of the response will be returned and
  290. * the bus will be kept allocated.
  291. *
  292. * \return The 1 or 2 byte response. On time out 0xFFFF is returned and
  293. * the bus is released, regardless of the expected response length.
  294. */
  295. static uint16_t CardTxCommand(NUTSPINODE * node, uint8_t cmd, uint32_t param, int len)
  296. {
  297. uint16_t rc = 0xFFFF;
  298. int retries = 10;
  299. uint8_t txb[6];
  300. uint8_t rxb;
  301. NUTSPIBUS *bus;
  302. /* Send command and parameter. */
  303. txb[0] = MMCMD_HOST | cmd;
  304. txb[1] = (uint8_t) (param >> 24);
  305. txb[2] = (uint8_t) (param >> 16);
  306. txb[3] = (uint8_t) (param >> 8);
  307. txb[4] = (uint8_t) param;
  308. /* We are running with CRC disabled. However, the reset command must
  309. ** be send with a valid CRC. Fortunately this command is sent with a
  310. ** fixed parameter value of zero, which results in a fixed CRC value. */
  311. if (cmd == 8) {
  312. txb[5] = MMCMD_IF_COND_CRC;
  313. } else {
  314. txb[5] = MMCMD_RESET_CRC;
  315. }
  316. do {
  317. bus = CardAllocate(node);
  318. if (bus) {
  319. #ifdef NUTDEBUG
  320. printf("\n[CMD%u,%lu]", cmd, param);
  321. #endif
  322. /* Transmit command to the card. */
  323. (*bus->bus_transfer) (node, txb, NULL, sizeof(txb));
  324. /* Receive the response. */
  325. rxb = CardRxTkn(node);
  326. /* Check for timeout. */
  327. if ((rxb & 0x80) == 0) {
  328. rc = rxb;
  329. if (len == 0) {
  330. /* Keep the bus allocated. */
  331. break;
  332. }
  333. if (len == 2) {
  334. /* R2 response. */
  335. (*bus->bus_transfer) (node, dummy_tx_buf, &rxb, 1);
  336. rc <<= 8;
  337. rc |= rxb;
  338. }
  339. /* We are done. */
  340. retries = 0;
  341. }
  342. (*bus->bus_release) (node);
  343. }
  344. } while (retries--);
  345. return rc;
  346. }
  347. /*!
  348. * \brief Initialize the multimedia card.
  349. *
  350. * This routine will put a newly powered up card into SPI mode.
  351. * It is called by SpiMmcMount().
  352. *
  353. * \param node Specifies the SPI node.
  354. *
  355. * \return 0 on success, -1 otherwise.
  356. */
  357. static int CardInit(NUTSPINODE * node)
  358. {
  359. NUTSPIBUS *bus;
  360. int i;
  361. uint8_t rsp;
  362. uint8_t rsp7[5];
  363. MEMCARDSUPP *mcs;
  364. uint32_t op_cond;
  365. uint_fast8_t mmc = 0;
  366. /*
  367. * Switch to idle state and wait until initialization is running
  368. * or idle state is reached.
  369. */
  370. mcs = (MEMCARDSUPP *) node->node_dcb;
  371. bus = (NUTSPIBUS *) node->node_bus;
  372. (*bus->bus_set_rate)(node, 400000);
  373. /* Send 80 dummy clocks. Some cards need this. */
  374. (*bus->bus_transfer) (node, NULL, NULL, 10);
  375. /* Reset card and switch to SPI mode. */
  376. rsp = CardTxCommand(node, MMCMD_GO_IDLE_STATE, 0, 1);
  377. /* Send 0x100 for voltage range 2.7 - 3.6V and add pattern 0xAA. */
  378. rsp = CardTxCommand(node, MMCMD_SEND_IF_COND, 0x1AA, 1);
  379. /* Default to SD version 1 or MMC. */
  380. mcs->mcs_sf &= ~NUTMC_SF_HC;
  381. op_cond = 0;
  382. if ((rsp & MMR1_ILLEGAL_COMMAND) == 0) {
  383. /* Card is SD version 2 or later, possibly SDHC. */
  384. op_cond = 1UL << 30;
  385. }
  386. for (i = 0; i < MMC_MAX_INIT_POLLS; i++) {
  387. /* Send operating conditions. */
  388. if (mmc) {
  389. rsp = CardTxCommand(node, MMCMD_SEND_OP_COND, 0, 1);
  390. if (rsp == MMR1_IDLE_STATE) {
  391. (*bus->bus_set_rate)(node, 20000000);
  392. return 0;
  393. }
  394. } else {
  395. CardTxCommand(node, MMCMD_SEND_APP_CMD, 0, 1);
  396. rsp = CardTxCommand(node, MMCMD_SEND_APP_OP_COND, op_cond, 0);
  397. (*bus->bus_release) (node);
  398. if (rsp & MMR1_ILLEGAL_COMMAND) {
  399. /* Not an SD memory card, try MMC. */
  400. mmc = 1;
  401. }
  402. else if (rsp == MMR1_IDLE_STATE) {
  403. CardTxCommand(node, MMCMD_READ_OCR, 0, 0);
  404. (*bus->bus_transfer) (node, dummy_tx_buf, rsp7, 4);
  405. (*bus->bus_release) (node);
  406. if (rsp7[0] & 0x80) {
  407. if (rsp7[0] & 0x40) {
  408. /* Card is SDHC. */
  409. mcs->mcs_sf |= NUTMC_SF_HC;
  410. }
  411. (*bus->bus_set_rate)(node, 20000000);
  412. return 0;
  413. }
  414. }
  415. }
  416. NutSleep(10);
  417. }
  418. return -1;
  419. }
  420. /*!
  421. * \brief Read data transaction.
  422. *
  423. * This routine is used to read data blocks as well as reading the CSD
  424. * and CID registers.
  425. *
  426. * \param node Specifies the SPI node.
  427. * \param cmd Command code. See MMCMD_ macros.
  428. * \param param Command parameter.
  429. * \param buf Pointer to the data buffer to fill.
  430. * \param len Number of data bytes to read.
  431. *
  432. * \return 0 on success or -1 in case of an error.
  433. */
  434. static int CardRxData(NUTSPINODE * node, uint8_t cmd, uint32_t param, uint8_t *buf, int len)
  435. {
  436. int rc = -1;
  437. uint8_t rsp;
  438. NUTSPIBUS *bus;
  439. int retries = MMC_MAX_READ_RETRIES;
  440. /* Sanity checks. */
  441. NUTASSERT(node != NULL);
  442. NUTASSERT(node->node_bus != NULL);
  443. bus = (NUTSPIBUS *) node->node_bus;
  444. while (rc && retries--) {
  445. rsp = (uint8_t)CardTxCommand(node, cmd, param, 0);
  446. if ((rsp & 0x80) == 0) {
  447. if (rsp == 0) {
  448. rsp = CardWaitRdy(node);
  449. if (rsp == 0xFE) {
  450. /* Data transfer. */
  451. (*bus->bus_transfer) (node, dummy_tx_buf, buf, len);
  452. /* Ignore the CRC. */
  453. (*bus->bus_transfer) (node, dummy_tx_buf, NULL, 2);
  454. rc = 0;
  455. }
  456. }
  457. /* Send 8 additional clocks and release the bus. */
  458. (*bus->bus_transfer) (node, NULL, NULL, 1);
  459. (*bus->bus_release) (node);
  460. }
  461. }
  462. return rc;
  463. }
  464. /*!
  465. * \brief Read data blocks from a mounted partition.
  466. *
  467. * Applications should not call this function directly, but use the
  468. * stdio interface.
  469. *
  470. * \param nfp Pointer to a ::NUTFILE structure, obtained by a previous
  471. * call to SpiMmcMount().
  472. * \param buffer Pointer to the data buffer to fill.
  473. * \param num Maximum number of blocks to read. However, reading
  474. * multiple blocks is not yet supported by this driver.
  475. *
  476. * \return The number of blocks actually read. A return value of -1
  477. * indicates an error.
  478. */
  479. int SpiMmcBlockRead(NUTFILE * nfp, void *buffer, int num)
  480. {
  481. MMCFCB *fcb;
  482. NUTDEVICE *dev;
  483. MEMCARDSUPP *msc;
  484. /* Sanity checks. */
  485. NUTASSERT(nfp != NULL);
  486. NUTASSERT(nfp->nf_fcb != NULL);
  487. NUTASSERT(nfp->nf_dev != NULL);
  488. fcb = (MMCFCB *) nfp->nf_fcb;
  489. dev = (NUTDEVICE *) nfp->nf_dev;
  490. NUTASSERT(dev->dev_dcb != NULL);
  491. msc = (MEMCARDSUPP *) dev->dev_dcb;
  492. /* Make sure there was no card change. */
  493. if (msc->mcs_cf == 0) {
  494. /* Activate the write indicator. */
  495. msc->mcs_act(NUTMC_IND_READ);
  496. /* Use the internal buffer if none is provided. */
  497. if (buffer == NULL) {
  498. buffer = fcb->fcb_blkbuf;
  499. }
  500. /* Transfer the data from the card. */
  501. if (CardRxData(dev->dev_icb, MMCMD_READ_SINGLE_BLOCK, fcb->fcb_address, buffer, MMC_BLOCK_SIZE) == 0) {
  502. /* Deactivate the indicator. */
  503. msc->mcs_act(NUTMC_IND_OFF);
  504. #ifdef NUTDEBUG
  505. DumpData(buffer, MMC_BLOCK_SIZE);
  506. #endif
  507. return 1;
  508. }
  509. }
  510. /* Activate the error indicator. */
  511. msc->mcs_act(NUTMC_IND_ERROR);
  512. return -1;
  513. }
  514. /*!
  515. * \brief Write data blocks to a mounted partition.
  516. *
  517. * Applications should not call this function directly, but use the
  518. * stdio interface.
  519. *
  520. * \param nfp Pointer to a \ref NUTFILE structure, obtained by a previous
  521. * call to SpiMmcMount().
  522. * \param buffer Pointer to the data to be written. However, writing
  523. * multiple blocks is not yet supported by this driver.
  524. * \param num Number of blocks to write.
  525. *
  526. * \return The number of blocks written. A return value of -1 indicates an
  527. * error.
  528. */
  529. int SpiMmcBlockWrite(NUTFILE * nfp, const void *buffer, int num)
  530. {
  531. MMCFCB *fcb;
  532. NUTDEVICE *dev;
  533. MEMCARDSUPP *msc;
  534. NUTSPINODE *node;
  535. NUTSPIBUS *bus;
  536. /* Sanity checks. */
  537. NUTASSERT(nfp != NULL);
  538. NUTASSERT(nfp->nf_fcb != NULL);
  539. NUTASSERT(nfp->nf_dev != NULL);
  540. fcb = (MMCFCB *) nfp->nf_fcb;
  541. dev = (NUTDEVICE *) nfp->nf_dev;
  542. NUTASSERT(dev->dev_dcb != NULL);
  543. msc = (MEMCARDSUPP *) dev->dev_dcb;
  544. NUTASSERT(dev->dev_icb != NULL);
  545. node = (NUTSPINODE *) dev->dev_icb;
  546. NUTASSERT(node->node_bus != NULL);
  547. bus = (NUTSPIBUS *) node->node_bus;
  548. /* Make sure there was no card change. */
  549. if (msc->mcs_cf == 0) {
  550. /* Activate the write indicator. */
  551. msc->mcs_act(NUTMC_IND_WRITE);
  552. /* Use the internal buffer if none is provided. */
  553. if (buffer == NULL) {
  554. buffer = fcb->fcb_blkbuf;
  555. }
  556. /* Transfer the data to the card. */
  557. if (num == 1) {
  558. uint8_t tkn = (uint8_t)CardTxCommand(node, MMCMD_WRITE_BLOCK, fcb->fcb_address, 0);
  559. if (tkn != 0xFF) {
  560. if (tkn == 0) {
  561. /* Send start token. */
  562. tkn = 0xFE;
  563. (*bus->bus_transfer) (node, &tkn, NULL, 1);
  564. /* Data transfer. */
  565. (*bus->bus_transfer) (node, buffer, NULL, MMC_BLOCK_SIZE);
  566. /* Send dummy CRC. */
  567. (*bus->bus_transfer) (node, dummy_tx_buf, NULL, 2);
  568. /* Get data response. */
  569. tkn = CardRxTkn(node);
  570. if (tkn == 0xE5) {
  571. /* Send 8 additional clocks and release the bus. */
  572. (*bus->bus_transfer) (node, NULL, NULL, 1);
  573. (*bus->bus_release) (node);
  574. /* Deactivate the indicator. */
  575. msc->mcs_act(NUTMC_IND_OFF);
  576. return 1;
  577. }
  578. }
  579. (*bus->bus_release) (node);
  580. }
  581. } else {
  582. int i;
  583. uint8_t tkn;
  584. uint8_t *bp = (uint8_t *) buffer;
  585. tkn = (uint8_t)CardTxCommand(node, MMCMD_WRITE_MULTIPLE_BLOCK, fcb->fcb_address, 0);
  586. if (tkn != 0xFF) {
  587. if (tkn == 0) {
  588. for (i = 0; i < num; i++) {
  589. /* Send start token. */
  590. tkn = 0xFC;
  591. (*bus->bus_transfer) (node, &tkn, NULL, 1);
  592. /* Data transfer. */
  593. (*bus->bus_transfer) (node, bp, NULL, MMC_BLOCK_SIZE);
  594. bp += MMC_BLOCK_SIZE;
  595. /* Send dummy CRC. */
  596. (*bus->bus_transfer) (node, dummy_tx_buf, NULL, 2);
  597. /* Get data response. */
  598. tkn = CardRxTkn(node);
  599. if (tkn != 0xE5) {
  600. (*bus->bus_release) (node);
  601. msc->mcs_act(NUTMC_IND_ERROR);
  602. return -1;
  603. }
  604. for (;;) {
  605. uint8_t b;
  606. (*bus->bus_transfer) (node, dummy_tx_buf, &b, 1);
  607. if (b == 0xFF) {
  608. break;
  609. }
  610. }
  611. }
  612. {
  613. uint8_t b = 0xfd;
  614. (*bus->bus_transfer) (node, &b, NULL, 1);
  615. }
  616. /* Send 8 additional clocks and release the bus. */
  617. (*bus->bus_transfer) (node, NULL, NULL, 1);
  618. (*bus->bus_release) (node);
  619. /* Deactivate the indicator. */
  620. msc->mcs_act(NUTMC_IND_OFF);
  621. return num;
  622. }
  623. (*bus->bus_release) (node);
  624. }
  625. }
  626. }
  627. /* Activate the error indicator. */
  628. msc->mcs_act(NUTMC_IND_ERROR);
  629. return -1;
  630. }
  631. #ifdef __HARVARD_ARCH__
  632. /*!
  633. * \brief Write data blocks from program space to a mounted partition.
  634. *
  635. * This function is not yet implemented and will always return -1.
  636. *
  637. * Similar to SpiMmcBlockWrite() except that the data is located in
  638. * program memory.
  639. *
  640. * Applications should not call this function directly, but use the
  641. * stdio interface.
  642. *
  643. * \param nfp File pointer to a previously opened device.
  644. * \param buffer Pointer to the data bytes in program space to be written.
  645. * \param num Maximum number of blocks to write. However, writing
  646. * multiple blocks is not yet supported by this driver.
  647. *
  648. * \return The number of blocks written. A return value of -1 indicates an
  649. * error.
  650. */
  651. int SpiMmcBlockWrite_P(NUTFILE * nfp, PGM_P buffer, int num)
  652. {
  653. return -1;
  654. }
  655. #endif
  656. int SpiMmcUnmount(NUTFILE * nfp);
  657. /*!
  658. * \brief Mount a partition.
  659. *
  660. * Nut/OS doesn't provide specific routines for mounting. Instead routines
  661. * for opening files are used.
  662. *
  663. * Applications should not directly call this function, but use the high
  664. * level stdio routines for opening a file.
  665. *
  666. * \param dev Pointer to the MMC device.
  667. * \param name Partition number followed by a slash followed by a name
  668. * of the file system device. Both items are optional. If no
  669. * file system driver name is given, the first file system
  670. * driver found in the list of registered devices will be
  671. * used. If no partition number is specified or if partition
  672. * zero is given, the first active primary partition will be
  673. * used.
  674. * \param mode Opening mode. Currently ignored, but
  675. * \code _O_RDWR | _O_BINARY \endcode should be used for
  676. * compatibility with future enhancements.
  677. * \param acc File attributes, ignored.
  678. *
  679. * \return Pointer to a newly created file pointer to the mounted
  680. * partition or NUTFILE_EOF in case of any error.
  681. */
  682. NUTFILE *SpiMmcMount(NUTDEVICE * dev, const char *name, int mode, int acc)
  683. {
  684. int partno = 0;
  685. int i;
  686. NUTDEVICE *fsdev;
  687. NUTFILE *nfp;
  688. MMCFCB *fcb;
  689. DOSPART *part;
  690. MEMCARDSUPP *msc = (MEMCARDSUPP *) dev->dev_dcb;
  691. FSCP_VOL_MOUNT mparm;
  692. NUTSPINODE * node = (NUTSPINODE *) dev->dev_icb;
  693. /* Return an error if no card is detected. */
  694. if ((msc->mcs_sf & NUTMC_SF_CD) == 0) {
  695. errno = ENODEV;
  696. return NUTFILE_EOF;
  697. }
  698. /* Clear the card change flag. */
  699. msc->mcs_cf = 0;
  700. /* Set the card in SPI mode. */
  701. if (CardInit(node)) {
  702. errno = ENODEV;
  703. return NUTFILE_EOF;
  704. }
  705. /* Parse the name for a partition number and a file system driver. */
  706. if (*name) {
  707. partno = atoi(name);
  708. do {
  709. name++;
  710. } while (*name && *name != '/');
  711. if (*name == '/') {
  712. name++;
  713. }
  714. }
  715. /*
  716. * Check the list of registered devices for the given name of the
  717. * files system driver. If none has been specified, get the first
  718. * file system driver in the list. Hopefully the application
  719. * registered one only.
  720. */
  721. for (fsdev = nutDeviceList; fsdev; fsdev = fsdev->dev_next) {
  722. if (*name == 0) {
  723. if (fsdev->dev_type == IFTYP_FS) {
  724. break;
  725. }
  726. } else if (strcmp(fsdev->dev_name, name) == 0) {
  727. break;
  728. }
  729. }
  730. if (fsdev == 0) {
  731. #ifdef NUTDEBUG
  732. printf("[NoFS'%s]", name);
  733. #endif
  734. errno = ENODEV;
  735. return NUTFILE_EOF;
  736. }
  737. if ((fcb = calloc(1, sizeof(MMCFCB))) == 0) {
  738. errno = ENOMEM;
  739. return NUTFILE_EOF;
  740. }
  741. fcb->fcb_fsdev = fsdev;
  742. /* Read MBR. */
  743. if (CardRxData(node, MMCMD_READ_SINGLE_BLOCK, 0, fcb->fcb_blkbuf, MMC_BLOCK_SIZE)) {
  744. free(fcb);
  745. return NUTFILE_EOF;
  746. }
  747. #ifdef NUTDEBUG
  748. DumpData(fcb->fcb_blkbuf, MMC_BLOCK_SIZE);
  749. #endif
  750. /* Check for the cookie at the end of this sector. */
  751. if (fcb->fcb_blkbuf[DOSPART_MAGICPOS] != 0x55 || fcb->fcb_blkbuf[DOSPART_MAGICPOS + 1] != 0xAA) {
  752. free(fcb);
  753. return NUTFILE_EOF;
  754. }
  755. /* Check for the partition table. */
  756. if(fcb->fcb_blkbuf[DOSPART_TYPEPOS] == 'F' &&
  757. fcb->fcb_blkbuf[DOSPART_TYPEPOS + 1] == 'A' &&
  758. fcb->fcb_blkbuf[DOSPART_TYPEPOS + 2] == 'T') {
  759. /* No partition table. Assume FAT12 and 32MB size. */
  760. fcb->fcb_part.part_type = PTYPE_FAT12;
  761. fcb->fcb_part.part_sect_offs = 0;
  762. fcb->fcb_part.part_sects = 65536; /* How to find out? */
  763. }
  764. else {
  765. /* Read partition table. */
  766. part = (DOSPART *) & fcb->fcb_blkbuf[DOSPART_SECTORPOS];
  767. #ifdef NUTDEBUG
  768. for (i = 0; i < 4; i++) {
  769. printf("- State 0x%02x\n", part[i].part_state);
  770. printf(" Type 0x%02x\n", part[i].part_type);
  771. printf(" Start %lu\n", part[i].part_sect_offs);
  772. printf(" Size %lu\n", part[i].part_sects);
  773. }
  774. #endif
  775. for (i = 1; i <= 4; i++) {
  776. if (partno) {
  777. if (i == partno) {
  778. /* Found specified partition number. */
  779. fcb->fcb_part = *part;
  780. break;
  781. }
  782. } else if (part->part_state & 0x80) {
  783. /* Located first active partition. */
  784. fcb->fcb_part = *part;
  785. break;
  786. }
  787. part++;
  788. }
  789. if (fcb->fcb_part.part_type == PTYPE_EMPTY) {
  790. free(fcb);
  791. return NUTFILE_EOF;
  792. }
  793. }
  794. if ((nfp = NutHeapAlloc(sizeof(NUTFILE))) == 0) {
  795. free(fcb);
  796. errno = ENOMEM;
  797. return NUTFILE_EOF;
  798. }
  799. nfp->nf_dev = dev;
  800. nfp->nf_fcb = fcb;
  801. /*
  802. * Mount the file system volume.
  803. */
  804. mparm.fscp_bmnt = nfp;
  805. mparm.fscp_part_type = fcb->fcb_part.part_type;
  806. if (fsdev->dev_ioctl(fsdev, FS_VOL_MOUNT, &mparm)) {
  807. SpiMmcUnmount(nfp);
  808. return NUTFILE_EOF;
  809. }
  810. return nfp;
  811. }
  812. /*!
  813. * \brief Unmount a previously mounted partition.
  814. *
  815. * Applications should not directly call this function, but use the high
  816. * level stdio routines for closing a previously opened volume.
  817. *
  818. * \param nfp Pointer to a \ref NUTFILE structure, obtained by a previous
  819. * call to SpiMmcMount().
  820. * \return 0 on success, -1 otherwise.
  821. */
  822. int SpiMmcUnmount(NUTFILE * nfp)
  823. {
  824. int rc;
  825. MMCFCB *fcb;
  826. /* Sanity checks. */
  827. NUTASSERT(nfp != NULL);
  828. NUTASSERT(nfp->nf_fcb != NULL);
  829. fcb = (MMCFCB *) nfp->nf_fcb;
  830. /* Intentionally we do not check the card change flag here to allow the
  831. ** file system to release all claimed resources. */
  832. rc = fcb->fcb_fsdev->dev_ioctl(fcb->fcb_fsdev, FS_VOL_UNMOUNT, NULL);
  833. free(fcb);
  834. free(nfp);
  835. return rc;
  836. }
  837. /*!
  838. * \brief Perform MMC control functions.
  839. *
  840. * This function is called by the ioctl() function of the C runtime
  841. * library. Applications should not directly call this function.
  842. *
  843. * \todo Card change detection should verify the serial card number.
  844. *
  845. * \param dev Identifies the device that receives the device-control
  846. * function.
  847. * \param req Requested control function. May be set to one of the
  848. * following constants:
  849. * - \ref NUTBLKDEV_MEDIACHANGE
  850. * - \ref NUTBLKDEV_INFO
  851. * - \ref NUTBLKDEV_SEEK
  852. * - \ref MMCARD_GETCID
  853. * - \ref MMCARD_GETCSD
  854. *
  855. * \param conf Points to a buffer that contains any data required for
  856. * the given control function or receives data from that
  857. * function.
  858. * \return 0 on success, -1 otherwise.
  859. */
  860. int SpiMmcIOCtl(NUTDEVICE * dev, int req, void *conf)
  861. {
  862. int rc = 0;
  863. NUTSPINODE * node = (NUTSPINODE *) dev->dev_icb;
  864. MEMCARDSUPP *msc = (MEMCARDSUPP *) dev->dev_dcb;
  865. switch (req) {
  866. case NUTBLKDEV_MEDIAAVAIL:
  867. {
  868. int *flg = (int *) conf;
  869. *flg = msc->mcs_sf & NUTMC_SF_CD;
  870. }
  871. break;
  872. case NUTBLKDEV_MEDIACHANGE:
  873. {
  874. int *flg = (int *) conf;
  875. *flg = msc->mcs_cf;
  876. }
  877. break;
  878. case NUTBLKDEV_INFO:
  879. {
  880. BLKPAR_INFO *par = (BLKPAR_INFO *) conf;
  881. MMCFCB *fcb = (MMCFCB *) par->par_nfp->nf_fcb;
  882. par->par_nblks = fcb->fcb_part.part_sects;
  883. par->par_blksz = MMC_BLOCK_SIZE;
  884. par->par_blkbp = fcb->fcb_blkbuf;
  885. }
  886. break;
  887. case NUTBLKDEV_SEEK:
  888. {
  889. BLKPAR_SEEK *par = (BLKPAR_SEEK *) conf;
  890. MMCFCB *fcb = (MMCFCB *) par->par_nfp->nf_fcb;
  891. /* Caclaulate the byte offset. */
  892. fcb->fcb_address = par->par_blknum + fcb->fcb_part.part_sect_offs;
  893. if ((msc->mcs_sf & NUTMC_SF_HC) == 0) {
  894. fcb->fcb_address <<= 9;
  895. }
  896. }
  897. break;
  898. case MMCARD_GETSTATUS:
  899. {
  900. uint16_t *s = (uint16_t *) conf;
  901. *s = CardTxCommand(node, MMCMD_SEND_STATUS, 0, 2);
  902. }
  903. break;
  904. case MMCARD_GETOCR:
  905. {
  906. NUTSPIBUS *bus = (NUTSPIBUS *) node->node_bus;
  907. if (CardTxCommand(node, MMCMD_READ_OCR, 0, 0) == MMR1_IDLE_STATE) {
  908. uint32_t * ocr = (uint32_t *) conf;
  909. uint_fast8_t i;
  910. uint8_t rxb;
  911. for (i = 0; i < 4; i++) {
  912. (*bus->bus_transfer) (node, dummy_tx_buf, &rxb, 1);
  913. *ocr <<= 8;
  914. *ocr |= rxb;
  915. }
  916. } else {
  917. rc = 1;
  918. }
  919. (*bus->bus_release) (node);
  920. }
  921. break;
  922. case MMCARD_GETCID:
  923. rc = CardRxData(node, MMCMD_SEND_CID, 0, (uint8_t *) conf, sizeof(MMC_CID));
  924. break;
  925. case MMCARD_GETCSD:
  926. rc = CardRxData(node, MMCMD_SEND_CSD, 0, (uint8_t *) conf, sizeof(MMC_CSD));
  927. break;
  928. case MMCARD_GETEXTCSD:
  929. rc = CardRxData(node, MMCMD_SEND_EXTCSD, 0, (uint8_t *) conf, sizeof(MMC_CSD));
  930. break;
  931. default:
  932. rc = -1;
  933. break;
  934. }
  935. return rc;
  936. }
  937. /*!
  938. * \brief Initialize MMC driver.
  939. *
  940. * Applications should not directly call this function. It is
  941. * automatically executed during during device registration by
  942. * NutRegisterDevice().
  943. *
  944. * \param dev Identifies the device to initialize.
  945. *
  946. * \return Always zero.
  947. */
  948. int SpiMmcInit(NUTDEVICE * dev)
  949. {
  950. #ifndef ELEKTOR_IR1
  951. memset(dummy_tx_buf, 0xFF, MMC_BLOCK_SIZE);
  952. #endif
  953. return 0;
  954. }
  955. /*@}*/