diff --git a/bootloader/Makefile b/bootloader/Makefile
index c0412ca98234cdcfbaa7aa1c2e6f9ac5c95d3e67..38a6b7d145f536409fa9c02680dad0291ca9f468 100644
--- a/bootloader/Makefile
+++ b/bootloader/Makefile
@@ -67,13 +67,17 @@ CMSIS_ROOT=$(LIBS_DIR)/CMSIS
 # Source files for this test (add path to VPATH below)
 SRCS  = main.c
 SRCS += mscmem.c
+SRCS += ../lib/card10/mx25lba.c
 
 # Where to find source files for this test
-VPATH = .
+VPATH = . 
 
 # Where to find header files for this test
 IPATH = .
 
+IPATH += ../lib/card10
+VPATH += ../lib/card10
+
 # Enable assertion checking for development
 PROJ_CFLAGS+=-DMXC_ASSERT_ENABLE
 
diff --git a/bootloader/mscmem.c b/bootloader/mscmem.c
index 27ff8e6f8f2b992f89c296b9abcd61f0b9acd724..d6daa95da50e270adfb73a4a7a5afd1a0396018e 100644
--- a/bootloader/mscmem.c
+++ b/bootloader/mscmem.c
@@ -48,266 +48,54 @@
 #include "mscmem.h"
 #include <string.h>
 #include <stdio.h>
-#include "mx25.h"
+#include "mx25lba.h"
 
 /***** Definitions *****/
 
-#define SPIXF_DISK      1
-#define RAM_DISK        0
-
-#define LBA_SIZE                    512         /* Size of "logical blocks" in bytes */
-#define LBA_SIZE_SHIFT              9           /* The shift value used to convert between addresses and block numbers */
-
 /***** Global Data *****/
 
 /***** File Scope Variables *****/
 
-static int initialized = 0;
-static int running = 0;
-
-#if SPIXF_DISK
-
-#define MX25_BAUD                   5000000     /* SPI clock rate to communicate with the MX25 */
-
-#define MX25_SECTOR_SIZE            4096        /* Number of bytes in one sector of the MX25 */
-#define MX25_SECTOR_SIZE_SHIFT      12          /* The shift value used to convert between addresses and block numbers */
-#define MX25_NUM_SECTORS            2048        /* Total number of sectors in the MX25 */
-
-#define LBA_PER_SECTOR              (MX25_SECTOR_SIZE >> LBA_SIZE_SHIFT)
-#define INVALID_SECTOR              MX25_NUM_SECTORS    /* Use a sector number past the end of memory to indicate invalid */
-
-/***** File Scope Variables *****/
-static uint32_t sectorNum = INVALID_SECTOR;
-static uint8_t sector[MX25_SECTOR_SIZE];
-static int sectorDirty = 0;
-
-/***** Function Prototypes *****/
-static uint32_t getSectorNum(uint32_t lba);
-static uint32_t getSectorAddr(uint32_t lba);
-static uint32_t getSector(uint32_t num);
-
-/******************************************************************************/
-static uint32_t getSectorNum(uint32_t lba)
-{
-    /* Absolute_address = lba * LBA_SIZE                    */
-    /* Sector_num = Absolute_address / MX25_SECTOR_SIZE     */
-    /* Sector_num = lba * 512 / 4096                        */
-    return lba >> (MX25_SECTOR_SIZE_SHIFT - LBA_SIZE_SHIFT);
-}
-
-/******************************************************************************/
-static uint32_t getSectorAddr(uint32_t lba)
-{
-    /* eight 512 byte blocks in each sector */
-    return (lba & (LBA_PER_SECTOR - 1)) << LBA_SIZE_SHIFT;
-}
-
-/******************************************************************************/
-static uint32_t getSector(uint32_t num)
-{
-    /* New sector requested? */
-    if(sectorNum != num) {
-        /* Is the current sector real? */
-        if(sectorNum != INVALID_SECTOR) {
-            /* Was it written to after it was read from memory? */
-            if(sectorDirty) {
-                /* Erase the old data. */
-                MX25_Erase(sectorNum << MX25_SECTOR_SIZE_SHIFT, MX25_Erase_4K);
-                /* Write the new */
-                MX25_Program_Page(sectorNum << MX25_SECTOR_SIZE_SHIFT, sector, MX25_SECTOR_SIZE, SPIXFC_WIDTH_4);
-                /* Mark data as clean */
-                sectorDirty = 0;
-            }
-        }
-
-        /* Requesting a new valid sector? */
-        if(num != INVALID_SECTOR) {
-            MX25_Read(num << MX25_SECTOR_SIZE_SHIFT, sector, MX25_SECTOR_SIZE, SPIXFC_WIDTH_4);
-            sectorDirty = 0;
-            sectorNum = num;
-        }
-    }
-
-    return 0;
-}
+//static int initialized = 0;
+//static int running = 0;
 
 /******************************************************************************/
 int mscmem_init()
 {
-
-    if(!initialized) {
-        MX25_Init();
-        MX25_Reset();
-        MX25_Quad(1);
-        initialized = 1;
-    }
-    return 0;
+	return mx25_init();
 }
