From 2067619a269f2b4a6e52fdcb1f968e48b952a7d1 Mon Sep 17 00:00:00 2001
From: Marcio Teixeira <marcio@alephobjects.com>
Date: Mon, 2 Jul 2018 09:06:17 -0600
Subject: [PATCH 1/2] Add USB_FLASH_DRIVE_SUPPORT

---
 Marlin/Configuration_adv.h                    |   18 +
 Marlin/src/Marlin.cpp                         |    4 +
 Marlin/src/config/default/Configuration_adv.h |   18 +
 Marlin/src/core/macros.h                      |    1 -
 Marlin/src/inc/MarlinConfigPre.h              |    2 +
 Marlin/src/inc/SanityCheck.h                  |    4 +
 Marlin/src/sd/Sd2Card.cpp                     |    2 +-
 Marlin/src/sd/Sd2Card.h                       |    1 -
 Marlin/src/sd/SdVolume.h                      |   10 +-
 Marlin/src/sd/cardreader.h                    |    4 +-
 Marlin/src/sd/usb_flashdrive/SOURCES.txt      |   48 +
 .../sd/usb_flashdrive/Sd2Card_FlashDrive.cpp  |  159 ++
 .../sd/usb_flashdrive/Sd2Card_FlashDrive.h    |   91 ++
 Marlin/src/sd/usb_flashdrive/lib/Usb.cpp      |  832 +++++++++++
 Marlin/src/sd/usb_flashdrive/lib/Usb.h        |   52 +
 Marlin/src/sd/usb_flashdrive/lib/UsbCore.h    |  314 ++++
 Marlin/src/sd/usb_flashdrive/lib/address.h    |  290 ++++
 .../sd/usb_flashdrive/lib/confdescparser.h    |  217 +++
 Marlin/src/sd/usb_flashdrive/lib/hexdump.h    |   69 +
 Marlin/src/sd/usb_flashdrive/lib/macros.h     |   89 ++
 .../src/sd/usb_flashdrive/lib/masstorage.cpp  | 1282 +++++++++++++++++
 Marlin/src/sd/usb_flashdrive/lib/masstorage.h |  578 ++++++++
 Marlin/src/sd/usb_flashdrive/lib/max3421e.h   |  235 +++
 Marlin/src/sd/usb_flashdrive/lib/message.cpp  |  130 ++
 Marlin/src/sd/usb_flashdrive/lib/message.h    |   85 ++
 .../src/sd/usb_flashdrive/lib/parsetools.cpp  |   81 ++
 Marlin/src/sd/usb_flashdrive/lib/parsetools.h |  147 ++
 Marlin/src/sd/usb_flashdrive/lib/printhex.h   |   91 ++
 Marlin/src/sd/usb_flashdrive/lib/settings.h   |  236 +++
 Marlin/src/sd/usb_flashdrive/lib/usb_ch9.h    |  173 +++
 .../usb-2.0-host-library-changes.patch        |  187 +++
 Marlin/src/sd/usb_flashdrive/usb_host.cpp     |  213 +++
 Marlin/src/sd/usb_flashdrive/usb_host.h       |   61 +
 buildroot/share/tests/megaatmega2560_tests    |    2 +-
 34 files changed, 5718 insertions(+), 8 deletions(-)
 create mode 100644 Marlin/src/sd/usb_flashdrive/SOURCES.txt
 create mode 100644 Marlin/src/sd/usb_flashdrive/Sd2Card_FlashDrive.cpp
 create mode 100644 Marlin/src/sd/usb_flashdrive/Sd2Card_FlashDrive.h
 create mode 100644 Marlin/src/sd/usb_flashdrive/lib/Usb.cpp
 create mode 100644 Marlin/src/sd/usb_flashdrive/lib/Usb.h
 create mode 100644 Marlin/src/sd/usb_flashdrive/lib/UsbCore.h
 create mode 100644 Marlin/src/sd/usb_flashdrive/lib/address.h
 create mode 100644 Marlin/src/sd/usb_flashdrive/lib/confdescparser.h
 create mode 100644 Marlin/src/sd/usb_flashdrive/lib/hexdump.h
 create mode 100644 Marlin/src/sd/usb_flashdrive/lib/macros.h
 create mode 100644 Marlin/src/sd/usb_flashdrive/lib/masstorage.cpp
 create mode 100644 Marlin/src/sd/usb_flashdrive/lib/masstorage.h
 create mode 100644 Marlin/src/sd/usb_flashdrive/lib/max3421e.h
 create mode 100644 Marlin/src/sd/usb_flashdrive/lib/message.cpp
 create mode 100644 Marlin/src/sd/usb_flashdrive/lib/message.h
 create mode 100644 Marlin/src/sd/usb_flashdrive/lib/parsetools.cpp
 create mode 100644 Marlin/src/sd/usb_flashdrive/lib/parsetools.h
 create mode 100644 Marlin/src/sd/usb_flashdrive/lib/printhex.h
 create mode 100644 Marlin/src/sd/usb_flashdrive/lib/settings.h
 create mode 100644 Marlin/src/sd/usb_flashdrive/lib/usb_ch9.h
 create mode 100644 Marlin/src/sd/usb_flashdrive/usb-2.0-host-library-changes.patch
 create mode 100644 Marlin/src/sd/usb_flashdrive/usb_host.cpp
 create mode 100644 Marlin/src/sd/usb_flashdrive/usb_host.h

diff --git a/Marlin/Configuration_adv.h b/Marlin/Configuration_adv.h
index 5a42882b3f..88a3df2d53 100644
--- a/Marlin/Configuration_adv.h
+++ b/Marlin/Configuration_adv.h
@@ -683,6 +683,24 @@
    */
   //#define AUTO_REPORT_SD_STATUS
 
+  /**
+   * Support for USB thumb drives using an Arduino USB Host Shield or
+   * equivalent MAX3421E breakout board. The USB thumb drive will appear
+   * to Marlin as an SD card.
+   *
+   * The MAX3421E must be assigned the same pins as the SD card reader, with
+   * the following pin mapping:
+   *
+   *    SCLK, MOSI, MISO --> SCLK, MOSI, MISO
+   *    INT              --> SD_DETECT_PIN
+   *    SS               --> SDSS
+   */
+  //#define USB_FLASH_DRIVE_SUPPORT
+  #if ENABLED(USB_FLASH_DRIVE_SUPPORT)
+    #define USB_CS_PIN         SDSS
+    #define USB_INTR_PIN       SD_DETECT_PIN
+  #endif
+
 #endif // SDSUPPORT
 
 /**
diff --git a/Marlin/src/Marlin.cpp b/Marlin/src/Marlin.cpp
index 931717ff16..02d34951b4 100644
--- a/Marlin/src/Marlin.cpp
+++ b/Marlin/src/Marlin.cpp
@@ -593,6 +593,10 @@ void idle(
       #endif
     }
   #endif
+
+  #if ENABLED(USB_FLASH_DRIVE_SUPPORT)
+    Sd2Card::idle();
+  #endif
 }
 
 /**
diff --git a/Marlin/src/config/default/Configuration_adv.h b/Marlin/src/config/default/Configuration_adv.h
index 5a42882b3f..88a3df2d53 100755
--- a/Marlin/src/config/default/Configuration_adv.h
+++ b/Marlin/src/config/default/Configuration_adv.h
@@ -683,6 +683,24 @@
    */
   //#define AUTO_REPORT_SD_STATUS
 
+  /**
+   * Support for USB thumb drives using an Arduino USB Host Shield or
+   * equivalent MAX3421E breakout board. The USB thumb drive will appear
+   * to Marlin as an SD card.
+   *
+   * The MAX3421E must be assigned the same pins as the SD card reader, with
+   * the following pin mapping:
+   *
+   *    SCLK, MOSI, MISO --> SCLK, MOSI, MISO
+   *    INT              --> SD_DETECT_PIN
+   *    SS               --> SDSS
+   */
+  //#define USB_FLASH_DRIVE_SUPPORT
+  #if ENABLED(USB_FLASH_DRIVE_SUPPORT)
+    #define USB_CS_PIN         SDSS
+    #define USB_INTR_PIN       SD_DETECT_PIN
+  #endif
+
 #endif // SDSUPPORT
 
 /**
diff --git a/Marlin/src/core/macros.h b/Marlin/src/core/macros.h
index df21b0519f..3f4e99ebb3 100644
--- a/Marlin/src/core/macros.h
+++ b/Marlin/src/core/macros.h
@@ -19,7 +19,6 @@
  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  *
  */
-
 #pragma once
 
 #include "minmax.h"
diff --git a/Marlin/src/inc/MarlinConfigPre.h b/Marlin/src/inc/MarlinConfigPre.h
index 9751df43e2..ae36a1efcd 100644
--- a/Marlin/src/inc/MarlinConfigPre.h
+++ b/Marlin/src/inc/MarlinConfigPre.h
@@ -21,6 +21,8 @@
  */
 #pragma once
 
+#define __MARLIN_FIRMWARE__
+
 //
 // Prefix header to acquire configurations
 //
diff --git a/Marlin/src/inc/SanityCheck.h b/Marlin/src/inc/SanityCheck.h
index b0d6758dc4..1c2ae52fae 100644
--- a/Marlin/src/inc/SanityCheck.h
+++ b/Marlin/src/inc/SanityCheck.h
@@ -1830,4 +1830,8 @@ static_assert(COUNT(sanity_arr_3) <= XYZE_N, "DEFAULT_MAX_ACCELERATION has too m
   #error "PRINTCOUNTER requires EEPROM_SETTINGS. Please update your Configuration."
 #endif
 
+#if ENABLED(USB_FLASH_DRIVE_SUPPORT) && !(PIN_EXISTS(USB_CS) && PIN_EXISTS(USB_INTR))
+  #error "USB_CS_PIN and USB_INTR_PIN are required for USB_FLASH_DRIVE_SUPPORT."
+#endif
+
 #endif // _SANITYCHECK_H_
diff --git a/Marlin/src/sd/Sd2Card.cpp b/Marlin/src/sd/Sd2Card.cpp
index b52e4fa16d..153611d7ad 100644
--- a/Marlin/src/sd/Sd2Card.cpp
+++ b/Marlin/src/sd/Sd2Card.cpp
@@ -30,7 +30,7 @@
 
 #include "../inc/MarlinConfig.h"
 
-#if ENABLED(SDSUPPORT)
+#if ENABLED(SDSUPPORT) && DISABLED(USB_FLASH_DRIVE_SUPPORT)
 
 /* Enable FAST CRC computations - You can trade speed for FLASH space if
  * needed by disabling the following define */
diff --git a/Marlin/src/sd/Sd2Card.h b/Marlin/src/sd/Sd2Card.h
index 0df9c0ba64..2d9ebf33e3 100644
--- a/Marlin/src/sd/Sd2Card.h
+++ b/Marlin/src/sd/Sd2Card.h
@@ -34,7 +34,6 @@
 #ifndef _SD2CARD_H_
 #define _SD2CARD_H_
 
-
 #include "SdFatConfig.h"
 #include "SdInfo.h"
 
diff --git a/Marlin/src/sd/SdVolume.h b/Marlin/src/sd/SdVolume.h
index d67d98f8be..697d0b4933 100644
--- a/Marlin/src/sd/SdVolume.h
+++ b/Marlin/src/sd/SdVolume.h
@@ -34,10 +34,14 @@
 #ifndef _SDVOLUME_H_
 #define _SDVOLUME_H_
 
-#include "SdFatConfig.h"
-#include "Sd2Card.h"
-#include "SdFatStructs.h"
+#if ENABLED(USB_FLASH_DRIVE_SUPPORT)
+  #include "usb_flashdrive/Sd2Card_FlashDrive.h"
+#else
+  #include "Sd2Card.h"
+#endif
 
+#include "SdFatConfig.h"
+#include "SdFatStructs.h"
 #include <stdint.h>
 
 //==============================================================================
diff --git a/Marlin/src/sd/cardreader.h b/Marlin/src/sd/cardreader.h
index 1e2f685fcf..b975d053f4 100644
--- a/Marlin/src/sd/cardreader.h
+++ b/Marlin/src/sd/cardreader.h
@@ -243,7 +243,9 @@ private:
   #endif
 };
 
-#if PIN_EXISTS(SD_DETECT)
+#if ENABLED(USB_FLASH_DRIVE_SUPPORT)
+  #define IS_SD_INSERTED Sd2Card::isInserted()
+#elif PIN_EXISTS(SD_DETECT)
   #if ENABLED(SD_DETECT_INVERTED)
     #define IS_SD_INSERTED (READ(SD_DETECT_PIN) == HIGH)
   #else
diff --git a/Marlin/src/sd/usb_flashdrive/SOURCES.txt b/Marlin/src/sd/usb_flashdrive/SOURCES.txt
new file mode 100644
index 0000000000..66f170a203
--- /dev/null
+++ b/Marlin/src/sd/usb_flashdrive/SOURCES.txt
@@ -0,0 +1,48 @@
+
+==== SUMMARY ====
+
+Source Path:                           Repository:                           License:
+------------                           -----------                           --------
+usb_flashdrive/lib                     github.com/felis/USB_Host_Shield_2.0  GPLv2 or later
+usb_flashdrive/lib/masstorage.cpp [1]  github.com/greiman/UsbFat             MIT
+usb_flashdrive/lib/settings.h [1]      github.com/greiman/UsbFat             MIT
+
+[1] Changes related to SKIP_WRITE_PROTECT and DELAY only
+
+
+==== USB HOST SHIELD 2.0 LIBRARY ====
+
+The lib/ folder contains a subset of the files from the USB Host Shield 2.0
+library:
+
+  https://github.com/felis/USB_Host_Shield_2.0
+
+While the original library was released under the GPLv2 and could not be
+commingled with Marlin, the developers have graciously re-licenced the
+files needed for Marlin as "GPLv2 or later", as documented in this thread.
+
+  https://github.com/felis/USB_Host_Shield_2.0/issues/364
+
+Small modifications have been made to the source. Please search for
+USB_FLASH_DRIVE_SUPPORT or look at the patch file to see what was changed.
+
+
+==== PERFORMANCE ENHANCEMENTS FOR USB DRIVES ====
+
+There are also some small performance enhancements from Bill Greiman, regarding
+SKIP_WRITE_PROTECT and DELAY. These changes came from the following repo:
+
+   https://github.com/greiman/UsbFat
+
+While the original library was released under the GPLv2 and could not be
+commingled with Marlin, the developer has graciously re-licenced his changes
+under the "MIT" license, as documented here:
+
+   https://github.com/greiman/UsbFat/issues/8
+
+==== MARLIN INTEGRATION WORK ====
+
+All additional work done to integrate USB into Marlin was performed by AlephObjects, Inc.
+and is licensed under the GPLv3.
+
+-- marcio@alephobjects.com
diff --git a/Marlin/src/sd/usb_flashdrive/Sd2Card_FlashDrive.cpp b/Marlin/src/sd/usb_flashdrive/Sd2Card_FlashDrive.cpp
new file mode 100644
index 0000000000..369b3d38d4
--- /dev/null
+++ b/Marlin/src/sd/usb_flashdrive/Sd2Card_FlashDrive.cpp
@@ -0,0 +1,159 @@
+/**
+ * Marlin 3D Printer Firmware
+ * Copyright (C) 2016 MarlinFirmware [https://github.com/MarlinFirmware/Marlin]
+ *
+ * Based on Sprinter and grbl.
+ * Copyright (C) 2011 Camiel Gubbels / Erik van der Zalm
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include "../../inc/MarlinConfigPre.h"
+
+#if ENABLED(USB_FLASH_DRIVE_SUPPORT)
+
+#include "lib/Usb.h"
+#include "lib/masstorage.h"
+
+#include "Sd2Card_FlashDrive.h"
+
+#include <SPI.h>
+
+#include "../../core/serial.h"
+
+USB usb;
+BulkOnly bulk(&usb);
+
+Sd2Card::state_t Sd2Card::state;
+uint32_t         Sd2Card::block;
+
+bool Sd2Card::usbHostReady() {
+  return state == USB_HOST_INITIALIZED;
+}
+
+bool Sd2Card::isInserted() {
+  return usb.getUsbTaskState() == USB_STATE_RUNNING;
+}
+
+// Marlin calls this whenever an SD card is detected, so this method
+// should not be used to initialize the USB host library
+bool Sd2Card::init(uint8_t sckRateID, uint8_t chipSelectPin) {
+  if (!usbHostReady()) return false;
+
+  if (!bulk.LUNIsGood(0)) {
+    SERIAL_ECHOLNPGM("LUN zero is not good\n");
+    return false;
+  }
+
+  SERIAL_ECHOLNPAIR("LUN Capacity: ",bulk.GetCapacity(0));
+
+  const uint32_t sectorSize = bulk.GetSectorSize(0);
+  if (sectorSize != 512) {
+    SERIAL_ECHOLNPAIR("Expecting sector size of 512, got: ",sectorSize);
+    return false;
+  }
+
+  return true;
+}
+
+void Sd2Card::idle() {
+  static uint32_t next_retry;
+
+  switch (state) {
+    case USB_HOST_DELAY_INIT:
+      next_retry = millis() + 10000;
+      state = USB_HOST_WAITING;
+      break;
+    case USB_HOST_WAITING:
+      if (millis() > next_retry) {
+        next_retry = millis() + 10000;
+        state = USB_HOST_UNINITIALIZED;
+      }
+      break;
+    case USB_HOST_UNINITIALIZED:
+      SERIAL_ECHOLNPGM("Starting USB host");
+      if (!usb.start()) {
+        SERIAL_ECHOLNPGM("USB host failed to start. Will retry in 10 seconds.");
+        state = USB_HOST_DELAY_INIT;
+      }
+      else {
+        SERIAL_ECHOLNPGM("USB host initialized");
+        state = USB_HOST_INITIALIZED;
+      }
+      break;
+    case USB_HOST_INITIALIZED:
+      const uint8_t lastUsbTaskState = usb.getUsbTaskState();
+      usb.Task();
+      const uint8_t newUsbTaskState  = usb.getUsbTaskState();
+
+      if (lastUsbTaskState == USB_STATE_RUNNING && newUsbTaskState != USB_STATE_RUNNING) {
+        // the user pulled the flash drive. Make sure the bulk storage driver releases the address
+        SERIAL_ECHOLNPGM("Drive removed\n");
+        //bulk.Release();
+      }
+      if (lastUsbTaskState != USB_STATE_RUNNING && newUsbTaskState == USB_STATE_RUNNING)
+        SERIAL_ECHOLNPGM("Drive inserted\n");
+      break;
+  }
+}
+
+uint32_t Sd2Card::cardSize() {
+  if (!usbHostReady()) return 0;
+  return bulk.GetCapacity(0);
+}
+
+bool Sd2Card::readData(uint8_t* dst) {
+  return readBlock(block++, dst);
+}
+
+bool Sd2Card::readStart(uint32_t blockNumber) {
+  block = blockNumber;
+  return true;
+}
+
+bool Sd2Card::readStop() {
+  return usbHostReady();
+}
+
+bool Sd2Card::readBlock(uint32_t block, uint8_t* dst) {
+  if (!usbHostReady()) {
+    SERIAL_ECHOLNPGM("Read from uninitalized USB host");
+    return false;
+  }
+  return bulk.Read(0, block, 512, 1, dst) == 0;
+}
+
+bool Sd2Card::writeData(const uint8_t* src) {
+  return writeBlock(block++, src);
+}
+
+bool Sd2Card::writeStart(uint32_t blockNumber, uint32_t eraseCount) {
+  block = blockNumber;
+  return true;
+}
+
+bool Sd2Card::writeStop() {
+  return usbHostReady();
+}
+
+bool Sd2Card::writeBlock(uint32_t blockNumber, const uint8_t* src) {
+  if (!usbHostReady()) {
+    SERIAL_ECHOLNPGM("Write to uninitalized USB host");
+    return false;
+  }
+  return bulk.Write(0, blockNumber, 512, 1, src) == 0;
+}
+
+#endif // USB_FLASH_DRIVE_SUPPORT
diff --git a/Marlin/src/sd/usb_flashdrive/Sd2Card_FlashDrive.h b/Marlin/src/sd/usb_flashdrive/Sd2Card_FlashDrive.h
new file mode 100644
index 0000000000..c364063156
--- /dev/null
+++ b/Marlin/src/sd/usb_flashdrive/Sd2Card_FlashDrive.h
@@ -0,0 +1,91 @@
+/**
+ * Marlin 3D Printer Firmware
+ * Copyright (C) 2016 MarlinFirmware [https://github.com/MarlinFirmware/Marlin]
+ *
+ * Based on Sprinter and grbl.
+ * Copyright (C) 2011 Camiel Gubbels / Erik van der Zalm
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+/**
+ * \file
+ * \brief Sd2Card class for V2 SD/SDHC cards
+ */
+
+#ifndef _SD2CARD_FLASHDRIVE_H_
+#define _SD2CARD_FLASHDRIVE_H_
+
+#include "../SdFatConfig.h"
+#include "../SdInfo.h"
+
+/**
+ * define SOFTWARE_SPI to use bit-bang SPI
+ */
+#if MEGA_SOFT_SPI || USE_SOFTWARE_SPI
+  #define SOFTWARE_SPI
+#endif
+
+// SPI pin definitions - do not edit here - change in SdFatConfig.h
+#if DISABLED(SOFTWARE_SPI)
+  // hardware pin defs
+  #define SD_CHIP_SELECT_PIN  SS_PIN            // The default chip select pin for the SD card is SS.
+  // The following three pins must not be redefined for hardware SPI.
+  #define SPI_MOSI_PIN        MOSI_PIN          // SPI Master Out Slave In pin
+  #define SPI_MISO_PIN        MISO_PIN          // SPI Master In Slave Out pin
+  #define SPI_SCK_PIN         SCK_PIN           // SPI Clock pin
+#else  // SOFTWARE_SPI
+  #define SD_CHIP_SELECT_PIN  SOFT_SPI_CS_PIN   // SPI chip select pin
+  #define SPI_MOSI_PIN        SOFT_SPI_MOSI_PIN // SPI Master Out Slave In pin
+  #define SPI_MISO_PIN        SOFT_SPI_MISO_PIN // SPI Master In Slave Out pin
+  #define SPI_SCK_PIN         SOFT_SPI_SCK_PIN  // SPI Clock pin
+#endif // SOFTWARE_SPI
+
+class Sd2Card {
+  private:
+
+    typedef enum {
+      USB_HOST_DELAY_INIT,
+      USB_HOST_WAITING,
+      USB_HOST_UNINITIALIZED,
+      USB_HOST_INITIALIZED
+    } state_t;
+
+    static state_t  state;
+    static uint32_t block;
+
+    static bool usbHostReady();
+
+  public:
+    static void idle();
+
+    static bool isInserted();
+
+    uint32_t cardSize();
+
+    bool init(uint8_t sckRateID = 0, uint8_t chipSelectPin = SD_CHIP_SELECT_PIN);
+
+    bool readData(uint8_t* dst);
+    bool readStart(uint32_t blockNumber);
+    bool readStop();
+    bool readBlock(uint32_t block, uint8_t* dst);
+
+    bool writeData(const uint8_t* src);
+    bool writeStart(uint32_t blockNumber, uint32_t eraseCount);
+    bool writeStop();
+    bool writeBlock(uint32_t blockNumber, const uint8_t* src);
+};
+
+#endif  // _SD2CARD_FLASHDRIVE_H_
diff --git a/Marlin/src/sd/usb_flashdrive/lib/Usb.cpp b/Marlin/src/sd/usb_flashdrive/lib/Usb.cpp
new file mode 100644
index 0000000000..55774fb045
--- /dev/null
+++ b/Marlin/src/sd/usb_flashdrive/lib/Usb.cpp
@@ -0,0 +1,832 @@
+/* Copyright (C) 2011 Circuits At Home, LTD. All rights reserved.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+Contact information
+-------------------
+
+Circuits At Home, LTD
+Web      :  http://www.circuitsathome.com
+e-mail   :  support@circuitsathome.com
+ */
+/* USB functions */
+
+#include "../../../inc/MarlinConfigPre.h"
+
+#if ENABLED(USB_FLASH_DRIVE_SUPPORT)
+
+#include "Usb.h"
+
+static uint8_t usb_error = 0;
+static uint8_t usb_task_state;
+
+/* constructor */
+USB::USB() : bmHubPre(0) {
+        usb_task_state = USB_DETACHED_SUBSTATE_INITIALIZE; //set up state machine
+        init();
+}
+
+/* Initialize data structures */
+void USB::init() {
+        //devConfigIndex = 0;
+        bmHubPre = 0;
+}
+
+uint8_t USB::getUsbTaskState(void) {
+        return ( usb_task_state);
+}
+
+void USB::setUsbTaskState(uint8_t state) {
+        usb_task_state = state;
+}
+
+EpInfo* USB::getEpInfoEntry(uint8_t addr, uint8_t ep) {
+        UsbDevice *p = addrPool.GetUsbDevicePtr(addr);
+
+        if(!p || !p->epinfo)
+                return NULL;
+
+        EpInfo *pep = p->epinfo;
+
+        for(uint8_t i = 0; i < p->epcount; i++) {
+                if((pep)->epAddr == ep)
+                        return pep;
+
+                pep++;
+        }
+        return NULL;
+}
+
+/* set device table entry */
+
+/* each device is different and has different number of endpoints. This function plugs endpoint record structure, defined in application, to devtable */
+uint8_t USB::setEpInfoEntry(uint8_t addr, uint8_t epcount, EpInfo* eprecord_ptr) {
+        if(!eprecord_ptr)
+                return USB_ERROR_INVALID_ARGUMENT;
+
+        UsbDevice *p = addrPool.GetUsbDevicePtr(addr);
+
+        if(!p)
+                return USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL;
+
+        p->address.devAddress = addr;
+        p->epinfo = eprecord_ptr;
+        p->epcount = epcount;
+
+        return 0;
+}
+
+uint8_t USB::SetAddress(uint8_t addr, uint8_t ep, EpInfo **ppep, uint16_t *nak_limit) {
+        UsbDevice *p = addrPool.GetUsbDevicePtr(addr);
+
+        if(!p)
+                return USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL;
+
+        if(!p->epinfo)
+                return USB_ERROR_EPINFO_IS_NULL;
+
+        *ppep = getEpInfoEntry(addr, ep);
+
+        if(!*ppep)
+                return USB_ERROR_EP_NOT_FOUND_IN_TBL;
+
+        *nak_limit = (0x0001UL << (((*ppep)->bmNakPower > USB_NAK_MAX_POWER) ? USB_NAK_MAX_POWER : (*ppep)->bmNakPower));
+        (*nak_limit)--;
+        /*
+          USBTRACE2("\r\nAddress: ", addr);
+          USBTRACE2(" EP: ", ep);
+          USBTRACE2(" NAK Power: ",(*ppep)->bmNakPower);
+          USBTRACE2(" NAK Limit: ", nak_limit);
+          USBTRACE("\r\n");
+         */
+        regWr(rPERADDR, addr); //set peripheral address
+
+        uint8_t mode = regRd(rMODE);
+
+        //Serial.print("\r\nMode: ");
+        //Serial.println( mode, HEX);
+        //Serial.print("\r\nLS: ");
+        //Serial.println(p->lowspeed, HEX);
+
+
+
+        // Set bmLOWSPEED and bmHUBPRE in case of low-speed device, reset them otherwise
+        regWr(rMODE, (p->lowspeed) ? mode | bmLOWSPEED | bmHubPre : mode & ~(bmHUBPRE | bmLOWSPEED));
+
+        return 0;
+}
+
+/* Control transfer. Sets address, endpoint, fills control packet with necessary data, dispatches control packet, and initiates bulk IN transfer,   */
+/* depending on request. Actual requests are defined as inlines                                                                                      */
+/* return codes:                */
+/* 00       =   success         */
+
+/* 01-0f    =   non-zero HRSLT  */
+uint8_t USB::ctrlReq(uint8_t addr, uint8_t ep, uint8_t bmReqType, uint8_t bRequest, uint8_t wValLo, uint8_t wValHi,
+        uint16_t wInd, uint16_t total, uint16_t nbytes, uint8_t* dataptr, USBReadParser *p) {
+        bool direction = false; //request direction, IN or OUT
+        uint8_t rcode;
+        SETUP_PKT setup_pkt;
+
+        EpInfo *pep = NULL;
+        uint16_t nak_limit = 0;
+
+        rcode = SetAddress(addr, ep, &pep, &nak_limit);
+
+        if(rcode)
+                return rcode;
+
+        direction = ((bmReqType & 0x80) > 0);
+
+        /* fill in setup packet */
+        setup_pkt.ReqType_u.bmRequestType = bmReqType;
+        setup_pkt.bRequest = bRequest;
+        setup_pkt.wVal_u.wValueLo = wValLo;
+        setup_pkt.wVal_u.wValueHi = wValHi;
+        setup_pkt.wIndex = wInd;
+        setup_pkt.wLength = total;
+
+        bytesWr(rSUDFIFO, 8, (uint8_t*) & setup_pkt); //transfer to setup packet FIFO
+
+        rcode = dispatchPkt(tokSETUP, ep, nak_limit); //dispatch packet
+
+        if(rcode) //return HRSLT if not zero
+                return ( rcode);
+
+        if(dataptr != NULL) //data stage, if present
+        {
+                if(direction) //IN transfer
+                {
+                        uint16_t left = total;
+
+                        pep->bmRcvToggle = 1; //bmRCVTOG1;
+
+                        while(left) {
+                                // Bytes read into buffer
+                                uint16_t read = nbytes;
+                                //uint16_t read = (left<nbytes) ? left : nbytes;
+
+                                rcode = InTransfer(pep, nak_limit, &read, dataptr);
+                                if(rcode == hrTOGERR) {
+                                        // yes, we flip it wrong here so that next time it is actually correct!
+                                        pep->bmRcvToggle = (regRd(rHRSL) & bmSNDTOGRD) ? 0 : 1;
+                                        continue;
+                                }
+
+                                if(rcode)
+                                        return rcode;
+
+                                // Invoke callback function if inTransfer completed successfully and callback function pointer is specified
+                                if(!rcode && p)
+                                        ((USBReadParser*)p)->Parse(read, dataptr, total - left);
+
+                                left -= read;
+
+                                if(read < nbytes)
+                                        break;
+                        }
+                } else //OUT transfer
+                {
+                        pep->bmSndToggle = 1; //bmSNDTOG1;
+                        rcode = OutTransfer(pep, nak_limit, nbytes, dataptr);
+                }
+                if(rcode) //return error
+                        return ( rcode);
+        }
+        // Status stage
+        return dispatchPkt((direction) ? tokOUTHS : tokINHS, ep, nak_limit); //GET if direction
+}
+
+/* IN transfer to arbitrary endpoint. Assumes PERADDR is set. Handles multiple packets if necessary. Transfers 'nbytes' bytes. */
+/* Keep sending INs and writes data to memory area pointed by 'data'                                                           */
+
+/* rcode 0 if no errors. rcode 01-0f is relayed from dispatchPkt(). Rcode f0 means RCVDAVIRQ error,
+            fe USB xfer timeout */
+uint8_t USB::inTransfer(uint8_t addr, uint8_t ep, uint16_t *nbytesptr, uint8_t* data, uint8_t bInterval /*= 0*/) {
+        EpInfo *pep = NULL;
+        uint16_t nak_limit = 0;
+
+        uint8_t rcode = SetAddress(addr, ep, &pep, &nak_limit);
+
+        if(rcode) {
+                USBTRACE3("(USB::InTransfer) SetAddress Failed ", rcode, 0x81);
+                USBTRACE3("(USB::InTransfer) addr requested ", addr, 0x81);
+                USBTRACE3("(USB::InTransfer) ep requested ", ep, 0x81);
+                return rcode;
+        }
+        return InTransfer(pep, nak_limit, nbytesptr, data, bInterval);
+}
+
+uint8_t USB::InTransfer(EpInfo *pep, uint16_t nak_limit, uint16_t *nbytesptr, uint8_t* data, uint8_t bInterval /*= 0*/) {
+        uint8_t rcode = 0;
+        uint8_t pktsize;
+
+        uint16_t nbytes = *nbytesptr;
+        //printf("Requesting %i bytes ", nbytes);
+        uint8_t maxpktsize = pep->maxPktSize;
+
+        *nbytesptr = 0;
+        regWr(rHCTL, (pep->bmRcvToggle) ? bmRCVTOG1 : bmRCVTOG0); //set toggle value
+
+        // use a 'break' to exit this loop
+        while(1) {
+                rcode = dispatchPkt(tokIN, pep->epAddr, nak_limit); //IN packet to EP-'endpoint'. Function takes care of NAKS.
+                if(rcode == hrTOGERR) {
+                        // yes, we flip it wrong here so that next time it is actually correct!
+                        pep->bmRcvToggle = (regRd(rHRSL) & bmRCVTOGRD) ? 0 : 1;
+                        regWr(rHCTL, (pep->bmRcvToggle) ? bmRCVTOG1 : bmRCVTOG0); //set toggle value
+                        continue;
+                }
+                if(rcode) {
+                        //printf(">>>>>>>> Problem! dispatchPkt %2.2x\r\n", rcode);
+                        break; //should be 0, indicating ACK. Else return error code.
+                }
+                /* check for RCVDAVIRQ and generate error if not present */
+                /* the only case when absence of RCVDAVIRQ makes sense is when toggle error occurred. Need to add handling for that */
+                if((regRd(rHIRQ) & bmRCVDAVIRQ) == 0) {
+                        //printf(">>>>>>>> Problem! NO RCVDAVIRQ!\r\n");
+                        rcode = 0xf0; //receive error
+                        break;
+                }
+                pktsize = regRd(rRCVBC); //number of received bytes
+                //printf("Got %i bytes \r\n", pktsize);
+                // This would be OK, but...
+                //assert(pktsize <= nbytes);
+                if(pktsize > nbytes) {
+                        // This can happen. Use of assert on Arduino locks up the Arduino.
+                        // So I will trim the value, and hope for the best.
+                        //printf(">>>>>>>> Problem! Wanted %i bytes but got %i.\r\n", nbytes, pktsize);
+                        pktsize = nbytes;
+                }
+
+                int16_t mem_left = (int16_t)nbytes - *((int16_t*)nbytesptr);
+
+                if(mem_left < 0)
+                        mem_left = 0;
+
+                data = bytesRd(rRCVFIFO, ((pktsize > mem_left) ? mem_left : pktsize), data);
+
+                regWr(rHIRQ, bmRCVDAVIRQ); // Clear the IRQ & free the buffer
+                *nbytesptr += pktsize; // add this packet's byte count to total transfer length
+
+                /* The transfer is complete under two conditions:           */
+                /* 1. The device sent a short packet (L.T. maxPacketSize)   */
+                /* 2. 'nbytes' have been transferred.                       */
+                if((pktsize < maxpktsize) || (*nbytesptr >= nbytes)) // have we transferred 'nbytes' bytes?
+                {
+                        // Save toggle value
+                        pep->bmRcvToggle = ((regRd(rHRSL) & bmRCVTOGRD)) ? 1 : 0;
+                        //printf("\r\n");
+                        rcode = 0;
+                        break;
+                } else if(bInterval > 0)
+                        delay(bInterval); // Delay according to polling interval
+        } //while( 1 )
+        return ( rcode);
+}
+
+/* OUT transfer to arbitrary endpoint. Handles multiple packets if necessary. Transfers 'nbytes' bytes. */
+/* Handles NAK bug per Maxim Application Note 4000 for single buffer transfer   */
+
+/* rcode 0 if no errors. rcode 01-0f is relayed from HRSL                       */
+uint8_t USB::outTransfer(uint8_t addr, uint8_t ep, uint16_t nbytes, uint8_t* data) {
+        EpInfo *pep = NULL;
+        uint16_t nak_limit = 0;
+
+        uint8_t rcode = SetAddress(addr, ep, &pep, &nak_limit);
+
+        if(rcode)
+                return rcode;
+
+        return OutTransfer(pep, nak_limit, nbytes, data);
+}
+
+uint8_t USB::OutTransfer(EpInfo *pep, uint16_t nak_limit, uint16_t nbytes, uint8_t *data) {
+        uint8_t rcode = hrSUCCESS, retry_count;
+        uint8_t *data_p = data; //local copy of the data pointer
+        uint16_t bytes_tosend, nak_count;
+        uint16_t bytes_left = nbytes;
+
+        uint8_t maxpktsize = pep->maxPktSize;
+
+        if(maxpktsize < 1 || maxpktsize > 64)
+                return USB_ERROR_INVALID_MAX_PKT_SIZE;
+
+        uint32_t timeout = (uint32_t)millis() + USB_XFER_TIMEOUT;
+
+        regWr(rHCTL, (pep->bmSndToggle) ? bmSNDTOG1 : bmSNDTOG0); //set toggle value
+
+        while(bytes_left) {
+                retry_count = 0;
+                nak_count = 0;
+                bytes_tosend = (bytes_left >= maxpktsize) ? maxpktsize : bytes_left;
+                bytesWr(rSNDFIFO, bytes_tosend, data_p); //filling output FIFO
+                regWr(rSNDBC, bytes_tosend); //set number of bytes
+                regWr(rHXFR, (tokOUT | pep->epAddr)); //dispatch packet
+                while(!(regRd(rHIRQ) & bmHXFRDNIRQ)); //wait for the completion IRQ
+                regWr(rHIRQ, bmHXFRDNIRQ); //clear IRQ
+                rcode = (regRd(rHRSL) & 0x0f);
+
+                while(rcode && ((int32_t)((uint32_t)millis() - timeout) < 0L)) {
+                        switch(rcode) {
+                                case hrNAK:
+                                        nak_count++;
+                                        if(nak_limit && (nak_count == nak_limit))
+                                                goto breakout;
+                                        //return ( rcode);
+                                        break;
+                                case hrTIMEOUT:
+                                        retry_count++;
+                                        if(retry_count == USB_RETRY_LIMIT)
+                                                goto breakout;
+                                        //return ( rcode);
+                                        break;
+                                case hrTOGERR:
+                                        // yes, we flip it wrong here so that next time it is actually correct!
+                                        pep->bmSndToggle = (regRd(rHRSL) & bmSNDTOGRD) ? 0 : 1;
+                                        regWr(rHCTL, (pep->bmSndToggle) ? bmSNDTOG1 : bmSNDTOG0); //set toggle value
+                                        break;
+                                default:
+                                        goto breakout;
+                        }//switch( rcode
+
+                        /* process NAK according to Host out NAK bug */
+                        regWr(rSNDBC, 0);
+                        regWr(rSNDFIFO, *data_p);
+                        regWr(rSNDBC, bytes_tosend);
+                        regWr(rHXFR, (tokOUT | pep->epAddr)); //dispatch packet
+                        while(!(regRd(rHIRQ) & bmHXFRDNIRQ)); //wait for the completion IRQ
+                        regWr(rHIRQ, bmHXFRDNIRQ); //clear IRQ
+                        rcode = (regRd(rHRSL) & 0x0f);
+                }//while( rcode && ....
+                bytes_left -= bytes_tosend;
+                data_p += bytes_tosend;
+        }//while( bytes_left...
+breakout:
+
+        pep->bmSndToggle = (regRd(rHRSL) & bmSNDTOGRD) ? 1 : 0; //bmSNDTOG1 : bmSNDTOG0;  //update toggle
+        return ( rcode); //should be 0 in all cases
+}
+/* dispatch USB packet. Assumes peripheral address is set and relevant buffer is loaded/empty       */
+/* If NAK, tries to re-send up to nak_limit times                                                   */
+/* If nak_limit == 0, do not count NAKs, exit after timeout                                         */
+/* If bus timeout, re-sends up to USB_RETRY_LIMIT times                                             */
+
+/* return codes 0x00-0x0f are HRSLT( 0x00 being success ), 0xff means timeout                       */
+uint8_t USB::dispatchPkt(uint8_t token, uint8_t ep, uint16_t nak_limit) {
+        uint32_t timeout = (uint32_t)millis() + USB_XFER_TIMEOUT;
+        uint8_t tmpdata;
+        uint8_t rcode = hrSUCCESS;
+        uint8_t retry_count = 0;
+        uint16_t nak_count = 0;
+
+        while((int32_t)((uint32_t)millis() - timeout) < 0L) {
+#if defined(ESP8266) || defined(ESP32)
+                        yield(); // needed in order to reset the watchdog timer on the ESP8266
+#endif
+                regWr(rHXFR, (token | ep)); //launch the transfer
+                rcode = USB_ERROR_TRANSFER_TIMEOUT;
+
+                while((int32_t)((uint32_t)millis() - timeout) < 0L) //wait for transfer completion
+                {
+#if defined(ESP8266) || defined(ESP32)
+                        yield(); // needed in order to reset the watchdog timer on the ESP8266
+#endif
+                        tmpdata = regRd(rHIRQ);
+
+                        if(tmpdata & bmHXFRDNIRQ) {
+                                regWr(rHIRQ, bmHXFRDNIRQ); //clear the interrupt
+                                rcode = 0x00;
+                                break;
+                        }//if( tmpdata & bmHXFRDNIRQ
+
+                }//while ( millis() < timeout
+
+                //if (rcode != 0x00) //exit if timeout
+                //        return ( rcode);
+
+                rcode = (regRd(rHRSL) & 0x0f); //analyze transfer result
+
+                switch(rcode) {
+                        case hrNAK:
+                                nak_count++;
+                                if(nak_limit && (nak_count == nak_limit))
+                                        return (rcode);
+                                break;
+                        case hrTIMEOUT:
+                                retry_count++;
+                                if(retry_count == USB_RETRY_LIMIT)
+                                        return (rcode);
+                                break;
+                        default:
+                                return (rcode);
+                }//switch( rcode
+
+        }//while( timeout > millis()
+        return ( rcode);
+}
+
+/* USB main task. Performs enumeration/cleanup */
+void USB::Task(void) //USB state machine
+{
+        uint8_t rcode;
+        uint8_t tmpdata;
+        static uint32_t delay = 0;
+        //USB_DEVICE_DESCRIPTOR buf;
+        bool lowspeed = false;
+
+        MAX3421E::Task();
+
+        tmpdata = getVbusState();
+
+        /* modify USB task state if Vbus changed */
+        switch(tmpdata) {
+                case SE1: //illegal state
+                        usb_task_state = USB_DETACHED_SUBSTATE_ILLEGAL;
+                        lowspeed = false;
+                        break;
+                case SE0: //disconnected
+                        if((usb_task_state & USB_STATE_MASK) != USB_STATE_DETACHED)
+                                usb_task_state = USB_DETACHED_SUBSTATE_INITIALIZE;
+                        lowspeed = false;
+                        break;
+                case LSHOST:
+
+                        lowspeed = true;
+                        //intentional fallthrough
+                case FSHOST: //attached
+                        if((usb_task_state & USB_STATE_MASK) == USB_STATE_DETACHED) {
+                                delay = (uint32_t)millis() + USB_SETTLE_DELAY;
+                                usb_task_state = USB_ATTACHED_SUBSTATE_SETTLE;
+                        }
+                        break;
+        }// switch( tmpdata
+
+        for(uint8_t i = 0; i < USB_NUMDEVICES; i++)
+                if(devConfig[i])
+                        rcode = devConfig[i]->Poll();
+
+        switch(usb_task_state) {
+                case USB_DETACHED_SUBSTATE_INITIALIZE:
+                        init();
+
+                        for(uint8_t i = 0; i < USB_NUMDEVICES; i++)
+                                if(devConfig[i])
+                                        rcode = devConfig[i]->Release();
+
+                        usb_task_state = USB_DETACHED_SUBSTATE_WAIT_FOR_DEVICE;
+                        break;
+                case USB_DETACHED_SUBSTATE_WAIT_FOR_DEVICE: //just sit here
+                        break;
+                case USB_DETACHED_SUBSTATE_ILLEGAL: //just sit here
+                        break;
+                case USB_ATTACHED_SUBSTATE_SETTLE: //settle time for just attached device
+                        if((int32_t)((uint32_t)millis() - delay) >= 0L)
+                                usb_task_state = USB_ATTACHED_SUBSTATE_RESET_DEVICE;
+                        else break; // don't fall through
+                case USB_ATTACHED_SUBSTATE_RESET_DEVICE:
+                        regWr(rHCTL, bmBUSRST); //issue bus reset
+                        usb_task_state = USB_ATTACHED_SUBSTATE_WAIT_RESET_COMPLETE;
+                        break;
+                case USB_ATTACHED_SUBSTATE_WAIT_RESET_COMPLETE:
+                        if((regRd(rHCTL) & bmBUSRST) == 0) {
+                                tmpdata = regRd(rMODE) | bmSOFKAENAB; //start SOF generation
+                                regWr(rMODE, tmpdata);
+                                usb_task_state = USB_ATTACHED_SUBSTATE_WAIT_SOF;
+                                //delay = (uint32_t)millis() + 20; //20ms wait after reset per USB spec
+                        }
+                        break;
+                case USB_ATTACHED_SUBSTATE_WAIT_SOF: //todo: change check order
+                        if(regRd(rHIRQ) & bmFRAMEIRQ) {
+                                //when first SOF received _and_ 20ms has passed we can continue
+                                /*
+                                if (delay < (uint32_t)millis()) //20ms passed
+                                        usb_task_state = USB_STATE_CONFIGURING;
+                                 */
+                                usb_task_state = USB_ATTACHED_SUBSTATE_WAIT_RESET;
+                                delay = (uint32_t)millis() + 20;
+                        }
+                        break;
+                case USB_ATTACHED_SUBSTATE_WAIT_RESET:
+                        if((int32_t)((uint32_t)millis() - delay) >= 0L) usb_task_state = USB_STATE_CONFIGURING;
+                        else break; // don't fall through
+                case USB_STATE_CONFIGURING:
+
+                        //Serial.print("\r\nConf.LS: ");
+                        //Serial.println(lowspeed, HEX);
+
+                        rcode = Configuring(0, 0, lowspeed);
+
+                        if(rcode) {
+                                if(rcode != USB_DEV_CONFIG_ERROR_DEVICE_INIT_INCOMPLETE) {
+                                        usb_error = rcode;
+                                        usb_task_state = USB_STATE_ERROR;
+                                }
+                        } else
+                                usb_task_state = USB_STATE_RUNNING;
+                        break;
+                case USB_STATE_RUNNING:
+                        break;
+                case USB_STATE_ERROR:
+                        //MAX3421E::Init();
+                        break;
+        } // switch( usb_task_state )
+}
+
+uint8_t USB::DefaultAddressing(uint8_t parent, uint8_t port, bool lowspeed) {
+        //uint8_t                buf[12];
+        uint8_t rcode;
+        UsbDevice *p0 = NULL, *p = NULL;
+
+        // Get pointer to pseudo device with address 0 assigned
+        p0 = addrPool.GetUsbDevicePtr(0);
+
+        if(!p0)
+                return USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL;
+
+        if(!p0->epinfo)
+                return USB_ERROR_EPINFO_IS_NULL;
+
+        p0->lowspeed = (lowspeed) ? true : false;
+
+        // Allocate new address according to device class
+        uint8_t bAddress = addrPool.AllocAddress(parent, false, port);
+
+        if(!bAddress)
+                return USB_ERROR_OUT_OF_ADDRESS_SPACE_IN_POOL;
+
+        p = addrPool.GetUsbDevicePtr(bAddress);
+
+        if(!p)
+                return USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL;
+
+        p->lowspeed = lowspeed;
+
+        // Assign new address to the device
+        rcode = setAddr(0, 0, bAddress);
+
+        if(rcode) {
+                addrPool.FreeAddress(bAddress);
+                bAddress = 0;
+                return rcode;
+        }
+        return 0;
+};
+
+uint8_t USB::AttemptConfig(uint8_t driver, uint8_t parent, uint8_t port, bool lowspeed) {
+        //printf("AttemptConfig: parent = %i, port = %i\r\n", parent, port);
+        uint8_t retries = 0;
+
+again:
+        uint8_t rcode = devConfig[driver]->ConfigureDevice(parent, port, lowspeed);
+        if(rcode == USB_ERROR_CONFIG_REQUIRES_ADDITIONAL_RESET) {
+                if(parent == 0) {
+                        // Send a bus reset on the root interface.
+                        regWr(rHCTL, bmBUSRST); //issue bus reset
+                        delay(102); // delay 102ms, compensate for clock inaccuracy.
+                } else {
+                        // reset parent port
+                        devConfig[parent]->ResetHubPort(port);
+                }
+        } else if(rcode == hrJERR && retries < 3) { // Some devices returns this when plugged in - trying to initialize the device again usually works
+                delay(100);
+                retries++;
+                goto again;
+        } else if(rcode)
+                return rcode;
+
+        rcode = devConfig[driver]->Init(parent, port, lowspeed);
+        if(rcode == hrJERR && retries < 3) { // Some devices returns this when plugged in - trying to initialize the device again usually works
+                delay(100);
+                retries++;
+                goto again;
+        }
+        if(rcode) {
+                // Issue a bus reset, because the device may be in a limbo state
+                if(parent == 0) {
+                        // Send a bus reset on the root interface.
+                        regWr(rHCTL, bmBUSRST); //issue bus reset
+                        delay(102); // delay 102ms, compensate for clock inaccuracy.
+                } else {
+                        // reset parent port
+                        devConfig[parent]->ResetHubPort(port);
+                }
+        }
+        return rcode;
+}
+
+/*
+ * This is broken. We need to enumerate differently.
+ * It causes major problems with several devices if detected in an unexpected order.
+ *
+ *
+ * Oleg - I wouldn't do anything before the newly connected device is considered sane.
+ * i.e.(delays are not indicated for brevity):
+ * 1. reset
+ * 2. GetDevDescr();
+ * 3a. If ACK, continue with allocating address, addressing, etc.
+ * 3b. Else reset again, count resets, stop at some number (5?).
+ * 4. When max.number of resets is reached, toggle power/fail
+ * If desired, this could be modified by performing two resets with GetDevDescr() in the middle - however, from my experience, if a device answers to GDD()
+ * it doesn't need to be reset again
+ * New steps proposal:
+ * 1: get address pool instance. exit on fail
+ * 2: pUsb->getDevDescr(0, 0, constBufSize, (uint8_t*)buf). exit on fail.
+ * 3: bus reset, 100ms delay
+ * 4: set address
+ * 5: pUsb->setEpInfoEntry(bAddress, 1, epInfo), exit on fail
+ * 6: while (configurations) {
+ *              for(each configuration) {
+ *                      for (each driver) {
+ *                              6a: Ask device if it likes configuration. Returns 0 on OK.
+ *                                      If successful, the driver configured device.
+ *                                      The driver now owns the endpoints, and takes over managing them.
+ *                                      The following will need codes:
+ *                                          Everything went well, instance consumed, exit with success.
+ *                                          Instance already in use, ignore it, try next driver.
+ *                                          Not a supported device, ignore it, try next driver.
+ *                                          Not a supported configuration for this device, ignore it, try next driver.
+ *                                          Could not configure device, fatal, exit with fail.
+ *                      }
+ *              }
+ *    }
+ * 7: for(each driver) {
+ *      7a: Ask device if it knows this VID/PID. Acts exactly like 6a, but using VID/PID
+ * 8: if we get here, no driver likes the device plugged in, so exit failure.
+ *
+ */
+uint8_t USB::Configuring(uint8_t parent, uint8_t port, bool lowspeed) {
+        //uint8_t bAddress = 0;
+        //printf("Configuring: parent = %i, port = %i\r\n", parent, port);
+        uint8_t devConfigIndex;
+        uint8_t rcode = 0;
+        uint8_t buf[sizeof (USB_DEVICE_DESCRIPTOR)];
+        USB_DEVICE_DESCRIPTOR *udd = reinterpret_cast<USB_DEVICE_DESCRIPTOR *>(buf);
+        UsbDevice *p = NULL;
+        EpInfo *oldep_ptr = NULL;
+        EpInfo epInfo;
+
+        epInfo.epAddr = 0;
+        epInfo.maxPktSize = 8;
+        epInfo.bmSndToggle = 0;
+        epInfo.bmRcvToggle = 0;
+        epInfo.bmNakPower = USB_NAK_MAX_POWER;
+
+        //delay(2000);
+        AddressPool &addrPool = GetAddressPool();
+        // Get pointer to pseudo device with address 0 assigned
+        p = addrPool.GetUsbDevicePtr(0);
+        if(!p) {
+                //printf("Configuring error: USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL\r\n");
+                return USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL;
+        }
+
+        // Save old pointer to EP_RECORD of address 0
+        oldep_ptr = p->epinfo;
+
+        // Temporary assign new pointer to epInfo to p->epinfo in order to
+        // avoid toggle inconsistence
+
+        p->epinfo = &epInfo;
+
+        p->lowspeed = lowspeed;
+        // Get device descriptor
+        rcode = getDevDescr(0, 0, sizeof (USB_DEVICE_DESCRIPTOR), (uint8_t*)buf);
+
+        // Restore p->epinfo
+        p->epinfo = oldep_ptr;
+
+        if(rcode) {
+                //printf("Configuring error: Can't get USB_DEVICE_DESCRIPTOR\r\n");
+                return rcode;
+        }
+
+        // to-do?
+        // Allocate new address according to device class
+        //bAddress = addrPool.AllocAddress(parent, false, port);
+
+        uint16_t vid = udd->idVendor;
+        uint16_t pid = udd->idProduct;
+        uint8_t klass = udd->bDeviceClass;
+        uint8_t subklass = udd->bDeviceSubClass;
+        // Attempt to configure if VID/PID or device class matches with a driver
+        // Qualify with subclass too.
+        //
+        // VID/PID & class tests default to false for drivers not yet ported
+        // subclass defaults to true, so you don't have to define it if you don't have to.
+        //
+        for(devConfigIndex = 0; devConfigIndex < USB_NUMDEVICES; devConfigIndex++) {
+                if(!devConfig[devConfigIndex]) continue; // no driver
+                if(devConfig[devConfigIndex]->GetAddress()) continue; // consumed
+                if(devConfig[devConfigIndex]->DEVSUBCLASSOK(subklass) && (devConfig[devConfigIndex]->VIDPIDOK(vid, pid) || devConfig[devConfigIndex]->DEVCLASSOK(klass))) {
+                        rcode = AttemptConfig(devConfigIndex, parent, port, lowspeed);
+                        if(rcode != USB_DEV_CONFIG_ERROR_DEVICE_NOT_SUPPORTED)
+                                break;
+                }
+        }
+
+        if(devConfigIndex < USB_NUMDEVICES) {
+                return rcode;
+        }
+
+
+        // blindly attempt to configure
+        for(devConfigIndex = 0; devConfigIndex < USB_NUMDEVICES; devConfigIndex++) {
+                if(!devConfig[devConfigIndex]) continue;
+                if(devConfig[devConfigIndex]->GetAddress()) continue; // consumed
+                if(devConfig[devConfigIndex]->DEVSUBCLASSOK(subklass) && (devConfig[devConfigIndex]->VIDPIDOK(vid, pid) || devConfig[devConfigIndex]->DEVCLASSOK(klass))) continue; // If this is true it means it must have returned USB_DEV_CONFIG_ERROR_DEVICE_NOT_SUPPORTED above
+                rcode = AttemptConfig(devConfigIndex, parent, port, lowspeed);
+
+                //printf("ERROR ENUMERATING %2.2x\r\n", rcode);
+                if(!(rcode == USB_DEV_CONFIG_ERROR_DEVICE_NOT_SUPPORTED || rcode == USB_ERROR_CLASS_INSTANCE_ALREADY_IN_USE)) {
+                        // in case of an error dev_index should be reset to 0
+                        //                in order to start from the very beginning the
+                        //                next time the program gets here
+                        //if (rcode != USB_DEV_CONFIG_ERROR_DEVICE_INIT_INCOMPLETE)
+                        //        devConfigIndex = 0;
+                        return rcode;
+                }
+        }
+        // if we get here that means that the device class is not supported by any of registered classes
+        rcode = DefaultAddressing(parent, port, lowspeed);
+
+        return rcode;
+}
+
+uint8_t USB::ReleaseDevice(uint8_t addr) {
+        if(!addr)
+                return 0;
+
+        for(uint8_t i = 0; i < USB_NUMDEVICES; i++) {
+                if(!devConfig[i]) continue;
+                if(devConfig[i]->GetAddress() == addr)
+                        return devConfig[i]->Release();
+        }
+        return 0;
+}
+
+#if 1 //!defined(USB_METHODS_INLINE)
+//get device descriptor
+
+uint8_t USB::getDevDescr(uint8_t addr, uint8_t ep, uint16_t nbytes, uint8_t* dataptr) {
+        return ( ctrlReq(addr, ep, bmREQ_GET_DESCR, USB_REQUEST_GET_DESCRIPTOR, 0x00, USB_DESCRIPTOR_DEVICE, 0x0000, nbytes, nbytes, dataptr, NULL));
+}
+//get configuration descriptor
+
+uint8_t USB::getConfDescr(uint8_t addr, uint8_t ep, uint16_t nbytes, uint8_t conf, uint8_t* dataptr) {
+        return ( ctrlReq(addr, ep, bmREQ_GET_DESCR, USB_REQUEST_GET_DESCRIPTOR, conf, USB_DESCRIPTOR_CONFIGURATION, 0x0000, nbytes, nbytes, dataptr, NULL));
+}
+
+/* Requests Configuration Descriptor. Sends two Get Conf Descr requests. The first one gets the total length of all descriptors, then the second one requests this
+ total length. The length of the first request can be shorter ( 4 bytes ), however, there are devices which won't work unless this length is set to 9 */
+uint8_t USB::getConfDescr(uint8_t addr, uint8_t ep, uint8_t conf, USBReadParser *p) {
+        const uint8_t bufSize = 64;
+        uint8_t buf[bufSize];
+        USB_CONFIGURATION_DESCRIPTOR *ucd = reinterpret_cast<USB_CONFIGURATION_DESCRIPTOR *>(buf);
+
+        uint8_t ret = getConfDescr(addr, ep, 9, conf, buf);
+
+        if(ret)
+                return ret;
+
+        uint16_t total = ucd->wTotalLength;
+
+        //USBTRACE2("\r\ntotal conf.size:", total);
+
+        return ( ctrlReq(addr, ep, bmREQ_GET_DESCR, USB_REQUEST_GET_DESCRIPTOR, conf, USB_DESCRIPTOR_CONFIGURATION, 0x0000, total, bufSize, buf, p));
+}
+
+//get string descriptor
+
+uint8_t USB::getStrDescr(uint8_t addr, uint8_t ep, uint16_t ns, uint8_t index, uint16_t langid, uint8_t* dataptr) {
+        return ( ctrlReq(addr, ep, bmREQ_GET_DESCR, USB_REQUEST_GET_DESCRIPTOR, index, USB_DESCRIPTOR_STRING, langid, ns, ns, dataptr, NULL));
+}
+//set address
+
+uint8_t USB::setAddr(uint8_t oldaddr, uint8_t ep, uint8_t newaddr) {
+        uint8_t rcode = ctrlReq(oldaddr, ep, bmREQ_SET, USB_REQUEST_SET_ADDRESS, newaddr, 0x00, 0x0000, 0x0000, 0x0000, NULL, NULL);
+        //delay(2); //per USB 2.0 sect.9.2.6.3
+        delay(300); // Older spec says you should wait at least 200ms
+        return rcode;
+        //return ( ctrlReq(oldaddr, ep, bmREQ_SET, USB_REQUEST_SET_ADDRESS, newaddr, 0x00, 0x0000, 0x0000, 0x0000, NULL, NULL));
+}
+//set configuration
+
+uint8_t USB::setConf(uint8_t addr, uint8_t ep, uint8_t conf_value) {
+        return ( ctrlReq(addr, ep, bmREQ_SET, USB_REQUEST_SET_CONFIGURATION, conf_value, 0x00, 0x0000, 0x0000, 0x0000, NULL, NULL));
+}
+
+#endif // defined(USB_METHODS_INLINE)
+#endif // USB_FLASH_DRIVE_SUPPORT
diff --git a/Marlin/src/sd/usb_flashdrive/lib/Usb.h b/Marlin/src/sd/usb_flashdrive/lib/Usb.h
new file mode 100644
index 0000000000..fef7b814a3
--- /dev/null
+++ b/Marlin/src/sd/usb_flashdrive/lib/Usb.h
@@ -0,0 +1,52 @@
+/* Copyright (C) 2011 Circuits At Home, LTD. All rights reserved.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+Contact information
+-------------------
+
+Circuits At Home, LTD
+Web      :  http://www.circuitsathome.com
+e-mail   :  support@circuitsathome.com
+ */
+/* USB functions */
+#ifndef _usb_h_
+#define _usb_h_
+
+#include "../../../inc/MarlinConfigPre.h"
+
+// WARNING: Do not change the order of includes, or stuff will break!
+#include <inttypes.h>
+#include <stddef.h>
+#include <stdio.h>
+
+// None of these should ever be included by a driver, or a user's sketch.
+#include "settings.h"
+#include "printhex.h"
+#include "message.h"
+
+#include "hexdump.h"
+//#include "sink_parser.h"
+#include "max3421e.h"
+#include "address.h"
+//#include "avrpins.h"
+#include "usb_ch9.h"
+//#include "usbhost.h"
+#include "../usb_host.h"
+#include "UsbCore.h"
+#include "parsetools.h"
+#include "confdescparser.h"
+
+#endif //_usb_h_
diff --git a/Marlin/src/sd/usb_flashdrive/lib/UsbCore.h b/Marlin/src/sd/usb_flashdrive/lib/UsbCore.h
new file mode 100644
index 0000000000..74f7b40d80
--- /dev/null
+++ b/Marlin/src/sd/usb_flashdrive/lib/UsbCore.h
@@ -0,0 +1,314 @@
+/* Copyright (C) 2011 Circuits At Home, LTD. All rights reserved.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+Contact information
+-------------------
+
+Circuits At Home, LTD
+Web      :  http://www.circuitsathome.com
+e-mail   :  support@circuitsathome.com
+ */
+
+#ifndef _usb_h_
+  #error "Never include UsbCore.h directly; include Usb.h instead"
+#endif
+
+#ifndef USBCORE_H
+#define USBCORE_H
+
+// Not used anymore? If anyone uses this, please let us know so that this may be
+// moved to the proper place, settings.h.
+//#define USB_METHODS_INLINE
+
+/* shield pins. First parameter - SS pin, second parameter - INT pin */
+
+#ifdef __MARLIN_FIRMWARE__
+typedef MAX3421e MAX3421E; // Marlin redefines this class in "../usb_host.h"
+#elif defined(BOARD_BLACK_WIDDOW)
+typedef MAX3421e<P6, P3> MAX3421E; // Black Widow
+#elif defined(CORE_TEENSY) && (defined(__AVR_AT90USB646__) || defined(__AVR_AT90USB1286__))
+#if EXT_RAM
+typedef MAX3421e<P20, P7> MAX3421E; // Teensy++ 2.0 with XMEM2
+#else
+typedef MAX3421e<P9, P8> MAX3421E; // Teensy++ 1.0 and 2.0
+#endif
+#elif defined(BOARD_MEGA_ADK)
+typedef MAX3421e<P53, P54> MAX3421E; // Arduino Mega ADK
+#elif defined(ARDUINO_AVR_BALANDUINO)
+typedef MAX3421e<P20, P19> MAX3421E; // Balanduino
+#elif defined(__ARDUINO_X86__) && PLATFORM_ID == 0x06
+typedef MAX3421e<P3, P2> MAX3421E; // The Intel Galileo supports much faster read and write speed at pin 2 and 3
+#elif defined(ESP8266)
+typedef MAX3421e<P15, P5> MAX3421E; // ESP8266 boards
+#elif defined(ESP32)
+typedef MAX3421e<P5, P17> MAX3421E; // ESP32 boards
+#else
+typedef MAX3421e<P10, P9> MAX3421E; // Official Arduinos (UNO, Duemilanove, Mega, 2560, Leonardo, Due etc.), Intel Edison, Intel Galileo 2 or Teensy 2.0 and 3.x
+#endif
+
+/* Common setup data constant combinations  */
+#define bmREQ_GET_DESCR     USB_SETUP_DEVICE_TO_HOST|USB_SETUP_TYPE_STANDARD|USB_SETUP_RECIPIENT_DEVICE     //get descriptor request type
+#define bmREQ_SET           USB_SETUP_HOST_TO_DEVICE|USB_SETUP_TYPE_STANDARD|USB_SETUP_RECIPIENT_DEVICE     //set request type for all but 'set feature' and 'set interface'
+#define bmREQ_CL_GET_INTF   USB_SETUP_DEVICE_TO_HOST|USB_SETUP_TYPE_CLASS|USB_SETUP_RECIPIENT_INTERFACE     //get interface request type
+
+// D7           data transfer direction (0 - host-to-device, 1 - device-to-host)
+// D6-5         Type (0- standard, 1 - class, 2 - vendor, 3 - reserved)
+// D4-0         Recipient (0 - device, 1 - interface, 2 - endpoint, 3 - other, 4..31 - reserved)
+
+// USB Device Classes
+#define USB_CLASS_USE_CLASS_INFO        0x00    // Use Class Info in the Interface Descriptors
+#define USB_CLASS_AUDIO                 0x01    // Audio
+#define USB_CLASS_COM_AND_CDC_CTRL      0x02    // Communications and CDC Control
+#define USB_CLASS_HID                   0x03    // HID
+#define USB_CLASS_PHYSICAL              0x05    // Physical
+#define USB_CLASS_IMAGE                 0x06    // Image
+#define USB_CLASS_PRINTER               0x07    // Printer
+#define USB_CLASS_MASS_STORAGE          0x08    // Mass Storage
+#define USB_CLASS_HUB                   0x09    // Hub
+#define USB_CLASS_CDC_DATA              0x0a    // CDC-Data
+#define USB_CLASS_SMART_CARD            0x0b    // Smart-Card
+#define USB_CLASS_CONTENT_SECURITY      0x0d    // Content Security
+#define USB_CLASS_VIDEO                 0x0e    // Video
+#define USB_CLASS_PERSONAL_HEALTH       0x0f    // Personal Healthcare
+#define USB_CLASS_DIAGNOSTIC_DEVICE     0xdc    // Diagnostic Device
+#define USB_CLASS_WIRELESS_CTRL         0xe0    // Wireless Controller
+#define USB_CLASS_MISC                  0xef    // Miscellaneous
+#define USB_CLASS_APP_SPECIFIC          0xfe    // Application Specific
+#define USB_CLASS_VENDOR_SPECIFIC       0xff    // Vendor Specific
+
+// Additional Error Codes
+#define USB_DEV_CONFIG_ERROR_DEVICE_NOT_SUPPORTED       0xD1
+#define USB_DEV_CONFIG_ERROR_DEVICE_INIT_INCOMPLETE     0xD2
+#define USB_ERROR_UNABLE_TO_REGISTER_DEVICE_CLASS       0xD3
+#define USB_ERROR_OUT_OF_ADDRESS_SPACE_IN_POOL          0xD4
+#define USB_ERROR_HUB_ADDRESS_OVERFLOW                  0xD5
+#define USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL             0xD6
+#define USB_ERROR_EPINFO_IS_NULL                        0xD7
+#define USB_ERROR_INVALID_ARGUMENT                      0xD8
+#define USB_ERROR_CLASS_INSTANCE_ALREADY_IN_USE         0xD9
+#define USB_ERROR_INVALID_MAX_PKT_SIZE                  0xDA
+#define USB_ERROR_EP_NOT_FOUND_IN_TBL                   0xDB
+#define USB_ERROR_CONFIG_REQUIRES_ADDITIONAL_RESET      0xE0
+#define USB_ERROR_FailGetDevDescr                       0xE1
+#define USB_ERROR_FailSetDevTblEntry                    0xE2
+#define USB_ERROR_FailGetConfDescr                      0xE3
+#define USB_ERROR_TRANSFER_TIMEOUT                      0xFF
+
+#define USB_XFER_TIMEOUT        5000    // (5000) USB transfer timeout in milliseconds, per section 9.2.6.1 of USB 2.0 spec
+//#define USB_NAK_LIMIT         32000   // NAK limit for a transfer. 0 means NAKs are not counted
+#define USB_RETRY_LIMIT         3       // 3 retry limit for a transfer
+#define USB_SETTLE_DELAY        200     // settle delay in milliseconds
+
+#define USB_NUMDEVICES          16      //number of USB devices
+//#define HUB_MAX_HUBS          7       // maximum number of hubs that can be attached to the host controller
+#define HUB_PORT_RESET_DELAY    20      // hub port reset delay 10 ms recomended, can be up to 20 ms
+
+/* USB state machine states */
+#define USB_STATE_MASK                                      0xf0
+
+#define USB_STATE_DETACHED                                  0x10
+#define USB_DETACHED_SUBSTATE_INITIALIZE                    0x11
+#define USB_DETACHED_SUBSTATE_WAIT_FOR_DEVICE               0x12
+#define USB_DETACHED_SUBSTATE_ILLEGAL                       0x13
+#define USB_ATTACHED_SUBSTATE_SETTLE                        0x20
+#define USB_ATTACHED_SUBSTATE_RESET_DEVICE                  0x30
+#define USB_ATTACHED_SUBSTATE_WAIT_RESET_COMPLETE           0x40
+#define USB_ATTACHED_SUBSTATE_WAIT_SOF                      0x50
+#define USB_ATTACHED_SUBSTATE_WAIT_RESET                    0x51
+#define USB_ATTACHED_SUBSTATE_GET_DEVICE_DESCRIPTOR_SIZE    0x60
+#define USB_STATE_ADDRESSING                                0x70
+#define USB_STATE_CONFIGURING                               0x80
+#define USB_STATE_RUNNING                                   0x90
+#define USB_STATE_ERROR                                     0xa0
+
+class USBDeviceConfig {
+public:
+
+        virtual uint8_t Init(uint8_t parent __attribute__((unused)), uint8_t port __attribute__((unused)), bool lowspeed __attribute__((unused))) {
+                return 0;
+        }
+
+        virtual uint8_t ConfigureDevice(uint8_t parent __attribute__((unused)), uint8_t port __attribute__((unused)), bool lowspeed __attribute__((unused))) {
+                return 0;
+        }
+
+        virtual uint8_t Release() {
+                return 0;
+        }
+
+        virtual uint8_t Poll() {
+                return 0;
+        }
+
+        virtual uint8_t GetAddress() {
+                return 0;
+        }
+
+        virtual void ResetHubPort(uint8_t port __attribute__((unused))) {
+                return;
+        } // Note used for hubs only!
+
+        virtual bool VIDPIDOK(uint16_t vid __attribute__((unused)), uint16_t pid __attribute__((unused))) {
+                return false;
+        }
+
+        virtual bool DEVCLASSOK(uint8_t klass __attribute__((unused))) {
+                return false;
+        }
+
+        virtual bool DEVSUBCLASSOK(uint8_t subklass __attribute__((unused))) {
+                return true;
+        }
+
+};
+
+/* USB Setup Packet Structure   */
+typedef struct {
+
+        union { // offset   description
+                uint8_t bmRequestType; //   0      Bit-map of request type
+
+                struct {
+                        uint8_t recipient : 5; //          Recipient of the request
+                        uint8_t type : 2; //          Type of request
+                        uint8_t direction : 1; //          Direction of data X-fer
+                } __attribute__((packed));
+        } ReqType_u;
+        uint8_t bRequest; //   1      Request
+
+        union {
+                uint16_t wValue; //   2      Depends on bRequest
+
+                struct {
+                        uint8_t wValueLo;
+                        uint8_t wValueHi;
+                } __attribute__((packed));
+        } wVal_u;
+        uint16_t wIndex; //   4      Depends on bRequest
+        uint16_t wLength; //   6      Depends on bRequest
+} __attribute__((packed)) SETUP_PKT, *PSETUP_PKT;
+
+
+
+// Base class for incoming data parser
+
+class USBReadParser {
+public:
+        virtual void Parse(const uint16_t len, const uint8_t *pbuf, const uint16_t &offset) = 0;
+};
+
+class USB : public MAX3421E {
+        AddressPoolImpl<USB_NUMDEVICES> addrPool;
+        USBDeviceConfig* devConfig[USB_NUMDEVICES];
+        uint8_t bmHubPre;
+
+public:
+        USB(void);
+
+        void SetHubPreMask() {
+                bmHubPre |= bmHUBPRE;
+        };
+
+        void ResetHubPreMask() {
+                bmHubPre &= (~bmHUBPRE);
+        };
+
+        AddressPool& GetAddressPool() {
+                return (AddressPool&)addrPool;
+        };
+
+        uint8_t RegisterDeviceClass(USBDeviceConfig *pdev) {
+                for(uint8_t i = 0; i < USB_NUMDEVICES; i++) {
+                        if(!devConfig[i]) {
+                                devConfig[i] = pdev;
+                                return 0;
+                        }
+                }
+                return USB_ERROR_UNABLE_TO_REGISTER_DEVICE_CLASS;
+        };
+
+        void ForEachUsbDevice(UsbDeviceHandleFunc pfunc) {
+                addrPool.ForEachUsbDevice(pfunc);
+        };
+        uint8_t getUsbTaskState(void);
+        void setUsbTaskState(uint8_t state);
+
+        EpInfo* getEpInfoEntry(uint8_t addr, uint8_t ep);
+        uint8_t setEpInfoEntry(uint8_t addr, uint8_t epcount, EpInfo* eprecord_ptr);
+
+        /* Control requests */
+        uint8_t getDevDescr(uint8_t addr, uint8_t ep, uint16_t nbytes, uint8_t* dataptr);
+        uint8_t getConfDescr(uint8_t addr, uint8_t ep, uint16_t nbytes, uint8_t conf, uint8_t* dataptr);
+
+        uint8_t getConfDescr(uint8_t addr, uint8_t ep, uint8_t conf, USBReadParser *p);
+
+        uint8_t getStrDescr(uint8_t addr, uint8_t ep, uint16_t nbytes, uint8_t index, uint16_t langid, uint8_t* dataptr);
+        uint8_t setAddr(uint8_t oldaddr, uint8_t ep, uint8_t newaddr);
+        uint8_t setConf(uint8_t addr, uint8_t ep, uint8_t conf_value);
+        /**/
+        uint8_t ctrlData(uint8_t addr, uint8_t ep, uint16_t nbytes, uint8_t* dataptr, bool direction);
+        uint8_t ctrlStatus(uint8_t ep, bool direction, uint16_t nak_limit);
+        uint8_t inTransfer(uint8_t addr, uint8_t ep, uint16_t *nbytesptr, uint8_t* data, uint8_t bInterval = 0);
+        uint8_t outTransfer(uint8_t addr, uint8_t ep, uint16_t nbytes, uint8_t* data);
+        uint8_t dispatchPkt(uint8_t token, uint8_t ep, uint16_t nak_limit);
+
+        void Task(void);
+
+        uint8_t DefaultAddressing(uint8_t parent, uint8_t port, bool lowspeed);
+        uint8_t Configuring(uint8_t parent, uint8_t port, bool lowspeed);
+        uint8_t ReleaseDevice(uint8_t addr);
+
+        uint8_t ctrlReq(uint8_t addr, uint8_t ep, uint8_t bmReqType, uint8_t bRequest, uint8_t wValLo, uint8_t wValHi,
+                uint16_t wInd, uint16_t total, uint16_t nbytes, uint8_t* dataptr, USBReadParser *p);
+
+private:
+        void init();
+        uint8_t SetAddress(uint8_t addr, uint8_t ep, EpInfo **ppep, uint16_t *nak_limit);
+        uint8_t OutTransfer(EpInfo *pep, uint16_t nak_limit, uint16_t nbytes, uint8_t *data);
+        uint8_t InTransfer(EpInfo *pep, uint16_t nak_limit, uint16_t *nbytesptr, uint8_t *data, uint8_t bInterval = 0);
+        uint8_t AttemptConfig(uint8_t driver, uint8_t parent, uint8_t port, bool lowspeed);
+};
+
+#if 0 //defined(USB_METHODS_INLINE)
+//get device descriptor
+
+inline uint8_t USB::getDevDescr(uint8_t addr, uint8_t ep, uint16_t nbytes, uint8_t* dataptr) {
+        return ( ctrlReq(addr, ep, bmREQ_GET_DESCR, USB_REQUEST_GET_DESCRIPTOR, 0x00, USB_DESCRIPTOR_DEVICE, 0x0000, nbytes, dataptr));
+}
+//get configuration descriptor
+
+inline uint8_t USB::getConfDescr(uint8_t addr, uint8_t ep, uint16_t nbytes, uint8_t conf, uint8_t* dataptr) {
+        return ( ctrlReq(addr, ep, bmREQ_GET_DESCR, USB_REQUEST_GET_DESCRIPTOR, conf, USB_DESCRIPTOR_CONFIGURATION, 0x0000, nbytes, dataptr));
+}
+//get string descriptor
+
+inline uint8_t USB::getStrDescr(uint8_t addr, uint8_t ep, uint16_t nuint8_ts, uint8_t index, uint16_t langid, uint8_t* dataptr) {
+        return ( ctrlReq(addr, ep, bmREQ_GET_DESCR, USB_REQUEST_GET_DESCRIPTOR, index, USB_DESCRIPTOR_STRING, langid, nuint8_ts, dataptr));
+}
+//set address
+
+inline uint8_t USB::setAddr(uint8_t oldaddr, uint8_t ep, uint8_t newaddr) {
+        return ( ctrlReq(oldaddr, ep, bmREQ_SET, USB_REQUEST_SET_ADDRESS, newaddr, 0x00, 0x0000, 0x0000, NULL));
+}
+//set configuration
+
+inline uint8_t USB::setConf(uint8_t addr, uint8_t ep, uint8_t conf_value) {
+        return ( ctrlReq(addr, ep, bmREQ_SET, USB_REQUEST_SET_CONFIGURATION, conf_value, 0x00, 0x0000, 0x0000, NULL));
+}
+
+#endif // defined(USB_METHODS_INLINE)
+
+#endif /* USBCORE_H */
diff --git a/Marlin/src/sd/usb_flashdrive/lib/address.h b/Marlin/src/sd/usb_flashdrive/lib/address.h
new file mode 100644
index 0000000000..0cc0ab16e5
--- /dev/null
+++ b/Marlin/src/sd/usb_flashdrive/lib/address.h
@@ -0,0 +1,290 @@
+/* Copyright (C) 2011 Circuits At Home, LTD. All rights reserved.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+Contact information
+-------------------
+
+Circuits At Home, LTD
+Web      :  http://www.circuitsathome.com
+e-mail   :  support@circuitsathome.com
+ */
+
+#if !defined(_usb_h_) || defined(__ADDRESS_H__)
+#error "Never include address.h directly; include Usb.h instead"
+#else
+#define __ADDRESS_H__
+
+
+
+/* NAK powers. To save space in endpoint data structure, amount of retries before giving up and returning 0x4 is stored in */
+/* bmNakPower as a power of 2. The actual nak_limit is then calculated as nak_limit = ( 2^bmNakPower - 1) */
+#define USB_NAK_MAX_POWER               15              //NAK binary order maximum value
+#define USB_NAK_DEFAULT                 14              //default 32K-1 NAKs before giving up
+#define USB_NAK_NOWAIT                  1               //Single NAK stops transfer
+#define USB_NAK_NONAK                   0               //Do not count NAKs, stop retrying after USB Timeout
+
+struct EpInfo {
+        uint8_t epAddr; // Endpoint address
+        uint8_t maxPktSize; // Maximum packet size
+
+        union {
+                uint8_t epAttribs;
+
+                struct {
+                        uint8_t bmSndToggle : 1; // Send toggle, when zero bmSNDTOG0, bmSNDTOG1 otherwise
+                        uint8_t bmRcvToggle : 1; // Send toggle, when zero bmRCVTOG0, bmRCVTOG1 otherwise
+                        uint8_t bmNakPower : 6; // Binary order for NAK_LIMIT value
+                } __attribute__((packed));
+        };
+} __attribute__((packed));
+
+//        7   6   5   4   3   2   1   0
+//  ---------------------------------
+//  |   | H | P | P | P | A | A | A |
+//  ---------------------------------
+//
+// H - if 1 the address is a hub address
+// P - parent hub address
+// A - device address / port number in case of hub
+//
+
+struct UsbDeviceAddress {
+
+        union {
+
+                struct {
+                        uint8_t bmAddress : 3; // device address/port number
+                        uint8_t bmParent : 3; // parent hub address
+                        uint8_t bmHub : 1; // hub flag
+                        uint8_t bmReserved : 1; // reserved, must be zero
+                } __attribute__((packed));
+                uint8_t devAddress;
+        };
+} __attribute__((packed));
+
+#define bmUSB_DEV_ADDR_ADDRESS          0x07
+#define bmUSB_DEV_ADDR_PARENT           0x38
+#define bmUSB_DEV_ADDR_HUB              0x40
+
+struct UsbDevice {
+        EpInfo *epinfo; // endpoint info pointer
+        UsbDeviceAddress address;
+        uint8_t epcount; // number of endpoints
+        bool lowspeed; // indicates if a device is the low speed one
+        //      uint8_t devclass; // device class
+} __attribute__((packed));
+
+class AddressPool {
+public:
+        virtual UsbDevice* GetUsbDevicePtr(uint8_t addr) = 0;
+        virtual uint8_t AllocAddress(uint8_t parent, bool is_hub = false, uint8_t port = 0) = 0;
+        virtual void FreeAddress(uint8_t addr) = 0;
+};
+
+typedef void (*UsbDeviceHandleFunc)(UsbDevice *pdev);
+
+#define ADDR_ERROR_INVALID_INDEX                0xFF
+#define ADDR_ERROR_INVALID_ADDRESS              0xFF
+
+template <const uint8_t MAX_DEVICES_ALLOWED>
+class AddressPoolImpl : public AddressPool {
+        EpInfo dev0ep; //Endpoint data structure used during enumeration for uninitialized device
+
+        uint8_t hubCounter; // hub counter is kept
+        // in order to avoid hub address duplication
+
+        UsbDevice thePool[MAX_DEVICES_ALLOWED];
+
+        // Initializes address pool entry
+
+        void InitEntry(uint8_t index) {
+                thePool[index].address.devAddress = 0;
+                thePool[index].epcount = 1;
+                thePool[index].lowspeed = 0;
+                thePool[index].epinfo = &dev0ep;
+        };
+
+        // Returns thePool index for a given address
+
+        uint8_t FindAddressIndex(uint8_t address = 0) {
+                for(uint8_t i = 1; i < MAX_DEVICES_ALLOWED; i++) {
+                        if(thePool[i].address.devAddress == address)
+                                return i;
+                }
+                return 0;
+        };
+
+        // Returns thePool child index for a given parent
+
+        uint8_t FindChildIndex(UsbDeviceAddress addr, uint8_t start = 1) {
+                for(uint8_t i = (start < 1 || start >= MAX_DEVICES_ALLOWED) ? 1 : start; i < MAX_DEVICES_ALLOWED; i++) {
+                        if(thePool[i].address.bmParent == addr.bmAddress)
+                                return i;
+                }
+                return 0;
+        };
+
+        // Frees address entry specified by index parameter
+
+        void FreeAddressByIndex(uint8_t index) {
+                // Zero field is reserved and should not be affected
+                if(index == 0)
+                        return;
+
+                UsbDeviceAddress uda = thePool[index].address;
+                // If a hub was switched off all port addresses should be freed
+                if(uda.bmHub == 1) {
+                        for(uint8_t i = 1; (i = FindChildIndex(uda, i));)
+                                FreeAddressByIndex(i);
+
+                        // If the hub had the last allocated address, hubCounter should be decremented
+                        if(hubCounter == uda.bmAddress)
+                                hubCounter--;
+                }
+                InitEntry(index);
+        }
+
+        // Initializes the whole address pool at once
+
+        void InitAllAddresses() {
+                for(uint8_t i = 1; i < MAX_DEVICES_ALLOWED; i++)
+                        InitEntry(i);
+
+                hubCounter = 0;
+        };
+
+public:
+
+        AddressPoolImpl() : hubCounter(0) {
+                // Zero address is reserved
+                InitEntry(0);
+
+                thePool[0].address.devAddress = 0;
+                thePool[0].epinfo = &dev0ep;
+                dev0ep.epAddr = 0;
+                dev0ep.maxPktSize = 8;
+                dev0ep.bmSndToggle = 0; // Set DATA0/1 toggles to 0
+                dev0ep.bmRcvToggle = 0;
+                dev0ep.bmNakPower = USB_NAK_MAX_POWER;
+
+                InitAllAddresses();
+        };
+
+        // Returns a pointer to a specified address entry
+
+        virtual UsbDevice* GetUsbDevicePtr(uint8_t addr) {
+                if(!addr)
+                        return thePool;
+
+                uint8_t index = FindAddressIndex(addr);
+
+                return (!index) ? NULL : thePool + index;
+        };
+
+        // Performs an operation specified by pfunc for each addressed device
+
+        void ForEachUsbDevice(UsbDeviceHandleFunc pfunc) {
+                if(!pfunc)
+                        return;
+
+                for(uint8_t i = 1; i < MAX_DEVICES_ALLOWED; i++)
+                        if(thePool[i].address.devAddress)
+                                pfunc(thePool + i);
+        };
+
+        // Allocates new address
+
+        virtual uint8_t AllocAddress(uint8_t parent, bool is_hub = false, uint8_t port = 0) {
+                /* if (parent != 0 && port == 0)
+                        USB_HOST_SERIAL.println("PRT:0"); */
+                UsbDeviceAddress _parent;
+                _parent.devAddress = parent;
+                if(_parent.bmReserved || port > 7)
+                        //if(parent > 127 || port > 7)
+                        return 0;
+
+                if(is_hub && hubCounter == 7)
+                        return 0;
+
+                // finds first empty address entry starting from one
+                uint8_t index = FindAddressIndex(0);
+
+                if(!index) // if empty entry is not found
+                        return 0;
+
+                if(_parent.devAddress == 0) {
+                        if(is_hub) {
+                                thePool[index].address.devAddress = 0x41;
+                                hubCounter++;
+                        } else
+                                thePool[index].address.devAddress = 1;
+
+                        return thePool[index].address.devAddress;
+                }
+
+                UsbDeviceAddress addr;
+                addr.devAddress = 0; // Ensure all bits are zero
+                addr.bmParent = _parent.bmAddress;
+                if(is_hub) {
+                        addr.bmHub = 1;
+                        addr.bmAddress = ++hubCounter;
+                } else {
+                        addr.bmHub = 0;
+                        addr.bmAddress = port;
+                }
+                thePool[index].address = addr;
+                /*
+                                USB_HOST_SERIAL.print("Addr:");
+                                USB_HOST_SERIAL.print(addr.bmHub, HEX);
+                                USB_HOST_SERIAL.print(".");
+                                USB_HOST_SERIAL.print(addr.bmParent, HEX);
+                                USB_HOST_SERIAL.print(".");
+                                USB_HOST_SERIAL.println(addr.bmAddress, HEX);
+                 */
+                return thePool[index].address.devAddress;
+        };
+
+        // Empties pool entry
+
+        virtual void FreeAddress(uint8_t addr) {
+                // if the root hub is disconnected all the addresses should be initialized
+                if(addr == 0x41) {
+                        InitAllAddresses();
+                        return;
+                }
+                uint8_t index = FindAddressIndex(addr);
+                FreeAddressByIndex(index);
+        };
+
+        // Returns number of hubs attached
+        // It can be rather helpfull to find out if there are hubs attached than getting the exact number of hubs.
+        //uint8_t GetNumHubs()
+        //{
+        //        return hubCounter;
+        //};
+        //uint8_t GetNumDevices()
+        //{
+        //        uint8_t counter = 0;
+
+        //        for (uint8_t i=1; i<MAX_DEVICES_ALLOWED; i++)
+        //                if (thePool[i].address != 0);
+        //                        counter ++;
+
+        //        return counter;
+        //};
+};
+
+#endif // __ADDRESS_H__
diff --git a/Marlin/src/sd/usb_flashdrive/lib/confdescparser.h b/Marlin/src/sd/usb_flashdrive/lib/confdescparser.h
new file mode 100644
index 0000000000..540535455d
--- /dev/null
+++ b/Marlin/src/sd/usb_flashdrive/lib/confdescparser.h
@@ -0,0 +1,217 @@
+/* Copyright (C) 2011 Circuits At Home, LTD. All rights reserved.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+Contact information
+-------------------
+
+Circuits At Home, LTD
+Web      :  http://www.circuitsathome.com
+e-mail   :  support@circuitsathome.com
+ */
+#if !defined(_usb_h_) || defined(__CONFDESCPARSER_H__)
+#error "Never include confdescparser.h directly; include Usb.h instead"
+#else
+
+#define __CONFDESCPARSER_H__
+
+class UsbConfigXtracter {
+public:
+        //virtual void ConfigXtract(const USB_CONFIGURATION_DESCRIPTOR *conf) = 0;
+        //virtual void InterfaceXtract(uint8_t conf, const USB_INTERFACE_DESCRIPTOR *iface) = 0;
+
+        virtual void EndpointXtract(uint8_t conf __attribute__((unused)), uint8_t iface __attribute__((unused)), uint8_t alt __attribute__((unused)), uint8_t proto __attribute__((unused)), const USB_ENDPOINT_DESCRIPTOR *ep __attribute__((unused))) {
+        };
+};
+
+#define CP_MASK_COMPARE_CLASS                   1
+#define CP_MASK_COMPARE_SUBCLASS                2
+#define CP_MASK_COMPARE_PROTOCOL                4
+#define CP_MASK_COMPARE_ALL                     7
+
+// Configuration Descriptor Parser Class Template
+
+template <const uint8_t CLASS_ID, const uint8_t SUBCLASS_ID, const uint8_t PROTOCOL_ID, const uint8_t MASK>
+class ConfigDescParser : public USBReadParser {
+        UsbConfigXtracter *theXtractor;
+        MultiValueBuffer theBuffer;
+        MultiByteValueParser valParser;
+        ByteSkipper theSkipper;
+        uint8_t varBuffer[16 /*sizeof(USB_CONFIGURATION_DESCRIPTOR)*/];
+
+        uint8_t stateParseDescr; // ParseDescriptor state
+
+        uint8_t dscrLen; // Descriptor length
+        uint8_t dscrType; // Descriptor type
+
+        bool isGoodInterface; // Apropriate interface flag
+        uint8_t confValue; // Configuration value
+        uint8_t protoValue; // Protocol value
+        uint8_t ifaceNumber; // Interface number
+        uint8_t ifaceAltSet; // Interface alternate settings
+
+        bool UseOr;
+        bool ParseDescriptor(uint8_t **pp, uint16_t *pcntdn);
+        void PrintHidDescriptor(const USB_HID_DESCRIPTOR *pDesc);
+
+public:
+
+        void SetOR(void) {
+                UseOr = true;
+        }
+        ConfigDescParser(UsbConfigXtracter *xtractor);
+        void Parse(const uint16_t len, const uint8_t *pbuf, const uint16_t &offset);
+};
+
+template <const uint8_t CLASS_ID, const uint8_t SUBCLASS_ID, const uint8_t PROTOCOL_ID, const uint8_t MASK>
+ConfigDescParser<CLASS_ID, SUBCLASS_ID, PROTOCOL_ID, MASK>::ConfigDescParser(UsbConfigXtracter *xtractor) :
+theXtractor(xtractor),
+stateParseDescr(0),
+dscrLen(0),
+dscrType(0),
+UseOr(false) {
+        theBuffer.pValue = varBuffer;
+        valParser.Initialize(&theBuffer);
+        theSkipper.Initialize(&theBuffer);
+};
+
+template <const uint8_t CLASS_ID, const uint8_t SUBCLASS_ID, const uint8_t PROTOCOL_ID, const uint8_t MASK>
+void ConfigDescParser<CLASS_ID, SUBCLASS_ID, PROTOCOL_ID, MASK>::Parse(const uint16_t len, const uint8_t *pbuf, const uint16_t &offset __attribute__((unused))) {
+        uint16_t cntdn = (uint16_t)len;
+        uint8_t *p = (uint8_t*)pbuf;
+
+        while(cntdn)
+                if(!ParseDescriptor(&p, &cntdn))
+                        return;
+}
+
+/* Parser for the configuration descriptor. Takes values for class, subclass, protocol fields in interface descriptor and
+  compare masks for them. When the match is found, calls EndpointXtract passing buffer containing endpoint descriptor */
+template <const uint8_t CLASS_ID, const uint8_t SUBCLASS_ID, const uint8_t PROTOCOL_ID, const uint8_t MASK>
+bool ConfigDescParser<CLASS_ID, SUBCLASS_ID, PROTOCOL_ID, MASK>::ParseDescriptor(uint8_t **pp, uint16_t *pcntdn) {
+        USB_CONFIGURATION_DESCRIPTOR* ucd = reinterpret_cast<USB_CONFIGURATION_DESCRIPTOR*>(varBuffer);
+        USB_INTERFACE_DESCRIPTOR* uid = reinterpret_cast<USB_INTERFACE_DESCRIPTOR*>(varBuffer);
+        switch(stateParseDescr) {
+                case 0:
+                        theBuffer.valueSize = 2;
+                        valParser.Initialize(&theBuffer);
+                        stateParseDescr = 1;
+                case 1:
+                        if(!valParser.Parse(pp, pcntdn))
+                                return false;
+                        dscrLen = *((uint8_t*)theBuffer.pValue);
+                        dscrType = *((uint8_t*)theBuffer.pValue + 1);
+                        stateParseDescr = 2;
+                case 2:
+                        // This is a sort of hack. Assuming that two bytes are all ready in the buffer
+                        //      the pointer is positioned two bytes ahead in order for the rest of descriptor
+                        //      to be read right after the size and the type fields.
+                        // This should be used carefully. varBuffer should be used directly to handle data
+                        //      in the buffer.
+                        theBuffer.pValue = varBuffer + 2;
+                        stateParseDescr = 3;
+                case 3:
+                        switch(dscrType) {
+                                case USB_DESCRIPTOR_INTERFACE:
+                                        isGoodInterface = false;
+                                        break;
+                                case USB_DESCRIPTOR_CONFIGURATION:
+                                case USB_DESCRIPTOR_ENDPOINT:
+                                case HID_DESCRIPTOR_HID:
+                                        break;
+                        }
+                        theBuffer.valueSize = dscrLen - 2;
+                        valParser.Initialize(&theBuffer);
+                        stateParseDescr = 4;
+                case 4:
+                        switch(dscrType) {
+                                case USB_DESCRIPTOR_CONFIGURATION:
+                                        if(!valParser.Parse(pp, pcntdn))
+                                                return false;
+                                        confValue = ucd->bConfigurationValue;
+                                        break;
+                                case USB_DESCRIPTOR_INTERFACE:
+                                        if(!valParser.Parse(pp, pcntdn))
+                                                return false;
+                                        if((MASK & CP_MASK_COMPARE_CLASS) && uid->bInterfaceClass != CLASS_ID)
+                                                break;
+                                        if((MASK & CP_MASK_COMPARE_SUBCLASS) && uid->bInterfaceSubClass != SUBCLASS_ID)
+                                                break;
+                                        if(UseOr) {
+                                                if((!((MASK & CP_MASK_COMPARE_PROTOCOL) && uid->bInterfaceProtocol)))
+                                                        break;
+                                        } else {
+                                                if((MASK & CP_MASK_COMPARE_PROTOCOL) && uid->bInterfaceProtocol != PROTOCOL_ID)
+                                                        break;
+                                        }
+                                        isGoodInterface = true;
+                                        ifaceNumber = uid->bInterfaceNumber;
+                                        ifaceAltSet = uid->bAlternateSetting;
+                                        protoValue = uid->bInterfaceProtocol;
+                                        break;
+                                case USB_DESCRIPTOR_ENDPOINT:
+                                        if(!valParser.Parse(pp, pcntdn))
+                                                return false;
+                                        if(isGoodInterface)
+                                                if(theXtractor)
+                                                        theXtractor->EndpointXtract(confValue, ifaceNumber, ifaceAltSet, protoValue, (USB_ENDPOINT_DESCRIPTOR*)varBuffer);
+                                        break;
+                                        //case HID_DESCRIPTOR_HID:
+                                        //      if (!valParser.Parse(pp, pcntdn))
+                                        //              return false;
+                                        //      PrintHidDescriptor((const USB_HID_DESCRIPTOR*)varBuffer);
+                                        //      break;
+                                default:
+                                        if(!theSkipper.Skip(pp, pcntdn, dscrLen - 2))
+                                                return false;
+                        }
+                        theBuffer.pValue = varBuffer;
+                        stateParseDescr = 0;
+        }
+        return true;
+}
+
+template <const uint8_t CLASS_ID, const uint8_t SUBCLASS_ID, const uint8_t PROTOCOL_ID, const uint8_t MASK>
+void ConfigDescParser<CLASS_ID, SUBCLASS_ID, PROTOCOL_ID, MASK>::PrintHidDescriptor(const USB_HID_DESCRIPTOR *pDesc) {
+        Notify(PSTR("\r\n\r\nHID Descriptor:\r\n"), 0x80);
+        Notify(PSTR("bDescLength:\t\t"), 0x80);
+        PrintHex<uint8_t > (pDesc->bLength, 0x80);
+
+        Notify(PSTR("\r\nbDescriptorType:\t"), 0x80);
+        PrintHex<uint8_t > (pDesc->bDescriptorType, 0x80);
+
+        Notify(PSTR("\r\nbcdHID:\t\t\t"), 0x80);
+        PrintHex<uint16_t > (pDesc->bcdHID, 0x80);
+
+        Notify(PSTR("\r\nbCountryCode:\t\t"), 0x80);
+        PrintHex<uint8_t > (pDesc->bCountryCode, 0x80);
+
+        Notify(PSTR("\r\nbNumDescriptors:\t"), 0x80);
+        PrintHex<uint8_t > (pDesc->bNumDescriptors, 0x80);
+
+        for(uint8_t i = 0; i < pDesc->bNumDescriptors; i++) {
+                HID_CLASS_DESCRIPTOR_LEN_AND_TYPE *pLT = (HID_CLASS_DESCRIPTOR_LEN_AND_TYPE*)&(pDesc->bDescrType);
+
+                Notify(PSTR("\r\nbDescrType:\t\t"), 0x80);
+                PrintHex<uint8_t > (pLT[i].bDescrType, 0x80);
+
+                Notify(PSTR("\r\nwDescriptorLength:\t"), 0x80);
+                PrintHex<uint16_t > (pLT[i].wDescriptorLength, 0x80);
+        }
+        Notify(PSTR("\r\n"), 0x80);
+}
+
+
+#endif // __CONFDESCPARSER_H__
diff --git a/Marlin/src/sd/usb_flashdrive/lib/hexdump.h b/Marlin/src/sd/usb_flashdrive/lib/hexdump.h
new file mode 100644
index 0000000000..3cdb9e2a11
--- /dev/null
+++ b/Marlin/src/sd/usb_flashdrive/lib/hexdump.h
@@ -0,0 +1,69 @@
+/* Copyright (C) 2011 Circuits At Home, LTD. All rights reserved.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+Contact information
+-------------------
+
+Circuits At Home, LTD
+Web      :  http://www.circuitsathome.com
+e-mail   :  support@circuitsathome.com
+ */
+
+#if !defined(_usb_h_) || defined(__HEXDUMP_H__)
+#error "Never include hexdump.h directly; include Usb.h instead"
+#else
+#define __HEXDUMP_H__
+
+extern int UsbDEBUGlvl;
+
+template <class BASE_CLASS, class LEN_TYPE, class OFFSET_TYPE>
+class HexDumper : public BASE_CLASS {
+        uint8_t byteCount;
+        OFFSET_TYPE byteTotal;
+
+public:
+
+        HexDumper() : byteCount(0), byteTotal(0) {
+        };
+
+        void Initialize() {
+                byteCount = 0;
+                byteTotal = 0;
+        };
+
+        void Parse(const LEN_TYPE len, const uint8_t *pbuf, const OFFSET_TYPE &offset);
+};
+
+template <class BASE_CLASS, class LEN_TYPE, class OFFSET_TYPE>
+void HexDumper<BASE_CLASS, LEN_TYPE, OFFSET_TYPE>::Parse(const LEN_TYPE len, const uint8_t *pbuf, const OFFSET_TYPE &offset __attribute__((unused))) {
+        if(UsbDEBUGlvl >= 0x80) { // Fully bypass this block of code if we do not debug.
+                for(LEN_TYPE j = 0; j < len; j++, byteCount++, byteTotal++) {
+                        if(!byteCount) {
+                                PrintHex<OFFSET_TYPE > (byteTotal, 0x80);
+                                E_Notify(PSTR(": "), 0x80);
+                        }
+                        PrintHex<uint8_t > (pbuf[j], 0x80);
+                        E_Notify(PSTR(" "), 0x80);
+
+                        if(byteCount == 15) {
+                                E_Notify(PSTR("\r\n"), 0x80);
+                                byteCount = 0xFF;
+                        }
+                }
+        }
+}
+
+#endif // __HEXDUMP_H__
diff --git a/Marlin/src/sd/usb_flashdrive/lib/macros.h b/Marlin/src/sd/usb_flashdrive/lib/macros.h
new file mode 100644
index 0000000000..6df44e1c36
--- /dev/null
+++ b/Marlin/src/sd/usb_flashdrive/lib/macros.h
@@ -0,0 +1,89 @@
+/* Copyright (C) 2011 Circuits At Home, LTD. All rights reserved.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+Contact information
+-------------------
+
+Circuits At Home, LTD
+Web      :  http://www.circuitsathome.com
+e-mail   :  support@circuitsathome.com
+ */
+
+#ifndef _usb_h_
+  #error "Never include macros.h directly; include Usb.h instead"
+#endif
+
+#ifndef MACROS_H
+#define MACROS_H
+
+////////////////////////////////////////////////////////////////////////////////
+// HANDY MACROS
+////////////////////////////////////////////////////////////////////////////////
+
+#define VALUE_BETWEEN(v,l,h) (((v)>(l)) && ((v)<(h)))
+#define VALUE_WITHIN(v,l,h) (((v)>=(l)) && ((v)<=(h)))
+#define output_pgm_message(wa,fp,mp,el) wa = &mp, fp((char *)pgm_read_pointer(wa), el)
+#define output_if_between(v,l,h,wa,fp,mp,el) if(VALUE_BETWEEN(v,l,h)) output_pgm_message(wa,fp,mp[v-(l+1)],el);
+
+#define SWAP(a, b) (((a) ^= (b)), ((b) ^= (a)), ((a) ^= (b)))
+#ifndef __BYTE_GRABBING_DEFINED__
+#define __BYTE_GRABBING_DEFINED__ 1
+#ifdef BROKEN_OPTIMIZER_LITTLE_ENDIAN
+// Note: Use this if your compiler generates horrible assembler!
+#define BGRAB0(__usi__)  (((uint8_t *)&(__usi__))[0])
+#define BGRAB1(__usi__)  (((uint8_t *)&(__usi__))[1])
+#define BGRAB2(__usi__)  (((uint8_t *)&(__usi__))[2])
+#define BGRAB3(__usi__)  (((uint8_t *)&(__usi__))[3])
+#define BGRAB4(__usi__)  (((uint8_t *)&(__usi__))[4])
+#define BGRAB5(__usi__)  (((uint8_t *)&(__usi__))[5])
+#define BGRAB6(__usi__)  (((uint8_t *)&(__usi__))[6])
+#define BGRAB7(__usi__)  (((uint8_t *)&(__usi__))[7])
+#else
+// Note: The cast alone to uint8_t is actually enough.
+// GCC throws out the "& 0xff", and the size is no different.
+// Some compilers need it.
+#define BGRAB0(__usi__)  ((uint8_t)((__usi__) & 0xff ))
+#define BGRAB1(__usi__)  ((uint8_t)(((__usi__) >> 8) & 0xff))
+#define BGRAB2(__usi__)  ((uint8_t)(((__usi__) >> 16) & 0xff))
+#define BGRAB3(__usi__)  ((uint8_t)(((__usi__) >> 24) & 0xff))
+#define BGRAB4(__usi__)  ((uint8_t)(((__usi__) >> 32) & 0xff))
+#define BGRAB5(__usi__)  ((uint8_t)(((__usi__) >> 40) & 0xff))
+#define BGRAB6(__usi__)  ((uint8_t)(((__usi__) >> 48) & 0xff))
+#define BGRAB7(__usi__)  ((uint8_t)(((__usi__) >> 56) & 0xff))
+#endif
+#define BOVER1(__usi__)  ((uint16_t)(__usi__) << 8)
+#define BOVER2(__usi__)  ((uint32_t)(__usi__) << 16)
+#define BOVER3(__usi__)  ((uint32_t)(__usi__) << 24)
+#define BOVER4(__usi__)  ((uint64_t)(__usi__) << 32)
+#define BOVER5(__usi__)  ((uint64_t)(__usi__) << 40)
+#define BOVER6(__usi__)  ((uint64_t)(__usi__) << 48)
+#define BOVER7(__usi__)  ((uint64_t)(__usi__) << 56)
+
+// These are the smallest and fastest ways I have found so far in pure C/C++.
+#define BMAKE16(__usc1__,__usc0__) ((uint16_t)((uint16_t)(__usc0__) | (uint16_t)BOVER1(__usc1__)))
+#define BMAKE32(__usc3__,__usc2__,__usc1__,__usc0__) ((uint32_t)((uint32_t)(__usc0__) | (uint32_t)BOVER1(__usc1__) | (uint32_t)BOVER2(__usc2__) | (uint32_t)BOVER3(__usc3__)))
+#define BMAKE64(__usc7__,__usc6__,__usc5__,__usc4__,__usc3__,__usc2__,__usc1__,__usc0__) ((uint64_t)((uint64_t)__usc0__ | (uint64_t)BOVER1(__usc1__) | (uint64_t)BOVER2(__usc2__) | (uint64_t)BOVER3(__usc3__) | (uint64_t)BOVER4(__usc4__) | (uint64_t)BOVER5(__usc5__) | (uint64_t)BOVER6(__usc6__) | (uint64_t)BOVER1(__usc7__)))
+#endif
+
+/*
+ * Debug macros: Strings are stored in progmem (flash) instead of RAM.
+ */
+#define USBTRACE(s) (Notify(PSTR(s), 0x80))
+#define USBTRACE1(s,l) (Notify(PSTR(s), l))
+#define USBTRACE2(s,r) (Notify(PSTR(s), 0x80), D_PrintHex((r), 0x80), Notify(PSTR("\r\n"), 0x80))
+#define USBTRACE3(s,r,l) (Notify(PSTR(s), l), D_PrintHex((r), l), Notify(PSTR("\r\n"), l))
+
+#endif /* MACROS_H */
diff --git a/Marlin/src/sd/usb_flashdrive/lib/masstorage.cpp b/Marlin/src/sd/usb_flashdrive/lib/masstorage.cpp
new file mode 100644
index 0000000000..e139febf3d
--- /dev/null
+++ b/Marlin/src/sd/usb_flashdrive/lib/masstorage.cpp
@@ -0,0 +1,1282 @@
+/* Copyright (C) 2011 Circuits At Home, LTD. All rights reserved.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+Contact information
+-------------------
+
+Circuits At Home, LTD
+Web      :  http://www.circuitsathome.com
+e-mail   :  support@circuitsathome.com
+ */
+
+#include "../../../inc/MarlinConfigPre.h"
+
+#if ENABLED(USB_FLASH_DRIVE_SUPPORT)
+
+#include "masstorage.h"
+
+const uint8_t BulkOnly::epDataInIndex = 1;
+const uint8_t BulkOnly::epDataOutIndex = 2;
+const uint8_t BulkOnly::epInterruptInIndex = 3;
+
+////////////////////////////////////////////////////////////////////////////////
+
+// Interface code
+
+////////////////////////////////////////////////////////////////////////////////
+
+/**
+ * Get the capacity of the media
+ *
+ * @param lun Logical Unit Number
+ * @return media capacity
+ */
+uint32_t BulkOnly::GetCapacity(uint8_t lun) {
+        if(LUNOk[lun])
+                return CurrentCapacity[lun];
+        return 0LU;
+}
+
+/**
+ * Get the sector (block) size used on the media
+ *
+ * @param lun Logical Unit Number
+ * @return media sector size
+ */
+uint16_t BulkOnly::GetSectorSize(uint8_t lun) {
+        if(LUNOk[lun])
+                return CurrentSectorSize[lun];
+        return 0U;
+}
+
+/**
+ * Test if LUN is ready for use
+ *
+ * @param lun Logical Unit Number
+ * @return true if LUN is ready for use
+ */
+bool BulkOnly::LUNIsGood(uint8_t lun) {
+        return LUNOk[lun];
+}
+
+/**
+ * Test if LUN is write protected
+ *
+ * @param lun Logical Unit Number
+ * @return cached status of write protect switch
+ */
+bool BulkOnly::WriteProtected(uint8_t lun) {
+        return WriteOk[lun];
+}
+
+/**
+ * Wrap and execute a SCSI CDB with length of 6
+ *
+ * @param cdb CDB to execute
+ * @param buf_size Size of expected transaction
+ * @param buf Buffer
+ * @param dir MASS_CMD_DIR_IN | MASS_CMD_DIR_OUT
+ * @return
+ */
+uint8_t BulkOnly::SCSITransaction6(CDB6_t *cdb, uint16_t buf_size, void *buf, uint8_t dir) {
+        // promote buf_size to 32bits.
+        CommandBlockWrapper cbw = CommandBlockWrapper(++dCBWTag, (uint32_t)buf_size, cdb, dir);
+        //SetCurLUN(cdb->LUN);
+        return (HandleSCSIError(Transaction(&cbw, buf_size, buf)));
+}
+
+/**
+ * Wrap and execute a SCSI CDB with length of 10
+ *
+ * @param cdb CDB to execute
+ * @param buf_size Size of expected transaction
+ * @param buf Buffer
+ * @param dir MASS_CMD_DIR_IN | MASS_CMD_DIR_OUT
+ * @return
+ */
+uint8_t BulkOnly::SCSITransaction10(CDB10_t *cdb, uint16_t buf_size, void *buf, uint8_t dir) {
+        // promote buf_size to 32bits.
+        CommandBlockWrapper cbw = CommandBlockWrapper(++dCBWTag, (uint32_t)buf_size, cdb, dir);
+        //SetCurLUN(cdb->LUN);
+        return (HandleSCSIError(Transaction(&cbw, buf_size, buf)));
+}
+
+/**
+ * Lock or Unlock the tray or door on device.
+ * Caution: Some devices with buggy firmware will lock up.
+ *
+ * @param lun Logical Unit Number
+ * @param lock 1 to lock, 0 to unlock
+ * @return
+ */
+uint8_t BulkOnly::LockMedia(uint8_t lun, uint8_t lock) {
+        Notify(PSTR("\r\nLockMedia\r\n"), 0x80);
+        Notify(PSTR("---------\r\n"), 0x80);
+
+        CDB6_t cdb = CDB6_t(SCSI_CMD_PREVENT_REMOVAL, lun, (uint8_t)0, lock);
+        return SCSITransaction6(&cdb, (uint16_t)0, NULL, (uint8_t)MASS_CMD_DIR_IN);
+}
+
+/**
+ * Media control, for spindle motor and media tray or door.
+ * This includes CDROM, TAPE and anything with a media loader.
+ *
+ * @param lun Logical Unit Number
+ * @param ctl 0x00 Stop Motor, 0x01 Start Motor, 0x02 Eject Media, 0x03 Load Media
+ * @return 0 on success
+ */
+uint8_t BulkOnly::MediaCTL(uint8_t lun, uint8_t ctl) {
+        Notify(PSTR("\r\nMediaCTL\r\n"), 0x80);
+        Notify(PSTR("-----------------\r\n"), 0x80);
+
+        uint8_t rcode = MASS_ERR_UNIT_NOT_READY;
+        if(bAddress) {
+                CDB6_t cdb = CDB6_t(SCSI_CMD_START_STOP_UNIT, lun, ctl & 0x03, 0);
+                rcode = SCSITransaction6(&cdb, (uint16_t)0, NULL, (uint8_t)MASS_CMD_DIR_OUT);
+        } else {
+                SetCurLUN(lun);
+        }
+        return rcode;
+}
+
+/**
+ * Read data from media
+ *
+ * @param lun Logical Unit Number
+ * @param addr LBA address on media to read
+ * @param bsize size of a block (we should probably use the cached size)
+ * @param blocks how many blocks to read
+ * @param buf memory that is able to hold the requested data
+ * @return 0 on success
+ */
+uint8_t BulkOnly::Read(uint8_t lun, uint32_t addr, uint16_t bsize, uint8_t blocks, uint8_t *buf) {
+        if(!LUNOk[lun]) return MASS_ERR_NO_MEDIA;
+        Notify(PSTR("\r\nRead LUN:\t"), 0x80);
+        D_PrintHex<uint8_t > (lun, 0x90);
+        Notify(PSTR("\r\nLBA:\t\t"), 0x90);
+        D_PrintHex<uint32_t > (addr, 0x90);
+        Notify(PSTR("\r\nblocks:\t\t"), 0x90);
+        D_PrintHex<uint8_t > (blocks, 0x90);
+        Notify(PSTR("\r\nblock size:\t"), 0x90);
+        D_PrintHex<uint16_t > (bsize, 0x90);
+        Notify(PSTR("\r\n---------\r\n"), 0x80);
+        CDB10_t cdb = CDB10_t(SCSI_CMD_READ_10, lun, blocks, addr);
+
+again:
+        uint8_t er = SCSITransaction10(&cdb, ((uint16_t)bsize * blocks), buf, (uint8_t)MASS_CMD_DIR_IN);
+
+        if(er == MASS_ERR_STALL) {
+                MediaCTL(lun, 1);
+                delay(150);
+                if(!TestUnitReady(lun)) goto again;
+        }
+        return er;
+}
+
+/**
+ * Write data to media
+ *
+ * @param lun Logical Unit Number
+ * @param addr LBA address on media to write
+ * @param bsize size of a block (we should probably use the cached size)
+ * @param blocks how many blocks to write
+ * @param buf memory that contains the data to write
+ * @return 0 on success
+ */
+uint8_t BulkOnly::Write(uint8_t lun, uint32_t addr, uint16_t bsize, uint8_t blocks, const uint8_t * buf) {
+        if(!LUNOk[lun]) return MASS_ERR_NO_MEDIA;
+        if(!WriteOk[lun]) return MASS_ERR_WRITE_PROTECTED;
+        Notify(PSTR("\r\nWrite LUN:\t"), 0x80);
+        D_PrintHex<uint8_t > (lun, 0x90);
+        Notify(PSTR("\r\nLBA:\t\t"), 0x90);
+        D_PrintHex<uint32_t > (addr, 0x90);
+        Notify(PSTR("\r\nblocks:\t\t"), 0x90);
+        D_PrintHex<uint8_t > (blocks, 0x90);
+        Notify(PSTR("\r\nblock size:\t"), 0x90);
+        D_PrintHex<uint16_t > (bsize, 0x90);
+        Notify(PSTR("\r\n---------\r\n"), 0x80);
+        CDB10_t cdb = CDB10_t(SCSI_CMD_WRITE_10, lun, blocks, addr);
+
+again:
+        uint8_t er = SCSITransaction10(&cdb, ((uint16_t)bsize * blocks), (void*)buf, (uint8_t)MASS_CMD_DIR_OUT);
+
+        if(er == MASS_ERR_WRITE_STALL) {
+                MediaCTL(lun, 1);
+                delay(150);
+                if(!TestUnitReady(lun)) goto again;
+        }
+        return er;
+}
+
+// End of user functions, the remaining code below is driver internals.
+// Only developer serviceable parts below!
+
+////////////////////////////////////////////////////////////////////////////////
+
+// Main driver code
+
+////////////////////////////////////////////////////////////////////////////////
+
+BulkOnly::BulkOnly(USB *p) :
+pUsb(p),
+bAddress(0),
+bIface(0),
+bNumEP(1),
+qNextPollTime(0),
+bPollEnable(false),
+//dCBWTag(0),
+bLastUsbError(0) {
+        ClearAllEP();
+        dCBWTag = 0;
+        if(pUsb)
+                pUsb->RegisterDeviceClass(this);
+}
+
+/**
+ * USB_ERROR_CONFIG_REQUIRES_ADDITIONAL_RESET == success
+ * We need to standardize either the rcode, or change the API to return values
+ * so a signal that additional actions are required can be produced.
+ * Some of these codes do exist already.
+ *
+ * TECHNICAL: We could do most of this code elsewhere, with the exception of checking the class instance.
+ * Doing so would save some program memory when using multiple drivers.
+ *
+ * @param parent USB address of parent
+ * @param port address of port on parent
+ * @param lowspeed true if device is low speed
+ * @return
+ */
+uint8_t BulkOnly::ConfigureDevice(uint8_t parent, uint8_t port, bool lowspeed) {
+
+        const uint8_t constBufSize = sizeof (USB_DEVICE_DESCRIPTOR);
+
+        uint8_t buf[constBufSize];
+        USB_DEVICE_DESCRIPTOR * udd = reinterpret_cast<USB_DEVICE_DESCRIPTOR*>(buf);
+        uint8_t rcode;
+        UsbDevice *p = NULL;
+        EpInfo *oldep_ptr = NULL;
+        USBTRACE("MS ConfigureDevice\r\n");
+        ClearAllEP();
+        AddressPool &addrPool = pUsb->GetAddressPool();
+
+
+        if(bAddress)
+                return USB_ERROR_CLASS_INSTANCE_ALREADY_IN_USE;
+
+        // <TECHNICAL>
+        // Get pointer to pseudo device with address 0 assigned
+        p = addrPool.GetUsbDevicePtr(0);
+        if(!p) {
+                return USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL;
+        }
+
+        if(!p->epinfo) {
+                USBTRACE("epinfo\r\n");
+                return USB_ERROR_EPINFO_IS_NULL;
+        }
+
+        // Save old pointer to EP_RECORD of address 0
+        oldep_ptr = p->epinfo;
+
+        // Temporary assign new pointer to epInfo to p->epinfo in order to avoid toggle inconsistence
+        p->epinfo = epInfo;
+
+        p->lowspeed = lowspeed;
+        // Get device descriptor
+        rcode = pUsb->getDevDescr(0, 0, constBufSize, (uint8_t*)buf);
+
+        // Restore p->epinfo
+        p->epinfo = oldep_ptr;
+
+        if(rcode) {
+                goto FailGetDevDescr;
+        }
+        // Allocate new address according to device class
+        bAddress = addrPool.AllocAddress(parent, false, port);
+
+        if(!bAddress)
+                return USB_ERROR_OUT_OF_ADDRESS_SPACE_IN_POOL;
+
+        // Extract Max Packet Size from the device descriptor
+        epInfo[0].maxPktSize = udd->bMaxPacketSize0;
+        // Steal and abuse from epInfo structure to save on memory.
+        epInfo[1].epAddr = udd->bNumConfigurations;
+        // </TECHNICAL>
+        return USB_ERROR_CONFIG_REQUIRES_ADDITIONAL_RESET;
+
+FailGetDevDescr:
+#ifdef DEBUG_USB_HOST
+        NotifyFailGetDevDescr(rcode);
+#endif
+        rcode = USB_ERROR_FailGetDevDescr;
+
+        Release();
+        return rcode;
+};
+
+/**
+ *
+ * @param parent (not used)
+ * @param port (not used)
+ * @param lowspeed true if device is low speed
+ * @return 0 for success
+ */
+uint8_t BulkOnly::Init(uint8_t parent __attribute__((unused)), uint8_t port __attribute__((unused)), bool lowspeed) {
+        uint8_t rcode;
+        uint8_t num_of_conf = epInfo[1].epAddr; // number of configurations
+        epInfo[1].epAddr = 0;
+        USBTRACE("MS Init\r\n");
+
+        AddressPool &addrPool = pUsb->GetAddressPool();
+        UsbDevice *p = addrPool.GetUsbDevicePtr(bAddress);
+
+        if(!p)
+                return USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL;
+
+        // Assign new address to the device
+        delay(2000);
+        rcode = pUsb->setAddr(0, 0, bAddress);
+
+        if(rcode) {
+                p->lowspeed = false;
+                addrPool.FreeAddress(bAddress);
+                bAddress = 0;
+                USBTRACE2("setAddr:", rcode);
+                return rcode;
+        }
+
+        USBTRACE2("Addr:", bAddress);
+
+        p->lowspeed = false;
+
+        p = addrPool.GetUsbDevicePtr(bAddress);
+
+        if(!p)
+                return USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL;
+
+        p->lowspeed = lowspeed;
+
+        // Assign epInfo to epinfo pointer
+        rcode = pUsb->setEpInfoEntry(bAddress, 1, epInfo);
+
+        if(rcode)
+                goto FailSetDevTblEntry;
+
+        USBTRACE2("NC:", num_of_conf);
+
+        for(uint8_t i = 0; i < num_of_conf; i++) {
+                ConfigDescParser< USB_CLASS_MASS_STORAGE,
+                        MASS_SUBCLASS_SCSI,
+                        MASS_PROTO_BBB,
+                        CP_MASK_COMPARE_CLASS |
+                        CP_MASK_COMPARE_SUBCLASS |
+                        CP_MASK_COMPARE_PROTOCOL > BulkOnlyParser(this);
+
+                rcode = pUsb->getConfDescr(bAddress, 0, i, &BulkOnlyParser);
+
+                if(rcode)
+                        goto FailGetConfDescr;
+
+                if(bNumEP > 1)
+                        break;
+        }
+
+        if(bNumEP < 3)
+                return USB_DEV_CONFIG_ERROR_DEVICE_NOT_SUPPORTED;
+
+        // Assign epInfo to epinfo pointer
+        pUsb->setEpInfoEntry(bAddress, bNumEP, epInfo);
+
+        USBTRACE2("Conf:", bConfNum);
+
+        // Set Configuration Value
+        rcode = pUsb->setConf(bAddress, 0, bConfNum);
+
+        if(rcode)
+                goto FailSetConfDescr;
+
+        //Linux does a 1sec delay after this.
+        delay(1000);
+
+        rcode = GetMaxLUN(&bMaxLUN);
+        if(rcode)
+                goto FailGetMaxLUN;
+
+        if(bMaxLUN >= MASS_MAX_SUPPORTED_LUN) bMaxLUN = MASS_MAX_SUPPORTED_LUN - 1;
+        ErrorMessage<uint8_t > (PSTR("MaxLUN"), bMaxLUN);
+
+        delay(1000); // Delay a bit for slow firmware.
+
+        for(uint8_t lun = 0; lun <= bMaxLUN; lun++) {
+                InquiryResponse response;
+                rcode = Inquiry(lun, sizeof (InquiryResponse), (uint8_t*) & response);
+                if(rcode) {
+                        ErrorMessage<uint8_t > (PSTR("Inquiry"), rcode);
+                } else {
+#if 0
+                        printf("LUN %i `", lun);
+                        uint8_t *buf = response.VendorID;
+                        for(int i = 0; i < 28; i++) printf("%c", buf[i]);
+                        printf("'\r\nQualifier %1.1X ", response.PeripheralQualifier);
+                        printf("Device type %2.2X ", response.DeviceType);
+                        printf("RMB %1.1X ", response.Removable);
+                        printf("SSCS %1.1X ", response.SCCS);
+                        uint8_t sv = response.Version;
+                        printf("SCSI version %2.2X\r\nDevice conforms to ", sv);
+                        switch(sv) {
+                                case 0:
+                                        printf("No specific");
+                                        break;
+                                case 1:
+                                        printf("ANSI X3.131-1986 (ANSI 1)");
+                                        break;
+                                case 2:
+                                        printf("ANSI X3.131-1994 (ANSI 2)");
+                                        break;
+                                case 3:
+                                        printf("ANSI INCITS 301-1997 (SPC)");
+                                        break;
+                                case 4:
+                                        printf("ANSI INCITS 351-2001 (SPC-2)");
+                                        break;
+                                case 5:
+                                        printf("ANSI INCITS 408-2005 (SPC-4)");
+                                        break;
+                                case 6:
+                                        printf("T10/1731-D (SPC-4)");
+                                        break;
+                                default:
+                                        printf("unknown");
+                        }
+                        printf(" standards.\r\n");
+#endif
+                        uint8_t tries = 0xf0;
+                        while((rcode = TestUnitReady(lun))) {
+                                if(rcode == 0x08) break; // break on no media, this is OK to do.
+                                // try to lock media and spin up
+                                if(tries < 14) {
+                                        LockMedia(lun, 1);
+                                        MediaCTL(lun, 1); // I actually have a USB stick that needs this!
+                                } else delay(2 * (tries + 1));
+                                tries++;
+                                if(!tries) break;
+                        }
+                        if(!rcode) {
+                                delay(1000);
+                                LUNOk[lun] = CheckLUN(lun);
+                                if(!LUNOk[lun]) LUNOk[lun] = CheckLUN(lun);
+                        }
+                }
+        }
+
+
+        CheckMedia();
+
+        rcode = OnInit();
+
+        if(rcode)
+                goto FailOnInit;
+
+#ifdef DEBUG_USB_HOST
+        USBTRACE("MS configured\r\n\r\n");
+#endif
+
+        bPollEnable = true;
+
+        //USBTRACE("Poll enabled\r\n");
+        return 0;
+
+FailSetConfDescr:
+#ifdef DEBUG_USB_HOST
+        NotifyFailSetConfDescr();
+        goto Fail;
+#endif
+
+FailOnInit:
+#ifdef DEBUG_USB_HOST
+        USBTRACE("OnInit:");
+        goto Fail;
+#endif
+
+FailGetMaxLUN:
+#ifdef DEBUG_USB_HOST
+        USBTRACE("GetMaxLUN:");
+        goto Fail;
+#endif
+
+        //#ifdef DEBUG_USB_HOST
+        //FailInvalidSectorSize:
+        //        USBTRACE("Sector Size is NOT VALID: ");
+        //        goto Fail;
+        //#endif
+
+FailSetDevTblEntry:
+#ifdef DEBUG_USB_HOST
+        NotifyFailSetDevTblEntry();
+        goto Fail;
+#endif
+
+FailGetConfDescr:
+#ifdef DEBUG_USB_HOST
+        NotifyFailGetConfDescr();
+#endif
+
+#ifdef DEBUG_USB_HOST
+Fail:
+        NotifyFail(rcode);
+#endif
+        Release();
+        return rcode;
+}
+
+/**
+ * For driver use only.
+ *
+ * @param conf
+ * @param iface
+ * @param alt
+ * @param proto
+ * @param pep
+ */
+void BulkOnly::EndpointXtract(uint8_t conf, uint8_t iface, uint8_t alt, uint8_t proto __attribute__((unused)), const USB_ENDPOINT_DESCRIPTOR * pep) {
+        ErrorMessage<uint8_t > (PSTR("Conf.Val"), conf);
+        ErrorMessage<uint8_t > (PSTR("Iface Num"), iface);
+        ErrorMessage<uint8_t > (PSTR("Alt.Set"), alt);
+
+        bConfNum = conf;
+
+        uint8_t index;
+
+#if 1
+        if((pep->bmAttributes & bmUSB_TRANSFER_TYPE) == USB_TRANSFER_TYPE_BULK) {
+                index = ((pep->bEndpointAddress & 0x80) == 0x80) ? epDataInIndex : epDataOutIndex;
+                // Fill in the endpoint info structure
+                epInfo[index].epAddr = (pep->bEndpointAddress & 0x0F);
+                epInfo[index].maxPktSize = (uint8_t)pep->wMaxPacketSize;
+                epInfo[index].bmSndToggle = 0;
+                epInfo[index].bmRcvToggle = 0;
+
+                bNumEP++;
+
+                PrintEndpointDescriptor(pep);
+
+        }
+#else
+        if((pep->bmAttributes & bmUSB_TRANSFER_TYPE) == USB_TRANSFER_TYPE_INTERRUPT && (pep->bEndpointAddress & 0x80) == 0x80)
+                index = epInterruptInIndex;
+        else if((pep->bmAttributes & bmUSB_TRANSFER_TYPE) == USB_TRANSFER_TYPE_BULK)
+                index = ((pep->bEndpointAddress & 0x80) == 0x80) ? epDataInIndex : epDataOutIndex;
+        else
+                return;
+
+        // Fill in the endpoint info structure
+        epInfo[index].epAddr = (pep->bEndpointAddress & 0x0F);
+        epInfo[index].maxPktSize = (uint8_t)pep->wMaxPacketSize;
+        epInfo[index].bmSndToggle = 0;
+        epInfo[index].bmRcvToggle = 0;
+
+        bNumEP++;
+
+        PrintEndpointDescriptor(pep);
+#endif
+}
+
+/**
+ * For driver use only.
+ *
+ * @return
+ */
+uint8_t BulkOnly::Release() {
+        ClearAllEP();
+        pUsb->GetAddressPool().FreeAddress(bAddress);
+        return 0;
+}
+
+/**
+ * For driver use only.
+ *
+ * @param lun Logical Unit Number
+ * @return true if LUN is ready for use.
+ */
+bool BulkOnly::CheckLUN(uint8_t lun) {
+        uint8_t rcode;
+        Capacity capacity;
+        for(uint8_t i = 0; i < 8; i++) capacity.data[i] = 0;
+
+        rcode = ReadCapacity10(lun, (uint8_t*)capacity.data);
+        if(rcode) {
+                //printf(">>>>>>>>>>>>>>>>ReadCapacity returned %i\r\n", rcode);
+                return false;
+        }
+        ErrorMessage<uint8_t > (PSTR(">>>>>>>>>>>>>>>>CAPACITY OK ON LUN"), lun);
+        for(uint8_t i = 0; i < 8 /*sizeof (Capacity)*/; i++)
+                D_PrintHex<uint8_t > (capacity.data[i], 0x80);
+        Notify(PSTR("\r\n\r\n"), 0x80);
+        // Only 512/1024/2048/4096 are valid values!
+        uint32_t c = BMAKE32(capacity.data[4], capacity.data[5], capacity.data[6], capacity.data[7]);
+        if(c != 0x0200LU && c != 0x0400LU && c != 0x0800LU && c != 0x1000LU) {
+                return false;
+        }
+        // Store capacity information.
+        CurrentSectorSize[lun] = (uint16_t)(c); // & 0xFFFF);
+
+        CurrentCapacity[lun] = BMAKE32(capacity.data[0], capacity.data[1], capacity.data[2], capacity.data[3]) + 1;
+        if(CurrentCapacity[lun] == /*0xffffffffLU */ 0x01LU || CurrentCapacity[lun] == 0x00LU) {
+                // Buggy firmware will report 0xffffffff or 0 for no media
+                if(CurrentCapacity[lun])
+                        ErrorMessage<uint8_t > (PSTR(">>>>>>>>>>>>>>>>BUGGY FIRMWARE. CAPACITY FAIL ON LUN"), lun);
+                return false;
+        }
+        delay(20);
+        Page3F(lun);
+        if(!TestUnitReady(lun)) return true;
+        return false;
+}
+
+/**
+ * For driver use only.
+ *
+ * Scan for media change on all LUNs
+ */
+void BulkOnly::CheckMedia() {
+        for(uint8_t lun = 0; lun <= bMaxLUN; lun++) {
+                if(TestUnitReady(lun)) {
+                        LUNOk[lun] = false;
+                        continue;
+                }
+                if(!LUNOk[lun])
+                        LUNOk[lun] = CheckLUN(lun);
+        }
+#if 0
+        printf("}}}}}}}}}}}}}}}}STATUS ");
+        for(uint8_t lun = 0; lun <= bMaxLUN; lun++) {
+                if(LUNOk[lun])
+                        printf("#");
+                else printf(".");
+        }
+        printf("\r\n");
+#endif
+        qNextPollTime = (uint32_t)millis() + 2000;
+}
+
+/**
+ * For driver use only.
+ *
+ * @return
+ */
+uint8_t BulkOnly::Poll() {
+        //uint8_t rcode = 0;
+
+        if(!bPollEnable)
+                return 0;
+
+        if((int32_t)((uint32_t)millis() - qNextPollTime) >= 0L) {
+                CheckMedia();
+        }
+        //rcode = 0;
+
+        return 0;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+
+// SCSI code
+
+
+////////////////////////////////////////////////////////////////////////////////
+
+/**
+ * For driver use only.
+ *
+ * @param plun
+ * @return
+ */
+uint8_t BulkOnly::GetMaxLUN(uint8_t *plun) {
+        uint8_t ret = pUsb->ctrlReq(bAddress, 0, bmREQ_MASSIN, MASS_REQ_GET_MAX_LUN, 0, 0, bIface, 1, 1, plun, NULL);
+
+        if(ret == hrSTALL)
+                *plun = 0;
+
+        return 0;
+}
+
+/**
+ * For driver use only. Used during Driver Init
+ *
+ * @param lun Logical Unit Number
+ * @param bsize
+ * @param buf
+ * @return
+ */
+uint8_t BulkOnly::Inquiry(uint8_t lun, uint16_t bsize, uint8_t *buf) {
+        Notify(PSTR("\r\nInquiry\r\n"), 0x80);
+        Notify(PSTR("---------\r\n"), 0x80);
+
+        CDB6_t cdb = CDB6_t(SCSI_CMD_INQUIRY, lun, 0LU, (uint8_t)bsize, 0);
+        uint8_t rc = SCSITransaction6(&cdb, bsize, buf, (uint8_t)MASS_CMD_DIR_IN);
+
+        return rc;
+}
+
+/**
+ * For driver use only.
+ *
+ * @param lun Logical Unit Number
+ * @return
+ */
+uint8_t BulkOnly::TestUnitReady(uint8_t lun) {
+        //SetCurLUN(lun);
+        if(!bAddress)
+                return MASS_ERR_UNIT_NOT_READY;
+
+        Notify(PSTR("\r\nTestUnitReady\r\n"), 0x80);
+        Notify(PSTR("-----------------\r\n"), 0x80);
+
+        CDB6_t cdb = CDB6_t(SCSI_CMD_TEST_UNIT_READY, lun, (uint8_t)0, 0);
+        return SCSITransaction6(&cdb, 0, NULL, (uint8_t)MASS_CMD_DIR_IN);
+
+}
+
+/**
+ * For driver use only.
+ *
+ * @param lun Logical Unit Number
+ * @param pc
+ * @param page
+ * @param subpage
+ * @param len
+ * @param pbuf
+ * @return
+ */
+uint8_t BulkOnly::ModeSense6(uint8_t lun, uint8_t pc, uint8_t page, uint8_t subpage, uint8_t len, uint8_t * pbuf) {
+        Notify(PSTR("\r\rModeSense\r\n"), 0x80);
+        Notify(PSTR("------------\r\n"), 0x80);
+
+        CDB6_t cdb = CDB6_t(SCSI_CMD_MODE_SENSE_6, lun, (uint32_t)((((pc << 6) | page) << 8) | subpage), len, 0);
+        return SCSITransaction6(&cdb, len, pbuf, (uint8_t)MASS_CMD_DIR_IN);
+}
+
+/**
+ * For driver use only.
+ *
+ * @param lun Logical Unit Number
+ * @param bsize
+ * @param buf
+ * @return
+ */
+uint8_t BulkOnly::ReadCapacity10(uint8_t lun, uint8_t *buf) {
+        Notify(PSTR("\r\nReadCapacity\r\n"), 0x80);
+        Notify(PSTR("---------------\r\n"), 0x80);
+
+        CDB10_t cdb = CDB10_t(SCSI_CMD_READ_CAPACITY_10, lun);
+        return SCSITransaction10(&cdb, 8, buf, (uint8_t)MASS_CMD_DIR_IN);
+}
+
+/**
+ * For driver use only.
+ *
+ * Page 3F contains write protect status.
+ *
+ * @param lun Logical Unit Number to test.
+ * @return Write protect switch status.
+ */
+uint8_t BulkOnly::Page3F(uint8_t lun) {
+        uint8_t buf[192];
+        for(int i = 0; i < 192; i++) {
+                buf[i] = 0x00;
+        }
+        WriteOk[lun] = true;
+        #if ENABLED(USB_FLASH_DRIVE_SUPPORT) && defined(SKIP_WRITE_PROTECT)
+          return 0;
+        #endif
+        uint8_t rc = ModeSense6(lun, 0, 0x3f, 0, 192, buf);
+        if(!rc) {
+                WriteOk[lun] = ((buf[2] & 0x80) == 0);
+                Notify(PSTR("Mode Sense: "), 0x80);
+                for(int i = 0; i < 4; i++) {
+                        D_PrintHex<uint8_t > (buf[i], 0x80);
+                        Notify(PSTR(" "), 0x80);
+                }
+                Notify(PSTR("\r\n"), 0x80);
+        }
+        return rc;
+}
+
+/**
+ * For driver use only.
+ *
+ * @param lun Logical Unit Number
+ * @param size
+ * @param buf
+ * @return
+ */
+uint8_t BulkOnly::RequestSense(uint8_t lun, uint16_t size, uint8_t *buf) {
+        Notify(PSTR("\r\nRequestSense\r\n"), 0x80);
+        Notify(PSTR("----------------\r\n"), 0x80);
+
+        CDB6_t cdb = CDB6_t(SCSI_CMD_REQUEST_SENSE, lun, 0LU, (uint8_t)size, 0);
+        CommandBlockWrapper cbw = CommandBlockWrapper(++dCBWTag, (uint32_t)size, &cdb, (uint8_t)MASS_CMD_DIR_IN);
+        //SetCurLUN(lun);
+        return Transaction(&cbw, size, buf);
+}
+
+
+////////////////////////////////////////////////////////////////////////////////
+
+
+// USB code
+
+
+////////////////////////////////////////////////////////////////////////////////
+
+/**
+ * For driver use only.
+ *
+ * @param index
+ * @return
+ */
+uint8_t BulkOnly::ClearEpHalt(uint8_t index) {
+        if(index == 0)
+                return 0;
+
+        uint8_t ret = 0;
+
+        while((ret = (pUsb->ctrlReq(bAddress, 0, USB_SETUP_HOST_TO_DEVICE | USB_SETUP_TYPE_STANDARD | USB_SETUP_RECIPIENT_ENDPOINT, USB_REQUEST_CLEAR_FEATURE, USB_FEATURE_ENDPOINT_HALT, 0, ((index == epDataInIndex) ? (0x80 | epInfo[index].epAddr) : epInfo[index].epAddr), 0, 0, NULL, NULL)) == 0x01))
+                delay(6);
+
+        if(ret) {
+                ErrorMessage<uint8_t > (PSTR("ClearEpHalt"), ret);
+                ErrorMessage<uint8_t > (PSTR("EP"), ((index == epDataInIndex) ? (0x80 | epInfo[index].epAddr) : epInfo[index].epAddr));
+                return ret;
+        }
+        epInfo[index].bmSndToggle = 0;
+        epInfo[index].bmRcvToggle = 0;
+        return 0;
+}
+
+/**
+ * For driver use only.
+ *
+ */
+void BulkOnly::Reset() {
+        while(pUsb->ctrlReq(bAddress, 0, bmREQ_MASSOUT, MASS_REQ_BOMSR, 0, 0, bIface, 0, 0, NULL, NULL) == 0x01) delay(6);
+}
+
+/**
+ * For driver use only.
+ *
+ * @return 0 if successful
+ */
+uint8_t BulkOnly::ResetRecovery() {
+        Notify(PSTR("\r\nResetRecovery\r\n"), 0x80);
+        Notify(PSTR("-----------------\r\n"), 0x80);
+
+        delay(6);
+        Reset();
+        delay(6);
+        ClearEpHalt(epDataInIndex);
+        delay(6);
+        bLastUsbError = ClearEpHalt(epDataOutIndex);
+        delay(6);
+        return bLastUsbError;
+}
+
+/**
+ * For driver use only.
+ *
+ * Clear all EP data and clear all LUN status
+ */
+void BulkOnly::ClearAllEP() {
+        for(uint8_t i = 0; i < MASS_MAX_ENDPOINTS; i++) {
+                epInfo[i].epAddr = 0;
+                epInfo[i].maxPktSize = (i) ? 0 : 8;
+                epInfo[i].bmSndToggle = 0;
+                epInfo[i].bmRcvToggle = 0;
+                epInfo[i].bmNakPower = USB_NAK_DEFAULT;
+        }
+
+        for(uint8_t i = 0; i < MASS_MAX_SUPPORTED_LUN; i++) {
+                LUNOk[i] = false;
+                WriteOk[i] = false;
+                CurrentCapacity[i] = 0lu;
+                CurrentSectorSize[i] = 0;
+        }
+
+        bIface = 0;
+        bNumEP = 1;
+        bAddress = 0;
+        qNextPollTime = 0;
+        bPollEnable = false;
+        bLastUsbError = 0;
+        bMaxLUN = 0;
+        bTheLUN = 0;
+}
+
+/**
+ * For driver use only.
+ *
+ * @param pcsw
+ * @param pcbw
+ * @return
+ */
+bool BulkOnly::IsValidCSW(CommandStatusWrapper *pcsw, CommandBlockWrapperBase *pcbw) {
+        if(pcsw->dCSWSignature != MASS_CSW_SIGNATURE) {
+                Notify(PSTR("CSW:Sig error\r\n"), 0x80);
+                return false;
+        }
+        if(pcsw->dCSWTag != pcbw->dCBWTag) {
+                Notify(PSTR("CSW:Wrong tag\r\n"), 0x80);
+                return false;
+        }
+        return true;
+}
+
+/**
+ * For driver use only.
+ *
+ * @param error
+ * @param index
+ * @return
+ */
+uint8_t BulkOnly::HandleUsbError(uint8_t error, uint8_t index) {
+        uint8_t count = 3;
+
+        bLastUsbError = error;
+        //if (error)
+        //ClearEpHalt(index);
+        while(error && count) {
+                if(error != hrSUCCESS) {
+                        ErrorMessage<uint8_t > (PSTR("USB Error"), error);
+                        ErrorMessage<uint8_t > (PSTR("Index"), index);
+                }
+                switch(error) {
+                                // case hrWRONGPID:
+                        case hrSUCCESS:
+                                return MASS_ERR_SUCCESS;
+                        case hrBUSY:
+                                // SIE is busy, just hang out and try again.
+                                return MASS_ERR_UNIT_BUSY;
+                        case hrTIMEOUT:
+                        case hrJERR: return MASS_ERR_DEVICE_DISCONNECTED;
+                        case hrSTALL:
+                                if(index == 0)
+                                        return MASS_ERR_STALL;
+                                ClearEpHalt(index);
+                                if(index != epDataInIndex)
+                                        return MASS_ERR_WRITE_STALL;
+                                return MASS_ERR_STALL;
+
+                        case hrNAK:
+                                if(index == 0)
+                                        return MASS_ERR_UNIT_BUSY;
+                                return MASS_ERR_UNIT_BUSY;
+
+                        case hrTOGERR:
+                                // Handle a very super rare corner case, where toggles become de-synched.
+                                // I have only ran into one device that has this firmware bug, and this is
+                                // the only clean way to get back into sync with the buggy device firmware.
+                                //   --AJK
+                                if(bAddress && bConfNum) {
+                                        error = pUsb->setConf(bAddress, 0, bConfNum);
+
+                                        if(error)
+                                                break;
+                                }
+                                return MASS_ERR_SUCCESS;
+                        default:
+                                ErrorMessage<uint8_t > (PSTR("\r\nUSB"), error);
+                                return MASS_ERR_GENERAL_USB_ERROR;
+                }
+                count--;
+        } // while
+
+        return ((error && !count) ? MASS_ERR_GENERAL_USB_ERROR : MASS_ERR_SUCCESS);
+}
+
+#if MS_WANT_PARSER
+
+uint8_t BulkOnly::Transaction(CommandBlockWrapper *pcbw, uint16_t buf_size, void *buf) {
+        return Transaction(CommandBlockWrapper *pcbw, uint16_t buf_size, void *buf, 0);
+}
+#endif
+
+/**
+ * For driver use only.
+ *
+ * @param pcbw
+ * @param buf_size
+ * @param buf
+ * @param flags
+ * @return
+ */
+uint8_t BulkOnly::Transaction(CommandBlockWrapper *pcbw, uint16_t buf_size, void *buf
+#if MS_WANT_PARSER
+        , uint8_t flags
+#endif
+        ) {
+
+#if MS_WANT_PARSER
+        uint16_t bytes = (pcbw->dCBWDataTransferLength > buf_size) ? buf_size : pcbw->dCBWDataTransferLength;
+        printf("Transfersize %i\r\n", bytes);
+        delay(1000);
+
+        bool callback = (flags & MASS_TRANS_FLG_CALLBACK) == MASS_TRANS_FLG_CALLBACK;
+#else
+        uint16_t bytes = buf_size;
+#endif
+        bool write = (pcbw->bmCBWFlags & MASS_CMD_DIR_IN) != MASS_CMD_DIR_IN;
+        uint8_t ret = 0;
+        uint8_t usberr;
+        CommandStatusWrapper csw; // up here, we allocate ahead to save cpu cycles.
+        SetCurLUN(pcbw->bmCBWLUN);
+        ErrorMessage<uint32_t > (PSTR("CBW.dCBWTag"), pcbw->dCBWTag);
+
+        while((usberr = pUsb->outTransfer(bAddress, epInfo[epDataOutIndex].epAddr, sizeof (CommandBlockWrapper), (uint8_t*)pcbw)) == hrBUSY) delay(1);
+
+        ret = HandleUsbError(usberr, epDataOutIndex);
+        //ret = HandleUsbError(pUsb->outTransfer(bAddress, epInfo[epDataOutIndex].epAddr, sizeof (CommandBlockWrapper), (uint8_t*)pcbw), epDataOutIndex);
+        if(ret) {
+                ErrorMessage<uint8_t > (PSTR("============================ CBW"), ret);
+        } else {
+                if(bytes) {
+                        if(!write) {
+#if MS_WANT_PARSER
+                                if(callback) {
+                                        uint8_t rbuf[bytes];
+                                        while((usberr = pUsb->inTransfer(bAddress, epInfo[epDataInIndex].epAddr, &bytes, rbuf)) == hrBUSY) delay(1);
+                                        if(usberr == hrSUCCESS) ((USBReadParser*)buf)->Parse(bytes, rbuf, 0);
+                                } else {
+#endif
+                                        while((usberr = pUsb->inTransfer(bAddress, epInfo[epDataInIndex].epAddr, &bytes, (uint8_t*)buf)) == hrBUSY) delay(1);
+#if MS_WANT_PARSER
+
+                                }
+#endif
+                                ret = HandleUsbError(usberr, epDataInIndex);
+                        } else {
+                                while((usberr = pUsb->outTransfer(bAddress, epInfo[epDataOutIndex].epAddr, bytes, (uint8_t*)buf)) == hrBUSY) delay(1);
+                                ret = HandleUsbError(usberr, epDataOutIndex);
+                        }
+                        if(ret) {
+                                ErrorMessage<uint8_t > (PSTR("============================ DAT"), ret);
+                        }
+                }
+        }
+
+        {
+                bytes = sizeof (CommandStatusWrapper);
+                int tries = 2;
+                while(tries--) {
+                        while((usberr = pUsb->inTransfer(bAddress, epInfo[epDataInIndex].epAddr, &bytes, (uint8_t*) & csw)) == hrBUSY) delay(1);
+                        if(!usberr) break;
+                        ClearEpHalt(epDataInIndex);
+                        if(tries) ResetRecovery();
+                }
+                if(!ret) {
+                        Notify(PSTR("CBW:\t\tOK\r\n"), 0x80);
+                        Notify(PSTR("Data Stage:\tOK\r\n"), 0x80);
+                } else {
+                        // Throw away csw, IT IS NOT OF ANY USE.
+                        ResetRecovery();
+                        return ret;
+                }
+                ret = HandleUsbError(usberr, epDataInIndex);
+                if(ret) {
+                        ErrorMessage<uint8_t > (PSTR("============================ CSW"), ret);
+                }
+                if(usberr == hrSUCCESS) {
+                        if(IsValidCSW(&csw, pcbw)) {
+                                //ErrorMessage<uint32_t > (PSTR("CSW.dCBWTag"), csw.dCSWTag);
+                                //ErrorMessage<uint8_t > (PSTR("bCSWStatus"), csw.bCSWStatus);
+                                //ErrorMessage<uint32_t > (PSTR("dCSWDataResidue"), csw.dCSWDataResidue);
+                                Notify(PSTR("CSW:\t\tOK\r\n\r\n"), 0x80);
+                                return csw.bCSWStatus;
+                        } else {
+                                // NOTE! Sometimes this is caused by the reported residue being wrong.
+                                // Get a different device. It isn't compliant, and should have never passed Q&A.
+                                // I own one... 05e3:0701 Genesys Logic, Inc. USB 2.0 IDE Adapter.
+                                // Other devices that exhibit this behavior exist in the wild too.
+                                // Be sure to check quirks in the Linux source code before reporting a bug. --xxxajk
+                                Notify(PSTR("Invalid CSW\r\n"), 0x80);
+                                ResetRecovery();
+                                //return MASS_ERR_SUCCESS;
+                                return MASS_ERR_INVALID_CSW;
+                        }
+                }
+        }
+        return ret;
+}
+
+/**
+ * For driver use only.
+ *
+ * @param lun Logical Unit Number
+ * @return
+ */
+uint8_t BulkOnly::SetCurLUN(uint8_t lun) {
+        if(lun > bMaxLUN)
+                return MASS_ERR_INVALID_LUN;
+        bTheLUN = lun;
+        return MASS_ERR_SUCCESS;
+};
+
+/**
+ * For driver use only.
+ *
+ * @param status
+ * @return
+ */
+uint8_t BulkOnly::HandleSCSIError(uint8_t status) {
+        uint8_t ret = 0;
+
+        switch(status) {
+                case 0: return MASS_ERR_SUCCESS;
+
+                case 2:
+                        ErrorMessage<uint8_t > (PSTR("Phase Error"), status);
+                        ErrorMessage<uint8_t > (PSTR("LUN"), bTheLUN);
+                        ResetRecovery();
+                        return MASS_ERR_GENERAL_SCSI_ERROR;
+
+                case 1:
+                        ErrorMessage<uint8_t > (PSTR("SCSI Error"), status);
+                        ErrorMessage<uint8_t > (PSTR("LUN"), bTheLUN);
+                        RequestSenseResponce rsp;
+
+                        ret = RequestSense(bTheLUN, sizeof (RequestSenseResponce), (uint8_t*) & rsp);
+
+                        if(ret) {
+                                return MASS_ERR_GENERAL_SCSI_ERROR;
+                        }
+                        ErrorMessage<uint8_t > (PSTR("Response Code"), rsp.bResponseCode);
+                        if(rsp.bResponseCode & 0x80) {
+                                Notify(PSTR("Information field: "), 0x80);
+                                for(int i = 0; i < 4; i++) {
+                                        D_PrintHex<uint8_t > (rsp.CmdSpecificInformation[i], 0x80);
+                                        Notify(PSTR(" "), 0x80);
+                                }
+                                Notify(PSTR("\r\n"), 0x80);
+                        }
+                        ErrorMessage<uint8_t > (PSTR("Sense Key"), rsp.bmSenseKey);
+                        ErrorMessage<uint8_t > (PSTR("Add Sense Code"), rsp.bAdditionalSenseCode);
+                        ErrorMessage<uint8_t > (PSTR("Add Sense Qual"), rsp.bAdditionalSenseQualifier);
+                        // warning, this is not testing ASQ, only SK and ASC.
+                        switch(rsp.bmSenseKey) {
+                                case SCSI_S_UNIT_ATTENTION:
+                                        switch(rsp.bAdditionalSenseCode) {
+                                                case SCSI_ASC_MEDIA_CHANGED:
+                                                        return MASS_ERR_MEDIA_CHANGED;
+                                                default:
+                                                        return MASS_ERR_UNIT_NOT_READY;
+                                        }
+                                case SCSI_S_NOT_READY:
+                                        switch(rsp.bAdditionalSenseCode) {
+                                                case SCSI_ASC_MEDIUM_NOT_PRESENT:
+                                                        return MASS_ERR_NO_MEDIA;
+                                                default:
+                                                        return MASS_ERR_UNIT_NOT_READY;
+                                        }
+                                case SCSI_S_ILLEGAL_REQUEST:
+                                        switch(rsp.bAdditionalSenseCode) {
+                                                case SCSI_ASC_LBA_OUT_OF_RANGE:
+                                                        return MASS_ERR_BAD_LBA;
+                                                default:
+                                                        return MASS_ERR_CMD_NOT_SUPPORTED;
+                                        }
+                                default:
+                                        return MASS_ERR_GENERAL_SCSI_ERROR;
+                        }
+
+                        // case 4: return MASS_ERR_UNIT_BUSY; // Busy means retry later.
+                        //    case 0x05/0x14: we stalled out
+                        //    case 0x15/0x16: we naked out.
+                default:
+                        ErrorMessage<uint8_t > (PSTR("Gen SCSI Err"), status);
+                        ErrorMessage<uint8_t > (PSTR("LUN"), bTheLUN);
+                        return status;
+        } // switch
+}
+
+
+////////////////////////////////////////////////////////////////////////////////
+
+
+// Debugging code
+
+
+////////////////////////////////////////////////////////////////////////////////
+
+/**
+ *
+ * @param ep_ptr
+ */
+void BulkOnly::PrintEndpointDescriptor(const USB_ENDPOINT_DESCRIPTOR * ep_ptr) {
+        Notify(PSTR("Endpoint descriptor:"), 0x80);
+        Notify(PSTR("\r\nLength:\t\t"), 0x80);
+        D_PrintHex<uint8_t > (ep_ptr->bLength, 0x80);
+        Notify(PSTR("\r\nType:\t\t"), 0x80);
+        D_PrintHex<uint8_t > (ep_ptr->bDescriptorType, 0x80);
+        Notify(PSTR("\r\nAddress:\t"), 0x80);
+        D_PrintHex<uint8_t > (ep_ptr->bEndpointAddress, 0x80);
+        Notify(PSTR("\r\nAttributes:\t"), 0x80);
+        D_PrintHex<uint8_t > (ep_ptr->bmAttributes, 0x80);
+        Notify(PSTR("\r\nMaxPktSize:\t"), 0x80);
+        D_PrintHex<uint16_t > (ep_ptr->wMaxPacketSize, 0x80);
+        Notify(PSTR("\r\nPoll Intrv:\t"), 0x80);
+        D_PrintHex<uint8_t > (ep_ptr->bInterval, 0x80);
+        Notify(PSTR("\r\n"), 0x80);
+}
+
+
+////////////////////////////////////////////////////////////////////////////////
+
+
+// misc/to kill/to-do
+
+
+////////////////////////////////////////////////////////////////////////////////
+
+/* We won't be needing this... */
+uint8_t BulkOnly::Read(uint8_t lun __attribute__((unused)), uint32_t addr __attribute__((unused)), uint16_t bsize __attribute__((unused)), uint8_t blocks __attribute__((unused)), USBReadParser * prs __attribute__((unused))) {
+#if MS_WANT_PARSER
+        if(!LUNOk[lun]) return MASS_ERR_NO_MEDIA;
+        Notify(PSTR("\r\nRead (With parser)\r\n"), 0x80);
+        Notify(PSTR("---------\r\n"), 0x80);
+
+        CommandBlockWrapper cbw = CommandBlockWrapper();
+
+        cbw.dCBWSignature = MASS_CBW_SIGNATURE;
+        cbw.dCBWTag = ++dCBWTag;
+        cbw.dCBWDataTransferLength = ((uint32_t)bsize * blocks);
+        cbw.bmCBWFlags = MASS_CMD_DIR_IN,
+                cbw.bmCBWLUN = lun;
+        cbw.bmCBWCBLength = 10;
+
+        cbw.CBWCB[0] = SCSI_CMD_READ_10;
+        cbw.CBWCB[8] = blocks;
+        cbw.CBWCB[2] = ((addr >> 24) & 0xff);
+        cbw.CBWCB[3] = ((addr >> 16) & 0xff);
+        cbw.CBWCB[4] = ((addr >> 8) & 0xff);
+        cbw.CBWCB[5] = (addr & 0xff);
+
+        return HandleSCSIError(Transaction(&cbw, bsize, prs, 1));
+#else
+        return MASS_ERR_NOT_IMPLEMENTED;
+#endif
+}
+
+#endif // USB_FLASH_DRIVE_SUPPORT
diff --git a/Marlin/src/sd/usb_flashdrive/lib/masstorage.h b/Marlin/src/sd/usb_flashdrive/lib/masstorage.h
new file mode 100644
index 0000000000..e2cc1887c7
--- /dev/null
+++ b/Marlin/src/sd/usb_flashdrive/lib/masstorage.h
@@ -0,0 +1,578 @@
+/* Copyright (C) 2011 Circuits At Home, LTD. All rights reserved.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+Contact information
+-------------------
+
+Circuits At Home, LTD
+Web      :  http://www.circuitsathome.com
+e-mail   :  support@circuitsathome.com
+ */
+
+#if !defined(__MASSTORAGE_H__)
+#define __MASSTORAGE_H__
+
+// Cruft removal, makes driver smaller, faster.
+#ifndef MS_WANT_PARSER
+#define MS_WANT_PARSER 0
+#endif
+
+#include "Usb.h"
+
+#define bmREQ_MASSOUT       USB_SETUP_HOST_TO_DEVICE|USB_SETUP_TYPE_CLASS|USB_SETUP_RECIPIENT_INTERFACE
+#define bmREQ_MASSIN        USB_SETUP_DEVICE_TO_HOST|USB_SETUP_TYPE_CLASS|USB_SETUP_RECIPIENT_INTERFACE
+
+// Mass Storage Subclass Constants
+#define MASS_SUBCLASS_SCSI_NOT_REPORTED 0x00    // De facto use
+#define MASS_SUBCLASS_RBC               0x01
+#define MASS_SUBCLASS_ATAPI             0x02    // MMC-5 (ATAPI)
+#define MASS_SUBCLASS_OBSOLETE1         0x03    // Was QIC-157
+#define MASS_SUBCLASS_UFI               0x04    // Specifies how to interface Floppy Disk Drives to USB
+#define MASS_SUBCLASS_OBSOLETE2         0x05    // Was SFF-8070i
+#define MASS_SUBCLASS_SCSI              0x06    // SCSI Transparent Command Set
+#define MASS_SUBCLASS_LSDFS             0x07    // Specifies how host has to negotiate access before trying SCSI
+#define MASS_SUBCLASS_IEEE1667          0x08
+
+// Mass Storage Class Protocols
+#define MASS_PROTO_CBI                  0x00    // CBI (with command completion interrupt)
+#define MASS_PROTO_CBI_NO_INT           0x01    // CBI (without command completion interrupt)
+#define MASS_PROTO_OBSOLETE             0x02
+#define MASS_PROTO_BBB                  0x50    // Bulk Only Transport
+#define MASS_PROTO_UAS                  0x62
+
+// Request Codes
+#define MASS_REQ_ADSC                   0x00
+#define MASS_REQ_GET                    0xFC
+#define MASS_REQ_PUT                    0xFD
+#define MASS_REQ_GET_MAX_LUN            0xFE
+#define MASS_REQ_BOMSR                  0xFF    // Bulk-Only Mass Storage Reset
+
+#define MASS_CBW_SIGNATURE              0x43425355
+#define MASS_CSW_SIGNATURE              0x53425355
+
+#define MASS_CMD_DIR_OUT                0 // (0 << 7)
+#define MASS_CMD_DIR_IN                 0x80 //(1 << 7)
+
+/*
+ * Reference documents from T10 (http://www.t10.org)
+ * SCSI Primary Commands - 3 (SPC-3)
+ * SCSI Block Commands - 2 (SBC-2)
+ * Multi-Media Commands - 5 (MMC-5)
+ */
+
+/* Group 1 commands (CDB's here are should all be 6-bytes) */
+#define SCSI_CMD_TEST_UNIT_READY        0x00
+#define SCSI_CMD_REQUEST_SENSE          0x03
+#define SCSI_CMD_FORMAT_UNIT            0x04
+#define SCSI_CMD_READ_6                 0x08
+#define SCSI_CMD_WRITE_6                0x0A
+#define SCSI_CMD_INQUIRY                0x12
+#define SCSI_CMD_MODE_SELECT_6          0x15
+#define SCSI_CMD_MODE_SENSE_6           0x1A
+#define SCSI_CMD_START_STOP_UNIT        0x1B
+#define SCSI_CMD_PREVENT_REMOVAL        0x1E
+/* Group 2 Commands (CDB's here are 10-bytes) */
+#define SCSI_CMD_READ_FORMAT_CAPACITIES 0x23
+#define SCSI_CMD_READ_CAPACITY_10       0x25
+#define SCSI_CMD_READ_10                0x28
+#define SCSI_CMD_WRITE_10               0x2A
+#define SCSI_CMD_SEEK_10                0x2B
+#define SCSI_CMD_ERASE_10               0x2C
+#define SCSI_CMD_WRITE_AND_VERIFY_10    0x2E
+#define SCSI_CMD_VERIFY_10              0x2F
+#define SCSI_CMD_SYNCHRONIZE_CACHE      0x35
+#define SCSI_CMD_WRITE_BUFFER           0x3B
+#define SCSI_CMD_READ_BUFFER            0x3C
+#define SCSI_CMD_READ_SUBCHANNEL        0x42
+#define SCSI_CMD_READ_TOC               0x43
+#define SCSI_CMD_READ_HEADER            0x44
+#define SCSI_CMD_PLAY_AUDIO_10          0x45
+#define SCSI_CMD_GET_CONFIGURATION      0x46
+#define SCSI_CMD_PLAY_AUDIO_MSF         0x47
+#define SCSI_CMD_PLAY_AUDIO_TI          0x48
+#define SCSI_CMD_PLAY_TRACK_REL_10      0x49
+#define SCSI_CMD_GET_EVENT_STATUS       0x4A
+#define SCSI_CMD_PAUSE_RESUME           0x4B
+#define SCSI_CMD_READ_DISC_INFORMATION  0x51
+#define SCSI_CMD_READ_TRACK_INFORMATION 0x52
+#define SCSI_CMD_RESERVE_TRACK          0x53
+#define SCSI_CMD_SEND_OPC_INFORMATION   0x54
+#define SCSI_CMD_MODE_SELECT_10         0x55
+#define SCSI_CMD_REPAIR_TRACK           0x58
+#define SCSI_CMD_MODE_SENSE_10          0x5A
+#define SCSI_CMD_CLOSE_TRACK_SESSION    0x5B
+#define SCSI_CMD_READ_BUFFER_CAPACITY   0x5C
+#define SCSI_CMD_SEND_CUE_SHEET         0x5D
+/* Group 5 Commands (CDB's here are 12-bytes) */
+#define SCSI_CMD_REPORT_LUNS            0xA0
+#define SCSI_CMD_BLANK                  0xA1
+#define SCSI_CMD_SECURITY_PROTOCOL_IN   0xA2
+#define SCSI_CMD_SEND_KEY               0xA3
+#define SCSI_CMD_REPORT_KEY             0xA4
+#define SCSI_CMD_PLAY_AUDIO_12          0xA5
+#define SCSI_CMD_LOAD_UNLOAD            0xA6
+#define SCSI_CMD_SET_READ_AHEAD         0xA7
+#define SCSI_CMD_READ_12                0xA8
+#define SCSI_CMD_PLAY_TRACK_REL_12      0xA9
+#define SCSI_CMD_WRITE_12               0xAA
+#define SCSI_CMD_READ_MEDIA_SERIAL_12   0xAB
+#define SCSI_CMD_GET_PERFORMANCE        0xAC
+#define SCSI_CMD_READ_DVD_STRUCTURE     0xAD
+#define SCSI_CMD_SECURITY_PROTOCOL_OUT  0xB5
+#define SCSI_CMD_SET_STREAMING          0xB6
+#define SCSI_CMD_READ_MSF               0xB9
+#define SCSI_CMD_SET_SPEED              0xBB
+#define SCSI_CMD_MECHANISM_STATUS       0xBD
+#define SCSI_CMD_READ_CD                0xBE
+#define SCSI_CMD_SEND_DISC_STRUCTURE    0xBF
+/* Vendor-unique Commands, included for completeness */
+#define SCSI_CMD_CD_PLAYBACK_STATUS     0xC4 /* SONY unique */
+#define SCSI_CMD_PLAYBACK_CONTROL       0xC9 /* SONY unique */
+#define SCSI_CMD_READ_CDDA              0xD8 /* Vendor unique */
+#define SCSI_CMD_READ_CDXA              0xDB /* Vendor unique */
+#define SCSI_CMD_READ_ALL_SUBCODES      0xDF /* Vendor unique */
+
+/* SCSI error codes */
+#define SCSI_S_NOT_READY                0x02
+#define SCSI_S_MEDIUM_ERROR             0x03
+#define SCSI_S_ILLEGAL_REQUEST          0x05
+#define SCSI_S_UNIT_ATTENTION           0x06
+#define SCSI_ASC_LBA_OUT_OF_RANGE       0x21
+#define SCSI_ASC_MEDIA_CHANGED          0x28
+#define SCSI_ASC_MEDIUM_NOT_PRESENT     0x3A
+
+/* USB error codes */
+#define MASS_ERR_SUCCESS                0x00
+#define MASS_ERR_PHASE_ERROR            0x02
+#define MASS_ERR_UNIT_NOT_READY         0x03
+#define MASS_ERR_UNIT_BUSY              0x04
+#define MASS_ERR_STALL                  0x05
+#define MASS_ERR_CMD_NOT_SUPPORTED      0x06
+#define MASS_ERR_INVALID_CSW            0x07
+#define MASS_ERR_NO_MEDIA               0x08
+#define MASS_ERR_BAD_LBA                0x09
+#define MASS_ERR_MEDIA_CHANGED          0x0A
+#define MASS_ERR_DEVICE_DISCONNECTED    0x11
+#define MASS_ERR_UNABLE_TO_RECOVER      0x12    // Reset recovery error
+#define MASS_ERR_INVALID_LUN            0x13
+#define MASS_ERR_WRITE_STALL            0x14
+#define MASS_ERR_READ_NAKS              0x15
+#define MASS_ERR_WRITE_NAKS             0x16
+#define MASS_ERR_WRITE_PROTECTED        0x17
+#define MASS_ERR_NOT_IMPLEMENTED        0xFD
+#define MASS_ERR_GENERAL_SCSI_ERROR     0xFE
+#define MASS_ERR_GENERAL_USB_ERROR      0xFF
+#define MASS_ERR_USER                   0xA0    // For subclasses to define their own error codes
+
+#define MASS_TRANS_FLG_CALLBACK         0x01    // Callback is involved
+#define MASS_TRANS_FLG_NO_STALL_CHECK   0x02    // STALL condition is not checked
+#define MASS_TRANS_FLG_NO_PHASE_CHECK   0x04    // PHASE_ERROR is not checked
+
+#define MASS_MAX_ENDPOINTS              3
+
+struct Capacity {
+        uint8_t data[8];
+        //uint32_t dwBlockAddress;
+        //uint32_t dwBlockLength;
+} __attribute__((packed));
+
+struct BASICCDB {
+        uint8_t Opcode;
+
+        unsigned unused : 5;
+        unsigned LUN : 3;
+
+        uint8_t info[12];
+} __attribute__((packed));
+
+typedef BASICCDB BASICCDB_t;
+
+struct CDB6 {
+        uint8_t Opcode;
+
+        unsigned LBAMSB : 5;
+        unsigned LUN : 3;
+
+        uint8_t LBAHB;
+        uint8_t LBALB;
+        uint8_t AllocationLength;
+        uint8_t Control;
+
+public:
+
+        CDB6(uint8_t _Opcode, uint8_t _LUN, uint32_t LBA, uint8_t _AllocationLength, uint8_t _Control) :
+        Opcode(_Opcode), LBAMSB(BGRAB2(LBA) & 0x1f), LUN(_LUN), LBAHB(BGRAB1(LBA)), LBALB(BGRAB0(LBA)),
+        AllocationLength(_AllocationLength), Control(_Control) {
+        }
+
+        CDB6(uint8_t _Opcode, uint8_t _LUN, uint8_t _AllocationLength, uint8_t _Control) :
+        Opcode(_Opcode), LBAMSB(0), LUN(_LUN), LBAHB(0), LBALB(0),
+        AllocationLength(_AllocationLength), Control(_Control) {
+        }
+} __attribute__((packed));
+
+typedef CDB6 CDB6_t;
+
+struct CDB10 {
+        uint8_t Opcode;
+
+        unsigned Service_Action : 5;
+        unsigned LUN : 3;
+
+        uint8_t LBA_L_M_MB;
+        uint8_t LBA_L_M_LB;
+        uint8_t LBA_L_L_MB;
+        uint8_t LBA_L_L_LB;
+
+        uint8_t Misc2;
+
+        uint8_t ALC_MB;
+        uint8_t ALC_LB;
+
+        uint8_t Control;
+public:
+
+        CDB10(uint8_t _Opcode, uint8_t _LUN) :
+        Opcode(_Opcode), Service_Action(0), LUN(_LUN),
+        LBA_L_M_MB(0), LBA_L_M_LB(0), LBA_L_L_MB(0), LBA_L_L_LB(0),
+        Misc2(0), ALC_MB(0), ALC_LB(0), Control(0) {
+        }
+
+        CDB10(uint8_t _Opcode, uint8_t _LUN, uint16_t xflen, uint32_t _LBA) :
+        Opcode(_Opcode), Service_Action(0), LUN(_LUN),
+        LBA_L_M_MB(BGRAB3(_LBA)), LBA_L_M_LB(BGRAB2(_LBA)), LBA_L_L_MB(BGRAB1(_LBA)), LBA_L_L_LB(BGRAB0(_LBA)),
+        Misc2(0), ALC_MB(BGRAB1(xflen)), ALC_LB(BGRAB0(xflen)), Control(0) {
+        }
+} __attribute__((packed));
+
+typedef CDB10 CDB10_t;
+
+struct CDB12 {
+        uint8_t Opcode;
+
+        unsigned Service_Action : 5;
+        unsigned Misc : 3;
+
+        uint8_t LBA_L_M_LB;
+        uint8_t LBA_L_L_MB;
+        uint8_t LBA_L_L_LB;
+
+        uint8_t ALC_M_LB;
+        uint8_t ALC_L_MB;
+        uint8_t ALC_L_LB;
+        uint8_t Control;
+} __attribute__((packed));
+
+typedef CDB12 CDB12_t;
+
+struct CDB_LBA32_16 {
+        uint8_t Opcode;
+
+        unsigned Service_Action : 5;
+        unsigned Misc : 3;
+
+        uint8_t LBA_L_M_MB;
+        uint8_t LBA_L_M_LB;
+        uint8_t LBA_L_L_MB;
+        uint8_t LBA_L_L_LB;
+
+        uint8_t A_M_M_MB;
+        uint8_t A_M_M_LB;
+        uint8_t A_M_L_MB;
+        uint8_t A_M_L_LB;
+
+        uint8_t ALC_M_MB;
+        uint8_t ALC_M_LB;
+        uint8_t ALC_L_MB;
+        uint8_t ALC_L_LB;
+
+        uint8_t Misc2;
+        uint8_t Control;
+} __attribute__((packed));
+
+struct CDB_LBA64_16 {
+        uint8_t Opcode;
+        uint8_t Misc;
+
+        uint8_t LBA_M_M_MB;
+        uint8_t LBA_M_M_LB;
+        uint8_t LBA_M_L_MB;
+        uint8_t LBA_M_L_LB;
+
+        uint8_t LBA_L_M_MB;
+        uint8_t LBA_L_M_LB;
+        uint8_t LBA_L_L_MB;
+        uint8_t LBA_L_L_LB;
+
+        uint8_t ALC_M_MB;
+        uint8_t ALC_M_LB;
+        uint8_t ALC_L_MB;
+        uint8_t ALC_L_LB;
+
+        uint8_t Misc2;
+        uint8_t Control;
+} __attribute__((packed));
+
+struct InquiryResponse {
+        uint8_t DeviceType : 5;
+        uint8_t PeripheralQualifier : 3;
+
+        unsigned Reserved : 7;
+        unsigned Removable : 1;
+
+        uint8_t Version;
+
+        unsigned ResponseDataFormat : 4;
+        unsigned HISUP : 1;
+        unsigned NormACA : 1;
+        unsigned TrmTsk : 1;
+        unsigned AERC : 1;
+
+        uint8_t AdditionalLength;
+        //uint8_t Reserved3[2];
+
+        unsigned PROTECT : 1;
+        unsigned Res : 2;
+        unsigned ThreePC : 1;
+        unsigned TPGS : 2;
+        unsigned ACC : 1;
+        unsigned SCCS : 1;
+
+        unsigned ADDR16 : 1;
+        unsigned R1 : 1;
+        unsigned R2 : 1;
+        unsigned MCHNGR : 1;
+        unsigned MULTIP : 1;
+        unsigned VS : 1;
+        unsigned ENCSERV : 1;
+        unsigned BQUE : 1;
+
+        unsigned SoftReset : 1;
+        unsigned CmdQue : 1;
+        unsigned Reserved4 : 1;
+        unsigned Linked : 1;
+        unsigned Sync : 1;
+        unsigned WideBus16Bit : 1;
+        unsigned WideBus32Bit : 1;
+        unsigned RelAddr : 1;
+
+        uint8_t VendorID[8];
+        uint8_t ProductID[16];
+        uint8_t RevisionID[4];
+} __attribute__((packed));
+
+struct CommandBlockWrapperBase {
+        uint32_t dCBWSignature;
+        uint32_t dCBWTag;
+        uint32_t dCBWDataTransferLength;
+        uint8_t bmCBWFlags;
+public:
+
+        CommandBlockWrapperBase() {
+        }
+
+        CommandBlockWrapperBase(uint32_t tag, uint32_t xflen, uint8_t flgs) :
+        dCBWSignature(MASS_CBW_SIGNATURE), dCBWTag(tag), dCBWDataTransferLength(xflen), bmCBWFlags(flgs) {
+        }
+} __attribute__((packed));
+
+struct CommandBlockWrapper : public CommandBlockWrapperBase {
+
+        struct {
+                uint8_t bmCBWLUN : 4;
+                uint8_t bmReserved1 : 4;
+        };
+
+        struct {
+                uint8_t bmCBWCBLength : 4;
+                uint8_t bmReserved2 : 4;
+        };
+
+        uint8_t CBWCB[16];
+
+public:
+        // All zeroed.
+
+        CommandBlockWrapper() :
+        CommandBlockWrapperBase(0, 0, 0), bmReserved1(0), bmReserved2(0) {
+                for(int i = 0; i < 16; i++) CBWCB[i] = 0;
+        }
+
+        // Generic Wrap, CDB zeroed.
+
+        CommandBlockWrapper(uint32_t tag, uint32_t xflen, uint8_t flgs, uint8_t lu, uint8_t cmdlen, uint8_t cmd) :
+        CommandBlockWrapperBase(tag, xflen, flgs),
+        bmCBWLUN(lu), bmReserved1(0), bmCBWCBLength(cmdlen), bmReserved2(0) {
+                for(int i = 0; i < 16; i++) CBWCB[i] = 0;
+                // Type punning can cause optimization problems and bugs.
+                // Using reinterpret_cast to a dreinterpretifferent object is the proper way to do this.
+                //(((BASICCDB_t *) CBWCB)->LUN) = cmd;
+                BASICCDB_t *x = reinterpret_cast<BASICCDB_t *>(CBWCB);
+                x->LUN = cmd;
+        }
+
+        // Wrap for CDB of 6
+
+        CommandBlockWrapper(uint32_t tag, uint32_t xflen, CDB6_t *cdb, uint8_t dir) :
+        CommandBlockWrapperBase(tag, xflen, dir),
+        bmCBWLUN(cdb->LUN), bmReserved1(0), bmCBWCBLength(6), bmReserved2(0) {
+                memcpy(&CBWCB, cdb, 6);
+        }
+        // Wrap for CDB of 10
+
+        CommandBlockWrapper(uint32_t tag, uint32_t xflen, CDB10_t *cdb, uint8_t dir) :
+        CommandBlockWrapperBase(tag, xflen, dir),
+        bmCBWLUN(cdb->LUN), bmReserved1(0), bmCBWCBLength(10), bmReserved2(0) {
+                memcpy(&CBWCB, cdb, 10);
+        }
+} __attribute__((packed));
+
+struct CommandStatusWrapper {
+        uint32_t dCSWSignature;
+        uint32_t dCSWTag;
+        uint32_t dCSWDataResidue;
+        uint8_t bCSWStatus;
+} __attribute__((packed));
+
+struct RequestSenseResponce {
+        uint8_t bResponseCode;
+        uint8_t bSegmentNumber;
+
+        uint8_t bmSenseKey : 4;
+        uint8_t bmReserved : 1;
+        uint8_t bmILI : 1;
+        uint8_t bmEOM : 1;
+        uint8_t bmFileMark : 1;
+
+        uint8_t Information[4];
+        uint8_t bAdditionalLength;
+        uint8_t CmdSpecificInformation[4];
+        uint8_t bAdditionalSenseCode;
+        uint8_t bAdditionalSenseQualifier;
+        uint8_t bFieldReplaceableUnitCode;
+        uint8_t SenseKeySpecific[3];
+} __attribute__((packed));
+
+class BulkOnly : public USBDeviceConfig, public UsbConfigXtracter {
+protected:
+        static const uint8_t epDataInIndex; // DataIn endpoint index
+        static const uint8_t epDataOutIndex; // DataOUT endpoint index
+        static const uint8_t epInterruptInIndex; // InterruptIN  endpoint index
+
+        USB *pUsb;
+        uint8_t bAddress;
+        uint8_t bConfNum; // configuration number
+        uint8_t bIface; // interface value
+        uint8_t bNumEP; // total number of EP in the configuration
+        uint32_t qNextPollTime; // next poll time
+        bool bPollEnable; // poll enable flag
+
+        EpInfo epInfo[MASS_MAX_ENDPOINTS];
+
+        uint32_t dCBWTag; // Tag
+        //uint32_t dCBWDataTransferLength; // Data Transfer Length
+        uint8_t bLastUsbError; // Last USB error
+        uint8_t bMaxLUN; // Max LUN
+        uint8_t bTheLUN; // Active LUN
+        uint32_t CurrentCapacity[MASS_MAX_SUPPORTED_LUN]; // Total sectors
+        uint16_t CurrentSectorSize[MASS_MAX_SUPPORTED_LUN]; // Sector size, clipped to 16 bits
+        bool LUNOk[MASS_MAX_SUPPORTED_LUN]; // use this to check for media changes.
+        bool WriteOk[MASS_MAX_SUPPORTED_LUN];
+        void PrintEndpointDescriptor(const USB_ENDPOINT_DESCRIPTOR* ep_ptr);
+
+
+        // Additional Initialization Method for Subclasses
+
+        virtual uint8_t OnInit() {
+                return 0;
+        };
+public:
+        BulkOnly(USB *p);
+
+        uint8_t GetLastUsbError() {
+                return bLastUsbError;
+        };
+
+        uint8_t GetbMaxLUN() {
+                return bMaxLUN; // Max LUN
+        }
+
+        uint8_t GetbTheLUN() {
+                return bTheLUN; // Active LUN
+        }
+
+        bool WriteProtected(uint8_t lun);
+        uint8_t MediaCTL(uint8_t lun, uint8_t ctl);
+        uint8_t Read(uint8_t lun, uint32_t addr, uint16_t bsize, uint8_t blocks, uint8_t *buf);
+        uint8_t Read(uint8_t lun, uint32_t addr, uint16_t bsize, uint8_t blocks, USBReadParser *prs);
+        uint8_t Write(uint8_t lun, uint32_t addr, uint16_t bsize, uint8_t blocks, const uint8_t *buf);
+        uint8_t LockMedia(uint8_t lun, uint8_t lock);
+
+        bool LUNIsGood(uint8_t lun);
+        uint32_t GetCapacity(uint8_t lun);
+        uint16_t GetSectorSize(uint8_t lun);
+
+        // USBDeviceConfig implementation
+        uint8_t Init(uint8_t parent, uint8_t port, bool lowspeed);
+        uint8_t ConfigureDevice(uint8_t parent, uint8_t port, bool lowspeed);
+
+        uint8_t Release();
+        uint8_t Poll();
+
+        virtual uint8_t GetAddress() {
+                return bAddress;
+        };
+
+        // UsbConfigXtracter implementation
+        void EndpointXtract(uint8_t conf, uint8_t iface, uint8_t alt, uint8_t proto, const USB_ENDPOINT_DESCRIPTOR *ep);
+
+        virtual bool DEVCLASSOK(uint8_t klass) {
+                return (klass == USB_CLASS_MASS_STORAGE);
+        }
+
+        uint8_t SCSITransaction6(CDB6_t *cdb, uint16_t buf_size, void *buf, uint8_t dir);
+        uint8_t SCSITransaction10(CDB10_t *cdb, uint16_t buf_size, void *buf, uint8_t dir);
+
+private:
+        uint8_t Inquiry(uint8_t lun, uint16_t size, uint8_t *buf);
+        uint8_t TestUnitReady(uint8_t lun);
+        uint8_t RequestSense(uint8_t lun, uint16_t size, uint8_t *buf);
+        uint8_t ModeSense6(uint8_t lun, uint8_t pc, uint8_t page, uint8_t subpage, uint8_t len, uint8_t *buf);
+        uint8_t GetMaxLUN(uint8_t *max_lun);
+        uint8_t SetCurLUN(uint8_t lun);
+        void Reset();
+        uint8_t ResetRecovery();
+        uint8_t ReadCapacity10(uint8_t lun, uint8_t *buf);
+        void ClearAllEP();
+        void CheckMedia();
+        bool CheckLUN(uint8_t lun);
+        uint8_t Page3F(uint8_t lun);
+        bool IsValidCBW(uint8_t size, uint8_t *pcbw);
+        bool IsMeaningfulCBW(uint8_t size, uint8_t *pcbw);
+
+        bool IsValidCSW(CommandStatusWrapper *pcsw, CommandBlockWrapperBase *pcbw);
+
+        uint8_t ClearEpHalt(uint8_t index);
+#if MS_WANT_PARSER
+        uint8_t Transaction(CommandBlockWrapper *cbw, uint16_t bsize, void *buf, uint8_t flags);
+#endif
+        uint8_t Transaction(CommandBlockWrapper *cbw, uint16_t bsize, void *buf);
+        uint8_t HandleUsbError(uint8_t error, uint8_t index);
+        uint8_t HandleSCSIError(uint8_t status);
+
+};
+
+#endif // __MASSTORAGE_H__
diff --git a/Marlin/src/sd/usb_flashdrive/lib/max3421e.h b/Marlin/src/sd/usb_flashdrive/lib/max3421e.h
new file mode 100644
index 0000000000..1ad1e3d301
--- /dev/null
+++ b/Marlin/src/sd/usb_flashdrive/lib/max3421e.h
@@ -0,0 +1,235 @@
+/* Copyright (C) 2011 Circuits At Home, LTD. All rights reserved.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+Contact information
+-------------------
+
+Circuits At Home, LTD
+Web      :  http://www.circuitsathome.com
+e-mail   :  support@circuitsathome.com
+ */
+#if !defined(_usb_h_) || defined(_max3421e_h_)
+#error "Never include max3421e.h directly; include Usb.h instead"
+#else
+
+#define _max3421e_h_
+
+/* MAX3421E register/bit names and bitmasks */
+
+/* Arduino pin definitions */
+/* pin numbers to port numbers */
+
+#define SE0     0
+#define SE1     1
+#define FSHOST  2
+#define LSHOST  3
+
+/* MAX3421E command byte format: rrrrr0wa where 'r' is register number  */
+//
+// MAX3421E Registers in HOST mode.
+//
+#define rRCVFIFO    0x08    //1<<3
+#define rSNDFIFO    0x10    //2<<3
+#define rSUDFIFO    0x20    //4<<3
+#define rRCVBC      0x30    //6<<3
+#define rSNDBC      0x38    //7<<3
+
+#define rUSBIRQ     0x68    //13<<3
+/* USBIRQ Bits  */
+#define bmVBUSIRQ   0x40    //b6
+#define bmNOVBUSIRQ 0x20    //b5
+#define bmOSCOKIRQ  0x01    //b0
+
+#define rUSBIEN     0x70    //14<<3
+/* USBIEN Bits  */
+#define bmVBUSIE    0x40    //b6
+#define bmNOVBUSIE  0x20    //b5
+#define bmOSCOKIE   0x01    //b0
+
+#define rUSBCTL     0x78    //15<<3
+/* USBCTL Bits  */
+#define bmCHIPRES   0x20    //b5
+#define bmPWRDOWN   0x10    //b4
+
+#define rCPUCTL     0x80    //16<<3
+/* CPUCTL Bits  */
+#define bmPUSLEWID1 0x80    //b7
+#define bmPULSEWID0 0x40    //b6
+#define bmIE        0x01    //b0
+
+#define rPINCTL     0x88    //17<<3
+/* PINCTL Bits  */
+#define bmFDUPSPI   0x10    //b4
+#define bmINTLEVEL  0x08    //b3
+#define bmPOSINT    0x04    //b2
+#define bmGPXB      0x02    //b1
+#define bmGPXA      0x01    //b0
+// GPX pin selections
+#define GPX_OPERATE 0x00
+#define GPX_VBDET   0x01
+#define GPX_BUSACT  0x02
+#define GPX_SOF     0x03
+
+#define rREVISION   0x90    //18<<3
+
+#define rIOPINS1    0xa0    //20<<3
+
+/* IOPINS1 Bits */
+#define bmGPOUT0    0x01
+#define bmGPOUT1    0x02
+#define bmGPOUT2    0x04
+#define bmGPOUT3    0x08
+#define bmGPIN0     0x10
+#define bmGPIN1     0x20
+#define bmGPIN2     0x40
+#define bmGPIN3     0x80
+
+#define rIOPINS2    0xa8    //21<<3
+/* IOPINS2 Bits */
+#define bmGPOUT4    0x01
+#define bmGPOUT5    0x02
+#define bmGPOUT6    0x04
+#define bmGPOUT7    0x08
+#define bmGPIN4     0x10
+#define bmGPIN5     0x20
+#define bmGPIN6     0x40
+#define bmGPIN7     0x80
+
+#define rGPINIRQ    0xb0    //22<<3
+/* GPINIRQ Bits */
+#define bmGPINIRQ0 0x01
+#define bmGPINIRQ1 0x02
+#define bmGPINIRQ2 0x04
+#define bmGPINIRQ3 0x08
+#define bmGPINIRQ4 0x10
+#define bmGPINIRQ5 0x20
+#define bmGPINIRQ6 0x40
+#define bmGPINIRQ7 0x80
+
+#define rGPINIEN    0xb8    //23<<3
+/* GPINIEN Bits */
+#define bmGPINIEN0 0x01
+#define bmGPINIEN1 0x02
+#define bmGPINIEN2 0x04
+#define bmGPINIEN3 0x08
+#define bmGPINIEN4 0x10
+#define bmGPINIEN5 0x20
+#define bmGPINIEN6 0x40
+#define bmGPINIEN7 0x80
+
+#define rGPINPOL    0xc0    //24<<3
+/* GPINPOL Bits */
+#define bmGPINPOL0 0x01
+#define bmGPINPOL1 0x02
+#define bmGPINPOL2 0x04
+#define bmGPINPOL3 0x08
+#define bmGPINPOL4 0x10
+#define bmGPINPOL5 0x20
+#define bmGPINPOL6 0x40
+#define bmGPINPOL7 0x80
+
+#define rHIRQ       0xc8    //25<<3
+/* HIRQ Bits */
+#define bmBUSEVENTIRQ   0x01   // indicates BUS Reset Done or BUS Resume
+#define bmRWUIRQ        0x02
+#define bmRCVDAVIRQ     0x04
+#define bmSNDBAVIRQ     0x08
+#define bmSUSDNIRQ      0x10
+#define bmCONDETIRQ     0x20
+#define bmFRAMEIRQ      0x40
+#define bmHXFRDNIRQ     0x80
+
+#define rHIEN           0xd0    //26<<3
+
+/* HIEN Bits */
+#define bmBUSEVENTIE    0x01
+#define bmRWUIE         0x02
+#define bmRCVDAVIE      0x04
+#define bmSNDBAVIE      0x08
+#define bmSUSDNIE       0x10
+#define bmCONDETIE      0x20
+#define bmFRAMEIE       0x40
+#define bmHXFRDNIE      0x80
+
+#define rMODE           0xd8    //27<<3
+
+/* MODE Bits */
+#define bmHOST          0x01
+#define bmLOWSPEED      0x02
+#define bmHUBPRE        0x04
+#define bmSOFKAENAB     0x08
+#define bmSEPIRQ        0x10
+#define bmDELAYISO      0x20
+#define bmDMPULLDN      0x40
+#define bmDPPULLDN      0x80
+
+#define rPERADDR    0xe0    //28<<3
+
+#define rHCTL       0xe8    //29<<3
+/* HCTL Bits */
+#define bmBUSRST        0x01
+#define bmFRMRST        0x02
+#define bmSAMPLEBUS     0x04
+#define bmSIGRSM        0x08
+#define bmRCVTOG0       0x10
+#define bmRCVTOG1       0x20
+#define bmSNDTOG0       0x40
+#define bmSNDTOG1       0x80
+
+#define rHXFR       0xf0    //30<<3
+/* Host transfer token values for writing the HXFR register (R30)   */
+/* OR this bit field with the endpoint number in bits 3:0               */
+#define tokSETUP  0x10  // HS=0, ISO=0, OUTNIN=0, SETUP=1
+#define tokIN     0x00  // HS=0, ISO=0, OUTNIN=0, SETUP=0
+#define tokOUT    0x20  // HS=0, ISO=0, OUTNIN=1, SETUP=0
+#define tokINHS   0x80  // HS=1, ISO=0, OUTNIN=0, SETUP=0
+#define tokOUTHS  0xA0  // HS=1, ISO=0, OUTNIN=1, SETUP=0
+#define tokISOIN  0x40  // HS=0, ISO=1, OUTNIN=0, SETUP=0
+#define tokISOOUT 0x60  // HS=0, ISO=1, OUTNIN=1, SETUP=0
+
+#define rHRSL       0xf8    //31<<3
+
+/* HRSL Bits */
+#define bmRCVTOGRD  0x10
+#define bmSNDTOGRD  0x20
+#define bmKSTATUS   0x40
+#define bmJSTATUS   0x80
+#define bmSE0       0x00    //SE0 - disconnect state
+#define bmSE1       0xc0    //SE1 - illegal state
+
+/* Host error result codes, the 4 LSB's in the HRSL register */
+#define hrSUCCESS   0x00
+#define hrBUSY      0x01
+#define hrBADREQ    0x02
+#define hrUNDEF     0x03
+#define hrNAK       0x04
+#define hrSTALL     0x05
+#define hrTOGERR    0x06
+#define hrWRONGPID  0x07
+#define hrBADBC     0x08
+#define hrPIDERR    0x09
+#define hrPKTERR    0x0A
+#define hrCRCERR    0x0B
+#define hrKERR      0x0C
+#define hrJERR      0x0D
+#define hrTIMEOUT   0x0E
+#define hrBABBLE    0x0F
+
+#define MODE_FS_HOST    (bmDPPULLDN|bmDMPULLDN|bmHOST|bmSOFKAENAB)
+#define MODE_LS_HOST    (bmDPPULLDN|bmDMPULLDN|bmHOST|bmLOWSPEED|bmSOFKAENAB)
+
+
+#endif //_max3421e_h_
diff --git a/Marlin/src/sd/usb_flashdrive/lib/message.cpp b/Marlin/src/sd/usb_flashdrive/lib/message.cpp
new file mode 100644
index 0000000000..ac73794c4b
--- /dev/null
+++ b/Marlin/src/sd/usb_flashdrive/lib/message.cpp
@@ -0,0 +1,130 @@
+/* Copyright (C) 2011 Circuits At Home, LTD. All rights reserved.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+Contact information
+-------------------
+
+Circuits At Home, LTD
+Web      :  http://www.circuitsathome.com
+e-mail   :  support@circuitsathome.com
+ */
+
+#include "../../../inc/MarlinConfigPre.h"
+
+#if ENABLED(USB_FLASH_DRIVE_SUPPORT)
+
+#include "Usb.h"
+
+// 0x80 is the default (i.e. trace) to turn off set this global to something lower.
+// this allows for 126 other debugging levels.
+// TO-DO: Allow assignment to a different serial port by software
+int UsbDEBUGlvl = 0x80;
+
+void E_Notifyc(char c, int lvl) {
+        if(UsbDEBUGlvl < lvl) return;
+#if defined(ARDUINO) && ARDUINO >=100
+        USB_HOST_SERIAL.print(c);
+#else
+        USB_HOST_SERIAL.print(c, BYTE);
+#endif
+        //USB_HOST_SERIAL.flush();
+}
+
+void E_Notify(char const * msg, int lvl) {
+        if(UsbDEBUGlvl < lvl) return;
+        if(!msg) return;
+        char c;
+
+        while((c = pgm_read_byte(msg++))) E_Notifyc(c, lvl);
+}
+
+void E_NotifyStr(char const * msg, int lvl) {
+        if(UsbDEBUGlvl < lvl) return;
+        if(!msg) return;
+        char c;
+
+        while((c = *msg++)) E_Notifyc(c, lvl);
+}
+
+void E_Notify(uint8_t b, int lvl) {
+        if(UsbDEBUGlvl < lvl) return;
+#if defined(ARDUINO) && ARDUINO >=100
+        USB_HOST_SERIAL.print(b);
+#else
+        USB_HOST_SERIAL.print(b, DEC);
+#endif
+        //USB_HOST_SERIAL.flush();
+}
+
+void E_Notify(double d, int lvl) {
+        if(UsbDEBUGlvl < lvl) return;
+        USB_HOST_SERIAL.print(d);
+        //USB_HOST_SERIAL.flush();
+}
+
+#ifdef DEBUG_USB_HOST
+
+void NotifyFailGetDevDescr(void) {
+        Notify(PSTR("\r\ngetDevDescr "), 0x80);
+}
+
+void NotifyFailSetDevTblEntry(void) {
+        Notify(PSTR("\r\nsetDevTblEn "), 0x80);
+}
+
+void NotifyFailGetConfDescr(void) {
+        Notify(PSTR("\r\ngetConf "), 0x80);
+}
+
+void NotifyFailSetConfDescr(void) {
+        Notify(PSTR("\r\nsetConf "), 0x80);
+}
+
+void NotifyFailGetDevDescr(uint8_t reason) {
+        NotifyFailGetDevDescr();
+        NotifyFail(reason);
+}
+
+void NotifyFailSetDevTblEntry(uint8_t reason) {
+        NotifyFailSetDevTblEntry();
+        NotifyFail(reason);
+
+}
+
+void NotifyFailGetConfDescr(uint8_t reason) {
+        NotifyFailGetConfDescr();
+        NotifyFail(reason);
+}
+
+void NotifyFailSetConfDescr(uint8_t reason) {
+        NotifyFailSetConfDescr();
+        NotifyFail(reason);
+}
+
+void NotifyFailUnknownDevice(uint16_t VID, uint16_t PID) {
+        Notify(PSTR("\r\nUnknown Device Connected - VID: "), 0x80);
+        D_PrintHex<uint16_t > (VID, 0x80);
+        Notify(PSTR(" PID: "), 0x80);
+        D_PrintHex<uint16_t > (PID, 0x80);
+}
+
+void NotifyFail(uint8_t rcode) {
+        D_PrintHex<uint8_t > (rcode, 0x80);
+        Notify(PSTR("\r\n"), 0x80);
+}
+#endif // DEBUG_USB_HOST
+
+#endif // USB_FLASH_DRIVE_SUPPORT
diff --git a/Marlin/src/sd/usb_flashdrive/lib/message.h b/Marlin/src/sd/usb_flashdrive/lib/message.h
new file mode 100644
index 0000000000..71c0f7bcde
--- /dev/null
+++ b/Marlin/src/sd/usb_flashdrive/lib/message.h
@@ -0,0 +1,85 @@
+/* Copyright (C) 2011 Circuits At Home, LTD. All rights reserved.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+Contact information
+-------------------
+
+Circuits At Home, LTD
+Web      :  http://www.circuitsathome.com
+e-mail   :  support@circuitsathome.com
+ */
+#if !defined(_usb_h_) || defined(__MESSAGE_H__)
+#error "Never include message.h directly; include Usb.h instead"
+#else
+#define __MESSAGE_H__
+
+extern int UsbDEBUGlvl;
+
+void E_Notify(char const * msg, int lvl);
+void E_Notify(uint8_t b, int lvl);
+void E_NotifyStr(char const * msg, int lvl);
+void E_Notifyc(char c, int lvl);
+
+#ifdef DEBUG_USB_HOST
+#define Notify E_Notify
+#define NotifyStr E_NotifyStr
+#define Notifyc E_Notifyc
+void NotifyFailGetDevDescr(uint8_t reason);
+void NotifyFailSetDevTblEntry(uint8_t reason);
+void NotifyFailGetConfDescr(uint8_t reason);
+void NotifyFailSetConfDescr(uint8_t reason);
+void NotifyFailGetDevDescr(void);
+void NotifyFailSetDevTblEntry(void);
+void NotifyFailGetConfDescr(void);
+void NotifyFailSetConfDescr(void);
+void NotifyFailUnknownDevice(uint16_t VID, uint16_t PID);
+void NotifyFail(uint8_t rcode);
+#else
+#define Notify(...) ((void)0)
+#define NotifyStr(...) ((void)0)
+#define Notifyc(...) ((void)0)
+#define NotifyFailGetDevDescr(...) ((void)0)
+#define NotifyFailSetDevTblEntry(...) ((void)0)
+#define NotifyFailGetConfDescr(...) ((void)0)
+#define NotifyFailGetDevDescr(...) ((void)0)
+#define NotifyFailSetDevTblEntry(...) ((void)0)
+#define NotifyFailGetConfDescr(...) ((void)0)
+#define NotifyFailSetConfDescr(...) ((void)0)
+#define NotifyFailUnknownDevice(...) ((void)0)
+#define NotifyFail(...) ((void)0)
+#endif
+
+template <class ERROR_TYPE>
+void ErrorMessage(uint8_t level, char const * msg, ERROR_TYPE rcode = 0) {
+#ifdef DEBUG_USB_HOST
+        Notify(msg, level);
+        Notify(PSTR(": "), level);
+        D_PrintHex<ERROR_TYPE > (rcode, level);
+        Notify(PSTR("\r\n"), level);
+#endif
+}
+
+template <class ERROR_TYPE>
+void ErrorMessage(char const * msg __attribute__((unused)), ERROR_TYPE rcode __attribute__((unused)) = 0) {
+#ifdef DEBUG_USB_HOST
+        Notify(msg, 0x80);
+        Notify(PSTR(": "), 0x80);
+        D_PrintHex<ERROR_TYPE > (rcode, 0x80);
+        Notify(PSTR("\r\n"), 0x80);
+#endif
+}
+
+#endif // __MESSAGE_H__
diff --git a/Marlin/src/sd/usb_flashdrive/lib/parsetools.cpp b/Marlin/src/sd/usb_flashdrive/lib/parsetools.cpp
new file mode 100644
index 0000000000..1d2a542df7
--- /dev/null
+++ b/Marlin/src/sd/usb_flashdrive/lib/parsetools.cpp
@@ -0,0 +1,81 @@
+/* Copyright (C) 2011 Circuits At Home, LTD. All rights reserved.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+Contact information
+-------------------
+
+Circuits At Home, LTD
+Web      :  http://www.circuitsathome.com
+e-mail   :  support@circuitsathome.com
+ */
+
+#include "../../../inc/MarlinConfigPre.h"
+
+#if ENABLED(USB_FLASH_DRIVE_SUPPORT)
+
+#include "Usb.h"
+
+bool MultiByteValueParser::Parse(uint8_t **pp, uint16_t *pcntdn) {
+        if(!pBuf) {
+                Notify(PSTR("Buffer pointer is NULL!\r\n"), 0x80);
+                return false;
+        }
+        for(; countDown && (*pcntdn); countDown--, (*pcntdn)--, (*pp)++)
+                pBuf[valueSize - countDown] = (**pp);
+
+        if(countDown)
+                return false;
+
+        countDown = valueSize;
+        return true;
+}
+
+bool PTPListParser::Parse(uint8_t **pp, uint16_t *pcntdn, PTP_ARRAY_EL_FUNC pf, const void *me) {
+        switch(nStage) {
+                case 0:
+                        pBuf->valueSize = lenSize;
+                        theParser.Initialize(pBuf);
+                        nStage = 1;
+
+                case 1:
+                        if(!theParser.Parse(pp, pcntdn))
+                                return false;
+
+                        arLen = 0;
+                        arLen = (pBuf->valueSize >= 4) ? *((uint32_t*)pBuf->pValue) : (uint32_t)(*((uint16_t*)pBuf->pValue));
+                        arLenCntdn = arLen;
+                        nStage = 2;
+
+                case 2:
+                        pBuf->valueSize = valSize;
+                        theParser.Initialize(pBuf);
+                        nStage = 3;
+
+                case 3:
+                        for(; arLenCntdn; arLenCntdn--) {
+                                if(!theParser.Parse(pp, pcntdn))
+                                        return false;
+
+                                if(pf)
+                                        pf(pBuf, (arLen - arLenCntdn), me);
+                        }
+
+                        nStage = 0;
+        }
+        return true;
+}
+
+#endif // USB_FLASH_DRIVE_SUPPORT
diff --git a/Marlin/src/sd/usb_flashdrive/lib/parsetools.h b/Marlin/src/sd/usb_flashdrive/lib/parsetools.h
new file mode 100644
index 0000000000..6289206157
--- /dev/null
+++ b/Marlin/src/sd/usb_flashdrive/lib/parsetools.h
@@ -0,0 +1,147 @@
+/* Copyright (C) 2011 Circuits At Home, LTD. All rights reserved.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+Contact information
+-------------------
+
+Circuits At Home, LTD
+Web      :  http://www.circuitsathome.com
+e-mail   :  support@circuitsathome.com
+ */
+
+#if !defined(_usb_h_) || defined(__PARSETOOLS_H__)
+#error "Never include parsetools.h directly; include Usb.h instead"
+#else
+#define __PARSETOOLS_H__
+
+struct MultiValueBuffer {
+        uint8_t valueSize;
+        void *pValue;
+} __attribute__((packed));
+
+class MultiByteValueParser {
+        uint8_t * pBuf;
+        uint8_t countDown;
+        uint8_t valueSize;
+
+public:
+
+        MultiByteValueParser() : pBuf(NULL), countDown(0), valueSize(0) {
+        };
+
+        const uint8_t* GetBuffer() {
+                return pBuf;
+        };
+
+        void Initialize(MultiValueBuffer * const pbuf) {
+                pBuf = (uint8_t*)pbuf->pValue;
+                countDown = valueSize = pbuf->valueSize;
+        };
+
+        bool Parse(uint8_t **pp, uint16_t *pcntdn);
+};
+
+class ByteSkipper {
+        uint8_t *pBuf;
+        uint8_t nStage;
+        uint16_t countDown;
+
+public:
+
+        ByteSkipper() : pBuf(NULL), nStage(0), countDown(0) {
+        };
+
+        void Initialize(MultiValueBuffer *pbuf) {
+                pBuf = (uint8_t*)pbuf->pValue;
+                countDown = 0;
+        };
+
+        bool Skip(uint8_t **pp, uint16_t *pcntdn, uint16_t bytes_to_skip) {
+                switch(nStage) {
+                        case 0:
+                                countDown = bytes_to_skip;
+                                nStage++;
+                        case 1:
+                                for(; countDown && (*pcntdn); countDown--, (*pp)++, (*pcntdn)--);
+
+                                if(!countDown)
+                                        nStage = 0;
+                };
+                return (!countDown);
+        };
+};
+
+// Pointer to a callback function triggered for each element of PTP array when used with PTPArrayParser
+typedef void (*PTP_ARRAY_EL_FUNC)(const MultiValueBuffer * const p, uint32_t count, const void *me);
+
+class PTPListParser {
+public:
+
+        enum ParseMode {
+                modeArray, modeRange/*, modeEnum*/
+        };
+
+private:
+        uint8_t nStage;
+        uint8_t enStage;
+
+        uint32_t arLen;
+        uint32_t arLenCntdn;
+
+        uint8_t lenSize; // size of the array length field in bytes
+        uint8_t valSize; // size of the array element in bytes
+
+        MultiValueBuffer *pBuf;
+
+        // The only parser for both size and array element parsing
+        MultiByteValueParser theParser;
+
+        uint8_t /*ParseMode*/ prsMode;
+
+public:
+
+        PTPListParser() :
+        nStage(0),
+        enStage(0),
+        arLen(0),
+        arLenCntdn(0),
+        lenSize(0),
+        valSize(0),
+        pBuf(NULL),
+        prsMode(modeArray) {
+        };
+
+        void Initialize(const uint8_t len_size, const uint8_t val_size, MultiValueBuffer * const p, const uint8_t mode = modeArray) {
+                pBuf = p;
+                lenSize = len_size;
+                valSize = val_size;
+                prsMode = mode;
+
+                if(prsMode == modeRange) {
+                        arLenCntdn = arLen = 3;
+                        nStage = 2;
+                } else {
+                        arLenCntdn = arLen = 0;
+                        nStage = 0;
+                }
+                enStage = 0;
+                theParser.Initialize(p);
+        };
+
+        bool Parse(uint8_t **pp, uint16_t *pcntdn, PTP_ARRAY_EL_FUNC pf, const void *me = NULL);
+};
+
+#endif // __PARSETOOLS_H__
diff --git a/Marlin/src/sd/usb_flashdrive/lib/printhex.h b/Marlin/src/sd/usb_flashdrive/lib/printhex.h
new file mode 100644
index 0000000000..1261a2889d
--- /dev/null
+++ b/Marlin/src/sd/usb_flashdrive/lib/printhex.h
@@ -0,0 +1,91 @@
+/* Copyright (C) 2011 Circuits At Home, LTD. All rights reserved.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+Contact information
+-------------------
+
+Circuits At Home, LTD
+Web      :  http://www.circuitsathome.com
+e-mail   :  support@circuitsathome.com
+ */
+
+#if !defined(_usb_h_) || defined(__PRINTHEX_H__)
+#error "Never include printhex.h directly; include Usb.h instead"
+#else
+#define __PRINTHEX_H__
+
+void E_Notifyc(char c, int lvl);
+
+template <class T>
+void PrintHex(T val, int lvl) {
+        int num_nibbles = sizeof (T) * 2;
+
+        do {
+                char v = 48 + (((val >> (num_nibbles - 1) * 4)) & 0x0f);
+                if(v > 57) v += 7;
+                E_Notifyc(v, lvl);
+        } while(--num_nibbles);
+}
+
+template <class T>
+void PrintBin(T val, int lvl) {
+        for(T mask = (((T)1) << ((sizeof (T) << 3) - 1)); mask; mask >>= 1)
+                if(val & mask)
+                        E_Notifyc('1', lvl);
+                else
+                        E_Notifyc('0', lvl);
+}
+
+template <class T>
+void SerialPrintHex(T val) {
+        int num_nibbles = sizeof (T) * 2;
+
+        do {
+                char v = 48 + (((val >> (num_nibbles - 1) * 4)) & 0x0f);
+                if(v > 57) v += 7;
+                USB_HOST_SERIAL.print(v);
+        } while(--num_nibbles);
+}
+
+template <class T>
+void PrintHex2(Print *prn, T val) {
+        T mask = (((T)1) << (((sizeof (T) << 1) - 1) << 2));
+
+        while(mask > 1) {
+                if(val < mask)
+                        prn->print("0");
+
+                mask >>= 4;
+        }
+        prn->print((T)val, HEX);
+}
+
+template <class T> void D_PrintHex(T val __attribute__((unused)), int lvl __attribute__((unused))) {
+#ifdef DEBUG_USB_HOST
+        PrintHex<T > (val, lvl);
+#endif
+}
+
+template <class T>
+void D_PrintBin(T val, int lvl) {
+#ifdef DEBUG_USB_HOST
+        PrintBin<T > (val, lvl);
+#endif
+}
+
+
+
+#endif // __PRINTHEX_H__
diff --git a/Marlin/src/sd/usb_flashdrive/lib/settings.h b/Marlin/src/sd/usb_flashdrive/lib/settings.h
new file mode 100644
index 0000000000..b549a1ae36
--- /dev/null
+++ b/Marlin/src/sd/usb_flashdrive/lib/settings.h
@@ -0,0 +1,236 @@
+/* Copyright (C) 2011 Circuits At Home, LTD. All rights reserved.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+Contact information
+-------------------
+
+Circuits At Home, LTD
+Web      :  http://www.circuitsathome.com
+e-mail   :  support@circuitsathome.com
+ */
+
+#ifndef USB_HOST_SHIELD_SETTINGS_H
+#define USB_HOST_SHIELD_SETTINGS_H
+
+#include "../../../inc/MarlinConfig.h"
+
+#include "macros.h"
+
+#if ENABLED(USB_FLASH_DRIVE_SUPPORT)
+  ////////////////////////////////////////////////////////////////////////////////
+  /* Added by Bill Greiman to speed up mass storage initialization with USB
+   * flash drives and simple USB hard drives.
+   * Disable this by defining DELAY(x) to be delay(x).
+   */
+  #define delay(x)  if((x) < 200) safe_delay(x)
+  /* Almost all USB flash drives and simple USB hard drives fail the write
+   * protect test and add 20 - 30 seconds to USB init.  Set SKIP_WRITE_PROTECT
+   * to nonzero to skip the test and assume the drive is writable.
+   */
+  #define SKIP_WRITE_PROTECT 1
+  /* Since Marlin only cares about USB flash drives, we only need one LUN. */
+  #define MASS_MAX_SUPPORTED_LUN 1
+#endif
+////////////////////////////////////////////////////////////////////////////////
+// SPI Configuration
+////////////////////////////////////////////////////////////////////////////////
+#ifndef USB_SPI
+  #define USB_SPI SPI
+  //#define USB_SPI SPI1
+#endif
+
+////////////////////////////////////////////////////////////////////////////////
+// DEBUGGING
+////////////////////////////////////////////////////////////////////////////////
+
+/* Set this to 1 to activate serial debugging */
+#define ENABLE_UHS_DEBUGGING 0
+
+/* This can be used to select which serial port to use for debugging if
+ * multiple serial ports are available.
+ * For example Serial3.
+ */
+#if ENABLED(USB_FLASH_DRIVE_SUPPORT)
+  #define USB_HOST_SERIAL MYSERIAL0
+#endif
+
+#ifndef USB_HOST_SERIAL
+  #define USB_HOST_SERIAL Serial
+#endif
+
+////////////////////////////////////////////////////////////////////////////////
+// Manual board activation
+////////////////////////////////////////////////////////////////////////////////
+
+/* Set this to 1 if you are using an Arduino Mega ADK board with MAX3421e built-in */
+#define USE_UHS_MEGA_ADK 0 // If you are using Arduino 1.5.5 or newer there is no need to do this manually
+
+/* Set this to 1 if you are using a Black Widdow */
+#define USE_UHS_BLACK_WIDDOW 0
+
+/* Set this to a one to use the xmem2 lock. This is needed for multitasking and threading */
+#define USE_XMEM_SPI_LOCK 0
+
+////////////////////////////////////////////////////////////////////////////////
+// Wii IR camera
+////////////////////////////////////////////////////////////////////////////////
+
+/* Set this to 1 to activate code for the Wii IR camera */
+#define ENABLE_WII_IR_CAMERA 0
+
+////////////////////////////////////////////////////////////////////////////////
+// MASS STORAGE
+////////////////////////////////////////////////////////////////////////////////
+// ******* IMPORTANT *******
+// Set this to 1 to support single LUN devices, and save RAM. -- I.E. thumb drives.
+// Each LUN needs ~13 bytes to be able to track the state of each unit.
+#ifndef MASS_MAX_SUPPORTED_LUN
+  #define MASS_MAX_SUPPORTED_LUN 8
+#endif
+
+////////////////////////////////////////////////////////////////////////////////
+// Set to 1 to use the faster spi4teensy3 driver.
+////////////////////////////////////////////////////////////////////////////////
+#ifndef USE_SPI4TEENSY3
+  #define USE_SPI4TEENSY3 1
+#endif
+
+// Disabled on the Teensy LC, as it is incompatible for now
+#ifdef __MKL26Z64__
+  #undef USE_SPI4TEENSY3
+  #define USE_SPI4TEENSY3 0
+#endif
+
+////////////////////////////////////////////////////////////////////////////////
+// AUTOMATIC Settings
+////////////////////////////////////////////////////////////////////////////////
+
+// No user serviceable parts below this line.
+// DO NOT change anything below here unless you are a developer!
+
+//#include "version_helper.h"
+
+#if defined(__GNUC__) && defined(__AVR__)
+  #ifndef GCC_VERSION
+    #define GCC_VERSION (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__)
+  #endif
+  #if GCC_VERSION < 40602 // Test for GCC < 4.6.2
+    #ifdef PROGMEM
+      #undef PROGMEM
+      #define PROGMEM __attribute__((section(".progmem.data"))) // Workaround for http://gcc.gnu.org/bugzilla/show_bug.cgi?id=34734#c4
+      #ifdef PSTR
+        #undef PSTR
+        #define PSTR(s) (__extension__({static const char __c[] PROGMEM = (s); &__c[0];})) // Copied from pgmspace.h in avr-libc source
+      #endif
+    #endif
+  #endif
+#endif
+
+#if !defined(DEBUG_USB_HOST) && ENABLE_UHS_DEBUGGING
+  #define DEBUG_USB_HOST
+#endif
+
+#if !defined(WIICAMERA) && ENABLE_WII_IR_CAMERA
+  #define WIICAMERA
+#endif
+
+// To use some other locking (e.g. freertos),
+// define XMEM_ACQUIRE_SPI and XMEM_RELEASE_SPI to point to your lock and unlock.
+// NOTE: NO argument is passed. You have to do this within your routine for
+// whatever you are using to lock and unlock.
+#if !defined(XMEM_ACQUIRE_SPI)
+  #if USE_XMEM_SPI_LOCK || defined(USE_MULTIPLE_APP_API)
+    #include <xmem.h>
+  #else
+    #define XMEM_ACQUIRE_SPI() (void(0))
+    #define XMEM_RELEASE_SPI() (void(0))
+  #endif
+#endif
+
+#if !defined(EXT_RAM) && defined(EXT_RAM_STACK) || defined(EXT_RAM_HEAP)
+  #include <xmem.h>
+#else
+  #define EXT_RAM 0
+#endif
+
+#if defined(CORE_TEENSY) && defined(KINETISK)
+  #define USING_SPI4TEENSY3 USE_SPI4TEENSY3
+#else
+  #define USING_SPI4TEENSY3 0
+#endif
+#if ((defined(ARDUINO_SAM_DUE) && defined(__SAM3X8E__)) || defined(__ARDUINO_X86__) || ARDUINO >= 10600) && !USING_SPI4TEENSY3
+  #include <SPI.h> // Use the Arduino SPI library for the Arduino Due, Intel Galileo 1 & 2, Intel Edison or if the SPI library with transaction is available
+#endif
+#ifdef RBL_NRF51822
+  #include <nrf_gpio.h>
+  #include <SPI_Master.h>
+  #define SPI SPI_Master
+  #define MFK_CASTUINT8T (uint8_t) // RBLs return type for sizeof needs casting to uint8_t
+#endif
+#if defined(__PIC32MX__) || defined(__PIC32MZ__)
+  #include <../../../../hardware/pic32/libraries/SPI/SPI.h> // Hack to use the SPI library
+#endif
+
+#if defined(ESP8266) || defined(ESP32)
+  #define MFK_CASTUINT8T (uint8_t) // ESP return type for sizeof needs casting to uint8_t
+#endif
+
+#ifdef STM32F4
+  #include "stm32f4xx_hal.h"
+  extern SPI_HandleTypeDef SPI_Handle; // Needed to be declared in your main.cpp
+#endif
+
+// Fix defines on Arduino Due
+#ifdef ARDUINO_SAM_DUE
+  #ifdef tokSETUP
+    #undef tokSETUP
+  #endif
+  #ifdef tokIN
+    #undef tokIN
+  #endif
+  #ifdef tokOUT
+    #undef tokOUT
+  #endif
+  #ifdef tokINHS
+    #undef tokINHS
+  #endif
+  #ifdef tokOUTHS
+    #undef tokOUTHS
+  #endif
+#endif
+
+// Set defaults
+#ifndef MFK_CASTUINT8T
+  #define MFK_CASTUINT8T
+#endif
+
+// Workaround issue: https://github.com/esp8266/Arduino/issues/2078
+#ifdef ESP8266
+  #undef PROGMEM
+  #define PROGMEM
+#undef PSTR
+  #define PSTR(s) (s)
+#undef pgm_read_byte
+  #define pgm_read_byte(addr) (*reinterpret_cast<const uint8_t*>(addr))
+  #undef pgm_read_word
+  #define pgm_read_word(addr) (*reinterpret_cast<const uint16_t*>(addr))
+#endif
+
+#ifdef ARDUINO_ESP8266_WIFIO
+  #error "This board is currently not supported"
+#endif
+
+#endif /* SETTINGS_H */
diff --git a/Marlin/src/sd/usb_flashdrive/lib/usb_ch9.h b/Marlin/src/sd/usb_flashdrive/lib/usb_ch9.h
new file mode 100644
index 0000000000..8b5e503fcc
--- /dev/null
+++ b/Marlin/src/sd/usb_flashdrive/lib/usb_ch9.h
@@ -0,0 +1,173 @@
+/* Copyright (C) 2011 Circuits At Home, LTD. All rights reserved.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+Contact information
+-------------------
+
+Circuits At Home, LTD
+Web      :  http://www.circuitsathome.com
+e-mail   :  support@circuitsathome.com
+ */
+
+#if !defined(_usb_h_) || defined(_ch9_h_)
+#error "Never include usb_ch9.h directly; include Usb.h instead"
+#else
+
+/* USB chapter 9 structures */
+#define _ch9_h_
+
+/* Misc.USB constants */
+#define DEV_DESCR_LEN   18      //device descriptor length
+#define CONF_DESCR_LEN  9       //configuration descriptor length
+#define INTR_DESCR_LEN  9       //interface descriptor length
+#define EP_DESCR_LEN    7       //endpoint descriptor length
+
+/* Standard Device Requests */
+
+#define USB_REQUEST_GET_STATUS                  0       // Standard Device Request - GET STATUS
+#define USB_REQUEST_CLEAR_FEATURE               1       // Standard Device Request - CLEAR FEATURE
+#define USB_REQUEST_SET_FEATURE                 3       // Standard Device Request - SET FEATURE
+#define USB_REQUEST_SET_ADDRESS                 5       // Standard Device Request - SET ADDRESS
+#define USB_REQUEST_GET_DESCRIPTOR              6       // Standard Device Request - GET DESCRIPTOR
+#define USB_REQUEST_SET_DESCRIPTOR              7       // Standard Device Request - SET DESCRIPTOR
+#define USB_REQUEST_GET_CONFIGURATION           8       // Standard Device Request - GET CONFIGURATION
+#define USB_REQUEST_SET_CONFIGURATION           9       // Standard Device Request - SET CONFIGURATION
+#define USB_REQUEST_GET_INTERFACE               10      // Standard Device Request - GET INTERFACE
+#define USB_REQUEST_SET_INTERFACE               11      // Standard Device Request - SET INTERFACE
+#define USB_REQUEST_SYNCH_FRAME                 12      // Standard Device Request - SYNCH FRAME
+
+#define USB_FEATURE_ENDPOINT_HALT               0       // CLEAR/SET FEATURE - Endpoint Halt
+#define USB_FEATURE_DEVICE_REMOTE_WAKEUP        1       // CLEAR/SET FEATURE - Device remote wake-up
+#define USB_FEATURE_TEST_MODE                   2       // CLEAR/SET FEATURE - Test mode
+
+/* Setup Data Constants */
+
+#define USB_SETUP_HOST_TO_DEVICE                0x00    // Device Request bmRequestType transfer direction - host to device transfer
+#define USB_SETUP_DEVICE_TO_HOST                0x80    // Device Request bmRequestType transfer direction - device to host transfer
+#define USB_SETUP_TYPE_STANDARD                 0x00    // Device Request bmRequestType type - standard
+#define USB_SETUP_TYPE_CLASS                    0x20    // Device Request bmRequestType type - class
+#define USB_SETUP_TYPE_VENDOR                   0x40    // Device Request bmRequestType type - vendor
+#define USB_SETUP_RECIPIENT_DEVICE              0x00    // Device Request bmRequestType recipient - device
+#define USB_SETUP_RECIPIENT_INTERFACE           0x01    // Device Request bmRequestType recipient - interface
+#define USB_SETUP_RECIPIENT_ENDPOINT            0x02    // Device Request bmRequestType recipient - endpoint
+#define USB_SETUP_RECIPIENT_OTHER               0x03    // Device Request bmRequestType recipient - other
+
+/* USB descriptors  */
+
+#define USB_DESCRIPTOR_DEVICE                   0x01    // bDescriptorType for a Device Descriptor.
+#define USB_DESCRIPTOR_CONFIGURATION            0x02    // bDescriptorType for a Configuration Descriptor.
+#define USB_DESCRIPTOR_STRING                   0x03    // bDescriptorType for a String Descriptor.
+#define USB_DESCRIPTOR_INTERFACE                0x04    // bDescriptorType for an Interface Descriptor.
+#define USB_DESCRIPTOR_ENDPOINT                 0x05    // bDescriptorType for an Endpoint Descriptor.
+#define USB_DESCRIPTOR_DEVICE_QUALIFIER         0x06    // bDescriptorType for a Device Qualifier.
+#define USB_DESCRIPTOR_OTHER_SPEED              0x07    // bDescriptorType for a Other Speed Configuration.
+#define USB_DESCRIPTOR_INTERFACE_POWER          0x08    // bDescriptorType for Interface Power.
+#define USB_DESCRIPTOR_OTG                      0x09    // bDescriptorType for an OTG Descriptor.
+
+#define HID_DESCRIPTOR_HID                      0x21
+
+
+
+/* OTG SET FEATURE Constants    */
+#define OTG_FEATURE_B_HNP_ENABLE                3       // SET FEATURE OTG - Enable B device to perform HNP
+#define OTG_FEATURE_A_HNP_SUPPORT               4       // SET FEATURE OTG - A device supports HNP
+#define OTG_FEATURE_A_ALT_HNP_SUPPORT           5       // SET FEATURE OTG - Another port on the A device supports HNP
+
+/* USB Endpoint Transfer Types  */
+#define USB_TRANSFER_TYPE_CONTROL               0x00    // Endpoint is a control endpoint.
+#define USB_TRANSFER_TYPE_ISOCHRONOUS           0x01    // Endpoint is an isochronous endpoint.
+#define USB_TRANSFER_TYPE_BULK                  0x02    // Endpoint is a bulk endpoint.
+#define USB_TRANSFER_TYPE_INTERRUPT             0x03    // Endpoint is an interrupt endpoint.
+#define bmUSB_TRANSFER_TYPE                     0x03    // bit mask to separate transfer type from ISO attributes
+
+
+/* Standard Feature Selectors for CLEAR_FEATURE Requests    */
+#define USB_FEATURE_ENDPOINT_STALL              0       // Endpoint recipient
+#define USB_FEATURE_DEVICE_REMOTE_WAKEUP        1       // Device recipient
+#define USB_FEATURE_TEST_MODE                   2       // Device recipient
+
+/* descriptor data structures */
+
+/* Device descriptor structure */
+typedef struct {
+        uint8_t bLength; // Length of this descriptor.
+        uint8_t bDescriptorType; // DEVICE descriptor type (USB_DESCRIPTOR_DEVICE).
+        uint16_t bcdUSB; // USB Spec Release Number (BCD).
+        uint8_t bDeviceClass; // Class code (assigned by the USB-IF). 0xFF-Vendor specific.
+        uint8_t bDeviceSubClass; // Subclass code (assigned by the USB-IF).
+        uint8_t bDeviceProtocol; // Protocol code (assigned by the USB-IF). 0xFF-Vendor specific.
+        uint8_t bMaxPacketSize0; // Maximum packet size for endpoint 0.
+        uint16_t idVendor; // Vendor ID (assigned by the USB-IF).
+        uint16_t idProduct; // Product ID (assigned by the manufacturer).
+        uint16_t bcdDevice; // Device release number (BCD).
+        uint8_t iManufacturer; // Index of String Descriptor describing the manufacturer.
+        uint8_t iProduct; // Index of String Descriptor describing the product.
+        uint8_t iSerialNumber; // Index of String Descriptor with the device's serial number.
+        uint8_t bNumConfigurations; // Number of possible configurations.
+} __attribute__((packed)) USB_DEVICE_DESCRIPTOR;
+
+/* Configuration descriptor structure */
+typedef struct {
+        uint8_t bLength; // Length of this descriptor.
+        uint8_t bDescriptorType; // CONFIGURATION descriptor type (USB_DESCRIPTOR_CONFIGURATION).
+        uint16_t wTotalLength; // Total length of all descriptors for this configuration.
+        uint8_t bNumInterfaces; // Number of interfaces in this configuration.
+        uint8_t bConfigurationValue; // Value of this configuration (1 based).
+        uint8_t iConfiguration; // Index of String Descriptor describing the configuration.
+        uint8_t bmAttributes; // Configuration characteristics.
+        uint8_t bMaxPower; // Maximum power consumed by this configuration.
+} __attribute__((packed)) USB_CONFIGURATION_DESCRIPTOR;
+
+/* Interface descriptor structure */
+typedef struct {
+        uint8_t bLength; // Length of this descriptor.
+        uint8_t bDescriptorType; // INTERFACE descriptor type (USB_DESCRIPTOR_INTERFACE).
+        uint8_t bInterfaceNumber; // Number of this interface (0 based).
+        uint8_t bAlternateSetting; // Value of this alternate interface setting.
+        uint8_t bNumEndpoints; // Number of endpoints in this interface.
+        uint8_t bInterfaceClass; // Class code (assigned by the USB-IF).  0xFF-Vendor specific.
+        uint8_t bInterfaceSubClass; // Subclass code (assigned by the USB-IF).
+        uint8_t bInterfaceProtocol; // Protocol code (assigned by the USB-IF).  0xFF-Vendor specific.
+        uint8_t iInterface; // Index of String Descriptor describing the interface.
+} __attribute__((packed)) USB_INTERFACE_DESCRIPTOR;
+
+/* Endpoint descriptor structure */
+typedef struct {
+        uint8_t bLength; // Length of this descriptor.
+        uint8_t bDescriptorType; // ENDPOINT descriptor type (USB_DESCRIPTOR_ENDPOINT).
+        uint8_t bEndpointAddress; // Endpoint address. Bit 7 indicates direction (0=OUT, 1=IN).
+        uint8_t bmAttributes; // Endpoint transfer type.
+        uint16_t wMaxPacketSize; // Maximum packet size.
+        uint8_t bInterval; // Polling interval in frames.
+} __attribute__((packed)) USB_ENDPOINT_DESCRIPTOR;
+
+/* HID descriptor */
+typedef struct {
+        uint8_t bLength;
+        uint8_t bDescriptorType;
+        uint16_t bcdHID; // HID class specification release
+        uint8_t bCountryCode;
+        uint8_t bNumDescriptors; // Number of additional class specific descriptors
+        uint8_t bDescrType; // Type of class descriptor
+        uint16_t wDescriptorLength; // Total size of the Report descriptor
+} __attribute__((packed)) USB_HID_DESCRIPTOR;
+
+typedef struct {
+        uint8_t bDescrType; // Type of class descriptor
+        uint16_t wDescriptorLength; // Total size of the Report descriptor
+} __attribute__((packed)) HID_CLASS_DESCRIPTOR_LEN_AND_TYPE;
+
+#endif // _ch9_h_
diff --git a/Marlin/src/sd/usb_flashdrive/usb-2.0-host-library-changes.patch b/Marlin/src/sd/usb_flashdrive/usb-2.0-host-library-changes.patch
new file mode 100644
index 0000000000..c057aaba04
--- /dev/null
+++ b/Marlin/src/sd/usb_flashdrive/usb-2.0-host-library-changes.patch
@@ -0,0 +1,187 @@
+diff -Naur /home/aleph/Downloads/USB_Host_Shield_2.0-master/masstorage.cpp lib/masstorage.cpp
+--- /home/aleph/Downloads/USB_Host_Shield_2.0-master/masstorage.cpp	2018-09-21 10:19:36.107502252 -0600
++++ lib/masstorage.cpp	2018-09-21 09:46:19.620175519 -0600
+@@ -24,6 +24,8 @@
+ 
+ #include "masstorage.h"
+ 
++#if ENABLED(USB_FLASH_DRIVE_SUPPORT)
++
+ const uint8_t BulkOnly::epDataInIndex = 1;
+ const uint8_t BulkOnly::epDataOutIndex = 2;
+ const uint8_t BulkOnly::epInterruptInIndex = 3;
+@@ -796,6 +798,9 @@
+                 buf[i] = 0x00;
+         }
+         WriteOk[lun] = true;
++        #if ENABLED(USB_FLASH_DRIVE_SUPPORT) && defined(SKIP_WRITE_PROTECT)
++          return 0;
++        #endif
+         uint8_t rc = ModeSense6(lun, 0, 0x3f, 0, 192, buf);
+         if(!rc) {
+                 WriteOk[lun] = ((buf[2] & 0x80) == 0);
+@@ -1271,3 +1276,5 @@
+         return MASS_ERR_NOT_IMPLEMENTED;
+ #endif
+ }
++
++#endif // USB_FLASH_DRIVE_SUPPORT
+\ No newline at end of file
+diff -Naur /home/aleph/Downloads/USB_Host_Shield_2.0-master/message.cpp lib/message.cpp
+--- /home/aleph/Downloads/USB_Host_Shield_2.0-master/message.cpp	2018-09-21 10:20:15.995647957 -0600
++++ lib/message.cpp	2018-09-19 07:43:46.520339375 -0600
+@@ -23,6 +23,9 @@
+  */
+ 
+ #include "Usb.h"
++
++#if ENABLED(USB_FLASH_DRIVE_SUPPORT)
++
+ // 0x80 is the default (i.e. trace) to turn off set this global to something lower.
+ // this allows for 126 other debugging levels.
+ // TO-DO: Allow assignment to a different serial port by software
+@@ -120,4 +123,6 @@
+         D_PrintHex<uint8_t > (rcode, 0x80);
+         Notify(PSTR("\r\n"), 0x80);
+ }
+-#endif
++#endif // DEBUG_USB_HOST
++
++#endif // USB_FLASH_DRIVE_SUPPORT
+\ No newline at end of file
+diff -Naur /home/aleph/Downloads/USB_Host_Shield_2.0-master/parsetools.cpp lib/parsetools.cpp
+--- /home/aleph/Downloads/USB_Host_Shield_2.0-master/parsetools.cpp	2018-09-21 10:21:16.215867769 -0600
++++ lib/parsetools.cpp	2018-09-19 07:43:46.520339375 -0600
+@@ -23,6 +23,8 @@
+  */
+ #include "Usb.h"
+ 
++#if ENABLED(USB_FLASH_DRIVE_SUPPORT)
++
+ bool MultiByteValueParser::Parse(uint8_t **pp, uint16_t *pcntdn) {
+         if(!pBuf) {
+                 Notify(PSTR("Buffer pointer is NULL!\r\n"), 0x80);
+@@ -72,3 +74,5 @@
+         }
+         return true;
+ }
++
++#endif // USB_FLASH_DRIVE_SUPPORT
+\ No newline at end of file
+diff -Naur /home/aleph/Downloads/USB_Host_Shield_2.0-master/settings.h lib/settings.h
+--- /home/aleph/Downloads/USB_Host_Shield_2.0-master/settings.h	2018-09-21 10:22:21.792106872 -0600
++++ lib/settings.h	2018-09-21 10:01:53.383594081 -0600
+@@ -25,7 +25,21 @@
+ #ifndef USB_HOST_SHIELD_SETTINGS_H
+ #define USB_HOST_SHIELD_SETTINGS_H
+ #include "macros.h"
+-
++#if ENABLED(USB_FLASH_DRIVE_SUPPORT)
++  ////////////////////////////////////////////////////////////////////////////////
++  /* Added by Bill Greiman to speed up mass storage initialization with USB
++   * flash drives and simple USB hard drives.
++   * Disable this by defining DELAY(x) to be delay(x).
++   */
++  #define delay(x)  if((x) < 200) safe_delay(x)
++  /* Almost all USB flash drives and simple USB hard drives fail the write
++   * protect test and add 20 - 30 seconds to USB init.  Set SKIP_WRITE_PROTECT
++   * to nonzero to skip the test and assume the drive is writable.
++   */
++  #define SKIP_WRITE_PROTECT 1
++  /* Since Marlin only cares about USB flash drives, we only need one LUN. */
++  #define MASS_MAX_SUPPORTED_LUN 1
++#endif
+ ////////////////////////////////////////////////////////////////////////////////
+ // SPI Configuration
+ ////////////////////////////////////////////////////////////////////////////////
+@@ -45,6 +59,10 @@
+  * multiple serial ports are available.
+  * For example Serial3.
+  */
++#if ENABLED(USB_FLASH_DRIVE_SUPPORT)
++  #define USB_HOST_SERIAL MYSERIAL0
++#endif
++
+ #ifndef USB_HOST_SERIAL
+ #define USB_HOST_SERIAL Serial
+ #endif
+@@ -99,7 +117,7 @@
+ // No user serviceable parts below this line.
+ // DO NOT change anything below here unless you are a developer!
+ 
+-#include "version_helper.h"
++//#include "version_helper.h"
+ 
+ #if defined(__GNUC__) && defined(__AVR__)
+ #ifndef GCC_VERSION
+@@ -149,7 +167,6 @@
+ #else
+ #define USING_SPI4TEENSY3 0
+ #endif
+-
+ #if ((defined(ARDUINO_SAM_DUE) && defined(__SAM3X8E__)) || defined(__ARDUINO_X86__) || ARDUINO >= 10600) && !USING_SPI4TEENSY3
+ #include <SPI.h> // Use the Arduino SPI library for the Arduino Due, Intel Galileo 1 & 2, Intel Edison or if the SPI library with transaction is available
+ #endif
+diff -Naur /home/aleph/Downloads/USB_Host_Shield_2.0-master/UsbCore.h lib/UsbCore.h
+--- /home/aleph/Downloads/USB_Host_Shield_2.0-master/UsbCore.h	2018-09-21 10:23:09.348280107 -0600
++++ lib/UsbCore.h	2018-09-19 07:43:46.520339375 -0600
+@@ -32,7 +32,10 @@
+ //#define USB_METHODS_INLINE
+ 
+ /* shield pins. First parameter - SS pin, second parameter - INT pin */
+-#ifdef BOARD_BLACK_WIDDOW
++
++#if defined(__MARLIN_H__)
++typedef MAX3421e MAX3421E; // Marlin redefines this class in "../usb_host.h"
++#elif defined(BOARD_BLACK_WIDDOW)
+ typedef MAX3421e<P6, P3> MAX3421E; // Black Widow
+ #elif defined(CORE_TEENSY) && (defined(__AVR_AT90USB646__) || defined(__AVR_AT90USB1286__))
+ #if EXT_RAM
+diff -Naur /home/aleph/Downloads/USB_Host_Shield_2.0-master/Usb.cpp lib/Usb.cpp
+--- /home/aleph/Downloads/USB_Host_Shield_2.0-master/Usb.cpp	2018-09-21 10:23:20.732321559 -0600
++++ lib/Usb.cpp	2018-09-19 07:43:46.520339375 -0600
+@@ -25,6 +25,8 @@
+ 
+ #include "Usb.h"
+ 
++#if ENABLED(USB_FLASH_DRIVE_SUPPORT)
++
+ static uint8_t usb_error = 0;
+ static uint8_t usb_task_state;
+ 
+@@ -825,3 +827,4 @@
+ }
+ 
+ #endif // defined(USB_METHODS_INLINE)
++#endif // USB_FLASH_DRIVE_SUPPORT
+diff -Naur /home/aleph/Downloads/USB_Host_Shield_2.0-master/Usb.h lib/Usb.h
+--- /home/aleph/Downloads/USB_Host_Shield_2.0-master/Usb.h	2018-09-21 10:23:33.756368972 -0600
++++ lib/Usb.h	2018-09-19 07:43:46.520339375 -0600
+@@ -25,6 +25,8 @@
+ #ifndef _usb_h_
+ #define _usb_h_
+ 
++#include "../../../Marlin.h"
++
+ // WARNING: Do not change the order of includes, or stuff will break!
+ #include <inttypes.h>
+ #include <stddef.h>
+@@ -34,13 +36,15 @@
+ #include "settings.h"
+ #include "printhex.h"
+ #include "message.h"
++
+ #include "hexdump.h"
+-#include "sink_parser.h"
++//#include "sink_parser.h"
+ #include "max3421e.h"
+ #include "address.h"
+-#include "avrpins.h"
++//#include "avrpins.h"
+ #include "usb_ch9.h"
+-#include "usbhost.h"
++//#include "usbhost.h"
++#include "../usb_host.h"
+ #include "UsbCore.h"
+ #include "parsetools.h"
+ #include "confdescparser.h"
diff --git a/Marlin/src/sd/usb_flashdrive/usb_host.cpp b/Marlin/src/sd/usb_flashdrive/usb_host.cpp
new file mode 100644
index 0000000000..75a2dc7bba
--- /dev/null
+++ b/Marlin/src/sd/usb_flashdrive/usb_host.cpp
@@ -0,0 +1,213 @@
+/****************
+ * usb_host.cpp *
+ ****************/
+
+/****************************************************************************
+ *   Written By Marcio Teixeira 2018 - Aleph Objects, Inc.                  *
+ *                                                                          *
+ *   This program is free software: you can redistribute it and/or modify   *
+ *   it under the terms of the GNU General Public License as published by   *
+ *   the Free Software Foundation, either version 3 of the License, or      *
+ *   (at your option) any later version.                                    *
+ *                                                                          *
+ *   This program is distributed in the hope that it will be useful,        *
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of         *
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the          *
+ *   GNU General Public License for more details.                           *
+ *                                                                          *
+ *   To view a copy of the GNU General Public License, go to the following  *
+ *   location: <http://www.gnu.org/licenses/>.                              *
+ ****************************************************************************/
+
+/* What follows is a modified version of the MAX3421e originally defined in
+ * lib/usbhost.c". This has been rewritten to use SPI routines from the
+ * Marlin HAL */
+
+#include "../../inc/MarlinConfigPre.h"
+
+#if ENABLED(USB_FLASH_DRIVE_SUPPORT)
+
+#include "lib/Usb.h"
+#include "usb_host.h"
+
+uint8_t MAX3421e::vbusState = 0;
+
+// constructor
+void MAX3421e::cs() {
+  WRITE(USB_CS_PIN,0);
+}
+
+void MAX3421e::ncs() {
+  WRITE(USB_CS_PIN,1);
+}
+
+// write single byte into MAX3421 register
+void MAX3421e::regWr(uint8_t reg, uint8_t data) {
+  cs();
+  spiSend(reg | 0x02);
+  spiSend(data);
+  ncs();
+};
+
+// multiple-byte write
+// return a pointer to memory position after last written
+uint8_t* MAX3421e::bytesWr(uint8_t reg, uint8_t nbytes, uint8_t* data_p) {
+  cs();
+  spiSend(reg | 0x02);
+  while (nbytes--) spiSend(*data_p++);
+  ncs();
+  return data_p;
+}
+
+// GPIO write
+// GPIO byte is split between 2 registers, so two writes are needed to write one byte
+
+// GPOUT bits are in the low nybble. 0-3 in IOPINS1, 4-7 in IOPINS2
+void MAX3421e::gpioWr(uint8_t data) {
+  regWr(rIOPINS1, data);
+  regWr(rIOPINS2, data >> 4);
+}
+
+// single host register read
+uint8_t MAX3421e::regRd(uint8_t reg) {
+  cs();
+  spiSend(reg);
+  uint8_t rv = spiRec();
+  ncs();
+  return rv;
+}
+// multiple-byte register read
+
+// return a pointer to a memory position after last read
+uint8_t* MAX3421e::bytesRd(uint8_t reg, uint8_t nbytes, uint8_t* data_p) {
+  cs();
+  spiSend(reg);
+  while (nbytes--) *data_p++ = spiRec();
+  ncs();
+  return data_p;
+}
+// GPIO read. See gpioWr for explanation
+
+// GPIN pins are in high nybbles of IOPINS1, IOPINS2
+uint8_t MAX3421e::gpioRd() {
+  return (regRd(rIOPINS2) & 0xf0) | // pins 4-7, clean lower nybble
+         (regRd(rIOPINS1)   >> 4);  // shift low bits and OR with upper from previous operation.
+}
+
+// reset MAX3421e. Returns false if PLL failed to stabilize 1 second after reset
+bool MAX3421e::reset() {
+  regWr(rUSBCTL, bmCHIPRES);
+  regWr(rUSBCTL, 0x00);
+  for (uint8_t i = 100; i--;) {
+    if (regRd(rUSBIRQ) & bmOSCOKIRQ) return true;
+    delay(10);
+  }
+  return false;
+}
+
+// initialize MAX3421e. Set Host mode, pullups, and stuff. Returns 0 if success, -1 if not
+bool MAX3421e::start() {
+  // Initialize pins and SPI bus
+
+  SET_OUTPUT(SDSS);
+  SET_INPUT(USB_INTR_PIN);
+  ncs();
+  spiBegin();
+
+  spiInit(
+    #ifdef SPI_SPEED
+      SPI_SPEED
+    #else
+      SPI_FULL_SPEED
+    #endif
+  );
+
+  // MAX3421e - full-duplex, level interrupt, vbus off.
+  regWr(rPINCTL, (bmFDUPSPI | bmINTLEVEL | GPX_VBDET));
+
+  const uint8_t revision = regRd(rREVISION);
+  if (revision == 0x00 || revision == 0xFF) {
+    SERIAL_ECHOLNPAIR("Revision register appears incorrect on MAX3421e initialization, got ", revision);
+    return false;
+  }
+
+  if (!reset()) {
+    SERIAL_ECHOLNPGM("OSCOKIRQ hasn't asserted in time");
+    return false;
+  }
+
+  // Delay a minimum of 1 second to ensure any capacitors are drained.
+  // 1 second is required to make sure we do not smoke a Microdrive!
+
+  delay(1000);
+
+  regWr(rMODE, bmDPPULLDN | bmDMPULLDN | bmHOST); // set pull-downs, Host
+  regWr(rHIEN, bmCONDETIE | bmFRAMEIE); // connection detection
+
+  // check if device is connected
+  regWr(rHCTL, bmSAMPLEBUS); // sample USB bus
+  while (!(regRd(rHCTL) & bmSAMPLEBUS)) delay(10); // wait for sample operation to finish
+
+  busprobe(); // check if anything is connected
+
+  regWr(rHIRQ, bmCONDETIRQ); // clear connection detect interrupt
+  regWr(rCPUCTL, 0x01);      // enable interrupt pin
+
+  // GPX pin on. This is done here so that busprobe will fail if we have a switch connected.
+  regWr(rPINCTL, bmFDUPSPI | bmINTLEVEL);
+
+  return true;
+}
+
+// Probe bus to determine device presence and speed. Switch host to this speed.
+void MAX3421e::busprobe() {
+  // Switch on just the J & K bits
+  switch (regRd(rHRSL) & (bmJSTATUS | bmKSTATUS)) {
+    case bmJSTATUS:
+      if ((regRd(rMODE) & bmLOWSPEED) == 0) {
+        regWr(rMODE, MODE_FS_HOST); // start full-speed host
+        vbusState = FSHOST;
+      }
+      else {
+        regWr(rMODE, MODE_LS_HOST); // start low-speed host
+        vbusState = LSHOST;
+      }
+      break;
+    case bmKSTATUS:
+      if ((regRd(rMODE) & bmLOWSPEED) == 0) {
+        regWr(rMODE, MODE_LS_HOST); // start low-speed host
+        vbusState = LSHOST;
+      }
+      else {
+        regWr(rMODE, MODE_FS_HOST); // start full-speed host
+        vbusState = FSHOST;
+      }
+      break;
+    case bmSE1: // illegal state
+      vbusState = SE1;
+      break;
+    case bmSE0: // disconnected state
+      regWr(rMODE, bmDPPULLDN | bmDMPULLDN | bmHOST | bmSEPIRQ);
+      vbusState = SE0;
+      break;
+  }
+}
+
+// MAX3421 state change task and interrupt handler
+uint8_t MAX3421e::Task(void) {
+  return READ(USB_INTR_PIN) ? 0 : IntHandler();
+}
+
+uint8_t MAX3421e::IntHandler() {
+  uint8_t HIRQ = regRd(rHIRQ), // determine interrupt source
+          HIRQ_sendback = 0x00;
+  if (HIRQ & bmCONDETIRQ) {
+    busprobe();
+    HIRQ_sendback |= bmCONDETIRQ;
+  }
+  // End HIRQ interrupts handling, clear serviced IRQs
+  regWr(rHIRQ, HIRQ_sendback);
+  return HIRQ_sendback;
+}
+
+#endif // USB_FLASH_DRIVE_SUPPORT
diff --git a/Marlin/src/sd/usb_flashdrive/usb_host.h b/Marlin/src/sd/usb_flashdrive/usb_host.h
new file mode 100644
index 0000000000..e19fcfe914
--- /dev/null
+++ b/Marlin/src/sd/usb_flashdrive/usb_host.h
@@ -0,0 +1,61 @@
+/**************
+ * usb_host.h *
+ **************/
+
+/****************************************************************************
+ *   Written By Marcio Teixeira 2018 - Aleph Objects, Inc.                  *
+ *                                                                          *
+ *   This program is free software: you can redistribute it and/or modify   *
+ *   it under the terms of the GNU General Public License as published by   *
+ *   the Free Software Foundation, either version 3 of the License, or      *
+ *   (at your option) any later version.                                    *
+ *                                                                          *
+ *   This program is distributed in the hope that it will be useful,        *
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of         *
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the          *
+ *   GNU General Public License for more details.                           *
+ *                                                                          *
+ *   To view a copy of the GNU General Public License, go to the following  *
+ *   location: <http://www.gnu.org/licenses/>.                              *
+ ****************************************************************************/
+
+#ifndef _USB_HOST_H_
+#define _USB_HOST_H_
+
+/* This the following comes from "lib/usbhost.h", but has been rewritten
+ * to use the SPI functions from Marlin's HAL */
+
+class MAX3421e {
+  private:
+    static uint8_t vbusState;
+    void cs();
+    void ncs();
+
+    uint8_t GpxHandler();
+    uint8_t IntHandler();
+
+  public:
+    bool      start();
+
+    void      regWr(uint8_t reg, uint8_t data);
+    uint8_t*  bytesWr(uint8_t reg, uint8_t nbytes, uint8_t* data_p);
+    void      gpioWr(uint8_t data);
+    uint8_t   regRd(uint8_t reg);
+    uint8_t*  bytesRd(uint8_t reg, uint8_t nbytes, uint8_t* data_p);
+    uint8_t   gpioRd();
+    bool      reset();
+
+    uint8_t   getVbusState(void)   {return vbusState;};
+
+    void busprobe();
+
+    uint8_t Task();
+};
+
+#define USE_MARLIN_MAX3421E
+
+#if defined(__SAM3X8E__) && !defined(ARDUINO_SAM_DUE)
+  #define ARDUINO_SAM_DUE // Spoof the USB library that this is a DUE
+#endif
+
+#endif // _USB_HOST_H_
diff --git a/buildroot/share/tests/megaatmega2560_tests b/buildroot/share/tests/megaatmega2560_tests
index 7477289d54..5c967c1713 100755
--- a/buildroot/share/tests/megaatmega2560_tests
+++ b/buildroot/share/tests/megaatmega2560_tests
@@ -45,7 +45,7 @@ opt_set TEMP_SENSOR_4 999
 opt_set TEMP_SENSOR_BED 1
 opt_enable AUTO_BED_LEVELING_UBL RESTORE_LEVELING_AFTER_G28 DEBUG_LEVELING_FEATURE G26_MESH_EDITING ENABLE_LEVELING_FADE_HEIGHT SKEW_CORRECTION \
            EEPROM_SETTINGS EEPROM_CHITCHAT REPRAP_DISCOUNT_FULL_GRAPHIC_SMART_CONTROLLER SDSUPPORT
-opt_enable_adv SDCARD_SORT_ALPHA STATUS_MESSAGE_SCROLLING SCROLL_LONG_FILENAMES LIGHTWEIGHT_UI \
+opt_enable_adv USB_FLASH_DRIVE_SUPPORT SDCARD_SORT_ALPHA STATUS_MESSAGE_SCROLLING SCROLL_LONG_FILENAMES LIGHTWEIGHT_UI \
                CUSTOM_USER_MENUS I2C_POSITION_ENCODERS BABYSTEPPING BABYSTEP_XY LIN_ADVANCE NANODLP_Z_SYNC QUICK_HOME JUNCTION_DEVIATION
 exec_test $1 $2 "Probeless build of AUTO_BED_LEVELING_UBL, with lots of extruders"
 #

From fc326b3dde8f02a8feb6fc9187b8ded4629028cc Mon Sep 17 00:00:00 2001
From: Scott Lahteine <github@thinkyhead.com>
Date: Thu, 4 Oct 2018 19:04:51 -0500
Subject: [PATCH 2/2] Add USB_FLASH_DRIVE_SUPPORT to examples

Co-Authored-By: marcio-ao <marcio@alephobjects.com>
---
 .../AlephObjects/TAZ4/Configuration_adv.h      | 18 ++++++++++++++++++
 .../examples/Anet/A2/Configuration_adv.h       | 18 ++++++++++++++++++
 .../examples/Anet/A2plus/Configuration_adv.h   | 18 ++++++++++++++++++
 .../examples/Anet/A6/Configuration_adv.h       | 18 ++++++++++++++++++
 .../examples/Anet/A8/Configuration_adv.h       | 18 ++++++++++++++++++
 .../BIBO/TouchX/cyclops/Configuration_adv.h    | 18 ++++++++++++++++++
 .../BIBO/TouchX/default/Configuration_adv.h    | 18 ++++++++++++++++++
 .../examples/BQ/Hephestos/Configuration_adv.h  | 18 ++++++++++++++++++
 .../BQ/Hephestos_2/Configuration_adv.h         | 18 ++++++++++++++++++
 .../examples/BQ/WITBOX/Configuration_adv.h     | 18 ++++++++++++++++++
 .../examples/Cartesio/Configuration_adv.h      | 18 ++++++++++++++++++
 .../Creality/CR-10/Configuration_adv.h         | 18 ++++++++++++++++++
 .../Creality/CR-10S/Configuration_adv.h        | 18 ++++++++++++++++++
 .../Creality/CR-10mini/Configuration_adv.h     | 18 ++++++++++++++++++
 .../examples/Creality/CR-8/Configuration_adv.h | 18 ++++++++++++++++++
 .../Creality/Ender-2/Configuration_adv.h       | 18 ++++++++++++++++++
 .../Creality/Ender-3/Configuration_adv.h       | 18 ++++++++++++++++++
 .../Creality/Ender-4/Configuration_adv.h       | 18 ++++++++++++++++++
 .../examples/Einstart-S/Configuration_adv.h    | 18 ++++++++++++++++++
 .../config/examples/Felix/Configuration_adv.h  | 18 ++++++++++++++++++
 .../FolgerTech/i3-2020/Configuration_adv.h     | 18 ++++++++++++++++++
 .../Formbot/Raptor/Configuration_adv.h         | 18 ++++++++++++++++++
 .../Formbot/T_Rex_2+/Configuration_adv.h       | 18 ++++++++++++++++++
 .../Formbot/T_Rex_3/Configuration_adv.h        | 18 ++++++++++++++++++
 .../Prusa i3 Pro C/Configuration_adv.h         | 18 ++++++++++++++++++
 .../Prusa i3 Pro W/Configuration_adv.h         | 18 ++++++++++++++++++
 .../Infitary/i3-M508/Configuration_adv.h       | 18 ++++++++++++++++++
 .../examples/JGAurora/A5/Configuration_adv.h   | 18 ++++++++++++++++++
 .../examples/MakerParts/Configuration_adv.h    | 18 ++++++++++++++++++
 .../examples/Malyan/M150/Configuration_adv.h   | 18 ++++++++++++++++++
 .../examples/Malyan/M200/Configuration_adv.h   | 18 ++++++++++++++++++
 .../Micromake/C1/enhanced/Configuration_adv.h  | 18 ++++++++++++++++++
 .../examples/Mks/Sbase/Configuration_adv.h     | 18 ++++++++++++++++++
 .../examples/RigidBot/Configuration_adv.h      | 18 ++++++++++++++++++
 .../config/examples/SCARA/Configuration_adv.h  | 18 ++++++++++++++++++
 .../examples/Sanguinololu/Configuration_adv.h  | 18 ++++++++++++++++++
 .../examples/TheBorg/Configuration_adv.h       | 18 ++++++++++++++++++
 .../examples/TinyBoy2/Configuration_adv.h      | 18 ++++++++++++++++++
 .../examples/Tronxy/X3A/Configuration_adv.h    | 18 ++++++++++++++++++
 .../UltiMachine/Archim2/Configuration_adv.h    | 18 ++++++++++++++++++
 .../Velleman/K8200/Configuration_adv.h         | 18 ++++++++++++++++++
 .../Velleman/K8400/Configuration_adv.h         | 18 ++++++++++++++++++
 .../Wanhao/Duplicator 6/Configuration_adv.h    | 18 ++++++++++++++++++
 .../delta/Anycubic/Kossel/Configuration_adv.h  | 18 ++++++++++++++++++
 .../FLSUN/auto_calibrate/Configuration_adv.h   | 18 ++++++++++++++++++
 .../delta/FLSUN/kossel/Configuration_adv.h     | 18 ++++++++++++++++++
 .../FLSUN/kossel_mini/Configuration_adv.h      | 18 ++++++++++++++++++
 .../examples/delta/generic/Configuration_adv.h | 18 ++++++++++++++++++
 .../delta/kossel_mini/Configuration_adv.h      | 18 ++++++++++++++++++
 .../delta/kossel_xl/Configuration_adv.h        | 18 ++++++++++++++++++
 .../gCreate/gMax1.5+/Configuration_adv.h       | 18 ++++++++++++++++++
 .../examples/makibox/Configuration_adv.h       | 18 ++++++++++++++++++
 .../examples/tvrrug/Round2/Configuration_adv.h | 18 ++++++++++++++++++
 .../config/examples/wt150/Configuration_adv.h  | 18 ++++++++++++++++++
 54 files changed, 972 insertions(+)

diff --git a/Marlin/src/config/examples/AlephObjects/TAZ4/Configuration_adv.h b/Marlin/src/config/examples/AlephObjects/TAZ4/Configuration_adv.h
index 22050a13f2..40bf2c1878 100644
--- a/Marlin/src/config/examples/AlephObjects/TAZ4/Configuration_adv.h
+++ b/Marlin/src/config/examples/AlephObjects/TAZ4/Configuration_adv.h
@@ -683,6 +683,24 @@
    */
   //#define AUTO_REPORT_SD_STATUS
 
+  /**
+   * Support for USB thumb drives using an Arduino USB Host Shield or
+   * equivalent MAX3421E breakout board. The USB thumb drive will appear
+   * to Marlin as an SD card.
+   *
+   * The MAX3421E must be assigned the same pins as the SD card reader, with
+   * the following pin mapping:
+   *
+   *    SCLK, MOSI, MISO --> SCLK, MOSI, MISO
+   *    INT              --> SD_DETECT_PIN
+   *    SS               --> SDSS
+   */
+  //#define USB_FLASH_DRIVE_SUPPORT
+  #if ENABLED(USB_FLASH_DRIVE_SUPPORT)
+    #define USB_CS_PIN         SDSS
+    #define USB_INTR_PIN       SD_DETECT_PIN
+  #endif
+
 #endif // SDSUPPORT
 
 /**
diff --git a/Marlin/src/config/examples/Anet/A2/Configuration_adv.h b/Marlin/src/config/examples/Anet/A2/Configuration_adv.h
index 3018b2737c..3967a8e746 100644
--- a/Marlin/src/config/examples/Anet/A2/Configuration_adv.h
+++ b/Marlin/src/config/examples/Anet/A2/Configuration_adv.h
@@ -683,6 +683,24 @@
    */
   //#define AUTO_REPORT_SD_STATUS
 
+  /**
+   * Support for USB thumb drives using an Arduino USB Host Shield or
+   * equivalent MAX3421E breakout board. The USB thumb drive will appear
+   * to Marlin as an SD card.
+   *
+   * The MAX3421E must be assigned the same pins as the SD card reader, with
+   * the following pin mapping:
+   *
+   *    SCLK, MOSI, MISO --> SCLK, MOSI, MISO
+   *    INT              --> SD_DETECT_PIN
+   *    SS               --> SDSS
+   */
+  //#define USB_FLASH_DRIVE_SUPPORT
+  #if ENABLED(USB_FLASH_DRIVE_SUPPORT)
+    #define USB_CS_PIN         SDSS
+    #define USB_INTR_PIN       SD_DETECT_PIN
+  #endif
+
 #endif // SDSUPPORT
 
 /**
diff --git a/Marlin/src/config/examples/Anet/A2plus/Configuration_adv.h b/Marlin/src/config/examples/Anet/A2plus/Configuration_adv.h
index 3018b2737c..3967a8e746 100644
--- a/Marlin/src/config/examples/Anet/A2plus/Configuration_adv.h
+++ b/Marlin/src/config/examples/Anet/A2plus/Configuration_adv.h
@@ -683,6 +683,24 @@
    */
   //#define AUTO_REPORT_SD_STATUS
 
+  /**
+   * Support for USB thumb drives using an Arduino USB Host Shield or
+   * equivalent MAX3421E breakout board. The USB thumb drive will appear
+   * to Marlin as an SD card.
+   *
+   * The MAX3421E must be assigned the same pins as the SD card reader, with
+   * the following pin mapping:
+   *
+   *    SCLK, MOSI, MISO --> SCLK, MOSI, MISO
+   *    INT              --> SD_DETECT_PIN
+   *    SS               --> SDSS
+   */
+  //#define USB_FLASH_DRIVE_SUPPORT
+  #if ENABLED(USB_FLASH_DRIVE_SUPPORT)
+    #define USB_CS_PIN         SDSS
+    #define USB_INTR_PIN       SD_DETECT_PIN
+  #endif
+
 #endif // SDSUPPORT
 
 /**
diff --git a/Marlin/src/config/examples/Anet/A6/Configuration_adv.h b/Marlin/src/config/examples/Anet/A6/Configuration_adv.h
index f3f405329f..793f661093 100644
--- a/Marlin/src/config/examples/Anet/A6/Configuration_adv.h
+++ b/Marlin/src/config/examples/Anet/A6/Configuration_adv.h
@@ -683,6 +683,24 @@
    */
   //#define AUTO_REPORT_SD_STATUS
 
+  /**
+   * Support for USB thumb drives using an Arduino USB Host Shield or
+   * equivalent MAX3421E breakout board. The USB thumb drive will appear
+   * to Marlin as an SD card.
+   *
+   * The MAX3421E must be assigned the same pins as the SD card reader, with
+   * the following pin mapping:
+   *
+   *    SCLK, MOSI, MISO --> SCLK, MOSI, MISO
+   *    INT              --> SD_DETECT_PIN
+   *    SS               --> SDSS
+   */
+  //#define USB_FLASH_DRIVE_SUPPORT
+  #if ENABLED(USB_FLASH_DRIVE_SUPPORT)
+    #define USB_CS_PIN         SDSS
+    #define USB_INTR_PIN       SD_DETECT_PIN
+  #endif
+
 #endif // SDSUPPORT
 
 /**
diff --git a/Marlin/src/config/examples/Anet/A8/Configuration_adv.h b/Marlin/src/config/examples/Anet/A8/Configuration_adv.h
index ade13db654..92bad26e64 100644
--- a/Marlin/src/config/examples/Anet/A8/Configuration_adv.h
+++ b/Marlin/src/config/examples/Anet/A8/Configuration_adv.h
@@ -683,6 +683,24 @@
    */
   //#define AUTO_REPORT_SD_STATUS
 
+  /**
+   * Support for USB thumb drives using an Arduino USB Host Shield or
+   * equivalent MAX3421E breakout board. The USB thumb drive will appear
+   * to Marlin as an SD card.
+   *
+   * The MAX3421E must be assigned the same pins as the SD card reader, with
+   * the following pin mapping:
+   *
+   *    SCLK, MOSI, MISO --> SCLK, MOSI, MISO
+   *    INT              --> SD_DETECT_PIN
+   *    SS               --> SDSS
+   */
+  //#define USB_FLASH_DRIVE_SUPPORT
+  #if ENABLED(USB_FLASH_DRIVE_SUPPORT)
+    #define USB_CS_PIN         SDSS
+    #define USB_INTR_PIN       SD_DETECT_PIN
+  #endif
+
 #endif // SDSUPPORT
 
 /**
diff --git a/Marlin/src/config/examples/BIBO/TouchX/cyclops/Configuration_adv.h b/Marlin/src/config/examples/BIBO/TouchX/cyclops/Configuration_adv.h
index ba7119039e..c7c8a16a9d 100644
--- a/Marlin/src/config/examples/BIBO/TouchX/cyclops/Configuration_adv.h
+++ b/Marlin/src/config/examples/BIBO/TouchX/cyclops/Configuration_adv.h
@@ -683,6 +683,24 @@
    */
   //#define AUTO_REPORT_SD_STATUS
 
+  /**
+   * Support for USB thumb drives using an Arduino USB Host Shield or
+   * equivalent MAX3421E breakout board. The USB thumb drive will appear
+   * to Marlin as an SD card.
+   *
+   * The MAX3421E must be assigned the same pins as the SD card reader, with
+   * the following pin mapping:
+   *
+   *    SCLK, MOSI, MISO --> SCLK, MOSI, MISO
+   *    INT              --> SD_DETECT_PIN
+   *    SS               --> SDSS
+   */
+  //#define USB_FLASH_DRIVE_SUPPORT
+  #if ENABLED(USB_FLASH_DRIVE_SUPPORT)
+    #define USB_CS_PIN         SDSS
+    #define USB_INTR_PIN       SD_DETECT_PIN
+  #endif
+
 #endif // SDSUPPORT
 
 /**
diff --git a/Marlin/src/config/examples/BIBO/TouchX/default/Configuration_adv.h b/Marlin/src/config/examples/BIBO/TouchX/default/Configuration_adv.h
index fc34b1853b..4ea5cc3ea4 100644
--- a/Marlin/src/config/examples/BIBO/TouchX/default/Configuration_adv.h
+++ b/Marlin/src/config/examples/BIBO/TouchX/default/Configuration_adv.h
@@ -683,6 +683,24 @@
    */
   //#define AUTO_REPORT_SD_STATUS
 
+  /**
+   * Support for USB thumb drives using an Arduino USB Host Shield or
+   * equivalent MAX3421E breakout board. The USB thumb drive will appear
+   * to Marlin as an SD card.
+   *
+   * The MAX3421E must be assigned the same pins as the SD card reader, with
+   * the following pin mapping:
+   *
+   *    SCLK, MOSI, MISO --> SCLK, MOSI, MISO
+   *    INT              --> SD_DETECT_PIN
+   *    SS               --> SDSS
+   */
+  //#define USB_FLASH_DRIVE_SUPPORT
+  #if ENABLED(USB_FLASH_DRIVE_SUPPORT)
+    #define USB_CS_PIN         SDSS
+    #define USB_INTR_PIN       SD_DETECT_PIN
+  #endif
+
 #endif // SDSUPPORT
 
 /**
diff --git a/Marlin/src/config/examples/BQ/Hephestos/Configuration_adv.h b/Marlin/src/config/examples/BQ/Hephestos/Configuration_adv.h
index 18f1e1853c..330f447352 100644
--- a/Marlin/src/config/examples/BQ/Hephestos/Configuration_adv.h
+++ b/Marlin/src/config/examples/BQ/Hephestos/Configuration_adv.h
@@ -683,6 +683,24 @@
    */
   //#define AUTO_REPORT_SD_STATUS
 
+  /**
+   * Support for USB thumb drives using an Arduino USB Host Shield or
+   * equivalent MAX3421E breakout board. The USB thumb drive will appear
+   * to Marlin as an SD card.
+   *
+   * The MAX3421E must be assigned the same pins as the SD card reader, with
+   * the following pin mapping:
+   *
+   *    SCLK, MOSI, MISO --> SCLK, MOSI, MISO
+   *    INT              --> SD_DETECT_PIN
+   *    SS               --> SDSS
+   */
+  //#define USB_FLASH_DRIVE_SUPPORT
+  #if ENABLED(USB_FLASH_DRIVE_SUPPORT)
+    #define USB_CS_PIN         SDSS
+    #define USB_INTR_PIN       SD_DETECT_PIN
+  #endif
+
 #endif // SDSUPPORT
 
 /**
diff --git a/Marlin/src/config/examples/BQ/Hephestos_2/Configuration_adv.h b/Marlin/src/config/examples/BQ/Hephestos_2/Configuration_adv.h
index 252c0bb687..0c40af37d2 100644
--- a/Marlin/src/config/examples/BQ/Hephestos_2/Configuration_adv.h
+++ b/Marlin/src/config/examples/BQ/Hephestos_2/Configuration_adv.h
@@ -691,6 +691,24 @@
    */
   //#define AUTO_REPORT_SD_STATUS
 
+  /**
+   * Support for USB thumb drives using an Arduino USB Host Shield or
+   * equivalent MAX3421E breakout board. The USB thumb drive will appear
+   * to Marlin as an SD card.
+   *
+   * The MAX3421E must be assigned the same pins as the SD card reader, with
+   * the following pin mapping:
+   *
+   *    SCLK, MOSI, MISO --> SCLK, MOSI, MISO
+   *    INT              --> SD_DETECT_PIN
+   *    SS               --> SDSS
+   */
+  //#define USB_FLASH_DRIVE_SUPPORT
+  #if ENABLED(USB_FLASH_DRIVE_SUPPORT)
+    #define USB_CS_PIN         SDSS
+    #define USB_INTR_PIN       SD_DETECT_PIN
+  #endif
+
 #endif // SDSUPPORT
 
 /**
diff --git a/Marlin/src/config/examples/BQ/WITBOX/Configuration_adv.h b/Marlin/src/config/examples/BQ/WITBOX/Configuration_adv.h
index 18f1e1853c..330f447352 100644
--- a/Marlin/src/config/examples/BQ/WITBOX/Configuration_adv.h
+++ b/Marlin/src/config/examples/BQ/WITBOX/Configuration_adv.h
@@ -683,6 +683,24 @@
    */
   //#define AUTO_REPORT_SD_STATUS
 
+  /**
+   * Support for USB thumb drives using an Arduino USB Host Shield or
+   * equivalent MAX3421E breakout board. The USB thumb drive will appear
+   * to Marlin as an SD card.
+   *
+   * The MAX3421E must be assigned the same pins as the SD card reader, with
+   * the following pin mapping:
+   *
+   *    SCLK, MOSI, MISO --> SCLK, MOSI, MISO
+   *    INT              --> SD_DETECT_PIN
+   *    SS               --> SDSS
+   */
+  //#define USB_FLASH_DRIVE_SUPPORT
+  #if ENABLED(USB_FLASH_DRIVE_SUPPORT)
+    #define USB_CS_PIN         SDSS
+    #define USB_INTR_PIN       SD_DETECT_PIN
+  #endif
+
 #endif // SDSUPPORT
 
 /**
diff --git a/Marlin/src/config/examples/Cartesio/Configuration_adv.h b/Marlin/src/config/examples/Cartesio/Configuration_adv.h
index 50ab4b2b4d..143fb18cc4 100644
--- a/Marlin/src/config/examples/Cartesio/Configuration_adv.h
+++ b/Marlin/src/config/examples/Cartesio/Configuration_adv.h
@@ -683,6 +683,24 @@
    */
   //#define AUTO_REPORT_SD_STATUS
 
+  /**
+   * Support for USB thumb drives using an Arduino USB Host Shield or
+   * equivalent MAX3421E breakout board. The USB thumb drive will appear
+   * to Marlin as an SD card.
+   *
+   * The MAX3421E must be assigned the same pins as the SD card reader, with
+   * the following pin mapping:
+   *
+   *    SCLK, MOSI, MISO --> SCLK, MOSI, MISO
+   *    INT              --> SD_DETECT_PIN
+   *    SS               --> SDSS
+   */
+  //#define USB_FLASH_DRIVE_SUPPORT
+  #if ENABLED(USB_FLASH_DRIVE_SUPPORT)
+    #define USB_CS_PIN         SDSS
+    #define USB_INTR_PIN       SD_DETECT_PIN
+  #endif
+
 #endif // SDSUPPORT
 
 /**
diff --git a/Marlin/src/config/examples/Creality/CR-10/Configuration_adv.h b/Marlin/src/config/examples/Creality/CR-10/Configuration_adv.h
index 34d440446f..028857f481 100755
--- a/Marlin/src/config/examples/Creality/CR-10/Configuration_adv.h
+++ b/Marlin/src/config/examples/Creality/CR-10/Configuration_adv.h
@@ -683,6 +683,24 @@
    */
   //#define AUTO_REPORT_SD_STATUS
 
+  /**
+   * Support for USB thumb drives using an Arduino USB Host Shield or
+   * equivalent MAX3421E breakout board. The USB thumb drive will appear
+   * to Marlin as an SD card.
+   *
+   * The MAX3421E must be assigned the same pins as the SD card reader, with
+   * the following pin mapping:
+   *
+   *    SCLK, MOSI, MISO --> SCLK, MOSI, MISO
+   *    INT              --> SD_DETECT_PIN
+   *    SS               --> SDSS
+   */
+  //#define USB_FLASH_DRIVE_SUPPORT
+  #if ENABLED(USB_FLASH_DRIVE_SUPPORT)
+    #define USB_CS_PIN         SDSS
+    #define USB_INTR_PIN       SD_DETECT_PIN
+  #endif
+
 #endif // SDSUPPORT
 
 /**
diff --git a/Marlin/src/config/examples/Creality/CR-10S/Configuration_adv.h b/Marlin/src/config/examples/Creality/CR-10S/Configuration_adv.h
index 1b0a0c865f..f7e3387b3e 100644
--- a/Marlin/src/config/examples/Creality/CR-10S/Configuration_adv.h
+++ b/Marlin/src/config/examples/Creality/CR-10S/Configuration_adv.h
@@ -683,6 +683,24 @@
    */
   //#define AUTO_REPORT_SD_STATUS
 
+  /**
+   * Support for USB thumb drives using an Arduino USB Host Shield or
+   * equivalent MAX3421E breakout board. The USB thumb drive will appear
+   * to Marlin as an SD card.
+   *
+   * The MAX3421E must be assigned the same pins as the SD card reader, with
+   * the following pin mapping:
+   *
+   *    SCLK, MOSI, MISO --> SCLK, MOSI, MISO
+   *    INT              --> SD_DETECT_PIN
+   *    SS               --> SDSS
+   */
+  //#define USB_FLASH_DRIVE_SUPPORT
+  #if ENABLED(USB_FLASH_DRIVE_SUPPORT)
+    #define USB_CS_PIN         SDSS
+    #define USB_INTR_PIN       SD_DETECT_PIN
+  #endif
+
 #endif // SDSUPPORT
 
 /**
diff --git a/Marlin/src/config/examples/Creality/CR-10mini/Configuration_adv.h b/Marlin/src/config/examples/Creality/CR-10mini/Configuration_adv.h
index 6bc256d981..318fcd5ac5 100644
--- a/Marlin/src/config/examples/Creality/CR-10mini/Configuration_adv.h
+++ b/Marlin/src/config/examples/Creality/CR-10mini/Configuration_adv.h
@@ -683,6 +683,24 @@
    */
   //#define AUTO_REPORT_SD_STATUS
 
+  /**
+   * Support for USB thumb drives using an Arduino USB Host Shield or
+   * equivalent MAX3421E breakout board. The USB thumb drive will appear
+   * to Marlin as an SD card.
+   *
+   * The MAX3421E must be assigned the same pins as the SD card reader, with
+   * the following pin mapping:
+   *
+   *    SCLK, MOSI, MISO --> SCLK, MOSI, MISO
+   *    INT              --> SD_DETECT_PIN
+   *    SS               --> SDSS
+   */
+  //#define USB_FLASH_DRIVE_SUPPORT
+  #if ENABLED(USB_FLASH_DRIVE_SUPPORT)
+    #define USB_CS_PIN         SDSS
+    #define USB_INTR_PIN       SD_DETECT_PIN
+  #endif
+
 #endif // SDSUPPORT
 
 /**
diff --git a/Marlin/src/config/examples/Creality/CR-8/Configuration_adv.h b/Marlin/src/config/examples/Creality/CR-8/Configuration_adv.h
index e8a0eea767..a118fe1f7c 100644
--- a/Marlin/src/config/examples/Creality/CR-8/Configuration_adv.h
+++ b/Marlin/src/config/examples/Creality/CR-8/Configuration_adv.h
@@ -683,6 +683,24 @@
    */
   //#define AUTO_REPORT_SD_STATUS
 
+  /**
+   * Support for USB thumb drives using an Arduino USB Host Shield or
+   * equivalent MAX3421E breakout board. The USB thumb drive will appear
+   * to Marlin as an SD card.
+   *
+   * The MAX3421E must be assigned the same pins as the SD card reader, with
+   * the following pin mapping:
+   *
+   *    SCLK, MOSI, MISO --> SCLK, MOSI, MISO
+   *    INT              --> SD_DETECT_PIN
+   *    SS               --> SDSS
+   */
+  //#define USB_FLASH_DRIVE_SUPPORT
+  #if ENABLED(USB_FLASH_DRIVE_SUPPORT)
+    #define USB_CS_PIN         SDSS
+    #define USB_INTR_PIN       SD_DETECT_PIN
+  #endif
+
 #endif // SDSUPPORT
 
 /**
diff --git a/Marlin/src/config/examples/Creality/Ender-2/Configuration_adv.h b/Marlin/src/config/examples/Creality/Ender-2/Configuration_adv.h
index 1e7808e577..8aa836b8d8 100644
--- a/Marlin/src/config/examples/Creality/Ender-2/Configuration_adv.h
+++ b/Marlin/src/config/examples/Creality/Ender-2/Configuration_adv.h
@@ -683,6 +683,24 @@
    */
   //#define AUTO_REPORT_SD_STATUS
 
+  /**
+   * Support for USB thumb drives using an Arduino USB Host Shield or
+   * equivalent MAX3421E breakout board. The USB thumb drive will appear
+   * to Marlin as an SD card.
+   *
+   * The MAX3421E must be assigned the same pins as the SD card reader, with
+   * the following pin mapping:
+   *
+   *    SCLK, MOSI, MISO --> SCLK, MOSI, MISO
+   *    INT              --> SD_DETECT_PIN
+   *    SS               --> SDSS
+   */
+  //#define USB_FLASH_DRIVE_SUPPORT
+  #if ENABLED(USB_FLASH_DRIVE_SUPPORT)
+    #define USB_CS_PIN         SDSS
+    #define USB_INTR_PIN       SD_DETECT_PIN
+  #endif
+
 #endif // SDSUPPORT
 
 /**
diff --git a/Marlin/src/config/examples/Creality/Ender-3/Configuration_adv.h b/Marlin/src/config/examples/Creality/Ender-3/Configuration_adv.h
index c2c479fb70..69ef271feb 100644
--- a/Marlin/src/config/examples/Creality/Ender-3/Configuration_adv.h
+++ b/Marlin/src/config/examples/Creality/Ender-3/Configuration_adv.h
@@ -683,6 +683,24 @@
    */
   //#define AUTO_REPORT_SD_STATUS
 
+  /**
+   * Support for USB thumb drives using an Arduino USB Host Shield or
+   * equivalent MAX3421E breakout board. The USB thumb drive will appear
+   * to Marlin as an SD card.
+   *
+   * The MAX3421E must be assigned the same pins as the SD card reader, with
+   * the following pin mapping:
+   *
+   *    SCLK, MOSI, MISO --> SCLK, MOSI, MISO
+   *    INT              --> SD_DETECT_PIN
+   *    SS               --> SDSS
+   */
+  //#define USB_FLASH_DRIVE_SUPPORT
+  #if ENABLED(USB_FLASH_DRIVE_SUPPORT)
+    #define USB_CS_PIN         SDSS
+    #define USB_INTR_PIN       SD_DETECT_PIN
+  #endif
+
 #endif // SDSUPPORT
 
 /**
diff --git a/Marlin/src/config/examples/Creality/Ender-4/Configuration_adv.h b/Marlin/src/config/examples/Creality/Ender-4/Configuration_adv.h
index e8a0eea767..a118fe1f7c 100644
--- a/Marlin/src/config/examples/Creality/Ender-4/Configuration_adv.h
+++ b/Marlin/src/config/examples/Creality/Ender-4/Configuration_adv.h
@@ -683,6 +683,24 @@
    */
   //#define AUTO_REPORT_SD_STATUS
 
+  /**
+   * Support for USB thumb drives using an Arduino USB Host Shield or
+   * equivalent MAX3421E breakout board. The USB thumb drive will appear
+   * to Marlin as an SD card.
+   *
+   * The MAX3421E must be assigned the same pins as the SD card reader, with
+   * the following pin mapping:
+   *
+   *    SCLK, MOSI, MISO --> SCLK, MOSI, MISO
+   *    INT              --> SD_DETECT_PIN
+   *    SS               --> SDSS
+   */
+  //#define USB_FLASH_DRIVE_SUPPORT
+  #if ENABLED(USB_FLASH_DRIVE_SUPPORT)
+    #define USB_CS_PIN         SDSS
+    #define USB_INTR_PIN       SD_DETECT_PIN
+  #endif
+
 #endif // SDSUPPORT
 
 /**
diff --git a/Marlin/src/config/examples/Einstart-S/Configuration_adv.h b/Marlin/src/config/examples/Einstart-S/Configuration_adv.h
index 4b23e50ddb..1c074c9b72 100644
--- a/Marlin/src/config/examples/Einstart-S/Configuration_adv.h
+++ b/Marlin/src/config/examples/Einstart-S/Configuration_adv.h
@@ -683,6 +683,24 @@
    */
   //#define AUTO_REPORT_SD_STATUS
 
+  /**
+   * Support for USB thumb drives using an Arduino USB Host Shield or
+   * equivalent MAX3421E breakout board. The USB thumb drive will appear
+   * to Marlin as an SD card.
+   *
+   * The MAX3421E must be assigned the same pins as the SD card reader, with
+   * the following pin mapping:
+   *
+   *    SCLK, MOSI, MISO --> SCLK, MOSI, MISO
+   *    INT              --> SD_DETECT_PIN
+   *    SS               --> SDSS
+   */
+  //#define USB_FLASH_DRIVE_SUPPORT
+  #if ENABLED(USB_FLASH_DRIVE_SUPPORT)
+    #define USB_CS_PIN         SDSS
+    #define USB_INTR_PIN       SD_DETECT_PIN
+  #endif
+
 #endif // SDSUPPORT
 
 /**
diff --git a/Marlin/src/config/examples/Felix/Configuration_adv.h b/Marlin/src/config/examples/Felix/Configuration_adv.h
index b18fd17bee..f0eef0c551 100644
--- a/Marlin/src/config/examples/Felix/Configuration_adv.h
+++ b/Marlin/src/config/examples/Felix/Configuration_adv.h
@@ -683,6 +683,24 @@
    */
   //#define AUTO_REPORT_SD_STATUS
 
+  /**
+   * Support for USB thumb drives using an Arduino USB Host Shield or
+   * equivalent MAX3421E breakout board. The USB thumb drive will appear
+   * to Marlin as an SD card.
+   *
+   * The MAX3421E must be assigned the same pins as the SD card reader, with
+   * the following pin mapping:
+   *
+   *    SCLK, MOSI, MISO --> SCLK, MOSI, MISO
+   *    INT              --> SD_DETECT_PIN
+   *    SS               --> SDSS
+   */
+  //#define USB_FLASH_DRIVE_SUPPORT
+  #if ENABLED(USB_FLASH_DRIVE_SUPPORT)
+    #define USB_CS_PIN         SDSS
+    #define USB_INTR_PIN       SD_DETECT_PIN
+  #endif
+
 #endif // SDSUPPORT
 
 /**
diff --git a/Marlin/src/config/examples/FolgerTech/i3-2020/Configuration_adv.h b/Marlin/src/config/examples/FolgerTech/i3-2020/Configuration_adv.h
index f020b0b310..1504fdd11b 100644
--- a/Marlin/src/config/examples/FolgerTech/i3-2020/Configuration_adv.h
+++ b/Marlin/src/config/examples/FolgerTech/i3-2020/Configuration_adv.h
@@ -683,6 +683,24 @@
    */
   //#define AUTO_REPORT_SD_STATUS
 
+  /**
+   * Support for USB thumb drives using an Arduino USB Host Shield or
+   * equivalent MAX3421E breakout board. The USB thumb drive will appear
+   * to Marlin as an SD card.
+   *
+   * The MAX3421E must be assigned the same pins as the SD card reader, with
+   * the following pin mapping:
+   *
+   *    SCLK, MOSI, MISO --> SCLK, MOSI, MISO
+   *    INT              --> SD_DETECT_PIN
+   *    SS               --> SDSS
+   */
+  //#define USB_FLASH_DRIVE_SUPPORT
+  #if ENABLED(USB_FLASH_DRIVE_SUPPORT)
+    #define USB_CS_PIN         SDSS
+    #define USB_INTR_PIN       SD_DETECT_PIN
+  #endif
+
 #endif // SDSUPPORT
 
 /**
diff --git a/Marlin/src/config/examples/Formbot/Raptor/Configuration_adv.h b/Marlin/src/config/examples/Formbot/Raptor/Configuration_adv.h
index 571060647c..3bd5048b40 100644
--- a/Marlin/src/config/examples/Formbot/Raptor/Configuration_adv.h
+++ b/Marlin/src/config/examples/Formbot/Raptor/Configuration_adv.h
@@ -683,6 +683,24 @@
    */
   #define AUTO_REPORT_SD_STATUS
 
+  /**
+   * Support for USB thumb drives using an Arduino USB Host Shield or
+   * equivalent MAX3421E breakout board. The USB thumb drive will appear
+   * to Marlin as an SD card.
+   *
+   * The MAX3421E must be assigned the same pins as the SD card reader, with
+   * the following pin mapping:
+   *
+   *    SCLK, MOSI, MISO --> SCLK, MOSI, MISO
+   *    INT              --> SD_DETECT_PIN
+   *    SS               --> SDSS
+   */
+  //#define USB_FLASH_DRIVE_SUPPORT
+  #if ENABLED(USB_FLASH_DRIVE_SUPPORT)
+    #define USB_CS_PIN         SDSS
+    #define USB_INTR_PIN       SD_DETECT_PIN
+  #endif
+
 #endif // SDSUPPORT
 
 /**
diff --git a/Marlin/src/config/examples/Formbot/T_Rex_2+/Configuration_adv.h b/Marlin/src/config/examples/Formbot/T_Rex_2+/Configuration_adv.h
index d3d4196f47..97311df671 100644
--- a/Marlin/src/config/examples/Formbot/T_Rex_2+/Configuration_adv.h
+++ b/Marlin/src/config/examples/Formbot/T_Rex_2+/Configuration_adv.h
@@ -687,6 +687,24 @@
    */
   #define AUTO_REPORT_SD_STATUS
 
+  /**
+   * Support for USB thumb drives using an Arduino USB Host Shield or
+   * equivalent MAX3421E breakout board. The USB thumb drive will appear
+   * to Marlin as an SD card.
+   *
+   * The MAX3421E must be assigned the same pins as the SD card reader, with
+   * the following pin mapping:
+   *
+   *    SCLK, MOSI, MISO --> SCLK, MOSI, MISO
+   *    INT              --> SD_DETECT_PIN
+   *    SS               --> SDSS
+   */
+  //#define USB_FLASH_DRIVE_SUPPORT
+  #if ENABLED(USB_FLASH_DRIVE_SUPPORT)
+    #define USB_CS_PIN         SDSS
+    #define USB_INTR_PIN       SD_DETECT_PIN
+  #endif
+
 #endif // SDSUPPORT
 
 /**
diff --git a/Marlin/src/config/examples/Formbot/T_Rex_3/Configuration_adv.h b/Marlin/src/config/examples/Formbot/T_Rex_3/Configuration_adv.h
index b3f1191af8..ea9238b225 100644
--- a/Marlin/src/config/examples/Formbot/T_Rex_3/Configuration_adv.h
+++ b/Marlin/src/config/examples/Formbot/T_Rex_3/Configuration_adv.h
@@ -688,6 +688,24 @@
    */
   #define AUTO_REPORT_SD_STATUS
 
+  /**
+   * Support for USB thumb drives using an Arduino USB Host Shield or
+   * equivalent MAX3421E breakout board. The USB thumb drive will appear
+   * to Marlin as an SD card.
+   *
+   * The MAX3421E must be assigned the same pins as the SD card reader, with
+   * the following pin mapping:
+   *
+   *    SCLK, MOSI, MISO --> SCLK, MOSI, MISO
+   *    INT              --> SD_DETECT_PIN
+   *    SS               --> SDSS
+   */
+  //#define USB_FLASH_DRIVE_SUPPORT
+  #if ENABLED(USB_FLASH_DRIVE_SUPPORT)
+    #define USB_CS_PIN         SDSS
+    #define USB_INTR_PIN       SD_DETECT_PIN
+  #endif
+
 #endif // SDSUPPORT
 
 /**
diff --git a/Marlin/src/config/examples/Geeetech/Prusa i3 Pro C/Configuration_adv.h b/Marlin/src/config/examples/Geeetech/Prusa i3 Pro C/Configuration_adv.h
index 4903f68efc..0e95764817 100644
--- a/Marlin/src/config/examples/Geeetech/Prusa i3 Pro C/Configuration_adv.h	
+++ b/Marlin/src/config/examples/Geeetech/Prusa i3 Pro C/Configuration_adv.h	
@@ -683,6 +683,24 @@
    */
   //#define AUTO_REPORT_SD_STATUS
 
+  /**
+   * Support for USB thumb drives using an Arduino USB Host Shield or
+   * equivalent MAX3421E breakout board. The USB thumb drive will appear
+   * to Marlin as an SD card.
+   *
+   * The MAX3421E must be assigned the same pins as the SD card reader, with
+   * the following pin mapping:
+   *
+   *    SCLK, MOSI, MISO --> SCLK, MOSI, MISO
+   *    INT              --> SD_DETECT_PIN
+   *    SS               --> SDSS
+   */
+  //#define USB_FLASH_DRIVE_SUPPORT
+  #if ENABLED(USB_FLASH_DRIVE_SUPPORT)
+    #define USB_CS_PIN         SDSS
+    #define USB_INTR_PIN       SD_DETECT_PIN
+  #endif
+
 #endif // SDSUPPORT
 
 /**
diff --git a/Marlin/src/config/examples/Geeetech/Prusa i3 Pro W/Configuration_adv.h b/Marlin/src/config/examples/Geeetech/Prusa i3 Pro W/Configuration_adv.h
index 4903f68efc..0e95764817 100644
--- a/Marlin/src/config/examples/Geeetech/Prusa i3 Pro W/Configuration_adv.h	
+++ b/Marlin/src/config/examples/Geeetech/Prusa i3 Pro W/Configuration_adv.h	
@@ -683,6 +683,24 @@
    */
   //#define AUTO_REPORT_SD_STATUS
 
+  /**
+   * Support for USB thumb drives using an Arduino USB Host Shield or
+   * equivalent MAX3421E breakout board. The USB thumb drive will appear
+   * to Marlin as an SD card.
+   *
+   * The MAX3421E must be assigned the same pins as the SD card reader, with
+   * the following pin mapping:
+   *
+   *    SCLK, MOSI, MISO --> SCLK, MOSI, MISO
+   *    INT              --> SD_DETECT_PIN
+   *    SS               --> SDSS
+   */
+  //#define USB_FLASH_DRIVE_SUPPORT
+  #if ENABLED(USB_FLASH_DRIVE_SUPPORT)
+    #define USB_CS_PIN         SDSS
+    #define USB_INTR_PIN       SD_DETECT_PIN
+  #endif
+
 #endif // SDSUPPORT
 
 /**
diff --git a/Marlin/src/config/examples/Infitary/i3-M508/Configuration_adv.h b/Marlin/src/config/examples/Infitary/i3-M508/Configuration_adv.h
index a020e4c6d0..f715c61f01 100644
--- a/Marlin/src/config/examples/Infitary/i3-M508/Configuration_adv.h
+++ b/Marlin/src/config/examples/Infitary/i3-M508/Configuration_adv.h
@@ -683,6 +683,24 @@
    */
   //#define AUTO_REPORT_SD_STATUS
 
+  /**
+   * Support for USB thumb drives using an Arduino USB Host Shield or
+   * equivalent MAX3421E breakout board. The USB thumb drive will appear
+   * to Marlin as an SD card.
+   *
+   * The MAX3421E must be assigned the same pins as the SD card reader, with
+   * the following pin mapping:
+   *
+   *    SCLK, MOSI, MISO --> SCLK, MOSI, MISO
+   *    INT              --> SD_DETECT_PIN
+   *    SS               --> SDSS
+   */
+  //#define USB_FLASH_DRIVE_SUPPORT
+  #if ENABLED(USB_FLASH_DRIVE_SUPPORT)
+    #define USB_CS_PIN         SDSS
+    #define USB_INTR_PIN       SD_DETECT_PIN
+  #endif
+
 #endif // SDSUPPORT
 
 /**
diff --git a/Marlin/src/config/examples/JGAurora/A5/Configuration_adv.h b/Marlin/src/config/examples/JGAurora/A5/Configuration_adv.h
index 414ecab0b0..a2ec109356 100644
--- a/Marlin/src/config/examples/JGAurora/A5/Configuration_adv.h
+++ b/Marlin/src/config/examples/JGAurora/A5/Configuration_adv.h
@@ -683,6 +683,24 @@
    */
   //#define AUTO_REPORT_SD_STATUS
 
+  /**
+   * Support for USB thumb drives using an Arduino USB Host Shield or
+   * equivalent MAX3421E breakout board. The USB thumb drive will appear
+   * to Marlin as an SD card.
+   *
+   * The MAX3421E must be assigned the same pins as the SD card reader, with
+   * the following pin mapping:
+   *
+   *    SCLK, MOSI, MISO --> SCLK, MOSI, MISO
+   *    INT              --> SD_DETECT_PIN
+   *    SS               --> SDSS
+   */
+  //#define USB_FLASH_DRIVE_SUPPORT
+  #if ENABLED(USB_FLASH_DRIVE_SUPPORT)
+    #define USB_CS_PIN         SDSS
+    #define USB_INTR_PIN       SD_DETECT_PIN
+  #endif
+
 #endif // SDSUPPORT
 
 /**
diff --git a/Marlin/src/config/examples/MakerParts/Configuration_adv.h b/Marlin/src/config/examples/MakerParts/Configuration_adv.h
index c7dcd768ee..7a12be3f6d 100644
--- a/Marlin/src/config/examples/MakerParts/Configuration_adv.h
+++ b/Marlin/src/config/examples/MakerParts/Configuration_adv.h
@@ -683,6 +683,24 @@
    */
   //#define AUTO_REPORT_SD_STATUS
 
+  /**
+   * Support for USB thumb drives using an Arduino USB Host Shield or
+   * equivalent MAX3421E breakout board. The USB thumb drive will appear
+   * to Marlin as an SD card.
+   *
+   * The MAX3421E must be assigned the same pins as the SD card reader, with
+   * the following pin mapping:
+   *
+   *    SCLK, MOSI, MISO --> SCLK, MOSI, MISO
+   *    INT              --> SD_DETECT_PIN
+   *    SS               --> SDSS
+   */
+  //#define USB_FLASH_DRIVE_SUPPORT
+  #if ENABLED(USB_FLASH_DRIVE_SUPPORT)
+    #define USB_CS_PIN         SDSS
+    #define USB_INTR_PIN       SD_DETECT_PIN
+  #endif
+
 #endif // SDSUPPORT
 
 /**
diff --git a/Marlin/src/config/examples/Malyan/M150/Configuration_adv.h b/Marlin/src/config/examples/Malyan/M150/Configuration_adv.h
index c60f26f2c3..4e3a050dfe 100644
--- a/Marlin/src/config/examples/Malyan/M150/Configuration_adv.h
+++ b/Marlin/src/config/examples/Malyan/M150/Configuration_adv.h
@@ -683,6 +683,24 @@
    */
   //#define AUTO_REPORT_SD_STATUS
 
+  /**
+   * Support for USB thumb drives using an Arduino USB Host Shield or
+   * equivalent MAX3421E breakout board. The USB thumb drive will appear
+   * to Marlin as an SD card.
+   *
+   * The MAX3421E must be assigned the same pins as the SD card reader, with
+   * the following pin mapping:
+   *
+   *    SCLK, MOSI, MISO --> SCLK, MOSI, MISO
+   *    INT              --> SD_DETECT_PIN
+   *    SS               --> SDSS
+   */
+  //#define USB_FLASH_DRIVE_SUPPORT
+  #if ENABLED(USB_FLASH_DRIVE_SUPPORT)
+    #define USB_CS_PIN         SDSS
+    #define USB_INTR_PIN       SD_DETECT_PIN
+  #endif
+
 #endif // SDSUPPORT
 
 /**
diff --git a/Marlin/src/config/examples/Malyan/M200/Configuration_adv.h b/Marlin/src/config/examples/Malyan/M200/Configuration_adv.h
index 495c95691f..2094752ab2 100644
--- a/Marlin/src/config/examples/Malyan/M200/Configuration_adv.h
+++ b/Marlin/src/config/examples/Malyan/M200/Configuration_adv.h
@@ -683,6 +683,24 @@
    */
   //#define AUTO_REPORT_SD_STATUS
 
+  /**
+   * Support for USB thumb drives using an Arduino USB Host Shield or
+   * equivalent MAX3421E breakout board. The USB thumb drive will appear
+   * to Marlin as an SD card.
+   *
+   * The MAX3421E must be assigned the same pins as the SD card reader, with
+   * the following pin mapping:
+   *
+   *    SCLK, MOSI, MISO --> SCLK, MOSI, MISO
+   *    INT              --> SD_DETECT_PIN
+   *    SS               --> SDSS
+   */
+  //#define USB_FLASH_DRIVE_SUPPORT
+  #if ENABLED(USB_FLASH_DRIVE_SUPPORT)
+    #define USB_CS_PIN         SDSS
+    #define USB_INTR_PIN       SD_DETECT_PIN
+  #endif
+
 #endif // SDSUPPORT
 
 /**
diff --git a/Marlin/src/config/examples/Micromake/C1/enhanced/Configuration_adv.h b/Marlin/src/config/examples/Micromake/C1/enhanced/Configuration_adv.h
index f1e550ec2f..13f97550cf 100644
--- a/Marlin/src/config/examples/Micromake/C1/enhanced/Configuration_adv.h
+++ b/Marlin/src/config/examples/Micromake/C1/enhanced/Configuration_adv.h
@@ -683,6 +683,24 @@
    */
   //#define AUTO_REPORT_SD_STATUS
 
+  /**
+   * Support for USB thumb drives using an Arduino USB Host Shield or
+   * equivalent MAX3421E breakout board. The USB thumb drive will appear
+   * to Marlin as an SD card.
+   *
+   * The MAX3421E must be assigned the same pins as the SD card reader, with
+   * the following pin mapping:
+   *
+   *    SCLK, MOSI, MISO --> SCLK, MOSI, MISO
+   *    INT              --> SD_DETECT_PIN
+   *    SS               --> SDSS
+   */
+  //#define USB_FLASH_DRIVE_SUPPORT
+  #if ENABLED(USB_FLASH_DRIVE_SUPPORT)
+    #define USB_CS_PIN         SDSS
+    #define USB_INTR_PIN       SD_DETECT_PIN
+  #endif
+
 #endif // SDSUPPORT
 
 /**
diff --git a/Marlin/src/config/examples/Mks/Sbase/Configuration_adv.h b/Marlin/src/config/examples/Mks/Sbase/Configuration_adv.h
index 8c84c4460e..f146cdb80a 100644
--- a/Marlin/src/config/examples/Mks/Sbase/Configuration_adv.h
+++ b/Marlin/src/config/examples/Mks/Sbase/Configuration_adv.h
@@ -684,6 +684,24 @@
    */
   //#define AUTO_REPORT_SD_STATUS
 
+  /**
+   * Support for USB thumb drives using an Arduino USB Host Shield or
+   * equivalent MAX3421E breakout board. The USB thumb drive will appear
+   * to Marlin as an SD card.
+   *
+   * The MAX3421E must be assigned the same pins as the SD card reader, with
+   * the following pin mapping:
+   *
+   *    SCLK, MOSI, MISO --> SCLK, MOSI, MISO
+   *    INT              --> SD_DETECT_PIN
+   *    SS               --> SDSS
+   */
+  //#define USB_FLASH_DRIVE_SUPPORT
+  #if ENABLED(USB_FLASH_DRIVE_SUPPORT)
+    #define USB_CS_PIN         SDSS
+    #define USB_INTR_PIN       SD_DETECT_PIN
+  #endif
+
 #endif // SDSUPPORT
 
 /**
diff --git a/Marlin/src/config/examples/RigidBot/Configuration_adv.h b/Marlin/src/config/examples/RigidBot/Configuration_adv.h
index c7d8e68fbb..a71a9a81d0 100644
--- a/Marlin/src/config/examples/RigidBot/Configuration_adv.h
+++ b/Marlin/src/config/examples/RigidBot/Configuration_adv.h
@@ -683,6 +683,24 @@
    */
   //#define AUTO_REPORT_SD_STATUS
 
+  /**
+   * Support for USB thumb drives using an Arduino USB Host Shield or
+   * equivalent MAX3421E breakout board. The USB thumb drive will appear
+   * to Marlin as an SD card.
+   *
+   * The MAX3421E must be assigned the same pins as the SD card reader, with
+   * the following pin mapping:
+   *
+   *    SCLK, MOSI, MISO --> SCLK, MOSI, MISO
+   *    INT              --> SD_DETECT_PIN
+   *    SS               --> SDSS
+   */
+  //#define USB_FLASH_DRIVE_SUPPORT
+  #if ENABLED(USB_FLASH_DRIVE_SUPPORT)
+    #define USB_CS_PIN         SDSS
+    #define USB_INTR_PIN       SD_DETECT_PIN
+  #endif
+
 #endif // SDSUPPORT
 
 /**
diff --git a/Marlin/src/config/examples/SCARA/Configuration_adv.h b/Marlin/src/config/examples/SCARA/Configuration_adv.h
index e5b07803f5..dd667f0bb7 100644
--- a/Marlin/src/config/examples/SCARA/Configuration_adv.h
+++ b/Marlin/src/config/examples/SCARA/Configuration_adv.h
@@ -683,6 +683,24 @@
    */
   //#define AUTO_REPORT_SD_STATUS
 
+  /**
+   * Support for USB thumb drives using an Arduino USB Host Shield or
+   * equivalent MAX3421E breakout board. The USB thumb drive will appear
+   * to Marlin as an SD card.
+   *
+   * The MAX3421E must be assigned the same pins as the SD card reader, with
+   * the following pin mapping:
+   *
+   *    SCLK, MOSI, MISO --> SCLK, MOSI, MISO
+   *    INT              --> SD_DETECT_PIN
+   *    SS               --> SDSS
+   */
+  //#define USB_FLASH_DRIVE_SUPPORT
+  #if ENABLED(USB_FLASH_DRIVE_SUPPORT)
+    #define USB_CS_PIN         SDSS
+    #define USB_INTR_PIN       SD_DETECT_PIN
+  #endif
+
 #endif // SDSUPPORT
 
 /**
diff --git a/Marlin/src/config/examples/Sanguinololu/Configuration_adv.h b/Marlin/src/config/examples/Sanguinololu/Configuration_adv.h
index d53cedd425..41dd7218ac 100644
--- a/Marlin/src/config/examples/Sanguinololu/Configuration_adv.h
+++ b/Marlin/src/config/examples/Sanguinololu/Configuration_adv.h
@@ -683,6 +683,24 @@
    */
   //#define AUTO_REPORT_SD_STATUS
 
+  /**
+   * Support for USB thumb drives using an Arduino USB Host Shield or
+   * equivalent MAX3421E breakout board. The USB thumb drive will appear
+   * to Marlin as an SD card.
+   *
+   * The MAX3421E must be assigned the same pins as the SD card reader, with
+   * the following pin mapping:
+   *
+   *    SCLK, MOSI, MISO --> SCLK, MOSI, MISO
+   *    INT              --> SD_DETECT_PIN
+   *    SS               --> SDSS
+   */
+  //#define USB_FLASH_DRIVE_SUPPORT
+  #if ENABLED(USB_FLASH_DRIVE_SUPPORT)
+    #define USB_CS_PIN         SDSS
+    #define USB_INTR_PIN       SD_DETECT_PIN
+  #endif
+
 #endif // SDSUPPORT
 
 /**
diff --git a/Marlin/src/config/examples/TheBorg/Configuration_adv.h b/Marlin/src/config/examples/TheBorg/Configuration_adv.h
index fe6a2e45fb..8cd4081633 100644
--- a/Marlin/src/config/examples/TheBorg/Configuration_adv.h
+++ b/Marlin/src/config/examples/TheBorg/Configuration_adv.h
@@ -683,6 +683,24 @@
    */
   //#define AUTO_REPORT_SD_STATUS
 
+  /**
+   * Support for USB thumb drives using an Arduino USB Host Shield or
+   * equivalent MAX3421E breakout board. The USB thumb drive will appear
+   * to Marlin as an SD card.
+   *
+   * The MAX3421E must be assigned the same pins as the SD card reader, with
+   * the following pin mapping:
+   *
+   *    SCLK, MOSI, MISO --> SCLK, MOSI, MISO
+   *    INT              --> SD_DETECT_PIN
+   *    SS               --> SDSS
+   */
+  //#define USB_FLASH_DRIVE_SUPPORT
+  #if ENABLED(USB_FLASH_DRIVE_SUPPORT)
+    #define USB_CS_PIN         SDSS
+    #define USB_INTR_PIN       SD_DETECT_PIN
+  #endif
+
 #endif // SDSUPPORT
 
 /**
diff --git a/Marlin/src/config/examples/TinyBoy2/Configuration_adv.h b/Marlin/src/config/examples/TinyBoy2/Configuration_adv.h
index fba19e4494..947f057371 100644
--- a/Marlin/src/config/examples/TinyBoy2/Configuration_adv.h
+++ b/Marlin/src/config/examples/TinyBoy2/Configuration_adv.h
@@ -683,6 +683,24 @@
    */
   //#define AUTO_REPORT_SD_STATUS
 
+  /**
+   * Support for USB thumb drives using an Arduino USB Host Shield or
+   * equivalent MAX3421E breakout board. The USB thumb drive will appear
+   * to Marlin as an SD card.
+   *
+   * The MAX3421E must be assigned the same pins as the SD card reader, with
+   * the following pin mapping:
+   *
+   *    SCLK, MOSI, MISO --> SCLK, MOSI, MISO
+   *    INT              --> SD_DETECT_PIN
+   *    SS               --> SDSS
+   */
+  //#define USB_FLASH_DRIVE_SUPPORT
+  #if ENABLED(USB_FLASH_DRIVE_SUPPORT)
+    #define USB_CS_PIN         SDSS
+    #define USB_INTR_PIN       SD_DETECT_PIN
+  #endif
+
 #endif // SDSUPPORT
 
 /**
diff --git a/Marlin/src/config/examples/Tronxy/X3A/Configuration_adv.h b/Marlin/src/config/examples/Tronxy/X3A/Configuration_adv.h
index f8d87c8b19..a4eaea42f8 100644
--- a/Marlin/src/config/examples/Tronxy/X3A/Configuration_adv.h
+++ b/Marlin/src/config/examples/Tronxy/X3A/Configuration_adv.h
@@ -683,6 +683,24 @@
    */
   //#define AUTO_REPORT_SD_STATUS
 
+  /**
+   * Support for USB thumb drives using an Arduino USB Host Shield or
+   * equivalent MAX3421E breakout board. The USB thumb drive will appear
+   * to Marlin as an SD card.
+   *
+   * The MAX3421E must be assigned the same pins as the SD card reader, with
+   * the following pin mapping:
+   *
+   *    SCLK, MOSI, MISO --> SCLK, MOSI, MISO
+   *    INT              --> SD_DETECT_PIN
+   *    SS               --> SDSS
+   */
+  //#define USB_FLASH_DRIVE_SUPPORT
+  #if ENABLED(USB_FLASH_DRIVE_SUPPORT)
+    #define USB_CS_PIN         SDSS
+    #define USB_INTR_PIN       SD_DETECT_PIN
+  #endif
+
 #endif // SDSUPPORT
 
 /**
diff --git a/Marlin/src/config/examples/UltiMachine/Archim2/Configuration_adv.h b/Marlin/src/config/examples/UltiMachine/Archim2/Configuration_adv.h
index 95d78117ca..29bb95289e 100644
--- a/Marlin/src/config/examples/UltiMachine/Archim2/Configuration_adv.h
+++ b/Marlin/src/config/examples/UltiMachine/Archim2/Configuration_adv.h
@@ -683,6 +683,24 @@
    */
   //#define AUTO_REPORT_SD_STATUS
 
+  /**
+   * Support for USB thumb drives using an Arduino USB Host Shield or
+   * equivalent MAX3421E breakout board. The USB thumb drive will appear
+   * to Marlin as an SD card.
+   *
+   * The MAX3421E must be assigned the same pins as the SD card reader, with
+   * the following pin mapping:
+   *
+   *    SCLK, MOSI, MISO --> SCLK, MOSI, MISO
+   *    INT              --> SD_DETECT_PIN
+   *    SS               --> SDSS
+   */
+  //#define USB_FLASH_DRIVE_SUPPORT
+  #if ENABLED(USB_FLASH_DRIVE_SUPPORT)
+    #define USB_CS_PIN         SDSS
+    #define USB_INTR_PIN       SD_DETECT_PIN
+  #endif
+
 #endif // SDSUPPORT
 
 /**
diff --git a/Marlin/src/config/examples/Velleman/K8200/Configuration_adv.h b/Marlin/src/config/examples/Velleman/K8200/Configuration_adv.h
index c933d7c230..d1b20263a9 100644
--- a/Marlin/src/config/examples/Velleman/K8200/Configuration_adv.h
+++ b/Marlin/src/config/examples/Velleman/K8200/Configuration_adv.h
@@ -696,6 +696,24 @@
    */
   //#define AUTO_REPORT_SD_STATUS
 
+  /**
+   * Support for USB thumb drives using an Arduino USB Host Shield or
+   * equivalent MAX3421E breakout board. The USB thumb drive will appear
+   * to Marlin as an SD card.
+   *
+   * The MAX3421E must be assigned the same pins as the SD card reader, with
+   * the following pin mapping:
+   *
+   *    SCLK, MOSI, MISO --> SCLK, MOSI, MISO
+   *    INT              --> SD_DETECT_PIN
+   *    SS               --> SDSS
+   */
+  //#define USB_FLASH_DRIVE_SUPPORT
+  #if ENABLED(USB_FLASH_DRIVE_SUPPORT)
+    #define USB_CS_PIN         SDSS
+    #define USB_INTR_PIN       SD_DETECT_PIN
+  #endif
+
 #endif // SDSUPPORT
 
 /**
diff --git a/Marlin/src/config/examples/Velleman/K8400/Configuration_adv.h b/Marlin/src/config/examples/Velleman/K8400/Configuration_adv.h
index 5c0578c4fe..c479880d9e 100644
--- a/Marlin/src/config/examples/Velleman/K8400/Configuration_adv.h
+++ b/Marlin/src/config/examples/Velleman/K8400/Configuration_adv.h
@@ -683,6 +683,24 @@
    */
   //#define AUTO_REPORT_SD_STATUS
 
+  /**
+   * Support for USB thumb drives using an Arduino USB Host Shield or
+   * equivalent MAX3421E breakout board. The USB thumb drive will appear
+   * to Marlin as an SD card.
+   *
+   * The MAX3421E must be assigned the same pins as the SD card reader, with
+   * the following pin mapping:
+   *
+   *    SCLK, MOSI, MISO --> SCLK, MOSI, MISO
+   *    INT              --> SD_DETECT_PIN
+   *    SS               --> SDSS
+   */
+  //#define USB_FLASH_DRIVE_SUPPORT
+  #if ENABLED(USB_FLASH_DRIVE_SUPPORT)
+    #define USB_CS_PIN         SDSS
+    #define USB_INTR_PIN       SD_DETECT_PIN
+  #endif
+
 #endif // SDSUPPORT
 
 /**
diff --git a/Marlin/src/config/examples/Wanhao/Duplicator 6/Configuration_adv.h b/Marlin/src/config/examples/Wanhao/Duplicator 6/Configuration_adv.h
index a4541cc099..b97d0b43e7 100644
--- a/Marlin/src/config/examples/Wanhao/Duplicator 6/Configuration_adv.h	
+++ b/Marlin/src/config/examples/Wanhao/Duplicator 6/Configuration_adv.h	
@@ -685,6 +685,24 @@
    */
   //#define AUTO_REPORT_SD_STATUS
 
+  /**
+   * Support for USB thumb drives using an Arduino USB Host Shield or
+   * equivalent MAX3421E breakout board. The USB thumb drive will appear
+   * to Marlin as an SD card.
+   *
+   * The MAX3421E must be assigned the same pins as the SD card reader, with
+   * the following pin mapping:
+   *
+   *    SCLK, MOSI, MISO --> SCLK, MOSI, MISO
+   *    INT              --> SD_DETECT_PIN
+   *    SS               --> SDSS
+   */
+  //#define USB_FLASH_DRIVE_SUPPORT
+  #if ENABLED(USB_FLASH_DRIVE_SUPPORT)
+    #define USB_CS_PIN         SDSS
+    #define USB_INTR_PIN       SD_DETECT_PIN
+  #endif
+
 #endif // SDSUPPORT
 
 /**
diff --git a/Marlin/src/config/examples/delta/Anycubic/Kossel/Configuration_adv.h b/Marlin/src/config/examples/delta/Anycubic/Kossel/Configuration_adv.h
index 1f31b411ab..f6160fed92 100644
--- a/Marlin/src/config/examples/delta/Anycubic/Kossel/Configuration_adv.h
+++ b/Marlin/src/config/examples/delta/Anycubic/Kossel/Configuration_adv.h
@@ -685,6 +685,24 @@
    */
   //#define AUTO_REPORT_SD_STATUS
 
+  /**
+   * Support for USB thumb drives using an Arduino USB Host Shield or
+   * equivalent MAX3421E breakout board. The USB thumb drive will appear
+   * to Marlin as an SD card.
+   *
+   * The MAX3421E must be assigned the same pins as the SD card reader, with
+   * the following pin mapping:
+   *
+   *    SCLK, MOSI, MISO --> SCLK, MOSI, MISO
+   *    INT              --> SD_DETECT_PIN
+   *    SS               --> SDSS
+   */
+  //#define USB_FLASH_DRIVE_SUPPORT
+  #if ENABLED(USB_FLASH_DRIVE_SUPPORT)
+    #define USB_CS_PIN         SDSS
+    #define USB_INTR_PIN       SD_DETECT_PIN
+  #endif
+
 #endif // SDSUPPORT
 
 /**
diff --git a/Marlin/src/config/examples/delta/FLSUN/auto_calibrate/Configuration_adv.h b/Marlin/src/config/examples/delta/FLSUN/auto_calibrate/Configuration_adv.h
index 4a0348aa5a..57af4af00a 100644
--- a/Marlin/src/config/examples/delta/FLSUN/auto_calibrate/Configuration_adv.h
+++ b/Marlin/src/config/examples/delta/FLSUN/auto_calibrate/Configuration_adv.h
@@ -685,6 +685,24 @@
    */
   //#define AUTO_REPORT_SD_STATUS
 
+  /**
+   * Support for USB thumb drives using an Arduino USB Host Shield or
+   * equivalent MAX3421E breakout board. The USB thumb drive will appear
+   * to Marlin as an SD card.
+   *
+   * The MAX3421E must be assigned the same pins as the SD card reader, with
+   * the following pin mapping:
+   *
+   *    SCLK, MOSI, MISO --> SCLK, MOSI, MISO
+   *    INT              --> SD_DETECT_PIN
+   *    SS               --> SDSS
+   */
+  //#define USB_FLASH_DRIVE_SUPPORT
+  #if ENABLED(USB_FLASH_DRIVE_SUPPORT)
+    #define USB_CS_PIN         SDSS
+    #define USB_INTR_PIN       SD_DETECT_PIN
+  #endif
+
 #endif // SDSUPPORT
 
 /**
diff --git a/Marlin/src/config/examples/delta/FLSUN/kossel/Configuration_adv.h b/Marlin/src/config/examples/delta/FLSUN/kossel/Configuration_adv.h
index 4a0348aa5a..57af4af00a 100644
--- a/Marlin/src/config/examples/delta/FLSUN/kossel/Configuration_adv.h
+++ b/Marlin/src/config/examples/delta/FLSUN/kossel/Configuration_adv.h
@@ -685,6 +685,24 @@
    */
   //#define AUTO_REPORT_SD_STATUS
 
+  /**
+   * Support for USB thumb drives using an Arduino USB Host Shield or
+   * equivalent MAX3421E breakout board. The USB thumb drive will appear
+   * to Marlin as an SD card.
+   *
+   * The MAX3421E must be assigned the same pins as the SD card reader, with
+   * the following pin mapping:
+   *
+   *    SCLK, MOSI, MISO --> SCLK, MOSI, MISO
+   *    INT              --> SD_DETECT_PIN
+   *    SS               --> SDSS
+   */
+  //#define USB_FLASH_DRIVE_SUPPORT
+  #if ENABLED(USB_FLASH_DRIVE_SUPPORT)
+    #define USB_CS_PIN         SDSS
+    #define USB_INTR_PIN       SD_DETECT_PIN
+  #endif
+
 #endif // SDSUPPORT
 
 /**
diff --git a/Marlin/src/config/examples/delta/FLSUN/kossel_mini/Configuration_adv.h b/Marlin/src/config/examples/delta/FLSUN/kossel_mini/Configuration_adv.h
index c34501f54f..eaa28eb8a3 100644
--- a/Marlin/src/config/examples/delta/FLSUN/kossel_mini/Configuration_adv.h
+++ b/Marlin/src/config/examples/delta/FLSUN/kossel_mini/Configuration_adv.h
@@ -685,6 +685,24 @@
    */
   //#define AUTO_REPORT_SD_STATUS
 
+  /**
+   * Support for USB thumb drives using an Arduino USB Host Shield or
+   * equivalent MAX3421E breakout board. The USB thumb drive will appear
+   * to Marlin as an SD card.
+   *
+   * The MAX3421E must be assigned the same pins as the SD card reader, with
+   * the following pin mapping:
+   *
+   *    SCLK, MOSI, MISO --> SCLK, MOSI, MISO
+   *    INT              --> SD_DETECT_PIN
+   *    SS               --> SDSS
+   */
+  //#define USB_FLASH_DRIVE_SUPPORT
+  #if ENABLED(USB_FLASH_DRIVE_SUPPORT)
+    #define USB_CS_PIN         SDSS
+    #define USB_INTR_PIN       SD_DETECT_PIN
+  #endif
+
 #endif // SDSUPPORT
 
 /**
diff --git a/Marlin/src/config/examples/delta/generic/Configuration_adv.h b/Marlin/src/config/examples/delta/generic/Configuration_adv.h
index c34501f54f..eaa28eb8a3 100644
--- a/Marlin/src/config/examples/delta/generic/Configuration_adv.h
+++ b/Marlin/src/config/examples/delta/generic/Configuration_adv.h
@@ -685,6 +685,24 @@
    */
   //#define AUTO_REPORT_SD_STATUS
 
+  /**
+   * Support for USB thumb drives using an Arduino USB Host Shield or
+   * equivalent MAX3421E breakout board. The USB thumb drive will appear
+   * to Marlin as an SD card.
+   *
+   * The MAX3421E must be assigned the same pins as the SD card reader, with
+   * the following pin mapping:
+   *
+   *    SCLK, MOSI, MISO --> SCLK, MOSI, MISO
+   *    INT              --> SD_DETECT_PIN
+   *    SS               --> SDSS
+   */
+  //#define USB_FLASH_DRIVE_SUPPORT
+  #if ENABLED(USB_FLASH_DRIVE_SUPPORT)
+    #define USB_CS_PIN         SDSS
+    #define USB_INTR_PIN       SD_DETECT_PIN
+  #endif
+
 #endif // SDSUPPORT
 
 /**
diff --git a/Marlin/src/config/examples/delta/kossel_mini/Configuration_adv.h b/Marlin/src/config/examples/delta/kossel_mini/Configuration_adv.h
index c34501f54f..eaa28eb8a3 100644
--- a/Marlin/src/config/examples/delta/kossel_mini/Configuration_adv.h
+++ b/Marlin/src/config/examples/delta/kossel_mini/Configuration_adv.h
@@ -685,6 +685,24 @@
    */
   //#define AUTO_REPORT_SD_STATUS
 
+  /**
+   * Support for USB thumb drives using an Arduino USB Host Shield or
+   * equivalent MAX3421E breakout board. The USB thumb drive will appear
+   * to Marlin as an SD card.
+   *
+   * The MAX3421E must be assigned the same pins as the SD card reader, with
+   * the following pin mapping:
+   *
+   *    SCLK, MOSI, MISO --> SCLK, MOSI, MISO
+   *    INT              --> SD_DETECT_PIN
+   *    SS               --> SDSS
+   */
+  //#define USB_FLASH_DRIVE_SUPPORT
+  #if ENABLED(USB_FLASH_DRIVE_SUPPORT)
+    #define USB_CS_PIN         SDSS
+    #define USB_INTR_PIN       SD_DETECT_PIN
+  #endif
+
 #endif // SDSUPPORT
 
 /**
diff --git a/Marlin/src/config/examples/delta/kossel_xl/Configuration_adv.h b/Marlin/src/config/examples/delta/kossel_xl/Configuration_adv.h
index 297b4f7286..d5c7df792f 100644
--- a/Marlin/src/config/examples/delta/kossel_xl/Configuration_adv.h
+++ b/Marlin/src/config/examples/delta/kossel_xl/Configuration_adv.h
@@ -685,6 +685,24 @@
    */
   //#define AUTO_REPORT_SD_STATUS
 
+  /**
+   * Support for USB thumb drives using an Arduino USB Host Shield or
+   * equivalent MAX3421E breakout board. The USB thumb drive will appear
+   * to Marlin as an SD card.
+   *
+   * The MAX3421E must be assigned the same pins as the SD card reader, with
+   * the following pin mapping:
+   *
+   *    SCLK, MOSI, MISO --> SCLK, MOSI, MISO
+   *    INT              --> SD_DETECT_PIN
+   *    SS               --> SDSS
+   */
+  //#define USB_FLASH_DRIVE_SUPPORT
+  #if ENABLED(USB_FLASH_DRIVE_SUPPORT)
+    #define USB_CS_PIN         SDSS
+    #define USB_INTR_PIN       SD_DETECT_PIN
+  #endif
+
 #endif // SDSUPPORT
 
 /**
diff --git a/Marlin/src/config/examples/gCreate/gMax1.5+/Configuration_adv.h b/Marlin/src/config/examples/gCreate/gMax1.5+/Configuration_adv.h
index b6b3983648..365ae3792e 100644
--- a/Marlin/src/config/examples/gCreate/gMax1.5+/Configuration_adv.h
+++ b/Marlin/src/config/examples/gCreate/gMax1.5+/Configuration_adv.h
@@ -683,6 +683,24 @@
    */
   //#define AUTO_REPORT_SD_STATUS
 
+  /**
+   * Support for USB thumb drives using an Arduino USB Host Shield or
+   * equivalent MAX3421E breakout board. The USB thumb drive will appear
+   * to Marlin as an SD card.
+   *
+   * The MAX3421E must be assigned the same pins as the SD card reader, with
+   * the following pin mapping:
+   *
+   *    SCLK, MOSI, MISO --> SCLK, MOSI, MISO
+   *    INT              --> SD_DETECT_PIN
+   *    SS               --> SDSS
+   */
+  //#define USB_FLASH_DRIVE_SUPPORT
+  #if ENABLED(USB_FLASH_DRIVE_SUPPORT)
+    #define USB_CS_PIN         SDSS
+    #define USB_INTR_PIN       SD_DETECT_PIN
+  #endif
+
 #endif // SDSUPPORT
 
 /**
diff --git a/Marlin/src/config/examples/makibox/Configuration_adv.h b/Marlin/src/config/examples/makibox/Configuration_adv.h
index d6ceb34a44..8af856f1e3 100644
--- a/Marlin/src/config/examples/makibox/Configuration_adv.h
+++ b/Marlin/src/config/examples/makibox/Configuration_adv.h
@@ -683,6 +683,24 @@
    */
   //#define AUTO_REPORT_SD_STATUS
 
+  /**
+   * Support for USB thumb drives using an Arduino USB Host Shield or
+   * equivalent MAX3421E breakout board. The USB thumb drive will appear
+   * to Marlin as an SD card.
+   *
+   * The MAX3421E must be assigned the same pins as the SD card reader, with
+   * the following pin mapping:
+   *
+   *    SCLK, MOSI, MISO --> SCLK, MOSI, MISO
+   *    INT              --> SD_DETECT_PIN
+   *    SS               --> SDSS
+   */
+  //#define USB_FLASH_DRIVE_SUPPORT
+  #if ENABLED(USB_FLASH_DRIVE_SUPPORT)
+    #define USB_CS_PIN         SDSS
+    #define USB_INTR_PIN       SD_DETECT_PIN
+  #endif
+
 #endif // SDSUPPORT
 
 /**
diff --git a/Marlin/src/config/examples/tvrrug/Round2/Configuration_adv.h b/Marlin/src/config/examples/tvrrug/Round2/Configuration_adv.h
index 1dba1721cd..fa3b4be542 100644
--- a/Marlin/src/config/examples/tvrrug/Round2/Configuration_adv.h
+++ b/Marlin/src/config/examples/tvrrug/Round2/Configuration_adv.h
@@ -683,6 +683,24 @@
    */
   //#define AUTO_REPORT_SD_STATUS
 
+  /**
+   * Support for USB thumb drives using an Arduino USB Host Shield or
+   * equivalent MAX3421E breakout board. The USB thumb drive will appear
+   * to Marlin as an SD card.
+   *
+   * The MAX3421E must be assigned the same pins as the SD card reader, with
+   * the following pin mapping:
+   *
+   *    SCLK, MOSI, MISO --> SCLK, MOSI, MISO
+   *    INT              --> SD_DETECT_PIN
+   *    SS               --> SDSS
+   */
+  //#define USB_FLASH_DRIVE_SUPPORT
+  #if ENABLED(USB_FLASH_DRIVE_SUPPORT)
+    #define USB_CS_PIN         SDSS
+    #define USB_INTR_PIN       SD_DETECT_PIN
+  #endif
+
 #endif // SDSUPPORT
 
 /**
diff --git a/Marlin/src/config/examples/wt150/Configuration_adv.h b/Marlin/src/config/examples/wt150/Configuration_adv.h
index 0bb6b75b67..184ca8cfa2 100644
--- a/Marlin/src/config/examples/wt150/Configuration_adv.h
+++ b/Marlin/src/config/examples/wt150/Configuration_adv.h
@@ -684,6 +684,24 @@
    */
   //#define AUTO_REPORT_SD_STATUS
 
+  /**
+   * Support for USB thumb drives using an Arduino USB Host Shield or
+   * equivalent MAX3421E breakout board. The USB thumb drive will appear
+   * to Marlin as an SD card.
+   *
+   * The MAX3421E must be assigned the same pins as the SD card reader, with
+   * the following pin mapping:
+   *
+   *    SCLK, MOSI, MISO --> SCLK, MOSI, MISO
+   *    INT              --> SD_DETECT_PIN
+   *    SS               --> SDSS
+   */
+  //#define USB_FLASH_DRIVE_SUPPORT
+  #if ENABLED(USB_FLASH_DRIVE_SUPPORT)
+    #define USB_CS_PIN         SDSS
+    #define USB_INTR_PIN       SD_DETECT_PIN
+  #endif
+
 #endif // SDSUPPORT
 
 /**