]> cloudbase.mooo.com Git - z180-stamp.git/blobdiff - avr/mmc.c
SD slot 0: Enable card detection
[z180-stamp.git] / avr / mmc.c
index eb10ea6dda9ef99753ac01983c0814e46c4c7398..80152f83500483b6f442cef4d235195f11e14571 100644 (file)
--- a/avr/mmc.c
+++ b/avr/mmc.c
@@ -5,16 +5,53 @@
 /* are platform dependent.                                               */
 /*-----------------------------------------------------------------------*/
 
-#include <avr/io.h>
+#include "common.h"
 #include <stdbool.h>
 #include "timer.h"
 #include "spi.h"
 #include "diskio.h"
 #include "debug.h"
-#include "print-utils.h"
 
+#define MAX_DRV                2
+
+/* Port Controls  (Platform dependent) */
+/* SD card socket connections */
+
+/* TODO: config.h cofig macros */
+
+//#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        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
+ ---------------------------------------------------------------------------*/
 
-/* Definitions for MMC/SDC command */
 #define CMD0   (0)                     /* GO_IDLE_STATE */
 #define CMD1   (1)                     /* SEND_OP_COND (MMC) */
 #define        ACMD41  (0x80+41)       /* SEND_OP_COND (SDC) */
 #define CMD58  (58)            /* READ_OCR */
 
 
-/* SD card socket connections */
-#if 0
-//#define MMC_PORT             PORTG           /* Socket contact port */
-//#define MMC_INPORT           PING
-//#define SD_WP_PIN            5                       /* Write protect switch */
-#endif
-
-/* SD card SPI access */
-#define SD_CD_PORT             PORTG
-#define SD_CD_DDR              DDRG
-#define SD_CD_INPORT           PING
-#define SD_CD_PIN              3                       /* Card detect switch */
-
-#define SD_WP_PORT             PORTG
-#define SD_WP_DDR              DDRG
-#define SD_WP_INPORT           PING
-//#define SD_WP_PIN            5                       /* Write protect switch */
-
-#define SD_CS_PORT             PORTG
-#define SD_CS_DDR              DDRG
-#define SD_CS_PIN              4                       /* Chip select pin */
-
-
-/* Port Controls  (Platform dependent) */
-
-#ifdef SD_CD_PIN
-static inline
-bool sd_cd(void)
-{
-       return (SD_CD_INPORT & _BV(SD_CD_PIN)) == 0;
-}
-#endif
-
-#ifdef SD_WP_PIN
-static inline
-bool sd_wp(void)
-{
-       return (SD_WP_INPORT & _BV(SD_WP_PIN)) == 0;
-}
-#endif
-
-#define CS_LOW()       SD_CS_PORT &= ~(1<<SD_CS_PIN)   /* MMC CS = L */
-#define CS_HIGH()      SD_CS_PORT |=  (1<<SD_CS_PIN)   /* MMC CS = H */
-
-#define        FCLK_SLOW()     SPISetMMCInitClock() /* Set slow clock (100k-400k) */
-#define        FCLK_FAST()     SPISetFastClock()        /* Set fast clock (depends on the CSD) */
-
 /*--------------------------------------------------------------------------
 
  Module Private Functions
 
  ---------------------------------------------------------------------------*/
 
-static volatile
-DSTATUS disk_stat = STA_NOINIT;        /* Disk status */
+struct sdsock_stat_s {
+       volatile DSTATUS stat;  /* Disk/socket status */
+       BYTE CardType;          /* Card type flags */
+};
 
 static
-BYTE CardType;                         /* Card type flags */
+struct sdsock_stat_s
+       socket[MAX_DRV] = {
+               {.stat=STA_NOINIT},
+               {.stat=STA_NOINIT}
+       };
 
 /*-----------------------------------------------------------------------*/
 /* Wait for card ready                                                   */
@@ -117,35 +113,73 @@ int wait_ready (void)     /* 1:OK, 0:Timeout */
 /*-----------------------------------------------------------------------*/
 
 static
-void deselect (void)
+void deselect(BYTE drv)
 {
-//     debug("*** enter deselect()\n");
-       CS_HIGH();
+       //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");
-       CS_LOW();
+       //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 */
 }
@@ -157,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");
-
-#ifdef SD_PWR_PIN
-       SD_PWR_DDR |= _BV(SD_PWR_PIN); // Turns on PWR pin as output
-       SD_PWR_PORT &= ~_BV(SD_PWR_PIN); // Drives PWR pin high
+       //debug("*** enter power_on()\n");
 
-       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_PIN
-       /* Card detect, input with pullup */
-       SD_CD_DDR &= ~_BV(SD_CD_PIN);
-       SD_CD_PORT |= _BV(SD_CD_PIN);
+       } else {
+#ifdef SD_PWR_1
+               SD_PWR_1 = 0;           /* Drives PWR pin high */
 #endif
-#ifdef SD_WP_PIN
-       SD_WP_DDR &= ~_BV(SD_WP_PIN);
-       SD_WP_PORT |= _BV(SD_WP_PIN);
+       }
+#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_PORT |= _BV(SD_CS_PIN);
-       SD_CS_DDR |= _BV(SD_CS_PIN); // Turns on CS pin as output
-
-//     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);
 
