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