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
00151 typedef struct _MMCFCB {
00154 NUTDEVICE *fcb_fsdev;
00155
00158 DOSPART fcb_part;
00159
00167 uint32_t fcb_address;
00168
00178 uint8_t fcb_blkbuf[MMC_BLOCK_SIZE];
00179 } MMCFCB;
00180
00181 #ifdef NUTDEBUG
00182 static void DumpData(uint8_t *buf, size_t len)
00183 {
00184 int i;
00185 int j;
00186
00187 for (i = 0; i < len; i += 16) {
00188 printf("\n%03x ", i);
00189 for (j = 0; j < 16; j++) {
00190 if (i + j < len) {
00191 printf("%02x ", buf[i + j]);
00192 } else {
00193 printf(" ");
00194 }
00195 }
00196 for (j = 0; j < 16; j++) {
00197 if (i + j < len) {
00198 if (buf[i + j] >= 32 && buf[i + j] < 127) {
00199 putchar(buf[i + j]);
00200 } else {
00201 putchar('.');
00202 }
00203 } else {
00204 break;
00205 }
00206 }
00207 }
00208 putchar('\n');
00209 }
00210 #endif
00211
00219 static int CardWaitRdy(NUTSPINODE * node)
00220 {
00221 int poll = MMC_MAX_READY_POLLS;
00222 uint8_t b;
00223 NUTSPIBUS *bus = (NUTSPIBUS *) node->node_bus;
00224
00225 do {
00226 (*bus->bus_transfer) (node, NULL, &b, 1);
00227 if (b == 0xFF) {
00228 return 0;
00229 }
00230 #ifdef NUTDEBUG
00231 putchar('b');
00232 #endif
00233 if (poll < MMC_MAX_READY_POLLS / 4) {
00234 NutSleep(1);
00235 }
00236 } while (poll--);
00237
00238 return -1;
00239 }
00240
00248 static uint8_t CardRxTkn(NUTSPINODE * node)
00249 {
00250 uint8_t rc;
00251 int poll = MMC_MAX_CMDACK_POLLS;
00252 NUTSPIBUS *bus = (NUTSPIBUS *) node->node_bus;
00253
00254 do {
00255 (*bus->bus_transfer) (node, NULL, &rc, 1);
00256 if (rc != 0xFF) {
00257 break;
00258 }
00259 #ifdef NUTDEBUG
00260 putchar('w');
00261 #endif
00262 if (poll < 3 * MMC_MAX_CMDACK_POLLS / 4) {
00263 NutSleep(1);
00264 }
00265 } while (poll--);
00266 #ifdef NUTDEBUG
00267 printf("[R%02x]", rc);
00268 #endif
00269
00270 return rc;
00271 }
00272
00294 static uint16_t CardTxCommand(NUTSPINODE * node, uint8_t cmd, uint32_t param, int len)
00295 {
00296 uint16_t rc = 0xFFFF;
00297 int retries = 4;
00298 uint8_t txb[7];
00299 uint8_t rxb;
00300 NUTSPIBUS *bus;
00301
00302 bus = (NUTSPIBUS *) node->node_bus;
00303
00304
00305 txb[0] = 0xFF;
00306 txb[1] = MMCMD_HOST | cmd;
00307 txb[2] = (uint8_t) (param >> 24);
00308 txb[3] = (uint8_t) (param >> 16);
00309 txb[4] = (uint8_t) (param >> 8);
00310 txb[5] = (uint8_t) param;
00311
00312
00313
00314 txb[6] = MMCMD_RESET_CRC;
00315
00316 while (rc == 0xFFFF && retries--) {
00317 if ((*bus->bus_alloc) (node, 1000)) {
00318 break;
00319 }
00320 if (CardWaitRdy(node) == 0) {
00321 #ifdef NUTDEBUG
00322 printf("\n[CMD%u,%lu]", cmd, param);
00323 #endif
00324 (*bus->bus_transfer) (node, txb, NULL, sizeof(txb));
00325 rxb = CardRxTkn(node);
00326 if (rxb != 0xFF) {
00327 rc = rxb;
00328 if (len == 0) {
00329 break;
00330 }
00331 if (len == 2) {
00332 (*bus->bus_transfer) (node, NULL, &rxb, 1);
00333 rc <<= 8;
00334 rc |= rxb;
00335 }
00336 }
00337 }
00338 (*bus->bus_release) (node);
00339 }
00340 return rc;
00341 }
00342
00353 static int CardInit(NUTSPINODE * node)
00354 {
00355 int i;
00356 int j;
00357 uint8_t rsp;
00358 NUTSPIBUS *bus;
00359
00360 bus = (NUTSPIBUS *) node->node_bus;
00361
00362
00363
00364
00365
00366 for (i = 0; i < MMC_MAX_RESET_RETRIES; i++) {
00367 rsp = CardTxCommand(node, MMCMD_GO_IDLE_STATE, 0, 1);
00368 for (j = 0; j < MMC_MAX_INIT_POLLS; j++) {
00369 rsp = CardTxCommand(node, MMCMD_SEND_OP_COND, 0, 1);
00370 if (rsp == MMR1_IDLE_STATE) {
00371 return 0;
00372 }
00373 if (j > MMC_MAX_INIT_POLLS / 4) {
00374 NutSleep(1);
00375 }
00376 }
00377 }
00378 return -1;
00379 }
00380
00395 static int CardRxData(NUTSPINODE * node, uint8_t cmd, uint32_t param, uint8_t *buf, int len)
00396 {
00397 int rc = -1;
00398 uint8_t rsp;
00399 NUTSPIBUS *bus;
00400 int retries = MMC_MAX_READ_RETRIES;
00401
00402
00403 NUTASSERT(node != NULL);
00404 NUTASSERT(node->node_bus != NULL);
00405
00406 bus = (NUTSPIBUS *) node->node_bus;
00407 while (rc && retries--) {
00408 rsp = (uint8_t)CardTxCommand(node, cmd, param, 0);
00409 if (rsp != 0xFF) {
00410 if (rsp == 0 && CardRxTkn(node) == 0xFE) {
00411
00412 (*bus->bus_transfer) (node, NULL, buf, len);
00413
00414 (*bus->bus_transfer) (node, NULL, NULL, 2);
00415 rc = 0;
00416 }
00417 (*bus->bus_release) (node);
00418 }
00419 }
00420 return rc;
00421 }
00422
00437 static int CardTxData(NUTSPINODE * node, uint8_t cmd, uint32_t param, CONST uint8_t *buf, int len)
00438 {
00439 int rc = -1;
00440 uint8_t rsp;
00441 NUTSPIBUS *bus;
00442 int retries = MMC_MAX_WRITE_RETRIES;
00443
00444
00445 NUTASSERT(node != NULL);
00446 NUTASSERT(node->node_bus != NULL);
00447
00448 bus = (NUTSPIBUS *) node->node_bus;
00449 while (rc && retries--) {
00450 rsp = (uint8_t)CardTxCommand(node, cmd, param, 0);
00451 if (rsp != 0xFF) {
00452 if (rsp == 0) {
00453 uint8_t tkn[2] = { 0xFF, 0xFE };
00454
00455
00456 (*bus->bus_transfer) (node, &tkn, NULL, sizeof(tkn));
00457
00458 (*bus->bus_transfer) (node, buf, NULL, len);
00459
00460 (*bus->bus_transfer) (node, NULL, NULL, 2);
00461
00462 if (CardRxTkn(node) == 0xE5) {
00463 rc = 0;
00464 }
00465 }
00466 (*bus->bus_release) (node);
00467 }
00468 }
00469 return rc;
00470 }
00471
00487 int SpiMmcBlockRead(NUTFILE * nfp, void *buffer, int num)
00488 {
00489 MMCFCB *fcb;
00490 NUTDEVICE *dev;
00491 MEMCARDSUPP *msc;
00492
00493
00494 NUTASSERT(nfp != NULL);
00495 NUTASSERT(nfp->nf_fcb != NULL);
00496 NUTASSERT(nfp->nf_dev != NULL);
00497 fcb = (MMCFCB *) nfp->nf_fcb;
00498 dev = (NUTDEVICE *) nfp->nf_dev;
00499 NUTASSERT(dev->dev_dcb != NULL);
00500 msc = (MEMCARDSUPP *) dev->dev_dcb;
00501
00502
00503 if (msc->mcs_cf == 0) {
00504
00505 msc->mcs_act(NUTMC_IND_READ);
00506
00507 if (buffer == NULL) {
00508 buffer = fcb->fcb_blkbuf;
00509 }
00510
00511 if (CardRxData(dev->dev_icb, MMCMD_READ_SINGLE_BLOCK, fcb->fcb_address, buffer, MMC_BLOCK_SIZE) == 0) {
00512
00513 msc->mcs_act(NUTMC_IND_OFF);
00514 #ifdef NUTDEBUG
00515 DumpData(buffer, MMC_BLOCK_SIZE);
00516 #endif
00517 return 1;
00518 }
00519 }
00520
00521 msc->mcs_act(NUTMC_IND_ERROR);
00522 return -1;
00523 }
00524
00540 int SpiMmcBlockWrite(NUTFILE * nfp, CONST void *buffer, int num)
00541 {
00542 MMCFCB *fcb;
00543 NUTDEVICE *dev;
00544 MEMCARDSUPP *msc;
00545
00546
00547 NUTASSERT(nfp != NULL);
00548 NUTASSERT(nfp->nf_fcb != NULL);
00549 NUTASSERT(nfp->nf_dev != NULL);
00550 fcb = (MMCFCB *) nfp->nf_fcb;
00551 dev = (NUTDEVICE *) nfp->nf_dev;
00552 NUTASSERT(dev->dev_dcb != NULL);
00553 msc = (MEMCARDSUPP *) dev->dev_dcb;
00554
00555
00556 if (msc->mcs_cf == 0) {
00557
00558 msc->mcs_act(NUTMC_IND_WRITE);
00559
00560 if (buffer == NULL) {
00561 buffer = fcb->fcb_blkbuf;
00562 }
00563
00564 if (CardTxData(dev->dev_icb, MMCMD_WRITE_BLOCK, fcb->fcb_address, buffer, MMC_BLOCK_SIZE) == 0) {
00565
00566 msc->mcs_act(NUTMC_IND_OFF);
00567 return 1;
00568 }
00569 }
00570
00571 msc->mcs_act(NUTMC_IND_ERROR);
00572 return -1;
00573 }
00574
00575 #ifdef __HARVARD_ARCH__
00576
00595 int SpiMmcBlockWrite_P(NUTFILE * nfp, PGM_P buffer, int num)
00596 {
00597 return -1;
00598 }
00599 #endif
00600
00601 int SpiMmcUnmount(NUTFILE * nfp);
00602
00628 NUTFILE *SpiMmcMount(NUTDEVICE * dev, CONST char *name, int mode, int acc)
00629 {
00630 int partno = 0;
00631 int i;
00632 NUTDEVICE *fsdev;
00633 NUTFILE *nfp;
00634 MMCFCB *fcb;
00635 DOSPART *part;
00636 MEMCARDSUPP *msc = (MEMCARDSUPP *) dev->dev_dcb;
00637 FSCP_VOL_MOUNT mparm;
00638 NUTSPINODE * node = (NUTSPINODE *) dev->dev_icb;
00639
00640
00641 if ((msc->mcs_sf & NUTMC_SF_CD) == 0) {
00642 errno = ENODEV;
00643 return NUTFILE_EOF;
00644 }
00645
00646 msc->mcs_cf = 0;
00647
00648
00649 if (CardInit(node)) {
00650 errno = ENODEV;
00651 return NUTFILE_EOF;
00652 }
00653
00654
00655 if (*name) {
00656 partno = atoi(name);
00657 do {
00658 name++;
00659 } while (*name && *name != '/');
00660 if (*name == '/') {
00661 name++;
00662 }
00663 }
00664
00665
00666
00667
00668
00669
00670
00671 for (fsdev = nutDeviceList; fsdev; fsdev = fsdev->dev_next) {
00672 if (*name == 0) {
00673 if (fsdev->dev_type == IFTYP_FS) {
00674 break;
00675 }
00676 } else if (strcmp(fsdev->dev_name, name) == 0) {
00677 break;
00678 }
00679 }
00680
00681 if (fsdev == 0) {
00682 #ifdef NUTDEBUG
00683 printf("[NoFS'%s]", name);
00684 #endif
00685 errno = ENODEV;
00686 return NUTFILE_EOF;
00687 }
00688
00689 if ((fcb = calloc(1, sizeof(MMCFCB))) == 0) {
00690 errno = ENOMEM;
00691 return NUTFILE_EOF;
00692 }
00693 fcb->fcb_fsdev = fsdev;
00694
00695
00696 if (CardRxData(node, MMCMD_READ_SINGLE_BLOCK, 0, fcb->fcb_blkbuf, MMC_BLOCK_SIZE)) {
00697 free(fcb);
00698 return NUTFILE_EOF;
00699 }
00700 #ifdef NUTDEBUG
00701 DumpData(fcb->fcb_blkbuf, MMC_BLOCK_SIZE);
00702 #endif
00703
00704 if (fcb->fcb_blkbuf[DOSPART_MAGICPOS] != 0x55 || fcb->fcb_blkbuf[DOSPART_MAGICPOS + 1] != 0xAA) {
00705 free(fcb);
00706 return NUTFILE_EOF;
00707 }
00708
00709 if(fcb->fcb_blkbuf[DOSPART_TYPEPOS] == 'F' &&
00710 fcb->fcb_blkbuf[DOSPART_TYPEPOS + 1] == 'A' &&
00711 fcb->fcb_blkbuf[DOSPART_TYPEPOS + 2] == 'T') {
00712
00713 fcb->fcb_part.part_type = PTYPE_FAT12;
00714 fcb->fcb_part.part_sect_offs = 0;
00715 fcb->fcb_part.part_sects = 65536;
00716 }
00717 else {
00718
00719 part = (DOSPART *) & fcb->fcb_blkbuf[DOSPART_SECTORPOS];
00720 #ifdef NUTDEBUG
00721 for (i = 0; i < 4; i++) {
00722 printf("- State 0x%02x\n", part[i].part_state);
00723 printf(" Type 0x%02x\n", part[i].part_type);
00724 printf(" Start %lu\n", part[i].part_sect_offs);
00725 printf(" Size %lu\n", part[i].part_sects);
00726 }
00727 #endif
00728 for (i = 1; i <= 4; i++) {
00729 if (partno) {
00730 if (i == partno) {
00731
00732 fcb->fcb_part = *part;
00733 break;
00734 }
00735 } else if (part->part_state & 0x80) {
00736
00737 fcb->fcb_part = *part;
00738 break;
00739 }
00740 part++;
00741 }
00742
00743 if (fcb->fcb_part.part_type == PTYPE_EMPTY) {
00744 free(fcb);
00745 return NUTFILE_EOF;
00746 }
00747 }
00748
00749 if ((nfp = NutHeapAlloc(sizeof(NUTFILE))) == 0) {
00750 free(fcb);
00751 errno = ENOMEM;
00752 return NUTFILE_EOF;
00753 }
00754 nfp->nf_next = 0;
00755 nfp->nf_dev = dev;
00756 nfp->nf_fcb = fcb;
00757
00758
00759
00760
00761 mparm.fscp_bmnt = nfp;
00762 mparm.fscp_part_type = fcb->fcb_part.part_type;
00763 if (fsdev->dev_ioctl(fsdev, FS_VOL_MOUNT, &mparm)) {
00764 SpiMmcUnmount(nfp);
00765 return NUTFILE_EOF;
00766 }
00767 return nfp;
00768 }
00769
00780 int SpiMmcUnmount(NUTFILE * nfp)
00781 {
00782 int rc;
00783 MMCFCB *fcb;
00784 NUTDEVICE *dev;
00785
00786
00787 NUTASSERT(nfp != NULL);
00788 NUTASSERT(nfp->nf_fcb != NULL);
00789 NUTASSERT(nfp->nf_dev != NULL);
00790 fcb = (MMCFCB *) nfp->nf_fcb;
00791 dev = (NUTDEVICE *) nfp->nf_dev;
00792 NUTASSERT(dev->dev_dcb != NULL);
00793
00794
00795
00796 rc = fcb->fcb_fsdev->dev_ioctl(fcb->fcb_fsdev, FS_VOL_UNMOUNT, NULL);
00797 free(fcb);
00798 free(nfp);
00799
00800 return rc;
00801 }
00802
00826 int SpiMmcIOCtl(NUTDEVICE * dev, int req, void *conf)
00827 {
00828 int rc = 0;
00829 NUTSPINODE * node = (NUTSPINODE *) dev->dev_icb;
00830 MEMCARDSUPP *msc = (MEMCARDSUPP *) dev->dev_dcb;
00831
00832 switch (req) {
00833 case NUTBLKDEV_MEDIAAVAIL:
00834 {
00835 int *flg = (int *) conf;
00836 *flg = msc->mcs_sf & NUTMC_SF_CD;
00837 }
00838 break;
00839 case NUTBLKDEV_MEDIACHANGE:
00840 {
00841 int *flg = (int *) conf;
00842 *flg = msc->mcs_cf;
00843 }
00844 break;
00845 case NUTBLKDEV_INFO:
00846 {
00847 BLKPAR_INFO *par = (BLKPAR_INFO *) conf;
00848 MMCFCB *fcb = (MMCFCB *) par->par_nfp->nf_fcb;
00849
00850 par->par_nblks = fcb->fcb_part.part_sects;
00851 par->par_blksz = MMC_BLOCK_SIZE;
00852 par->par_blkbp = fcb->fcb_blkbuf;
00853 }
00854 break;
00855 case NUTBLKDEV_SEEK:
00856 {
00857 BLKPAR_SEEK *par = (BLKPAR_SEEK *) conf;
00858 MMCFCB *fcb = (MMCFCB *) par->par_nfp->nf_fcb;
00859
00860
00861 fcb->fcb_address = (par->par_blknum + fcb->fcb_part.part_sect_offs) << 9;
00862 }
00863 break;
00864 case MMCARD_GETSTATUS:
00865 {
00866 uint16_t *s = (uint16_t *) conf;
00867
00868 *s = CardTxCommand(node, MMCMD_SEND_STATUS, 0, 2);
00869 }
00870 break;
00871 case MMCARD_GETOCR:
00872 {
00873 NUTSPIBUS *bus = (NUTSPIBUS *) node->node_bus;
00874
00875 if (CardTxCommand(node, MMCMD_READ_OCR, 0, 0) == MMR1_IDLE_STATE) {
00876 uint32_t * ocr = (uint32_t *) conf;
00877 uint_fast8_t i;
00878 uint8_t rxb;
00879
00880 for (i = 0; i < 4; i++) {
00881 (*bus->bus_transfer) (node, NULL, &rxb, 1);
00882 *ocr <<= 8;
00883 *ocr |= rxb;
00884 }
00885
00886 } else {
00887 rc = 1;
00888 }
00889 (*bus->bus_release) (node);
00890 }
00891 break;
00892 case MMCARD_GETCID:
00893 rc = CardRxData(node, MMCMD_SEND_CID, 0, (uint8_t *) conf, sizeof(MMC_CID));
00894 break;
00895 case MMCARD_GETCSD:
00896 rc = CardRxData(node, MMCMD_SEND_CSD, 0, (uint8_t *) conf, sizeof(MMC_CSD));
00897 break;
00898 case MMCARD_GETEXTCSD:
00899 rc = CardRxData(node, MMCMD_SEND_EXTCSD, 0, (uint8_t *) conf, sizeof(MMC_CSD));
00900 break;
00901 default:
00902 rc = -1;
00903 break;
00904 }
00905 return rc;
00906 }
00907
00919 int SpiMmcInit(NUTDEVICE * dev)
00920 {
00921 return 0;
00922 }
00923