-#ifdef SD_PWR_PIN
-       SD_PWR_PORT |= (1 << SD_PWR_PIN); /* Socket power OFF */
+       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 */
 #endif
-       disk_stat |= STA_NOINIT; /* Set 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 */
 {
-#ifdef SD_PWR_PIN
-       return (SD_PWR_PORT & (1 << SD_PWR_PIN)) ? 0 : 1;
+       if (drv == 0) {
+#ifdef SD_PWR_0
+               return SD_PWR_0 == 0;
 #else
-       return 1;
+               return 1;
+#endif /* SD_PWR_PIN */
+       } else {
+#ifdef SD_PWR_1
+               return SD_PWR_1 == 0;
+#else
+               return 1;
 #endif /* SD_PWR_PIN */
+       }
 }
 #endif
 
@@ -286,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;
@@ -295,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;
        }
 
@@ -343,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                                                 */
 /*-----------------------------------------------------------------------*/
@@ -355,56 +447,65 @@ DSTATUS disk_initialize (
 {
        BYTE n, cmd, ty, ocr[4];
 
-       if (drv)
+       if (drv >= MAX_DRV)
                return STA_NOINIT; /* Supports only single drive */
-       if (disk_stat & STA_NODISK)
-               return disk_stat; /* No card in the socket */
+       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;
                }
        }
-       CardType = ty;
-       deselect();
+       socket[drv].CardType = ty;
+       deselect(drv);
 
        if (ty) { /* Initialization succeded */
-               disk_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 disk_stat;
+       return socket[drv].stat;
 }
 
 /*-----------------------------------------------------------------------*/
@@ -412,11 +513,12 @@ 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 */
-       return disk_stat;
+       if (drv >= MAX_DRV)
+               return STA_NOINIT;
+       return socket[drv].stat;
 }
 
 /*-----------------------------------------------------------------------*/
@@ -424,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 (disk_stat & STA_NOINIT) return RES_NOTRDY;
+       if (drv >= MAX_DRV || !count)
+               return RES_PARERR;
+       if (socket[drv].stat & STA_NOINIT)
+               return RES_NOTRDY;
 
-       if (!(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;
 }
@@ -458,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 (disk_stat & STA_NOINIT) return RES_NOTRDY;
-       if (disk_stat & STA_PROTECT) return RES_WRPRT;
-
-       if (!(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 (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;
 }
@@ -507,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 (disk_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;
@@ -535,8 +654,8 @@ DRESULT disk_ioctl (
                break;
 
        case GET_BLOCK_SIZE:    /* Get erase block size in unit of sector (DWORD) */
-               if (CardType & CT_SD2) {        /* SDv2? */
-                       if (send_cmd(ACMD13, 0) == 0) { /* Read SD status */
+               if (socket[drv].CardType & CT_SD2) {    /* SDv2? */
+                       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--)
@@ -546,8 +665,8 @@ DRESULT disk_ioctl (
                                }
                        }
                } else {                                        /* SDv1 or MMCv3 */
-                       if ((send_cmd(CMD9, 0) == 0) && rcvr_datablock(csd, 16)) { /* Read CSD */
-                               if (CardType & CT_SD1) {        /* SDv1 */
+                       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 */
                                        *(DWORD*)buff = ((WORD)((csd[10] & 124) >> 2) + 1) * (((csd[11] & 3) << 3) + ((csd[11] & 224) >> 5) + 1);
@@ -560,24 +679,24 @@ DRESULT disk_ioctl (
        /* Following commands are never used by FatFs module */
 
        case MMC_GET_TYPE:              /* Get card type flags (1 byte) */
-               *ptr = CardType;
+               *ptr = socket[drv].CardType;
                res = RES_OK;
                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;
@@ -585,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;
@@ -593,8 +712,8 @@ DRESULT disk_ioctl (
                break;
 
        case CTRL_POWER_OFF :   /* Power off */
-               power_off();
-               disk_stat |= STA_NOINIT;
+               power_off(drv);
+               socket[drv].stat |= STA_NOINIT;
                res = RES_OK;
                break;
 
@@ -602,7 +721,7 @@ DRESULT disk_ioctl (
                res = RES_PARERR;
        }
 
-       deselect();
+       deselect(drv);
 
        return res;
 }
@@ -617,21 +736,49 @@ void disk_timerproc (void)
 {
        BYTE s;
 
-       s = disk_stat;
-
-#ifdef SD_WP_PIN
-       if (sd_wp())                            /* Write protected */
+       s = socket[0].stat;
+#ifdef SD_WP_0
+       if (SD_WP_0_IN == 0)                    /* Write protected */
                s |= STA_PROTECT;
-       else                                    /* Write enabled */
+       else                                                    /* Write enabled */
                s &= ~STA_PROTECT;
 #endif
 
-#ifdef SD_CD_PIN
-       if (sd_cd())                            /* Card inserted */
+#if defined SD_CD_0
+       if (SD_CD_0_IN == 0)                    /* Card inserted */
                s &= ~STA_NODISK;
-       else                                    /* Socket empty */
+       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 */
 
-       disk_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 */
+               s &= ~STA_PROTECT;
+#endif
+
+#if defined SD_CD_1
+       if (SD_CD_1_IN == 0)                    /* Card inserted */
+               s &= ~STA_NODISK;
+       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[1].stat = s;                     /* Update MMC status */
 }