00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00049 #include <cfg/mmci.h>
00050 #include <sys/nutdebug.h>
00051
00052 #if 0
00053
00054 #define NUTDEBUG
00055 #include <stdio.h>
00056 #endif
00057
00058 #include <errno.h>
00059 #include <string.h>
00060 #include <stdlib.h>
00061 #include <memdebug.h>
00062
00063 #include <sys/heap.h>
00064 #include <sys/timer.h>
00065 #include <sys/event.h>
00066 #include <fs/dospart.h>
00067 #include <fs/fs.h>
00068
00069 #include <dev/blockdev.h>
00070 #include <dev/spibus.h>
00071 #include <dev/mmcard.h>
00072
00077
00078 #ifndef MMC_BLOCK_SIZE
00079
00085 #define MMC_BLOCK_SIZE 512
00086 #endif
00087
00088 #ifndef MMC_MAX_INIT_POLLS
00089
00096 #define MMC_MAX_INIT_POLLS 512
00097 #endif
00098
00099 #ifndef MMC_MAX_RESET_RETRIES
00100
00105 #define MMC_MAX_RESET_RETRIES 2
00106 #endif
00107
00108 #ifndef MMC_MAX_WRITE_RETRIES
00109
00114 #define MMC_MAX_WRITE_RETRIES 2
00115 #endif
00116
00117 #ifndef MMC_MAX_READ_RETRIES
00118
00123 #define MMC_MAX_READ_RETRIES MMC_MAX_WRITE_RETRIES
00124 #endif
00125
00126 #ifndef MMC_MAX_CMDACK_POLLS
00127
00134 #define MMC_MAX_CMDACK_POLLS 1024
00135 #endif
00136
00137 #ifndef MMC_MAX_READY_POLLS
00138
00145 #define MMC_MAX_READY_POLLS 800
00146 #endif
00147
00148
00149
00150
00151
00152
00153
00154
00155
00156
00157
00158
00159 static uint8_t dummy_tx_buf[MMC_BLOCK_SIZE];
00160
00164 typedef struct _MMCFCB {
00167 NUTDEVICE *fcb_fsdev;
00168
00171 DOSPART fcb_part;
00172
00180 uint32_t fcb_address;
00181
00191 uint8_t fcb_blkbuf[MMC_BLOCK_SIZE];
00192 } MMCFCB;
00193
00194 #ifdef NUTDEBUG
00195 static void DumpData(uint8_t *buf, size_t len)
00196 {
00197 int i;
00198 int j;
00199
00200 for (i = 0; i < len; i += 16) {
00201 printf("\n%03x ", i);
00202 for (j = 0; j < 16; j++) {
00203 if (i + j < len) {
00204 printf("%02x ", buf[i + j]);
00205 } else {
00206 printf(" ");
00207 }
00208 }
00209 for (j = 0; j < 16; j++) {
00210 if (i + j < len) {
00211 if (buf[i + j] >= 32 && buf[i + j] < 127) {
00212 putchar(buf[i + j]);
00213 } else {
00214 putchar('.');
00215 }
00216 } else {
00217 break;
00218 }
00219 }
00220 }
00221 putchar('\n');
00222 }
00223 #endif
00224
00232 static int CardWaitRdy(NUTSPINODE * node)
00233 {
00234 int poll = MMC_MAX_READY_POLLS;
00235 uint8_t b;
00236 NUTSPIBUS *bus = (NUTSPIBUS *) node->node_bus;
00237
00238 do {
00239 (*bus->bus_transfer) (node, dummy_tx_buf, &b, 1);
00240 if (b == 0xFF) {
00241 return 0;
00242 }
00243 #ifdef NUTDEBUG
00244 putchar('b');
00245 #endif
00246 if (poll < MMC_MAX_READY_POLLS / 4) {
00247 NutSleep(1);
00248 }
00249 } while (poll--);
00250
00251 return -1;
00252 }
00253
00261 static uint8_t CardRxTkn(NUTSPINODE * node)
00262 {
00263 uint8_t rc;
00264
00265 int poll = MMC_MAX_CMDACK_POLLS;
00266 NUTSPIBUS *bus = (NUTSPIBUS *) node->node_bus;
00267
00268 do {
00269 (*bus->bus_transfer) (node, dummy_tx_buf, &rc, 1);
00270 if (rc != 0xFF) {
00271 break;
00272 }
00273 #ifdef NUTDEBUG
00274 putchar('w');
00275 #endif
00276 if (poll < 3 * MMC_MAX_CMDACK_POLLS / 4) {
00277 NutSleep(1);
00278 }
00279 } while (poll--);
00280 #ifdef NUTDEBUG
00281 printf("[R%02x]", rc);
00282 #endif
00283
00284 return rc;
00285 }
00286
00308 static uint16_t CardTxCommand(NUTSPINODE * node, uint8_t cmd, uint32_t param, int len)
00309 {
00310 uint16_t rc = 0xFFFF;
00311 int retries = 4;
00312 uint8_t txb[7];
00313 uint8_t rxb;
00314 NUTSPIBUS *bus;
00315
00316 bus = (NUTSPIBUS *) node->node_bus;
00317
00318
00319 txb[0] = 0xFF;
00320 txb[1] = MMCMD_HOST | cmd;
00321 txb[2] = (uint8_t) (param >> 24);
00322 txb[3] = (uint8_t) (param >> 16);
00323 txb[4] = (uint8_t) (param >> 8);
00324 txb[5] = (uint8_t) param;
00325
00326
00327
00328 txb[6] = MMCMD_RESET_CRC;
00329
00330 while (rc == 0xFFFF && retries--) {
00331 if ((*bus->bus_alloc) (node, 1000)) {
00332 break;
00333 }
00334 if (CardWaitRdy(node) == 0) {
00335 #ifdef NUTDEBUG
00336 printf("\n[CMD%u,%lu]", cmd, param);
00337 #endif
00338 (*bus->bus_transfer) (node, txb, NULL, sizeof(txb));
00339 rxb = CardRxTkn(node);
00340 if (rxb != 0xFF) {
00341 rc = rxb;
00342 if (len == 0) {
00343 break;
00344 }
00345 if (len == 2) {
00346 (*bus->bus_transfer) (node, dummy_tx_buf, &rxb, 1);
00347 rc <<= 8;
00348 rc |= rxb;
00349 }
00350 }
00351 }
00352 (*bus->bus_release) (node);
00353 }
00354 return rc;
00355 }
00356
00367 static int CardInit(NUTSPINODE * node)
00368 {
00369 int i;
00370 int j;
00371 uint8_t rsp;
00372
00373
00374
00375
00376
00377 for (i = 0; i < MMC_MAX_RESET_RETRIES; i++) {
00378 rsp = CardTxCommand(node, MMCMD_GO_IDLE_STATE, 0, 1);
00379 for (j = 0; j < MMC_MAX_INIT_POLLS; j++) {
00380 rsp = CardTxCommand(node, MMCMD_SEND_OP_COND, 0, 1);
00381 if (rsp == MMR1_IDLE_STATE) {
00382 return 0;
00383 }
00384 if (j > MMC_MAX_INIT_POLLS / 4) {
00385 NutSleep(1);
00386 }
00387 }
00388 }
00389 return -1;
00390 }
00391
00406 static int CardRxData(NUTSPINODE * node, uint8_t cmd, uint32_t param, uint8_t *buf, int len)
00407 {
00408 int rc = -1;
00409 uint8_t rsp;
00410 NUTSPIBUS *bus;
00411 int retries = MMC_MAX_READ_RETRIES;
00412
00413
00414
00415 NUTASSERT(node != NULL);
00416 NUTASSERT(node->node_bus != NULL);
00417
00418 bus = (NUTSPIBUS *) node->node_bus;
00419
00420 while (rc && retries--) {
00421 rsp = (uint8_t)CardTxCommand(node, cmd, param, 0);
00422 if (rsp != 0xFF) {
00423 if (rsp == 0 && CardRxTkn(node) == 0xFE) {
00424
00425 (*bus->bus_transfer) (node, dummy_tx_buf, buf, len);
00426
00427 (*bus->bus_transfer) (node, dummy_tx_buf, NULL, 2);
00428 rc = 0;
00429 }
00430 (*bus->bus_release) (node);
00431 }
00432 }
00433 return rc;
00434 }
00435
00450 static int CardTxData(NUTSPINODE * node, uint8_t cmd, uint32_t param, CONST uint8_t *buf, int len)
00451 {
00452 int rc = -1;
00453 uint8_t rsp;
00454 NUTSPIBUS *bus;
00455 int retries = MMC_MAX_WRITE_RETRIES;
00456
00457
00458 NUTASSERT(node != NULL);
00459 NUTASSERT(node->node_bus != NULL);
00460
00461 bus = (NUTSPIBUS *) node->node_bus;
00462 while (rc && retries--) {
00463 rsp = (uint8_t)CardTxCommand(node, cmd, param, 0);
00464 if (rsp != 0xFF) {
00465 if (rsp == 0) {
00466 uint8_t tkn[2] = { 0xFF, 0xFE };
00467
00468
00469 (*bus->bus_transfer) (node, &tkn, NULL, sizeof(tkn));
00470
00471 (*bus->bus_transfer) (node, buf, NULL, len);
00472
00473 (*bus->bus_transfer) (node, dummy_tx_buf, NULL, 2);
00474
00475 if (CardRxTkn(node) == 0xE5) {
00476 rc = 0;
00477 }
00478 }
00479 (*bus->bus_release) (node);
00480 }
00481 }
00482 return rc;
00483 }
00484
00500 int SpiMmcBlockRead(NUTFILE * nfp, void *buffer, int num)
00501 {
00502 MMCFCB *fcb;
00503 NUTDEVICE *dev;
00504 MEMCARDSUPP *msc;
00505
00506
00507 NUTASSERT(nfp != NULL);
00508 NUTASSERT(nfp->nf_fcb != NULL);
00509 NUTASSERT(nfp->nf_dev != NULL);
00510 fcb = (MMCFCB *) nfp->nf_fcb;
00511 dev = (NUTDEVICE *) nfp->nf_dev;
00512 NUTASSERT(dev->dev_dcb != NULL);
00513 msc = (MEMCARDSUPP *) dev->dev_dcb;
00514
00515
00516 if (msc->mcs_cf == 0) {
00517
00518 msc->mcs_act(NUTMC_IND_READ);
00519
00520 if (buffer == NULL) {
00521 buffer = fcb->fcb_blkbuf;
00522 }
00523
00524 if (CardRxData(dev->dev_icb, MMCMD_READ_SINGLE_BLOCK, fcb->fcb_address, buffer, MMC_BLOCK_SIZE) == 0) {
00525
00526 msc->mcs_act(NUTMC_IND_OFF);
00527 #ifdef NUTDEBUG
00528 DumpData(buffer, MMC_BLOCK_SIZE);
00529 #endif
00530 return 1;
00531 }
00532 }
00533
00534 msc->mcs_act(NUTMC_IND_ERROR);
00535 return -1;
00536 }
00537
00553 int SpiMmcBlockWrite(NUTFILE * nfp, CONST void *buffer, int num)
00554 {
00555 MMCFCB *fcb;
00556 NUTDEVICE *dev;
00557 MEMCARDSUPP *msc;
00558
00559
00560 NUTASSERT(nfp != NULL);
00561 NUTASSERT(nfp->nf_fcb != NULL);
00562 NUTASSERT(nfp->nf_dev != NULL);
00563 fcb = (MMCFCB *) nfp->nf_fcb;
00564 dev = (NUTDEVICE *) nfp->nf_dev;
00565 NUTASSERT(dev->dev_dcb != NULL);
00566 msc = (MEMCARDSUPP *) dev->dev_dcb;
00567
00568
00569 if (msc->mcs_cf == 0) {
00570
00571 msc->mcs_act(NUTMC_IND_WRITE);
00572
00573 if (buffer == NULL) {
00574 buffer = fcb->fcb_blkbuf;
00575 }
00576
00577 if (CardTxData(dev->dev_icb, MMCMD_WRITE_BLOCK, fcb->fcb_address, buffer, MMC_BLOCK_SIZE) == 0) {
00578
00579 msc->mcs_act(NUTMC_IND_OFF);
00580 return 1;
00581 }
00582 }
00583
00584 msc->mcs_act(NUTMC_IND_ERROR);
00585 return -1;
00586 }
00587
00588 #ifdef __HARVARD_ARCH__
00589
00608 int SpiMmcBlockWrite_P(NUTFILE * nfp, PGM_P buffer, int num)
00609 {
00610 return -1;
00611 }
00612 #endif
00613
00614 int SpiMmcUnmount(NUTFILE * nfp);
00615
00641 NUTFILE *SpiMmcMount(NUTDEVICE * dev, CONST char *name, int mode, int acc)
00642 {
00643 int partno = 0;
00644 int i;
00645 NUTDEVICE *fsdev;
00646 NUTFILE *nfp;
00647 MMCFCB *fcb;
00648 DOSPART *part;
00649 MEMCARDSUPP *msc = (MEMCARDSUPP *) dev->dev_dcb;
00650 FSCP_VOL_MOUNT mparm;
00651 NUTSPINODE * node = (NUTSPINODE *) dev->dev_icb;
00652
00653
00654 if ((msc->mcs_sf & NUTMC_SF_CD) == 0) {
00655 errno = ENODEV;
00656 return NUTFILE_EOF;
00657 }
00658
00659 msc->mcs_cf = 0;
00660
00661
00662 if (CardInit(node)) {
00663 errno = ENODEV;
00664 return NUTFILE_EOF;
00665 }
00666
00667
00668 if (*name) {
00669 partno = atoi(name);
00670 do {
00671 name++;
00672 } while (*name && *name != '/');
00673 if (*name == '/') {
00674 name++;
00675 }
00676 }
00677
00678
00679
00680
00681
00682
00683
00684 for (fsdev = nutDeviceList; fsdev; fsdev = fsdev->dev_next) {
00685 if (*name == 0) {
00686 if (fsdev->dev_type == IFTYP_FS) {
00687 break;
00688 }
00689 } else if (strcmp(fsdev->dev_name, name) == 0) {
00690 break;
00691 }
00692 }
00693
00694 if (fsdev == 0) {
00695 #ifdef NUTDEBUG
00696 printf("[NoFS'%s]", name);
00697 #endif
00698 errno = ENODEV;
00699 return NUTFILE_EOF;
00700 }
00701
00702 if ((fcb = calloc(1, sizeof(MMCFCB))) == 0) {
00703 errno = ENOMEM;
00704 return NUTFILE_EOF;
00705 }
00706 fcb->fcb_fsdev = fsdev;
00707
00708
00709 if (CardRxData(node, MMCMD_READ_SINGLE_BLOCK, 0, fcb->fcb_blkbuf, MMC_BLOCK_SIZE)) {
00710 free(fcb);
00711 return NUTFILE_EOF;
00712 }
00713 #ifdef NUTDEBUG
00714 DumpData(fcb->fcb_blkbuf, MMC_BLOCK_SIZE);
00715 #endif
00716
00717 if (fcb->fcb_blkbuf[DOSPART_MAGICPOS] != 0x55 || fcb->fcb_blkbuf[DOSPART_MAGICPOS + 1] != 0xAA) {
00718 free(fcb);
00719 return NUTFILE_EOF;
00720 }
00721
00722 if(fcb->fcb_blkbuf[DOSPART_TYPEPOS] == 'F' &&
00723 fcb->fcb_blkbuf[DOSPART_TYPEPOS + 1] == 'A' &&
00724 fcb->fcb_blkbuf[DOSPART_TYPEPOS + 2] == 'T') {
00725
00726 fcb->fcb_part.part_type = PTYPE_FAT12;
00727 fcb->fcb_part.part_sect_offs = 0;
00728 fcb->fcb_part.part_sects = 65536;
00729 }
00730 else {
00731
00732 part = (DOSPART *) & fcb->fcb_blkbuf[DOSPART_SECTORPOS];
00733 #ifdef NUTDEBUG
00734 for (i = 0; i < 4; i++) {
00735 printf("- State 0x%02x\n", part[i].part_state);
00736 printf(" Type 0x%02x\n", part[i].part_type);
00737 printf(" Start %lu\n", part[i].part_sect_offs);
00738 printf(" Size %lu\n", part[i].part_sects);
00739 }
00740 #endif
00741 for (i = 1; i <= 4; i++) {
00742 if (partno) {
00743 if (i == partno) {
00744
00745 fcb->fcb_part = *part;
00746 break;
00747 }
00748 } else if (part->part_state & 0x80) {
00749
00750 fcb->fcb_part = *part;
00751 break;
00752 }
00753 part++;
00754 }
00755
00756 if (fcb->fcb_part.part_type == PTYPE_EMPTY) {
00757 free(fcb);
00758 return NUTFILE_EOF;
00759 }
00760 }
00761
00762 if ((nfp = NutHeapAlloc(sizeof(NUTFILE))) == 0) {
00763 free(fcb);
00764 errno = ENOMEM;
00765 return NUTFILE_EOF;
00766 }
00767 nfp->nf_next = 0;
00768 nfp->nf_dev = dev;
00769 nfp->nf_fcb = fcb;
00770
00771
00772
00773
00774 mparm.fscp_bmnt = nfp;
00775 mparm.fscp_part_type = fcb->fcb_part.part_type;
00776 if (fsdev->dev_ioctl(fsdev, FS_VOL_MOUNT, &mparm)) {
00777 SpiMmcUnmount(nfp);
00778 return NUTFILE_EOF;
00779 }
00780 return nfp;
00781 }
00782
00793 int SpiMmcUnmount(NUTFILE * nfp)
00794 {
00795 int rc;
00796 MMCFCB *fcb;
00797
00798
00799 NUTASSERT(nfp != NULL);
00800 NUTASSERT(nfp->nf_fcb != NULL);
00801 fcb = (MMCFCB *) nfp->nf_fcb;
00802
00803
00804
00805 rc = fcb->fcb_fsdev->dev_ioctl(fcb->fcb_fsdev, FS_VOL_UNMOUNT, NULL);
00806 free(fcb);
00807 free(nfp);
00808
00809 return rc;
00810 }
00811
00835 int SpiMmcIOCtl(NUTDEVICE * dev, int req, void *conf)
00836 {
00837 int rc = 0;
00838 NUTSPINODE * node = (NUTSPINODE *) dev->dev_icb;
00839 MEMCARDSUPP *msc = (MEMCARDSUPP *) dev->dev_dcb;
00840
00841 switch (req) {
00842 case NUTBLKDEV_MEDIAAVAIL:
00843 {
00844 int *flg = (int *) conf;
00845 *flg = msc->mcs_sf & NUTMC_SF_CD;
00846 }
00847 break;
00848 case NUTBLKDEV_MEDIACHANGE:
00849 {
00850 int *flg = (int *) conf;
00851 *flg = msc->mcs_cf;
00852 }
00853 break;
00854 case NUTBLKDEV_INFO:
00855 {
00856 BLKPAR_INFO *par = (BLKPAR_INFO *) conf;
00857 MMCFCB *fcb = (MMCFCB *) par->par_nfp->nf_fcb;
00858
00859 par->par_nblks = fcb->fcb_part.part_sects;
00860 par->par_blksz = MMC_BLOCK_SIZE;
00861 par->par_blkbp = fcb->fcb_blkbuf;
00862 }
00863 break;
00864 case NUTBLKDEV_SEEK:
00865 {
00866 BLKPAR_SEEK *par = (BLKPAR_SEEK *) conf;
00867 MMCFCB *fcb = (MMCFCB *) par->par_nfp->nf_fcb;
00868
00869
00870 fcb->fcb_address = (par->par_blknum + fcb->fcb_part.part_sect_offs) << 9;
00871 }
00872 break;
00873 case MMCARD_GETSTATUS:
00874 {
00875 uint16_t *s = (uint16_t *) conf;
00876
00877 *s = CardTxCommand(node, MMCMD_SEND_STATUS, 0, 2);
00878 }
00879 break;
00880 case MMCARD_GETOCR:
00881 {
00882 NUTSPIBUS *bus = (NUTSPIBUS *) node->node_bus;
00883
00884 if (CardTxCommand(node, MMCMD_READ_OCR, 0, 0) == MMR1_IDLE_STATE) {
00885 uint32_t * ocr = (uint32_t *) conf;
00886 uint_fast8_t i;
00887 uint8_t rxb;
00888
00889 for (i = 0; i < 4; i++) {
00890 (*bus->bus_transfer) (node, dummy_tx_buf, &rxb, 1);
00891 *ocr <<= 8;
00892 *ocr |= rxb;
00893 }
00894
00895 } else {
00896 rc = 1;
00897 }
00898 (*bus->bus_release) (node);
00899 }
00900 break;
00901 case MMCARD_GETCID:
00902 rc = CardRxData(node, MMCMD_SEND_CID, 0, (uint8_t *) conf, sizeof(MMC_CID));
00903 break;
00904 case MMCARD_GETCSD:
00905 rc = CardRxData(node, MMCMD_SEND_CSD, 0, (uint8_t *) conf, sizeof(MMC_CSD));
00906 break;
00907 case MMCARD_GETEXTCSD:
00908 rc = CardRxData(node, MMCMD_SEND_EXTCSD, 0, (uint8_t *) conf, sizeof(MMC_CSD));
00909 break;
00910 default:
00911 rc = -1;
00912 break;
00913 }
00914 return rc;
00915 }
00916
00928 int SpiMmcInit(NUTDEVICE * dev)
00929 {
00930 memset(dummy_tx_buf, 0xFF, MMC_BLOCK_SIZE);
00931 return 0;
00932 }
00933