-
 /******************************************************************************/
 uint32_t mscmem_size(void)
 {
-    /* Get number of 512 byte chunks the MX25 contains. */
-    return (MX25_SECTOR_SIZE >> LBA_SIZE_SHIFT) * MX25_NUM_SECTORS;
+	return mx25_size();
 }
 
 /******************************************************************************/
 int mscmem_read(uint32_t lba, uint8_t* buffer)
 {
-    uint32_t addr;
-
-    /* Convert to MX25 sector number. */
-    uint32_t sNum = getSectorNum(lba);
-
-    if(getSector(sNum)) {
-        /* Failed to write/read from MX25 */
-        return 1;
-    }
-
-    /* Get the offset into the current sector */
-    addr = getSectorAddr(lba);
-
-    memcpy(buffer, sector + addr, LBA_SIZE);
-
-    return 0;
+	return mx25_read(lba, buffer);
 }
 
 /******************************************************************************/
 int mscmem_write(uint32_t lba, uint8_t* buffer)
 {
-    uint32_t addr;
-
-    /* Convert to MX25 sector number. */
-    uint32_t sNum = getSectorNum(lba);
-
-    if(getSector(sNum)) {
-        /* Failed to write/read from MX25 */
-        return 1;
-    }
-
-    /* Get the offset into the current sector */
-    addr = getSectorAddr(lba);
-
-    memcpy(sector + addr, buffer, LBA_SIZE);
-    sectorDirty = 1;
-
-    return 0;
+    return mx25_write(lba, buffer);
 }
 
 /******************************************************************************/
 int mscmem_start()
 {
-    /* Turn on the MX25 if it is not already. */
-    if(!initialized) {
-        mscmem_init();
-    }
-
-    /* Check if the initialization succeeded. If it has, start running. */
-    if(initialized) {
-        running = 1;
-    }
-
-    /* Start should return fail (non-zero) if the memory cannot be initialized. */
-    return !initialized;
+    return mx25_start();
 }
 
 /******************************************************************************/
 int mscmem_stop()
 {
-    /* TODO - could shut down XIPF interface here. */
-
-    /* Flush the currently cached sector if necessary. */
-    if(getSector(INVALID_SECTOR)) {
-        return 1;
-    }
-
-    running = 0;
-    return 0;
+    return mx25_stop();
 }
 
 /******************************************************************************/
 int mscmem_ready()
 {
-    return running;
+    return mx25_ready();
 }
