]> cloudbase.mooo.com Git - z180-stamp.git/blobdiff - avr/mmc.c
SD slot 0: Enable card detection
[z180-stamp.git] / avr / mmc.c
index 2592c45f12b7fb644294a028f561f645fbf5b7b2..80152f83500483b6f442cef4d235195f11e14571 100644 (file)
--- a/avr/mmc.c
+++ b/avr/mmc.c
 #include "timer.h"
 #include "spi.h"
 #include "diskio.h"
-//#include "debug.h"
+#include "debug.h"
 
+#define MAX_DRV                2
 
 /* Port Controls  (Platform dependent) */
 /* SD card socket connections */
 
-#define SD_CD_1                SBIT(PORTG,3)           /* Card detect switch */
-#define SD_CD_1_IN     SBIT(PING,3)
-#define SD_CD_1_DDR    SBIT(DDRG,3)
+/* TODO: config.h cofig macros */
 
-//#define SD_WP_1      SBIT(PORTG,5)           /* Write protect switch */
-#define SD_WP_1_IN     SBIT(PING,5)
-#define SD_WP_1_DDR    SBIT(DDRG,5)
+//#define SD_CD_0              SBIT(PORT,)             /* Card detect switch */
+//#define SD_CD_0_IN   SBIT(PIN,)
+//#define SD_CD_0_DDR  SBIT(DDR,)
+
+//#define SD_WP_0              SBIT(PORT,)             /* Write protect switch */
+//#define SD_WP_0_IN   SBIT(PIN,)
+//#define SD_WP_0_DDR  SBIT(DDR,)
+
+#define SD_CS_0                SBIT(PORTB,0)   /* Chip select pin */
+#define SD_CS_0_IN     SBIT(PINB,0)
+#define SD_CS_0_DDR    SBIT(DDRB,0)
+
+
+//#define SD_CD_1              SBIT(PORTG,3)   /* Card detect switch */
+//#define SD_CD_1_IN   SBIT(PING,3)
+//#define SD_CD_1_DDR  SBIT(DDRG,3)
+
+//#define SD_WP_1              SBIT(PORTG,5)   /* Write protect switch */
+//#define SD_WP_1_IN   SBIT(PING,5)
+//#define SD_WP_1_DDR  SBIT(DDRG,5)
 
 #define SD_CS_1                SBIT(PORTG,4)           /* Chip select pin */
 #define SD_CS_1_IN     SBIT(PING,4)
 #define SD_CS_1_DDR    SBIT(DDRG,4)
 
 
-#define        FCLK_SLOW()     SPISetMMCInitClock()    /* Set slow clock (100k-400k) */
-#define        FCLK_FAST()     SPISetFastClock()       /* Set fast clock (depends on the CSD) */
-
+#define        SPI_CLK_SLOW()  SPISetMMCInitClock()    /* Set slow clock (100k-400k) */
+#define        SPI_CLK_FAST()  SPISetFastClock()               /* Set fast clock (depends on the CSD) */
 
 /*--------------------------------------------------------------------------
  Definitions for MMC/SDC command
@@ -69,7 +84,7 @@ struct sdsock_stat_s {
 
 static
 struct sdsock_stat_s
-       socket[2] = {
+       socket[MAX_DRV] = {
                {.stat=STA_NOINIT},
                {.stat=STA_NOINIT}
        };
@@ -98,35 +113,73 @@ int wait_ready (void)      /* 1:OK, 0:Timeout */
 /*-----------------------------------------------------------------------*/
 
 static
-void deselect (void)
+void deselect(BYTE drv)
 {
-//     debug("*** enter deselect()\n");
-       SD_CS_1 = 1;
+       //debug("*** enter deselect()\n");
+       if (drv == 0)
+               SD_CS_0 = 1;
+       else {
+               SD_CS_1 = 1;
+       }
+
        /* Dummy clock (TODO: force DO hi-z for multiple slave SPI) */
+       if (socket[drv].stat & STA_FAST)
+               SPI_CLK_FAST();
+       else
+               SPI_CLK_SLOW();
        spi_rcvr();
-//     debug("***  exit deselect()\n");
-}
-
+       SPI_OFF();
 