-
-#elif RAM_DISK
-
-#define NUM_PAGES               0x100
-static uint8_t mem[NUM_PAGES][LBA_SIZE];
-
-/******************************************************************************/
-int mscmem_init()
-{
-    if(!initialized) {
-        initialized = 1;
-#if (ERASE_MEMORY_ON_INIT)
-        memset(mem, 0, sizeof(mem));
-#endif
-    }
-    return 0;
-}
-
-/******************************************************************************/
-uint32_t mscmem_size(void)
-{
-    return NUM_PAGES;
-}
-
-/******************************************************************************/
-int mscmem_read(uint32_t lba, uint8_t* buffer)
-{
-    if(lba >= NUM_PAGES) {
-        return 1;
-    }
-
-    memcpy(buffer, mem[lba], LBA_SIZE);
-    return 0;
-}
-
-/******************************************************************************/
-int mscmem_write(uint32_t lba, uint8_t* buffer)
-{
-    if(lba >= NUM_PAGES) {
-        return 1;
-    }
-
-    memcpy(mem[lba], buffer, LBA_SIZE);
-    return 0;
-}
-
-/******************************************************************************/
-int mscmem_start()
-{
-    /* Not much to do for this implementation.  The RAM is always ready. */
-    if(!initialized) {
-        mscmem_init();
-    }
-
-    /* Check if the RAM has been initialized. If it has, start running. */
-    if(initialized) {
-        running = 1;
-    }
-
-    /* Start should return fail (non-zero) if the memory cannot be initialized. */
-    return !initialized;
-}
-
-/******************************************************************************/
-int mscmem_stop()
-{
-    /* Nothing to do for this implementation.  All data is written as it is */
-    /*   received so there are no pending writes that need to be flushed.   */
-    running = 0;
-    return 0;
-}
-
-/******************************************************************************/
-int mscmem_ready()
-{
-    return running;
-}
-
-#else
-    #error "You must assign either RAM_DISK or SPIXF_DISK to 1."
-#endif
diff --git a/lib/card10/mx25lba.c b/lib/card10/mx25lba.c
new file mode 100644
index 0000000000000000000000000000000000000000..609d3c6782bae12b4fdad55d9471f86d8bcfb31a
--- /dev/null
+++ b/lib/card10/mx25lba.c
@@ -0,0 +1,236 @@
+/*******************************************************************************
+ * Copyright (C) 2017 Maxim Integrated Products, Inc., All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL MAXIM INTEGRATED BE LIABLE FOR ANY CLAIM, DAMAGES
+ * OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Except as contained in this notice, the name of Maxim Integrated
+ * Products, Inc. shall not be used except as stated in the Maxim Integrated
+ * Products, Inc. Branding Policy.
+ *
+ * The mere transfer of this software does not imply any licenses
+ * of trade secrets, proprietary technology, copyrights, patents,
+ * trademarks, maskwork rights, or any other form of intellectual
+ * property whatsoever. Maxim Integrated Products, Inc. retains all
+ * ownership rights.
+ *
+ * Description: Communications Device Class ACM (Serial Port) over USB
+ * $Id: descriptors.h 31172 2017-10-05 19:05:57Z zach.metzinger $
+ *
+ *******************************************************************************
+ */
+
+/**
+ * @file    mscmem.h
+ * @brief   Memory routines used by the USB Mass Storage Class example.
+ *          See the msc_mem_t structure in msc.h for function details.
+ * @details Functions are provided for using the internal RAM of the
+ *          device or the external SPI flash memory.  Use the SPIXF_DISK
+ *          and RAM_DISK defines to select the desired memory at compile
+ *          time.
+ */
+
+#include "mscmem.h"
+#include <string.h>
+#include <stdio.h>
+#include "mx25.h"
+
+/***** Definitions *****/
+
+#define LBA_SIZE                    512         /* Size of "logical blocks" in bytes */
+#define LBA_SIZE_SHIFT              9           /* The shift value used to convert between addresses and block numbers */
+
+/***** Global Data *****/
+
+/***** File Scope Variables *****/
+
+static int initialized = 0;
+static int running = 0;
+
+#define MX25_BAUD                   5000000     /* SPI clock rate to communicate with the MX25 */
+
+#define MX25_SECTOR_SIZE            4096        /* Number of bytes in one sector of the MX25 */
+#define MX25_SECTOR_SIZE_SHIFT      12          /* The shift value used to convert between addresses and block numbers */
+#define MX25_NUM_SECTORS            2048        /* Total number of sectors in the MX25 */
+
+#define LBA_PER_SECTOR              (MX25_SECTOR_SIZE >> LBA_SIZE_SHIFT)
+#define INVALID_SECTOR              MX25_NUM_SECTORS    /* Use a sector number past the end of memory to indicate invalid */
+
+/***** File Scope Variables *****/
+static uint32_t sectorNum = INVALID_SECTOR;
+static uint8_t sector[MX25_SECTOR_SIZE];
+static int sectorDirty = 0;
+
+/***** Function Prototypes *****/
+static uint32_t getSectorNum(uint32_t lba);
+static uint32_t getSectorAddr(uint32_t lba);
+static uint32_t getSector(uint32_t num);
+
+/******************************************************************************/
+static uint32_t getSectorNum(uint32_t lba)
+{
+    /* Absolute_address = lba * LBA_SIZE                    */
+    /* Sector_num = Absolute_address / MX25_SECTOR_SIZE     */
+    /* Sector_num = lba * 512 / 4096                        */
+    return lba >> (MX25_SECTOR_SIZE_SHIFT - LBA_SIZE_SHIFT);
+}
+
+/******************************************************************************/
+static uint32_t getSectorAddr(uint32_t lba)
+{
+    /* eight 512 byte blocks in each sector */
+    return (lba & (LBA_PER_SECTOR - 1)) << LBA_SIZE_SHIFT;
+}
+
+/******************************************************************************/
+static uint32_t getSector(uint32_t num)
+{
+    /* New sector requested? */
+    if(sectorNum != num) {
+        /* Is the current sector real? */
+        if(sectorNum != INVALID_SECTOR) {
+            /* Was it written to after it was read from memory? */
+            if(sectorDirty) {
+                /* Erase the old data. */
+                MX25_Erase(sectorNum << MX25_SECTOR_SIZE_SHIFT, MX25_Erase_4K);
+                /* Write the new */
+                MX25_Program_Page(sectorNum << MX25_SECTOR_SIZE_SHIFT, sector, MX25_SECTOR_SIZE, SPIXFC_WIDTH_4);
+                /* Mark data as clean */
+                sectorDirty = 0;
+            }
+        }
+
+        /* Requesting a new valid sector? */
+        if(num != INVALID_SECTOR) {
+            MX25_Read(num << MX25_SECTOR_SIZE_SHIFT, sector, MX25_SECTOR_SIZE, SPIXFC_WIDTH_4);
+            sectorDirty = 0;
+            sectorNum = num;
+        }
+    }
+
+    return 0;
+}
+
+/******************************************************************************/
+int mx25_init()
+{
+
+    if(!initialized) {
+        MX25_Init();
+        MX25_Reset();
+        MX25_Quad(1);
+        initialized = 1;
+    }
+    return 0;
+}
+
+/******************************************************************************/
+uint32_t mx25_size(void)
+{
+    /* Get number of 512 byte chunks the MX25 contains. */
+    return (MX25_SECTOR_SIZE >> LBA_SIZE_SHIFT) * MX25_NUM_SECTORS;
+}
+
+/******************************************************************************/
+int mx25_read(uint32_t lba, uint8_t* buffer)
+{
+    uint32_t addr;
+
+    /* Convert to MX25 sector number. */
+    uint32_t sNum = getSectorNum(lba);
+
+    if(getSector(sNum)) {
+        /* Failed to write/read from MX25 */
+        return 1;
+    }
+
+    /* Get the offset into the current sector */
+    addr = getSectorAddr(lba);
+
+    memcpy(buffer, sector + addr, LBA_SIZE);
+
+    return 0;
+}
+
+/******************************************************************************/
+int mx25_write(uint32_t lba, uint8_t* buffer)
+{
+    uint32_t addr;
+
+    /* Convert to MX25 sector number. */
+    uint32_t sNum = getSectorNum(lba);
+
+    if(getSector(sNum)) {
+        /* Failed to write/read from MX25 */
+        return 1;
+    }
+
+    /* Get the offset into the current sector */
+    addr = getSectorAddr(lba);
+
+    memcpy(sector + addr, buffer, LBA_SIZE);
+    sectorDirty = 1;
+
+    return 0;
+}
+
+/******************************************************************************/
+int mx25_start()
+{
+    /* Turn on the MX25 if it is not already. */
+    if(!initialized) {
+        mscmem_init();
+    }
+
+    /* Check if the initialization succeeded. If it has, start running. */
+    if(initialized) {
+        running = 1;
+    }
+
+    /* Start should return fail (non-zero) if the memory cannot be initialized. */
+    return !initialized;
+}
+
+/******************************************************************************/
+int mx25_stop()
+{
+    /* TODO - could shut down XIPF interface here. */
+
+    /* Flush the currently cached sector if necessary. */
+    if(getSector(INVALID_SECTOR)) {
+        return 1;
+    }
+
+    running = 0;
+    return 0;
+}
+/******************************************************************************/
+int mx25_sync()
+{
+    /* Flush the currently cached sector if necessary. */
+    if(getSector(INVALID_SECTOR)) {
+        return 1;
+    }
+    return 0;
+}
+/******************************************************************************/
+int mx25_ready()
+{
+    return running;
+}
+
diff --git a/lib/card10/mx25lba.h b/lib/card10/mx25lba.h
new file mode 100644
index 0000000000000000000000000000000000000000..11c0176d0d022ddab7dc04c1959be80803a10f2b
--- /dev/null
+++ b/lib/card10/mx25lba.h
@@ -0,0 +1,56 @@
+/*******************************************************************************
+ * Copyright (C) 2017 Maxim Integrated Products, Inc., All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL MAXIM INTEGRATED BE LIABLE FOR ANY CLAIM, DAMAGES
+ * OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Except as contained in this notice, the name of Maxim Integrated
+ * Products, Inc. shall not be used except as stated in the Maxim Integrated
+ * Products, Inc. Branding Policy.
+ *
+ * The mere transfer of this software does not imply any licenses
+ * of trade secrets, proprietary technology, copyrights, patents,
+ * trademarks, maskwork rights, or any other form of intellectual
+ * property whatsoever. Maxim Integrated Products, Inc. retains all
+ * ownership rights.
+ *
+ * Description: Communications Device Class ACM (Serial Port) over USB
+ * $Id: descriptors.h 31172 2017-10-05 19:05:57Z zach.metzinger $
+ *
+ *******************************************************************************
+ */
+ 
+/**
+ * @file    mx25.h
+ * @brief   External flash access, adapted from USB MSC example
+ */
+ 
+#ifndef __MX25_H__
+#define __MX25_H__
+
+#include <stdint.h>
+
+int mx25_init(void);
+int mx25_start(void);
+int mx25_stop(void);
+uint32_t mx25_size(void);
+int mx25_read(uint32_t lba, uint8_t* buffer);
+int mx25_write(uint32_t lba, uint8_t* buffer);
+int mx25_ready(void);
+
+#endif  /* __MX25_H__ */
diff --git a/lib/ff13/Source/diskio.c b/lib/ff13/Source/diskio.c
index 662ca2be7155c4c154b7e863ada57b16060d91fa..1c06d6d846c76027074bc1744b1077aef7c41224 100644
--- a/lib/ff13/Source/diskio.c
+++ b/lib/ff13/Source/diskio.c
@@ -10,9 +10,14 @@
 #include "diskio.h"     /* FatFs lower layer API */
 
 /* Definitions of physical drive number for each drive */