+       if (drv == 0) {
+#ifdef SD_CS_0_IN
+               SD_CS_0_DDR = 0;
+               SD_CS_0 = 0;
+#endif
+       } else {
+#ifdef SD_CS_1_IN
+               SD_CS_1_DDR = 0;
+               SD_CS_1 = 0;
+#endif
+       }
+       //debug("***  exit deselect()\n");
+}
 
 /*-----------------------------------------------------------------------*/
 /* Select the card and wait for ready                                    */
 /*-----------------------------------------------------------------------*/
 
 static
-int select (void)      /* 1:Successful, 0:Timeout */
+int select(BYTE drv)   /* 1:Successful, 0:Timeout */
 {
-//     debug("*** enter select()\n");
-       SD_CS_1 = 0;
+       //debug("*** enter select()\n");
+       if (drv == 0) {
+#ifdef SD_CS_0_IN
+               SD_CS_0 = 1;
+               SD_CS_0_DDR = 1;
+#endif
+               SD_CS_0 = 0;
+       } else {
+#ifdef SD_CS_1_IN
+               SD_CS_1 = 1;
+               SD_CS_1_DDR = 1;
+#endif
+               SD_CS_1 = 0;
+       }
+
+       if (socket[drv].stat & STA_FAST)
+               SPI_CLK_FAST();
+       else
+               SPI_CLK_SLOW();
+
        /* Dummy clock (force DO enabled) */
        spi_rcvr();
 
        if (wait_ready()) {
-//             debug("***  exit select() == 1\n");
+               //debug("***  exit select() == 1\n");
                return 1;       /* OK */
        }
-       deselect();
-//     debug("***  exit select() == 0\n");
+       deselect(drv);
+       //debug("***  exit select() == 0\n");
 
        return 0;       /* Timeout */
 }
@@ -138,56 +191,64 @@ int select (void) /* 1:Successful, 0:Timeout */
 /* is nothing to do in these functions and chk_power always returns 1.   */
 
 static
-void power_on(void)
+void power_on(BYTE drv)
 {
-//     debug("*** enter power_on()\n");
+       //debug("*** enter power_on()\n");
 
-#ifdef SD_PWR_1
-       SD_PWR_1_DDR = 1;       /* Turns on PWR pin as output */
-       SD_PWR_1 = 0;           /* Drives PWR pin high */
-
-       for (uint32_t to = get_timer(0); get_timer(to) < 30;)
-               ; /* Wait for 30ms */
+       if (drv == 0) {
+#ifdef SD_PWR_0
+               SD_PWR_0 = 0;           /* Drives PWR pin high */
 #endif
 
-#ifdef SD_CD_1
-       /* Card detect, input with pullup */
-       SD_CD_1_DDR = 0;
-       SD_CD_1 = 1;
+       } else {
+#ifdef SD_PWR_1
+               SD_PWR_1 = 0;           /* Drives PWR pin high */
 #endif
-#ifdef SD_WP_1
-       SD_WP_1_DDR = 0;
-       SD_WP_1 = 1;
+       }
+#if defined SD_PWR_0 || defined SD_PWR_1
+               for (uint32_t to = get_timer(0); get_timer(to) < 30;)
+                       ; /* Wait for 30ms */
 #endif
-       SD_CS_1 = 1;
-       SD_CS_1_DDR = 1;
-
-//     debug("***  exit power_on()\n");
+       //debug("***  exit power_on()\n");
 }
 
 static
-void power_off (void)
+void power_off(BYTE drv)
 {
-//     debug("*** enter power_off()\n");
-       select();               /* Wait for card ready */
-       deselect();
+       //debug("*** enter power_off()\n");
+       select(drv);            /* Wait for card ready */
+       deselect(drv);
 
+       if (drv == 0) {
+#ifdef SD_PWR_0
+               SD_PWR_0 = 1;           /* Socket power OFF */
+#endif
+       } else {
 #ifdef SD_PWR_1
-       SD_PWR_1 = 1;           /* Socket power OFF */
+               SD_PWR_1 = 1;           /* Socket power OFF */
 #endif
-       socket[0].stat |= STA_NOINIT;
-//     debug("***  exit power_off()\n");
+       }
+       socket[drv].stat |= STA_NOINIT;
+       //debug("***  exit power_off()\n");
 }
 
 #if 0
 static
-int chk_power(void) /* Socket power state: 0=off, 1=on */
+int chk_power(BYTE drv) /* Socket power state: 0=off, 1=on */
 {
+       if (drv == 0) {
+#ifdef SD_PWR_0
+               return SD_PWR_0 == 0;
+#else
+               return 1;
+#endif /* SD_PWR_PIN */
+       } else {
 #ifdef SD_PWR_1
-       return SD_PWR_1 == 0;
+               return SD_PWR_1 == 0;
 #else
-       return 1;
+               return 1;
 #endif /* SD_PWR_PIN */
+       }
 }
 #endif
 
@@ -267,8 +328,9 @@ int xmit_datablock (
 
 static
 BYTE send_cmd (                /* Returns R1 resp (bit7==1:Send failed) */
-       BYTE cmd,               /* Command index */
-                                        DWORD arg /* Argument */
+       BYTE drv,       /* Physical drive nmuber (0) */
+       BYTE cmd,       /* Command index */
+       DWORD arg       /* Argument */
 ) {
        union {
                DWORD as32;
@@ -276,19 +338,19 @@ BYTE send_cmd (           /* Returns R1 resp (bit7==1:Send failed) */
        } argtmp;
        BYTE n, res;
 
-//     debug("*** send_cmd( %.2x )\n", cmd);
+       //debug("*** send_cmd( %.2x )\n", cmd);
 
        if (cmd & 0x80) { /* ACMD<n> is the command sequense of CMD55-CMD<n> */
                cmd &= 0x7F;
-               res = send_cmd(CMD55, 0);
+               res = send_cmd(drv, CMD55, 0);
                if (res > 1)
                        return res;
        }
 
        /* Select the card and wait for ready except to stop multiple block read */
        if (cmd != CMD12) {
-               deselect();
-               if (!select())
+               deselect(drv);
+               if (!select(drv))
                        return 0xFF;
        }
 
@@ -324,6 +386,55 @@ BYTE send_cmd (            /* Returns R1 resp (bit7==1:Send failed) */
 
  ---------------------------------------------------------------------------*/
 
+void setup_mmc(void)
+{
+#ifdef SD_PWR_0
+               SD_PWR_1 = 1;           /* Drives PWR pin low */
+               SD_PWR_0_DDR = 1;       /* Turns on PWR pin as output */
+#endif
+#ifdef SD_WP_0
+               SD_WP_0_DDR = 0;
+               SD_WP_0 = 1;            /* Pullup */
+#endif
+
+#ifdef SD_PWR_1
+               SD_PWR_1 = 1;           /* Drives PWR pin low */
+               SD_PWR_1_DDR = 1;       /* Turns on PWR pin as output */
+#endif
+#ifdef SD_WP_1
+               SD_WP_1_DDR = 0;
+               SD_WP_1 = 1;            /* Pullup */
+#endif
+
+       /* SPI as master */
+       PRR0 &= ~_BV(PRSPI);
+       SPI_DDR = (SPI_DDR & ~(_BV(SPI_MISO) | _BV(SPI_SS)))
+                       | _BV(SPI_MOSI) | _BV(SPI_SCK);
+       SPI_PORT = SPI_PORT & ~(_BV(SPI_MOSI) | _BV(SPI_SCK));
+
+#if defined SD_CD_0
+       SD_CD_0_DDR = 0;
+       SD_CD_0 = 1;
+#elif defined SD_CS_0_IN
+       SD_CS_0_DDR = 0;
+       SD_CS_0 = 0;
+#else
+       SD_CS_0_DDR = 1;
+       SD_CS_0 = 1;
+#endif
+
+#if defined SD_CD_1
+       SD_CD_1_DDR = 0;
+       SD_CD_1 = 1;
+#elif defined SD_CS_1_IN
+       SD_CS_1_DDR = 0;
+       SD_CS_1 = 0;
+#else
+       SD_CS_1_DDR = 1;
+       SD_CS_1 = 1;
+#endif
+}
+
 /*-----------------------------------------------------------------------*/
 /* Initialize Disk Drive                                                 */
 /*-----------------------------------------------------------------------*/
@@ -336,53 +447,62 @@ DSTATUS disk_initialize (
 {
        BYTE n, cmd, ty, ocr[4];
 
-       if (drv)
+       if (drv >= MAX_DRV)
                return STA_NOINIT; /* Supports only single drive */
        if (socket[drv].stat & STA_NODISK)
                return socket[drv].stat; /* No card in the socket */
 
-       power_on(); /* Force socket power on */
-       FCLK_SLOW();
+       power_on(drv); /* Force socket power on */
+       socket[drv].stat &= ~STA_FAST;
+       SPI_CLK_SLOW();
        for (n = 10; n; n--)
                spi_rcvr(); /* 80 dummy clocks */
 
        ty = 0;
-       if (send_cmd(CMD0, 0) == 1) { /* Enter Idle state */
+       if (send_cmd(drv, CMD0, 0) == 1) { /* Enter Idle state */
                /* Init timeout timer */
                uint32_t timer = get_timer(0);
 
-               if (send_cmd(CMD8, 0x1AA) == 1) {       /* SDv2? */
-                       for (n = 0; n < 4; n++) ocr[n] = spi_rcvr();            /* Get trailing return value of R7 resp */
-                       if (ocr[2] == 0x01 && ocr[3] == 0xAA) { /* The card can work at vdd range of 2.7-3.6V */
-                               while (get_timer(timer) < MMC_INIT_TO && send_cmd(ACMD41, 1UL << 30));  /* Wait for leaving idle state (ACMD41 with HCS bit) */
-                               if (get_timer(timer) < MMC_INIT_TO && send_cmd(CMD58, 0) == 0) {                /* Check CCS bit in the OCR */
-                                       for (n = 0; n < 4; n++) ocr[n] = spi_rcvr();
+               if (send_cmd(drv, CMD8, 0x1AA) == 1) {  /* SDv2? */
+                       /* Get trailing return value of R7 resp */
+                       for (n = 0; n < 4; n++)
+                               ocr[n] = spi_rcvr();
+                       if (ocr[2] == 0x01 && ocr[3] == 0xAA) {
+                               /* The card can work at vdd range of 2.7-3.6V */
+                               while (get_timer(timer) < MMC_INIT_TO
+                                       && send_cmd(drv, ACMD41, 1UL << 30))
+                                       ; /* Wait for leaving idle state (ACMD41 with HCS bit) */
+                               if (get_timer(timer) < MMC_INIT_TO && send_cmd(drv, CMD58, 0) == 0) {
+                                       /* Check CCS bit in the OCR */
+                                       for (n = 0; n < 4; n++)
+                                               ocr[n] = spi_rcvr();
                                        ty = (ocr[0] & 0x40) ? CT_SD2 | CT_BLOCK : CT_SD2;      /* SDv2 */
                                }
                        }
                } else {                                                        /* SDv1 or MMCv3 */
-                       if (send_cmd(ACMD41, 0) <= 1) {
+                       if (send_cmd(drv, ACMD41, 0) <= 1) {
                                ty = CT_SD1; cmd = ACMD41;      /* SDv1 */
                        } else {
                                ty = CT_MMC; cmd = CMD1;        /* MMCv3 */
                        }
 
                        /* Wait for leaving idle state */
-                       while (get_timer(timer) < MMC_INIT_TO && send_cmd(cmd, 0));
+                       while (get_timer(timer) < MMC_INIT_TO && send_cmd(drv, cmd, 0))
+                               ;
 
                        /* Set R/W block length to 512 */
-                       if (!(get_timer(timer) < MMC_INIT_TO) || send_cmd(CMD16, 512) != 0)
+                       if (!(get_timer(timer) < MMC_INIT_TO) || send_cmd(drv, CMD16, 512) != 0)
                                ty = 0;
                }
        }
        socket[drv].CardType = ty;
-       deselect();
+       deselect(drv);
 
        if (ty) { /* Initialization succeded */
-               socket[drv].stat &= ~STA_NOINIT; /* Clear STA_NOINIT */
-               FCLK_FAST();
+               /* Clear STA_NOINIT */
+               socket[drv].stat = (socket[drv].stat & ~STA_NOINIT) | STA_FAST;
        } else { /* Initialization failed */
-               power_off();
+               power_off(drv);
        }
 
        return socket[drv].stat;
@@ -393,10 +513,11 @@ DSTATUS disk_initialize (
 /*-----------------------------------------------------------------------*/
 
 DSTATUS disk_status (
-       BYTE drv                /* Physical drive nmuber (0) */
+       BYTE drv        /* Physical drive nmuber (0) */
 )
 {
-       if (drv) return STA_NOINIT;             /* Supports only single drive */
+       if (drv >= MAX_DRV)
+               return STA_NOINIT;
        return socket[drv].stat;
 }
 
@@ -405,30 +526,35 @@ DSTATUS disk_status (
 /*-----------------------------------------------------------------------*/
 
 DRESULT disk_read (
-       BYTE drv,                       /* Physical drive nmuber (0) */
-       BYTE *buff, /* Pointer to the data buffer to store read data */
-       DWORD sector, /* Start sector number (LBA) */
-       UINT count /* Sector count (1..255) */
+       BYTE drv,       /* Physical drive nmuber (0) */
+       BYTE *buff,     /* Pointer to the data buffer to store read data */
+       DWORD sector,   /* Start sector number (LBA) */
+       UINT count      /* Sector count (1..255) */
 )
 {
        BYTE cmd;
 
-       if (drv || !count) return RES_PARERR;
-       if (socket[drv].stat & STA_NOINIT) return RES_NOTRDY;
+       if (drv >= MAX_DRV || !count)
+               return RES_PARERR;
+       if (socket[drv].stat & STA_NOINIT)
+               return RES_NOTRDY;
 
-       if (!(socket[drv].CardType & CT_BLOCK)) sector *= 512;  /* Convert to byte address if needed */
+       /* Convert to byte address if needed */
+       if (!(socket[drv].CardType & CT_BLOCK))
+               sector *= 512;
 
-       cmd = count > 1 ? CMD18 : CMD17;                        /*  READ_MULTIPLE_BLOCK : READ_SINGLE_BLOCK */
-       if (send_cmd(cmd, sector) == 0) {
+       /*  READ_MULTIPLE_BLOCK : READ_SINGLE_BLOCK */
+       cmd = count > 1 ? CMD18 : CMD17;
+       if (send_cmd(drv, cmd, sector) == 0) {
                do {
                        if (!rcvr_datablock(buff, 512))
                                break;
                        buff += 512;
                } while (--count);
                if (cmd == CMD18)
-                       send_cmd(CMD12, 0);     /* STOP_TRANSMISSION */
+                       send_cmd(drv, CMD12, 0);        /* STOP_TRANSMISSION */
        }
-       deselect();
+       deselect(drv);
 
        return count ? RES_ERROR : RES_OK;
 }
@@ -439,35 +565,44 @@ DRESULT disk_read (
 
 #if _USE_WRITE
 DRESULT disk_write (
-               BYTE drv, /* Physical drive nmuber (0) */
-               const BYTE *buff, /* Pointer to the data to be written */
-               DWORD sector, /* Start sector number (LBA) */
-               UINT count /* Sector count (1..255) */
+       BYTE drv,       /* Physical drive nmuber (0) */
+       const BYTE *buff, /* Pointer to the data to be written */
+       DWORD sector,   /* Start sector number (LBA) */
+       UINT count      /* Sector count (1..255) */
 )
 {
-       if (drv || !count) return RES_PARERR;
-       if (socket[drv].stat & STA_NOINIT) return RES_NOTRDY;
-       if (socket[drv].stat & STA_PROTECT) return RES_WRPRT;
-
-       if (!(socket[drv].CardType & CT_BLOCK)) sector *= 512; /* Convert to byte address if needed */
-
-       if (count == 1) { /* Single block write */
-               if ((send_cmd(CMD24, sector) == 0) /* WRITE_BLOCK */
+       if (drv >= MAX_DRV || !count)
+               return RES_PARERR;
+       if (socket[drv].stat & STA_NOINIT)
+               return RES_NOTRDY;
+       if (socket[drv].stat & STA_PROTECT)
+               return RES_WRPRT;
+
+       /* Convert to byte address if needed */
+       if (!(socket[drv].CardType & CT_BLOCK))
+               sector *= 512;
+
+       if (count == 1) {
+               /* Single block write */
+               if ((send_cmd(drv, CMD24, sector) == 0) /* WRITE_BLOCK */
                                && xmit_datablock(buff, 0xFE))
                count = 0;
-       }
-       else { /* Multiple block write */
-               if (socket[drv].CardType & CT_SDC) send_cmd(ACMD23, count);
-               if (send_cmd(CMD25, sector) == 0) { /* WRITE_MULTIPLE_BLOCK */
+       } else {
+               /* Multiple block write */
+               if (socket[drv].CardType & CT_SDC)
+                       send_cmd(drv, ACMD23, count);
+               if (send_cmd(drv, CMD25, sector) == 0) {
+                       /* WRITE_MULTIPLE_BLOCK */
                        do {
-                               if (!xmit_datablock(buff, 0xFC)) break;
+                               if (!xmit_datablock(buff, 0xFC))
+                                       break;
                                buff += 512;
-                       }while (--count);
+                       } while (--count);
                        if (!xmit_datablock(0, 0xFD)) /* STOP_TRAN token */
-                       count = 1;
+                               count = 1;
                }
        }
-       deselect();
+       deselect(drv);
 
        return count ? RES_ERROR : RES_OK;
 }
@@ -488,21 +623,24 @@ DRESULT disk_ioctl (
        BYTE n, csd[16], *ptr = buff;
        DWORD csize;
 
-       if (drv)
+       if (drv >= MAX_DRV)
                return RES_PARERR;
 
        res = RES_ERROR;
 
-       if (socket[drv].stat & STA_NOINIT) return RES_NOTRDY;
+       if (socket[drv].stat & STA_NOINIT)
+               return RES_NOTRDY;
+
+       /* TODO: SPI clock? */
 
        switch (cmd) {
        case CTRL_SYNC :                /* Make sure that no pending write process. Do not remove this or written sector might not left updated. */
-               if (select())
+               if (select(drv))
                        res = RES_OK;
                break;
 
        case GET_SECTOR_COUNT: /* Get number of sectors on the disk (DWORD) */
-               if ((send_cmd(CMD9, 0) == 0) && rcvr_datablock(csd, 16)) {
+               if ((send_cmd(drv, CMD9, 0) == 0) && rcvr_datablock(csd, 16)) {
                        if ((csd[0] >> 6) == 1) {       /* SDC ver 2.00 */
                                csize = csd[9] + ((WORD)csd[8] << 8) + ((DWORD)(csd[7] & 63) << 16) + 1;
                                *(DWORD*)buff = csize << 10;
@@ -517,7 +655,7 @@ DRESULT disk_ioctl (
 
        case GET_BLOCK_SIZE:    /* Get erase block size in unit of sector (DWORD) */
                if (socket[drv].CardType & CT_SD2) {    /* SDv2? */
-                       if (send_cmd(ACMD13, 0) == 0) { /* Read SD status */
+                       if (send_cmd(drv, ACMD13, 0) == 0) { /* Read SD status */
                                spi_rcvr();
                                if (rcvr_datablock(csd, 16)) { /* Read partial block */
                                        for (n = 64 - 16; n; n--)
@@ -527,7 +665,7 @@ DRESULT disk_ioctl (
                                }
                        }
                } else {                                        /* SDv1 or MMCv3 */
-                       if ((send_cmd(CMD9, 0) == 0) && rcvr_datablock(csd, 16)) { /* Read CSD */
+                       if ((send_cmd(drv, CMD9, 0) == 0) && rcvr_datablock(csd, 16)) { /* Read CSD */
                                if (socket[drv].CardType & CT_SD1) {    /* SDv1 */
                                        *(DWORD*)buff = (((csd[10] & 63) << 1) + ((WORD)(csd[11] & 128) >> 7) + 1) << ((csd[13] >> 6) - 1);
                                } else {                                        /* MMCv3 */
@@ -546,19 +684,19 @@ DRESULT disk_ioctl (
                break;
 
        case MMC_GET_CSD: /* Receive CSD as a data block (16 bytes) */
-               if (send_cmd(CMD9, 0) == 0 /* READ_CSD */
+               if (send_cmd(drv, CMD9, 0) == 0 /* READ_CSD */
                && rcvr_datablock(ptr, 16))
                        res = RES_OK;
                break;
 
        case MMC_GET_CID: /* Receive CID as a data block (16 bytes) */
-               if (send_cmd(CMD10, 0) == 0 /* READ_CID */
+               if (send_cmd(drv, CMD10, 0) == 0 /* READ_CID */
                && rcvr_datablock(ptr, 16))
                        res = RES_OK;
                break;
 
        case MMC_GET_OCR: /* Receive OCR as an R3 resp (4 bytes) */
-               if (send_cmd(CMD58, 0) == 0) { /* READ_OCR */
+               if (send_cmd(drv, CMD58, 0) == 0) { /* READ_OCR */
                        for (n = 4; n; n--)
                                *ptr++ = spi_rcvr();
                        res = RES_OK;
@@ -566,7 +704,7 @@ DRESULT disk_ioctl (
                break;
 
        case MMC_GET_SDSTAT: /* Receive SD status as a data block (64 bytes) */
-               if (send_cmd(ACMD13, 0) == 0) { /* SD_STATUS */
+               if (send_cmd(drv, ACMD13, 0) == 0) { /* SD_STATUS */
                        spi_rcvr();
                        if (rcvr_datablock(ptr, 64))
                                res = RES_OK;
@@ -574,7 +712,7 @@ DRESULT disk_ioctl (
                break;
 
        case CTRL_POWER_OFF :   /* Power off */
-               power_off();
+               power_off(drv);
                socket[drv].stat |= STA_NOINIT;
                res = RES_OK;
                break;
@@ -583,7 +721,7 @@ DRESULT disk_ioctl (
                res = RES_PARERR;
        }
 
-       deselect();
+       deselect(drv);
 
        return res;
 }
@@ -599,20 +737,48 @@ void disk_timerproc (void)
        BYTE s;
 
        s = socket[0].stat;
+#ifdef SD_WP_0
+       if (SD_WP_0_IN == 0)                    /* Write protected */
+               s |= STA_PROTECT;
+       else                                                    /* Write enabled */
+               s &= ~STA_PROTECT;
+#endif
 
+#if defined SD_CD_0
+       if (SD_CD_0_IN == 0)                    /* Card inserted */
+               s &= ~STA_NODISK;
+       else                                                    /* Socket empty */
+               s |= (STA_NODISK | STA_NOINIT);
+#elif defined SD_CS_0_IN
+       if (SD_CS_0_DDR == 0) {
+               if (SD_CS_0_IN == 1)            /* Card inserted */
+                       s &= ~STA_NODISK;
+               else                                            /* Socket empty */
+                       s |= (STA_NODISK | STA_NOINIT);
+       }
+#endif
+       socket[0].stat = s;                             /* Update MMC status */
+
+       s = socket[1].stat;
 #ifdef SD_WP_1
        if (SD_WP_1_IN == 0)                    /* Write protected */
                s |= STA_PROTECT;
-       else                                    /* Write enabled */
+       else                                                    /* Write enabled */
                s &= ~STA_PROTECT;
 #endif
 
-#ifdef SD_CD_1
+#if defined SD_CD_1
        if (SD_CD_1_IN == 0)                    /* Card inserted */
                s &= ~STA_NODISK;
-       else                                    /* Socket empty */
+       else                                                    /* Socket empty */
                s |= (STA_NODISK | STA_NOINIT);
+#elif defined SD_CS_1_IN
+       if (SD_CS_1_DDR == 0) {
+               if (SD_CS_1_IN == 1)            /* Card inserted */
+                       s &= ~STA_NODISK;
+               else                                            /* Socket empty */
+                       s |= (STA_NODISK | STA_NOINIT);
+       }
 #endif
-
-       socket[0].stat = s;                     /* Update MMC status */
+       socket[1].stat = s;                     /* Update MMC status */
 }