-#define DEV_FLASH	0   /* Example: Map MMC/SD card to physical drive 1 */
+#define DEV_FLASH       0   /* Example: Map MMC/SD card to physical drive 1 */
 #define DEV_SD          1   /* Example: Map MMC/SD card to physical drive 1 */
 
+#define SDHC            0
+
+#define SECTOR_SIZE     512UL
+
+#if SDHC
 /* # of times to check for a card, should be > 1 to detect both SD and MMC */
 #define INIT_CARD_RETRIES 10
 
@@ -24,6 +29,15 @@ static DRESULT mmc_get_csd(void *buff);
 
 /* Globals */
 unsigned int init_done = 0;
+#endif
+
+extern int mx25_init(void);
+extern int mx25_start(void);
+extern int mx25_stop(void);
+extern uint32_t mx25_size(void);
+extern int mx25_read(uint32_t lba, uint8_t* buffer);
+extern int mx25_write(uint32_t lba, uint8_t* buffer);
+extern int mx25_sync(void);
 
 /*-----------------------------------------------------------------------*/
 /* Get Drive Status                                                      */
@@ -33,11 +47,23 @@ DSTATUS disk_status (
     BYTE pdrv       /* Physical drive nmuber to identify the drive */
 )
 {
-    DSTATUS status = 0;
 #if 0
-    if (!SDHC_Card_Inserted()) {
-        init_done = 0;
-        status = STA_NOINIT | STA_NODISK;
+    #define STA_NOINIT		0x01	/* Drive not initialized */
+    #define STA_NODISK		0x02	/* No medium in the drive */
+    #define STA_PROTECT		0x04	/* Write protected */
+#endif
+
+    DSTATUS status = 0;
+    if(pdrv == 0) {
+        return STA_NOINIT;
+    }
+
+#if SDHC
+    if(pdrv == 1) {
+        if (!SDHC_Card_Inserted()) {
+            init_done = 0;
+            status = STA_NOINIT | STA_NODISK;
+        }
     }
 #endif
     return status;
@@ -70,13 +96,21 @@ DSTATUS disk_initialize (
     }
 #endif
 
-#if 0
-    if (SDHC_Card_Inserted() && (SDHC_Lib_InitCard(INIT_CARD_RETRIES) == E_NO_ERROR)) {
-        /* Card initialized and ready for work */
-        init_done = 1;
-        status = 0;
-    } else {
-        status = STA_NOINIT;
+    if(pdrv == 0) {
+        if(mx25_start()) {
+            status = RES_OK;
+        }
+    }
+
+#if SDHC
+    if(pdrv == 1) {
+        if (SDHC_Card_Inserted() && (SDHC_Lib_InitCard(INIT_CARD_RETRIES) == E_NO_ERROR)) {
+            /* Card initialized and ready for work */
+            init_done = 1;
+            status = 0;
+        } else {
+            status = STA_NOINIT;
+        }
     }
 #endif
 
@@ -98,11 +132,21 @@ DRESULT disk_read (
 {
     DRESULT status = RES_ERROR;
 
-#if 0
-    if (SDHC_Lib_Read(buff, sector, count, SDHC_LIB_SINGLE_DATA) != E_NO_ERROR) {
-        status = RES_ERROR;
-    } else {
+    if(pdrv == 0) {
+        int sector_offset;
         status = RES_OK;
+        for(sector_offset = 0; sector_offset < count; sector_offset++) {
+            if(mx25_read(sector + sector_offset, (uint8_t*)buff + SECTOR_SIZE * sector_offset) == 1) {
+                status = RES_ERROR;
+                break;
+            }
+        }
+    }
+#if SDHC
+    if(pdrv == 1) {
+        if (SDHC_Lib_Read(buff, sector, count, SDHC_LIB_SINGLE_DATA) == E_NO_ERROR) {
+            status = RES_OK;
+        }
     }
 #endif
 
@@ -124,11 +168,24 @@ DRESULT disk_write (
 {
     DRESULT status = RES_ERROR;
 
-#if 0
-    if (SDHC_Lib_Write(sector, (void *)buff, count, SDHC_LIB_SINGLE_DATA) != E_NO_ERROR) {
-        status = RES_ERROR;
-    } else {
+    if(pdrv == 0) {
+        int sector_offset;
         status = RES_OK;
+        for(sector_offset = 0; sector_offset < count; sector_offset++) {
+            if(mx25_write(sector + sector_offset, (uint8_t*)buff + SECTOR_SIZE * sector_offset) == 1) {
+                status = RES_ERROR;
+                break;
+            }
+        }
+    }
+
+#if SDHC
+    if(pdrv == 1) {
+        if (SDHC_Lib_Write(sector, (void *)buff, count, SDHC_LIB_SINGLE_DATA) != E_NO_ERROR) {
+            status = RES_ERROR;
+        } else {
+            status = RES_OK;
+        }
     }
 #endif
 
@@ -147,30 +204,55 @@ DRESULT disk_ioctl (
     void *buff      /* Buffer to send/receive control data */
 )
 {
-    DRESULT status;
-
-    switch(cmd) {
-        case CTRL_SYNC:
-            /* Mandatory */
-            status = ctrl_sync(buff);
-            break;
-        case GET_SECTOR_COUNT:
-            /* Mandatory */
-            status = get_sector_count(buff);
-            break;
-        case GET_BLOCK_SIZE:
-            /* Mandatory */
-            status = get_block_size(buff);
-            break;
-        case MMC_GET_CSD:
-            /* Optional */
-            status = mmc_get_csd(buff);
-            break;
-        default:
-            status = RES_PARERR;
-            break;
+    DRESULT status = RES_PARERR;
+
+    if(pdrv == 0) {
+        switch(cmd) {
+            case CTRL_SYNC:
+                /* Mandatory */
+                status = mx25_sync();
+                break;
+            case GET_SECTOR_COUNT:
+                /* Mandatory */
+                *((DWORD *)buff) = mx25_size() / SECTOR_SIZE;
+                status = RES_OK;
+                break;
+            case GET_BLOCK_SIZE:
+                /* Mandatory */
+                *((DWORD *)buff) = SECTOR_SIZE;
+                status = RES_OK;
+                break;
+            default:
+                status = RES_PARERR;
+                break;
+        }
     }
 
+#if SDHC
+    if(pdrv == 1) {
+        switch(cmd) {
+            case CTRL_SYNC:
+                /* Mandatory */
+                status = ctrl_sync(buff);
+                break;
+            case GET_SECTOR_COUNT:
+                /* Mandatory */
+                status = get_sector_count(buff);
+                break;
+            case GET_BLOCK_SIZE:
+                /* Mandatory */
+                status = get_block_size(buff);
+                break;
+            case MMC_GET_CSD:
+                /* Optional */
+                status = mmc_get_csd(buff);
+                break;
+            default:
+                status = RES_PARERR;
+                break;
+        }
+    }
+#endif
     return status;
 }
 
@@ -216,6 +298,7 @@ DWORD get_fattime(void) {
     }
 }
 
+#if SDHC
 static DRESULT ctrl_sync(void *buff)
 {
     return RES_OK;
@@ -225,7 +308,6 @@ static DRESULT get_sector_count(void *buff)
 {
     DRESULT status = RES_ERROR;
 
-#if 0
     mxc_sdhc_csd_regs_t csd;
 
     if (init_done) {
@@ -236,7 +318,6 @@ static DRESULT get_sector_count(void *buff)
     } else {
         status = RES_NOTRDY;
     }
-#endif
 
     return status;
 }
@@ -245,7 +326,6 @@ static DRESULT get_block_size(void *buff)
 {
     DRESULT status = RES_ERROR;
 
-#if 0
     mxc_sdhc_csd_regs_t csd;
     if (init_done) {
             if (SDHC_Lib_GetCSD(&csd) == E_NO_ERROR) {
@@ -255,7 +335,6 @@ static DRESULT get_block_size(void *buff)
     } else {
         status = RES_NOTRDY;
     }
-#endif
 
     return status;
 }
@@ -264,7 +343,6 @@ static DRESULT mmc_get_csd(void *buff)
 {
     DRESULT status = RES_ERROR;
 
-#if 0
     if (init_done) {
             if (SDHC_Lib_GetCSD(buff) == E_NO_ERROR) {
             status = RES_OK;
@@ -272,7 +350,7 @@ static DRESULT mmc_get_csd(void *buff)
     } else {
         status = RES_NOTRDY;
     }
-#endif
 
     return status;
 }
+#endif