aboutsummaryrefslogtreecommitdiff
path: root/Marlin/src/sd
diff options
context:
space:
mode:
Diffstat (limited to 'Marlin/src/sd')
-rw-r--r--Marlin/src/sd/Sd2Card.cpp669
-rw-r--r--Marlin/src/sd/Sd2Card.h186
-rw-r--r--Marlin/src/sd/Sd2Card_sdio.h39
-rw-r--r--Marlin/src/sd/SdBaseFile.cpp1813
-rw-r--r--Marlin/src/sd/SdBaseFile.h384
-rw-r--r--Marlin/src/sd/SdFatConfig.h112
-rw-r--r--Marlin/src/sd/SdFatStructs.h609
-rw-r--r--Marlin/src/sd/SdFatUtil.cpp62
-rw-r--r--Marlin/src/sd/SdFatUtil.h42
-rw-r--r--Marlin/src/sd/SdFile.cpp102
-rw-r--r--Marlin/src/sd/SdFile.h56
-rw-r--r--Marlin/src/sd/SdInfo.h265
-rw-r--r--Marlin/src/sd/SdVolume.cpp405
-rw-r--r--Marlin/src/sd/SdVolume.h198
-rw-r--r--Marlin/src/sd/cardreader.cpp1265
-rw-r--r--Marlin/src/sd/cardreader.h302
-rw-r--r--Marlin/src/sd/usb_flashdrive/Sd2Card_FlashDrive.cpp326
-rw-r--r--Marlin/src/sd/usb_flashdrive/Sd2Card_FlashDrive.h78
-rw-r--r--Marlin/src/sd/usb_flashdrive/lib-uhs2/Usb.cpp795
-rw-r--r--Marlin/src/sd/usb_flashdrive/lib-uhs2/Usb.h53
-rw-r--r--Marlin/src/sd/usb_flashdrive/lib-uhs2/UsbCore.h312
-rw-r--r--Marlin/src/sd/usb_flashdrive/lib-uhs2/address.h271
-rw-r--r--Marlin/src/sd/usb_flashdrive/lib-uhs2/confdescparser.h201
-rw-r--r--Marlin/src/sd/usb_flashdrive/lib-uhs2/hexdump.h68
-rw-r--r--Marlin/src/sd/usb_flashdrive/lib-uhs2/macros.h86
-rw-r--r--Marlin/src/sd/usb_flashdrive/lib-uhs2/masstorage.cpp1217
-rw-r--r--Marlin/src/sd/usb_flashdrive/lib-uhs2/masstorage.h562
-rw-r--r--Marlin/src/sd/usb_flashdrive/lib-uhs2/max3421e.h242
-rw-r--r--Marlin/src/sd/usb_flashdrive/lib-uhs2/message.cpp128
-rw-r--r--Marlin/src/sd/usb_flashdrive/lib-uhs2/message.h85
-rw-r--r--Marlin/src/sd/usb_flashdrive/lib-uhs2/parsetools.cpp77
-rw-r--r--Marlin/src/sd/usb_flashdrive/lib-uhs2/parsetools.h145
-rw-r--r--Marlin/src/sd/usb_flashdrive/lib-uhs2/printhex.h80
-rw-r--r--Marlin/src/sd/usb_flashdrive/lib-uhs2/settings.h236
-rw-r--r--Marlin/src/sd/usb_flashdrive/lib-uhs2/usb_ch9.h170
-rw-r--r--Marlin/src/sd/usb_flashdrive/lib-uhs2/usbhost.cpp207
-rw-r--r--Marlin/src/sd/usb_flashdrive/lib-uhs2/usbhost.h58
-rw-r--r--Marlin/src/sd/usb_flashdrive/lib-uhs3/UHS_host/UHS_BULK_STORAGE/UHS_BULK_STORAGE.h249
-rw-r--r--Marlin/src/sd/usb_flashdrive/lib-uhs3/UHS_host/UHS_BULK_STORAGE/UHS_BULK_STORAGE_INLINE.h1205
-rw-r--r--Marlin/src/sd/usb_flashdrive/lib-uhs3/UHS_host/UHS_BULK_STORAGE/UHS_SCSI.h327
-rw-r--r--Marlin/src/sd/usb_flashdrive/lib-uhs3/UHS_host/UHS_UNOFFICIAL_IDs.h33
-rw-r--r--Marlin/src/sd/usb_flashdrive/lib-uhs3/UHS_host/UHS_USB_IDs.h2993
-rw-r--r--Marlin/src/sd/usb_flashdrive/lib-uhs3/UHS_host/UHS_UsbCore.h336
-rw-r--r--Marlin/src/sd/usb_flashdrive/lib-uhs3/UHS_host/UHS_address.h248
-rw-r--r--Marlin/src/sd/usb_flashdrive/lib-uhs3/UHS_host/UHS_hexdump.h70
-rw-r--r--Marlin/src/sd/usb_flashdrive/lib-uhs3/UHS_host/UHS_host.h111
-rw-r--r--Marlin/src/sd/usb_flashdrive/lib-uhs3/UHS_host/UHS_host_INLINE.h1222
-rw-r--r--Marlin/src/sd/usb_flashdrive/lib-uhs3/UHS_host/UHS_macros.h230
-rw-r--r--Marlin/src/sd/usb_flashdrive/lib-uhs3/UHS_host/UHS_message.h91
-rw-r--r--Marlin/src/sd/usb_flashdrive/lib-uhs3/UHS_host/UHS_printf_HELPER.h200
-rw-r--r--Marlin/src/sd/usb_flashdrive/lib-uhs3/UHS_host/UHS_printhex.h96
-rw-r--r--Marlin/src/sd/usb_flashdrive/lib-uhs3/UHS_host/UHS_settings.h141
-rw-r--r--Marlin/src/sd/usb_flashdrive/lib-uhs3/UHS_host/UHS_usb_ch9.h222
-rw-r--r--Marlin/src/sd/usb_flashdrive/lib-uhs3/UHS_host/UHS_usbhost.h449
-rw-r--r--Marlin/src/sd/usb_flashdrive/lib-uhs3/UHS_host/UHS_util_INLINE.h129
-rw-r--r--Marlin/src/sd/usb_flashdrive/lib-uhs3/UHS_host/USB_HOST_SHIELD/UHS_max3421e.h226
-rw-r--r--Marlin/src/sd/usb_flashdrive/lib-uhs3/UHS_host/USB_HOST_SHIELD/USB_HOST_SHIELD.h519
-rw-r--r--Marlin/src/sd/usb_flashdrive/lib-uhs3/UHS_host/USB_HOST_SHIELD/USB_HOST_SHIELD_INLINE.h1003
-rw-r--r--Marlin/src/sd/usb_flashdrive/lib-uhs3/UHS_host/macro_logic.h152
-rw-r--r--Marlin/src/sd/usb_flashdrive/lib-uhs3/dyn_SWI/SWI_INLINE.h244
-rw-r--r--Marlin/src/sd/usb_flashdrive/lib-uhs3/dyn_SWI/dyn_SWI.h172
61 files changed, 22574 insertions, 0 deletions
diff --git a/Marlin/src/sd/Sd2Card.cpp b/Marlin/src/sd/Sd2Card.cpp
new file mode 100644
index 0000000..491c069
--- /dev/null
+++ b/Marlin/src/sd/Sd2Card.cpp
@@ -0,0 +1,669 @@
+/**
+ * Marlin 3D Printer Firmware
+ * Copyright (c) 2020 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 <https://www.gnu.org/licenses/>.
+ *
+ */
+
+/**
+ * Arduino Sd2Card Library
+ * Copyright (c) 2009 by William Greiman
+ * Updated with backports of the latest SdFat library from the same author
+ *
+ * This file is part of the Arduino Sd2Card Library
+ */
+
+#include "../inc/MarlinConfig.h"
+
+#if ENABLED(SDSUPPORT) && NONE(USB_FLASH_DRIVE_SUPPORT, SDIO_SUPPORT)
+
+/* Enable FAST CRC computations - You can trade speed for FLASH space if
+ * needed by disabling the following define */
+#define FAST_CRC 1
+
+#include "Sd2Card.h"
+
+#include "../MarlinCore.h"
+
+#if ENABLED(SD_CHECK_AND_RETRY)
+ static bool crcSupported = true;
+
+ #ifdef FAST_CRC
+ static const uint8_t crctab7[] PROGMEM = {
+ 0x00,0x09,0x12,0x1B,0x24,0x2D,0x36,0x3F,0x48,0x41,0x5A,0x53,0x6C,0x65,0x7E,0x77,
+ 0x19,0x10,0x0B,0x02,0x3D,0x34,0x2F,0x26,0x51,0x58,0x43,0x4A,0x75,0x7C,0x67,0x6E,
+ 0x32,0x3B,0x20,0x29,0x16,0x1F,0x04,0x0D,0x7A,0x73,0x68,0x61,0x5E,0x57,0x4C,0x45,
+ 0x2B,0x22,0x39,0x30,0x0F,0x06,0x1D,0x14,0x63,0x6A,0x71,0x78,0x47,0x4E,0x55,0x5C,
+ 0x64,0x6D,0x76,0x7F,0x40,0x49,0x52,0x5B,0x2C,0x25,0x3E,0x37,0x08,0x01,0x1A,0x13,
+ 0x7D,0x74,0x6F,0x66,0x59,0x50,0x4B,0x42,0x35,0x3C,0x27,0x2E,0x11,0x18,0x03,0x0A,
+ 0x56,0x5F,0x44,0x4D,0x72,0x7B,0x60,0x69,0x1E,0x17,0x0C,0x05,0x3A,0x33,0x28,0x21,
+ 0x4F,0x46,0x5D,0x54,0x6B,0x62,0x79,0x70,0x07,0x0E,0x15,0x1C,0x23,0x2A,0x31,0x38,
+ 0x41,0x48,0x53,0x5A,0x65,0x6C,0x77,0x7E,0x09,0x00,0x1B,0x12,0x2D,0x24,0x3F,0x36,
+ 0x58,0x51,0x4A,0x43,0x7C,0x75,0x6E,0x67,0x10,0x19,0x02,0x0B,0x34,0x3D,0x26,0x2F,
+ 0x73,0x7A,0x61,0x68,0x57,0x5E,0x45,0x4C,0x3B,0x32,0x29,0x20,0x1F,0x16,0x0D,0x04,
+ 0x6A,0x63,0x78,0x71,0x4E,0x47,0x5C,0x55,0x22,0x2B,0x30,0x39,0x06,0x0F,0x14,0x1D,
+ 0x25,0x2C,0x37,0x3E,0x01,0x08,0x13,0x1A,0x6D,0x64,0x7F,0x76,0x49,0x40,0x5B,0x52,
+ 0x3C,0x35,0x2E,0x27,0x18,0x11,0x0A,0x03,0x74,0x7D,0x66,0x6F,0x50,0x59,0x42,0x4B,
+ 0x17,0x1E,0x05,0x0C,0x33,0x3A,0x21,0x28,0x5F,0x56,0x4D,0x44,0x7B,0x72,0x69,0x60,
+ 0x0E,0x07,0x1C,0x15,0x2A,0x23,0x38,0x31,0x46,0x4F,0x54,0x5D,0x62,0x6B,0x70,0x79
+ };
+
+ static uint8_t CRC7(const uint8_t* data, uint8_t n) {
+ uint8_t crc = 0;
+ while (n > 0) {
+ crc = pgm_read_byte(&crctab7[ (crc << 1) ^ *data++ ]);
+ n--;
+ }
+ return (crc << 1) | 1;
+ }
+ #else
+ static uint8_t CRC7(const uint8_t* data, uint8_t n) {
+ uint8_t crc = 0;
+ LOOP_L_N(i, n) {
+ uint8_t d = data[i];
+ d ^= crc << 1;
+ if (d & 0x80) d ^= 9;
+ crc = d ^ (crc & 0x78) ^ (crc << 4) ^ ((crc >> 3) & 15);
+ crc &= 0x7F;
+ }
+ crc = (crc << 1) ^ (crc << 4) ^ (crc & 0x70) ^ ((crc >> 3) & 0x0F);
+ return crc | 1;
+ }
+ #endif
+#endif
+
+// Send command and return error code. Return zero for OK
+uint8_t Sd2Card::cardCommand(const uint8_t cmd, const uint32_t arg) {
+ // Select card
+ chipSelect();
+
+ // Wait up to 300 ms if busy
+ waitNotBusy(SD_WRITE_TIMEOUT);
+
+ uint8_t *pa = (uint8_t *)(&arg);
+
+ #if ENABLED(SD_CHECK_AND_RETRY)
+
+ // Form message
+ uint8_t d[6] = {(uint8_t) (cmd | 0x40), pa[3], pa[2], pa[1], pa[0] };
+
+ // Add crc
+ d[5] = CRC7(d, 5);
+
+ // Send message
+ LOOP_L_N(k, 6) spiSend(d[k]);
+
+ #else
+ // Send command
+ spiSend(cmd | 0x40);
+
+ // Send argument
+ for (int8_t i = 3; i >= 0; i--) spiSend(pa[i]);
+
+ // Send CRC - correct for CMD0 with arg zero or CMD8 with arg 0X1AA
+ spiSend(cmd == CMD0 ? 0X95 : 0X87);
+ #endif
+
+ // Skip stuff byte for stop read
+ if (cmd == CMD12) spiRec();
+
+ // Wait for response
+ for (uint8_t i = 0; ((status_ = spiRec()) & 0x80) && i != 0xFF; i++) { /* Intentionally left empty */ }
+ return status_;
+}
+
+/**
+ * Determine the size of an SD flash memory card.
+ *
+ * \return The number of 512 byte data blocks in the card
+ * or zero if an error occurs.
+ */
+uint32_t Sd2Card::cardSize() {
+ csd_t csd;
+ if (!readCSD(&csd)) return 0;
+ if (csd.v1.csd_ver == 0) {
+ uint8_t read_bl_len = csd.v1.read_bl_len;
+ uint16_t c_size = (csd.v1.c_size_high << 10)
+ | (csd.v1.c_size_mid << 2) | csd.v1.c_size_low;
+ uint8_t c_size_mult = (csd.v1.c_size_mult_high << 1)
+ | csd.v1.c_size_mult_low;
+ return (uint32_t)(c_size + 1) << (c_size_mult + read_bl_len - 7);
+ }
+ else if (csd.v2.csd_ver == 1) {
+ uint32_t c_size = ((uint32_t)csd.v2.c_size_high << 16)
+ | (csd.v2.c_size_mid << 8) | csd.v2.c_size_low;
+ return (c_size + 1) << 10;
+ }
+ else {
+ error(SD_CARD_ERROR_BAD_CSD);
+ return 0;
+ }
+}
+
+void Sd2Card::chipDeselect() {
+ extDigitalWrite(chipSelectPin_, HIGH);
+ spiSend(0xFF); // Ensure MISO goes high impedance
+}
+
+void Sd2Card::chipSelect() {
+ spiInit(spiRate_);
+ extDigitalWrite(chipSelectPin_, LOW);
+}
+
+/**
+ * Erase a range of blocks.
+ *
+ * \param[in] firstBlock The address of the first block in the range.
+ * \param[in] lastBlock The address of the last block in the range.
+ *
+ * \note This function requests the SD card to do a flash erase for a
+ * range of blocks. The data on the card after an erase operation is
+ * either 0 or 1, depends on the card vendor. The card must support
+ * single block erase.
+ *
+ * \return true for success, false for failure.
+ */
+bool Sd2Card::erase(uint32_t firstBlock, uint32_t lastBlock) {
+ if (ENABLED(SDCARD_READONLY)) return false;
+
+ csd_t csd;
+ if (!readCSD(&csd)) goto FAIL;
+
+ // check for single block erase
+ if (!csd.v1.erase_blk_en) {
+ // erase size mask
+ uint8_t m = (csd.v1.sector_size_high << 1) | csd.v1.sector_size_low;
+ if ((firstBlock & m) != 0 || ((lastBlock + 1) & m) != 0) {
+ // error card can't erase specified area
+ error(SD_CARD_ERROR_ERASE_SINGLE_BLOCK);
+ goto FAIL;
+ }
+ }
+ if (type_ != SD_CARD_TYPE_SDHC) { firstBlock <<= 9; lastBlock <<= 9; }
+ if (cardCommand(CMD32, firstBlock) || cardCommand(CMD33, lastBlock) || cardCommand(CMD38, 0)) {
+ error(SD_CARD_ERROR_ERASE);
+ goto FAIL;
+ }
+ if (!waitNotBusy(SD_ERASE_TIMEOUT)) {
+ error(SD_CARD_ERROR_ERASE_TIMEOUT);
+ goto FAIL;
+ }
+ chipDeselect();
+ return true;
+ FAIL:
+ chipDeselect();
+ return false;
+}
+
+/**
+ * Determine if card supports single block erase.
+ *
+ * \return true if single block erase is supported.
+ * false if single block erase is not supported.
+ */
+bool Sd2Card::eraseSingleBlockEnable() {
+ csd_t csd;
+ return readCSD(&csd) ? csd.v1.erase_blk_en : false;
+}
+
+/**
+ * Initialize an SD flash memory card.
+ *
+ * \param[in] sckRateID SPI clock rate selector. See setSckRate().
+ * \param[in] chipSelectPin SD chip select pin number.
+ *
+ * \return true for success, false for failure.
+ * The reason for failure can be determined by calling errorCode() and errorData().
+ */
+bool Sd2Card::init(const uint8_t sckRateID, const pin_t chipSelectPin) {
+ #if IS_TEENSY_35_36 || IS_TEENSY_40_41
+ chipSelectPin_ = BUILTIN_SDCARD;
+ const uint8_t ret = SDHC_CardInit();
+ type_ = SDHC_CardGetType();
+ return (ret == 0);
+ #endif
+
+ errorCode_ = type_ = 0;
+ chipSelectPin_ = chipSelectPin;
+ // 16-bit init start time allows over a minute
+ const millis_t init_timeout = millis() + SD_INIT_TIMEOUT;
+ uint32_t arg;
+
+ watchdog_refresh(); // In case init takes too long
+
+ // Set pin modes
+ #if ENABLED(ZONESTAR_12864OLED)
+ if (chipSelectPin_ != DOGLCD_CS) {
+ SET_OUTPUT(DOGLCD_CS);
+ WRITE(DOGLCD_CS, HIGH);
+ }
+ #else
+ extDigitalWrite(chipSelectPin_, HIGH); // For some CPUs pinMode can write the wrong data so init desired data value first
+ pinMode(chipSelectPin_, OUTPUT); // Solution for #8746 by @benlye
+ #endif
+ spiBegin();
+
+ // Set SCK rate for initialization commands
+ spiRate_ = SPI_SD_INIT_RATE;
+ spiInit(spiRate_);
+
+ // Must supply min of 74 clock cycles with CS high.
+ LOOP_L_N(i, 10) spiSend(0xFF);
+
+ watchdog_refresh(); // In case init takes too long
+
+ // Command to go idle in SPI mode
+ while ((status_ = cardCommand(CMD0, 0)) != R1_IDLE_STATE) {
+ if (ELAPSED(millis(), init_timeout)) {
+ error(SD_CARD_ERROR_CMD0);
+ goto FAIL;
+ }
+ }
+
+ #if ENABLED(SD_CHECK_AND_RETRY)
+ crcSupported = (cardCommand(CMD59, 1) == R1_IDLE_STATE);
+ #endif
+
+ watchdog_refresh(); // In case init takes too long
+
+ // check SD version
+ for (;;) {
+ if (cardCommand(CMD8, 0x1AA) == (R1_ILLEGAL_COMMAND | R1_IDLE_STATE)) {
+ type(SD_CARD_TYPE_SD1);
+ break;
+ }
+
+ // Get the last byte of r7 response
+ LOOP_L_N(i, 4) status_ = spiRec();
+ if (status_ == 0xAA) {
+ type(SD_CARD_TYPE_SD2);
+ break;
+ }
+
+ if (ELAPSED(millis(), init_timeout)) {
+ error(SD_CARD_ERROR_CMD8);
+ goto FAIL;
+ }
+ }
+
+ watchdog_refresh(); // In case init takes too long
+
+ // Initialize card and send host supports SDHC if SD2
+ arg = type() == SD_CARD_TYPE_SD2 ? 0x40000000 : 0;
+ while ((status_ = cardAcmd(ACMD41, arg)) != R1_READY_STATE) {
+ // Check for timeout
+ if (ELAPSED(millis(), init_timeout)) {
+ error(SD_CARD_ERROR_ACMD41);
+ goto FAIL;
+ }
+ }
+ // If SD2 read OCR register to check for SDHC card
+ if (type() == SD_CARD_TYPE_SD2) {
+ if (cardCommand(CMD58, 0)) {
+ error(SD_CARD_ERROR_CMD58);
+ goto FAIL;
+ }
+ if ((spiRec() & 0xC0) == 0xC0) type(SD_CARD_TYPE_SDHC);
+ // Discard rest of ocr - contains allowed voltage range
+ LOOP_L_N(i, 3) spiRec();
+ }
+ chipDeselect();
+
+ return setSckRate(sckRateID);
+
+ FAIL:
+ chipDeselect();
+ return false;
+}
+
+/**
+ * Read a 512 byte block from an SD card.
+ *
+ * \param[in] blockNumber Logical block to be read.
+ * \param[out] dst Pointer to the location that will receive the data.
+ * \return true for success, false for failure.
+ */
+bool Sd2Card::readBlock(uint32_t blockNumber, uint8_t* dst) {
+ #if IS_TEENSY_35_36 || IS_TEENSY_40_41
+ return 0 == SDHC_CardReadBlock(dst, blockNumber);
+ #endif
+
+ if (type() != SD_CARD_TYPE_SDHC) blockNumber <<= 9; // Use address if not SDHC card
+
+ #if ENABLED(SD_CHECK_AND_RETRY)
+ uint8_t retryCnt = 3;
+ for (;;) {
+ if (cardCommand(CMD17, blockNumber))
+ error(SD_CARD_ERROR_CMD17);
+ else if (readData(dst, 512))
+ return true;
+
+ chipDeselect();
+ if (!--retryCnt) break;
+
+ cardCommand(CMD12, 0); // Try sending a stop command, ignore the result.
+ errorCode_ = 0;
+ }
+ return false;
+ #else
+ if (cardCommand(CMD17, blockNumber)) {
+ error(SD_CARD_ERROR_CMD17);
+ chipDeselect();
+ return false;
+ }
+ else
+ return readData(dst, 512);
+ #endif
+}
+
+/**
+ * Read one data block in a multiple block read sequence
+ *
+ * \param[in] dst Pointer to the location for the data to be read.
+ *
+ * \return true for success, false for failure.
+ */
+bool Sd2Card::readData(uint8_t* dst) {
+ chipSelect();
+ return readData(dst, 512);
+}
+
+#if ENABLED(SD_CHECK_AND_RETRY)
+ #ifdef FAST_CRC
+ static const uint16_t crctab16[] PROGMEM = {
+ 0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50A5, 0x60C6, 0x70E7,
+ 0x8108, 0x9129, 0xA14A, 0xB16B, 0xC18C, 0xD1AD, 0xE1CE, 0xF1EF,
+ 0x1231, 0x0210, 0x3273, 0x2252, 0x52B5, 0x4294, 0x72F7, 0x62D6,
+ 0x9339, 0x8318, 0xB37B, 0xA35A, 0xD3BD, 0xC39C, 0xF3FF, 0xE3DE,
+ 0x2462, 0x3443, 0x0420, 0x1401, 0x64E6, 0x74C7, 0x44A4, 0x5485,
+ 0xA56A, 0xB54B, 0x8528, 0x9509, 0xE5EE, 0xF5CF, 0xC5AC, 0xD58D,
+ 0x3653, 0x2672, 0x1611, 0x0630, 0x76D7, 0x66F6, 0x5695, 0x46B4,
+ 0xB75B, 0xA77A, 0x9719, 0x8738, 0xF7DF, 0xE7FE, 0xD79D, 0xC7BC,
+ 0x48C4, 0x58E5, 0x6886, 0x78A7, 0x0840, 0x1861, 0x2802, 0x3823,
+ 0xC9CC, 0xD9ED, 0xE98E, 0xF9AF, 0x8948, 0x9969, 0xA90A, 0xB92B,
+ 0x5AF5, 0x4AD4, 0x7AB7, 0x6A96, 0x1A71, 0x0A50, 0x3A33, 0x2A12,
+ 0xDBFD, 0xCBDC, 0xFBBF, 0xEB9E, 0x9B79, 0x8B58, 0xBB3B, 0xAB1A,
+ 0x6CA6, 0x7C87, 0x4CE4, 0x5CC5, 0x2C22, 0x3C03, 0x0C60, 0x1C41,
+ 0xEDAE, 0xFD8F, 0xCDEC, 0xDDCD, 0xAD2A, 0xBD0B, 0x8D68, 0x9D49,
+ 0x7E97, 0x6EB6, 0x5ED5, 0x4EF4, 0x3E13, 0x2E32, 0x1E51, 0x0E70,
+ 0xFF9F, 0xEFBE, 0xDFDD, 0xCFFC, 0xBF1B, 0xAF3A, 0x9F59, 0x8F78,
+ 0x9188, 0x81A9, 0xB1CA, 0xA1EB, 0xD10C, 0xC12D, 0xF14E, 0xE16F,
+ 0x1080, 0x00A1, 0x30C2, 0x20E3, 0x5004, 0x4025, 0x7046, 0x6067,
+ 0x83B9, 0x9398, 0xA3FB, 0xB3DA, 0xC33D, 0xD31C, 0xE37F, 0xF35E,
+ 0x02B1, 0x1290, 0x22F3, 0x32D2, 0x4235, 0x5214, 0x6277, 0x7256,
+ 0xB5EA, 0xA5CB, 0x95A8, 0x8589, 0xF56E, 0xE54F, 0xD52C, 0xC50D,
+ 0x34E2, 0x24C3, 0x14A0, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405,
+ 0xA7DB, 0xB7FA, 0x8799, 0x97B8, 0xE75F, 0xF77E, 0xC71D, 0xD73C,
+ 0x26D3, 0x36F2, 0x0691, 0x16B0, 0x6657, 0x7676, 0x4615, 0x5634,
+ 0xD94C, 0xC96D, 0xF90E, 0xE92F, 0x99C8, 0x89E9, 0xB98A, 0xA9AB,
+ 0x5844, 0x4865, 0x7806, 0x6827, 0x18C0, 0x08E1, 0x3882, 0x28A3,
+ 0xCB7D, 0xDB5C, 0xEB3F, 0xFB1E, 0x8BF9, 0x9BD8, 0xABBB, 0xBB9A,
+ 0x4A75, 0x5A54, 0x6A37, 0x7A16, 0x0AF1, 0x1AD0, 0x2AB3, 0x3A92,
+ 0xFD2E, 0xED0F, 0xDD6C, 0xCD4D, 0xBDAA, 0xAD8B, 0x9DE8, 0x8DC9,
+ 0x7C26, 0x6C07, 0x5C64, 0x4C45, 0x3CA2, 0x2C83, 0x1CE0, 0x0CC1,
+ 0xEF1F, 0xFF3E, 0xCF5D, 0xDF7C, 0xAF9B, 0xBFBA, 0x8FD9, 0x9FF8,
+ 0x6E17, 0x7E36, 0x4E55, 0x5E74, 0x2E93, 0x3EB2, 0x0ED1, 0x1EF0
+ };
+ // faster CRC-CCITT
+ // uses the x^16,x^12,x^5,x^1 polynomial.
+ static uint16_t CRC_CCITT(const uint8_t* data, size_t n) {
+ uint16_t crc = 0;
+ for (size_t i = 0; i < n; i++) {
+ crc = pgm_read_word(&crctab16[(crc >> 8 ^ data[i]) & 0xFF]) ^ (crc << 8);
+ }
+ return crc;
+ }
+ #else
+ // slower CRC-CCITT
+ // uses the x^16,x^12,x^5,x^1 polynomial.
+ static uint16_t CRC_CCITT(const uint8_t* data, size_t n) {
+ uint16_t crc = 0;
+ for (size_t i = 0; i < n; i++) {
+ crc = (uint8_t)(crc >> 8) | (crc << 8);
+ crc ^= data[i];
+ crc ^= (uint8_t)(crc & 0xFF) >> 4;
+ crc ^= crc << 12;
+ crc ^= (crc & 0xFF) << 5;
+ }
+ return crc;
+ }
+ #endif
+#endif // SD_CHECK_AND_RETRY
+
+bool Sd2Card::readData(uint8_t* dst, const uint16_t count) {
+ bool success = false;
+
+ const millis_t read_timeout = millis() + SD_READ_TIMEOUT;
+ while ((status_ = spiRec()) == 0xFF) { // Wait for start block token
+ if (ELAPSED(millis(), read_timeout)) {
+ error(SD_CARD_ERROR_READ_TIMEOUT);
+ goto FAIL;
+ }
+ }
+
+ if (status_ == DATA_START_BLOCK) {
+ spiRead(dst, count); // Transfer data
+
+ const uint16_t recvCrc = (spiRec() << 8) | spiRec();
+ #if ENABLED(SD_CHECK_AND_RETRY)
+ success = !crcSupported || recvCrc == CRC_CCITT(dst, count);
+ if (!success) error(SD_CARD_ERROR_READ_CRC);
+ #else
+ success = true;
+ UNUSED(recvCrc);
+ #endif
+ }
+ else
+ error(SD_CARD_ERROR_READ);
+
+ FAIL:
+ chipDeselect();
+ return success;
+}
+
+/** read CID or CSR register */
+bool Sd2Card::readRegister(const uint8_t cmd, void* buf) {
+ uint8_t* dst = reinterpret_cast<uint8_t*>(buf);
+ if (cardCommand(cmd, 0)) {
+ error(SD_CARD_ERROR_READ_REG);
+ chipDeselect();
+ return false;
+ }
+ return readData(dst, 16);
+}
+
+/**
+ * Start a read multiple blocks sequence.
+ *
+ * \param[in] blockNumber Address of first block in sequence.
+ *
+ * \note This function is used with readData() and readStop() for optimized
+ * multiple block reads. SPI chipSelect must be low for the entire sequence.
+ *
+ * \return true for success, false for failure.
+ */
+bool Sd2Card::readStart(uint32_t blockNumber) {
+ if (type() != SD_CARD_TYPE_SDHC) blockNumber <<= 9;
+
+ const bool success = !cardCommand(CMD18, blockNumber);
+ if (!success) error(SD_CARD_ERROR_CMD18);
+ chipDeselect();
+ return success;
+}
+
+/**
+ * End a read multiple blocks sequence.
+ *
+ * \return true for success, false for failure.
+ */
+bool Sd2Card::readStop() {
+ chipSelect();
+ const bool success = !cardCommand(CMD12, 0);
+ if (!success) error(SD_CARD_ERROR_CMD12);
+ chipDeselect();
+ return success;
+}
+
+/**
+ * Set the SPI clock rate.
+ *
+ * \param[in] sckRateID A value in the range [0, 6].
+ *
+ * The SPI clock will be set to F_CPU/pow(2, 1 + sckRateID). The maximum
+ * SPI rate is F_CPU/2 for \a sckRateID = 0 and the minimum rate is F_CPU/128
+ * for \a scsRateID = 6.
+ *
+ * \return The value one, true, is returned for success and the value zero,
+ * false, is returned for an invalid value of \a sckRateID.
+ */
+bool Sd2Card::setSckRate(const uint8_t sckRateID) {
+ const bool success = (sckRateID <= 6);
+ if (success) spiRate_ = sckRateID; else error(SD_CARD_ERROR_SCK_RATE);
+ return success;
+}
+
+/**
+ * Wait for card to become not-busy
+ * \param[in] timeout_ms Timeout to abort.
+ * \return true for success, false for timeout.
+ */
+bool Sd2Card::waitNotBusy(const millis_t timeout_ms) {
+ const millis_t wait_timeout = millis() + timeout_ms;
+ while (spiRec() != 0xFF) if (ELAPSED(millis(), wait_timeout)) return false;
+ return true;
+}
+
+/**
+ * Write a 512 byte block to an SD card.
+ *
+ * \param[in] blockNumber Logical block to be written.
+ * \param[in] src Pointer to the location of the data to be written.
+ * \return true for success, false for failure.
+ */
+bool Sd2Card::writeBlock(uint32_t blockNumber, const uint8_t* src) {
+ if (ENABLED(SDCARD_READONLY)) return false;
+
+ #if IS_TEENSY_35_36 || IS_TEENSY_40_41
+ return 0 == SDHC_CardWriteBlock(src, blockNumber);
+ #endif
+
+ bool success = false;
+ if (type() != SD_CARD_TYPE_SDHC) blockNumber <<= 9; // Use address if not SDHC card
+ if (!cardCommand(CMD24, blockNumber)) {
+ if (writeData(DATA_START_BLOCK, src)) {
+ if (waitNotBusy(SD_WRITE_TIMEOUT)) { // Wait for flashing to complete
+ success = !(cardCommand(CMD13, 0) || spiRec()); // Response is r2 so get and check two bytes for nonzero
+ if (!success) error(SD_CARD_ERROR_WRITE_PROGRAMMING);
+ }
+ else
+ error(SD_CARD_ERROR_WRITE_TIMEOUT);
+ }
+ }
+ else
+ error(SD_CARD_ERROR_CMD24);
+
+ chipDeselect();
+ return success;
+}
+
+/**
+ * Write one data block in a multiple block write sequence
+ * \param[in] src Pointer to the location of the data to be written.
+ * \return true for success, false for failure.
+ */
+bool Sd2Card::writeData(const uint8_t* src) {
+ if (ENABLED(SDCARD_READONLY)) return false;
+
+ bool success = true;
+ chipSelect();
+ // Wait for previous write to finish
+ if (!waitNotBusy(SD_WRITE_TIMEOUT) || !writeData(WRITE_MULTIPLE_TOKEN, src)) {
+ error(SD_CARD_ERROR_WRITE_MULTIPLE);
+ success = false;
+ }
+ chipDeselect();
+ return success;
+}
+
+// Send one block of data for write block or write multiple blocks
+bool Sd2Card::writeData(const uint8_t token, const uint8_t* src) {
+ if (ENABLED(SDCARD_READONLY)) return false;
+
+ const uint16_t crc = TERN(SD_CHECK_AND_RETRY, CRC_CCITT(src, 512), 0xFFFF);
+ spiSendBlock(token, src);
+ spiSend(crc >> 8);
+ spiSend(crc & 0xFF);
+
+ status_ = spiRec();
+ if ((status_ & DATA_RES_MASK) != DATA_RES_ACCEPTED) {
+ error(SD_CARD_ERROR_WRITE);
+ chipDeselect();
+ return false;
+ }
+ return true;
+}
+
+/**
+ * Start a write multiple blocks sequence.
+ *
+ * \param[in] blockNumber Address of first block in sequence.
+ * \param[in] eraseCount The number of blocks to be pre-erased.
+ *
+ * \note This function is used with writeData() and writeStop()
+ * for optimized multiple block writes.
+ *
+ * \return true for success, false for failure.
+ */
+bool Sd2Card::writeStart(uint32_t blockNumber, const uint32_t eraseCount) {
+ if (ENABLED(SDCARD_READONLY)) return false;
+
+ bool success = false;
+ if (!cardAcmd(ACMD23, eraseCount)) { // Send pre-erase count
+ if (type() != SD_CARD_TYPE_SDHC) blockNumber <<= 9; // Use address if not SDHC card
+ success = !cardCommand(CMD25, blockNumber);
+ if (!success) error(SD_CARD_ERROR_CMD25);
+ }
+ else
+ error(SD_CARD_ERROR_ACMD23);
+
+ chipDeselect();
+ return success;
+}
+
+/**
+ * End a write multiple blocks sequence.
+ *
+ * \return true for success, false for failure.
+ */
+bool Sd2Card::writeStop() {
+ if (ENABLED(SDCARD_READONLY)) return false;
+
+ bool success = false;
+ chipSelect();
+ if (waitNotBusy(SD_WRITE_TIMEOUT)) {
+ spiSend(STOP_TRAN_TOKEN);
+ success = waitNotBusy(SD_WRITE_TIMEOUT);
+ }
+ else
+ error(SD_CARD_ERROR_STOP_TRAN);
+
+ chipDeselect();
+ return success;
+}
+
+#endif // SDSUPPORT
diff --git a/Marlin/src/sd/Sd2Card.h b/Marlin/src/sd/Sd2Card.h
new file mode 100644
index 0000000..6900502
--- /dev/null
+++ b/Marlin/src/sd/Sd2Card.h
@@ -0,0 +1,186 @@
+/**
+ * Marlin 3D Printer Firmware
+ * Copyright (c) 2020 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 <https://www.gnu.org/licenses/>.
+ *
+ */
+#pragma once
+
+/**
+ * \file
+ * \brief Sd2Card class for V2 SD/SDHC cards
+ */
+
+/**
+ * Arduino Sd2Card Library
+ * Copyright (c) 2009 by William Greiman
+ *
+ * This file is part of the Arduino Sd2Card Library
+ */
+
+#include "SdFatConfig.h"
+#include "SdInfo.h"
+
+#include <stdint.h>
+
+uint16_t const SD_INIT_TIMEOUT = 2000, // init timeout ms
+ SD_ERASE_TIMEOUT = 10000, // erase timeout ms
+ SD_READ_TIMEOUT = 300, // read timeout ms
+ SD_WRITE_TIMEOUT = 600; // write time out ms
+
+// SD card errors
+uint8_t const SD_CARD_ERROR_CMD0 = 0x01, // timeout error for command CMD0 (initialize card in SPI mode)
+ SD_CARD_ERROR_CMD8 = 0x02, // CMD8 was not accepted - not a valid SD card
+ SD_CARD_ERROR_CMD12 = 0x03, // card returned an error response for CMD12 (write stop)
+ SD_CARD_ERROR_CMD17 = 0x04, // card returned an error response for CMD17 (read block)
+ SD_CARD_ERROR_CMD18 = 0x05, // card returned an error response for CMD18 (read multiple block)
+ SD_CARD_ERROR_CMD24 = 0x06, // card returned an error response for CMD24 (write block)
+ SD_CARD_ERROR_CMD25 = 0x07, // WRITE_MULTIPLE_BLOCKS command failed
+ SD_CARD_ERROR_CMD58 = 0x08, // card returned an error response for CMD58 (read OCR)
+ SD_CARD_ERROR_ACMD23 = 0x09, // SET_WR_BLK_ERASE_COUNT failed
+ SD_CARD_ERROR_ACMD41 = 0x0A, // ACMD41 initialization process timeout
+ SD_CARD_ERROR_BAD_CSD = 0x0B, // card returned a bad CSR version field
+ SD_CARD_ERROR_ERASE = 0x0C, // erase block group command failed
+ SD_CARD_ERROR_ERASE_SINGLE_BLOCK = 0x0D, // card not capable of single block erase
+ SD_CARD_ERROR_ERASE_TIMEOUT = 0x0E, // Erase sequence timed out
+ SD_CARD_ERROR_READ = 0x0F, // card returned an error token instead of read data
+ SD_CARD_ERROR_READ_REG = 0x10, // read CID or CSD failed
+ SD_CARD_ERROR_READ_TIMEOUT = 0x11, // timeout while waiting for start of read data
+ SD_CARD_ERROR_STOP_TRAN = 0x12, // card did not accept STOP_TRAN_TOKEN
+ SD_CARD_ERROR_WRITE = 0x13, // card returned an error token as a response to a write operation
+ SD_CARD_ERROR_WRITE_BLOCK_ZERO = 0x14, // REMOVE - not used ... attempt to write protected block zero
+ SD_CARD_ERROR_WRITE_MULTIPLE = 0x15, // card did not go ready for a multiple block write
+ SD_CARD_ERROR_WRITE_PROGRAMMING = 0x16, // card returned an error to a CMD13 status check after a write
+ SD_CARD_ERROR_WRITE_TIMEOUT = 0x17, // timeout occurred during write programming
+ SD_CARD_ERROR_SCK_RATE = 0x18, // incorrect rate selected
+ SD_CARD_ERROR_INIT_NOT_CALLED = 0x19, // init() not called
+ // 0x1A is unused now, it was: card returned an error for CMD59 (CRC_ON_OFF)
+ SD_CARD_ERROR_READ_CRC = 0x1B; // invalid read CRC
+
+// card types
+uint8_t const SD_CARD_TYPE_SD1 = 1, // Standard capacity V1 SD card
+ SD_CARD_TYPE_SD2 = 2, // Standard capacity V2 SD card
+ SD_CARD_TYPE_SDHC = 3; // High Capacity SD card
+
+/**
+ * Define SOFTWARE_SPI to use bit-bang SPI
+ */
+#if EITHER(MEGA_SOFT_SPI, USE_SOFTWARE_SPI)
+ #define SOFTWARE_SPI
+#endif
+
+#if IS_TEENSY_35_36 || IS_TEENSY_40_41
+ #include "NXP_SDHC.h"
+ #define BUILTIN_SDCARD 254
+#endif
+
+/**
+ * \class Sd2Card
+ * \brief Raw access to SD and SDHC flash memory cards.
+ */
+class Sd2Card {
+public:
+
+ Sd2Card() : errorCode_(SD_CARD_ERROR_INIT_NOT_CALLED), type_(0) {}
+
+ uint32_t cardSize();
+ bool erase(uint32_t firstBlock, uint32_t lastBlock);
+ bool eraseSingleBlockEnable();
+
+ /**
+ * Set SD error code.
+ * \param[in] code value for error code.
+ */
+ inline void error(const uint8_t code) { errorCode_ = code; }
+
+ /**
+ * \return error code for last error. See Sd2Card.h for a list of error codes.
+ */
+ inline int errorCode() const { return errorCode_; }
+
+ /** \return error data for last error. */
+ inline int errorData() const { return status_; }
+
+ /**
+ * Initialize an SD flash memory card with default clock rate and chip
+ * select pin. See sd2Card::init(uint8_t sckRateID, uint8_t chipSelectPin).
+ *
+ * \return true for success or false for failure.
+ */
+ bool init(const uint8_t sckRateID, const pin_t chipSelectPin);
+
+ bool readBlock(uint32_t block, uint8_t* dst);
+
+ /**
+ * Read a card's CID register. The CID contains card identification
+ * information such as Manufacturer ID, Product name, Product serial
+ * number and Manufacturing date.
+ *
+ * \param[out] cid pointer to area for returned data.
+ *
+ * \return true for success or false for failure.
+ */
+ bool readCID(cid_t* cid) { return readRegister(CMD10, cid); }
+
+ /**
+ * Read a card's CSD register. The CSD contains Card-Specific Data that
+ * provides information regarding access to the card's contents.
+ *
+ * \param[out] csd pointer to area for returned data.
+ *
+ * \return true for success or false for failure.
+ */
+ inline bool readCSD(csd_t* csd) { return readRegister(CMD9, csd); }
+
+ bool readData(uint8_t* dst);
+ bool readStart(uint32_t blockNumber);
+ bool readStop();
+ bool setSckRate(const uint8_t sckRateID);
+
+ /**
+ * Return the card type: SD V1, SD V2 or SDHC
+ * \return 0 - SD V1, 1 - SD V2, or 3 - SDHC.
+ */
+ int type() const {return type_;}
+ bool writeBlock(uint32_t blockNumber, const uint8_t* src);
+ bool writeData(const uint8_t* src);
+ bool writeStart(uint32_t blockNumber, const uint32_t eraseCount);
+ bool writeStop();
+
+private:
+ uint8_t chipSelectPin_,
+ errorCode_,
+ spiRate_,
+ status_,
+ type_;
+
+ // private functions
+ inline uint8_t cardAcmd(const uint8_t cmd, const uint32_t arg) {
+ cardCommand(CMD55, 0);
+ return cardCommand(cmd, arg);
+ }
+ uint8_t cardCommand(const uint8_t cmd, const uint32_t arg);
+
+ bool readData(uint8_t* dst, const uint16_t count);
+ bool readRegister(const uint8_t cmd, void* buf);
+ void chipDeselect();
+ void chipSelect();
+ inline void type(const uint8_t value) { type_ = value; }
+ bool waitNotBusy(const millis_t timeout_ms);
+ bool writeData(const uint8_t token, const uint8_t* src);
+};
diff --git a/Marlin/src/sd/Sd2Card_sdio.h b/Marlin/src/sd/Sd2Card_sdio.h
new file mode 100644
index 0000000..10fb757
--- /dev/null
+++ b/Marlin/src/sd/Sd2Card_sdio.h
@@ -0,0 +1,39 @@
+/**
+ * Marlin 3D Printer Firmware
+ * Copyright (c) 2020 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 <https://www.gnu.org/licenses/>.
+ *
+ */
+#pragma once
+
+#include "../inc/MarlinConfig.h"
+
+#if ENABLED(SDIO_SUPPORT)
+
+bool SDIO_Init();
+bool SDIO_ReadBlock(uint32_t block, uint8_t *dst);
+bool SDIO_WriteBlock(uint32_t block, const uint8_t *src);
+
+class Sd2Card {
+ public:
+ bool init(uint8_t sckRateID = 0, uint8_t chipSelectPin = 0) { return SDIO_Init(); }
+ bool readBlock(uint32_t block, uint8_t *dst) { return SDIO_ReadBlock(block, dst); }
+ bool writeBlock(uint32_t block, const uint8_t *src) { return SDIO_WriteBlock(block, src); }
+};
+
+#endif // SDIO_SUPPORT
diff --git a/Marlin/src/sd/SdBaseFile.cpp b/Marlin/src/sd/SdBaseFile.cpp
new file mode 100644
index 0000000..7693c52
--- /dev/null
+++ b/Marlin/src/sd/SdBaseFile.cpp
@@ -0,0 +1,1813 @@
+/**
+ * Marlin 3D Printer Firmware
+ * Copyright (c) 2020 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 <https://www.gnu.org/licenses/>.
+ *
+ */
+
+#if __GNUC__ > 8
+ #pragma GCC diagnostic ignored "-Waddress-of-packed-member"
+#endif
+
+/**
+ * sd/SdBaseFile.cpp
+ *
+ * Arduino SdFat Library
+ * Copyright (c) 2009 by William Greiman
+ *
+ * This file is part of the Arduino Sd2Card Library
+ */
+
+#include "../inc/MarlinConfig.h"
+
+#if ENABLED(SDSUPPORT)
+
+#include "SdBaseFile.h"
+
+#include "../MarlinCore.h"
+SdBaseFile* SdBaseFile::cwd_ = 0; // Pointer to Current Working Directory
+
+// callback function for date/time
+void (*SdBaseFile::dateTime_)(uint16_t* date, uint16_t* time) = 0;
+
+// add a cluster to a file
+bool SdBaseFile::addCluster() {
+ if (ENABLED(SDCARD_READONLY)) return false;
+
+ if (!vol_->allocContiguous(1, &curCluster_)) return false;
+
+ // if first cluster of file link to directory entry
+ if (firstCluster_ == 0) {
+ firstCluster_ = curCluster_;
+ flags_ |= F_FILE_DIR_DIRTY;
+ }
+ return true;
+}
+
+// Add a cluster to a directory file and zero the cluster.
+// return with first block of cluster in the cache
+bool SdBaseFile::addDirCluster() {
+ if (ENABLED(SDCARD_READONLY)) return false;
+
+ uint32_t block;
+ // max folder size
+ if (fileSize_ / sizeof(dir_t) >= 0xFFFF) return false;
+
+ if (!addCluster()) return false;
+ if (!vol_->cacheFlush()) return false;
+
+ block = vol_->clusterStartBlock(curCluster_);
+
+ // set cache to first block of cluster
+ vol_->cacheSetBlockNumber(block, true);
+
+ // zero first block of cluster
+ memset(vol_->cacheBuffer_.data, 0, 512);
+
+ // zero rest of cluster
+ for (uint8_t i = 1; i < vol_->blocksPerCluster_; i++) {
+ if (!vol_->writeBlock(block + i, vol_->cacheBuffer_.data)) return false;
+ }
+ // Increase directory file size by cluster size
+ fileSize_ += 512UL << vol_->clusterSizeShift_;
+ return true;
+}
+
+// cache a file's directory entry
+// return pointer to cached entry or null for failure
+dir_t* SdBaseFile::cacheDirEntry(uint8_t action) {
+ if (!vol_->cacheRawBlock(dirBlock_, action)) return nullptr;
+ return vol_->cache()->dir + dirIndex_;
+}
+
+/**
+ * Close a file and force cached data and directory information
+ * to be written to the storage device.
+ *
+ * \return true for success, false for failure.
+ * Reasons for failure include no file is open or an I/O error.
+ */
+bool SdBaseFile::close() {
+ bool rtn = sync();
+ type_ = FAT_FILE_TYPE_CLOSED;
+ return rtn;
+}
+
+/**
+ * Check for contiguous file and return its raw block range.
+ *
+ * \param[out] bgnBlock the first block address for the file.
+ * \param[out] endBlock the last block address for the file.
+ *
+ * \return true for success, false for failure.
+ * Reasons for failure include file is not contiguous, file has zero length
+ * or an I/O error occurred.
+ */
+bool SdBaseFile::contiguousRange(uint32_t* bgnBlock, uint32_t* endBlock) {
+ // error if no blocks
+ if (firstCluster_ == 0) return false;
+
+ for (uint32_t c = firstCluster_; ; c++) {
+ uint32_t next;
+ if (!vol_->fatGet(c, &next)) return false;
+
+ // check for contiguous
+ if (next != (c + 1)) {
+ // error if not end of chain
+ if (!vol_->isEOC(next)) return false;
+ *bgnBlock = vol_->clusterStartBlock(firstCluster_);
+ *endBlock = vol_->clusterStartBlock(c)
+ + vol_->blocksPerCluster_ - 1;
+ return true;
+ }
+ }
+ return false;
+}
+
+/**
+ * Create and open a new contiguous file of a specified size.
+ *
+ * \note This function only supports short DOS 8.3 names.
+ * See open() for more information.
+ *
+ * \param[in] dirFile The directory where the file will be created.
+ * \param[in] path A path with a valid DOS 8.3 file name.
+ * \param[in] size The desired file size.
+ *
+ * \return true for success, false for failure.
+ * Reasons for failure include \a path contains
+ * an invalid DOS 8.3 file name, the FAT volume has not been initialized,
+ * a file is already open, the file already exists, the root
+ * directory is full or an I/O error.
+ */
+bool SdBaseFile::createContiguous(SdBaseFile* dirFile, const char* path, uint32_t size) {
+ if (ENABLED(SDCARD_READONLY)) return false;
+
+ uint32_t count;
+ // don't allow zero length file
+ if (size == 0) return false;
+ if (!open(dirFile, path, O_CREAT | O_EXCL | O_RDWR)) return false;
+
+ // calculate number of clusters needed
+ count = ((size - 1) >> (vol_->clusterSizeShift_ + 9)) + 1;
+
+ // allocate clusters
+ if (!vol_->allocContiguous(count, &firstCluster_)) {
+ remove();
+ return false;
+ }
+ fileSize_ = size;
+
+ // insure sync() will update dir entry
+ flags_ |= F_FILE_DIR_DIRTY;
+
+ return sync();
+}
+
+/**
+ * Return a file's directory entry.
+ *
+ * \param[out] dir Location for return of the file's directory entry.
+ *
+ * \return true for success, false for failure.
+ */
+bool SdBaseFile::dirEntry(dir_t* dir) {
+ dir_t* p;
+ // make sure fields on SD are correct
+ if (!sync()) return false;
+
+ // read entry
+ p = cacheDirEntry(SdVolume::CACHE_FOR_READ);
+ if (!p) return false;
+
+ // copy to caller's struct
+ memcpy(dir, p, sizeof(dir_t));
+ return true;
+}
+
+/**
+ * Format the name field of \a dir into the 13 byte array
+ * \a name in standard 8.3 short name format.
+ *
+ * \param[in] dir The directory structure containing the name.
+ * \param[out] name A 13 byte char array for the formatted name.
+ */
+void SdBaseFile::dirName(const dir_t& dir, char* name) {
+ uint8_t j = 0;
+ LOOP_L_N(i, 11) {
+ if (dir.name[i] == ' ')continue;
+ if (i == 8) name[j++] = '.';
+ name[j++] = dir.name[i];
+ }
+ name[j] = 0;
+}
+
+/**
+ * Test for the existence of a file in a directory
+ *
+ * \param[in] name Name of the file to be tested for.
+ *
+ * The calling instance must be an open directory file.
+ *
+ * dirFile.exists("TOFIND.TXT") searches for "TOFIND.TXT" in the directory
+ * dirFile.
+ *
+ * \return true if the file exists else false.
+ */
+bool SdBaseFile::exists(const char* name) {
+ SdBaseFile file;
+ return file.open(this, name, O_READ);
+}
+
+/**
+ * Get a string from a file.
+ *
+ * fgets() reads bytes from a file into the array pointed to by \a str, until
+ * \a num - 1 bytes are read, or a delimiter is read and transferred to \a str,
+ * or end-of-file is encountered. The string is then terminated
+ * with a null byte.
+ *
+ * fgets() deletes CR, '\\r', from the string. This insures only a '\\n'
+ * terminates the string for Windows text files which use CRLF for newline.
+ *
+ * \param[out] str Pointer to the array where the string is stored.
+ * \param[in] num Maximum number of characters to be read
+ * (including the final null byte). Usually the length
+ * of the array \a str is used.
+ * \param[in] delim Optional set of delimiters. The default is "\n".
+ *
+ * \return For success fgets() returns the length of the string in \a str.
+ * If no data is read, fgets() returns zero for EOF or -1 if an error occurred.
+ **/
+int16_t SdBaseFile::fgets(char* str, int16_t num, char* delim) {
+ char ch;
+ int16_t n = 0;
+ int16_t r = -1;
+ while ((n + 1) < num && (r = read(&ch, 1)) == 1) {
+ // delete CR
+ if (ch == '\r') continue;
+ str[n++] = ch;
+ if (!delim) {
+ if (ch == '\n') break;
+ }
+ else {
+ if (strchr(delim, ch)) break;
+ }
+ }
+ if (r < 0) {
+ // read error
+ return -1;
+ }
+ str[n] = '\0';
+ return n;
+}
+
+/**
+ * Get a file's name
+ *
+ * \param[out] name An array of 13 characters for the file's name.
+ *
+ * \return true for success, false for failure.
+ */
+bool SdBaseFile::getDosName(char * const name) {
+ if (!isOpen()) return false;
+
+ if (isRoot()) {
+ name[0] = '/';
+ name[1] = '\0';
+ return true;
+ }
+ // cache entry
+ dir_t* p = cacheDirEntry(SdVolume::CACHE_FOR_READ);
+ if (!p) return false;
+
+ // format name
+ dirName(*p, name);
+ return true;
+}
+
+void SdBaseFile::getpos(filepos_t* pos) {
+ pos->position = curPosition_;
+ pos->cluster = curCluster_;
+}
+
+/**
+ * List directory contents.
+ *
+ * \param[in] pr Print stream for list.
+ *
+ * \param[in] flags The inclusive OR of
+ *
+ * LS_DATE - %Print file modification date
+ *
+ * LS_SIZE - %Print file size.
+ *
+ * LS_R - Recursive list of subdirectories.
+ *
+ * \param[in] indent Amount of space before file name. Used for recursive
+ * list to indicate subdirectory level.
+ */
+void SdBaseFile::ls(uint8_t flags, uint8_t indent) {
+ rewind();
+ int8_t status;
+ while ((status = lsPrintNext(flags, indent))) {
+ if (status > 1 && (flags & LS_R)) {
+ uint16_t index = curPosition() / 32 - 1;
+ SdBaseFile s;
+ if (s.open(this, index, O_READ)) s.ls(flags, indent + 2);
+ seekSet(32 * (index + 1));
+ }
+ }
+}
+
+// saves 32 bytes on stack for ls recursion
+// return 0 - EOF, 1 - normal file, or 2 - directory
+int8_t SdBaseFile::lsPrintNext(uint8_t flags, uint8_t indent) {
+ dir_t dir;
+ uint8_t w = 0;
+
+ while (1) {
+ if (read(&dir, sizeof(dir)) != sizeof(dir)) return 0;
+ if (dir.name[0] == DIR_NAME_FREE) return 0;
+
+ // skip deleted entry and entries for . and ..
+ if (dir.name[0] != DIR_NAME_DELETED && dir.name[0] != '.'
+ && DIR_IS_FILE_OR_SUBDIR(&dir)) break;
+ }
+ // indent for dir level
+ LOOP_L_N(i, indent) SERIAL_CHAR(' ');
+
+ // print name
+ LOOP_L_N(i, 11) {
+ if (dir.name[i] == ' ')continue;
+ if (i == 8) {
+ SERIAL_CHAR('.');
+ w++;
+ }
+ SERIAL_CHAR(dir.name[i]);
+ w++;
+ }
+ if (DIR_IS_SUBDIR(&dir)) {
+ SERIAL_CHAR('/');
+ w++;
+ }
+ if (flags & (LS_DATE | LS_SIZE)) {
+ while (w++ < 14) SERIAL_CHAR(' ');
+ }
+ // print modify date/time if requested
+ if (flags & LS_DATE) {
+ SERIAL_CHAR(' ');
+ printFatDate(dir.lastWriteDate);
+ SERIAL_CHAR(' ');
+ printFatTime(dir.lastWriteTime);
+ }
+ // print size if requested
+ if (!DIR_IS_SUBDIR(&dir) && (flags & LS_SIZE)) {
+ SERIAL_CHAR(' ');
+ SERIAL_ECHO(dir.fileSize);
+ }
+ SERIAL_EOL();
+ return DIR_IS_FILE(&dir) ? 1 : 2;
+}
+
+// Format directory name field from a 8.3 name string
+bool SdBaseFile::make83Name(const char* str, uint8_t* name, const char** ptr) {
+ uint8_t n = 7, // Max index until a dot is found
+ i = 11;
+ while (i) name[--i] = ' '; // Set whole FILENAME.EXT to spaces
+ while (*str && *str != '/') { // For each character, until nul or '/'
+ uint8_t c = *str++; // Get char and advance
+ if (c == '.') { // For a dot...
+ if (n == 10) return false; // Already moved the max index? fail!
+ n = 10; // Move the max index for full 8.3 name
+ i = 8; // Move up to the extension place
+ }
+ else {
+ // Fail for illegal characters
+ PGM_P p = PSTR("|<>^+=?/[];,*\"\\");
+ while (uint8_t b = pgm_read_byte(p++)) if (b == c) return false;
+ if (i > n || c < 0x21 || c == 0x7F) return false; // Check size, non-printable characters
+ name[i++] = c + (WITHIN(c, 'a', 'z') ? 'A' - 'a' : 0); // Uppercase required for 8.3 name
+ }
+ }
+ *ptr = str; // Set passed pointer to the end
+ return name[0] != ' '; // Return true if any name was set
+}
+
+/**
+ * Make a new directory.
+ *
+ * \param[in] parent An open SdFat instance for the directory that will contain
+ * the new directory.
+ *
+ * \param[in] path A path with a valid 8.3 DOS name for the new directory.
+ *
+ * \param[in] pFlag Create missing parent directories if true.
+ *
+ * \return true for success, false for failure.
+ * Reasons for failure include this file is already open, \a parent is not a
+ * directory, \a path is invalid or already exists in \a parent.
+ */
+bool SdBaseFile::mkdir(SdBaseFile* parent, const char* path, bool pFlag) {
+ if (ENABLED(SDCARD_READONLY)) return false;
+
+ uint8_t dname[11];
+ SdBaseFile dir1, dir2;
+ SdBaseFile* sub = &dir1;
+ SdBaseFile* start = parent;
+
+ if (!parent || isOpen()) return false;
+
+ if (*path == '/') {
+ while (*path == '/') path++;
+ if (!parent->isRoot()) {
+ if (!dir2.openRoot(parent->vol_)) return false;
+ parent = &dir2;
+ }
+ }
+ while (1) {
+ if (!make83Name(path, dname, &path)) return false;
+ while (*path == '/') path++;
+ if (!*path) break;
+ if (!sub->open(parent, dname, O_READ)) {
+ if (!pFlag || !sub->mkdir(parent, dname))
+ return false;
+ }
+ if (parent != start) parent->close();
+ parent = sub;
+ sub = parent != &dir1 ? &dir1 : &dir2;
+ }
+ return mkdir(parent, dname);
+}
+
+bool SdBaseFile::mkdir(SdBaseFile* parent, const uint8_t dname[11]) {
+ if (ENABLED(SDCARD_READONLY)) return false;
+
+ uint32_t block;
+ dir_t d;
+ dir_t* p;
+
+ if (!parent->isDir()) return false;
+
+ // create a normal file
+ if (!open(parent, dname, O_CREAT | O_EXCL | O_RDWR)) return false;
+
+ // convert file to directory
+ flags_ = O_READ;
+ type_ = FAT_FILE_TYPE_SUBDIR;
+
+ // allocate and zero first cluster
+ if (!addDirCluster()) return false;
+
+ // force entry to SD
+ if (!sync()) return false;
+
+ // cache entry - should already be in cache due to sync() call
+ p = cacheDirEntry(SdVolume::CACHE_FOR_WRITE);
+ if (!p) return false;
+
+ // change directory entry attribute
+ p->attributes = DIR_ATT_DIRECTORY;
+
+ // make entry for '.'
+ memcpy(&d, p, sizeof(d));
+ d.name[0] = '.';
+ LOOP_S_L_N(i, 1, 11) d.name[i] = ' ';
+
+ // cache block for '.' and '..'
+ block = vol_->clusterStartBlock(firstCluster_);
+ if (!vol_->cacheRawBlock(block, SdVolume::CACHE_FOR_WRITE)) return false;
+
+ // copy '.' to block
+ memcpy(&vol_->cache()->dir[0], &d, sizeof(d));
+
+ // make entry for '..'
+ d.name[1] = '.';
+ if (parent->isRoot()) {
+ d.firstClusterLow = 0;
+ d.firstClusterHigh = 0;
+ }
+ else {
+ d.firstClusterLow = parent->firstCluster_ & 0xFFFF;
+ d.firstClusterHigh = parent->firstCluster_ >> 16;
+ }
+ // copy '..' to block
+ memcpy(&vol_->cache()->dir[1], &d, sizeof(d));
+
+ // write first block
+ return vol_->cacheFlush();
+}
+
+/**
+ * Open a file in the current working directory.
+ *
+ * \param[in] path A path with a valid 8.3 DOS name for a file to be opened.
+ *
+ * \param[in] oflag Values for \a oflag are constructed by a bitwise-inclusive
+ * OR of open flags. see SdBaseFile::open(SdBaseFile*, const char*, uint8_t).
+ *
+ * \return true for success, false for failure.
+ */
+bool SdBaseFile::open(const char* path, uint8_t oflag) {
+ return open(cwd_, path, oflag);
+}
+
+/**
+ * Open a file or directory by name.
+ *
+ * \param[in] dirFile An open SdFat instance for the directory containing the
+ * file to be opened.
+ *
+ * \param[in] path A path with a valid 8.3 DOS name for a file to be opened.
+ *
+ * \param[in] oflag Values for \a oflag are constructed by a bitwise-inclusive
+ * OR of flags from the following list
+ *
+ * O_READ - Open for reading.
+ *
+ * O_RDONLY - Same as O_READ.
+ *
+ * O_WRITE - Open for writing.
+ *
+ * O_WRONLY - Same as O_WRITE.
+ *
+ * O_RDWR - Open for reading and writing.
+ *
+ * O_APPEND - If set, the file offset shall be set to the end of the
+ * file prior to each write.
+ *
+ * O_AT_END - Set the initial position at the end of the file.
+ *
+ * O_CREAT - If the file exists, this flag has no effect except as noted
+ * under O_EXCL below. Otherwise, the file shall be created
+ *
+ * O_EXCL - If O_CREAT and O_EXCL are set, open() shall fail if the file exists.
+ *
+ * O_SYNC - Call sync() after each write. This flag should not be used with
+ * write(uint8_t), write_P(PGM_P), writeln_P(PGM_P), or the Arduino Print class.
+ * These functions do character at a time writes so sync() will be called
+ * after each byte.
+ *
+ * O_TRUNC - If the file exists and is a regular file, and the file is
+ * successfully opened and is not read only, its length shall be truncated to 0.
+ *
+ * WARNING: A given file must not be opened by more than one SdBaseFile object
+ * of file corruption may occur.
+ *
+ * \note Directory files must be opened read only. Write and truncation is
+ * not allowed for directory files.
+ *
+ * \return true for success, false for failure.
+ * Reasons for failure include this file is already open, \a dirFile is not
+ * a directory, \a path is invalid, the file does not exist
+ * or can't be opened in the access mode specified by oflag.
+ */
+bool SdBaseFile::open(SdBaseFile* dirFile, const char* path, uint8_t oflag) {
+ uint8_t dname[11];
+ SdBaseFile dir1, dir2;
+ SdBaseFile *parent = dirFile, *sub = &dir1;
+
+ if (!dirFile || isOpen()) return false;
+
+ if (*path == '/') { // Path starts with '/'
+ if (!dirFile->isRoot()) { // Is the passed dirFile the root?
+ if (!dir2.openRoot(dirFile->vol_)) return false; // Get the root in dir2, if possible
+ parent = &dir2; // Change 'parent' to point at the root dir
+ }
+ while (*path == '/') path++; // Skip all leading slashes
+ }
+
+ for (;;) {
+ if (!make83Name(path, dname, &path)) return false;
+ while (*path == '/') path++;
+ if (!*path) break;
+ if (!sub->open(parent, dname, O_READ)) return false;
+ if (parent != dirFile) parent->close();
+ parent = sub;
+ sub = parent != &dir1 ? &dir1 : &dir2;
+ }
+ return open(parent, dname, oflag);
+}
+
+// open with filename in dname
+bool SdBaseFile::open(SdBaseFile* dirFile, const uint8_t dname[11], uint8_t oflag) {
+ bool emptyFound = false, fileFound = false;
+ uint8_t index;
+ dir_t* p;
+
+ vol_ = dirFile->vol_;
+
+ dirFile->rewind();
+ // search for file
+
+ while (dirFile->curPosition_ < dirFile->fileSize_) {
+ index = 0xF & (dirFile->curPosition_ >> 5);
+ p = dirFile->readDirCache();
+ if (!p) return false;
+
+ if (p->name[0] == DIR_NAME_FREE || p->name[0] == DIR_NAME_DELETED) {
+ // remember first empty slot
+ if (!emptyFound) {
+ dirBlock_ = dirFile->vol_->cacheBlockNumber();
+ dirIndex_ = index;
+ emptyFound = true;
+ }
+ // done if no entries follow
+ if (p->name[0] == DIR_NAME_FREE) break;
+ }
+ else if (!memcmp(dname, p->name, 11)) {
+ fileFound = true;
+ break;
+ }
+ }
+ if (fileFound) {
+ // don't open existing file if O_EXCL
+ if (oflag & O_EXCL) return false;
+ }
+ else {
+ // don't create unless O_CREAT and O_WRITE
+ if ((oflag & (O_CREAT | O_WRITE)) != (O_CREAT | O_WRITE)) return false;
+ if (emptyFound) {
+ index = dirIndex_;
+ p = cacheDirEntry(SdVolume::CACHE_FOR_WRITE);
+ if (!p) return false;
+ }
+ else {
+ if (dirFile->type_ == FAT_FILE_TYPE_ROOT_FIXED) return false;
+
+ // add and zero cluster for dirFile - first cluster is in cache for write
+ if (!dirFile->addDirCluster()) return false;
+
+ // use first entry in cluster
+ p = dirFile->vol_->cache()->dir;
+ index = 0;
+ }
+ // initialize as empty file
+ memset(p, 0, sizeof(*p));
+ memcpy(p->name, dname, 11);
+
+ // set timestamps
+ if (dateTime_) {
+ // call user date/time function
+ dateTime_(&p->creationDate, &p->creationTime);
+ }
+ else {
+ // use default date/time
+ p->creationDate = FAT_DEFAULT_DATE;
+ p->creationTime = FAT_DEFAULT_TIME;
+ }
+ p->lastAccessDate = p->creationDate;
+ p->lastWriteDate = p->creationDate;
+ p->lastWriteTime = p->creationTime;
+
+ // write entry to SD
+ if (!dirFile->vol_->cacheFlush()) return false;
+ }
+ // open entry in cache
+ return openCachedEntry(index, oflag);
+}
+
+/**
+ * Open a file by index.
+ *
+ * \param[in] dirFile An open SdFat instance for the directory.
+ *
+ * \param[in] index The \a index of the directory entry for the file to be
+ * opened. The value for \a index is (directory file position)/32.
+ *
+ * \param[in] oflag Values for \a oflag are constructed by a bitwise-inclusive
+ * OR of flags O_READ, O_WRITE, O_TRUNC, and O_SYNC.
+ *
+ * See open() by path for definition of flags.
+ * \return true for success or false for failure.
+ */
+bool SdBaseFile::open(SdBaseFile* dirFile, uint16_t index, uint8_t oflag) {
+ dir_t* p;
+
+ vol_ = dirFile->vol_;
+
+ // error if already open
+ if (isOpen() || !dirFile) return false;
+
+ // don't open existing file if O_EXCL - user call error
+ if (oflag & O_EXCL) return false;
+
+ // seek to location of entry
+ if (!dirFile->seekSet(32 * index)) return false;
+
+ // read entry into cache
+ p = dirFile->readDirCache();
+ if (!p) return false;
+
+ // error if empty slot or '.' or '..'
+ if (p->name[0] == DIR_NAME_FREE ||
+ p->name[0] == DIR_NAME_DELETED || p->name[0] == '.') {
+ return false;
+ }
+ // open cached entry
+ return openCachedEntry(index & 0xF, oflag);
+}
+
+// open a cached directory entry. Assumes vol_ is initialized
+bool SdBaseFile::openCachedEntry(uint8_t dirIndex, uint8_t oflag) {
+ dir_t* p;
+
+ #if ENABLED(SDCARD_READONLY)
+ if (oflag & (O_WRITE | O_CREAT | O_TRUNC)) goto FAIL;
+ #endif
+
+ // location of entry in cache
+ p = &vol_->cache()->dir[dirIndex];
+
+ // write or truncate is an error for a directory or read-only file
+ if (p->attributes & (DIR_ATT_READ_ONLY | DIR_ATT_DIRECTORY)) {
+ if (oflag & (O_WRITE | O_TRUNC)) goto FAIL;
+ }
+ // remember location of directory entry on SD
+ dirBlock_ = vol_->cacheBlockNumber();
+ dirIndex_ = dirIndex;
+
+ // copy first cluster number for directory fields
+ firstCluster_ = (uint32_t)p->firstClusterHigh << 16;
+ firstCluster_ |= p->firstClusterLow;
+
+ // make sure it is a normal file or subdirectory
+ if (DIR_IS_FILE(p)) {
+ fileSize_ = p->fileSize;
+ type_ = FAT_FILE_TYPE_NORMAL;
+ }
+ else if (DIR_IS_SUBDIR(p)) {
+ if (!vol_->chainSize(firstCluster_, &fileSize_)) goto FAIL;
+ type_ = FAT_FILE_TYPE_SUBDIR;
+ }
+ else
+ goto FAIL;
+
+ // save open flags for read/write
+ flags_ = oflag & F_OFLAG;
+
+ // set to start of file
+ curCluster_ = 0;
+ curPosition_ = 0;
+ if ((oflag & O_TRUNC) && !truncate(0)) return false;
+ return oflag & O_AT_END ? seekEnd(0) : true;
+
+ FAIL:
+ type_ = FAT_FILE_TYPE_CLOSED;
+ return false;
+}
+
+/**
+ * Open the next file or subdirectory in a directory.
+ *
+ * \param[in] dirFile An open SdFat instance for the directory containing the
+ * file to be opened.
+ *
+ * \param[in] oflag Values for \a oflag are constructed by a bitwise-inclusive
+ * OR of flags O_READ, O_WRITE, O_TRUNC, and O_SYNC.
+ *
+ * See open() by path for definition of flags.
+ * \return true for success or false for failure.
+ */
+bool SdBaseFile::openNext(SdBaseFile* dirFile, uint8_t oflag) {
+ dir_t* p;
+ uint8_t index;
+
+ if (!dirFile) return false;
+
+ // error if already open
+ if (isOpen()) return false;
+
+ vol_ = dirFile->vol_;
+
+ while (1) {
+ index = 0xF & (dirFile->curPosition_ >> 5);
+
+ // read entry into cache
+ p = dirFile->readDirCache();
+ if (!p) return false;
+
+ // done if last entry
+ if (p->name[0] == DIR_NAME_FREE) return false;
+
+ // skip empty slot or '.' or '..'
+ if (p->name[0] == DIR_NAME_DELETED || p->name[0] == '.') {
+ continue;
+ }
+ // must be file or dir
+ if (DIR_IS_FILE_OR_SUBDIR(p)) {
+ return openCachedEntry(index, oflag);
+ }
+ }
+ return false;
+}
+
+#if 0
+/**
+ * Open a directory's parent directory.
+ *
+ * \param[in] dir Parent of this directory will be opened. Must not be root.
+ *
+ * \return true for success, false for failure.
+ */
+bool SdBaseFile::openParent(SdBaseFile* dir) {
+ dir_t entry;
+ dir_t* p;
+ SdBaseFile file;
+ uint32_t c;
+ uint32_t cluster;
+ uint32_t lbn;
+ // error if already open or dir is root or dir is not a directory
+ if (isOpen() || !dir || dir->isRoot() || !dir->isDir()) return false;
+ vol_ = dir->vol_;
+ // position to '..'
+ if (!dir->seekSet(32)) return false;
+ // read '..' entry
+ if (dir->read(&entry, sizeof(entry)) != 32) return false;
+ // verify it is '..'
+ if (entry.name[0] != '.' || entry.name[1] != '.') return false;
+ // start cluster for '..'
+ cluster = entry.firstClusterLow;
+ cluster |= (uint32_t)entry.firstClusterHigh << 16;
+ if (cluster == 0) return openRoot(vol_);
+ // start block for '..'
+ lbn = vol_->clusterStartBlock(cluster);
+ // first block of parent dir
+ if (!vol_->cacheRawBlock(lbn, SdVolume::CACHE_FOR_READ)) return false;
+
+ p = &vol_->cacheBuffer_.dir[1];
+ // verify name for '../..'
+ if (p->name[0] != '.' || p->name[1] != '.') return false;
+ // '..' is pointer to first cluster of parent. open '../..' to find parent
+ if (p->firstClusterHigh == 0 && p->firstClusterLow == 0) {
+ if (!file.openRoot(dir->volume())) return false;
+ }
+ else if (!file.openCachedEntry(1, O_READ))
+ return false;
+
+ // search for parent in '../..'
+ do {
+ if (file.readDir(&entry, nullptr) != 32) return false;
+ c = entry.firstClusterLow;
+ c |= (uint32_t)entry.firstClusterHigh << 16;
+ } while (c != cluster);
+
+ // open parent
+ return open(&file, file.curPosition() / 32 - 1, O_READ);
+}
+#endif
+
+/**
+ * Open a volume's root directory.
+ *
+ * \param[in] vol The FAT volume containing the root directory to be opened.
+ *
+ * \return true for success, false for failure.
+ * Reasons for failure include the file is already open, the FAT volume has
+ * not been initialized or it a FAT12 volume.
+ */
+bool SdBaseFile::openRoot(SdVolume* vol) {
+ // error if file is already open
+ if (isOpen()) return false;
+
+ if (vol->fatType() == 16 || (FAT12_SUPPORT && vol->fatType() == 12)) {
+ type_ = FAT_FILE_TYPE_ROOT_FIXED;
+ firstCluster_ = 0;
+ fileSize_ = 32 * vol->rootDirEntryCount();
+ }
+ else if (vol->fatType() == 32) {
+ type_ = FAT_FILE_TYPE_ROOT32;
+ firstCluster_ = vol->rootDirStart();
+ if (!vol->chainSize(firstCluster_, &fileSize_)) return false;
+ }
+ else // volume is not initialized, invalid, or FAT12 without support
+ return false;
+
+ vol_ = vol;
+ // read only
+ flags_ = O_READ;
+
+ // set to start of file
+ curCluster_ = curPosition_ = 0;
+
+ // root has no directory entry
+ dirBlock_ = dirIndex_ = 0;
+ return true;
+}
+
+/**
+ * Return the next available byte without consuming it.
+ *
+ * \return The byte if no error and not at eof else -1;
+ */
+int SdBaseFile::peek() {
+ filepos_t pos;
+ getpos(&pos);
+ int c = read();
+ if (c >= 0) setpos(&pos);
+ return c;
+}
+
+// print uint8_t with width 2
+static void print2u(const uint8_t v) {
+ if (v < 10) SERIAL_CHAR('0');
+ SERIAL_ECHO((int)v);
+}
+
+/**
+ * %Print a directory date field to Serial.
+ *
+ * Format is yyyy-mm-dd.
+ *
+ * \param[in] fatDate The date field from a directory entry.
+ */
+
+
+/**
+ * %Print a directory date field.
+ *
+ * Format is yyyy-mm-dd.
+ *
+ * \param[in] pr Print stream for output.
+ * \param[in] fatDate The date field from a directory entry.
+ */
+void SdBaseFile::printFatDate(uint16_t fatDate) {
+ SERIAL_ECHO(FAT_YEAR(fatDate));
+ SERIAL_CHAR('-');
+ print2u(FAT_MONTH(fatDate));
+ SERIAL_CHAR('-');
+ print2u(FAT_DAY(fatDate));
+}
+
+
+/**
+ * %Print a directory time field.
+ *
+ * Format is hh:mm:ss.
+ *
+ * \param[in] pr Print stream for output.
+ * \param[in] fatTime The time field from a directory entry.
+ */
+void SdBaseFile::printFatTime(uint16_t fatTime) {
+ print2u(FAT_HOUR(fatTime));
+ SERIAL_CHAR(':');
+ print2u(FAT_MINUTE(fatTime));
+ SERIAL_CHAR(':');
+ print2u(FAT_SECOND(fatTime));
+}
+
+/**
+ * Print a file's name to Serial
+ *
+ * \return true for success, false for failure.
+ */
+bool SdBaseFile::printName() {
+ char name[FILENAME_LENGTH];
+ if (!getDosName(name)) return false;
+ SERIAL_ECHO(name);
+ return true;
+}
+
+/**
+ * Read the next byte from a file.
+ *
+ * \return For success read returns the next byte in the file as an int.
+ * If an error occurs or end of file is reached -1 is returned.
+ */
+int16_t SdBaseFile::read() {
+ uint8_t b;
+ return read(&b, 1) == 1 ? b : -1;
+}
+
+/**
+ * Read data from a file starting at the current position.
+ *
+ * \param[out] buf Pointer to the location that will receive the data.
+ *
+ * \param[in] nbyte Maximum number of bytes to read.
+ *
+ * \return For success read() returns the number of bytes read.
+ * A value less than \a nbyte, including zero, will be returned
+ * if end of file is reached.
+ * If an error occurs, read() returns -1. Possible errors include
+ * read() called before a file has been opened, corrupt file system
+ * or an I/O error occurred.
+ */
+int16_t SdBaseFile::read(void* buf, uint16_t nbyte) {
+ uint8_t* dst = reinterpret_cast<uint8_t*>(buf);
+ uint16_t offset, toRead;
+ uint32_t block; // raw device block number
+
+ // error if not open or write only
+ if (!isOpen() || !(flags_ & O_READ)) return -1;
+
+ // max bytes left in file
+ NOMORE(nbyte, fileSize_ - curPosition_);
+
+ // amount left to read
+ toRead = nbyte;
+ while (toRead > 0) {
+ offset = curPosition_ & 0x1FF; // offset in block
+ if (type_ == FAT_FILE_TYPE_ROOT_FIXED) {
+ block = vol_->rootDirStart() + (curPosition_ >> 9);
+ }
+ else {
+ uint8_t blockOfCluster = vol_->blockOfCluster(curPosition_);
+ if (offset == 0 && blockOfCluster == 0) {
+ // start of new cluster
+ if (curPosition_ == 0)
+ curCluster_ = firstCluster_; // use first cluster in file
+ else if (!vol_->fatGet(curCluster_, &curCluster_)) // get next cluster from FAT
+ return -1;
+ }
+ block = vol_->clusterStartBlock(curCluster_) + blockOfCluster;
+ }
+ uint16_t n = toRead;
+
+ // amount to be read from current block
+ NOMORE(n, 512 - offset);
+
+ // no buffering needed if n == 512
+ if (n == 512 && block != vol_->cacheBlockNumber()) {
+ if (!vol_->readBlock(block, dst)) return -1;
+ }
+ else {
+ // read block to cache and copy data to caller
+ if (!vol_->cacheRawBlock(block, SdVolume::CACHE_FOR_READ)) return -1;
+ uint8_t* src = vol_->cache()->data + offset;
+ memcpy(dst, src, n);
+ }
+ dst += n;
+ curPosition_ += n;
+ toRead -= n;
+ }
+ return nbyte;
+}
+
+/**
+ * Read the next entry in a directory.
+ *
+ * \param[out] dir The dir_t struct that will receive the data.
+ *
+ * \return For success readDir() returns the number of bytes read.
+ * A value of zero will be returned if end of file is reached.
+ * If an error occurs, readDir() returns -1. Possible errors include
+ * readDir() called before a directory has been opened, this is not
+ * a directory file or an I/O error occurred.
+ */
+int8_t SdBaseFile::readDir(dir_t* dir, char* longFilename) {
+ int16_t n;
+ // if not a directory file or miss-positioned return an error
+ if (!isDir() || (0x1F & curPosition_)) return -1;
+
+ // If we have a longFilename buffer, mark it as invalid.
+ // If a long filename is found it will be filled automatically.
+ if (longFilename) { longFilename[0] = '\0'; longFilename[1] = '\0'; }
+
+ while (1) {
+
+ n = read(dir, sizeof(dir_t));
+ if (n != sizeof(dir_t)) return n ? -1 : 0;
+
+ // last entry if DIR_NAME_FREE
+ if (dir->name[0] == DIR_NAME_FREE) return 0;
+
+ // skip deleted entry and entry for . and ..
+ if (dir->name[0] == DIR_NAME_DELETED || dir->name[0] == '.') {
+ if (longFilename) { longFilename[0] = '\0'; longFilename[1] = '\0'; } // Invalidate erased file long name, if any
+ continue;
+ }
+
+ // Fill the long filename if we have a long filename entry.
+ // Long filename entries are stored before the short filename.
+ if (longFilename && DIR_IS_LONG_NAME(dir)) {
+ vfat_t* VFAT = (vfat_t*)dir;
+ // Sanity-check the VFAT entry. The first cluster is always set to zero. And the sequence number should be higher than 0
+ if (VFAT->firstClusterLow == 0) {
+ const uint8_t seq = VFAT->sequenceNumber & 0x1F;
+ if (WITHIN(seq, 1, MAX_VFAT_ENTRIES)) {
+ // TODO: Store the filename checksum to verify if a long-filename-unaware system modified the file table.
+ n = (seq - 1) * (FILENAME_LENGTH);
+ LOOP_L_N(i, FILENAME_LENGTH) {
+ uint16_t utf16_ch = (i < 5) ? VFAT->name1[i] : (i < 11) ? VFAT->name2[i - 5] : VFAT->name3[i - 11];
+ #if ENABLED(UTF_FILENAME_SUPPORT)
+ // We can't reconvert to UTF-8 here as UTF-8 is variable-size encoding, but joining LFN blocks
+ // needs static bytes addressing. So here just store full UTF-16LE words to re-convert later.
+ uint16_t idx = (n + i) * 2; // This is fixed as FAT LFN always contain UTF-16LE encoding
+ longFilename[idx] = utf16_ch & 0xFF;
+ longFilename[idx + 1] = (utf16_ch >> 8) & 0xFF;
+ #else
+ // Replace all multibyte characters to '_'
+ longFilename[n + i] = (utf16_ch > 0xFF) ? '_' : (utf16_ch & 0xFF);
+ #endif
+ }
+ // If this VFAT entry is the last one, add a NUL terminator at the end of the string
+ if (VFAT->sequenceNumber & 0x40) longFilename[(n + FILENAME_LENGTH) * LONG_FILENAME_CHARSIZE] = '\0';
+ }
+ }
+ }
+
+ // Post-process normal file or subdirectory longname, if any
+ if (DIR_IS_FILE_OR_SUBDIR(dir)) {
+ #if ENABLED(UTF_FILENAME_SUPPORT)
+ #if LONG_FILENAME_CHARSIZE > 2
+ // Add warning for developers for currently not supported 3-byte cases (Conversion series of 2-byte
+ // codepoints to 3-byte in-place will break the rest of filename)
+ #error "Currently filename re-encoding is done in-place. It may break the remaining chars to use 3-byte codepoints."
+ #endif
+
+ // Is there a long filename to decode?
+ if (longFilename) {
+ // Reset n to the start of the long name
+ n = 0;
+ for (uint16_t idx = 0; idx < (LONG_FILENAME_LENGTH) / 2; idx += 2) { // idx is fixed since FAT LFN always contains UTF-16LE encoding
+ uint16_t utf16_ch = longFilename[idx] | (longFilename[idx + 1] << 8);
+ if (0xD800 == (utf16_ch & 0xF800)) // Surrogate pair - encode as '_'
+ longFilename[n++] = '_';
+ else if (0 == (utf16_ch & 0xFF80)) // Encode as 1-byte UTF-8 char
+ longFilename[n++] = utf16_ch & 0x007F;
+ else if (0 == (utf16_ch & 0xF800)) { // Encode as 2-byte UTF-8 char
+ longFilename[n++] = 0xC0 | ((utf16_ch >> 6) & 0x1F);
+ longFilename[n++] = 0x80 | ( utf16_ch & 0x3F);
+ }
+ else {
+ #if LONG_FILENAME_CHARSIZE > 2 // Encode as 3-byte UTF-8 char
+ longFilename[n++] = 0xE0 | ((utf16_ch >> 12) & 0x0F);
+ longFilename[n++] = 0xC0 | ((utf16_ch >> 6) & 0x3F);
+ longFilename[n++] = 0xC0 | ( utf16_ch & 0x3F);
+ #else // Encode as '_'
+ longFilename[n++] = '_';
+ #endif
+ }
+ if (0 == utf16_ch) break; // End of filename
+ } // idx
+ } // longFilename
+ #endif
+ return n;
+ } // DIR_IS_FILE_OR_SUBDIR
+ }
+}
+
+// Read next directory entry into the cache
+// Assumes file is correctly positioned
+dir_t* SdBaseFile::readDirCache() {
+ uint8_t i;
+ // error if not directory
+ if (!isDir()) return 0;
+
+ // index of entry in cache
+ i = (curPosition_ >> 5) & 0xF;
+
+ // use read to locate and cache block
+ if (read() < 0) return 0;
+
+ // advance to next entry
+ curPosition_ += 31;
+
+ // return pointer to entry
+ return vol_->cache()->dir + i;
+}
+
+/**
+ * Remove a file.
+ *
+ * The directory entry and all data for the file are deleted.
+ *
+ * \note This function should not be used to delete the 8.3 version of a
+ * file that has a long name. For example if a file has the long name
+ * "New Text Document.txt" you should not delete the 8.3 name "NEWTEX~1.TXT".
+ *
+ * \return true for success, false for failure.
+ * Reasons for failure include the file read-only, is a directory,
+ * or an I/O error occurred.
+ */
+bool SdBaseFile::remove() {
+ if (ENABLED(SDCARD_READONLY)) return false;
+
+ dir_t* d;
+ // free any clusters - will fail if read-only or directory
+ if (!truncate(0)) return false;
+
+ // cache directory entry
+ d = cacheDirEntry(SdVolume::CACHE_FOR_WRITE);
+ if (!d) return false;
+
+ // mark entry deleted
+ d->name[0] = DIR_NAME_DELETED;
+
+ // set this file closed
+ type_ = FAT_FILE_TYPE_CLOSED;
+
+ // write entry to SD
+ return vol_->cacheFlush();
+ return true;
+}
+
+/**
+ * Remove a file.
+ *
+ * The directory entry and all data for the file are deleted.
+ *
+ * \param[in] dirFile The directory that contains the file.
+ * \param[in] path Path for the file to be removed.
+ *
+ * \note This function should not be used to delete the 8.3 version of a
+ * file that has a long name. For example if a file has the long name
+ * "New Text Document.txt" you should not delete the 8.3 name "NEWTEX~1.TXT".
+ *
+ * \return true for success, false for failure.
+ * Reasons for failure include the file is a directory, is read only,
+ * \a dirFile is not a directory, \a path is not found
+ * or an I/O error occurred.
+ */
+bool SdBaseFile::remove(SdBaseFile* dirFile, const char* path) {
+ if (ENABLED(SDCARD_READONLY)) return false;
+
+ SdBaseFile file;
+ return file.open(dirFile, path, O_WRITE) ? file.remove() : false;
+}
+
+/**
+ * Rename a file or subdirectory.
+ *
+ * \param[in] dirFile Directory for the new path.
+ * \param[in] newPath New path name for the file/directory.
+ *
+ * \return true for success, false for failure.
+ * Reasons for failure include \a dirFile is not open or is not a directory
+ * file, newPath is invalid or already exists, or an I/O error occurs.
+ */
+bool SdBaseFile::rename(SdBaseFile* dirFile, const char* newPath) {
+ if (ENABLED(SDCARD_READONLY)) return false;
+
+ dir_t entry;
+ uint32_t dirCluster = 0;
+ SdBaseFile file;
+ dir_t* d;
+
+ // must be an open file or subdirectory
+ if (!(isFile() || isSubDir())) return false;
+
+ // can't move file
+ if (vol_ != dirFile->vol_) return false;
+
+ // sync() and cache directory entry
+ sync();
+ d = cacheDirEntry(SdVolume::CACHE_FOR_WRITE);
+ if (!d) return false;
+
+ // save directory entry
+ memcpy(&entry, d, sizeof(entry));
+
+ // mark entry deleted
+ d->name[0] = DIR_NAME_DELETED;
+
+ // make directory entry for new path
+ if (isFile()) {
+ if (!file.open(dirFile, newPath, O_CREAT | O_EXCL | O_WRITE)) {
+ goto restore;
+ }
+ }
+ else {
+ // don't create missing path prefix components
+ if (!file.mkdir(dirFile, newPath, false)) {
+ goto restore;
+ }
+ // save cluster containing new dot dot
+ dirCluster = file.firstCluster_;
+ }
+ // change to new directory entry
+ dirBlock_ = file.dirBlock_;
+ dirIndex_ = file.dirIndex_;
+
+ // mark closed to avoid possible destructor close call
+ file.type_ = FAT_FILE_TYPE_CLOSED;
+
+ // cache new directory entry
+ d = cacheDirEntry(SdVolume::CACHE_FOR_WRITE);
+ if (!d) return false;
+
+ // copy all but name field to new directory entry
+ memcpy(&d->attributes, &entry.attributes, sizeof(entry) - sizeof(d->name));
+
+ // update dot dot if directory
+ if (dirCluster) {
+ // get new dot dot
+ uint32_t block = vol_->clusterStartBlock(dirCluster);
+ if (!vol_->cacheRawBlock(block, SdVolume::CACHE_FOR_READ)) return false;
+ memcpy(&entry, &vol_->cache()->dir[1], sizeof(entry));
+
+ // free unused cluster
+ if (!vol_->freeChain(dirCluster)) return false;
+
+ // store new dot dot
+ block = vol_->clusterStartBlock(firstCluster_);
+ if (!vol_->cacheRawBlock(block, SdVolume::CACHE_FOR_WRITE)) return false;
+ memcpy(&vol_->cache()->dir[1], &entry, sizeof(entry));
+ }
+ return vol_->cacheFlush();
+
+restore:
+ if ((d = cacheDirEntry(SdVolume::CACHE_FOR_WRITE))) {
+ // restore entry
+ d->name[0] = entry.name[0];
+ vol_->cacheFlush();
+ }
+ return false;
+}
+
+/**
+ * Remove a directory file.
+ *
+ * The directory file will be removed only if it is empty and is not the
+ * root directory. rmdir() follows DOS and Windows and ignores the
+ * read-only attribute for the directory.
+ *
+ * \note This function should not be used to delete the 8.3 version of a
+ * directory that has a long name. For example if a directory has the
+ * long name "New folder" you should not delete the 8.3 name "NEWFOL~1".
+ *
+ * \return true for success, false for failure.
+ * Reasons for failure include the file is not a directory, is the root
+ * directory, is not empty, or an I/O error occurred.
+ */
+bool SdBaseFile::rmdir() {
+ if (ENABLED(SDCARD_READONLY)) return false;
+
+ // must be open subdirectory
+ if (!isSubDir()) return false;
+
+ rewind();
+
+ // make sure directory is empty
+ while (curPosition_ < fileSize_) {
+ dir_t* p = readDirCache();
+ if (!p) return false;
+ // done if past last used entry
+ if (p->name[0] == DIR_NAME_FREE) break;
+ // skip empty slot, '.' or '..'
+ if (p->name[0] == DIR_NAME_DELETED || p->name[0] == '.') continue;
+ // error not empty
+ if (DIR_IS_FILE_OR_SUBDIR(p)) return false;
+ }
+ // convert empty directory to normal file for remove
+ type_ = FAT_FILE_TYPE_NORMAL;
+ flags_ |= O_WRITE;
+ return remove();
+}
+
+/**
+ * Recursively delete a directory and all contained files.
+ *
+ * This is like the Unix/Linux 'rm -rf *' if called with the root directory
+ * hence the name.
+ *
+ * Warning - This will remove all contents of the directory including
+ * subdirectories. The directory will then be removed if it is not root.
+ * The read-only attribute for files will be ignored.
+ *
+ * \note This function should not be used to delete the 8.3 version of
+ * a directory that has a long name. See remove() and rmdir().
+ *
+ * \return true for success, false for failure.
+ */
+bool SdBaseFile::rmRfStar() {
+ if (ENABLED(SDCARD_READONLY)) return false;
+
+ uint32_t index;
+ SdBaseFile f;
+ rewind();
+ while (curPosition_ < fileSize_) {
+ // remember position
+ index = curPosition_ / 32;
+
+ dir_t* p = readDirCache();
+ if (!p) return false;
+
+ // done if past last entry
+ if (p->name[0] == DIR_NAME_FREE) break;
+
+ // skip empty slot or '.' or '..'
+ if (p->name[0] == DIR_NAME_DELETED || p->name[0] == '.') continue;
+
+ // skip if part of long file name or volume label in root
+ if (!DIR_IS_FILE_OR_SUBDIR(p)) continue;
+
+ if (!f.open(this, index, O_READ)) return false;
+ if (f.isSubDir()) {
+ // recursively delete
+ if (!f.rmRfStar()) return false;
+ }
+ else {
+ // ignore read-only
+ f.flags_ |= O_WRITE;
+ if (!f.remove()) return false;
+ }
+ // position to next entry if required
+ if (curPosition_ != (32 * (index + 1))) {
+ if (!seekSet(32 * (index + 1))) return false;
+ }
+ }
+ // don't try to delete root
+ if (!isRoot()) {
+ if (!rmdir()) return false;
+ }
+ return true;
+}
+
+/**
+ * Create a file object and open it in the current working directory.
+ *
+ * \param[in] path A path with a valid 8.3 DOS name for a file to be opened.
+ *
+ * \param[in] oflag Values for \a oflag are constructed by a bitwise-inclusive
+ * OR of open flags. see SdBaseFile::open(SdBaseFile*, const char*, uint8_t).
+ */
+SdBaseFile::SdBaseFile(const char* path, uint8_t oflag) {
+ type_ = FAT_FILE_TYPE_CLOSED;
+ writeError = false;
+ open(path, oflag);
+}
+
+/**
+ * Sets a file's position.
+ *
+ * \param[in] pos The new position in bytes from the beginning of the file.
+ *
+ * \return true for success, false for failure.
+ */
+bool SdBaseFile::seekSet(const uint32_t pos) {
+ uint32_t nCur, nNew;
+ // error if file not open or seek past end of file
+ if (!isOpen() || pos > fileSize_) return false;
+
+ if (type_ == FAT_FILE_TYPE_ROOT_FIXED) {
+ curPosition_ = pos;
+ return true;
+ }
+ if (pos == 0) {
+ curCluster_ = curPosition_ = 0; // set position to start of file
+ return true;
+ }
+
+ // calculate cluster index for cur and new position
+ nCur = (curPosition_ - 1) >> (vol_->clusterSizeShift_ + 9);
+ nNew = (pos - 1) >> (vol_->clusterSizeShift_ + 9);
+
+ if (nNew < nCur || curPosition_ == 0)
+ curCluster_ = firstCluster_; // must follow chain from first cluster
+ else
+ nNew -= nCur; // advance from curPosition
+
+ while (nNew--)
+ if (!vol_->fatGet(curCluster_, &curCluster_)) return false;
+
+ curPosition_ = pos;
+ return true;
+}
+
+void SdBaseFile::setpos(filepos_t* pos) {
+ curPosition_ = pos->position;
+ curCluster_ = pos->cluster;
+}
+
+/**
+ * The sync() call causes all modified data and directory fields
+ * to be written to the storage device.
+ *
+ * \return true for success, false for failure.
+ * Reasons for failure include a call to sync() before a file has been
+ * opened or an I/O error.
+ */
+bool SdBaseFile::sync() {
+ // only allow open files and directories
+ if (ENABLED(SDCARD_READONLY) || !isOpen()) goto FAIL;
+
+ if (flags_ & F_FILE_DIR_DIRTY) {
+ dir_t* d = cacheDirEntry(SdVolume::CACHE_FOR_WRITE);
+ // check for deleted by another open file object
+ if (!d || d->name[0] == DIR_NAME_DELETED) goto FAIL;
+
+ // do not set filesize for dir files
+ if (!isDir()) d->fileSize = fileSize_;
+
+ // update first cluster fields
+ d->firstClusterLow = firstCluster_ & 0xFFFF;
+ d->firstClusterHigh = firstCluster_ >> 16;
+
+ // set modify time if user supplied a callback date/time function
+ if (dateTime_) {
+ dateTime_(&d->lastWriteDate, &d->lastWriteTime);
+ d->lastAccessDate = d->lastWriteDate;
+ }
+ // clear directory dirty
+ flags_ &= ~F_FILE_DIR_DIRTY;
+ }
+ return vol_->cacheFlush();
+
+ FAIL:
+ writeError = true;
+ return false;
+}
+
+/**
+ * Copy a file's timestamps
+ *
+ * \param[in] file File to copy timestamps from.
+ *
+ * \note
+ * Modify and access timestamps may be overwritten if a date time callback
+ * function has been set by dateTimeCallback().
+ *
+ * \return true for success, false for failure.
+ */
+bool SdBaseFile::timestamp(SdBaseFile* file) {
+ dir_t* d;
+ dir_t dir;
+
+ // get timestamps
+ if (!file->dirEntry(&dir)) return false;
+
+ // update directory fields
+ if (!sync()) return false;
+
+ d = cacheDirEntry(SdVolume::CACHE_FOR_WRITE);
+ if (!d) return false;
+
+ // copy timestamps
+ d->lastAccessDate = dir.lastAccessDate;
+ d->creationDate = dir.creationDate;
+ d->creationTime = dir.creationTime;
+ d->creationTimeTenths = dir.creationTimeTenths;
+ d->lastWriteDate = dir.lastWriteDate;
+ d->lastWriteTime = dir.lastWriteTime;
+
+ // write back entry
+ return vol_->cacheFlush();
+}
+
+/**
+ * Set a file's timestamps in its directory entry.
+ *
+ * \param[in] flags Values for \a flags are constructed by a bitwise-inclusive
+ * OR of flags from the following list
+ *
+ * T_ACCESS - Set the file's last access date.
+ *
+ * T_CREATE - Set the file's creation date and time.
+ *
+ * T_WRITE - Set the file's last write/modification date and time.
+ *
+ * \param[in] year Valid range 1980 - 2107 inclusive.
+ *
+ * \param[in] month Valid range 1 - 12 inclusive.
+ *
+ * \param[in] day Valid range 1 - 31 inclusive.
+ *
+ * \param[in] hour Valid range 0 - 23 inclusive.
+ *
+ * \param[in] minute Valid range 0 - 59 inclusive.
+ *
+ * \param[in] second Valid range 0 - 59 inclusive
+ *
+ * \note It is possible to set an invalid date since there is no check for
+ * the number of days in a month.
+ *
+ * \note
+ * Modify and access timestamps may be overwritten if a date time callback
+ * function has been set by dateTimeCallback().
+ *
+ * \return true for success, false for failure.
+ */
+bool SdBaseFile::timestamp(uint8_t flags, uint16_t year, uint8_t month,
+ uint8_t day, uint8_t hour, uint8_t minute, uint8_t second) {
+ if (ENABLED(SDCARD_READONLY)) return false;
+
+ uint16_t dirDate, dirTime;
+ dir_t* d;
+
+ if (!isOpen()
+ || year < 1980
+ || year > 2107
+ || month < 1
+ || month > 12
+ || day < 1
+ || day > 31
+ || hour > 23
+ || minute > 59
+ || second > 59) {
+ return false;
+ }
+ // update directory entry
+ if (!sync()) return false;
+
+ d = cacheDirEntry(SdVolume::CACHE_FOR_WRITE);
+ if (!d) return false;
+
+ dirDate = FAT_DATE(year, month, day);
+ dirTime = FAT_TIME(hour, minute, second);
+ if (flags & T_ACCESS) {
+ d->lastAccessDate = dirDate;
+ }
+ if (flags & T_CREATE) {
+ d->creationDate = dirDate;
+ d->creationTime = dirTime;
+ // seems to be units of 1/100 second not 1/10 as Microsoft states
+ d->creationTimeTenths = second & 1 ? 100 : 0;
+ }
+ if (flags & T_WRITE) {
+ d->lastWriteDate = dirDate;
+ d->lastWriteTime = dirTime;
+ }
+ return vol_->cacheFlush();
+}
+
+/**
+ * Truncate a file to a specified length. The current file position
+ * will be maintained if it is less than or equal to \a length otherwise
+ * it will be set to end of file.
+ *
+ * \param[in] length The desired length for the file.
+ *
+ * \return true for success, false for failure.
+ * Reasons for failure include file is read only, file is a directory,
+ * \a length is greater than the current file size or an I/O error occurs.
+ */
+bool SdBaseFile::truncate(uint32_t length) {
+ if (ENABLED(SDCARD_READONLY)) return false;
+
+ uint32_t newPos;
+ // error if not a normal file or read-only
+ if (!isFile() || !(flags_ & O_WRITE)) return false;
+
+ // error if length is greater than current size
+ if (length > fileSize_) return false;
+
+ // fileSize and length are zero - nothing to do
+ if (fileSize_ == 0) return true;
+
+ // remember position for seek after truncation
+ newPos = curPosition_ > length ? length : curPosition_;
+
+ // position to last cluster in truncated file
+ if (!seekSet(length)) return false;
+
+ if (length == 0) {
+ // free all clusters
+ if (!vol_->freeChain(firstCluster_)) return false;
+ firstCluster_ = 0;
+ }
+ else {
+ uint32_t toFree;
+ if (!vol_->fatGet(curCluster_, &toFree)) return false;
+
+ if (!vol_->isEOC(toFree)) {
+ // free extra clusters
+ if (!vol_->freeChain(toFree)) return false;
+
+ // current cluster is end of chain
+ if (!vol_->fatPutEOC(curCluster_)) return false;
+ }
+ }
+ fileSize_ = length;
+
+ // need to update directory entry
+ flags_ |= F_FILE_DIR_DIRTY;
+
+ if (!sync()) return false;
+
+ // set file to correct position
+ return seekSet(newPos);
+}
+
+/**
+ * Write data to an open file.
+ *
+ * \note Data is moved to the cache but may not be written to the
+ * storage device until sync() is called.
+ *
+ * \param[in] buf Pointer to the location of the data to be written.
+ *
+ * \param[in] nbyte Number of bytes to write.
+ *
+ * \return For success write() returns the number of bytes written, always
+ * \a nbyte. If an error occurs, write() returns -1. Possible errors
+ * include write() is called before a file has been opened, write is called
+ * for a read-only file, device is full, a corrupt file system or an I/O error.
+ */
+int16_t SdBaseFile::write(const void* buf, uint16_t nbyte) {
+ #if ENABLED(SDCARD_READONLY)
+ writeError = true; return -1;
+ #endif
+
+ // convert void* to uint8_t* - must be before goto statements
+ const uint8_t* src = reinterpret_cast<const uint8_t*>(buf);
+
+ // number of bytes left to write - must be before goto statements
+ uint16_t nToWrite = nbyte;
+
+ // error if not a normal file or is read-only
+ if (!isFile() || !(flags_ & O_WRITE)) goto FAIL;
+
+ // seek to end of file if append flag
+ if ((flags_ & O_APPEND) && curPosition_ != fileSize_) {
+ if (!seekEnd()) goto FAIL;
+ }
+
+ while (nToWrite > 0) {
+ uint8_t blockOfCluster = vol_->blockOfCluster(curPosition_);
+ uint16_t blockOffset = curPosition_ & 0x1FF;
+ if (blockOfCluster == 0 && blockOffset == 0) {
+ // start of new cluster
+ if (curCluster_ == 0) {
+ if (firstCluster_ == 0) {
+ // allocate first cluster of file
+ if (!addCluster()) goto FAIL;
+ }
+ else {
+ curCluster_ = firstCluster_;
+ }
+ }
+ else {
+ uint32_t next;
+ if (!vol_->fatGet(curCluster_, &next)) goto FAIL;
+ if (vol_->isEOC(next)) {
+ // add cluster if at end of chain
+ if (!addCluster()) goto FAIL;
+ }
+ else {
+ curCluster_ = next;
+ }
+ }
+ }
+ // max space in block
+ uint16_t n = 512 - blockOffset;
+
+ // lesser of space and amount to write
+ NOMORE(n, nToWrite);
+
+ // block for data write
+ uint32_t block = vol_->clusterStartBlock(curCluster_) + blockOfCluster;
+ if (n == 512) {
+ // full block - don't need to use cache
+ if (vol_->cacheBlockNumber() == block) {
+ // invalidate cache if block is in cache
+ vol_->cacheSetBlockNumber(0xFFFFFFFF, false);
+ }
+ if (!vol_->writeBlock(block, src)) goto FAIL;
+ }
+ else {
+ if (blockOffset == 0 && curPosition_ >= fileSize_) {
+ // start of new block don't need to read into cache
+ if (!vol_->cacheFlush()) goto FAIL;
+ // set cache dirty and SD address of block
+ vol_->cacheSetBlockNumber(block, true);
+ }
+ else {
+ // rewrite part of block
+ if (!vol_->cacheRawBlock(block, SdVolume::CACHE_FOR_WRITE)) goto FAIL;
+ }
+ uint8_t* dst = vol_->cache()->data + blockOffset;
+ memcpy(dst, src, n);
+ }
+ curPosition_ += n;
+ src += n;
+ nToWrite -= n;
+ }
+ if (curPosition_ > fileSize_) {
+ // update fileSize and insure sync will update dir entry
+ fileSize_ = curPosition_;
+ flags_ |= F_FILE_DIR_DIRTY;
+ }
+ else if (dateTime_ && nbyte) {
+ // insure sync will update modified date and time
+ flags_ |= F_FILE_DIR_DIRTY;
+ }
+
+ if (flags_ & O_SYNC) {
+ if (!sync()) goto FAIL;
+ }
+ return nbyte;
+
+ FAIL:
+ // return for write error
+ writeError = true;
+ return -1;
+}
+
+#endif // SDSUPPORT
diff --git a/Marlin/src/sd/SdBaseFile.h b/Marlin/src/sd/SdBaseFile.h
new file mode 100644
index 0000000..2f7dfb9
--- /dev/null
+++ b/Marlin/src/sd/SdBaseFile.h
@@ -0,0 +1,384 @@
+/**
+ * Marlin 3D Printer Firmware
+ * Copyright (c) 2020 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 <https://www.gnu.org/licenses/>.
+ *
+ */
+#pragma once
+
+/**
+ * sd/SdBaseFile.h
+ *
+ * Arduino SdFat Library
+ * Copyright (c) 2009 by William Greiman
+ *
+ * This file is part of the Arduino Sd2Card Library
+ */
+
+#include "SdFatConfig.h"
+#include "SdVolume.h"
+
+#include <stdint.h>
+
+/**
+ * \struct filepos_t
+ * \brief internal type for istream
+ * do not use in user apps
+ */
+struct filepos_t {
+ uint32_t position; // stream byte position
+ uint32_t cluster; // cluster of position
+ filepos_t() : position(0), cluster(0) {}
+};
+
+// use the gnu style oflag in open()
+uint8_t const O_READ = 0x01, // open() oflag for reading
+ O_RDONLY = O_READ, // open() oflag - same as O_IN
+ O_WRITE = 0x02, // open() oflag for write
+ O_WRONLY = O_WRITE, // open() oflag - same as O_WRITE
+ O_RDWR = (O_READ | O_WRITE), // open() oflag for reading and writing
+ O_ACCMODE = (O_READ | O_WRITE), // open() oflag mask for access modes
+ O_APPEND = 0x04, // The file offset shall be set to the end of the file prior to each write.
+ O_SYNC = 0x08, // Synchronous writes - call sync() after each write
+ O_TRUNC = 0x10, // Truncate the file to zero length
+ O_AT_END = 0x20, // Set the initial position at the end of the file
+ O_CREAT = 0x40, // Create the file if nonexistent
+ O_EXCL = 0x80; // If O_CREAT and O_EXCL are set, open() shall fail if the file exists
+
+// SdBaseFile class static and const definitions
+
+// flags for ls()
+uint8_t const LS_DATE = 1, // ls() flag to print modify date
+ LS_SIZE = 2, // ls() flag to print file size
+ LS_R = 4; // ls() flag for recursive list of subdirectories
+
+
+// flags for timestamp
+uint8_t const T_ACCESS = 1, // Set the file's last access date
+ T_CREATE = 2, // Set the file's creation date and time
+ T_WRITE = 4; // Set the file's write date and time
+
+// values for type_
+uint8_t const FAT_FILE_TYPE_CLOSED = 0, // This file has not been opened.
+ FAT_FILE_TYPE_NORMAL = 1, // A normal file
+ FAT_FILE_TYPE_ROOT_FIXED = 2, // A FAT12 or FAT16 root directory
+ FAT_FILE_TYPE_ROOT32 = 3, // A FAT32 root directory
+ FAT_FILE_TYPE_SUBDIR = 4, // A subdirectory file
+ FAT_FILE_TYPE_MIN_DIR = FAT_FILE_TYPE_ROOT_FIXED; // Test value for directory type
+
+/**
+ * date field for FAT directory entry
+ * \param[in] year [1980,2107]
+ * \param[in] month [1,12]
+ * \param[in] day [1,31]
+ *
+ * \return Packed date for dir_t entry.
+ */
+static inline uint16_t FAT_DATE(uint16_t year, uint8_t month, uint8_t day) { return (year - 1980) << 9 | month << 5 | day; }
+
+/**
+ * year part of FAT directory date field
+ * \param[in] fatDate Date in packed dir format.
+ *
+ * \return Extracted year [1980,2107]
+ */
+static inline uint16_t FAT_YEAR(uint16_t fatDate) { return 1980 + (fatDate >> 9); }
+
+/**
+ * month part of FAT directory date field
+ * \param[in] fatDate Date in packed dir format.
+ *
+ * \return Extracted month [1,12]
+ */
+static inline uint8_t FAT_MONTH(uint16_t fatDate) { return (fatDate >> 5) & 0xF; }
+
+/**
+ * day part of FAT directory date field
+ * \param[in] fatDate Date in packed dir format.
+ *
+ * \return Extracted day [1,31]
+ */
+static inline uint8_t FAT_DAY(uint16_t fatDate) { return fatDate & 0x1F; }
+
+/**
+ * time field for FAT directory entry
+ * \param[in] hour [0,23]
+ * \param[in] minute [0,59]
+ * \param[in] second [0,59]
+ *
+ * \return Packed time for dir_t entry.
+ */
+static inline uint16_t FAT_TIME(uint8_t hour, uint8_t minute, uint8_t second) { return hour << 11 | minute << 5 | second >> 1; }
+
+/**
+ * hour part of FAT directory time field
+ * \param[in] fatTime Time in packed dir format.
+ *
+ * \return Extracted hour [0,23]
+ */
+static inline uint8_t FAT_HOUR(uint16_t fatTime) { return fatTime >> 11; }
+
+/**
+ * minute part of FAT directory time field
+ * \param[in] fatTime Time in packed dir format.
+ *
+ * \return Extracted minute [0,59]
+ */
+static inline uint8_t FAT_MINUTE(uint16_t fatTime) { return (fatTime >> 5) & 0x3F; }
+
+/**
+ * second part of FAT directory time field
+ * Note second/2 is stored in packed time.
+ *
+ * \param[in] fatTime Time in packed dir format.
+ *
+ * \return Extracted second [0,58]
+ */
+static inline uint8_t FAT_SECOND(uint16_t fatTime) { return 2 * (fatTime & 0x1F); }
+
+// Default date for file timestamps is 1 Jan 2000
+uint16_t const FAT_DEFAULT_DATE = ((2000 - 1980) << 9) | (1 << 5) | 1;
+// Default time for file timestamp is 1 am
+uint16_t const FAT_DEFAULT_TIME = (1 << 11);
+
+/**
+ * \class SdBaseFile
+ * \brief Base class for SdFile with Print and C++ streams.
+ */
+class SdBaseFile {
+ public:
+ SdBaseFile() : writeError(false), type_(FAT_FILE_TYPE_CLOSED) {}
+ SdBaseFile(const char* path, uint8_t oflag);
+ ~SdBaseFile() { if (isOpen()) close(); }
+
+ /**
+ * writeError is set to true if an error occurs during a write().
+ * Set writeError to false before calling print() and/or write() and check
+ * for true after calls to print() and/or write().
+ */
+ bool writeError;
+
+ // helpers for stream classes
+
+ /**
+ * get position for streams
+ * \param[out] pos struct to receive position
+ */
+ void getpos(filepos_t* pos);
+
+ /**
+ * set position for streams
+ * \param[out] pos struct with value for new position
+ */
+ void setpos(filepos_t* pos);
+
+ bool close();
+ bool contiguousRange(uint32_t* bgnBlock, uint32_t* endBlock);
+ bool createContiguous(SdBaseFile* dirFile,
+ const char* path, uint32_t size);
+ /**
+ * \return The current cluster number for a file or directory.
+ */
+ uint32_t curCluster() const { return curCluster_; }
+
+ /**
+ * \return The current position for a file or directory.
+ */
+ uint32_t curPosition() const { return curPosition_; }
+
+ /**
+ * \return Current working directory
+ */
+ static SdBaseFile* cwd() { return cwd_; }
+
+ /**
+ * Set the date/time callback function
+ *
+ * \param[in] dateTime The user's call back function. The callback
+ * function is of the form:
+ *
+ * \code
+ * void dateTime(uint16_t* date, uint16_t* time) {
+ * uint16_t year;
+ * uint8_t month, day, hour, minute, second;
+ *
+ * // User gets date and time from GPS or real-time clock here
+ *
+ * // return date using FAT_DATE macro to format fields
+ * *date = FAT_DATE(year, month, day);
+ *
+ * // return time using FAT_TIME macro to format fields
+ * *time = FAT_TIME(hour, minute, second);
+ * }
+ * \endcode
+ *
+ * Sets the function that is called when a file is created or when
+ * a file's directory entry is modified by sync(). All timestamps,
+ * access, creation, and modify, are set when a file is created.
+ * sync() maintains the last access date and last modify date/time.
+ *
+ * See the timestamp() function.
+ */
+ static void dateTimeCallback(
+ void (*dateTime)(uint16_t* date, uint16_t* time)) {
+ dateTime_ = dateTime;
+ }
+
+ /**
+ * Cancel the date/time callback function.
+ */
+ static void dateTimeCallbackCancel() { dateTime_ = 0; }
+ bool dirEntry(dir_t* dir);
+ static void dirName(const dir_t& dir, char* name);
+ bool exists(const char* name);
+ int16_t fgets(char* str, int16_t num, char* delim = 0);
+
+ /**
+ * \return The total number of bytes in a file or directory.
+ */
+ uint32_t fileSize() const { return fileSize_; }
+
+ /**
+ * \return The first cluster number for a file or directory.
+ */
+ uint32_t firstCluster() const { return firstCluster_; }
+
+ /**
+ * \return True if this is a directory else false.
+ */
+ bool isDir() const { return type_ >= FAT_FILE_TYPE_MIN_DIR; }
+
+ /**
+ * \return True if this is a normal file else false.
+ */
+ bool isFile() const { return type_ == FAT_FILE_TYPE_NORMAL; }
+
+ /**
+ * \return True if this is an open file/directory else false.
+ */
+ bool isOpen() const { return type_ != FAT_FILE_TYPE_CLOSED; }
+
+ /**
+ * \return True if this is a subdirectory else false.
+ */
+ bool isSubDir() const { return type_ == FAT_FILE_TYPE_SUBDIR; }
+
+ /**
+ * \return True if this is the root directory.
+ */
+ bool isRoot() const { return type_ == FAT_FILE_TYPE_ROOT_FIXED || type_ == FAT_FILE_TYPE_ROOT32; }
+
+ bool getDosName(char * const name);
+ void ls(uint8_t flags = 0, uint8_t indent = 0);
+
+ bool mkdir(SdBaseFile* dir, const char* path, bool pFlag = true);
+ bool open(SdBaseFile* dirFile, uint16_t index, uint8_t oflag);
+ bool open(SdBaseFile* dirFile, const char* path, uint8_t oflag);
+ bool open(const char* path, uint8_t oflag = O_READ);
+ bool openNext(SdBaseFile* dirFile, uint8_t oflag);
+ bool openRoot(SdVolume* vol);
+ int peek();
+ static void printFatDate(uint16_t fatDate);
+ static void printFatTime(uint16_t fatTime);
+ bool printName();
+ int16_t read();
+ int16_t read(void* buf, uint16_t nbyte);
+ int8_t readDir(dir_t* dir, char* longFilename);
+ static bool remove(SdBaseFile* dirFile, const char* path);
+ bool remove();
+
+ /**
+ * Set the file's current position to zero.
+ */
+ void rewind() { seekSet(0); }
+ bool rename(SdBaseFile* dirFile, const char* newPath);
+ bool rmdir();
+ bool rmRfStar();
+
+ /**
+ * Set the files position to current position + \a pos. See seekSet().
+ * \param[in] offset The new position in bytes from the current position.
+ * \return true for success or false for failure.
+ */
+ bool seekCur(const int32_t offset) { return seekSet(curPosition_ + offset); }
+
+ /**
+ * Set the files position to end-of-file + \a offset. See seekSet().
+ * \param[in] offset The new position in bytes from end-of-file.
+ * \return true for success or false for failure.
+ */
+ bool seekEnd(const int32_t offset = 0) { return seekSet(fileSize_ + offset); }
+ bool seekSet(const uint32_t pos);
+ bool sync();
+ bool timestamp(SdBaseFile* file);
+ bool timestamp(uint8_t flag, uint16_t year, uint8_t month, uint8_t day,
+ uint8_t hour, uint8_t minute, uint8_t second);
+
+ /**
+ * Type of file. Use isFile() or isDir() instead of type() if possible.
+ *
+ * \return The file or directory type.
+ */
+ uint8_t type() const { return type_; }
+ bool truncate(uint32_t size);
+
+ /**
+ * \return SdVolume that contains this file.
+ */
+ SdVolume* volume() const { return vol_; }
+ int16_t write(const void* buf, uint16_t nbyte);
+
+ private:
+ friend class SdFat; // allow SdFat to set cwd_
+ static SdBaseFile* cwd_; // global pointer to cwd dir
+
+ // data time callback function
+ static void (*dateTime_)(uint16_t* date, uint16_t* time);
+
+ // bits defined in flags_
+ static uint8_t const F_OFLAG = (O_ACCMODE | O_APPEND | O_SYNC), // should be 0x0F
+ F_FILE_DIR_DIRTY = 0x80; // sync of directory entry required
+
+ // private data
+ uint8_t flags_; // See above for definition of flags_ bits
+ uint8_t fstate_; // error and eof indicator
+ uint8_t type_; // type of file see above for values
+ uint32_t curCluster_; // cluster for current file position
+ uint32_t curPosition_; // current file position in bytes from beginning
+ uint32_t dirBlock_; // block for this files directory entry
+ uint8_t dirIndex_; // index of directory entry in dirBlock
+ uint32_t fileSize_; // file size in bytes
+ uint32_t firstCluster_; // first cluster of file
+ SdVolume* vol_; // volume where file is located
+
+ /**
+ * EXPERIMENTAL - Don't use!
+ */
+ //bool openParent(SdBaseFile* dir);
+
+ // private functions
+ bool addCluster();
+ bool addDirCluster();
+ dir_t* cacheDirEntry(uint8_t action);
+ int8_t lsPrintNext(uint8_t flags, uint8_t indent);
+ static bool make83Name(const char* str, uint8_t* name, const char** ptr);
+ bool mkdir(SdBaseFile* parent, const uint8_t dname[11]);
+ bool open(SdBaseFile* dirFile, const uint8_t dname[11], uint8_t oflag);
+ bool openCachedEntry(uint8_t cacheIndex, uint8_t oflags);
+ dir_t* readDirCache();
+};
diff --git a/Marlin/src/sd/SdFatConfig.h b/Marlin/src/sd/SdFatConfig.h
new file mode 100644
index 0000000..13ac3a7
--- /dev/null
+++ b/Marlin/src/sd/SdFatConfig.h
@@ -0,0 +1,112 @@
+/**
+ * Marlin 3D Printer Firmware
+ * Copyright (c) 2020 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 <https://www.gnu.org/licenses/>.
+ *
+ */
+#pragma once
+
+/**
+ * sd/SdFatConfig.h
+ *
+ * Arduino SdFat Library
+ * Copyright (c) 2009 by William Greiman
+ *
+ * This file is part of the Arduino Sd2Card Library
+ */
+
+#include "../inc/MarlinConfig.h"
+
+/**
+ * To use multiple SD cards set USE_MULTIPLE_CARDS nonzero.
+ *
+ * Using multiple cards costs 400 - 500 bytes of flash.
+ *
+ * Each card requires about 550 bytes of SRAM so use of a Mega is recommended.
+ */
+#define USE_MULTIPLE_CARDS 0
+
+/**
+ * Call flush for endl if ENDL_CALLS_FLUSH is nonzero
+ *
+ * The standard for iostreams is to call flush. This is very costly for
+ * SdFat. Each call to flush causes 2048 bytes of I/O to the SD.
+ *
+ * SdFat has a single 512 byte buffer for SD I/O so it must write the current
+ * data block to the SD, read the directory block from the SD, update the
+ * directory entry, write the directory block to the SD and read the data
+ * block back into the buffer.
+ *
+ * The SD flash memory controller is not designed for this many rewrites
+ * so performance may be reduced by more than a factor of 100.
+ *
+ * If ENDL_CALLS_FLUSH is zero, you must call flush and/or close to force
+ * all data to be written to the SD.
+ */
+#define ENDL_CALLS_FLUSH 0
+
+/**
+ * Allow FAT12 volumes if FAT12_SUPPORT is nonzero.
+ * FAT12 has not been well tested.
+ */
+#define FAT12_SUPPORT 0
+
+/**
+ * SPI init rate for SD initialization commands. Must be 5 (F_CPU/64)
+ * or 6 (F_CPU/128).
+ */
+#define SPI_SD_INIT_RATE 5
+
+/**
+ * Set the SS pin high for hardware SPI. If SS is chip select for another SPI
+ * device this will disable that device during the SD init phase.
+ */
+#define SET_SPI_SS_HIGH 1
+
+/**
+ * Define MEGA_SOFT_SPI nonzero to use software SPI on Mega Arduinos.
+ * Pins used are SS 10, MOSI 11, MISO 12, and SCK 13.
+ *
+ * MEGA_SOFT_SPI allows an unmodified Adafruit GPS Shield to be used
+ * on Mega Arduinos. Software SPI works well with GPS Shield V1.1
+ * but many SD cards will fail with GPS Shield V1.0.
+ */
+#define MEGA_SOFT_SPI 0
+
+// Set USE_SOFTWARE_SPI nonzero to ALWAYS use Software SPI.
+#define USE_SOFTWARE_SPI 0
+
+/**
+ * The __cxa_pure_virtual function is an error handler that is invoked when
+ * a pure virtual function is called.
+ */
+#define USE_CXA_PURE_VIRTUAL 1
+
+/**
+ * Defines for 8.3 and long (vfat) filenames
+ */
+
+#define FILENAME_LENGTH 13 // Number of UTF-16 characters per entry
+
+// UTF-8 may use up to 3 bytes to represent single UTF-16 code point.
+// We discard 3-byte characters allowing only 2-bytes
+// or 1-byte if UTF_FILENAME_SUPPORT disabled.
+#define LONG_FILENAME_CHARSIZE TERN(UTF_FILENAME_SUPPORT, 2, 1)
+
+// Total bytes needed to store a single long filename
+#define LONG_FILENAME_LENGTH (FILENAME_LENGTH * LONG_FILENAME_CHARSIZE * MAX_VFAT_ENTRIES + 1)
diff --git a/Marlin/src/sd/SdFatStructs.h b/Marlin/src/sd/SdFatStructs.h
new file mode 100644
index 0000000..ac81f1d
--- /dev/null
+++ b/Marlin/src/sd/SdFatStructs.h
@@ -0,0 +1,609 @@
+/**
+ * Marlin 3D Printer Firmware
+ * Copyright (c) 2020 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 <https://www.gnu.org/licenses/>.
+ *
+ */
+#pragma once
+
+/**
+ * sd/SdFatStructs.h
+ *
+ * Arduino SdFat Library
+ * Copyright (c) 2009 by William Greiman
+ *
+ * This file is part of the Arduino Sd2Card Library
+ */
+
+#include <stdint.h>
+
+#define PACKED __attribute__((__packed__))
+
+/**
+ * mostly from Microsoft document fatgen103.doc
+ * https://www.microsoft.com/whdc/system/platform/firmware/fatgen.mspx
+ */
+
+uint8_t const BOOTSIG0 = 0x55, // Value for byte 510 of boot block or MBR
+ BOOTSIG1 = 0xAA, // Value for byte 511 of boot block or MBR
+ EXTENDED_BOOT_SIG = 0x29; // Value for bootSignature field int FAT/FAT32 boot sector
+
+/**
+ * \struct partitionTable
+ * \brief MBR partition table entry
+ *
+ * A partition table entry for a MBR formatted storage device.
+ * The MBR partition table has four entries.
+ */
+struct partitionTable {
+ /**
+ * Boot Indicator . Indicates whether the volume is the active
+ * partition. Legal values include: 0x00. Do not use for booting.
+ * 0x80 Active partition.
+ */
+ uint8_t boot;
+ /**
+ * Head part of Cylinder-head-sector address of the first block in
+ * the partition. Legal values are 0-255. Only used in old PC BIOS.
+ */
+ uint8_t beginHead;
+ /**
+ * Sector part of Cylinder-head-sector address of the first block in
+ * the partition. Legal values are 1-63. Only used in old PC BIOS.
+ */
+ unsigned beginSector : 6;
+ /** High bits cylinder for first block in partition. */
+ unsigned beginCylinderHigh : 2;
+ /**
+ * Combine beginCylinderLow with beginCylinderHigh. Legal values
+ * are 0-1023. Only used in old PC BIOS.
+ */
+ uint8_t beginCylinderLow;
+ /**
+ * Partition type. See defines that begin with PART_TYPE_ for
+ * some Microsoft partition types.
+ */
+ uint8_t type;
+ /**
+ * head part of cylinder-head-sector address of the last sector in the
+ * partition. Legal values are 0-255. Only used in old PC BIOS.
+ */
+ uint8_t endHead;
+ /**
+ * Sector part of cylinder-head-sector address of the last sector in
+ * the partition. Legal values are 1-63. Only used in old PC BIOS.
+ */
+ unsigned endSector : 6;
+ /** High bits of end cylinder */
+ unsigned endCylinderHigh : 2;
+ /**
+ * Combine endCylinderLow with endCylinderHigh. Legal values
+ * are 0-1023. Only used in old PC BIOS.
+ */
+ uint8_t endCylinderLow;
+
+ uint32_t firstSector; // Logical block address of the first block in the partition.
+ uint32_t totalSectors; // Length of the partition, in blocks.
+} PACKED;
+
+typedef struct partitionTable part_t; // Type name for partitionTable
+
+/**
+ * \struct masterBootRecord
+ *
+ * \brief Master Boot Record
+ *
+ * The first block of a storage device that is formatted with a MBR.
+ */
+struct masterBootRecord {
+ uint8_t codeArea[440]; // Code Area for master boot program.
+ uint32_t diskSignature; // Optional Windows NT disk signature. May contain boot code.
+ uint16_t usuallyZero; // Usually zero but may be more boot code.
+ part_t part[4]; // Partition tables.
+ uint8_t mbrSig0; // First MBR signature byte. Must be 0x55
+ uint8_t mbrSig1; // Second MBR signature byte. Must be 0xAA
+} PACKED;
+/** Type name for masterBootRecord */
+typedef struct masterBootRecord mbr_t;
+
+/**
+ * \struct fat_boot
+ *
+ * \brief Boot sector for a FAT12/FAT16 volume.
+ */
+struct fat_boot {
+ /**
+ * The first three bytes of the boot sector must be valid,
+ * executable x 86-based CPU instructions. This includes a
+ * jump instruction that skips the next nonexecutable bytes.
+ */
+ uint8_t jump[3];
+ /**
+ * This is typically a string of characters that identifies
+ * the operating system that formatted the volume.
+ */
+ char oemId[8];
+ /**
+ * The size of a hardware sector. Valid decimal values for this
+ * field are 512, 1024, 2048, and 4096. For most disks used in
+ * the United States, the value of this field is 512.
+ */
+ uint16_t bytesPerSector;
+ /**
+ * Number of sectors per allocation unit. This value must be a
+ * power of 2 that is greater than 0. The legal values are
+ * 1, 2, 4, 8, 16, 32, 64, and 128. 128 should be avoided.
+ */
+ uint8_t sectorsPerCluster;
+ /**
+ * The number of sectors preceding the start of the first FAT,
+ * including the boot sector. The value of this field is always 1.
+ */
+ uint16_t reservedSectorCount;
+ /**
+ * The number of copies of the FAT on the volume.
+ * The value of this field is always 2.
+ */
+ uint8_t fatCount;
+ /**
+ * For FAT12 and FAT16 volumes, this field contains the count of
+ * 32-byte directory entries in the root directory. For FAT32 volumes,
+ * this field must be set to 0. For FAT12 and FAT16 volumes, this
+ * value should always specify a count that when multiplied by 32
+ * results in a multiple of bytesPerSector. FAT16 volumes should
+ * use the value 512.
+ */
+ uint16_t rootDirEntryCount;
+ /**
+ * This field is the old 16-bit total count of sectors on the volume.
+ * This count includes the count of all sectors in all four regions
+ * of the volume. This field can be 0; if it is 0, then totalSectors32
+ * must be nonzero. For FAT32 volumes, this field must be 0. For
+ * FAT12 and FAT16 volumes, this field contains the sector count, and
+ * totalSectors32 is 0 if the total sector count fits
+ * (is less than 0x10000).
+ */
+ uint16_t totalSectors16;
+ /**
+ * This dates back to the old MS-DOS 1.x media determination and is
+ * no longer usually used for anything. 0xF8 is the standard value
+ * for fixed (nonremovable) media. For removable media, 0xF0 is
+ * frequently used. Legal values are 0xF0 or 0xF8-0xFF.
+ */
+ uint8_t mediaType;
+ /**
+ * Count of sectors occupied by one FAT on FAT12/FAT16 volumes.
+ * On FAT32 volumes this field must be 0, and sectorsPerFat32
+ * contains the FAT size count.
+ */
+ uint16_t sectorsPerFat16;
+
+ uint16_t sectorsPerTrack; // Sectors per track for interrupt 0x13. Not used otherwise.
+ uint16_t headCount; // Number of heads for interrupt 0x13. Not used otherwise.
+
+ /**
+ * Count of hidden sectors preceding the partition that contains this
+ * FAT volume. This field is generally only relevant for media
+ * visible on interrupt 0x13.
+ */
+ uint32_t hidddenSectors;
+ /**
+ * This field is the new 32-bit total count of sectors on the volume.
+ * This count includes the count of all sectors in all four regions
+ * of the volume. This field can be 0; if it is 0, then
+ * totalSectors16 must be nonzero.
+ */
+ uint32_t totalSectors32;
+ /**
+ * Related to the BIOS physical drive number. Floppy drives are
+ * identified as 0x00 and physical hard disks are identified as
+ * 0x80, regardless of the number of physical disk drives.
+ * Typically, this value is set prior to issuing an INT 13h BIOS
+ * call to specify the device to access. The value is only
+ * relevant if the device is a boot device.
+ */
+ uint8_t driveNumber;
+
+ uint8_t reserved1; // used by Windows NT - should be zero for FAT
+ uint8_t bootSignature; // 0x29 if next three fields are valid
+
+ /**
+ * A random serial number created when formatting a disk,
+ * which helps to distinguish between disks.
+ * Usually generated by combining date and time.
+ */
+ uint32_t volumeSerialNumber;
+ /**
+ * A field once used to store the volume label. The volume label
+ * is now stored as a special file in the root directory.
+ */
+ char volumeLabel[11];
+ /**
+ * A field with a value of either FAT, FAT12 or FAT16,
+ * depending on the disk format.
+ */
+ char fileSystemType[8];
+
+ uint8_t bootCode[448]; // X86 boot code
+ uint8_t bootSectorSig0; // must be 0x55
+ uint8_t bootSectorSig1; // must be 0xAA
+} PACKED;
+
+typedef struct fat_boot fat_boot_t; // Type name for FAT Boot Sector
+
+/**
+ * \struct fat32_boot
+ *
+ * \brief Boot sector for a FAT32 volume.
+ */
+struct fat32_boot {
+ /**
+ * The first three bytes of the boot sector must be valid,
+ * executable x 86-based CPU instructions. This includes a
+ * jump instruction that skips the next nonexecutable bytes.
+ */
+ uint8_t jump[3];
+ /**
+ * This is typically a string of characters that identifies
+ * the operating system that formatted the volume.
+ */
+ char oemId[8];
+ /**
+ * The size of a hardware sector. Valid decimal values for this
+ * field are 512, 1024, 2048, and 4096. For most disks used in
+ * the United States, the value of this field is 512.
+ */
+ uint16_t bytesPerSector;
+ /**
+ * Number of sectors per allocation unit. This value must be a
+ * power of 2 that is greater than 0. The legal values are
+ * 1, 2, 4, 8, 16, 32, 64, and 128. 128 should be avoided.
+ */
+ uint8_t sectorsPerCluster;
+ /**
+ * The number of sectors preceding the start of the first FAT,
+ * including the boot sector. Must not be zero
+ */
+ uint16_t reservedSectorCount;
+ /**
+ * The number of copies of the FAT on the volume.
+ * The value of this field is always 2.
+ */
+ uint8_t fatCount;
+ /**
+ * FAT12/FAT16 only. For FAT32 volumes, this field must be set to 0.
+ */
+ uint16_t rootDirEntryCount;
+ /**
+ * For FAT32 volumes, this field must be 0.
+ */
+ uint16_t totalSectors16;
+ /**
+ * This dates back to the old MS-DOS 1.x media determination and is
+ * no longer usually used for anything. 0xF8 is the standard value
+ * for fixed (nonremovable) media. For removable media, 0xF0 is
+ * frequently used. Legal values are 0xF0 or 0xF8-0xFF.
+ */
+ uint8_t mediaType;
+ /**
+ * On FAT32 volumes this field must be 0, and sectorsPerFat32
+ * contains the FAT size count.
+ */
+ uint16_t sectorsPerFat16;
+
+ uint16_t sectorsPerTrack; // Sectors per track for interrupt 0x13. Not used otherwise.
+ uint16_t headCount; // Number of heads for interrupt 0x13. Not used otherwise.
+
+ /**
+ * Count of hidden sectors preceding the partition that contains this
+ * FAT volume. This field is generally only relevant for media
+ * visible on interrupt 0x13.
+ */
+ uint32_t hidddenSectors;
+ /**
+ * Contains the total number of sectors in the FAT32 volume.
+ */
+ uint32_t totalSectors32;
+ /**
+ * Count of sectors occupied by one FAT on FAT32 volumes.
+ */
+ uint32_t sectorsPerFat32;
+ /**
+ * This field is only defined for FAT32 media and does not exist on
+ * FAT12 and FAT16 media.
+ * Bits 0-3 -- Zero-based number of active FAT.
+ * Only valid if mirroring is disabled.
+ * Bits 4-6 -- Reserved.
+ * Bit 7 -- 0 means the FAT is mirrored at runtime into all FATs.
+ * -- 1 means only one FAT is active; it is the one referenced
+ * in bits 0-3.
+ * Bits 8-15 -- Reserved.
+ */
+ uint16_t fat32Flags;
+ /**
+ * FAT32 version. High byte is major revision number.
+ * Low byte is minor revision number. Only 0.0 define.
+ */
+ uint16_t fat32Version;
+ /**
+ * Cluster number of the first cluster of the root directory for FAT32.
+ * This usually 2 but not required to be 2.
+ */
+ uint32_t fat32RootCluster;
+ /**
+ * Sector number of FSINFO structure in the reserved area of the
+ * FAT32 volume. Usually 1.
+ */
+ uint16_t fat32FSInfo;
+ /**
+ * If nonzero, indicates the sector number in the reserved area
+ * of the volume of a copy of the boot record. Usually 6.
+ * No value other than 6 is recommended.
+ */
+ uint16_t fat32BackBootBlock;
+ /**
+ * Reserved for future expansion. Code that formats FAT32 volumes
+ * should always set all of the bytes of this field to 0.
+ */
+ uint8_t fat32Reserved[12];
+ /**
+ * Related to the BIOS physical drive number. Floppy drives are
+ * identified as 0x00 and physical hard disks are identified as
+ * 0x80, regardless of the number of physical disk drives.
+ * Typically, this value is set prior to issuing an INT 13h BIOS
+ * call to specify the device to access. The value is only
+ * relevant if the device is a boot device.
+ */
+ uint8_t driveNumber;
+
+ uint8_t reserved1; // Used by Windows NT - should be zero for FAT
+ uint8_t bootSignature; // 0x29 if next three fields are valid
+
+ /**
+ * A random serial number created when formatting a disk,
+ * which helps to distinguish between disks.
+ * Usually generated by combining date and time.
+ */
+ uint32_t volumeSerialNumber;
+ /**
+ * A field once used to store the volume label. The volume label
+ * is now stored as a special file in the root directory.
+ */
+ char volumeLabel[11];
+ /**
+ * A text field with a value of FAT32.
+ */
+ char fileSystemType[8];
+
+ uint8_t bootCode[420]; // X86 boot code
+ uint8_t bootSectorSig0; // must be 0x55
+ uint8_t bootSectorSig1; // must be 0xAA
+
+} PACKED;
+
+typedef struct fat32_boot fat32_boot_t; // Type name for FAT32 Boot Sector
+
+uint32_t const FSINFO_LEAD_SIG = 0x41615252, // 'AaRR' Lead signature for a FSINFO sector
+ FSINFO_STRUCT_SIG = 0x61417272; // 'aArr' Struct signature for a FSINFO sector
+
+/**
+ * \struct fat32_fsinfo
+ *
+ * \brief FSINFO sector for a FAT32 volume.
+ */
+struct fat32_fsinfo {
+ uint32_t leadSignature; // must be 0x52, 0x52, 0x61, 0x41 'RRaA'
+ uint8_t reserved1[480]; // must be zero
+ uint32_t structSignature; // must be 0x72, 0x72, 0x41, 0x61 'rrAa'
+ /**
+ * Contains the last known free cluster count on the volume.
+ * If the value is 0xFFFFFFFF, then the free count is unknown
+ * and must be computed. Any other value can be used, but is
+ * not necessarily correct. It should be range checked at least
+ * to make sure it is <= volume cluster count.
+ */
+ uint32_t freeCount;
+ /**
+ * This is a hint for the FAT driver. It indicates the cluster
+ * number at which the driver should start looking for free clusters.
+ * If the value is 0xFFFFFFFF, then there is no hint and the driver
+ * should start looking at cluster 2.
+ */
+ uint32_t nextFree;
+
+ uint8_t reserved2[12]; // must be zero
+ uint8_t tailSignature[4]; // must be 0x00, 0x00, 0x55, 0xAA
+} PACKED;
+
+typedef struct fat32_fsinfo fat32_fsinfo_t; // Type name for FAT32 FSINFO Sector
+
+// End Of Chain values for FAT entries
+uint16_t const FAT12EOC = 0xFFF, // FAT12 end of chain value used by Microsoft.
+ FAT12EOC_MIN = 0xFF8, // Minimum value for FAT12 EOC. Use to test for EOC.
+ FAT16EOC = 0xFFFF, // FAT16 end of chain value used by Microsoft.
+ FAT16EOC_MIN = 0xFFF8; // Minimum value for FAT16 EOC. Use to test for EOC.
+uint32_t const FAT32EOC = 0x0FFFFFFF, // FAT32 end of chain value used by Microsoft.
+ FAT32EOC_MIN = 0x0FFFFFF8, // Minimum value for FAT32 EOC. Use to test for EOC.
+ FAT32MASK = 0x0FFFFFFF; // Mask a for FAT32 entry. Entries are 28 bits.
+
+/**
+ * \struct directoryEntry
+ * \brief FAT short directory entry
+ *
+ * Short means short 8.3 name, not the entry size.
+ *
+ * Date Format. A FAT directory entry date stamp is a 16-bit field that is
+ * basically a date relative to the MS-DOS epoch of 01/01/1980. Here is the
+ * format (bit 0 is the LSB of the 16-bit word, bit 15 is the MSB of the
+ * 16-bit word):
+ *
+ * Bits 9-15: Count of years from 1980, valid value range 0-127
+ * inclusive (1980-2107).
+ *
+ * Bits 5-8: Month of year, 1 = January, valid value range 1-12 inclusive.
+ *
+ * Bits 0-4: Day of month, valid value range 1-31 inclusive.
+ *
+ * Time Format. A FAT directory entry time stamp is a 16-bit field that has
+ * a granularity of 2 seconds. Here is the format (bit 0 is the LSB of the
+ * 16-bit word, bit 15 is the MSB of the 16-bit word).
+ *
+ * Bits 11-15: Hours, valid value range 0-23 inclusive.
+ *
+ * Bits 5-10: Minutes, valid value range 0-59 inclusive.
+ *
+ * Bits 0-4: 2-second count, valid value range 0-29 inclusive (0 - 58 seconds).
+ *
+ * The valid time range is from Midnight 00:00:00 to 23:59:58.
+ */
+struct directoryEntry {
+ /**
+ * Short 8.3 name.
+ *
+ * The first eight bytes contain the file name with blank fill.
+ * The last three bytes contain the file extension with blank fill.
+ */
+ uint8_t name[11];
+ /**
+ * Entry attributes.
+ *
+ * The upper two bits of the attribute byte are reserved and should
+ * always be set to 0 when a file is created and never modified or
+ * looked at after that. See defines that begin with DIR_ATT_.
+ */
+ uint8_t attributes;
+ /**
+ * Reserved for use by Windows NT. Set value to 0 when a file is
+ * created and never modify or look at it after that.
+ */
+ uint8_t reservedNT;
+ /**
+ * The granularity of the seconds part of creationTime is 2 seconds
+ * so this field is a count of tenths of a second and it's valid
+ * value range is 0-199 inclusive. (WHG note - seems to be hundredths)
+ */
+ uint8_t creationTimeTenths;
+
+ uint16_t creationTime; // Time file was created.
+ uint16_t creationDate; // Date file was created.
+
+ /**
+ * Last access date. Note that there is no last access time, only
+ * a date. This is the date of last read or write. In the case of
+ * a write, this should be set to the same date as lastWriteDate.
+ */
+ uint16_t lastAccessDate;
+ /**
+ * High word of this entry's first cluster number (always 0 for a
+ * FAT12 or FAT16 volume).
+ */
+ uint16_t firstClusterHigh;
+
+ uint16_t lastWriteTime; // Time of last write. File creation is considered a write.
+ uint16_t lastWriteDate; // Date of last write. File creation is considered a write.
+ uint16_t firstClusterLow; // Low word of this entry's first cluster number.
+ uint32_t fileSize; // 32-bit unsigned holding this file's size in bytes.
+} PACKED;
+
+/**
+ * \struct directoryVFATEntry
+ * \brief VFAT long filename directory entry
+ *
+ * directoryVFATEntries are found in the same list as normal directoryEntry.
+ * But have the attribute field set to DIR_ATT_LONG_NAME.
+ *
+ * Long filenames are saved in multiple directoryVFATEntries.
+ * Each entry containing 13 UTF-16 characters.
+ */
+struct directoryVFATEntry {
+ /**
+ * Sequence number. Consists of 2 parts:
+ * bit 6: indicates first long filename block for the next file
+ * bit 0-4: the position of this long filename block (first block is 1)
+ */
+ uint8_t sequenceNumber;
+
+ uint16_t name1[5]; // First set of UTF-16 characters
+ uint8_t attributes; // attributes (at the same location as in directoryEntry), always 0x0F
+ uint8_t reservedNT; // Reserved for use by Windows NT. Always 0.
+ uint8_t checksum; // Checksum of the short 8.3 filename, can be used to checked if the file system as modified by a not-long-filename aware implementation.
+ uint16_t name2[6]; // Second set of UTF-16 characters
+ uint16_t firstClusterLow; // firstClusterLow is always zero for longFilenames
+ uint16_t name3[2]; // Third set of UTF-16 characters
+} PACKED;
+
+// Definitions for directory entries
+//
+typedef struct directoryEntry dir_t; // Type name for directoryEntry
+typedef struct directoryVFATEntry vfat_t; // Type name for directoryVFATEntry
+
+uint8_t const DIR_NAME_0xE5 = 0x05, // escape for name[0] = 0xE5
+ DIR_NAME_DELETED = 0xE5, // name[0] value for entry that is free after being "deleted"
+ DIR_NAME_FREE = 0x00, // name[0] value for entry that is free and no allocated entries follow
+ DIR_ATT_READ_ONLY = 0x01, // file is read-only
+ DIR_ATT_HIDDEN = 0x02, // File should hidden in directory listings
+ DIR_ATT_SYSTEM = 0x04, // Entry is for a system file
+ DIR_ATT_VOLUME_ID = 0x08, // Directory entry contains the volume label
+ DIR_ATT_DIRECTORY = 0x10, // Entry is for a directory
+ DIR_ATT_ARCHIVE = 0x20, // Old DOS archive bit for backup support
+ DIR_ATT_LONG_NAME = 0x0F, // Test value for long name entry. Test is (d->attributes & DIR_ATT_LONG_NAME_MASK) == DIR_ATT_LONG_NAME.
+ DIR_ATT_LONG_NAME_MASK = 0x3F, // Test mask for long name entry
+ DIR_ATT_DEFINED_BITS = 0x3F; // defined attribute bits
+
+/**
+ * Directory entry is part of a long name
+ * \param[in] dir Pointer to a directory entry.
+ *
+ * \return true if the entry is for part of a long name else false.
+ */
+static inline uint8_t DIR_IS_LONG_NAME(const dir_t* dir) {
+ return (dir->attributes & DIR_ATT_LONG_NAME_MASK) == DIR_ATT_LONG_NAME;
+}
+
+/** Mask for file/subdirectory tests */
+uint8_t const DIR_ATT_FILE_TYPE_MASK = (DIR_ATT_VOLUME_ID | DIR_ATT_DIRECTORY);
+
+/**
+ * Directory entry is for a file
+ * \param[in] dir Pointer to a directory entry.
+ *
+ * \return true if the entry is for a normal file else false.
+ */
+static inline uint8_t DIR_IS_FILE(const dir_t* dir) {
+ return (dir->attributes & DIR_ATT_FILE_TYPE_MASK) == 0;
+}
+
+/**
+ * Directory entry is for a subdirectory
+ * \param[in] dir Pointer to a directory entry.
+ *
+ * \return true if the entry is for a subdirectory else false.
+ */
+static inline uint8_t DIR_IS_SUBDIR(const dir_t* dir) {
+ return (dir->attributes & DIR_ATT_FILE_TYPE_MASK) == DIR_ATT_DIRECTORY;
+}
+
+/**
+ * Directory entry is for a file or subdirectory
+ * \param[in] dir Pointer to a directory entry.
+ *
+ * \return true if the entry is for a normal file or subdirectory else false.
+ */
+static inline uint8_t DIR_IS_FILE_OR_SUBDIR(const dir_t* dir) {
+ return (dir->attributes & DIR_ATT_VOLUME_ID) == 0;
+}
diff --git a/Marlin/src/sd/SdFatUtil.cpp b/Marlin/src/sd/SdFatUtil.cpp
new file mode 100644
index 0000000..7d9f33d
--- /dev/null
+++ b/Marlin/src/sd/SdFatUtil.cpp
@@ -0,0 +1,62 @@
+/**
+ * Marlin 3D Printer Firmware
+ * Copyright (c) 2020 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 <https://www.gnu.org/licenses/>.
+ *
+ */
+
+/**
+ * sd/SdFatUtil.cpp
+ *
+ * Arduino SdFat Library
+ * Copyright (c) 2008 by William Greiman
+ *
+ * This file is part of the Arduino Sd2Card Library
+ */
+
+#include "../inc/MarlinConfig.h"
+
+#if ENABLED(SDSUPPORT)
+
+#include "SdFatUtil.h"
+#include <string.h>
+
+/**
+ * Amount of free RAM
+ * \return The number of free bytes.
+ */
+#ifdef __arm__
+
+ extern "C" char* sbrk(int incr);
+ int SdFatUtil::FreeRam() {
+ char top;
+ return &top - reinterpret_cast<char*>(sbrk(0));
+ }
+
+#else
+
+ extern char* __brkval;
+ extern char __bss_end;
+ int SdFatUtil::FreeRam() {
+ char top;
+ return __brkval ? &top - __brkval : &top - &__bss_end;
+ }
+
+#endif
+
+#endif // SDSUPPORT
diff --git a/Marlin/src/sd/SdFatUtil.h b/Marlin/src/sd/SdFatUtil.h
new file mode 100644
index 0000000..f1bb657
--- /dev/null
+++ b/Marlin/src/sd/SdFatUtil.h
@@ -0,0 +1,42 @@
+/**
+ * Marlin 3D Printer Firmware
+ * Copyright (c) 2020 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 <https://www.gnu.org/licenses/>.
+ *
+ */
+#pragma once
+
+/**
+ * sd/SdFatUtil.h
+ *
+ * Arduino SdFat Library
+ * Copyright (c) 2008 by William Greiman
+ *
+ * This file is part of the Arduino Sd2Card Library
+ */
+
+/**
+ * \file
+ * \brief Useful utility functions.
+ */
+
+namespace SdFatUtil {
+ int FreeRam();
+}
+
+using namespace SdFatUtil; // NOLINT
diff --git a/Marlin/src/sd/SdFile.cpp b/Marlin/src/sd/SdFile.cpp
new file mode 100644
index 0000000..cba67e2
--- /dev/null
+++ b/Marlin/src/sd/SdFile.cpp
@@ -0,0 +1,102 @@
+/**
+ * Marlin 3D Printer Firmware
+ * Copyright (c) 2020 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 <https://www.gnu.org/licenses/>.
+ *
+ */
+
+/**
+ * sd/SdFile.cpp
+ *
+ * Arduino SdFat Library
+ * Copyright (c) 2009 by William Greiman
+ *
+ * This file is part of the Arduino Sd2Card Library
+ */
+
+#include "../inc/MarlinConfig.h"
+
+#if ENABLED(SDSUPPORT)
+
+#include "SdFile.h"
+
+/**
+ * Create a file object and open it in the current working directory.
+ *
+ * \param[in] path A path with a valid 8.3 DOS name for a file to be opened.
+ *
+ * \param[in] oflag Values for \a oflag are constructed by a bitwise-inclusive
+ * OR of open flags. see SdBaseFile::open(SdBaseFile*, const char*, uint8_t).
+ */
+SdFile::SdFile(const char* path, uint8_t oflag) : SdBaseFile(path, oflag) { }
+
+/**
+ * Write data to an open file.
+ *
+ * \note Data is moved to the cache but may not be written to the
+ * storage device until sync() is called.
+ *
+ * \param[in] buf Pointer to the location of the data to be written.
+ *
+ * \param[in] nbyte Number of bytes to write.
+ *
+ * \return For success write() returns the number of bytes written, always
+ * \a nbyte. If an error occurs, write() returns -1. Possible errors
+ * include write() is called before a file has been opened, write is called
+ * for a read-only file, device is full, a corrupt file system or an I/O error.
+ */
+int16_t SdFile::write(const void* buf, uint16_t nbyte) { return SdBaseFile::write(buf, nbyte); }
+
+/**
+ * Write a byte to a file. Required by the Arduino Print class.
+ * \param[in] b the byte to be written.
+ * Use writeError to check for errors.
+ */
+#if ARDUINO >= 100
+ size_t SdFile::write(uint8_t b) { return SdBaseFile::write(&b, 1); }
+#else
+ void SdFile::write(uint8_t b) { SdBaseFile::write(&b, 1); }
+#endif
+
+/**
+ * Write a string to a file. Used by the Arduino Print class.
+ * \param[in] str Pointer to the string.
+ * Use writeError to check for errors.
+ */
+void SdFile::write(const char* str) { SdBaseFile::write(str, strlen(str)); }
+
+/**
+ * Write a PROGMEM string to a file.
+ * \param[in] str Pointer to the PROGMEM string.
+ * Use writeError to check for errors.
+ */
+void SdFile::write_P(PGM_P str) {
+ for (uint8_t c; (c = pgm_read_byte(str)); str++) write(c);
+}
+
+/**
+ * Write a PROGMEM string followed by CR/LF to a file.
+ * \param[in] str Pointer to the PROGMEM string.
+ * Use writeError to check for errors.
+ */
+void SdFile::writeln_P(PGM_P str) {
+ write_P(str);
+ write_P(PSTR("\r\n"));
+}
+
+#endif // SDSUPPORT
diff --git a/Marlin/src/sd/SdFile.h b/Marlin/src/sd/SdFile.h
new file mode 100644
index 0000000..17256b4
--- /dev/null
+++ b/Marlin/src/sd/SdFile.h
@@ -0,0 +1,56 @@
+/**
+ * Marlin 3D Printer Firmware
+ * Copyright (c) 2020 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 <https://www.gnu.org/licenses/>.
+ *
+ */
+#pragma once
+
+/**
+ * sd/SdFile.h
+ *
+ * Arduino SdFat Library
+ * Copyright (c) 2009 by William Greiman
+ *
+ * This file is part of the Arduino Sd2Card Library
+ */
+
+#include "SdBaseFile.h"
+
+#include <stdint.h>
+#include <string.h>
+
+/**
+ * \class SdFile
+ * \brief SdBaseFile with Print.
+ */
+class SdFile : public SdBaseFile {
+ public:
+ SdFile() {}
+ SdFile(const char* name, uint8_t oflag);
+ #if ARDUINO >= 100
+ size_t write(uint8_t b);
+ #else
+ void write(uint8_t b);
+ #endif
+
+ int16_t write(const void* buf, uint16_t nbyte);
+ void write(const char* str);
+ void write_P(PGM_P str);
+ void writeln_P(PGM_P str);
+};
diff --git a/Marlin/src/sd/SdInfo.h b/Marlin/src/sd/SdInfo.h
new file mode 100644
index 0000000..bfa5a01
--- /dev/null
+++ b/Marlin/src/sd/SdInfo.h
@@ -0,0 +1,265 @@
+/**
+ * Marlin 3D Printer Firmware
+ * Copyright (c) 2020 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 <https://www.gnu.org/licenses/>.
+ *
+ */
+#pragma once
+
+/**
+ * Arduino Sd2Card Library
+ * Copyright (c) 2009 by William Greiman
+ *
+ * This file is part of the Arduino Sd2Card Library
+ */
+
+#include <stdint.h>
+
+// Based on the document:
+//
+// SD Specifications
+// Part 1
+// Physical Layer
+// Simplified Specification
+// Version 3.01
+// May 18, 2010
+//
+// https://www.sdcard.org/downloads/pls/index.html
+
+// SD card commands
+uint8_t const CMD0 = 0x00, // GO_IDLE_STATE - init card in spi mode if CS low
+ CMD8 = 0x08, // SEND_IF_COND - verify SD Memory Card interface operating condition
+ CMD9 = 0x09, // SEND_CSD - read the Card Specific Data (CSD register)
+ CMD10 = 0x0A, // SEND_CID - read the card identification information (CID register)
+ CMD12 = 0x0C, // STOP_TRANSMISSION - end multiple block read sequence
+ CMD13 = 0x0D, // SEND_STATUS - read the card status register
+ CMD17 = 0x11, // READ_SINGLE_BLOCK - read a single data block from the card
+ CMD18 = 0x12, // READ_MULTIPLE_BLOCK - read a multiple data blocks from the card
+ CMD24 = 0x18, // WRITE_BLOCK - write a single data block to the card
+ CMD25 = 0x19, // WRITE_MULTIPLE_BLOCK - write blocks of data until a STOP_TRANSMISSION
+ CMD32 = 0x20, // ERASE_WR_BLK_START - sets the address of the first block to be erased
+ CMD33 = 0x21, // ERASE_WR_BLK_END - sets the address of the last block of the continuous range to be erased
+ CMD38 = 0x26, // ERASE - erase all previously selected blocks
+ CMD55 = 0x37, // APP_CMD - escape for application specific command
+ CMD58 = 0x3A, // READ_OCR - read the OCR register of a card
+ CMD59 = 0x3B, // CRC_ON_OFF - enable or disable CRC checking
+ ACMD23 = 0x17, // SET_WR_BLK_ERASE_COUNT - Set the number of write blocks to be pre-erased before writing
+ ACMD41 = 0x29; // SD_SEND_OP_COMD - Sends host capacity support information and activates the card's initialization process
+
+/** status for card in the ready state */
+uint8_t const R1_READY_STATE = 0x00;
+/** status for card in the idle state */
+uint8_t const R1_IDLE_STATE = 0x01;
+/** status bit for illegal command */
+uint8_t const R1_ILLEGAL_COMMAND = 0x04;
+/** start data token for read or write single block*/
+uint8_t const DATA_START_BLOCK = 0xFE;
+/** stop token for write multiple blocks*/
+uint8_t const STOP_TRAN_TOKEN = 0xFD;
+/** start data token for write multiple blocks*/
+uint8_t const WRITE_MULTIPLE_TOKEN = 0xFC;
+/** mask for data response tokens after a write block operation */
+uint8_t const DATA_RES_MASK = 0x1F;
+/** write data accepted token */
+uint8_t const DATA_RES_ACCEPTED = 0x05;
+
+/** Card IDentification (CID) register */
+typedef struct CID {
+ // byte 0
+ /** Manufacturer ID */
+ unsigned char mid;
+ // byte 1-2
+ /** OEM/Application ID */
+ char oid[2];
+ // byte 3-7
+ /** Product name */
+ char pnm[5];
+ // byte 8
+ /** Product revision least significant digit */
+ unsigned char prv_m : 4;
+ /** Product revision most significant digit */
+ unsigned char prv_n : 4;
+ // byte 9-12
+ /** Product serial number */
+ uint32_t psn;
+ // byte 13
+ /** Manufacturing date year low digit */
+ unsigned char mdt_year_high : 4;
+ /** not used */
+ unsigned char reserved : 4;
+ // byte 14
+ /** Manufacturing date month */
+ unsigned char mdt_month : 4;
+ /** Manufacturing date year low digit */
+ unsigned char mdt_year_low : 4;
+ // byte 15
+ /** not used always 1 */
+ unsigned char always1 : 1;
+ /** CRC7 checksum */
+ unsigned char crc : 7;
+} cid_t;
+
+/** CSD for version 1.00 cards */
+typedef struct CSDV1 {
+ // byte 0
+ unsigned char reserved1 : 6;
+ unsigned char csd_ver : 2;
+ // byte 1
+ unsigned char taac;
+ // byte 2
+ unsigned char nsac;
+ // byte 3
+ unsigned char tran_speed;
+ // byte 4
+ unsigned char ccc_high;
+ // byte 5
+ unsigned char read_bl_len : 4;
+ unsigned char ccc_low : 4;
+ // byte 6
+ unsigned char c_size_high : 2;
+ unsigned char reserved2 : 2;
+ unsigned char dsr_imp : 1;
+ unsigned char read_blk_misalign : 1;
+ unsigned char write_blk_misalign : 1;
+ unsigned char read_bl_partial : 1;
+ // byte 7
+ unsigned char c_size_mid;
+ // byte 8
+ unsigned char vdd_r_curr_max : 3;
+ unsigned char vdd_r_curr_min : 3;
+ unsigned char c_size_low : 2;
+ // byte 9
+ unsigned char c_size_mult_high : 2;
+ unsigned char vdd_w_cur_max : 3;
+ unsigned char vdd_w_curr_min : 3;
+ // byte 10
+ unsigned char sector_size_high : 6;
+ unsigned char erase_blk_en : 1;
+ unsigned char c_size_mult_low : 1;
+ // byte 11
+ unsigned char wp_grp_size : 7;
+ unsigned char sector_size_low : 1;
+ // byte 12
+ unsigned char write_bl_len_high : 2;
+ unsigned char r2w_factor : 3;
+ unsigned char reserved3 : 2;
+ unsigned char wp_grp_enable : 1;
+ // byte 13
+ unsigned char reserved4 : 5;
+ unsigned char write_partial : 1;
+ unsigned char write_bl_len_low : 2;
+ // byte 14
+ unsigned char reserved5: 2;
+ unsigned char file_format : 2;
+ unsigned char tmp_write_protect : 1;
+ unsigned char perm_write_protect : 1;
+ unsigned char copy : 1;
+ /** Indicates the file format on the card */
+ unsigned char file_format_grp : 1;
+ // byte 15
+ unsigned char always1 : 1;
+ unsigned char crc : 7;
+} csd1_t;
+
+/** CSD for version 2.00 cards */
+typedef struct CSDV2 {
+ // byte 0
+ unsigned char reserved1 : 6;
+ unsigned char csd_ver : 2;
+ // byte 1
+ /** fixed to 0x0E */
+ unsigned char taac;
+ // byte 2
+ /** fixed to 0 */
+ unsigned char nsac;
+ // byte 3
+ unsigned char tran_speed;
+ // byte 4
+ unsigned char ccc_high;
+ // byte 5
+ /** This field is fixed to 9h, which indicates READ_BL_LEN=512 Byte */
+ unsigned char read_bl_len : 4;
+ unsigned char ccc_low : 4;
+ // byte 6
+ /** not used */
+ unsigned char reserved2 : 4;
+ unsigned char dsr_imp : 1;
+ /** fixed to 0 */
+ unsigned char read_blk_misalign : 1;
+ /** fixed to 0 */
+ unsigned char write_blk_misalign : 1;
+ /** fixed to 0 - no partial read */
+ unsigned char read_bl_partial : 1;
+ // byte 7
+ /** not used */
+ unsigned char reserved3 : 2;
+ /** high part of card size */
+ unsigned char c_size_high : 6;
+ // byte 8
+ /** middle part of card size */
+ unsigned char c_size_mid;
+ // byte 9
+ /** low part of card size */
+ unsigned char c_size_low;
+ // byte 10
+ /** sector size is fixed at 64 KB */
+ unsigned char sector_size_high : 6;
+ /** fixed to 1 - erase single is supported */
+ unsigned char erase_blk_en : 1;
+ /** not used */
+ unsigned char reserved4 : 1;
+ // byte 11
+ unsigned char wp_grp_size : 7;
+ /** sector size is fixed at 64 KB */
+ unsigned char sector_size_low : 1;
+ // byte 12
+ /** write_bl_len fixed for 512 byte blocks */
+ unsigned char write_bl_len_high : 2;
+ /** fixed value of 2 */
+ unsigned char r2w_factor : 3;
+ /** not used */
+ unsigned char reserved5 : 2;
+ /** fixed value of 0 - no write protect groups */
+ unsigned char wp_grp_enable : 1;
+ // byte 13
+ unsigned char reserved6 : 5;
+ /** always zero - no partial block read*/
+ unsigned char write_partial : 1;
+ /** write_bl_len fixed for 512 byte blocks */
+ unsigned char write_bl_len_low : 2;
+ // byte 14
+ unsigned char reserved7: 2;
+ /** Do not use always 0 */
+ unsigned char file_format : 2;
+ unsigned char tmp_write_protect : 1;
+ unsigned char perm_write_protect : 1;
+ unsigned char copy : 1;
+ /** Do not use always 0 */
+ unsigned char file_format_grp : 1;
+ // byte 15
+ /** not used always 1 */
+ unsigned char always1 : 1;
+ /** checksum */
+ unsigned char crc : 7;
+} csd2_t;
+
+/** union of old and new style CSD register */
+union csd_t {
+ csd1_t v1;
+ csd2_t v2;
+};
diff --git a/Marlin/src/sd/SdVolume.cpp b/Marlin/src/sd/SdVolume.cpp
new file mode 100644
index 0000000..e262c88
--- /dev/null
+++ b/Marlin/src/sd/SdVolume.cpp
@@ -0,0 +1,405 @@
+/**
+ * Marlin 3D Printer Firmware
+ * Copyright (c) 2020 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 <https://www.gnu.org/licenses/>.
+ *
+ */
+
+/**
+ * sd/SdVolume.cpp
+ *
+ * Arduino SdFat Library
+ * Copyright (c) 2009 by William Greiman
+ *
+ * This file is part of the Arduino Sd2Card Library
+ */
+
+#include "../inc/MarlinConfig.h"
+
+#if ENABLED(SDSUPPORT)
+
+#include "SdVolume.h"
+
+#include "../MarlinCore.h"
+
+#if !USE_MULTIPLE_CARDS
+ // raw block cache
+ uint32_t SdVolume::cacheBlockNumber_; // current block number
+ cache_t SdVolume::cacheBuffer_; // 512 byte cache for Sd2Card
+ Sd2Card* SdVolume::sdCard_; // pointer to SD card object
+ bool SdVolume::cacheDirty_; // cacheFlush() will write block if true
+ uint32_t SdVolume::cacheMirrorBlock_; // mirror block for second FAT
+#endif // USE_MULTIPLE_CARDS
+
+// find a contiguous group of clusters
+bool SdVolume::allocContiguous(uint32_t count, uint32_t* curCluster) {
+ if (ENABLED(SDCARD_READONLY)) return false;
+
+ // start of group
+ uint32_t bgnCluster;
+ // end of group
+ uint32_t endCluster;
+ // last cluster of FAT
+ uint32_t fatEnd = clusterCount_ + 1;
+
+ // flag to save place to start next search
+ bool setStart;
+
+ // set search start cluster
+ if (*curCluster) {
+ // try to make file contiguous
+ bgnCluster = *curCluster + 1;
+
+ // don't save new start location
+ setStart = false;
+ }
+ else {
+ // start at likely place for free cluster
+ bgnCluster = allocSearchStart_;
+
+ // save next search start if one cluster
+ setStart = count == 1;
+ }
+ // end of group
+ endCluster = bgnCluster;
+
+ // search the FAT for free clusters
+ for (uint32_t n = 0;; n++, endCluster++) {
+ // can't find space checked all clusters
+ if (n >= clusterCount_) return false;
+
+ // past end - start from beginning of FAT
+ if (endCluster > fatEnd) {
+ bgnCluster = endCluster = 2;
+ }
+ uint32_t f;
+ if (!fatGet(endCluster, &f)) return false;
+
+ if (f != 0) {
+ // cluster in use try next cluster as bgnCluster
+ bgnCluster = endCluster + 1;
+ }
+ else if ((endCluster - bgnCluster + 1) == count) {
+ // done - found space
+ break;
+ }
+ }
+ // mark end of chain
+ if (!fatPutEOC(endCluster)) return false;
+
+ // link clusters
+ while (endCluster > bgnCluster) {
+ if (!fatPut(endCluster - 1, endCluster)) return false;
+ endCluster--;
+ }
+ if (*curCluster != 0) {
+ // connect chains
+ if (!fatPut(*curCluster, bgnCluster)) return false;
+ }
+ // return first cluster number to caller
+ *curCluster = bgnCluster;
+
+ // remember possible next free cluster
+ if (setStart) allocSearchStart_ = bgnCluster + 1;
+
+ return true;
+}
+
+bool SdVolume::cacheFlush() {
+ #if DISABLED(SDCARD_READONLY)
+ if (cacheDirty_) {
+ if (!sdCard_->writeBlock(cacheBlockNumber_, cacheBuffer_.data))
+ return false;
+
+ // mirror FAT tables
+ if (cacheMirrorBlock_) {
+ if (!sdCard_->writeBlock(cacheMirrorBlock_, cacheBuffer_.data))
+ return false;
+ cacheMirrorBlock_ = 0;
+ }
+ cacheDirty_ = 0;
+ }
+ #endif
+ return true;
+}
+
+bool SdVolume::cacheRawBlock(uint32_t blockNumber, bool dirty) {
+ if (cacheBlockNumber_ != blockNumber) {
+ if (!cacheFlush()) return false;
+ if (!sdCard_->readBlock(blockNumber, cacheBuffer_.data)) return false;
+ cacheBlockNumber_ = blockNumber;
+ }
+ if (dirty) cacheDirty_ = true;
+ return true;
+}
+
+// return the size in bytes of a cluster chain
+bool SdVolume::chainSize(uint32_t cluster, uint32_t* size) {
+ uint32_t s = 0;
+ do {
+ if (!fatGet(cluster, &cluster)) return false;
+ s += 512UL << clusterSizeShift_;
+ } while (!isEOC(cluster));
+ *size = s;
+ return true;
+}
+
+// Fetch a FAT entry
+bool SdVolume::fatGet(uint32_t cluster, uint32_t* value) {
+ uint32_t lba;
+ if (cluster > (clusterCount_ + 1)) return false;
+ if (FAT12_SUPPORT && fatType_ == 12) {
+ uint16_t index = cluster;
+ index += index >> 1;
+ lba = fatStartBlock_ + (index >> 9);
+ if (!cacheRawBlock(lba, CACHE_FOR_READ)) return false;
+ index &= 0x1FF;
+ uint16_t tmp = cacheBuffer_.data[index];
+ index++;
+ if (index == 512) {
+ if (!cacheRawBlock(lba + 1, CACHE_FOR_READ)) return false;
+ index = 0;
+ }
+ tmp |= cacheBuffer_.data[index] << 8;
+ *value = cluster & 1 ? tmp >> 4 : tmp & 0xFFF;
+ return true;
+ }
+
+ if (fatType_ == 16)
+ lba = fatStartBlock_ + (cluster >> 8);
+ else if (fatType_ == 32)
+ lba = fatStartBlock_ + (cluster >> 7);
+ else
+ return false;
+
+ if (lba != cacheBlockNumber_ && !cacheRawBlock(lba, CACHE_FOR_READ))
+ return false;
+
+ *value = (fatType_ == 16) ? cacheBuffer_.fat16[cluster & 0xFF] : (cacheBuffer_.fat32[cluster & 0x7F] & FAT32MASK);
+ return true;
+}
+
+// Store a FAT entry
+bool SdVolume::fatPut(uint32_t cluster, uint32_t value) {
+ if (ENABLED(SDCARD_READONLY)) return false;
+
+ uint32_t lba;
+ // error if reserved cluster
+ if (cluster < 2) return false;
+
+ // error if not in FAT
+ if (cluster > (clusterCount_ + 1)) return false;
+
+ if (FAT12_SUPPORT && fatType_ == 12) {
+ uint16_t index = cluster;
+ index += index >> 1;
+ lba = fatStartBlock_ + (index >> 9);
+ if (!cacheRawBlock(lba, CACHE_FOR_WRITE)) return false;
+ // mirror second FAT
+ if (fatCount_ > 1) cacheMirrorBlock_ = lba + blocksPerFat_;
+ index &= 0x1FF;
+ uint8_t tmp = value;
+ if (cluster & 1) {
+ tmp = (cacheBuffer_.data[index] & 0xF) | tmp << 4;
+ }
+ cacheBuffer_.data[index] = tmp;
+ index++;
+ if (index == 512) {
+ lba++;
+ index = 0;
+ if (!cacheRawBlock(lba, CACHE_FOR_WRITE)) return false;
+ // mirror second FAT
+ if (fatCount_ > 1) cacheMirrorBlock_ = lba + blocksPerFat_;
+ }
+ tmp = value >> 4;
+ if (!(cluster & 1)) {
+ tmp = ((cacheBuffer_.data[index] & 0xF0)) | tmp >> 4;
+ }
+ cacheBuffer_.data[index] = tmp;
+ return true;
+ }
+
+ if (fatType_ == 16)
+ lba = fatStartBlock_ + (cluster >> 8);
+ else if (fatType_ == 32)
+ lba = fatStartBlock_ + (cluster >> 7);
+ else
+ return false;
+
+ if (!cacheRawBlock(lba, CACHE_FOR_WRITE)) return false;
+
+ // store entry
+ if (fatType_ == 16)
+ cacheBuffer_.fat16[cluster & 0xFF] = value;
+ else
+ cacheBuffer_.fat32[cluster & 0x7F] = value;
+
+ // mirror second FAT
+ if (fatCount_ > 1) cacheMirrorBlock_ = lba + blocksPerFat_;
+ return true;
+}
+
+// free a cluster chain
+bool SdVolume::freeChain(uint32_t cluster) {
+ // clear free cluster location
+ allocSearchStart_ = 2;
+
+ do {
+ uint32_t next;
+ if (!fatGet(cluster, &next)) return false;
+
+ // free cluster
+ if (!fatPut(cluster, 0)) return false;
+
+ cluster = next;
+ } while (!isEOC(cluster));
+
+ return true;
+}
+
+/** Volume free space in clusters.
+ *
+ * \return Count of free clusters for success or -1 if an error occurs.
+ */
+int32_t SdVolume::freeClusterCount() {
+ uint32_t free = 0;
+ uint16_t n;
+ uint32_t todo = clusterCount_ + 2;
+
+ if (fatType_ == 16)
+ n = 256;
+ else if (fatType_ == 32)
+ n = 128;
+ else // put FAT12 here
+ return -1;
+
+ for (uint32_t lba = fatStartBlock_; todo; todo -= n, lba++) {
+ if (!cacheRawBlock(lba, CACHE_FOR_READ)) return -1;
+ NOMORE(n, todo);
+ if (fatType_ == 16) {
+ for (uint16_t i = 0; i < n; i++)
+ if (cacheBuffer_.fat16[i] == 0) free++;
+ }
+ else {
+ for (uint16_t i = 0; i < n; i++)
+ if (cacheBuffer_.fat32[i] == 0) free++;
+ }
+ #ifdef ESP32
+ // Needed to reset the idle task watchdog timer on ESP32 as reading the complete FAT may easily
+ // block for 10+ seconds. yield() is insufficient since it blocks lower prio tasks (e.g., idle).
+ static millis_t nextTaskTime = 0;
+ const millis_t ms = millis();
+ if (ELAPSED(ms, nextTaskTime)) {
+ vTaskDelay(1); // delay 1 tick (Minimum. Usually 10 or 1 ms depending on skdconfig.h)
+ nextTaskTime = ms + 1000; // tickle the task manager again in 1 second
+ }
+ #endif // ESP32
+ }
+ return free;
+}
+
+/** Initialize a FAT volume.
+ *
+ * \param[in] dev The SD card where the volume is located.
+ *
+ * \param[in] part The partition to be used. Legal values for \a part are
+ * 1-4 to use the corresponding partition on a device formatted with
+ * a MBR, Master Boot Record, or zero if the device is formatted as
+ * a super floppy with the FAT boot sector in block zero.
+ *
+ * \return true for success, false for failure.
+ * Reasons for failure include not finding a valid partition, not finding a valid
+ * FAT file system in the specified partition or an I/O error.
+ */
+bool SdVolume::init(Sd2Card* dev, uint8_t part) {
+ uint32_t totalBlocks, volumeStartBlock = 0;
+ fat32_boot_t* fbs;
+
+ sdCard_ = dev;
+ fatType_ = 0;
+ allocSearchStart_ = 2;
+ cacheDirty_ = 0; // cacheFlush() will write block if true
+ cacheMirrorBlock_ = 0;
+ cacheBlockNumber_ = 0xFFFFFFFF;
+
+ // if part == 0 assume super floppy with FAT boot sector in block zero
+ // if part > 0 assume mbr volume with partition table
+ if (part) {
+ if (part > 4) return false;
+ if (!cacheRawBlock(volumeStartBlock, CACHE_FOR_READ)) return false;
+ part_t* p = &cacheBuffer_.mbr.part[part - 1];
+ if ((p->boot & 0x7F) != 0 || p->totalSectors < 100 || p->firstSector == 0)
+ return false; // not a valid partition
+ volumeStartBlock = p->firstSector;
+ }
+ if (!cacheRawBlock(volumeStartBlock, CACHE_FOR_READ)) return false;
+ fbs = &cacheBuffer_.fbs32;
+ if (fbs->bytesPerSector != 512 ||
+ fbs->fatCount == 0 ||
+ fbs->reservedSectorCount == 0 ||
+ fbs->sectorsPerCluster == 0) {
+ // not valid FAT volume
+ return false;
+ }
+ fatCount_ = fbs->fatCount;
+ blocksPerCluster_ = fbs->sectorsPerCluster;
+ // determine shift that is same as multiply by blocksPerCluster_
+ clusterSizeShift_ = 0;
+ while (blocksPerCluster_ != _BV(clusterSizeShift_)) {
+ // error if not power of 2
+ if (clusterSizeShift_++ > 7) return false;
+ }
+ blocksPerFat_ = fbs->sectorsPerFat16 ?
+ fbs->sectorsPerFat16 : fbs->sectorsPerFat32;
+
+ fatStartBlock_ = volumeStartBlock + fbs->reservedSectorCount;
+
+ // count for FAT16 zero for FAT32
+ rootDirEntryCount_ = fbs->rootDirEntryCount;
+
+ // directory start for FAT16 dataStart for FAT32
+ rootDirStart_ = fatStartBlock_ + fbs->fatCount * blocksPerFat_;
+
+ // data start for FAT16 and FAT32
+ dataStartBlock_ = rootDirStart_ + ((32 * fbs->rootDirEntryCount + 511) / 512);
+
+ // total blocks for FAT16 or FAT32
+ totalBlocks = fbs->totalSectors16 ?
+ fbs->totalSectors16 : fbs->totalSectors32;
+
+ // total data blocks
+ clusterCount_ = totalBlocks - (dataStartBlock_ - volumeStartBlock);
+
+ // divide by cluster size to get cluster count
+ clusterCount_ >>= clusterSizeShift_;
+
+ // FAT type is determined by cluster count
+ if (clusterCount_ < 4085) {
+ fatType_ = 12;
+ if (!FAT12_SUPPORT) return false;
+ }
+ else if (clusterCount_ < 65525)
+ fatType_ = 16;
+ else {
+ rootDirStart_ = fbs->fat32RootCluster;
+ fatType_ = 32;
+ }
+ return true;
+}
+
+#endif // SDSUPPORT
diff --git a/Marlin/src/sd/SdVolume.h b/Marlin/src/sd/SdVolume.h
new file mode 100644
index 0000000..2d57c68
--- /dev/null
+++ b/Marlin/src/sd/SdVolume.h
@@ -0,0 +1,198 @@
+/**
+ * Marlin 3D Printer Firmware
+ * Copyright (c) 2020 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 <https://www.gnu.org/licenses/>.
+ *
+ */
+#pragma once
+
+/**
+ * sd/SdVolume.h
+ *
+ * Arduino SdFat Library
+ * Copyright (c) 2009 by William Greiman
+ *
+ * This file is part of the Arduino Sd2Card Library
+ */
+
+#include <stdint.h>
+
+#include "../inc/MarlinConfigPre.h"
+
+#if ENABLED(USB_FLASH_DRIVE_SUPPORT)
+ #include "usb_flashdrive/Sd2Card_FlashDrive.h"
+#elif ENABLED(SDIO_SUPPORT)
+ #include "Sd2Card_sdio.h"
+#else
+ #include "Sd2Card.h"
+#endif
+
+#include "SdFatConfig.h"
+#include "SdFatStructs.h"
+
+//==============================================================================
+// SdVolume class
+/**
+ * \brief Cache for an SD data block
+ */
+union cache_t {
+ uint8_t data[512]; // Used to access cached file data blocks.
+ uint16_t fat16[256]; // Used to access cached FAT16 entries.
+ uint32_t fat32[128]; // Used to access cached FAT32 entries.
+ dir_t dir[16]; // Used to access cached directory entries.
+ mbr_t mbr; // Used to access a cached Master Boot Record.
+ fat_boot_t fbs; // Used to access to a cached FAT boot sector.
+ fat32_boot_t fbs32; // Used to access to a cached FAT32 boot sector.
+ fat32_fsinfo_t fsinfo; // Used to access to a cached FAT32 FSINFO sector.
+};
+
+/**
+ * \class SdVolume
+ * \brief Access FAT16 and FAT32 volumes on SD and SDHC cards.
+ */
+class SdVolume {
+ public:
+ // Create an instance of SdVolume
+ SdVolume() : fatType_(0) {}
+ /**
+ * Clear the cache and returns a pointer to the cache. Used by the WaveRP
+ * recorder to do raw write to the SD card. Not for normal apps.
+ * \return A pointer to the cache buffer or zero if an error occurs.
+ */
+ cache_t* cacheClear() {
+ if (!cacheFlush()) return 0;
+ cacheBlockNumber_ = 0xFFFFFFFF;
+ return &cacheBuffer_;
+ }
+
+ /**
+ * Initialize a FAT volume. Try partition one first then try super
+ * floppy format.
+ *
+ * \param[in] dev The Sd2Card where the volume is located.
+ *
+ * \return true for success, false for failure.
+ * Reasons for failure include not finding a valid partition, not finding
+ * a valid FAT file system or an I/O error.
+ */
+ bool init(Sd2Card* dev) { return init(dev, 1) ? true : init(dev, 0); }
+ bool init(Sd2Card* dev, uint8_t part);
+
+ // inline functions that return volume info
+ uint8_t blocksPerCluster() const { return blocksPerCluster_; } //> \return The volume's cluster size in blocks.
+ uint32_t blocksPerFat() const { return blocksPerFat_; } //> \return The number of blocks in one FAT.
+ uint32_t clusterCount() const { return clusterCount_; } //> \return The total number of clusters in the volume.
+ uint8_t clusterSizeShift() const { return clusterSizeShift_; } //> \return The shift count required to multiply by blocksPerCluster.
+ uint32_t dataStartBlock() const { return dataStartBlock_; } //> \return The logical block number for the start of file data.
+ uint8_t fatCount() const { return fatCount_; } //> \return The number of FAT structures on the volume.
+ uint32_t fatStartBlock() const { return fatStartBlock_; } //> \return The logical block number for the start of the first FAT.
+ uint8_t fatType() const { return fatType_; } //> \return The FAT type of the volume. Values are 12, 16 or 32.
+ int32_t freeClusterCount();
+ uint32_t rootDirEntryCount() const { return rootDirEntryCount_; } /** \return The number of entries in the root directory for FAT16 volumes. */
+
+ /**
+ * \return The logical block number for the start of the root directory
+ * on FAT16 volumes or the first cluster number on FAT32 volumes.
+ */
+ uint32_t rootDirStart() const { return rootDirStart_; }
+
+ /**
+ * Sd2Card object for this volume
+ * \return pointer to Sd2Card object.
+ */
+ Sd2Card* sdCard() { return sdCard_; }
+
+ /**
+ * Debug access to FAT table
+ *
+ * \param[in] n cluster number.
+ * \param[out] v value of entry
+ * \return true for success or false for failure
+ */
+ bool dbgFat(uint32_t n, uint32_t* v) { return fatGet(n, v); }
+
+ private:
+ // Allow SdBaseFile access to SdVolume private data.
+ friend class SdBaseFile;
+
+ // value for dirty argument in cacheRawBlock to indicate read from cache
+ static bool const CACHE_FOR_READ = false;
+ // value for dirty argument in cacheRawBlock to indicate write to cache
+ static bool const CACHE_FOR_WRITE = true;
+
+ #if USE_MULTIPLE_CARDS
+ cache_t cacheBuffer_; // 512 byte cache for device blocks
+ uint32_t cacheBlockNumber_; // Logical number of block in the cache
+ Sd2Card* sdCard_; // Sd2Card object for cache
+ bool cacheDirty_; // cacheFlush() will write block if true
+ uint32_t cacheMirrorBlock_; // block number for mirror FAT
+ #else
+ static cache_t cacheBuffer_; // 512 byte cache for device blocks
+ static uint32_t cacheBlockNumber_; // Logical number of block in the cache
+ static Sd2Card* sdCard_; // Sd2Card object for cache
+ static bool cacheDirty_; // cacheFlush() will write block if true
+ static uint32_t cacheMirrorBlock_; // block number for mirror FAT
+ #endif
+
+ uint32_t allocSearchStart_; // start cluster for alloc search
+ uint8_t blocksPerCluster_; // cluster size in blocks
+ uint32_t blocksPerFat_; // FAT size in blocks
+ uint32_t clusterCount_; // clusters in one FAT
+ uint8_t clusterSizeShift_; // shift to convert cluster count to block count
+ uint32_t dataStartBlock_; // first data block number
+ uint8_t fatCount_; // number of FATs on volume
+ uint32_t fatStartBlock_; // start block for first FAT
+ uint8_t fatType_; // volume type (12, 16, OR 32)
+ uint16_t rootDirEntryCount_; // number of entries in FAT16 root dir
+ uint32_t rootDirStart_; // root start block for FAT16, cluster for FAT32
+
+ bool allocContiguous(uint32_t count, uint32_t* curCluster);
+ uint8_t blockOfCluster(uint32_t position) const { return (position >> 9) & (blocksPerCluster_ - 1); }
+ uint32_t clusterStartBlock(uint32_t cluster) const { return dataStartBlock_ + ((cluster - 2) << clusterSizeShift_); }
+ uint32_t blockNumber(uint32_t cluster, uint32_t position) const { return clusterStartBlock(cluster) + blockOfCluster(position); }
+
+ cache_t* cache() { return &cacheBuffer_; }
+ uint32_t cacheBlockNumber() const { return cacheBlockNumber_; }
+
+ #if USE_MULTIPLE_CARDS
+ bool cacheFlush();
+ bool cacheRawBlock(uint32_t blockNumber, bool dirty);
+ #else
+ static bool cacheFlush();
+ static bool cacheRawBlock(uint32_t blockNumber, bool dirty);
+ #endif
+
+ // used by SdBaseFile write to assign cache to SD location
+ void cacheSetBlockNumber(uint32_t blockNumber, bool dirty) {
+ cacheDirty_ = dirty;
+ cacheBlockNumber_ = blockNumber;
+ }
+ void cacheSetDirty() { cacheDirty_ |= CACHE_FOR_WRITE; }
+ bool chainSize(uint32_t beginCluster, uint32_t* size);
+ bool fatGet(uint32_t cluster, uint32_t* value);
+ bool fatPut(uint32_t cluster, uint32_t value);
+ bool fatPutEOC(uint32_t cluster) { return fatPut(cluster, 0x0FFFFFFF); }
+ bool freeChain(uint32_t cluster);
+ bool isEOC(uint32_t cluster) const {
+ if (FAT12_SUPPORT && fatType_ == 12) return cluster >= FAT12EOC_MIN;
+ if (fatType_ == 16) return cluster >= FAT16EOC_MIN;
+ return cluster >= FAT32EOC_MIN;
+ }
+ bool readBlock(uint32_t block, uint8_t* dst) { return sdCard_->readBlock(block, dst); }
+ bool writeBlock(uint32_t block, const uint8_t* dst) { return sdCard_->writeBlock(block, dst); }
+};
diff --git a/Marlin/src/sd/cardreader.cpp b/Marlin/src/sd/cardreader.cpp
new file mode 100644
index 0000000..647e3f3
--- /dev/null
+++ b/Marlin/src/sd/cardreader.cpp
@@ -0,0 +1,1265 @@
+/**
+ * Marlin 3D Printer Firmware
+ * Copyright (c) 2020 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 <https://www.gnu.org/licenses/>.
+ *
+ */
+
+#include "../inc/MarlinConfig.h"
+
+#if ENABLED(SDSUPPORT)
+
+//#define DEBUG_CARDREADER
+
+#include "cardreader.h"
+
+#include "../MarlinCore.h"
+#include "../lcd/marlinui.h"
+
+#if ENABLED(DWIN_CREALITY_LCD)
+ #include "../lcd/dwin/e3v2/dwin.h"
+#endif
+
+#include "../module/planner.h" // for synchronize
+#include "../module/printcounter.h"
+#include "../gcode/queue.h"
+#include "../module/settings.h"
+#include "../module/stepper/indirection.h"
+
+#if ENABLED(EMERGENCY_PARSER)
+ #include "../feature/e_parser.h"
+#endif
+
+#if ENABLED(POWER_LOSS_RECOVERY)
+ #include "../feature/powerloss.h"
+#endif
+
+#if ENABLED(ADVANCED_PAUSE_FEATURE)
+ #include "../feature/pause.h"
+#endif
+
+#define DEBUG_OUT EITHER(DEBUG_CARDREADER, MARLIN_DEV_MODE)
+#include "../core/debug_out.h"
+#include "../libs/hex_print.h"
+
+// extern
+
+PGMSTR(M23_STR, "M23 %s");
+PGMSTR(M24_STR, "M24");
+
+// public:
+
+card_flags_t CardReader::flag;
+char CardReader::filename[FILENAME_LENGTH], CardReader::longFilename[LONG_FILENAME_LENGTH];
+
+IF_DISABLED(NO_SD_AUTOSTART, uint8_t CardReader::autofile_index); // = 0
+
+#if BOTH(HAS_MULTI_SERIAL, BINARY_FILE_TRANSFER)
+ int8_t CardReader::transfer_port_index;
+#endif
+
+// private:
+
+SdFile CardReader::root, CardReader::workDir, CardReader::workDirParents[MAX_DIR_DEPTH];
+uint8_t CardReader::workDirDepth;
+
+#if ENABLED(SDCARD_SORT_ALPHA)
+
+ uint16_t CardReader::sort_count;
+ #if ENABLED(SDSORT_GCODE)
+ bool CardReader::sort_alpha;
+ int CardReader::sort_folders;
+ //bool CardReader::sort_reverse;
+ #endif
+
+ #if ENABLED(SDSORT_DYNAMIC_RAM)
+ uint8_t *CardReader::sort_order;
+ #else
+ uint8_t CardReader::sort_order[SDSORT_LIMIT];
+ #endif
+
+ #if ENABLED(SDSORT_USES_RAM)
+
+ #if ENABLED(SDSORT_CACHE_NAMES)
+ uint16_t CardReader::nrFiles; // Cached total file count
+ #if ENABLED(SDSORT_DYNAMIC_RAM)
+ char **CardReader::sortshort, **CardReader::sortnames;
+ #else
+ char CardReader::sortshort[SDSORT_LIMIT][FILENAME_LENGTH];
+ char CardReader::sortnames[SDSORT_LIMIT][SORTED_LONGNAME_STORAGE];
+ #endif
+ #elif DISABLED(SDSORT_USES_STACK)
+ char CardReader::sortnames[SDSORT_LIMIT][SORTED_LONGNAME_STORAGE];
+ #endif
+
+ #if HAS_FOLDER_SORTING
+ #if ENABLED(SDSORT_DYNAMIC_RAM)
+ uint8_t *CardReader::isDir;
+ #elif ENABLED(SDSORT_CACHE_NAMES) || DISABLED(SDSORT_USES_STACK)
+ uint8_t CardReader::isDir[(SDSORT_LIMIT+7)>>3];
+ #endif
+ #define IS_DIR(n) TEST(isDir[(n) >> 3], (n) & 0x07)
+ #endif
+
+ #endif // SDSORT_USES_RAM
+
+#endif // SDCARD_SORT_ALPHA
+
+Sd2Card CardReader::sd2card;
+SdVolume CardReader::volume;
+SdFile CardReader::file;
+
+#if HAS_MEDIA_SUBCALLS
+ uint8_t CardReader::file_subcall_ctr;
+ uint32_t CardReader::filespos[SD_PROCEDURE_DEPTH];
+ char CardReader::proc_filenames[SD_PROCEDURE_DEPTH][MAXPATHNAMELENGTH];
+#endif
+
+uint32_t CardReader::filesize, CardReader::sdpos;
+
+CardReader::CardReader() {
+ #if ENABLED(SDCARD_SORT_ALPHA)
+ sort_count = 0;
+ #if ENABLED(SDSORT_GCODE)
+ sort_alpha = true;
+ sort_folders = FOLDER_SORTING;
+ //sort_reverse = false;
+ #endif
+ #endif
+
+ flag.sdprinting = flag.mounted = flag.saving = flag.logging = false;
+ filesize = sdpos = 0;
+
+ TERN_(HAS_MEDIA_SUBCALLS, file_subcall_ctr = 0);
+
+ IF_DISABLED(NO_SD_AUTOSTART, autofile_cancel());
+
+ workDirDepth = 0;
+ ZERO(workDirParents);
+
+ #if ENABLED(SDSUPPORT) && PIN_EXISTS(SD_DETECT)
+ SET_INPUT_PULLUP(SD_DETECT_PIN);
+ #endif
+
+ #if PIN_EXISTS(SDPOWER)
+ OUT_WRITE(SDPOWER_PIN, HIGH); // Power the SD reader
+ #endif
+}
+
+//
+// Get a DOS 8.3 filename in its useful form
+//
+char *createFilename(char * const buffer, const dir_t &p) {
+ char *pos = buffer;
+ LOOP_L_N(i, 11) {
+ if (p.name[i] == ' ') continue;
+ if (i == 8) *pos++ = '.';
+ *pos++ = p.name[i];
+ }
+ *pos++ = 0;
+ return buffer;
+}
+
+//
+// Return 'true' if the item is a folder or G-code file
+//
+bool CardReader::is_dir_or_gcode(const dir_t &p) {
+ //uint8_t pn0 = p.name[0];
+
+ if ( (p.attributes & DIR_ATT_HIDDEN) // Hidden by attribute
+ // When readDir() > 0 these must be false:
+ //|| pn0 == DIR_NAME_FREE || pn0 == DIR_NAME_DELETED // Clear or Deleted entry
+ //|| pn0 == '.' || longFilename[0] == '.' // Hidden file
+ //|| !DIR_IS_FILE_OR_SUBDIR(&p) // Not a File or Directory
+ ) return false;
+
+ flag.filenameIsDir = DIR_IS_SUBDIR(&p); // We know it's a File or Folder
+
+ return (
+ flag.filenameIsDir // All Directories are ok
+ || (p.name[8] == 'G' && p.name[9] != '~') // Non-backup *.G* files are accepted
+ );
+}
+
+//
+// Get the number of (compliant) items in the folder
+//
+int CardReader::countItems(SdFile dir) {
+ dir_t p;
+ int c = 0;
+ while (dir.readDir(&p, longFilename) > 0)
+ c += is_dir_or_gcode(p);
+
+ #if ALL(SDCARD_SORT_ALPHA, SDSORT_USES_RAM, SDSORT_CACHE_NAMES)
+ nrFiles = c;
+ #endif
+
+ return c;
+}
+
+//
+// Get file/folder info for an item by index
+//
+void CardReader::selectByIndex(SdFile dir, const uint8_t index) {
+ dir_t p;
+ for (uint8_t cnt = 0; dir.readDir(&p, longFilename) > 0;) {
+ if (is_dir_or_gcode(p)) {
+ if (cnt == index) {
+ createFilename(filename, p);
+ return; // 0 based index
+ }
+ cnt++;
+ }
+ }
+}
+
+//
+// Get file/folder info for an item by name
+//
+void CardReader::selectByName(SdFile dir, const char * const match) {
+ dir_t p;
+ for (uint8_t cnt = 0; dir.readDir(&p, longFilename) > 0; cnt++) {
+ if (is_dir_or_gcode(p)) {
+ createFilename(filename, p);
+ if (strcasecmp(match, filename) == 0) return;
+ }
+ }
+}
+
+//
+// Recursive method to list all files within a folder
+//
+void CardReader::printListing(SdFile parent, const char * const prepend/*=nullptr*/) {
+ dir_t p;
+ while (parent.readDir(&p, longFilename) > 0) {
+ if (DIR_IS_SUBDIR(&p)) {
+
+ // Get the short name for the item, which we know is a folder
+ char dosFilename[FILENAME_LENGTH];
+ createFilename(dosFilename, p);
+
+ // Allocate enough stack space for the full path to a folder, trailing slash, and nul
+ const bool prepend_is_empty = (!prepend || prepend[0] == '\0');
+ const int len = (prepend_is_empty ? 1 : strlen(prepend)) + strlen(dosFilename) + 1 + 1;
+ char path[len];
+
+ // Append the FOLDERNAME12/ to the passed string.
+ // It contains the full path to the "parent" argument.
+ // We now have the full path to the item in this folder.
+ strcpy(path, prepend_is_empty ? "/" : prepend); // root slash if prepend is empty
+ strcat(path, dosFilename); // FILENAME_LENGTH characters maximum
+ strcat(path, "/"); // 1 character
+
+ // Serial.print(path);
+
+ // Get a new directory object using the full path
+ // and dive recursively into it.
+ SdFile child;
+ if (!child.open(&parent, dosFilename, O_READ)) {
+ SERIAL_ECHO_START();
+ SERIAL_ECHOLNPAIR(STR_SD_CANT_OPEN_SUBDIR, dosFilename);
+ }
+ printListing(child, path);
+ // close() is done automatically by destructor of SdFile
+ }
+ else if (is_dir_or_gcode(p)) {
+ createFilename(filename, p);
+ if (prepend) SERIAL_ECHO(prepend);
+ SERIAL_ECHO(filename);
+ SERIAL_CHAR(' ');
+ SERIAL_ECHOLN(p.fileSize);
+ }
+ }
+}
+
+//
+// List all files on the SD card
+//
+void CardReader::ls() {
+ if (flag.mounted) {
+ root.rewind();
+ printListing(root);
+ }
+}
+
+#if ENABLED(LONG_FILENAME_HOST_SUPPORT)
+
+ //
+ // Get a long pretty path based on a DOS 8.3 path
+ //
+ void CardReader::printLongPath(char * const path) {
+
+ int i, pathLen = strlen(path);
+
+ // SERIAL_ECHOPGM("Full Path: "); SERIAL_ECHOLN(path);
+
+ // Zero out slashes to make segments
+ for (i = 0; i < pathLen; i++) if (path[i] == '/') path[i] = '\0';
+
+ SdFile diveDir = root; // start from the root for segment 1
+ for (i = 0; i < pathLen;) {
+
+ if (path[i] == '\0') i++; // move past a single nul
+
+ char *segment = &path[i]; // The segment after most slashes
+
+ // If a segment is empty (extra-slash) then exit
+ if (!*segment) break;
+
+ // Go to the next segment
+ while (path[++i]) { }
+
+ // SERIAL_ECHOPGM("Looking for segment: "); SERIAL_ECHOLN(segment);
+
+ // Find the item, setting the long filename
+ diveDir.rewind();
+ selectByName(diveDir, segment);
+
+ // Print /LongNamePart to serial output
+ SERIAL_CHAR('/');
+ SERIAL_ECHO(longFilename[0] ? longFilename : "???");
+
+ // If the filename was printed then that's it
+ if (!flag.filenameIsDir) break;
+
+ // SERIAL_ECHOPGM("Opening dir: "); SERIAL_ECHOLN(segment);
+
+ // Open the sub-item as the new dive parent
+ SdFile dir;
+ if (!dir.open(&diveDir, segment, O_READ)) {
+ SERIAL_EOL();
+ SERIAL_ECHO_START();
+ SERIAL_ECHOPAIR(STR_SD_CANT_OPEN_SUBDIR, segment);
+ break;
+ }
+
+ diveDir.close();
+ diveDir = dir;
+
+ } // while i<pathLen
+
+ SERIAL_EOL();
+ }
+
+#endif // LONG_FILENAME_HOST_SUPPORT
+
+//
+// Echo the DOS 8.3 filename (and long filename, if any)
+//
+void CardReader::printFilename() {
+ if (file.isOpen()) {
+ char dosFilename[FILENAME_LENGTH];
+ file.getDosName(dosFilename);
+ SERIAL_ECHO(dosFilename);
+ #if ENABLED(LONG_FILENAME_HOST_SUPPORT)
+ selectFileByName(dosFilename);
+ if (longFilename[0]) {
+ SERIAL_ECHO(' ');
+ SERIAL_ECHO(longFilename);
+ }
+ #endif
+ }
+ else
+ SERIAL_ECHOPGM("(no file)");
+
+ SERIAL_EOL();
+}
+
+void CardReader::mount() {
+ flag.mounted = false;
+ if (root.isOpen()) root.close();
+
+ if (!sd2card.init(SD_SPI_SPEED, SDSS)
+ #if defined(LCD_SDSS) && (LCD_SDSS != SDSS)
+ && !sd2card.init(SD_SPI_SPEED, LCD_SDSS)
+ #endif
+ ) SERIAL_ECHO_MSG(STR_SD_INIT_FAIL);
+ else if (!volume.init(&sd2card))
+ SERIAL_ERROR_MSG(STR_SD_VOL_INIT_FAIL);
+ else if (!root.openRoot(&volume))
+ SERIAL_ERROR_MSG(STR_SD_OPENROOT_FAIL);
+ else {
+ flag.mounted = true;
+ SERIAL_ECHO_MSG(STR_SD_CARD_OK);
+ }
+
+ if (flag.mounted)
+ cdroot();
+ #if ENABLED(USB_FLASH_DRIVE_SUPPORT) || PIN_EXISTS(SD_DETECT)
+ else if (marlin_state != MF_INITIALIZING)
+ ui.set_status_P(GET_TEXT(MSG_SD_INIT_FAIL), -1);
+ #endif
+
+ ui.refresh();
+}
+
+/**
+ * Handle SD card events
+ */
+#if MB(FYSETC_CHEETAH, FYSETC_AIO_II)
+ #include "../module/stepper.h"
+#endif
+
+void CardReader::manage_media() {
+ static uint8_t prev_stat = 2; // First call, no prior state
+ uint8_t stat = uint8_t(IS_SD_INSERTED());
+ if (stat == prev_stat) return;
+
+ DEBUG_ECHOLNPAIR("SD: Status changed from ", prev_stat, " to ", stat);
+
+ flag.workDirIsRoot = true; // Return to root on mount/release
+
+ if (ui.detected()) {
+
+ uint8_t old_stat = prev_stat;
+ prev_stat = stat; // Change now to prevent re-entry
+
+ if (stat) { // Media Inserted
+ safe_delay(500); // Some boards need a delay to get settled
+ if (TERN1(SD_IGNORE_AT_STARTUP, old_stat != 2))
+ mount(); // Try to mount the media
+ #if MB(FYSETC_CHEETAH, FYSETC_CHEETAH_V12, FYSETC_AIO_II)
+ reset_stepper_drivers(); // Workaround for Cheetah bug
+ #endif
+ if (!isMounted()) stat = 0; // Not mounted?
+ }
+ else {
+ #if PIN_EXISTS(SD_DETECT)
+ release(); // Card is released
+ #endif
+ }
+
+ ui.media_changed(old_stat, stat); // Update the UI
+
+ if (stat) {
+ TERN_(SDCARD_EEPROM_EMULATION, settings.first_load());
+ if (old_stat == 2) { // First mount?
+ DEBUG_ECHOLNPGM("First mount.");
+ #if ENABLED(POWER_LOSS_RECOVERY)
+ recovery.check(); // Check for PLR file. (If not there then call autofile_begin)
+ #elif DISABLED(NO_SD_AUTOSTART)
+ autofile_begin(); // Look for auto0.g on the next loop
+ #endif
+ }
+ }
+ }
+ else
+ DEBUG_ECHOLNPGM("SD: No UI Detected.");
+}
+
+/**
+ * "Release" the media by clearing the 'mounted' flag.
+ * Used by M22, "Release Media", manage_media.
+ */
+void CardReader::release() {
+ // Card removed while printing? Abort!
+ if (IS_SD_PRINTING())
+ card.flag.abort_sd_printing = true;
+ else
+ endFilePrint();
+
+ flag.mounted = false;
+ flag.workDirIsRoot = true;
+ #if ALL(SDCARD_SORT_ALPHA, SDSORT_USES_RAM, SDSORT_CACHE_NAMES)
+ nrFiles = 0;
+ #endif
+}
+
+/**
+ * Open a G-code file and set Marlin to start processing it.
+ * Enqueues M23 and M24 commands to initiate a media print.
+ */
+void CardReader::openAndPrintFile(const char *name) {
+ char cmd[4 + strlen(name) + 1 + 3 + 1]; // Room for "M23 ", filename, "\n", "M24", and null
+ sprintf_P(cmd, M23_STR, name);
+ for (char *c = &cmd[4]; *c; c++) *c = tolower(*c);
+ strcat_P(cmd, PSTR("\nM24"));
+ queue.inject(cmd);
+}
+
+/**
+ * Start or resume a media print by setting the sdprinting flag.
+ * The file browser pre-sort is also purged to free up memory,
+ * since you cannot browse files during active printing.
+ * Used by M24 and anywhere Start / Resume applies.
+ */
+void CardReader::startFileprint() {
+ if (isMounted()) {
+ flag.sdprinting = true;
+ TERN_(SD_RESORT, flush_presort());
+ }
+}
+
+//
+// Run tasks upon finishing or aborting a file print.
+//
+void CardReader::endFilePrint(TERN_(SD_RESORT, const bool re_sort/*=false*/)) {
+ TERN_(ADVANCED_PAUSE_FEATURE, did_pause_print = 0);
+ TERN_(DWIN_CREALITY_LCD, HMI_flag.print_finish = flag.sdprinting);
+ flag.sdprinting = flag.abort_sd_printing = false;
+ if (isFileOpen()) file.close();
+ TERN_(SD_RESORT, if (re_sort) presort());
+}
+
+void CardReader::openLogFile(char * const path) {
+ flag.logging = DISABLED(SDCARD_READONLY);
+ IF_DISABLED(SDCARD_READONLY, openFileWrite(path));
+}
+
+//
+// Get the root-relative DOS path of the selected file
+//
+void CardReader::getAbsFilename(char *dst) {
+ *dst++ = '/';
+ uint8_t cnt = 1;
+
+ auto appendAtom = [&](SdFile &file) {
+ file.getDosName(dst);
+ while (*dst && cnt < MAXPATHNAMELENGTH) { dst++; cnt++; }
+ if (cnt < MAXPATHNAMELENGTH) { *dst = '/'; dst++; cnt++; }
+ };
+
+ LOOP_L_N(i, workDirDepth) // Loop down to current work dir
+ appendAtom(workDirParents[i]);
+
+ if (cnt < MAXPATHNAMELENGTH - (FILENAME_LENGTH) - 1) { // Leave room for filename and nul
+ appendAtom(file);
+ --dst;
+ }
+ *dst = '\0';
+}
+
+void openFailed(const char * const fname) {
+ SERIAL_ECHOLNPAIR(STR_SD_OPEN_FILE_FAIL, fname, ".");
+}
+
+void announceOpen(const uint8_t doing, const char * const path) {
+ if (doing) {
+ PORT_REDIRECT(SERIAL_ALL);
+ SERIAL_ECHO_START();
+ SERIAL_ECHOPGM("Now ");
+ serialprintPGM(doing == 1 ? PSTR("doing") : PSTR("fresh"));
+ SERIAL_ECHOLNPAIR(" file: ", path);
+ }
+}
+
+//
+// Open a file by DOS path for read
+// The 'subcall_type' flag indicates...
+// - 0 : Standard open from host or user interface.
+// - 1 : (file open) Opening a new sub-procedure.
+// - 1 : (no file open) Opening a macro (M98).
+// - 2 : Resuming from a sub-procedure
+//
+void CardReader::openFileRead(char * const path, const uint8_t subcall_type/*=0*/) {
+ if (!isMounted()) return;
+
+ switch (subcall_type) {
+ case 0: // Starting a new print. "Now fresh file: ..."
+ announceOpen(2, path);
+ TERN_(HAS_MEDIA_SUBCALLS, file_subcall_ctr = 0);
+ break;
+
+ #if HAS_MEDIA_SUBCALLS
+
+ case 1: // Starting a sub-procedure
+
+ // With no file is open it's a simple macro. "Now doing file: ..."
+ if (!isFileOpen()) { announceOpen(1, path); break; }
+
+ // Too deep? The firmware has to bail.
+ if (file_subcall_ctr > SD_PROCEDURE_DEPTH - 1) {
+ SERIAL_ERROR_MSG("Exceeded max SUBROUTINE depth:", int(SD_PROCEDURE_DEPTH));
+ kill(GET_TEXT(MSG_KILL_SUBCALL_OVERFLOW));
+ return;
+ }
+
+ // Store current filename (based on workDirParents) and position
+ getAbsFilename(proc_filenames[file_subcall_ctr]);
+ filespos[file_subcall_ctr] = sdpos;
+
+ // For sub-procedures say 'SUBROUTINE CALL target: "..." parent: "..." pos12345'
+ SERIAL_ECHO_START();
+ SERIAL_ECHOLNPAIR("SUBROUTINE CALL target:\"", path, "\" parent:\"", proc_filenames[file_subcall_ctr], "\" pos", sdpos);
+ file_subcall_ctr++;
+ break;
+
+ case 2: // Resuming previous file after sub-procedure
+ SERIAL_ECHO_MSG("END SUBROUTINE");
+ break;
+
+ #endif
+ }
+
+ endFilePrint();
+
+ SdFile *diveDir;
+ const char * const fname = diveToFile(true, diveDir, path);
+ if (!fname) return;
+
+ if (file.open(diveDir, fname, O_READ)) {
+ filesize = file.fileSize();
+ sdpos = 0;
+
+ { // Don't remove this block, as the PORT_REDIRECT is a RAII
+ PORT_REDIRECT(SERIAL_ALL);
+ SERIAL_ECHOLNPAIR(STR_SD_FILE_OPENED, fname, STR_SD_SIZE, filesize);
+ SERIAL_ECHOLNPGM(STR_SD_FILE_SELECTED);
+ }
+
+ selectFileByName(fname);
+ ui.set_status(longFilename[0] ? longFilename : fname);
+ }
+ else
+ openFailed(fname);
+}
+
+inline void echo_write_to_file(const char * const fname) {
+ SERIAL_ECHOLNPAIR(STR_SD_WRITE_TO_FILE, fname);
+}
+
+//
+// Open a file by DOS path for write
+//
+void CardReader::openFileWrite(char * const path) {
+ if (!isMounted()) return;
+
+ announceOpen(2, path);
+ TERN_(HAS_MEDIA_SUBCALLS, file_subcall_ctr = 0);
+
+ endFilePrint();
+
+ SdFile *diveDir;
+ const char * const fname = diveToFile(false, diveDir, path);
+ if (!fname) return;
+
+ #if ENABLED(SDCARD_READONLY)
+ openFailed(fname);
+ #else
+ if (file.open(diveDir, fname, O_CREAT | O_APPEND | O_WRITE | O_TRUNC)) {
+ flag.saving = true;
+ selectFileByName(fname);
+ TERN_(EMERGENCY_PARSER, emergency_parser.disable());
+ echo_write_to_file(fname);
+ ui.set_status(fname);
+ }
+ else
+ openFailed(fname);
+ #endif
+}
+
+//
+// Check if a file exists by absolute or workDir-relative path
+// If the file exists, the long name can also be fetched.
+//
+bool CardReader::fileExists(const char * const path) {
+ if (!isMounted()) return false;
+
+ DEBUG_ECHOLNPAIR("fileExists: ", path);
+
+ // Dive to the file's directory and get the base name
+ SdFile *diveDir = nullptr;
+ const char * const fname = diveToFile(false, diveDir, path);
+ if (!fname) return false;
+
+ // Get the longname of the checked file
+ //diveDir->rewind();
+ //selectByName(*diveDir, fname);
+ //diveDir->close();
+
+ // Try to open the file and return the result
+ SdFile tmpFile;
+ const bool success = tmpFile.open(diveDir, fname, O_READ);
+ if (success) tmpFile.close();
+ return success;
+}
+
+//
+// Delete a file by name in the working directory
+//
+void CardReader::removeFile(const char * const name) {
+ if (!isMounted()) return;
+
+ //endFilePrint();
+
+ SdFile *curDir;
+ const char * const fname = diveToFile(false, curDir, name);
+ if (!fname) return;
+
+ #if ENABLED(SDCARD_READONLY)
+ SERIAL_ECHOLNPAIR("Deletion failed (read-only), File: ", fname, ".");
+ #else
+ if (file.remove(curDir, fname)) {
+ SERIAL_ECHOLNPAIR("File deleted:", fname);
+ sdpos = 0;
+ TERN_(SDCARD_SORT_ALPHA, presort());
+ }
+ else
+ SERIAL_ECHOLNPAIR("Deletion failed, File: ", fname, ".");
+ #endif
+}
+
+void CardReader::report_status() {
+ if (isPrinting()) {
+ SERIAL_ECHOPAIR(STR_SD_PRINTING_BYTE, sdpos);
+ SERIAL_CHAR('/');
+ SERIAL_ECHOLN(filesize);
+ }
+ else
+ SERIAL_ECHOLNPGM(STR_SD_NOT_PRINTING);
+}
+
+void CardReader::write_command(char * const buf) {
+ char* begin = buf;
+ char* npos = nullptr;
+ char* end = buf + strlen(buf) - 1;
+
+ file.writeError = false;
+ if ((npos = strchr(buf, 'N'))) {
+ begin = strchr(npos, ' ') + 1;
+ end = strchr(npos, '*') - 1;
+ }
+ end[1] = '\r';
+ end[2] = '\n';
+ end[3] = '\0';
+ file.write(begin);
+
+ if (file.writeError) SERIAL_ERROR_MSG(STR_SD_ERR_WRITE_TO_FILE);
+}
+
+#if DISABLED(NO_SD_AUTOSTART)
+ /**
+ * Run all the auto#.g files. Called:
+ * - On boot after successful card init.
+ * - From the LCD command to Run Auto Files
+ */
+ void CardReader::autofile_begin() {
+ autofile_index = 1;
+ (void)autofile_check();
+ }
+
+ /**
+ * Run the next auto#.g file. Called:
+ * - On boot after successful card init
+ * - After finishing the previous auto#.g file
+ * - From the LCD command to begin the auto#.g files
+ *
+ * Return 'true' if an auto file was started
+ */
+ bool CardReader::autofile_check() {
+ if (!autofile_index) return false;
+
+ if (!isMounted())
+ mount();
+ else if (ENABLED(SDCARD_EEPROM_EMULATION))
+ settings.first_load();
+
+ // Don't run auto#.g when a PLR file exists
+ if (isMounted() && TERN1(POWER_LOSS_RECOVERY, !recovery.valid())) {
+ char autoname[10];
+ sprintf_P(autoname, PSTR("/auto%c.g"), '0' + autofile_index - 1);
+ if (fileExists(autoname)) {
+ cdroot();
+ openAndPrintFile(autoname);
+ autofile_index++;
+ return true;
+ }
+ }
+ autofile_cancel();
+ return false;
+ }
+#endif
+
+void CardReader::closefile(const bool store_location/*=false*/) {
+ file.sync();
+ file.close();
+ flag.saving = flag.logging = false;
+ sdpos = 0;
+ TERN_(EMERGENCY_PARSER, emergency_parser.enable());
+
+ if (store_location) {
+ //future: store printer state, filename and position for continuing a stopped print
+ // so one can unplug the printer and continue printing the next day.
+ }
+}
+
+//
+// Get info for a file in the working directory by index
+//
+void CardReader::selectFileByIndex(const uint16_t nr) {
+ #if ENABLED(SDSORT_CACHE_NAMES)
+ if (nr < sort_count) {
+ strcpy(filename, sortshort[nr]);
+ strcpy(longFilename, sortnames[nr]);
+ flag.filenameIsDir = IS_DIR(nr);
+ return;
+ }
+ #endif
+ workDir.rewind();
+ selectByIndex(workDir, nr);
+}
+
+//
+// Get info for a file in the working directory by DOS name
+//
+void CardReader::selectFileByName(const char * const match) {
+ #if ENABLED(SDSORT_CACHE_NAMES)
+ for (uint16_t nr = 0; nr < sort_count; nr++)
+ if (strcasecmp(match, sortshort[nr]) == 0) {
+ strcpy(filename, sortshort[nr]);
+ strcpy(longFilename, sortnames[nr]);
+ flag.filenameIsDir = IS_DIR(nr);
+ return;
+ }
+ #endif
+ workDir.rewind();
+ selectByName(workDir, match);
+}
+
+uint16_t CardReader::countFilesInWorkDir() {
+ workDir.rewind();
+ return countItems(workDir);
+}
+
+/**
+ * Dive to the given DOS 8.3 file path, with optional echo of the dive paths.
+ *
+ * On exit:
+ * - Your curDir pointer contains an SdFile reference to the file's directory.
+ * - If update_cwd was 'true' the workDir now points to the file's directory.
+ *
+ * Returns a pointer to the last segment (filename) of the given DOS 8.3 path.
+ *
+ * A nullptr result indicates an unrecoverable error.
+ */
+const char* CardReader::diveToFile(const bool update_cwd, SdFile*& diveDir, const char * const path, const bool echo/*=false*/) {
+ // Track both parent and subfolder
+ static SdFile newDir1, newDir2;
+ SdFile *sub = &newDir1, *startDir;
+
+ // Parsing the path string
+ const char *item_name_adr = path;
+
+ DEBUG_ECHOLNPAIR("diveToFile: path = '", path, "'");
+
+ if (path[0] == '/') { // Starting at the root directory?
+ diveDir = &root;
+ item_name_adr++;
+ DEBUG_ECHOLNPAIR("diveToFile: CWD to root: ", hex_address((void*)diveDir));
+ if (update_cwd) workDirDepth = 0; // The cwd can be updated for the benefit of sub-programs
+ }
+ else
+ diveDir = &workDir; // Dive from workDir (as set by the UI)
+
+ startDir = diveDir;
+
+ DEBUG_ECHOLNPAIR("diveToFile: startDir = ", hex_address((void*)startDir));
+
+ while (item_name_adr) {
+ // Find next subdirectory delimiter
+ char * const name_end = strchr(item_name_adr, '/');
+
+ // Last atom in the path? Item found.
+ if (name_end <= item_name_adr) break;
+
+ // Set subDirName
+ const uint8_t len = name_end - item_name_adr;
+ char dosSubdirname[len + 1];
+ strncpy(dosSubdirname, item_name_adr, len);
+ dosSubdirname[len] = 0;
+
+ if (echo) SERIAL_ECHOLN(dosSubdirname);
+
+ DEBUG_ECHOLNPAIR("diveToFile: sub = ", hex_address((void*)sub));
+
+ // Open diveDir (closing first)
+ sub->close();
+ if (!sub->open(diveDir, dosSubdirname, O_READ)) {
+ openFailed(dosSubdirname);
+ item_name_adr = nullptr;
+ break;
+ }
+
+ // Close diveDir if not at starting-point
+ if (diveDir != startDir) {
+ DEBUG_ECHOLNPAIR("diveToFile: closing diveDir: ", hex_address((void*)diveDir));
+ diveDir->close();
+ }
+
+ // diveDir now subDir
+ diveDir = sub;
+ DEBUG_ECHOLNPAIR("diveToFile: diveDir = sub: ", hex_address((void*)diveDir));
+
+ // Update workDirParents and workDirDepth
+ if (update_cwd) {
+ DEBUG_ECHOLNPAIR("diveToFile: update_cwd");
+ if (workDirDepth < MAX_DIR_DEPTH)
+ workDirParents[workDirDepth++] = *diveDir;
+ }
+
+ // Point sub at the other scratch object
+ sub = (diveDir != &newDir1) ? &newDir1 : &newDir2;
+ DEBUG_ECHOLNPAIR("diveToFile: swapping sub = ", hex_address((void*)sub));
+
+ // Next path atom address
+ item_name_adr = name_end + 1;
+ }
+
+ if (update_cwd) {
+ workDir = *diveDir;
+ DEBUG_ECHOLNPAIR("diveToFile: final workDir = ", hex_address((void*)diveDir));
+ flag.workDirIsRoot = (workDirDepth == 0);
+ TERN_(SDCARD_SORT_ALPHA, presort());
+ }
+
+ return item_name_adr;
+}
+
+void CardReader::cd(const char * relpath) {
+ SdFile newDir;
+ SdFile *parent = workDir.isOpen() ? &workDir : &root;
+
+ if (newDir.open(parent, relpath, O_READ)) {
+ workDir = newDir;
+ flag.workDirIsRoot = false;
+ if (workDirDepth < MAX_DIR_DEPTH)
+ workDirParents[workDirDepth++] = workDir;
+ TERN_(SDCARD_SORT_ALPHA, presort());
+ }
+ else {
+ SERIAL_ECHO_START();
+ SERIAL_ECHOLNPAIR(STR_SD_CANT_ENTER_SUBDIR, relpath);
+ }
+}
+
+int8_t CardReader::cdup() {
+ if (workDirDepth > 0) { // At least 1 dir has been saved
+ workDir = --workDirDepth ? workDirParents[workDirDepth - 1] : root; // Use parent, or root if none
+ TERN_(SDCARD_SORT_ALPHA, presort());
+ }
+ if (!workDirDepth) flag.workDirIsRoot = true;
+ return workDirDepth;
+}
+
+void CardReader::cdroot() {
+ workDir = root;
+ flag.workDirIsRoot = true;
+ TERN_(SDCARD_SORT_ALPHA, presort());
+}
+
+#if ENABLED(SDCARD_SORT_ALPHA)
+
+ /**
+ * Get the name of a file in the working directory by sort-index
+ */
+ void CardReader::getfilename_sorted(const uint16_t nr) {
+ selectFileByIndex(TERN1(SDSORT_GCODE, sort_alpha) && (nr < sort_count)
+ ? sort_order[nr] : nr);
+ }
+
+ #if ENABLED(SDSORT_USES_RAM)
+ #if ENABLED(SDSORT_DYNAMIC_RAM)
+ // Use dynamic method to copy long filename
+ #define SET_SORTNAME(I) (sortnames[I] = strdup(longest_filename()))
+ #if ENABLED(SDSORT_CACHE_NAMES)
+ // When caching also store the short name, since
+ // we're replacing the selectFileByIndex() behavior.
+ #define SET_SORTSHORT(I) (sortshort[I] = strdup(filename))
+ #else
+ #define SET_SORTSHORT(I) NOOP
+ #endif
+ #else
+ // Copy filenames into the static array
+ #define _SET_SORTNAME(I) strncpy(sortnames[I], longest_filename(), SORTED_LONGNAME_MAXLEN)
+ #if SORTED_LONGNAME_MAXLEN == LONG_FILENAME_LENGTH
+ // Short name sorting always use LONG_FILENAME_LENGTH with no trailing nul
+ #define SET_SORTNAME(I) _SET_SORTNAME(I)
+ #else
+ // Copy multiple name blocks. Add a nul for the longest case.
+ #define SET_SORTNAME(I) do{ _SET_SORTNAME(I); sortnames[I][SORTED_LONGNAME_MAXLEN] = '\0'; }while(0)
+ #endif
+ #if ENABLED(SDSORT_CACHE_NAMES)
+ #define SET_SORTSHORT(I) strcpy(sortshort[I], filename)
+ #else
+ #define SET_SORTSHORT(I) NOOP
+ #endif
+ #endif
+ #endif
+
+ /**
+ * Read all the files and produce a sort key
+ *
+ * We can do this in 3 ways...
+ * - Minimal RAM: Read two filenames at a time sorting along...
+ * - Some RAM: Buffer the directory just for this sort
+ * - Most RAM: Buffer the directory and return filenames from RAM
+ */
+ void CardReader::presort() {
+
+ // Throw away old sort index
+ flush_presort();
+
+ // Sorting may be turned off
+ if (TERN0(SDSORT_GCODE, !sort_alpha)) return;
+
+ // If there are files, sort up to the limit
+ uint16_t fileCnt = countFilesInWorkDir();
+ if (fileCnt > 0) {
+
+ // Never sort more than the max allowed
+ // If you use folders to organize, 20 may be enough
+ NOMORE(fileCnt, uint16_t(SDSORT_LIMIT));
+
+ // Sort order is always needed. May be static or dynamic.
+ TERN_(SDSORT_DYNAMIC_RAM, sort_order = new uint8_t[fileCnt]);
+
+ // Use RAM to store the entire directory during pre-sort.
+ // SDSORT_LIMIT should be set to prevent over-allocation.
+ #if ENABLED(SDSORT_USES_RAM)
+
+ // If using dynamic ram for names, allocate on the heap.
+ #if ENABLED(SDSORT_CACHE_NAMES)
+ #if ENABLED(SDSORT_DYNAMIC_RAM)
+ sortshort = new char*[fileCnt];
+ sortnames = new char*[fileCnt];
+ #endif
+ #elif ENABLED(SDSORT_USES_STACK)
+ char sortnames[fileCnt][SORTED_LONGNAME_STORAGE];
+ #endif
+
+ // Folder sorting needs 1 bit per entry for flags.
+ #if HAS_FOLDER_SORTING
+ #if ENABLED(SDSORT_DYNAMIC_RAM)
+ isDir = new uint8_t[(fileCnt + 7) >> 3];
+ #elif ENABLED(SDSORT_USES_STACK)
+ uint8_t isDir[(fileCnt + 7) >> 3];
+ #endif
+ #endif
+
+ #else // !SDSORT_USES_RAM
+
+ // By default re-read the names from SD for every compare
+ // retaining only two filenames at a time. This is very
+ // slow but is safest and uses minimal RAM.
+ char name1[LONG_FILENAME_LENGTH];
+
+ #endif
+
+ if (fileCnt > 1) {
+
+ // Init sort order.
+ for (uint16_t i = 0; i < fileCnt; i++) {
+ sort_order[i] = i;
+ // If using RAM then read all filenames now.
+ #if ENABLED(SDSORT_USES_RAM)
+ selectFileByIndex(i);
+ SET_SORTNAME(i);
+ SET_SORTSHORT(i);
+ // char out[30];
+ // sprintf_P(out, PSTR("---- %i %s %s"), i, flag.filenameIsDir ? "D" : " ", sortnames[i]);
+ // SERIAL_ECHOLN(out);
+ #if HAS_FOLDER_SORTING
+ const uint16_t bit = i & 0x07, ind = i >> 3;
+ if (bit == 0) isDir[ind] = 0x00;
+ if (flag.filenameIsDir) SBI(isDir[ind], bit);
+ #endif
+ #endif
+ }
+
+ // Bubble Sort
+ for (uint16_t i = fileCnt; --i;) {
+ bool didSwap = false;
+ uint8_t o1 = sort_order[0];
+ #if DISABLED(SDSORT_USES_RAM)
+ selectFileByIndex(o1); // Pre-fetch the first entry and save it
+ strcpy(name1, longest_filename()); // so the loop only needs one fetch
+ TERN_(HAS_FOLDER_SORTING, bool dir1 = flag.filenameIsDir);
+ #endif
+
+ for (uint16_t j = 0; j < i; ++j) {
+ const uint16_t o2 = sort_order[j + 1];
+
+ // Compare names from the array or just the two buffered names
+ #if ENABLED(SDSORT_USES_RAM)
+ #define _SORT_CMP_NODIR() (strcasecmp(sortnames[o1], sortnames[o2]) > 0)
+ #else
+ #define _SORT_CMP_NODIR() (strcasecmp(name1, name2) > 0)
+ #endif
+
+ #if HAS_FOLDER_SORTING
+ #if ENABLED(SDSORT_USES_RAM)
+ // Folder sorting needs an index and bit to test for folder-ness.
+ #define _SORT_CMP_DIR(fs) (IS_DIR(o1) == IS_DIR(o2) ? _SORT_CMP_NODIR() : IS_DIR(fs > 0 ? o1 : o2))
+ #else
+ #define _SORT_CMP_DIR(fs) ((dir1 == flag.filenameIsDir) ? _SORT_CMP_NODIR() : (fs > 0 ? dir1 : !dir1))
+ #endif
+ #endif
+
+ // The most economical method reads names as-needed
+ // throughout the loop. Slow if there are many.
+ #if DISABLED(SDSORT_USES_RAM)
+ selectFileByIndex(o2);
+ const bool dir2 = flag.filenameIsDir;
+ char * const name2 = longest_filename(); // use the string in-place
+ #endif // !SDSORT_USES_RAM
+
+ // Sort the current pair according to settings.
+ if (
+ #if HAS_FOLDER_SORTING
+ #if ENABLED(SDSORT_GCODE)
+ sort_folders ? _SORT_CMP_DIR(sort_folders) : _SORT_CMP_NODIR()
+ #else
+ _SORT_CMP_DIR(FOLDER_SORTING)
+ #endif
+ #else
+ _SORT_CMP_NODIR()
+ #endif
+ ) {
+ // Reorder the index, indicate that sorting happened
+ // Note that the next o1 will be the current o1. No new fetch needed.
+ sort_order[j] = o2;
+ sort_order[j + 1] = o1;
+ didSwap = true;
+ }
+ else {
+ // The next o1 is the current o2. No new fetch needed.
+ o1 = o2;
+ #if DISABLED(SDSORT_USES_RAM)
+ TERN_(HAS_FOLDER_SORTING, dir1 = dir2);
+ strcpy(name1, name2);
+ #endif
+ }
+ }
+ if (!didSwap) break;
+ }
+ // Using RAM but not keeping names around
+ #if ENABLED(SDSORT_USES_RAM) && DISABLED(SDSORT_CACHE_NAMES)
+ #if ENABLED(SDSORT_DYNAMIC_RAM)
+ for (uint16_t i = 0; i < fileCnt; ++i) free(sortnames[i]);
+ TERN_(HAS_FOLDER_SORTING, free(isDir));
+ #endif
+ #endif
+ }
+ else {
+ sort_order[0] = 0;
+ #if BOTH(SDSORT_USES_RAM, SDSORT_CACHE_NAMES)
+ #if ENABLED(SDSORT_DYNAMIC_RAM)
+ sortnames = new char*[1];
+ sortshort = new char*[1];
+ isDir = new uint8_t[1];
+ #endif
+ selectFileByIndex(0);
+ SET_SORTNAME(0);
+ SET_SORTSHORT(0);
+ isDir[0] = flag.filenameIsDir;
+ #endif
+ }
+
+ sort_count = fileCnt;
+ }
+ }
+
+ void CardReader::flush_presort() {
+ if (sort_count > 0) {
+ #if ENABLED(SDSORT_DYNAMIC_RAM)
+ delete sort_order;
+ #if ENABLED(SDSORT_CACHE_NAMES)
+ LOOP_L_N(i, sort_count) {
+ free(sortshort[i]); // strdup
+ free(sortnames[i]); // strdup
+ }
+ delete sortshort;
+ delete sortnames;
+ #endif
+ #endif
+ sort_count = 0;
+ }
+ }
+
+#endif // SDCARD_SORT_ALPHA
+
+uint16_t CardReader::get_num_Files() {
+ if (!isMounted()) return 0;
+ return (
+ #if ALL(SDCARD_SORT_ALPHA, SDSORT_USES_RAM, SDSORT_CACHE_NAMES)
+ nrFiles // no need to access the SD card for filenames
+ #else
+ countFilesInWorkDir()
+ #endif
+ );
+}
+
+//
+// Return from procedure or close out the Print Job
+//
+void CardReader::fileHasFinished() {
+ planner.synchronize();
+ file.close();
+
+ #if HAS_MEDIA_SUBCALLS
+ if (file_subcall_ctr > 0) { // Resume calling file after closing procedure
+ file_subcall_ctr--;
+ openFileRead(proc_filenames[file_subcall_ctr], 2); // 2 = Returning from sub-procedure
+ setIndex(filespos[file_subcall_ctr]);
+ startFileprint();
+ return;
+ }
+ #endif
+
+ endFilePrint(TERN_(SD_RESORT, true));
+ marlin_state = MF_SD_COMPLETE;
+}
+
+#if ENABLED(AUTO_REPORT_SD_STATUS)
+ AutoReporter<CardReader::AutoReportSD> CardReader::auto_reporter;
+#endif
+
+#if ENABLED(POWER_LOSS_RECOVERY)
+
+ bool CardReader::jobRecoverFileExists() {
+ const bool exists = recovery.file.open(&root, recovery.filename, O_READ);
+ if (exists) recovery.file.close();
+ return exists;
+ }
+
+ void CardReader::openJobRecoveryFile(const bool read) {
+ if (!isMounted()) return;
+ if (recovery.file.isOpen()) return;
+ if (!recovery.file.open(&root, recovery.filename, read ? O_READ : O_CREAT | O_WRITE | O_TRUNC | O_SYNC))
+ openFailed(recovery.filename);
+ else if (!read)
+ echo_write_to_file(recovery.filename);
+ }
+
+ // Removing the job recovery file currently requires closing
+ // the file being printed, so during SD printing the file should
+ // be zeroed and written instead of deleted.
+ void CardReader::removeJobRecoveryFile() {
+ if (jobRecoverFileExists()) {
+ recovery.init();
+ removeFile(recovery.filename);
+ #if ENABLED(DEBUG_POWER_LOSS_RECOVERY)
+ SERIAL_ECHOPGM("Power-loss file delete");
+ serialprintPGM(jobRecoverFileExists() ? PSTR(" failed.\n") : PSTR("d.\n"));
+ #endif
+ }
+ }
+
+#endif // POWER_LOSS_RECOVERY
+
+#endif // SDSUPPORT
diff --git a/Marlin/src/sd/cardreader.h b/Marlin/src/sd/cardreader.h
new file mode 100644
index 0000000..0a89bbb
--- /dev/null
+++ b/Marlin/src/sd/cardreader.h
@@ -0,0 +1,302 @@
+/**
+ * Marlin 3D Printer Firmware
+ * Copyright (c) 2020 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 <https://www.gnu.org/licenses/>.
+ *
+ */
+#pragma once
+
+#include "../inc/MarlinConfig.h"
+
+#define IFSD(A,B) TERN(SDSUPPORT,A,B)
+
+#if ENABLED(SDSUPPORT)
+
+extern const char M23_STR[], M24_STR[];
+
+#if BOTH(SDCARD_SORT_ALPHA, SDSORT_DYNAMIC_RAM)
+ #define SD_RESORT 1
+#endif
+
+#if ENABLED(SDCARD_RATHERRECENTFIRST) && DISABLED(SDCARD_SORT_ALPHA)
+ #define SD_ORDER(N,C) ((C) - 1 - (N))
+#else
+ #define SD_ORDER(N,C) N
+#endif
+
+#define MAX_DIR_DEPTH 10 // Maximum folder depth
+#define MAXDIRNAMELENGTH 8 // DOS folder name size
+#define MAXPATHNAMELENGTH (1 + (MAXDIRNAMELENGTH + 1) * (MAX_DIR_DEPTH) + 1 + FILENAME_LENGTH) // "/" + N * ("ADIRNAME/") + "filename.ext"
+
+#include "SdFile.h"
+
+typedef struct {
+ bool saving:1,
+ logging:1,
+ sdprinting:1,
+ mounted:1,
+ filenameIsDir:1,
+ workDirIsRoot:1,
+ abort_sd_printing:1
+ #if ENABLED(BINARY_FILE_TRANSFER)
+ , binary_mode:1
+ #endif
+ ;
+} card_flags_t;
+
+#if ENABLED(AUTO_REPORT_SD_STATUS)
+ #include "../libs/autoreport.h"
+#endif
+
+class CardReader {
+public:
+ static card_flags_t flag; // Flags (above)
+ static char filename[FILENAME_LENGTH], // DOS 8.3 filename of the selected item
+ longFilename[LONG_FILENAME_LENGTH]; // Long name of the selected item
+
+ // Fast! binary file transfer
+ #if ENABLED(BINARY_FILE_TRANSFER)
+ #if HAS_MULTI_SERIAL
+ static int8_t transfer_port_index;
+ #else
+ static constexpr int8_t transfer_port_index = 0;
+ #endif
+ #endif
+
+ // // // Methods // // //
+
+ CardReader();
+
+ static SdFile getroot() { return root; }
+
+ static void mount();
+ static void release();
+ static inline bool isMounted() { return flag.mounted; }
+ static void ls();
+
+ // Handle media insert/remove
+ static void manage_media();
+
+ // SD Card Logging
+ static void openLogFile(char * const path);
+ static void write_command(char * const buf);
+
+ #if DISABLED(NO_SD_AUTOSTART) // Auto-Start auto#.g file handling
+ static uint8_t autofile_index; // Next auto#.g index to run, plus one. Ignored by autofile_check when zero.
+ static void autofile_begin(); // Begin check. Called automatically after boot-up.
+ static bool autofile_check(); // Check for the next auto-start file and run it.
+ static inline void autofile_cancel() { autofile_index = 0; }
+ #endif
+
+ // Basic file ops
+ static void openFileRead(char * const path, const uint8_t subcall=0);
+ static void openFileWrite(char * const path);
+ static void closefile(const bool store_location=false);
+ static bool fileExists(const char * const name);
+ static void removeFile(const char * const name);
+
+ static inline char* longest_filename() { return longFilename[0] ? longFilename : filename; }
+ #if ENABLED(LONG_FILENAME_HOST_SUPPORT)
+ static void printLongPath(char * const path); // Used by M33
+ #endif
+
+ // Working Directory for SD card menu
+ static void cdroot();
+ static void cd(const char *relpath);
+ static int8_t cdup();
+ static uint16_t countFilesInWorkDir();
+ static uint16_t get_num_Files();
+
+ // Select a file
+ static void selectFileByIndex(const uint16_t nr);
+ static void selectFileByName(const char* const match);
+
+ // Print job
+ static void openAndPrintFile(const char *name); // (working directory)
+ static void fileHasFinished();
+ static void getAbsFilename(char *dst);
+ static void printFilename();
+ static void startFileprint();
+ static void endFilePrint(TERN_(SD_RESORT, const bool re_sort=false));
+ static void report_status();
+ static inline void pauseSDPrint() { flag.sdprinting = false; }
+ static inline bool isPaused() { return isFileOpen() && !flag.sdprinting; }
+ static inline bool isPrinting() { return flag.sdprinting; }
+ #if HAS_PRINT_PROGRESS_PERMYRIAD
+ static inline uint16_t permyriadDone() { return (isFileOpen() && filesize) ? sdpos / ((filesize + 9999) / 10000) : 0; }
+ #endif
+ static inline uint8_t percentDone() { return (isFileOpen() && filesize) ? sdpos / ((filesize + 99) / 100) : 0; }
+
+ // Helper for open and remove
+ static const char* diveToFile(const bool update_cwd, SdFile*& curDir, const char * const path, const bool echo=false);
+
+ #if ENABLED(SDCARD_SORT_ALPHA)
+ static void presort();
+ static void getfilename_sorted(const uint16_t nr);
+ #if ENABLED(SDSORT_GCODE)
+ FORCE_INLINE static void setSortOn(bool b) { sort_alpha = b; presort(); }
+ FORCE_INLINE static void setSortFolders(int i) { sort_folders = i; presort(); }
+ //FORCE_INLINE static void setSortReverse(bool b) { sort_reverse = b; }
+ #endif
+ #else
+ FORCE_INLINE static void getfilename_sorted(const uint16_t nr) { selectFileByIndex(nr); }
+ #endif
+
+ #if ENABLED(POWER_LOSS_RECOVERY)
+ static bool jobRecoverFileExists();
+ static void openJobRecoveryFile(const bool read);
+ static void removeJobRecoveryFile();
+ #endif
+
+ static inline bool isFileOpen() { return isMounted() && file.isOpen(); }
+ static inline uint32_t getIndex() { return sdpos; }
+ static inline uint32_t getFileSize() { return filesize; }
+ static inline bool eof() { return sdpos >= filesize; }
+ static inline void setIndex(const uint32_t index) { file.seekSet((sdpos = index)); }
+ static inline char* getWorkDirName() { workDir.getDosName(filename); return filename; }
+ static inline int16_t get() { int16_t out = (int16_t)file.read(); sdpos = file.curPosition(); return out; }
+ static inline int16_t read(void* buf, uint16_t nbyte) { return file.isOpen() ? file.read(buf, nbyte) : -1; }
+ static inline int16_t write(void* buf, uint16_t nbyte) { return file.isOpen() ? file.write(buf, nbyte) : -1; }
+
+ static Sd2Card& getSd2Card() { return sd2card; }
+
+ #if ENABLED(AUTO_REPORT_SD_STATUS)
+ //
+ // SD Auto Reporting
+ //
+ struct AutoReportSD { static void report() { report_status(); } };
+ static AutoReporter<AutoReportSD> auto_reporter;
+ #endif
+
+private:
+ //
+ // Working directory and parents
+ //
+ static SdFile root, workDir, workDirParents[MAX_DIR_DEPTH];
+ static uint8_t workDirDepth;
+
+ //
+ // Alphabetical file and folder sorting
+ //
+ #if ENABLED(SDCARD_SORT_ALPHA)
+ static uint16_t sort_count; // Count of sorted items in the current directory
+ #if ENABLED(SDSORT_GCODE)
+ static bool sort_alpha; // Flag to enable / disable the feature
+ static int sort_folders; // Folder sorting before/none/after
+ //static bool sort_reverse; // Flag to enable / disable reverse sorting
+ #endif
+
+ // By default the sort index is static
+ #if ENABLED(SDSORT_DYNAMIC_RAM)
+ static uint8_t *sort_order;
+ #else
+ static uint8_t sort_order[SDSORT_LIMIT];
+ #endif
+
+ #if BOTH(SDSORT_USES_RAM, SDSORT_CACHE_NAMES) && DISABLED(SDSORT_DYNAMIC_RAM)
+ #define SORTED_LONGNAME_MAXLEN (SDSORT_CACHE_VFATS) * (FILENAME_LENGTH)
+ #define SORTED_LONGNAME_STORAGE (SORTED_LONGNAME_MAXLEN + 1)
+ #else
+ #define SORTED_LONGNAME_MAXLEN LONG_FILENAME_LENGTH
+ #define SORTED_LONGNAME_STORAGE SORTED_LONGNAME_MAXLEN
+ #endif
+
+ // Cache filenames to speed up SD menus.
+ #if ENABLED(SDSORT_USES_RAM)
+
+ // If using dynamic ram for names, allocate on the heap.
+ #if ENABLED(SDSORT_CACHE_NAMES)
+ static uint16_t nrFiles; // Cache the total count
+ #if ENABLED(SDSORT_DYNAMIC_RAM)
+ static char **sortshort, **sortnames;
+ #else
+ static char sortshort[SDSORT_LIMIT][FILENAME_LENGTH];
+ #endif
+ #endif
+
+ #if (ENABLED(SDSORT_CACHE_NAMES) && DISABLED(SDSORT_DYNAMIC_RAM)) || NONE(SDSORT_CACHE_NAMES, SDSORT_USES_STACK)
+ static char sortnames[SDSORT_LIMIT][SORTED_LONGNAME_STORAGE];
+ #endif
+
+ // Folder sorting uses an isDir array when caching items.
+ #if HAS_FOLDER_SORTING
+ #if ENABLED(SDSORT_DYNAMIC_RAM)
+ static uint8_t *isDir;
+ #elif ENABLED(SDSORT_CACHE_NAMES) || DISABLED(SDSORT_USES_STACK)
+ static uint8_t isDir[(SDSORT_LIMIT+7)>>3];
+ #endif
+ #endif
+
+ #endif // SDSORT_USES_RAM
+
+ #endif // SDCARD_SORT_ALPHA
+
+ static Sd2Card sd2card;
+ static SdVolume volume;
+ static SdFile file;
+
+ static uint32_t filesize, // Total size of the current file, in bytes
+ sdpos; // Index most recently read (one behind file.getPos)
+
+ //
+ // Procedure calls to other files
+ //
+ #if HAS_MEDIA_SUBCALLS
+ static uint8_t file_subcall_ctr;
+ static uint32_t filespos[SD_PROCEDURE_DEPTH];
+ static char proc_filenames[SD_PROCEDURE_DEPTH][MAXPATHNAMELENGTH];
+ #endif
+
+ //
+ // Directory items
+ //
+ static bool is_dir_or_gcode(const dir_t &p);
+ static int countItems(SdFile dir);
+ static void selectByIndex(SdFile dir, const uint8_t index);
+ static void selectByName(SdFile dir, const char * const match);
+ static void printListing(SdFile parent, const char * const prepend=nullptr);
+
+ #if ENABLED(SDCARD_SORT_ALPHA)
+ static void flush_presort();
+ #endif
+};
+
+#if ENABLED(USB_FLASH_DRIVE_SUPPORT)
+ #define IS_SD_INSERTED() Sd2Card::isInserted()
+#elif PIN_EXISTS(SD_DETECT)
+ #define IS_SD_INSERTED() (READ(SD_DETECT_PIN) == SD_DETECT_STATE)
+#else
+ // No card detect line? Assume the card is inserted.
+ #define IS_SD_INSERTED() true
+#endif
+
+#define IS_SD_PRINTING() card.flag.sdprinting
+#define IS_SD_PAUSED() card.isPaused()
+#define IS_SD_FILE_OPEN() card.isFileOpen()
+
+extern CardReader card;
+
+#else // !SDSUPPORT
+
+#define IS_SD_PRINTING() false
+#define IS_SD_PAUSED() false
+#define IS_SD_FILE_OPEN() false
+
+#define LONG_FILENAME_LENGTH 0
+
+#endif // !SDSUPPORT
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 0000000..c6e3c73
--- /dev/null
+++ b/Marlin/src/sd/usb_flashdrive/Sd2Card_FlashDrive.cpp
@@ -0,0 +1,326 @@
+/**
+ * Marlin 3D Printer Firmware
+ * Copyright (c) 2020 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 <https://www.gnu.org/licenses/>.
+ *
+ */
+
+#include "../../inc/MarlinConfigPre.h"
+
+/**
+ * Adjust USB_DEBUG to select debugging verbosity.
+ * 0 - no debug messages
+ * 1 - basic insertion/removal messages
+ * 2 - show USB state transitions
+ * 3 - perform block range checking
+ * 4 - print each block access
+ */
+#define USB_DEBUG 1
+#define USB_STARTUP_DELAY 0
+
+// uncomment to get 'printf' console debugging. NOT FOR UNO!
+//#define HOST_DEBUG(...) {char s[255]; sprintf(s,__VA_ARGS__); SERIAL_ECHOLNPAIR("UHS:",s);}
+//#define BS_HOST_DEBUG(...) {char s[255]; sprintf(s,__VA_ARGS__); SERIAL_ECHOLNPAIR("UHS:",s);}
+//#define MAX_HOST_DEBUG(...) {char s[255]; sprintf(s,__VA_ARGS__); SERIAL_ECHOLNPAIR("UHS:",s);}
+
+#if ENABLED(USB_FLASH_DRIVE_SUPPORT)
+
+#include "../../MarlinCore.h"
+#include "../../core/serial.h"
+#include "../../module/temperature.h"
+
+#if DISABLED(USE_OTG_USB_HOST) && !PINS_EXIST(USB_CS, USB_INTR)
+ #error "USB_FLASH_DRIVE_SUPPORT requires USB_CS_PIN and USB_INTR_PIN to be defined."
+#endif
+
+#if ENABLED(USE_UHS3_USB)
+ #define NO_AUTO_SPEED
+ #define UHS_MAX3421E_SPD 8000000 >> SD_SPI_SPEED
+ #define UHS_DEVICE_WINDOWS_USB_SPEC_VIOLATION_DESCRIPTOR_DEVICE 1
+ #define UHS_HOST_MAX_INTERFACE_DRIVERS 2
+ #define MASS_MAX_SUPPORTED_LUN 1
+ #define USB_HOST_SERIAL MYSERIAL0
+
+ // Workaround for certain issues with UHS3
+ #define SKIP_PAGE3F // Required for IOGEAR media adapter
+ #define USB_NO_TEST_UNIT_READY // Required for removable media adapter
+ #define USB_HOST_MANUAL_POLL // Optimization to shut off IRQ automatically
+
+ // Workarounds for keeping Marlin's watchdog timer from barking...
+ void marlin_yield() {
+ thermalManager.manage_heater();
+ }
+ #define SYSTEM_OR_SPECIAL_YIELD(...) marlin_yield();
+ #define delay(x) safe_delay(x)
+
+ #define LOAD_USB_HOST_SYSTEM
+ #define LOAD_USB_HOST_SHIELD
+ #define LOAD_UHS_BULK_STORAGE
+
+ #define MARLIN_UHS_WRITE_SS(v) WRITE(USB_CS_PIN, v)
+ #define MARLIN_UHS_READ_IRQ() READ(USB_INTR_PIN)
+
+ #include "lib-uhs3/UHS_host/UHS_host.h"
+
+ MAX3421E_HOST usb(USB_CS_PIN, USB_INTR_PIN);
+ UHS_Bulk_Storage bulk(&usb);
+
+ #define UHS_START (usb.Init() == 0)
+ #define UHS_STATE(state) UHS_USB_HOST_STATE_##state
+#elif ENABLED(USE_OTG_USB_HOST)
+
+ #if HAS_SD_HOST_DRIVE
+ #include HAL_PATH(../../HAL, msc_sd.h)
+ #endif
+
+ #include HAL_PATH(../../HAL, usb_host.h)
+
+ #define UHS_START usb.start()
+ #define rREVISION 0
+ #define UHS_STATE(state) USB_STATE_##state
+#else
+ #include "lib-uhs2/Usb.h"
+ #include "lib-uhs2/masstorage.h"
+
+ USB usb;
+ BulkOnly bulk(&usb);
+
+ #define UHS_START usb.start()
+ #define UHS_STATE(state) USB_STATE_##state
+#endif
+
+#include "Sd2Card_FlashDrive.h"
+
+#include "../../lcd/marlinui.h"
+
+static enum {
+ UNINITIALIZED,
+ DO_STARTUP,
+ WAIT_FOR_DEVICE,
+ WAIT_FOR_LUN,
+ MEDIA_READY,
+ MEDIA_ERROR
+} state;
+
+#if USB_DEBUG >= 3
+ uint32_t lun0_capacity;
+#endif
+
+bool Sd2Card::usbStartup() {
+ if (state <= DO_STARTUP) {
+ SERIAL_ECHOPGM("Starting USB host...");
+ if (!UHS_START) {
+ SERIAL_ECHOLNPGM(" failed.");
+ LCD_MESSAGEPGM(MSG_MEDIA_USB_FAILED);
+ return false;
+ }
+
+ // SPI quick test - check revision register
+ switch (usb.regRd(rREVISION)) {
+ case 0x01: SERIAL_ECHOLNPGM("rev.01 started"); break;
+ case 0x12: SERIAL_ECHOLNPGM("rev.02 started"); break;
+ case 0x13: SERIAL_ECHOLNPGM("rev.03 started"); break;
+ default: SERIAL_ECHOLNPGM("started. rev unknown."); break;
+ }
+ state = WAIT_FOR_DEVICE;
+ }
+ return true;
+}
+
+// The USB library needs to be called periodically to detect USB thumbdrive
+// insertion and removals. Call this idle() function periodically to allow
+// the USB library to monitor for such events. This function also takes care
+// of initializing the USB library for the first time.
+
+void Sd2Card::idle() {
+ usb.Task();
+
+ const uint8_t task_state = usb.getUsbTaskState();
+
+ #if USB_DEBUG >= 2
+ if (state > DO_STARTUP) {
+ static uint8_t laststate = 232;
+ if (task_state != laststate) {
+ laststate = task_state;
+ #define UHS_USB_DEBUG(x) case UHS_STATE(x): SERIAL_ECHOLNPGM(#x); break
+ switch (task_state) {
+ UHS_USB_DEBUG(IDLE);
+ UHS_USB_DEBUG(RESET_DEVICE);
+ UHS_USB_DEBUG(RESET_NOT_COMPLETE);
+ UHS_USB_DEBUG(DEBOUNCE);
+ UHS_USB_DEBUG(DEBOUNCE_NOT_COMPLETE);
+ UHS_USB_DEBUG(WAIT_SOF);
+ UHS_USB_DEBUG(ERROR);
+ UHS_USB_DEBUG(CONFIGURING);
+ UHS_USB_DEBUG(CONFIGURING_DONE);
+ UHS_USB_DEBUG(RUNNING);
+ default:
+ SERIAL_ECHOLNPAIR("UHS_USB_HOST_STATE: ", task_state);
+ break;
+ }
+ }
+ }
+ #endif
+
+ static millis_t next_state_ms = millis();
+
+ #define GOTO_STATE_AFTER_DELAY(STATE, DELAY) do{ state = STATE; next_state_ms = millis() + DELAY; }while(0)
+
+ if (ELAPSED(millis(), next_state_ms)) {
+ GOTO_STATE_AFTER_DELAY(state, 250); // Default delay
+
+ switch (state) {
+
+ case UNINITIALIZED:
+ #ifndef MANUAL_USB_STARTUP
+ GOTO_STATE_AFTER_DELAY( DO_STARTUP, USB_STARTUP_DELAY );
+ #endif
+ break;
+
+ case DO_STARTUP: usbStartup(); break;
+
+ case WAIT_FOR_DEVICE:
+ if (task_state == UHS_STATE(RUNNING)) {
+ #if USB_DEBUG >= 1
+ SERIAL_ECHOLNPGM("USB device inserted");
+ #endif
+ GOTO_STATE_AFTER_DELAY( WAIT_FOR_LUN, 250 );
+ }
+ break;
+
+ case WAIT_FOR_LUN:
+ /* USB device is inserted, but if it is an SD card,
+ * adapter it may not have an SD card in it yet. */
+ if (bulk.LUNIsGood(0)) {
+ #if USB_DEBUG >= 1
+ SERIAL_ECHOLNPGM("LUN is good");
+ #endif
+ GOTO_STATE_AFTER_DELAY( MEDIA_READY, 100 );
+ }
+ else {
+ #ifdef USB_HOST_MANUAL_POLL
+ // Make sure we catch disconnect events
+ usb.busprobe();
+ usb.VBUS_changed();
+ #endif
+ #if USB_DEBUG >= 1
+ SERIAL_ECHOLNPGM("Waiting for media");
+ #endif
+ LCD_MESSAGEPGM(MSG_MEDIA_WAITING);
+ GOTO_STATE_AFTER_DELAY(state, 2000);
+ }
+ break;
+
+ case MEDIA_READY: break;
+ case MEDIA_ERROR: break;
+ }
+
+ if (state > WAIT_FOR_DEVICE && task_state != UHS_STATE(RUNNING)) {
+ // Handle device removal events
+ #if USB_DEBUG >= 1
+ SERIAL_ECHOLNPGM("USB device removed");
+ #endif
+ if (state != MEDIA_READY)
+ LCD_MESSAGEPGM(MSG_MEDIA_USB_REMOVED);
+ GOTO_STATE_AFTER_DELAY(WAIT_FOR_DEVICE, 0);
+ }
+
+ else if (state > WAIT_FOR_LUN && !bulk.LUNIsGood(0)) {
+ // Handle media removal events
+ #if USB_DEBUG >= 1
+ SERIAL_ECHOLNPGM("Media removed");
+ #endif
+ LCD_MESSAGEPGM(MSG_MEDIA_REMOVED);
+ GOTO_STATE_AFTER_DELAY(WAIT_FOR_DEVICE, 0);
+ }
+
+ else if (task_state == UHS_STATE(ERROR)) {
+ LCD_MESSAGEPGM(MSG_MEDIA_READ_ERROR);
+ GOTO_STATE_AFTER_DELAY(MEDIA_ERROR, 0);
+ }
+ }
+}
+
+// Marlin calls this function to check whether an USB drive is inserted.
+// This is equivalent to polling the SD_DETECT when using SD cards.
+bool Sd2Card::isInserted() {
+ return state == MEDIA_READY;
+}
+
+bool Sd2Card::isReady() {
+ return state > DO_STARTUP;
+}
+
+// Marlin calls this to initialize an SD card once it is inserted.
+bool Sd2Card::init(const uint8_t, const pin_t) {
+ if (!isInserted()) return false;
+
+ #if USB_DEBUG >= 1
+ const uint32_t sectorSize = bulk.GetSectorSize(0);
+ if (sectorSize != 512) {
+ SERIAL_ECHOLNPAIR("Expecting sector size of 512. Got: ", sectorSize);
+ return false;
+ }
+ #endif
+
+ #if USB_DEBUG >= 3
+ lun0_capacity = bulk.GetCapacity(0);
+ SERIAL_ECHOLNPAIR("LUN Capacity (in blocks): ", lun0_capacity);
+ #endif
+ return true;
+}
+
+// Returns the capacity of the card in blocks.
+uint32_t Sd2Card::cardSize() {
+ if (!isInserted()) return false;
+ #if USB_DEBUG < 3
+ const uint32_t
+ #endif
+ lun0_capacity = bulk.GetCapacity(0);
+ return lun0_capacity;
+}
+
+bool Sd2Card::readBlock(uint32_t block, uint8_t* dst) {
+ if (!isInserted()) return false;
+ #if USB_DEBUG >= 3
+ if (block >= lun0_capacity) {
+ SERIAL_ECHOLNPAIR("Attempt to read past end of LUN: ", block);
+ return false;
+ }
+ #if USB_DEBUG >= 4
+ SERIAL_ECHOLNPAIR("Read block ", block);
+ #endif
+ #endif
+ return bulk.Read(0, block, 512, 1, dst) == 0;
+}
+
+bool Sd2Card::writeBlock(uint32_t block, const uint8_t* src) {
+ if (!isInserted()) return false;
+ #if USB_DEBUG >= 3
+ if (block >= lun0_capacity) {
+ SERIAL_ECHOLNPAIR("Attempt to write past end of LUN: ", block);
+ return false;
+ }
+ #if USB_DEBUG >= 4
+ SERIAL_ECHOLNPAIR("Write block ", block);
+ #endif
+ #endif
+ return bulk.Write(0, block, 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 0000000..5789121
--- /dev/null
+++ b/Marlin/src/sd/usb_flashdrive/Sd2Card_FlashDrive.h
@@ -0,0 +1,78 @@
+/**
+ * Marlin 3D Printer Firmware
+ * Copyright (c) 2020 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 <https://www.gnu.org/licenses/>.
+ *
+ */
+#pragma once
+
+/**
+ * \file
+ * \brief Sd2Card class for USB Flash Drive
+ */
+#include "../SdFatConfig.h"
+#include "../SdInfo.h"
+
+#if DISABLED(USE_OTG_USB_HOST)
+ /**
+ * Define SOFTWARE_SPI to use bit-bang SPI
+ */
+ #if EITHER(MEGA_SOFT_SPI, USE_SOFTWARE_SPI)
+ #define SOFTWARE_SPI
+ #endif
+
+ // SPI pin definitions - do not edit here - change in SdFatConfig.h
+ #if ENABLED(SOFTWARE_SPI)
+ #warning "Auto-assigning '10' as the SD_CHIP_SELECT_PIN."
+ #define SD_CHIP_SELECT_PIN 10 // Software SPI chip select pin for the SD
+ #else
+ // hardware pin defs
+ #define SD_CHIP_SELECT_PIN SD_SS_PIN // The default chip select pin for the SD card is SS.
+ #endif
+#endif
+
+class Sd2Card {
+ private:
+ uint32_t pos;
+
+ static void usbStateDebug();
+
+ public:
+ static bool usbStartup();
+
+ bool init(const uint8_t sckRateID=0, const pin_t chipSelectPin=TERN(USE_OTG_USB_HOST, 0, SD_CHIP_SELECT_PIN));
+
+ static void idle();
+
+ inline bool readStart(const uint32_t block) { pos = block; return isReady(); }
+ inline bool readData(uint8_t* dst) { return readBlock(pos++, dst); }
+ inline bool readStop() const { return true; }
+
+ inline bool writeStart(const uint32_t block, const uint32_t) { pos = block; return isReady(); }
+ inline bool writeData(uint8_t* src) { return writeBlock(pos++, src); }
+ inline bool writeStop() const { return true; }
+
+ bool readBlock(uint32_t block, uint8_t* dst);
+ bool writeBlock(uint32_t blockNumber, const uint8_t* src);
+
+ bool readCSD(csd_t*) { return true; }
+
+ uint32_t cardSize();
+ static bool isInserted();
+ bool isReady();
+};
diff --git a/Marlin/src/sd/usb_flashdrive/lib-uhs2/Usb.cpp b/Marlin/src/sd/usb_flashdrive/lib-uhs2/Usb.cpp
new file mode 100644
index 0000000..f26e82b
--- /dev/null
+++ b/Marlin/src/sd/usb_flashdrive/lib-uhs2/Usb.cpp
@@ -0,0 +1,795 @@
+/**
+ * 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 : https://www.circuitsathome.com
+ * e-mail : support@circuitsathome.com
+ */
+
+//
+// USB functions supporting Flash Drive
+//
+
+#include "../../../inc/MarlinConfigPre.h"
+
+#if ENABLED(USB_FLASH_DRIVE_SUPPORT) && DISABLED(USE_UHS3_USB)
+
+#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() { 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 nullptr;
+
+ EpInfo *pep = p->epinfo;
+
+ for (uint8_t i = 0; i < p->epcount; i++) {
+ if ((pep)->epAddr == ep)
+ return pep;
+
+ pep++;
+ }
+ return nullptr;
+}
+
+/**
+ * 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 = nullptr;
+ 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 rcode; // Return HRSLT if not zero
+
+ if (dataptr) { // 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 rcode; // Return error
+ }
+ // 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 = nullptr;
+ 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
+ for (;;) {
+ 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) { // 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
+ }
+ 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 = nullptr;
+ 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;
+ }
+
+ /* 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 to reset the watchdog timer on the ESP8266
+ #endif
+ tmpdata = regRd(rHIRQ);
+
+ if (tmpdata & bmHXFRDNIRQ) {
+ regWr(rHIRQ, bmHXFRDNIRQ); // Clear the interrupt
+ rcode = 0x00;
+ break;
+ }
+
+ } // While millis() < timeout
+
+ //if (rcode != 0x00) return rcode; // Exit if timeout
+
+ 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);
+ }
+
+ } // While timeout > millis()
+ return rcode;
+}
+
+// USB main task. Performs enumeration/cleanup
+void USB::Task() { // USB state machine
+ uint8_t rcode;
+ uint8_t tmpdata;
+ static uint32_t delay = 0;
+ //USB_FD_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;
+ }
+
+ 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)
+ usb_task_state = USB_STATE_RUNNING;
+ else if (rcode != USB_DEV_CONFIG_ERROR_DEVICE_INIT_INCOMPLETE) {
+ usb_error = rcode;
+ usb_task_state = USB_STATE_ERROR;
+ }
+ break;
+ case USB_STATE_RUNNING:
+ break;
+ case USB_STATE_ERROR:
+ //MAX3421E::Init();
+ break;
+ }
+}
+
+uint8_t USB::DefaultAddressing(uint8_t parent, uint8_t port, bool lowspeed) {
+ //uint8_t buf[12];
+ uint8_t rcode;
+ UsbDevice *p0 = nullptr, *p = nullptr;
+
+ // 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;
+
+ // 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;
+}
+
+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. It needs 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_FD_DEVICE_DESCRIPTOR)];
+ USB_FD_DEVICE_DESCRIPTOR *udd = reinterpret_cast<USB_FD_DEVICE_DESCRIPTOR *>(buf);
+ UsbDevice *p = nullptr;
+ EpInfo *oldep_ptr = nullptr;
+ 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_FD_DEVICE_DESCRIPTOR), (uint8_t*)buf);
+
+ // Restore p->epinfo
+ p->epinfo = oldep_ptr;
+
+ if (rcode) {
+ //printf("Configuring error: Can't get USB_FD_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, pid = udd->idProduct;
+ uint8_t klass = udd->bDeviceClass, 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;
+ }
+ }
+ // Arriving here means the device class is unsupported by registered classes
+ return DefaultAddressing(parent, port, lowspeed);
+}
+
+uint8_t USB::ReleaseDevice(uint8_t addr) {
+ if (addr) {
+ for (uint8_t i = 0; i < USB_NUMDEVICES; i++) {
+ if (!devConfig[i]) continue;
+ if (devConfig[i]->GetAddress() == addr)
+ return devConfig[i]->Release();
+ }
+ }
+ return 0;
+}
+
+// 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, nullptr);
+}
+
+// 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, nullptr);
+}
+
+/**
+ * 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_FD_CONFIGURATION_DESCRIPTOR *ucd = reinterpret_cast<USB_FD_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, nullptr);
+}
+
+// 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, nullptr, nullptr);
+ //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, nullptr, nullptr);
+}
+
+// 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, nullptr, nullptr);
+}
+
+#endif // USB_FLASH_DRIVE_SUPPORT
diff --git a/Marlin/src/sd/usb_flashdrive/lib-uhs2/Usb.h b/Marlin/src/sd/usb_flashdrive/lib-uhs2/Usb.h
new file mode 100644
index 0000000..b1ec146
--- /dev/null
+++ b/Marlin/src/sd/usb_flashdrive/lib-uhs2/Usb.h
@@ -0,0 +1,53 @@
+/**
+ * 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 : https://www.circuitsathome.com
+ * e-mail : support@circuitsathome.com
+ */
+#pragma once
+
+/* USB functions */
+#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 "UsbCore.h"
+#include "parsetools.h"
+#include "confdescparser.h"
+
+#undef _usb_h_
diff --git a/Marlin/src/sd/usb_flashdrive/lib-uhs2/UsbCore.h b/Marlin/src/sd/usb_flashdrive/lib-uhs2/UsbCore.h
new file mode 100644
index 0000000..d94958d
--- /dev/null
+++ b/Marlin/src/sd/usb_flashdrive/lib-uhs2/UsbCore.h
@@ -0,0 +1,312 @@
+/**
+ * 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 : https://www.circuitsathome.com
+ * e-mail : support@circuitsathome.com
+ */
+
+#ifndef _usb_h_
+ #error "Never include UsbCore.h directly; include Usb.h instead"
+#endif
+
+#pragma once
+
+// 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 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 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();
+
+ 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, nullptr));
+}
+//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, nullptr));
+}
+
+#endif // defined(USB_METHODS_INLINE)
diff --git a/Marlin/src/sd/usb_flashdrive/lib-uhs2/address.h b/Marlin/src/sd/usb_flashdrive/lib-uhs2/address.h
new file mode 100644
index 0000000..373b95a
--- /dev/null
+++ b/Marlin/src/sd/usb_flashdrive/lib-uhs2/address.h
@@ -0,0 +1,271 @@
+/**
+ * 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 : https://www.circuitsathome.com
+ * e-mail : support@circuitsathome.com
+ */
+#pragma once
+
+#ifndef _usb_h_
+ #error "Never include address.h directly; include Usb.h instead"
+#endif
+
+/* 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];
+
+ // Initialize 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;
+ }
+
+ // Return 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;
+ }
+
+ // Return 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);
+ }
+
+ // Initialize 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();
+ }
+
+ // Return a pointer to a specified address entry
+
+ virtual UsbDevice* GetUsbDevicePtr(uint8_t addr) {
+ if (!addr) return thePool;
+ uint8_t index = FindAddressIndex(addr);
+ return index ? thePool + index : nullptr;
+ }
+
+ // Perform an operation specified by pfunc for each addressed device
+
+ void ForEachUsbDevice(UsbDeviceHandleFunc pfunc) {
+ if (pfunc) {
+ for (uint8_t i = 1; i < MAX_DEVICES_ALLOWED; i++)
+ if (thePool[i].address.devAddress)
+ pfunc(thePool + i);
+ }
+ }
+
+ // Allocate 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) return 0; // if empty entry is not found
+
+ 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;
+ }
+
+ // Empty the 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;
+ }
+ FreeAddressByIndex(FindAddressIndex(addr));
+ }
+
+ // Return number of hubs attached
+ // It can be helpful to find out if hubs are attached when 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;
+ //}
+};
diff --git a/Marlin/src/sd/usb_flashdrive/lib-uhs2/confdescparser.h b/Marlin/src/sd/usb_flashdrive/lib-uhs2/confdescparser.h
new file mode 100644
index 0000000..9ed35ff
--- /dev/null
+++ b/Marlin/src/sd/usb_flashdrive/lib-uhs2/confdescparser.h
@@ -0,0 +1,201 @@
+/**
+ * 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 : https://www.circuitsathome.com
+ * e-mail : support@circuitsathome.com
+ */
+#pragma once
+
+#ifndef _usb_h_
+ #error "Never include confdescparser.h directly; include Usb.h instead"
+#endif
+
+class UsbConfigXtracter {
+public:
+ //virtual void ConfigXtract(const USB_FD_CONFIGURATION_DESCRIPTOR *conf) = 0;
+ //virtual void InterfaceXtract(uint8_t conf, const USB_FD_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_FD_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_FD_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() { 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_FD_CONFIGURATION_DESCRIPTOR* ucd = reinterpret_cast<USB_FD_CONFIGURATION_DESCRIPTOR*>(varBuffer);
+ USB_FD_INTERFACE_DESCRIPTOR* uid = reinterpret_cast<USB_FD_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 && theXtractor)
+ theXtractor->EndpointXtract(confValue, ifaceNumber, ifaceAltSet, protoValue, (USB_FD_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);
+}
diff --git a/Marlin/src/sd/usb_flashdrive/lib-uhs2/hexdump.h b/Marlin/src/sd/usb_flashdrive/lib-uhs2/hexdump.h
new file mode 100644
index 0000000..c948e5a
--- /dev/null
+++ b/Marlin/src/sd/usb_flashdrive/lib-uhs2/hexdump.h
@@ -0,0 +1,68 @@
+/**
+ * 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 : https://www.circuitsathome.com
+ * e-mail : support@circuitsathome.com
+ */
+#pragma once
+
+#ifndef _usb_h_
+ #error "Never include hexdump.h directly; include Usb.h instead"
+#endif
+
+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;
+ }
+ }
+ }
+}
diff --git a/Marlin/src/sd/usb_flashdrive/lib-uhs2/macros.h b/Marlin/src/sd/usb_flashdrive/lib-uhs2/macros.h
new file mode 100644
index 0000000..8cb5b6b
--- /dev/null
+++ b/Marlin/src/sd/usb_flashdrive/lib-uhs2/macros.h
@@ -0,0 +1,86 @@
+/**
+ * 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 : https://www.circuitsathome.com
+ * e-mail : support@circuitsathome.com
+ */
+#pragma once
+
+#ifndef _usb_h_
+ #error "Never include macros.h directly; include Usb.h instead"
+#endif
+
+////////////////////////////////////////////////////////////////////////////////
+// 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))
diff --git a/Marlin/src/sd/usb_flashdrive/lib-uhs2/masstorage.cpp b/Marlin/src/sd/usb_flashdrive/lib-uhs2/masstorage.cpp
new file mode 100644
index 0000000..a84a683
--- /dev/null
+++ b/Marlin/src/sd/usb_flashdrive/lib-uhs2/masstorage.cpp
@@ -0,0 +1,1217 @@
+/**
+ * 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 : https://www.circuitsathome.com
+ * e-mail : support@circuitsathome.com
+ */
+
+#include "../../../inc/MarlinConfigPre.h"
+
+#if ENABLED(USB_FLASH_DRIVE_SUPPORT) && DISABLED(USE_UHS3_USB)
+
+#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) {
+ return LUNOk[lun] ? CurrentCapacity[lun] : 0UL;
+}
+
+/**
+ * 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) {
+ return LUNOk[lun] ? CurrentSectorSize[lun] : 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, nullptr, (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, nullptr, (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_FD_DEVICE_DESCRIPTOR);
+
+ uint8_t buf[constBufSize];
+ USB_FD_DEVICE_DESCRIPTOR * udd = reinterpret_cast<USB_FD_DEVICE_DESCRIPTOR*>(buf);
+ uint8_t rcode;
+ UsbDevice *p = nullptr;
+ EpInfo *oldep_ptr = nullptr;
+ 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_FD_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 != 0x0200UL && c != 0x0400UL && c != 0x0800UL && c != 0x1000UL) 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] == /*0xFFFFFFFFUL */ 0x01UL || CurrentCapacity[lun] == 0x00UL) {
+ // 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);
+ return !TestUnitReady(lun);
+}
+
+/**
+ * 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++)
+ printf(LUNOk[lun] ? "#" : ".");
+ 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, nullptr);
+
+ 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, 0UL, (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, nullptr, (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;
+ #ifdef 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, 0UL, (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, nullptr, nullptr)) == 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, nullptr, nullptr) == 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] = 0UL;
+ 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: return MASS_ERR_UNIT_BUSY; // SIE is busy, just hang out and try again.
+ case hrTIMEOUT:
+ case hrJERR: return MASS_ERR_DEVICE_DISCONNECTED;
+ case hrSTALL:
+ if (index) {
+ ClearEpHalt(index);
+ return (index == epDataInIndex) ? MASS_ERR_STALL : MASS_ERR_WRITE_STALL;
+ }
+ return MASS_ERR_STALL;
+
+ case hrNAK:
+ return index ? MASS_ERR_UNIT_BUSY : MASS_ERR_UNIT_BUSY;
+
+ case hrTOGERR:
+ // Handle a super rare corner case, where toggles become de-synced.
+ // I've only run 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);
+ }
+ 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_FD_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-uhs2/masstorage.h b/Marlin/src/sd/usb_flashdrive/lib-uhs2/masstorage.h
new file mode 100644
index 0000000..25df006
--- /dev/null
+++ b/Marlin/src/sd/usb_flashdrive/lib-uhs2/masstorage.h
@@ -0,0 +1,562 @@
+/**
+ * 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 : https://www.circuitsathome.com
+ * e-mail : support@circuitsathome.com
+ */
+
+#pragma once
+
+// 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 (https://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_FD_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_FD_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);
+};
diff --git a/Marlin/src/sd/usb_flashdrive/lib-uhs2/max3421e.h b/Marlin/src/sd/usb_flashdrive/lib-uhs2/max3421e.h
new file mode 100644
index 0000000..6cad39d
--- /dev/null
+++ b/Marlin/src/sd/usb_flashdrive/lib-uhs2/max3421e.h
@@ -0,0 +1,242 @@
+/**
+ * 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 : https://www.circuitsathome.com
+ * e-mail : support@circuitsathome.com
+ */
+#pragma once
+
+#ifndef _usb_h_
+ #error "Never include max3421e.h directly; include Usb.h instead"
+#endif
+
+/* 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
+
+#undef tokSETUP
+#undef tokIN
+#undef tokOUT
+#undef tokINHS
+#undef tokOUTHS
+#undef tokISOIN
+#undef tokISOOUT
+
+/* 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)
diff --git a/Marlin/src/sd/usb_flashdrive/lib-uhs2/message.cpp b/Marlin/src/sd/usb_flashdrive/lib-uhs2/message.cpp
new file mode 100644
index 0000000..dcc3090
--- /dev/null
+++ b/Marlin/src/sd/usb_flashdrive/lib-uhs2/message.cpp
@@ -0,0 +1,128 @@
+/**
+ * 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 : https://www.circuitsathome.com
+ * e-mail : support@circuitsathome.com
+ */
+
+#include "../../../inc/MarlinConfigPre.h"
+
+#if ENABLED(USB_FLASH_DRIVE_SUPPORT) && DISABLED(USE_UHS3_USB)
+
+#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;
+ USB_HOST_SERIAL.print(c
+ #if !defined(ARDUINO) && !defined(ARDUINO_ARCH_LPC176X)
+ , BYTE
+ #endif
+ );
+ //USB_HOST_SERIAL.flush();
+}
+
+void E_Notify(char const * msg, int lvl) {
+ if (UsbDEBUGlvl < lvl) return;
+ if (!msg) return;
+ while (const char c = pgm_read_byte(msg++)) E_Notifyc(c, lvl);
+}
+
+void E_NotifyStr(char const * msg, int lvl) {
+ if (UsbDEBUGlvl < lvl) return;
+ if (!msg) return;
+ while (const char c = *msg++) E_Notifyc(c, lvl);
+}
+
+void E_Notify(uint8_t b, int lvl) {
+ if (UsbDEBUGlvl < lvl) return;
+ USB_HOST_SERIAL.print(b
+ #if !defined(ARDUINO) || ARDUINO < 100
+ , 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() {
+ Notify(PSTR("\r\ngetDevDescr "), 0x80);
+ }
+
+ void NotifyFailSetDevTblEntry() {
+ Notify(PSTR("\r\nsetDevTblEn "), 0x80);
+ }
+
+ void NotifyFailGetConfDescr() {
+ Notify(PSTR("\r\ngetConf "), 0x80);
+ }
+
+ void NotifyFailSetConfDescr() {
+ 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-uhs2/message.h b/Marlin/src/sd/usb_flashdrive/lib-uhs2/message.h
new file mode 100644
index 0000000..12195dc
--- /dev/null
+++ b/Marlin/src/sd/usb_flashdrive/lib-uhs2/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 : https://www.circuitsathome.com
+ * e-mail : support@circuitsathome.com
+ */
+#pragma once
+
+#ifndef _usb_h_
+ #error "Never include message.h directly; include Usb.h instead"
+#endif
+
+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 NotifyFailSetDevTblEntry();
+ void NotifyFailGetConfDescr();
+ void NotifyFailSetConfDescr();
+ 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
+}
diff --git a/Marlin/src/sd/usb_flashdrive/lib-uhs2/parsetools.cpp b/Marlin/src/sd/usb_flashdrive/lib-uhs2/parsetools.cpp
new file mode 100644
index 0000000..5d25576
--- /dev/null
+++ b/Marlin/src/sd/usb_flashdrive/lib-uhs2/parsetools.cpp
@@ -0,0 +1,77 @@
+/**
+ * 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 : https://www.circuitsathome.com
+ * e-mail : support@circuitsathome.com
+ */
+
+#include "../../../inc/MarlinConfigPre.h"
+
+#if ENABLED(USB_FLASH_DRIVE_SUPPORT) && DISABLED(USE_UHS3_USB)
+
+#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-uhs2/parsetools.h b/Marlin/src/sd/usb_flashdrive/lib-uhs2/parsetools.h
new file mode 100644
index 0000000..403766d
--- /dev/null
+++ b/Marlin/src/sd/usb_flashdrive/lib-uhs2/parsetools.h
@@ -0,0 +1,145 @@
+/**
+ * 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 : https://www.circuitsathome.com
+ * e-mail : support@circuitsathome.com
+ */
+#pragma once
+
+#ifndef _usb_h_
+ #error "Never include parsetools.h directly; include Usb.h instead"
+#endif
+
+struct MultiValueBuffer {
+ uint8_t valueSize;
+ void *pValue;
+} __attribute__((packed));
+
+class MultiByteValueParser {
+ uint8_t * pBuf;
+ uint8_t countDown;
+ uint8_t valueSize;
+
+public:
+
+ MultiByteValueParser() : pBuf(nullptr), 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(nullptr), 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(nullptr),
+ 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 = nullptr);
+};
diff --git a/Marlin/src/sd/usb_flashdrive/lib-uhs2/printhex.h b/Marlin/src/sd/usb_flashdrive/lib-uhs2/printhex.h
new file mode 100644
index 0000000..319cd9c
--- /dev/null
+++ b/Marlin/src/sd/usb_flashdrive/lib-uhs2/printhex.h
@@ -0,0 +1,80 @@
+/**
+ * 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 : https://www.circuitsathome.com
+ * e-mail : support@circuitsathome.com
+ */
+#pragma once
+
+#ifndef _usb_h_
+ #error "Never include printhex.h directly; include Usb.h instead"
+#endif
+
+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)
+ E_Notifyc(val & mask ? '1' : '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
+}
diff --git a/Marlin/src/sd/usb_flashdrive/lib-uhs2/settings.h b/Marlin/src/sd/usb_flashdrive/lib-uhs2/settings.h
new file mode 100644
index 0000000..2de0d46
--- /dev/null
+++ b/Marlin/src/sd/usb_flashdrive/lib-uhs2/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 : https://www.circuitsathome.com
+ * e-mail : support@circuitsathome.com
+ */
+
+#pragma once
+
+#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 https://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.
+#ifndef 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
diff --git a/Marlin/src/sd/usb_flashdrive/lib-uhs2/usb_ch9.h b/Marlin/src/sd/usb_flashdrive/lib-uhs2/usb_ch9.h
new file mode 100644
index 0000000..99c628f
--- /dev/null
+++ b/Marlin/src/sd/usb_flashdrive/lib-uhs2/usb_ch9.h
@@ -0,0 +1,170 @@
+/**
+ * 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 : https://www.circuitsathome.com
+ * e-mail : support@circuitsathome.com
+ */
+
+#ifndef _usb_h_
+ #error "Never include usb_ch9.h directly; include Usb.h instead"
+#endif
+
+/* USB chapter 9 structures */
+
+/* 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_FD_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_FD_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_FD_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_FD_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;
diff --git a/Marlin/src/sd/usb_flashdrive/lib-uhs2/usbhost.cpp b/Marlin/src/sd/usb_flashdrive/lib-uhs2/usbhost.cpp
new file mode 100644
index 0000000..190a0f1
--- /dev/null
+++ b/Marlin/src/sd/usb_flashdrive/lib-uhs2/usbhost.cpp
@@ -0,0 +1,207 @@
+/****************
+ * 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: <https://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) && DISABLED(USE_UHS3_USB)
+
+#include "Usb.h"
+#include "usbhost.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(USB_CS_PIN);
+ SET_INPUT_PULLUP(USB_INTR_PIN);
+ ncs();
+ spiBegin();
+
+ spiInit(SD_SPI_SPEED);
+
+ // 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() {
+ 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/lib-uhs2/usbhost.h b/Marlin/src/sd/usb_flashdrive/lib-uhs2/usbhost.h
new file mode 100644
index 0000000..5c3b852
--- /dev/null
+++ b/Marlin/src/sd/usb_flashdrive/lib-uhs2/usbhost.h
@@ -0,0 +1,58 @@
+/**************
+ * 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: <https://www.gnu.org/licenses/>. *
+ ****************************************************************************/
+
+#pragma once
+
+/* 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() {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
diff --git a/Marlin/src/sd/usb_flashdrive/lib-uhs3/UHS_host/UHS_BULK_STORAGE/UHS_BULK_STORAGE.h b/Marlin/src/sd/usb_flashdrive/lib-uhs3/UHS_host/UHS_BULK_STORAGE/UHS_BULK_STORAGE.h
new file mode 100644
index 0000000..b35e536
--- /dev/null
+++ b/Marlin/src/sd/usb_flashdrive/lib-uhs3/UHS_host/UHS_BULK_STORAGE/UHS_BULK_STORAGE.h
@@ -0,0 +1,249 @@
+/* Copyright (C) 2015-2016 Andrew J. Kroll
+ and
+ 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 : https://www.circuitsathome.com
+e-mail : support@circuitsathome.com
+ */
+
+#ifndef __UHS_BULK_STORAGE_H__
+#define __UHS_BULK_STORAGE_H__
+
+
+////////////////////////////////////////////////////////////////////////////////
+// Define any of these options at the top of your sketch to override
+// the defaults contained herewith. Do NOT do modifications here.
+// Macro | Settings and notes | Default
+// -----------------------------------------+-----------------------+-----------
+// | 1 to 8 |
+// | Each LUN needs |
+// MASS_MAX_SUPPORTED_LUN | ~13 bytes to be able | 8
+// | to track the state of |
+// | each unit. |
+// -----------------------------------------+-----------------------+-----------
+// | Just define to use. |
+// DEBUG_PRINTF_EXTRA_HUGE_UHS_BULK_STORAGE | works only if extra |
+// | huge debug is on too. |
+// -----------------------------------------^-----------------------^-----------
+
+#ifndef MASS_MAX_SUPPORTED_LUN
+#define MASS_MAX_SUPPORTED_LUN 8
+#endif
+
+#include "UHS_SCSI.h"
+
+#define UHS_BULK_bmREQ_OUT USB_SETUP_HOST_TO_DEVICE|USB_SETUP_TYPE_CLASS|USB_SETUP_RECIPIENT_INTERFACE
+#define UHS_BULK_bmREQ_IN USB_SETUP_DEVICE_TO_HOST|USB_SETUP_TYPE_CLASS|USB_SETUP_RECIPIENT_INTERFACE
+
+// Request Codes
+#define UHS_BULK_REQ_ADSC 0x00U
+#define UHS_BULK_REQ_GET 0xFCU
+#define UHS_BULK_REQ_PUT 0xFDU
+#define UHS_BULK_REQ_GET_MAX_LUN 0xFEU
+#define UHS_BULK_REQ_BOMSR 0xFFU // Mass Storage Reset
+
+#define UHS_BULK_CBW_SIGNATURE 0x43425355LU
+#define UHS_BULK_CSW_SIGNATURE 0x53425355LU
+
+#define UHS_BULK_CMD_DIR_OUT 0x00U
+#define UHS_BULK_CMD_DIR_IN 0x80U
+
+/* Bulk error codes */
+#define UHS_BULK_ERR_SUCCESS UHS_HOST_ERROR_NONE
+#define UHS_BULK_ERR_PHASE_ERROR 0x22U
+#define UHS_BULK_ERR_UNIT_NOT_READY 0x23U
+#define UHS_BULK_ERR_UNIT_BUSY 0x24U
+#define UHS_BULK_ERR_STALL 0x25U
+#define UHS_BULK_ERR_CMD_NOT_SUPPORTED 0x26U
+#define UHS_BULK_ERR_INVALID_CSW 0x27U
+#define UHS_BULK_ERR_NO_MEDIA 0x28U
+#define UHS_BULK_ERR_BAD_LBA 0x29U
+#define UHS_BULK_ERR_MEDIA_CHANGED 0x2AU
+#define UHS_BULK_ERR_DEVICE_DISCONNECTED UHS_HOST_ERROR_UNPLUGGED
+#define UHS_BULK_ERR_UNABLE_TO_RECOVER 0x32U // Reset recovery error
+#define UHS_BULK_ERR_INVALID_LUN 0x33U
+#define UHS_BULK_ERR_WRITE_STALL 0x34U
+#define UHS_BULK_ERR_READ_NAKS 0x35U
+#define UHS_BULK_ERR_WRITE_NAKS 0x36U
+#define UHS_BULK_ERR_WRITE_PROTECTED 0x37U
+#define UHS_BULK_ERR_NOT_IMPLEMENTED 0xFDU
+#define UHS_BULK_ERR_GENERAL_SCSI_ERROR 0xF0U
+#define UHS_BULK_ERR_GENERAL_USB_ERROR 0xFFU
+#define UHS_BULK_ERR_USER 0xA0U // For subclasses to define their own error codes
+
+#define MASS_MAX_ENDPOINTS 3
+
+struct UHS_BULK_CommandBlockWrapperBase {
+ volatile uint32_t dCBWSignature;
+ volatile uint32_t dCBWTag;
+ volatile uint32_t dCBWDataTransferLength;
+ volatile uint8_t bmCBWFlags;
+public:
+
+ UHS_BULK_CommandBlockWrapperBase() {
+ }
+
+ UHS_BULK_CommandBlockWrapperBase(uint32_t tag, uint32_t xflen, uint8_t flgs) :
+ dCBWSignature(UHS_BULK_CBW_SIGNATURE), dCBWTag(tag), dCBWDataTransferLength(xflen), bmCBWFlags(flgs) {
+ }
+} __attribute__((packed));
+
+struct UHS_BULK_CommandBlockWrapper : public UHS_BULK_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.
+
+ UHS_BULK_CommandBlockWrapper() :
+ UHS_BULK_CommandBlockWrapperBase(0, 0, 0), bmReserved1(0), bmReserved2(0) {
+ for(int i = 0; i < 16; i++) CBWCB[i] = 0;
+ }
+
+ // Generic Wrap, CDB zeroed.
+
+ UHS_BULK_CommandBlockWrapper(uint32_t tag, uint32_t xflen, uint8_t flgs, uint8_t lu, uint8_t cmdlen, uint8_t cmd) :
+ UHS_BULK_CommandBlockWrapperBase(tag, xflen, flgs),
+ bmCBWLUN(lu), bmReserved1(0), bmCBWCBLength(cmdlen), bmReserved2(0) {
+ for(int i = 0; i < 16; i++) CBWCB[i] = 0;
+ SCSI_CDB_BASE_t *x = reinterpret_cast<SCSI_CDB_BASE_t *>(CBWCB);
+ x->LUN = cmd;
+ }
+
+ // Wrap for CDB of 6
+
+ UHS_BULK_CommandBlockWrapper(uint32_t tag, uint32_t xflen, SCSI_CDB6_t *cdb, uint8_t dir) :
+ UHS_BULK_CommandBlockWrapperBase(tag, xflen, dir),
+ bmCBWLUN(cdb->LUN), bmReserved1(0), bmCBWCBLength(6), bmReserved2(0) {
+ memcpy(&CBWCB, cdb, 6);
+ }
+ // Wrap for CDB of 10
+
+ UHS_BULK_CommandBlockWrapper(uint32_t tag, uint32_t xflen, SCSI_CDB10_t *cdb, uint8_t dir) :
+ UHS_BULK_CommandBlockWrapperBase(tag, xflen, dir),
+ bmCBWLUN(cdb->LUN), bmReserved1(0), bmCBWCBLength(10), bmReserved2(0) {
+ memcpy(&CBWCB, cdb, 10);
+ }
+} __attribute__((packed));
+
+struct UHS_BULK_CommandStatusWrapper {
+ uint32_t dCSWSignature;
+ uint32_t dCSWTag;
+ uint32_t dCSWDataResidue;
+ uint8_t bCSWStatus;
+} __attribute__((packed));
+
+class UHS_Bulk_Storage : public UHS_USBInterface {
+protected:
+ static const uint8_t epDataInIndex = 1; // DataIn endpoint index
+ static const uint8_t epDataOutIndex = 2; // DataOUT endpoint index
+ static const uint8_t epInterruptInIndex = 3; // InterruptIN endpoint index
+
+ uint8_t bMaxLUN; // Max LUN
+ volatile uint32_t dCBWTag; // Tag
+ volatile uint8_t bTheLUN; // Active LUN
+ volatile uint32_t CurrentCapacity[MASS_MAX_SUPPORTED_LUN]; // Total sectors
+ volatile uint16_t CurrentSectorSize[MASS_MAX_SUPPORTED_LUN]; // Sector size, clipped to 16 bits
+ volatile bool LUNOk[MASS_MAX_SUPPORTED_LUN]; // use this to check for media changes.
+ volatile bool WriteOk[MASS_MAX_SUPPORTED_LUN];
+ void PrintEndpointDescriptor(const USB_FD_ENDPOINT_DESCRIPTOR* ep_ptr);
+
+public:
+ UHS_Bulk_Storage(UHS_USB_HOST_BASE *p);
+
+ volatile UHS_EpInfo epInfo[MASS_MAX_ENDPOINTS];
+
+ 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 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);
+ uint8_t SCSITransaction6(SCSI_CDB6_t *cdb, uint16_t buf_size, void *buf, uint8_t dir);
+ uint8_t SCSITransaction10(SCSI_CDB10_t *cdb, uint16_t buf_size, void *buf, uint8_t dir);
+
+
+ // Configure and internal methods, these should never be called by a user's sketch.
+ uint8_t Start();
+ bool OKtoEnumerate(ENUMERATION_INFO *ei);
+ uint8_t SetInterface(ENUMERATION_INFO *ei);
+
+ uint8_t GetAddress() {
+ return bAddress;
+ };
+
+
+ void Poll();
+
+ void DriverDefaults();
+
+
+private:
+ void Reset();
+ void CheckMedia();
+
+ bool IsValidCBW(uint8_t size, uint8_t *pcbw);
+ bool IsMeaningfulCBW(uint8_t size, uint8_t *pcbw);
+ bool IsValidCSW(UHS_BULK_CommandStatusWrapper *pcsw, UHS_BULK_CommandBlockWrapperBase *pcbw);
+
+ bool CheckLUN(uint8_t lun);
+
+ 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);
+ uint8_t ResetRecovery();
+ uint8_t ReadCapacity10(uint8_t lun, uint8_t *buf);
+ uint8_t Page3F(uint8_t lun);
+ uint8_t ClearEpHalt(uint8_t index);
+ uint8_t Transaction(UHS_BULK_CommandBlockWrapper *cbw, uint16_t bsize, void *buf);
+ uint8_t HandleUsbError(uint8_t error, uint8_t index);
+ uint8_t HandleSCSIError(uint8_t status);
+
+};
+
+#if defined(LOAD_UHS_BULK_STORAGE) && !defined(UHS_BULK_STORAGE_LOADED)
+#include "UHS_BULK_STORAGE_INLINE.h"
+#endif
+#endif // __MASSTORAGE_H__
diff --git a/Marlin/src/sd/usb_flashdrive/lib-uhs3/UHS_host/UHS_BULK_STORAGE/UHS_BULK_STORAGE_INLINE.h b/Marlin/src/sd/usb_flashdrive/lib-uhs3/UHS_host/UHS_BULK_STORAGE/UHS_BULK_STORAGE_INLINE.h
new file mode 100644
index 0000000..37ba681
--- /dev/null
+++ b/Marlin/src/sd/usb_flashdrive/lib-uhs3/UHS_host/UHS_BULK_STORAGE/UHS_BULK_STORAGE_INLINE.h
@@ -0,0 +1,1205 @@
+/* Copyright (C) 2015-2016 Andrew J. Kroll
+ and
+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 : https://www.circuitsathome.com
+e-mail : support@circuitsathome.com
+ */
+
+#if defined(LOAD_UHS_BULK_STORAGE) && defined(__UHS_BULK_STORAGE_H__) && !defined(UHS_BULK_STORAGE_LOADED)
+#define UHS_BULK_STORAGE_LOADED
+
+// uncomment to get 'printf' console debugging. NOT FOR UNO!
+//#define DEBUG_PRINTF_EXTRA_HUGE_UHS_BULK_STORAGE
+
+#if DEBUG_PRINTF_EXTRA_HUGE
+#ifdef DEBUG_PRINTF_EXTRA_HUGE_UHS_BULK_STORAGE
+#define BS_HOST_DEBUG(...) printf(__VA_ARGS__)
+#else
+#define BS_HOST_DEBUG(...) VOID0
+#endif
+#else
+#define BS_HOST_DEBUG(...) VOID0
+#endif
+
+////////////////////////////////////////////////////////////////////////////////
+
+// Interface code
+
+////////////////////////////////////////////////////////////////////////////////
+
+/**
+ * Get the capacity of the media
+ *
+ * @param lun Logical Unit Number
+ * @return media capacity
+ */
+uint32_t UHS_NI UHS_Bulk_Storage::GetCapacity(uint8_t lun) {
+ uint32_t v = 0LU;
+ pUsb->DisablePoll();
+ if(LUNOk[lun])
+ v = CurrentCapacity[lun];
+ pUsb->EnablePoll();
+ return v;
+}
+
+/**
+ * Get the sector (block) size used on the media
+ *
+ * @param lun Logical Unit Number
+ * @return media sector size
+ */
+uint16_t UHS_NI UHS_Bulk_Storage::GetSectorSize(uint8_t lun) {
+ uint16_t v = 0U;
+ pUsb->DisablePoll();
+ if(LUNOk[lun])
+ v = CurrentSectorSize[lun];
+ pUsb->EnablePoll();
+ return v;
+}
+
+/**
+ * Test if LUN is ready for use
+ *
+ * @param lun Logical Unit Number
+ * @return true if LUN is ready for use
+ */
+bool UHS_NI UHS_Bulk_Storage::LUNIsGood(uint8_t lun) {
+ bool v;
+ pUsb->DisablePoll();
+ v = LUNOk[lun];
+ pUsb->EnablePoll();
+ return v;
+}
+
+/**
+ * Test if LUN is write protected
+ *
+ * @param lun Logical Unit Number
+ * @return cached status of write protect switch
+ */
+bool UHS_NI UHS_Bulk_Storage::WriteProtected(uint8_t lun) {
+ bool v;
+ pUsb->DisablePoll();
+ v = WriteOk[lun];
+ pUsb->EnablePoll();
+ return v;
+}
+
+/**
+ * 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 UHS_NI UHS_Bulk_Storage::SCSITransaction6(SCSI_CDB6_t *cdb, uint16_t buf_size, void *buf, uint8_t dir) {
+ if(!bAddress) return UHS_BULK_ERR_DEVICE_DISCONNECTED;
+ pUsb->DisablePoll();
+ // promote buf_size to 32bits.
+ UHS_BULK_CommandBlockWrapper cbw = UHS_BULK_CommandBlockWrapper(++dCBWTag, (uint32_t)buf_size, cdb, dir);
+
+#if 0
+ // Lets check the CBW here:
+ printf("\r\n");
+ printf("\r\n");
+ uint8_t *dump = (uint8_t*)(&cbw);
+
+ for(int i=0; i<(sizeof (UHS_BULK_CommandBlockWrapper)); i++) {
+ printf("%02.2x ", *dump);
+ dump++;
+ }
+ printf("\r\n");
+ printf("\r\n");
+#endif
+
+ uint8_t v = (HandleSCSIError(Transaction(&cbw, buf_size, buf)));
+ pUsb->EnablePoll();
+ return v;
+}
+
+/**
+ * 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 UHS_NI UHS_Bulk_Storage::SCSITransaction10(SCSI_CDB10_t *cdb, uint16_t buf_size, void *buf, uint8_t dir) {
+ if(!bAddress) return UHS_BULK_ERR_DEVICE_DISCONNECTED;
+ pUsb->DisablePoll();
+ // promote buf_size to 32bits.
+ UHS_BULK_CommandBlockWrapper cbw = UHS_BULK_CommandBlockWrapper(++dCBWTag, (uint32_t)buf_size, cdb, dir);
+ //SetCurLUN(cdb->LUN);
+ uint8_t v = (HandleSCSIError(Transaction(&cbw, buf_size, buf)));
+ pUsb->EnablePoll();
+ return v;
+}
+
+/**
+ * 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 UHS_NI UHS_Bulk_Storage::LockMedia(uint8_t lun, uint8_t lock) {
+ if(!bAddress) return UHS_BULK_ERR_DEVICE_DISCONNECTED;
+ pUsb->DisablePoll();
+ Notify(PSTR("\r\nLockMedia\r\n"), 0x80);
+ Notify(PSTR("---------\r\n"), 0x80);
+
+ SCSI_CDB6_t cdb = SCSI_CDB6_t(SCSI_CMD_PREVENT_REMOVAL, lun, (uint8_t)0, lock);
+
+ uint8_t v = SCSITransaction6(&cdb, (uint16_t)0, NULL, (uint8_t)UHS_BULK_CMD_DIR_IN);
+ pUsb->EnablePoll();
+ return v;
+}
+
+/**
+ * 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 UHS_NI UHS_Bulk_Storage::MediaCTL(uint8_t lun, uint8_t ctl) {
+ if(!bAddress) return UHS_BULK_ERR_DEVICE_DISCONNECTED;
+ pUsb->DisablePoll();
+ Notify(PSTR("\r\nMediaCTL\r\n"), 0x80);
+ Notify(PSTR("-----------------\r\n"), 0x80);
+
+ uint8_t rcode = UHS_BULK_ERR_UNIT_NOT_READY;
+ if(bAddress) {
+ SCSI_CDB6_t cdb = SCSI_CDB6_t(SCSI_CMD_START_STOP_UNIT, lun, ctl & 0x03, 0);
+ rcode = SCSITransaction6(&cdb, (uint16_t)0, NULL, (uint8_t)UHS_BULK_CMD_DIR_OUT);
+ } else {
+ SetCurLUN(lun);
+ }
+ pUsb->EnablePoll();
+ 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 UHS_NI UHS_Bulk_Storage::Read(uint8_t lun, uint32_t addr, uint16_t bsize, uint8_t blocks, uint8_t *buf) {
+ if(!bAddress) return UHS_BULK_ERR_NO_MEDIA;
+ uint8_t er = UHS_BULK_ERR_NO_MEDIA;
+ pUsb->DisablePoll();
+ if(LUNOk[lun]) {
+ 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);
+ SCSI_CDB10_t cdb = SCSI_CDB10_t(SCSI_CMD_READ_10, lun, blocks, addr);
+
+again:
+ er = SCSITransaction10(&cdb, ((uint16_t)bsize * blocks), buf, (uint8_t)UHS_BULK_CMD_DIR_IN);
+
+ if(er == UHS_BULK_ERR_STALL) {
+ MediaCTL(lun, 1);
+
+ if(UHS_SLEEP_MS(150)) {
+ if(!TestUnitReady(lun)) goto again;
+ }
+ }
+ }
+ qNextPollTime = millis() + 100;
+ pUsb->EnablePoll();
+
+ 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 UHS_NI UHS_Bulk_Storage::Write(uint8_t lun, uint32_t addr, uint16_t bsize, uint8_t blocks, const uint8_t * buf) {
+ if(!bAddress) return UHS_BULK_ERR_NO_MEDIA;
+ uint8_t er = UHS_BULK_ERR_NO_MEDIA;
+ pUsb->DisablePoll();
+ if(LUNOk[lun]) {
+ if(!WriteOk[lun]) {
+ er = UHS_BULK_ERR_WRITE_PROTECTED;
+ } else {
+ 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);
+ SCSI_CDB10_t cdb = SCSI_CDB10_t(SCSI_CMD_WRITE_10, lun, blocks, addr);
+
+again:
+ er = SCSITransaction10(&cdb, ((uint16_t)bsize * blocks), (void*)buf, (uint8_t)UHS_BULK_CMD_DIR_OUT);
+
+ if(er == UHS_BULK_ERR_WRITE_STALL) {
+ MediaCTL(lun, 1);
+
+ if(UHS_SLEEP_MS(150)) {
+ if(!TestUnitReady(lun)) goto again;
+ }
+ }
+ }
+ }
+ qNextPollTime = millis() + 100;
+ pUsb->EnablePoll();
+
+ return er;
+}
+
+// End of user functions, the remaining code below is driver internals.
+// Only developer serviceable parts below!
+
+////////////////////////////////////////////////////////////////////////////////
+
+// Main driver code
+
+////////////////////////////////////////////////////////////////////////////////
+
+UHS_NI UHS_Bulk_Storage::UHS_Bulk_Storage(UHS_USB_HOST_BASE *p) {
+ pUsb = p;
+ dCBWTag = 0;
+ if(pUsb) {
+
+ DriverDefaults();
+ pUsb->RegisterDeviceClass(this);
+ // Serial.print("Bulk Register to USB Host @ 0x");
+ // Serial.println((uint32_t)pUsb, HEX);
+ // Serial.print("Bulk Register to USB Host Address Pool @ 0x");
+ // Serial.println((uint32_t)pUsb->GetAddressPool(), HEX);
+ }
+}
+
+/**
+ * @param ei Enumeration information
+ * @return true if this interface driver can handle this interface description
+ */
+bool UHS_NI UHS_Bulk_Storage::OKtoEnumerate(ENUMERATION_INFO *ei) {
+ BS_HOST_DEBUG("BulkOnly: checking numep %i, klass %2.2x, subklass %2.2x\r\n", ei->interface.numep, ei->klass, ei->subklass);
+ BS_HOST_DEBUG("BulkOnly: checking protocol %2.2x, interface.klass %2.2x, interface.subklass %2.2x\r\n", ei->protocol, ei->interface.klass, ei->interface.subklass);
+ BS_HOST_DEBUG("BulkOnly: checking interface.protocol %2.2x\r\n", ei->interface.protocol);
+ //
+ // TO-DO?
+ // Check that we have 2 bulk endpoints, and one in each direction??
+ // e.g. (ei->interface.numep > 1) && // two or more endpoints AND check types
+ // This will work with proper hardware though.
+ //
+
+ return (
+ ((ei->klass == UHS_USB_CLASS_MASS_STORAGE) || (ei->interface.klass == UHS_USB_CLASS_MASS_STORAGE)) && // mass storage class AND
+ ((ei->subklass == UHS_BULK_SUBCLASS_SCSI) || (ei->interface.subklass == UHS_BULK_SUBCLASS_SCSI)) && // SCSI command set AND
+ ((ei->protocol == UHS_STOR_PROTO_BBB) || (ei->interface.protocol == UHS_STOR_PROTO_BBB)) // Bulk Only transport
+ );
+}
+
+/**
+ * @param ei Enumeration information
+ * @return 0 always
+ */
+uint8_t UHS_NI UHS_Bulk_Storage::SetInterface(ENUMERATION_INFO *ei) {
+ uint8_t index;
+
+ bAddress = ei->address;
+ BS_HOST_DEBUG("BS SetInterface\r\n");
+ // Fill in the endpoint info structure
+ for(uint8_t ep = 0; ep < ei->interface.numep; ep++) {
+ BS_HOST_DEBUG("ep: 0x%2.2x bmAttributes: 0x%2.2x ", ep, ei->interface.epInfo[ep].bmAttributes);
+ if(ei->interface.epInfo[ep].bmAttributes == USB_TRANSFER_TYPE_BULK) {
+ index = ((ei->interface.epInfo[ep].bEndpointAddress & USB_TRANSFER_DIRECTION_IN) == USB_TRANSFER_DIRECTION_IN) ? epDataInIndex : epDataOutIndex;
+ epInfo[index].epAddr = (ei->interface.epInfo[ep].bEndpointAddress & 0x0F);
+ epInfo[index].maxPktSize = ei->interface.epInfo[ep].wMaxPacketSize;
+ epInfo[index].epAttribs = 0;
+ epInfo[index].bmNakPower = UHS_USB_NAK_MAX_POWER;
+ epInfo[index].bmSndToggle = 0;
+ epInfo[index].bmRcvToggle = 0;
+ epInfo[index].bIface=ei->interface.bInterfaceNumber;
+ BS_HOST_DEBUG("index: %i\r\n", index);
+ }
+ BS_HOST_DEBUG("\r\n");
+ }
+ bNumEP = 3;
+ epInfo[0].epAddr = 0;
+ epInfo[0].maxPktSize = ei->bMaxPacketSize0;
+ epInfo[0].bmNakPower = UHS_USB_NAK_MAX_POWER;
+ bIface = ei->interface.bInterfaceNumber;
+
+ return 0;
+};
+
+/**
+ * @return 0 for success
+ */
+uint8_t UHS_NI UHS_Bulk_Storage::Start() {
+ uint8_t rcode;
+ // Serial.print("Bulk Start from USB Host @ 0x");
+ // Serial.println((uint32_t)pUsb, HEX);
+ // Serial.print("Bulk Start USB Host Address Pool @ 0x");
+ // Serial.println((uint32_t)pUsb->GetAddressPool(), HEX);
+
+ BS_HOST_DEBUG("BS Start, speed: %i\r\n", pUsb->GetAddressPool()->GetUsbDevicePtr(bAddress)->speed);
+ BS_HOST_DEBUG("BS Start\r\n");
+ rcode = pUsb->setEpInfoEntry(bAddress, bIface, 3, epInfo);
+ // Serial.println(rcode,HEX);
+ if(rcode) goto FailOnInit;
+
+ // Do a 1 second delay before LUN query
+ if(!UHS_SLEEP_MS(1000)) goto FailUnPlug;
+
+ rcode = GetMaxLUN(&bMaxLUN);
+ BS_HOST_DEBUG("GetMaxLUN 0x%2.2x\r\n", rcode);
+ if(rcode) {
+ goto FailGetMaxLUN;
+ }
+ if(bMaxLUN >= MASS_MAX_SUPPORTED_LUN) bMaxLUN = MASS_MAX_SUPPORTED_LUN - 1;
+ BS_HOST_DEBUG("MaxLUN %u\r\n", bMaxLUN);
+ //ErrorMessage<uint8_t > (PSTR("MaxLUN"), bMaxLUN);
+ if(!UHS_SLEEP_MS(150)) goto FailUnPlug; // Delay a bit for slow firmware. (again)
+
+ for(uint8_t lun = 0; lun <= bMaxLUN; lun++) {
+ if(!UHS_SLEEP_MS(3)) goto FailUnPlug;
+ SCSI_Inquiry_Response response;
+ rcode = Inquiry(lun, sizeof (SCSI_Inquiry_Response), (uint8_t*) & response);
+ BS_HOST_DEBUG("Inquiry 0x%2.2x 0x%2.2x\r\n", sizeof (SCSI_Inquiry_Response), rcode);
+ if(rcode) {
+ goto FailInquiry;
+#if 0
+ } else {
+ BS_HOST_DEBUG("LUN %i `", lun);
+ uint8_t *buf = response.VendorID;
+ for(int i = 0; i < 28; i++) BS_HOST_DEBUG("%c", buf[i]);
+ BS_HOST_DEBUG("'\r\nQualifier %1.1X ", response.PeripheralQualifier);
+ BS_HOST_DEBUG("Device type %2.2X ", response.DeviceType);
+ BS_HOST_DEBUG("RMB %1.1X ", response.Removable);
+ BS_HOST_DEBUG("SSCS %1.1X ", response.SCCS);
+ uint8_t sv = response.Version;
+ BS_HOST_DEBUG("SCSI version %2.2X\r\nDevice conforms to ", sv);
+ switch(sv) {
+ case 0:
+ BS_HOST_DEBUG("No specific");
+ break;
+ case 1:
+ BS_HOST_DEBUG("ANSI X3.131-1986 (ANSI 1)");
+ break;
+ case 2:
+ BS_HOST_DEBUG("ANSI X3.131-1994 (ANSI 2)");
+ break;
+ case 3:
+ BS_HOST_DEBUG("ANSI INCITS 301-1997 (SPC)");
+ break;
+ case 4:
+ BS_HOST_DEBUG("ANSI INCITS 351-2001 (SPC-2)");
+ break;
+ case 5:
+ BS_HOST_DEBUG("ANSI INCITS 408-2005 (SPC-4)");
+ break;
+ case 6:
+ BS_HOST_DEBUG("T10/1731-D (SPC-4)");
+ break;
+ default:
+ BS_HOST_DEBUG("unknown");
+ }
+ BS_HOST_DEBUG(" standards.\r\n");
+#endif
+ }
+ }
+
+ for(uint8_t lun = 0; lun <= bMaxLUN; lun++) {
+ if(!UHS_SLEEP_MS(3)) goto FailUnPlug;
+ #ifndef USB_NO_TEST_UNIT_READY
+ uint8_t tries = 0xF0;
+ while((rcode = TestUnitReady(lun))) {
+ BS_HOST_DEBUG("\r\nTry %2.2x TestUnitReady %2.2x\r\n", tries - 0xF0, rcode);
+ if(rcode == 0x08) break; // break on no media, this is OK to do.
+ if(rcode == UHS_BULK_ERR_DEVICE_DISCONNECTED) goto FailUnPlug;
+ if(rcode == UHS_BULK_ERR_INVALID_CSW) goto Fail;
+ if(rcode != UHS_BULK_ERR_MEDIA_CHANGED) goto Fail;
+ if(!UHS_SLEEP_MS(2 * (tries + 1))) goto FailUnPlug;
+ tries++;
+ if(!tries) break;
+ }
+ #else
+ // Don't wait for the LUN to become ready, as this will
+ // trigger Marlin's watchdog timer
+ rcode = -1;
+ #endif
+ if(!UHS_SLEEP_MS(3)) goto FailUnPlug;
+ LockMedia(lun, 1);
+ if(rcode == 0x08) {
+ if(!UHS_SLEEP_MS(3)) goto FailUnPlug;
+ if(MediaCTL(lun, 1) == UHS_BULK_ERR_DEVICE_DISCONNECTED) goto FailUnPlug; // I actually have a USB stick that needs this!
+ }
+ BS_HOST_DEBUG("\r\nTry %2.2x TestUnitReady %2.2x\r\n", tries - 0xF0, rcode);
+ if(!rcode) {
+ if(!UHS_SLEEP_MS(3)) goto FailUnPlug;
+ BS_HOST_DEBUG("CheckLUN...\r\n");
+ BS_HOST_DEBUG("%lu\r\n", millis()/1000);
+ // Stalls on ***some*** devices, ***WHY***?! Device SAID it is READY!!
+ LUNOk[lun] = CheckLUN(lun);
+ BS_HOST_DEBUG("%lu\r\n", millis()/1000);
+ if(!LUNOk[lun]) LUNOk[lun] = CheckLUN(lun);
+ if(!UHS_SLEEP_MS(1)) goto FailUnPlug;
+ BS_HOST_DEBUG("Checked LUN...\r\n");
+ } else {
+ LUNOk[lun] = false;
+ }
+ }
+
+ rcode = OnStart();
+
+ if(rcode) goto FailOnInit;
+
+#ifdef DEBUG_USB_HOST
+ USBTRACE("BS configured\r\n\r\n");
+#endif
+ qNextPollTime = millis() + 100;
+ bPollEnable = true;
+
+ return 0;
+FailUnPlug:
+ rcode = UHS_BULK_ERR_DEVICE_DISCONNECTED;
+ goto Fail;
+
+FailOnInit:
+#ifdef DEBUG_USB_HOST
+ USBTRACE("OnStart:");
+ goto Fail;
+#endif
+
+FailGetMaxLUN:
+#ifdef DEBUG_USB_HOST
+ USBTRACE("GetMaxLUN:");
+ goto Fail;
+#endif
+
+FailInquiry:
+#ifdef DEBUG_USB_HOST
+ USBTRACE("Inquiry:");
+#endif
+
+Fail:
+#ifdef DEBUG_USB_HOST
+ NotifyFail(rcode);
+#endif
+ Release();
+
+ return rcode;
+}
+
+// Base class definition of Release() used. See UHS_USBInterface class definition for details
+
+/**
+ * For driver use only.
+ *
+ * @return
+ */
+//void UHS_NI UHS_Bulk_Storage::Release() {
+// pUsb->DisablePoll();
+// OnRelease();
+// DriverDefaults();
+// pUsb->EnablePoll();
+// return;
+//}
+
+/**
+ * For driver use only.
+ *
+ * @param lun Logical Unit Number
+ * @return true if LUN is ready for use.
+ */
+bool UHS_NI UHS_Bulk_Storage::CheckLUN(uint8_t lun) {
+ uint8_t rcode;
+ SCSI_Capacity capacity;
+ for(uint8_t i = 0; i < 8; i++) capacity.data[i] = 0;
+
+ rcode = ReadCapacity10(lun, (uint8_t*)capacity.data);
+ if(rcode) {
+ BS_HOST_DEBUG(">>>>>>>>>>>>>>>>ReadCapacity returned %i\r\n", rcode);
+ return false;
+ }
+#ifdef DEBUG_USB_HOST
+ 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);
+#endif
+ // Only 512/1024/2048/4096 are valid values!
+ uint32_t c = UHS_BYTES_TO_UINT32(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] = UHS_BYTES_TO_UINT32(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
+#ifdef DEBUG_USB_HOST
+ if(CurrentCapacity[lun])
+ ErrorMessage<uint8_t > (PSTR(">>>>>>>>>>>>>>>>BUGGY FIRMWARE. CAPACITY FAIL ON LUN"), lun);
+#endif
+ return false;
+ }
+ if(!UHS_SLEEP_MS(20)) return false;
+ #ifndef SKIP_PAGE3F
+ Page3F(lun);
+ #endif
+ if(!TestUnitReady(lun)) return true;
+
+ return false;
+}
+
+/**
+ * For driver use only.
+ *
+ * Scan for media change on all LUNs
+ */
+void UHS_NI UHS_Bulk_Storage::CheckMedia() {
+ if(!bAddress) return;
+ for(uint8_t lun = 0; lun <= bMaxLUN; lun++) {
+ if(TestUnitReady(lun)) {
+ LUNOk[lun] = false;
+ continue;
+ }
+ if(!LUNOk[lun])
+ LUNOk[lun] = CheckLUN(lun);
+ }
+#if 0
+ BS_HOST_DEBUG("}}}}}}}}}}}}}}}}STATUS ");
+ for(uint8_t lun = 0; lun <= bMaxLUN; lun++) {
+ if(LUNOk[lun])
+ BS_HOST_DEBUG("#");
+
+ else BS_HOST_DEBUG(".");
+ }
+ BS_HOST_DEBUG("\r\n");
+#endif
+ OnPoll();
+ qNextPollTime = millis() + 100;
+}
+
+/**
+ * For driver use only.
+ */
+void UHS_NI UHS_Bulk_Storage::Poll() {
+ if((long)(millis() - qNextPollTime) >= 0L) {
+
+ CheckMedia();
+ }
+
+ return;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+
+// SCSI code
+
+
+////////////////////////////////////////////////////////////////////////////////
+
+/**
+ * For driver use only.
+ *
+ * @param plun
+ * @return
+ */
+uint8_t UHS_NI UHS_Bulk_Storage::GetMaxLUN(uint8_t *plun) {
+ if(!bAddress) return UHS_BULK_ERR_DEVICE_DISCONNECTED;
+ uint8_t ret = pUsb->ctrlReq(bAddress, mkSETUP_PKT16(UHS_BULK_bmREQ_IN, UHS_BULK_REQ_GET_MAX_LUN, 0x0000U, bIface, 1), 1, plun);
+
+ if(ret == UHS_HOST_ERROR_STALL) {
+
+ *plun = 0;
+ Notify(PSTR("\r\nGetMaxLUN Stalled\r\n"), 0x80);
+ }
+ return 0;
+}
+
+/**
+ * For driver use only. Used during Driver Start
+ *
+ * @param lun Logical Unit Number
+ * @param bsize
+ * @param buf
+ * @return
+ */
+uint8_t UHS_NI UHS_Bulk_Storage::Inquiry(uint8_t lun, uint16_t bsize, uint8_t *buf) {
+ if(!bAddress) return UHS_BULK_ERR_DEVICE_DISCONNECTED;
+ Notify(PSTR("\r\nInquiry\r\n"), 0x80);
+ Notify(PSTR("---------\r\n"), 0x80);
+
+ SCSI_CDB6_t cdb = SCSI_CDB6_t(SCSI_CMD_INQUIRY, lun, 0LU, (uint8_t)bsize, 0);
+ uint8_t rc = SCSITransaction6(&cdb, bsize, buf, (uint8_t)UHS_BULK_CMD_DIR_IN);
+
+ return rc;
+}
+
+/**
+ * For driver use only.
+ *
+ * @param lun Logical Unit Number
+ * @return
+ */
+uint8_t UHS_NI UHS_Bulk_Storage::TestUnitReady(uint8_t lun) {
+ if(!bAddress) return UHS_BULK_ERR_DEVICE_DISCONNECTED;
+ //SetCurLUN(lun);
+ if(!bAddress)
+ return UHS_BULK_ERR_UNIT_NOT_READY;
+
+ Notify(PSTR("\r\nTestUnitReady\r\n"), 0x80);
+ Notify(PSTR("-----------------\r\n"), 0x80);
+
+ SCSI_CDB6_t cdb = SCSI_CDB6_t(SCSI_CMD_TEST_UNIT_READY, lun, (uint8_t)0, 0);
+
+ return SCSITransaction6(&cdb, 0, NULL, (uint8_t)UHS_BULK_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 UHS_NI UHS_Bulk_Storage::ModeSense6(uint8_t lun, uint8_t pc, uint8_t page, uint8_t subpage, uint8_t len, uint8_t * pbuf) {
+ if(!bAddress) return UHS_BULK_ERR_DEVICE_DISCONNECTED;
+ Notify(PSTR("\r\rModeSense\r\n"), 0x80);
+ Notify(PSTR("------------\r\n"), 0x80);
+
+ SCSI_CDB6_t cdb = SCSI_CDB6_t(SCSI_CMD_MODE_SENSE_6, lun, (uint32_t)((((pc << 6) | page) << 8) | subpage), len, 0);
+
+ return SCSITransaction6(&cdb, len, pbuf, (uint8_t)UHS_BULK_CMD_DIR_IN);
+}
+
+/**
+ * For driver use only.
+ *
+ * @param lun Logical Unit Number
+ * @param bsize
+ * @param buf
+ * @return
+ */
+uint8_t UHS_NI UHS_Bulk_Storage::ReadCapacity10(uint8_t lun, uint8_t *buf) {
+ if(!bAddress) return UHS_BULK_ERR_DEVICE_DISCONNECTED;
+ Notify(PSTR("\r\nReadCapacity\r\n"), 0x80);
+ Notify(PSTR("---------------\r\n"), 0x80);
+
+ SCSI_CDB10_t cdb = SCSI_CDB10_t(SCSI_CMD_READ_CAPACITY_10, lun);
+
+ return SCSITransaction10(&cdb, 8, buf, (uint8_t)UHS_BULK_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 UHS_NI UHS_Bulk_Storage::Page3F(uint8_t lun) {
+ if(!bAddress) return UHS_BULK_ERR_DEVICE_DISCONNECTED;
+ uint8_t buf[192];
+ for(int i = 0; i < 192; i++) {
+ buf[i] = 0x00;
+ }
+ WriteOk[lun] = true;
+ uint8_t rc = ModeSense6(lun, 0, 0x3F, 0, 192, buf);
+ if(!rc) {
+ WriteOk[lun] = ((buf[2] & 0x80) == 0);
+#ifdef DEBUG_USB_HOST
+ 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);
+#endif
+ }
+ return rc;
+}
+
+/**
+ * For driver use only.
+ *
+ * @param lun Logical Unit Number
+ * @param size
+ * @param buf
+ * @return
+ */
+uint8_t UHS_NI UHS_Bulk_Storage::RequestSense(uint8_t lun, uint16_t size, uint8_t *buf) {
+ if(!bAddress) return UHS_BULK_ERR_DEVICE_DISCONNECTED;
+ pUsb->DisablePoll();
+ Notify(PSTR("\r\nRequestSense\r\n"), 0x80);
+ Notify(PSTR("----------------\r\n"), 0x80);
+
+ SCSI_CDB6_t cdb = SCSI_CDB6_t(SCSI_CMD_REQUEST_SENSE, lun, 0LU, (uint8_t)size, 0);
+ UHS_BULK_CommandBlockWrapper cbw = UHS_BULK_CommandBlockWrapper(++dCBWTag, (uint32_t)size, &cdb, (uint8_t)UHS_BULK_CMD_DIR_IN);
+ uint8_t v = Transaction(&cbw, size, buf);
+ pUsb->EnablePoll();
+
+ return v;
+}
+
+
+////////////////////////////////////////////////////////////////////////////////
+
+
+// USB code
+
+
+////////////////////////////////////////////////////////////////////////////////
+
+/**
+ * For driver use only.
+ *
+ * @param index
+ * @return
+ */
+uint8_t UHS_NI UHS_Bulk_Storage::ClearEpHalt(uint8_t index) {
+ if(!bAddress) return UHS_BULK_ERR_DEVICE_DISCONNECTED;
+ uint8_t ret = 0;
+ if(index != 0) {
+ uint8_t ep = (index == epDataInIndex) ? (0x80 | epInfo[index].epAddr) : epInfo[index].epAddr;
+ do {
+ ret = pUsb->EPClearHalt(bAddress, ep);
+ if(!UHS_SLEEP_MS(6)) break;
+ } while(ret == 0x01);
+
+ if(ret) {
+ ErrorMessage<uint8_t > (PSTR("ClearEpHalt"), ret);
+ ErrorMessage<uint8_t > (PSTR("EP"), ep);
+ epInfo[index].bmSndToggle = 0;
+ epInfo[index].bmRcvToggle = 0;
+ return ret;
+ } else {
+
+ epInfo[index].bmSndToggle = 0;
+ epInfo[index].bmRcvToggle = 0;
+ }
+ }
+ return ret;
+}
+
+/**
+ * For driver use only.
+ */
+void UHS_NI UHS_Bulk_Storage::Reset() {
+ if(!bAddress) return;
+
+ while(pUsb->ctrlReq(bAddress, mkSETUP_PKT16(UHS_BULK_bmREQ_OUT, UHS_BULK_REQ_BOMSR, 0x0000U, bIface, 0), 0, NULL) == 0x01) {
+ if(!UHS_SLEEP_MS(6)) break;
+ }
+
+ if(!bAddress) return;
+
+ UHS_SLEEP_MS(2500);
+}
+
+/**
+ * For driver use only.
+ *
+ * @return 0 if successful
+ */
+uint8_t UHS_NI UHS_Bulk_Storage::ResetRecovery() {
+ if(!bAddress) return UHS_BULK_ERR_DEVICE_DISCONNECTED;
+ Notify(PSTR("\r\nResetRecovery\r\n"), 0x80);
+ Notify(PSTR("-----------------\r\n"), 0x80);
+ qNextPollTime = millis() + 90000;
+ uint8_t bLastUsbError = UHS_HOST_ERROR_UNPLUGGED;
+ if(UHS_SLEEP_MS(6)) {
+ Reset();
+ if(UHS_SLEEP_MS(6)) {
+ bLastUsbError = ClearEpHalt(epDataInIndex);
+ if(UHS_SLEEP_MS(6)) {
+
+ bLastUsbError = ClearEpHalt(epDataOutIndex);
+ UHS_SLEEP_MS(6);
+ }
+ }
+ }
+ return bLastUsbError;
+}
+
+/**
+ * For driver use only.
+ *
+ * Clear all EP data and clear all LUN status
+ */
+void UHS_NI UHS_Bulk_Storage::DriverDefaults() {
+
+ pUsb->DeviceDefaults(MASS_MAX_ENDPOINTS, this);
+
+ for(uint8_t i = 0; i < MASS_MAX_SUPPORTED_LUN; i++) {
+
+ LUNOk[i] = false;
+ WriteOk[i] = false;
+ CurrentCapacity[i] = 0lu;
+ CurrentSectorSize[i] = 0;
+ }
+
+ dCBWTag = 0;
+ bMaxLUN = 0;
+ bTheLUN = 0;
+}
+
+/**
+ * For driver use only.
+ *
+ * @param pcsw
+ * @param pcbw
+ * @return
+ */
+bool UHS_NI UHS_Bulk_Storage::IsValidCSW(UHS_BULK_CommandStatusWrapper *pcsw, UHS_BULK_CommandBlockWrapperBase *pcbw) {
+ if(!bAddress) return false;
+ if(pcsw->dCSWSignature != UHS_BULK_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);
+ ErrorMessage<uint32_t > (PSTR("dCSWTag"), pcsw->dCSWTag);
+ ErrorMessage<uint32_t > (PSTR("dCBWTag"), pcbw->dCBWTag);
+
+ return false;
+ }
+ return true;
+}
+
+/**
+ * For driver use only.
+ *
+ * @param error
+ * @param index
+ * @return
+ */
+uint8_t UHS_NI UHS_Bulk_Storage::HandleUsbError(uint8_t error, uint8_t index) {
+ if(!bAddress) return UHS_BULK_ERR_DEVICE_DISCONNECTED;
+
+ uint8_t count = 3;
+ while(error && count) {
+ if(error != UHS_HOST_ERROR_NONE) {
+ ErrorMessage<uint8_t > (PSTR("USB Error"), error);
+ ErrorMessage<uint8_t > (PSTR("Index"), index);
+ }
+ switch(error) {
+ // case UHS_HOST_ERROR_WRONGPID:
+ case UHS_HOST_ERROR_NONE:
+ return UHS_BULK_ERR_SUCCESS;
+ case UHS_HOST_ERROR_BUSY:
+ // SIE is busy, just hang out and try again.
+ return UHS_BULK_ERR_UNIT_BUSY;
+ case UHS_HOST_ERROR_NAK:
+ return UHS_BULK_ERR_UNIT_BUSY;
+ case UHS_HOST_ERROR_UNPLUGGED:
+ case UHS_HOST_ERROR_TIMEOUT:
+ case UHS_HOST_ERROR_JERR:
+ return UHS_BULK_ERR_DEVICE_DISCONNECTED;
+ case UHS_HOST_ERROR_STALL:
+ if(index == 0) return UHS_BULK_ERR_STALL;
+ ClearEpHalt(index);
+ if(index != epDataInIndex) return UHS_BULK_ERR_WRITE_STALL;
+ return UHS_BULK_ERR_STALL;
+
+
+ case UHS_HOST_ERROR_TOGERR:
+ // 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, bConfNum);
+
+ if(error) break;
+ }
+ return UHS_BULK_ERR_SUCCESS;
+
+ default:
+ ErrorMessage<uint8_t > (PSTR("\r\nUSB"), error);
+
+ return UHS_BULK_ERR_GENERAL_USB_ERROR;
+ }
+ count--;
+ } // while
+
+ return ((error && !count) ? UHS_BULK_ERR_GENERAL_USB_ERROR : UHS_BULK_ERR_SUCCESS);
+}
+
+/**
+ * For driver use only.
+ *
+ * @param pcbw
+ * @param buf_size
+ * @param buf
+ * @param flags
+ * @return
+ */
+uint8_t UHS_NI UHS_Bulk_Storage::Transaction(UHS_BULK_CommandBlockWrapper *pcbw, uint16_t buf_size, void *buf) {
+ if(!bAddress) return UHS_BULK_ERR_DEVICE_DISCONNECTED;
+
+ uint16_t bytes = buf_size;
+ bool write = (pcbw->bmCBWFlags & UHS_BULK_CMD_DIR_IN) != UHS_BULK_CMD_DIR_IN;
+ uint8_t ret = 0;
+ uint8_t usberr;
+ UHS_BULK_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 (UHS_BULK_CommandBlockWrapper), (uint8_t*)pcbw)) == UHS_HOST_ERROR_BUSY) {
+ if(!UHS_SLEEP_MS(1)) return UHS_BULK_ERR_DEVICE_DISCONNECTED;
+ }
+ ret = HandleUsbError(usberr, epDataOutIndex);
+ if(ret) {
+ ErrorMessage<uint8_t > (PSTR("============================ CBW"), ret);
+ } else {
+ if(bytes) {
+ if(!write) {
+ while((usberr = pUsb->inTransfer(bAddress, epInfo[epDataInIndex].epAddr, &bytes, (uint8_t*)buf)) == UHS_HOST_ERROR_BUSY) {
+ if(!UHS_SLEEP_MS(1)) return UHS_BULK_ERR_DEVICE_DISCONNECTED;
+ }
+ ret = HandleUsbError(usberr, epDataInIndex);
+ } else {
+ while((usberr = pUsb->outTransfer(bAddress, epInfo[epDataOutIndex].epAddr, bytes, (uint8_t*)buf)) == UHS_HOST_ERROR_BUSY) {
+ if(!UHS_SLEEP_MS(1)) return UHS_BULK_ERR_DEVICE_DISCONNECTED;
+ }
+ ret = HandleUsbError(usberr, epDataOutIndex);
+ }
+ if(ret) {
+ ErrorMessage<uint8_t > (PSTR("============================ DAT"), ret);
+ }
+ }
+ }
+
+ {
+ bytes = sizeof (UHS_BULK_CommandStatusWrapper);
+ int tries = 2;
+ while(tries--) {
+ while((usberr = pUsb->inTransfer(bAddress, epInfo[epDataInIndex].epAddr, &bytes, (uint8_t*) & csw)) == UHS_HOST_ERROR_BUSY) {
+ if(!UHS_SLEEP_MS(1)) return UHS_BULK_ERR_DEVICE_DISCONNECTED;
+ }
+ if(!usberr) break;
+ if(tries) {
+ if(usberr == UHS_HOST_ERROR_STALL) {
+ ResetRecovery();
+ } else {
+ ClearEpHalt(epDataInIndex);
+ }
+ }
+ }
+ 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 == UHS_HOST_ERROR_NONE) {
+ 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);
+ Reset();
+ ResetRecovery();
+
+ return UHS_BULK_ERR_INVALID_CSW;
+ }
+ }
+ }
+ return ret;
+}
+
+/**
+ * For driver use only.
+ *
+ * @param lun Logical Unit Number
+ * @return
+ */
+uint8_t UHS_NI UHS_Bulk_Storage::SetCurLUN(uint8_t lun) {
+ if(!bAddress) return UHS_BULK_ERR_DEVICE_DISCONNECTED;
+ if(lun > bMaxLUN)
+ return UHS_BULK_ERR_INVALID_LUN;
+ bTheLUN = lun;
+
+ return UHS_BULK_ERR_SUCCESS;
+};
+
+/**
+ * For driver use only.
+ *
+ * @param status
+ * @return
+ */
+uint8_t UHS_NI UHS_Bulk_Storage::HandleSCSIError(uint8_t status) {
+ if(!bAddress) return UHS_BULK_ERR_DEVICE_DISCONNECTED;
+ uint8_t ret = 0;
+ switch(status) {
+ case 0: return UHS_BULK_ERR_SUCCESS;
+
+ case 2:
+ ErrorMessage<uint8_t > (PSTR("Phase Error"), status);
+ ErrorMessage<uint8_t > (PSTR("LUN"), bTheLUN);
+ ResetRecovery();
+ return UHS_BULK_ERR_GENERAL_SCSI_ERROR;
+
+ case 1:
+ ErrorMessage<uint8_t > (PSTR("SCSI Error"), status);
+ ErrorMessage<uint8_t > (PSTR("LUN"), bTheLUN);
+ SCSI_Request_Sense_Response rsp;
+
+ ret = RequestSense(bTheLUN, sizeof (SCSI_Request_Sense_Response), (uint8_t*) & rsp);
+
+ if(ret) {
+ if(ret == UHS_BULK_ERR_DEVICE_DISCONNECTED) return UHS_BULK_ERR_DEVICE_DISCONNECTED;
+ return UHS_BULK_ERR_GENERAL_SCSI_ERROR;
+ }
+#if ENABLE_UHS_DEBUGGING
+ 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);
+#endif
+ // 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 UHS_BULK_ERR_MEDIA_CHANGED;
+ default:
+ return UHS_BULK_ERR_UNIT_NOT_READY;
+ }
+ case SCSI_S_NOT_READY:
+ switch(rsp.bAdditionalSenseCode) {
+ case SCSI_ASC_MEDIUM_NOT_PRESENT:
+ return UHS_BULK_ERR_NO_MEDIA;
+ default:
+ return UHS_BULK_ERR_UNIT_NOT_READY;
+ }
+ case SCSI_S_ILLEGAL_REQUEST:
+ switch(rsp.bAdditionalSenseCode) {
+ case SCSI_ASC_LBA_OUT_OF_RANGE:
+ return UHS_BULK_ERR_BAD_LBA;
+ default:
+ return UHS_BULK_ERR_CMD_NOT_SUPPORTED;
+ }
+ default:
+ return UHS_BULK_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 UHS_NI UHS_Bulk_Storage::PrintEndpointDescriptor(const USB_FD_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);
+}
+
+#else
+#error "Never include UHS_BULK_STORAGE_INLINE.h, include UHS_host.h instead"
+#endif
diff --git a/Marlin/src/sd/usb_flashdrive/lib-uhs3/UHS_host/UHS_BULK_STORAGE/UHS_SCSI.h b/Marlin/src/sd/usb_flashdrive/lib-uhs3/UHS_host/UHS_BULK_STORAGE/UHS_SCSI.h
new file mode 100644
index 0000000..bead520
--- /dev/null
+++ b/Marlin/src/sd/usb_flashdrive/lib-uhs3/UHS_host/UHS_BULK_STORAGE/UHS_SCSI.h
@@ -0,0 +1,327 @@
+/* Copyright (C) 2015-2016 Andrew J. Kroll
+ and
+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 : https://www.circuitsathome.com
+e-mail : support@circuitsathome.com
+ */
+
+#ifndef UHS_SCSI_H
+#define UHS_SCSI_H
+
+/*
+ * Reference documents from T10 (https://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 0x00U
+#define SCSI_CMD_REQUEST_SENSE 0x03U
+#define SCSI_CMD_FORMAT_UNIT 0x04U
+#define SCSI_CMD_READ_6 0x08U
+#define SCSI_CMD_WRITE_6 0x0AU
+#define SCSI_CMD_INQUIRY 0x12U
+#define SCSI_CMD_MODE_SELECT_6 0x15U
+#define SCSI_CMD_MODE_SENSE_6 0x1AU
+#define SCSI_CMD_START_STOP_UNIT 0x1BU
+#define SCSI_CMD_PREVENT_REMOVAL 0x1EU
+/* Group 2 Commands (CDB's here are 10-bytes) */
+#define SCSI_CMD_READ_FORMAT_CAPACITIES 0x23U
+#define SCSI_CMD_READ_CAPACITY_10 0x25U
+#define SCSI_CMD_READ_10 0x28U
+#define SCSI_CMD_WRITE_10 0x2AU
+#define SCSI_CMD_SEEK_10 0x2BU
+#define SCSI_CMD_ERASE_10 0x2CU
+#define SCSI_CMD_WRITE_AND_VERIFY_10 0x2EU
+#define SCSI_CMD_VERIFY_10 0x2FU
+#define SCSI_CMD_SYNCHRONIZE_CACHE 0x35U
+#define SCSI_CMD_WRITE_BUFFER 0x3BU
+#define SCSI_CMD_READ_BUFFER 0x3CU
+#define SCSI_CMD_READ_SUBCHANNEL 0x42U
+#define SCSI_CMD_READ_TOC 0x43U
+#define SCSI_CMD_READ_HEADER 0x44U
+#define SCSI_CMD_PLAY_AUDIO_10 0x45U
+#define SCSI_CMD_GET_CONFIGURATION 0x46U
+#define SCSI_CMD_PLAY_AUDIO_MSF 0x47U
+#define SCSI_CMD_PLAY_AUDIO_TI 0x48U
+#define SCSI_CMD_PLAY_TRACK_REL_10 0x49U
+#define SCSI_CMD_GET_EVENT_STATUS 0x4AU
+#define SCSI_CMD_PAUSE_RESUME 0x4BU
+#define SCSI_CMD_READ_DISC_INFORMATION 0x51U
+#define SCSI_CMD_READ_TRACK_INFORMATION 0x52U
+#define SCSI_CMD_RESERVE_TRACK 0x53U
+#define SCSI_CMD_SEND_OPC_INFORMATION 0x54U
+#define SCSI_CMD_MODE_SELECT_10 0x55U
+#define SCSI_CMD_REPAIR_TRACK 0x58U
+#define SCSI_CMD_MODE_SENSE_10 0x5AU
+#define SCSI_CMD_CLOSE_TRACK_SESSION 0x5BU
+#define SCSI_CMD_READ_BUFFER_CAPACITY 0x5CU
+#define SCSI_CMD_SEND_CUE_SHEET 0x5DU
+/* Group 5 Commands (CDB's here are 12-bytes) */
+#define SCSI_CMD_REPORT_LUNS 0xA0U
+#define SCSI_CMD_BLANK 0xA1U
+#define SCSI_CMD_SECURITY_PROTOCOL_IN 0xA2U
+#define SCSI_CMD_SEND_KEY 0xA3U
+#define SCSI_CMD_REPORT_KEY 0xA4U
+#define SCSI_CMD_PLAY_AUDIO_12 0xA5U
+#define SCSI_CMD_LOAD_UNLOAD 0xA6U
+#define SCSI_CMD_SET_READ_AHEAD 0xA7U
+#define SCSI_CMD_READ_12 0xA8U
+#define SCSI_CMD_PLAY_TRACK_REL_12 0xA9U
+#define SCSI_CMD_WRITE_12 0xAAU
+#define SCSI_CMD_READ_MEDIA_SERIAL_12 0xABU
+#define SCSI_CMD_GET_PERFORMANCE 0xACU
+#define SCSI_CMD_READ_DVD_STRUCTURE 0xADU
+#define SCSI_CMD_SECURITY_PROTOCOL_OUT 0xB5U
+#define SCSI_CMD_SET_STREAMING 0xB6U
+#define SCSI_CMD_READ_MSF 0xB9U
+#define SCSI_CMD_SET_SPEED 0xBBU
+#define SCSI_CMD_MECHANISM_STATUS 0xBDU
+#define SCSI_CMD_READ_CD 0xBEU
+#define SCSI_CMD_SEND_DISC_STRUCTURE 0xBFU
+/* Vendor-unique Commands, included for completeness */
+#define SCSI_CMD_CD_PLAYBACK_STATUS 0xC4U /* SONY unique */
+#define SCSI_CMD_PLAYBACK_CONTROL 0xC9U /* SONY unique */
+#define SCSI_CMD_READ_CDDA 0xD8U /* Vendor unique */
+#define SCSI_CMD_READ_CDXA 0xDBU /* Vendor unique */
+#define SCSI_CMD_READ_ALL_SUBCODES 0xDFU /* Vendor unique */
+
+/* SCSI error codes */
+#define SCSI_S_NOT_READY 0x02U
+#define SCSI_S_MEDIUM_ERROR 0x03U
+#define SCSI_S_ILLEGAL_REQUEST 0x05U
+#define SCSI_S_UNIT_ATTENTION 0x06U
+#define SCSI_ASC_LBA_OUT_OF_RANGE 0x21U
+#define SCSI_ASC_MEDIA_CHANGED 0x28U
+#define SCSI_ASC_MEDIUM_NOT_PRESENT 0x3AU
+
+struct SCSI_Capacity {
+ uint8_t data[8];
+ //uint32_t dwBlockAddress;
+ //uint32_t dwBlockLength;
+} __attribute__((packed));
+
+struct SCSI_CDB_BASE {
+ uint8_t Opcode;
+
+ unsigned unused : 5;
+ unsigned LUN : 3;
+
+ uint8_t info[12];
+} __attribute__((packed));
+
+typedef SCSI_CDB_BASE SCSI_CDB_BASE_t;
+
+struct SCSI_CDB6 {
+ uint8_t Opcode;
+
+ unsigned LBAMSB : 5;
+ unsigned LUN : 3;
+
+ uint8_t LBAHB;
+ uint8_t LBALB;
+ uint8_t AllocationLength;
+ uint8_t Control;
+
+public:
+
+ SCSI_CDB6(uint8_t _Opcode, uint8_t _LUN, uint32_t LBA, uint8_t _AllocationLength, uint8_t _Control) :
+ Opcode(_Opcode), LBAMSB(UHS_UINT8_BYTE2(LBA) & 0x1F), LUN(_LUN), LBAHB(UHS_UINT8_BYTE1(LBA)), LBALB(UHS_UINT8_BYTE0(LBA)),
+ AllocationLength(_AllocationLength), Control(_Control) {
+ }
+
+ SCSI_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 SCSI_CDB6 SCSI_CDB6_t;
+
+struct SCSI_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:
+
+ SCSI_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) {
+ }
+
+ SCSI_CDB10(uint8_t _Opcode, uint8_t _LUN, uint16_t xflen, uint32_t _LBA) :
+ Opcode(_Opcode), Service_Action(0), LUN(_LUN),
+ LBA_L_M_MB(UHS_UINT8_BYTE3(_LBA)), LBA_L_M_LB(UHS_UINT8_BYTE2(_LBA)), LBA_L_L_MB(UHS_UINT8_BYTE1(_LBA)), LBA_L_L_LB(UHS_UINT8_BYTE0(_LBA)),
+ Misc2(0), ALC_MB(UHS_UINT8_BYTE1(xflen)), ALC_LB(UHS_UINT8_BYTE0(xflen)), Control(0) {
+ }
+} __attribute__((packed));
+
+typedef SCSI_CDB10 SCSI_CDB10_t;
+
+struct SCSI_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 SCSI_CDB12 SCSI_CDB12_t;
+
+struct SCSI_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 SCSI_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 SCSI_Inquiry_Response {
+ 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;
+
+ 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 SCSI_Request_Sense_Response {
+ 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));
+
+#endif /* UHS_SCSI_H */
diff --git a/Marlin/src/sd/usb_flashdrive/lib-uhs3/UHS_host/UHS_UNOFFICIAL_IDs.h b/Marlin/src/sd/usb_flashdrive/lib-uhs3/UHS_host/UHS_UNOFFICIAL_IDs.h
new file mode 100644
index 0000000..6442bcc
--- /dev/null
+++ b/Marlin/src/sd/usb_flashdrive/lib-uhs3/UHS_host/UHS_UNOFFICIAL_IDs.h
@@ -0,0 +1,33 @@
+/* Copyright (C) 2015-2016 Andrew J. Kroll
+ and
+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 : https://www.circuitsathome.com
+e-mail : support@circuitsathome.com
+ */
+#ifndef _UHS_UNOFFICIAL_IDs_h
+#define _UHS_UNOFFICIAL_IDs_h
+
+// Bogus unofficial and unregistered VIDs from cloners to be listed here.
+
+#define UHS_VID_UNOFFICIAL_JOYTECH 0x162EU // For unofficial Joytech controllers
+
+#endif
diff --git a/Marlin/src/sd/usb_flashdrive/lib-uhs3/UHS_host/UHS_USB_IDs.h b/Marlin/src/sd/usb_flashdrive/lib-uhs3/UHS_host/UHS_USB_IDs.h
new file mode 100644
index 0000000..417c9f6
--- /dev/null
+++ b/Marlin/src/sd/usb_flashdrive/lib-uhs3/UHS_host/UHS_USB_IDs.h
@@ -0,0 +1,2993 @@
+/*
+ * USB vendor ids
+ * This file was generated by running python ./make-USB_IDs.py > UHS_USB_IDs.h
+ * Don't change it directly.
+ *
+ * Copyright 2014, Andrew J. Kroll for Circuits At Home, LTD. All rights reserved.
+ *
+ * Copyright 2012, Michal Labedzki for Tieto Corporation
+ * Other values imported from libghoto2/camlibs/ptp2/library.c, music-players.h
+ * Copyright (C) 2001-2005 Mariusz Woloszyn <emsi@ipartners.pl>
+ * Copyright (C) 2003-2013 Marcus Meissner <marcus@jet.franken.de>
+ * Copyright (C) 2005 Hubert Figuiere <hfiguiere@teaser.fr>
+ * Copyright (C) 2009 Axel Waggershauser <awagger@web.de>
+ * Copyright (C) 2005-2007 Richard A. Low <richard@wentnet.com>
+ * Copyright (C) 2005-2012 Linus Walleij <triad@df.lth.se>
+ * Copyright (C) 2007 Ted Bullock
+ * Copyright (C) 2012 Sony Mobile Communications AB
+ *
+ * Wireshark - Network traffic analyzer
+ * By Gerald Combs <gerald@wireshark.org>
+ * Copyright 1998 Gerald Combs
+ *
+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+#ifndef _UHS_USB_IDs_h_
+#define _UHS_USB_IDs_h_
+#include "UHS_UNOFFICIAL_IDs.h"
+
+#define UHS_VID_FRYS_ELECTRONICS 0x0001U // Fry's Electronics
+#define UHS_VID_INGRAM 0x0002U // Ingram
+#define UHS_VID_CLUB_MAC 0x0003U // Club Mac
+#define UHS_VID_NEBRASKA_FURNITURE_MART 0x0004U // Nebraska Furniture Mart
+#define UHS_VID_UNKNOWN 0x0011U // Unknown
+#define UHS_VID_PLANEX 0x0053U // Planex
+#define UHS_VID_DRAGONRISE 0x0079U // DragonRise Inc.
+#define UHS_VID_TRUST_INTERNATIONAL_BV 0x0105U // Trust International B.V.
+#define UHS_VID_IBP 0x0127U // IBP
+#define UHS_VID_UNKNOWN_1 0x0145U // Unknown
+#define UHS_VID_MLK 0x017cU // MLK
+#define UHS_VID_TP_LINK 0x0200U // TP-Link
+#define UHS_VID_CHIPSBANK_MICROELECTRONICS 0x0204U // Chipsbank Microelectronics Co., Ltd
+#define UHS_VID_HANGZHOU_WORLDE 0x0218U // Hangzhou Worlde
+#define UHS_VID_HUMAX 0x02adU // HUMAX Co., Ltd.
+#define UHS_VID_MM300_EBOOK_READER 0x0300U // MM300 eBook Reader
+#define UHS_VID_OCZ_TECHNOLOGY 0x0324U // OCZ Technology Inc
+#define UHS_VID_OCZ_TECHNOLOGY_1 0x0325U // OCZ Technology Inc
+#define UHS_VID_LTS 0x0386U // LTS
+#define UHS_VID_SHENZHEN_SINOTE_TECH_ELECTRON 0x03d9U // Shenzhen Sinote Tech-Electron Co., Ltd
+#define UHS_VID_BERND_WALTER_COMPUTER_TECHNOLOGY 0x03daU // Bernd Walter Computer Technology
+#define UHS_VID_ENDPOINTS 0x03e8U // EndPoints, Inc.
+#define UHS_VID_THESYS_MICROELECTRONICS 0x03e9U // Thesys Microelectronics
+#define UHS_VID_DATA_BROADCASTING 0x03eaU // Data Broadcasting Corp.
+#define UHS_VID_ATMEL 0x03ebU // Atmel Corp.
+#define UHS_VID_IWATSU_AMERICA 0x03ecU // Iwatsu America, Inc.
+#define UHS_VID_MITEL 0x03edU // Mitel Corp.
+#define UHS_VID_MITSUMI 0x03eeU // Mitsumi
+#define UHS_VID_HEWLETT_PACKARD 0x03f0U // Hewlett-Packard
+#define UHS_VID_GENOA_TECHNOLOGY 0x03f1U // Genoa Technology
+#define UHS_VID_OAK_TECHNOLOGY 0x03f2U // Oak Technology, Inc.
+#define UHS_VID_ADAPTEC 0x03f3U // Adaptec, Inc.
+#define UHS_VID_DIEBOLD 0x03f4U // Diebold, Inc.
+#define UHS_VID_SIEMENS_ELECTROMECHANICAL 0x03f5U // Siemens Electromechanical
+#define UHS_VID_EPSON_IMAGING_TECHNOLOGY_CENTER 0x03f8U // Epson Imaging Technology Center
+#define UHS_VID_KEYTRONIC 0x03f9U // KeyTronic Corp.
+#define UHS_VID_OPTI 0x03fbU // OPTi, Inc.
+#define UHS_VID_ELITEGROUP_COMPUTER_SYSTEMS 0x03fcU // Elitegroup Computer Systems
+#define UHS_VID_XILINX 0x03fdU // Xilinx, Inc.
+#define UHS_VID_FARALLON_COMUNICATIONS 0x03feU // Farallon Communications
+#define UHS_VID_NATIONAL_SEMICONDUCTOR 0x0400U // National Semiconductor Corp.
+#define UHS_VID_NATIONAL_REGISTRY 0x0401U // National Registry, Inc.
+#define UHS_VID_ALI 0x0402U // ALi Corp.
+#define UHS_VID_FUTURE_TECHNOLOGY_DEVICES_INTERNATIONAL 0x0403U // Future Technology Devices International, Ltd
+#define UHS_VID_NCR 0x0404U // NCR Corp.
+#define UHS_VID_SYNOPSYS 0x0405U // Synopsys, Inc.
+#define UHS_VID_FUJITSU_ICL_COMPUTERS 0x0406U // Fujitsu-ICL Computers
+#define UHS_VID_FUJITSU_PERSONAL_SYSTEMS 0x0407U // Fujitsu Personal Systems, Inc.
+#define UHS_VID_QUANTA_COMPUTER 0x0408U // Quanta Computer, Inc.
+#define UHS_VID_NEC 0x0409U // NEC Corp.
+#define UHS_VID_KODAK 0x040aU // Kodak Co.
+#define UHS_VID_WELTREND_SEMICONDUCTOR 0x040bU // Weltrend Semiconductor
+#define UHS_VID_VTECH_COMPUTERS 0x040cU // VTech Computers, Ltd
+#define UHS_VID_VIA_TECHNOLOGIES 0x040dU // VIA Technologies, Inc.
+#define UHS_VID_MCCI 0x040eU // MCCI
+#define UHS_VID_ECHO_SPEECH 0x040fU // Echo Speech Corp.
+#define UHS_VID_BUFFALO_INC_FORMERLY_MELCO 0x0411U // BUFFALO INC. (formerly MelCo., Inc.)
+#define UHS_VID_AWARD_SOFTWARE_INTERNATIONAL 0x0412U // Award Software International
+#define UHS_VID_LEADTEK_RESEARCH 0x0413U // Leadtek Research, Inc.
+#define UHS_VID_GIGA_BYTE_TECHNOLOGY 0x0414U // Giga-Byte Technology Co., Ltd
+#define UHS_VID_WINBOND_ELECTRONICS 0x0416U // Winbond Electronics Corp.
+#define UHS_VID_SYMBIOS_LOGIC 0x0417U // Symbios Logic
+#define UHS_VID_AST_RESEARCH 0x0418U // AST Research
+#define UHS_VID_SAMSUNG_INFO_SYSTEMS_AMERICA 0x0419U // Samsung Info. Systems America, Inc.
+#define UHS_VID_PHOENIX_TECHNOLOGIES 0x041aU // Phoenix Technologies, Ltd
+#define UHS_VID_DTV 0x041bU // d'TV
+#define UHS_VID_S3 0x041dU // S3, Inc.
+#define UHS_VID_CREATIVE_TECHNOLOGY 0x041eU // Creative Technology, Ltd
+#define UHS_VID_LCS_TELEGRAPHICS 0x041fU // LCS Telegraphics
+#define UHS_VID_CHIPS_AND_TECHNOLOGIES 0x0420U // Chips and Technologies
+#define UHS_VID_NOKIA_MOBILE_PHONES 0x0421U // Nokia Mobile Phones
+#define UHS_VID_ADI_SYSTEMS 0x0422U // ADI Systems, Inc.
+#define UHS_VID_COMPUTER_ACCESS_TECHNOLOGY 0x0423U // Computer Access Technology Corp.
+#define UHS_VID_STANDARD_MICROSYSTEMS 0x0424U // Standard Microsystems Corp.
+#define UHS_VID_MOTOROLA_SEMICONDUCTORS_HK 0x0425U // Motorola Semiconductors HK, Ltd
+#define UHS_VID_INTEGRATED_DEVICE_TECHNOLOGY 0x0426U // Integrated Device Technology, Inc.
+#define UHS_VID_MOTOROLA_ELECTRONICS_TAIWAN 0x0427U // Motorola Electronics Taiwan, Ltd
+#define UHS_VID_ADVANCED_GRAVIS_COMPUTER_TECH 0x0428U // Advanced Gravis Computer Tech, Ltd
+#define UHS_VID_CIRRUS_LOGIC 0x0429U // Cirrus Logic
+#define UHS_VID_ERICSSON_AUSTRIAN_AG 0x042aU // Ericsson Austrian, AG
+#define UHS_VID_INTEL 0x042bU // Intel Corp.
+#define UHS_VID_INNOVATIVE_SEMICONDUCTORS 0x042cU // Innovative Semiconductors, Inc.
+#define UHS_VID_MICRONICS 0x042dU // Micronics
+#define UHS_VID_ACER 0x042eU // Acer, Inc.
+#define UHS_VID_MOLEX 0x042fU // Molex, Inc.
+#define UHS_VID_SUN_MICROSYSTEMS 0x0430U // Sun Microsystems, Inc.
+#define UHS_VID_ITAC_SYSTEMS 0x0431U // Itac Systems, Inc.
+#define UHS_VID_UNISYS 0x0432U // Unisys Corp.
+#define UHS_VID_ALPS_ELECTRIC 0x0433U // Alps Electric, Inc.
+#define UHS_VID_SAMSUNG_INFO_SYSTEMS_AMERICA_1 0x0434U // Samsung Info. Systems America, Inc.
+#define UHS_VID_HYUNDAI_ELECTRONICS_AMERICA 0x0435U // Hyundai Electronics America
+#define UHS_VID_TAUGAGREINING_HF 0x0436U // Taugagreining HF
+#define UHS_VID_FRAMATOME_CONNECTORS_USA 0x0437U // Framatome Connectors USA
+#define UHS_VID_ADVANCED_MICRO_DEVICES 0x0438U // Advanced Micro Devices, Inc.
+#define UHS_VID_VOICE_TECHNOLOGIES_GROUP 0x0439U // Voice Technologies Group
+#define UHS_VID_LEXMARK_INTERNATIONAL 0x043dU // Lexmark International, Inc.
+#define UHS_VID_LG_ELECTRONICS_USA 0x043eU // LG Electronics USA, Inc.
+#define UHS_VID_RADISYS 0x043fU // RadiSys Corp.
+#define UHS_VID_EIZO_NANAO 0x0440U // Eizo Nanao Corp.
+#define UHS_VID_WINBOND_SYSTEMS_LAB 0x0441U // Winbond Systems Lab.
+#define UHS_VID_ERICSSON 0x0442U // Ericsson, Inc.
+#define UHS_VID_GATEWAY 0x0443U // Gateway, Inc.
+#define UHS_VID_LUCENT_TECHNOLOGIES 0x0445U // Lucent Technologies, Inc.
+#define UHS_VID_NMB_TECHNOLOGIES 0x0446U // NMB Technologies Corp.
+#define UHS_VID_MOMENTUM_MICROSYSTEMS 0x0447U // Momentum Microsystems
+#define UHS_VID_SHAMROCK_TECH 0x044aU // Shamrock Tech. Co., Ltd
+#define UHS_VID_WSI 0x044bU // WSI
+#define UHS_VID_CCLITRI 0x044cU // CCL/ITRI
+#define UHS_VID_SIEMENS_NIXDORF_AG 0x044dU // Siemens Nixdorf AG
+#define UHS_VID_ALPS_ELECTRIC_1 0x044eU // Alps Electric Co., Ltd
+#define UHS_VID_THRUSTMASTER 0x044fU // ThrustMaster, Inc.
+#define UHS_VID_DFI 0x0450U // DFI, Inc.
+#define UHS_VID_TEXAS_INSTRUMENTS 0x0451U // Texas Instruments, Inc.
+#define UHS_VID_MITSUBISHI_ELECTRONICS_AMERICA 0x0452U // Mitsubishi Electronics America, Inc.
+#define UHS_VID_CMD_TECHNOLOGY 0x0453U // CMD Technology
+#define UHS_VID_VOBIS_MICROCOMPUTER_AG 0x0454U // Vobis Microcomputer AG
+#define UHS_VID_TELEMATICS_INTERNATIONAL 0x0455U // Telematics International, Inc.
+#define UHS_VID_ANALOG_DEVICES 0x0456U // Analog Devices, Inc.
+#define UHS_VID_SILICON_INTEGRATED_SYSTEMS 0x0457U // Silicon Integrated Systems Corp.
+#define UHS_VID_KYE_SYSTEMS_CORP_MOUSE_SYSTEMS 0x0458U // KYE Systems Corp. (Mouse Systems)
+#define UHS_VID_ADOBE_SYSTEMS 0x0459U // Adobe Systems, Inc.
+#define UHS_VID_SONICBLUE 0x045aU // SONICblue, Inc.
+#define UHS_VID_HITACHI 0x045bU // Hitachi, Ltd
+#define UHS_VID_NORTEL_NETWORKS 0x045dU // Nortel Networks, Ltd
+#define UHS_VID_MICROSOFT 0x045eU // Microsoft Corp.
+#define UHS_VID_ACE_CAD_ENTERPRISE 0x0460U // Ace Cad Enterprise Co., Ltd
+#define UHS_VID_PRIMAX_ELECTRONICS 0x0461U // Primax Electronics, Ltd
+#define UHS_VID_MGE_UPS_SYSTEMS 0x0463U // MGE UPS Systems
+#define UHS_VID_AMPTYCOELECTRONICS 0x0464U // AMP/Tycoelectronics Corp.
+#define UHS_VID_ATANDT_PARADYNE 0x0467U // AT&T Paradyne
+#define UHS_VID_WIESON_TECHNOLOGIES 0x0468U // Wieson Technologies Co., Ltd
+#define UHS_VID_CHERRY 0x046aU // Cherry GmbH
+#define UHS_VID_AMERICAN_MEGATRENDS 0x046bU // American Megatrends, Inc.
+#define UHS_VID_TOSHIBA_CORP_DIGITAL_MEDIA_EQUIPMENT 0x046cU // Toshiba Corp., Digital Media Equipment
+#define UHS_VID_LOGITECH 0x046dU // Logitech, Inc.
+#define UHS_VID_BEHAVIOR_TECH_COMPUTER 0x046eU // Behavior Tech. Computer Corp.
+#define UHS_VID_CRYSTAL_SEMICONDUCTOR 0x046fU // Crystal Semiconductor
+#define UHS_VID_PHILIPS_OR_NXP 0x0471U // Philips (or NXP)
+#define UHS_VID_CHICONY_ELECTRONICS 0x0472U // Chicony Electronics Co., Ltd
+#define UHS_VID_SANYO_INFORMATION_BUSINESS 0x0473U // Sanyo Information Business Co., Ltd
+#define UHS_VID_SANYO_ELECTRIC 0x0474U // Sanyo Electric Co., Ltd
+#define UHS_VID_RELISYSTECO_INFORMATION_SYSTEM 0x0475U // Relisys/Teco Information System
+#define UHS_VID_AESP 0x0476U // AESP
+#define UHS_VID_SEAGATE_TECHNOLOGY 0x0477U // Seagate Technology, Inc.
+#define UHS_VID_CONNECTIX 0x0478U // Connectix Corp.
+#define UHS_VID_ADVANCED_PERIPHERAL_LABORATORIES 0x0479U // Advanced Peripheral Laboratories
+#define UHS_VID_SEMTECH 0x047aU // Semtech Corp.
+#define UHS_VID_SILITEK 0x047bU // Silitek Corp.
+#define UHS_VID_DELL_COMPUTER 0x047cU // Dell Computer Corp.
+#define UHS_VID_KENSINGTON 0x047dU // Kensington
+#define UHS_VID_AGERE_SYSTEMS_INC_LUCENT 0x047eU // Agere Systems, Inc. (Lucent)
+#define UHS_VID_PLANTRONICS 0x047fU // Plantronics, Inc.
+#define UHS_VID_TOSHIBA_AMERICA 0x0480U // Toshiba America Inc
+#define UHS_VID_ZENITH_DATA_SYSTEMS 0x0481U // Zenith Data Systems
+#define UHS_VID_KYOCERA 0x0482U // Kyocera Corp.
+#define UHS_VID_STMICROELECTRONICS 0x0483U // STMicroelectronics
+#define UHS_VID_SPECIALIX 0x0484U // Specialix
+#define UHS_VID_NOKIA_MONITORS 0x0485U // Nokia Monitors
+#define UHS_VID_ASUS_COMPUTERS 0x0486U // ASUS Computers, Inc.
+#define UHS_VID_STEWART_CONNECTOR 0x0487U // Stewart Connector
+#define UHS_VID_CIRQUE 0x0488U // Cirque Corp.
+#define UHS_VID_FOXCONN_HON_HAI 0x0489U // Foxconn / Hon Hai
+#define UHS_VID_S_MOS_SYSTEMS 0x048aU // S-MOS Systems, Inc.
+#define UHS_VID_ALPS_ELECTRIC_IRELAND 0x048cU // Alps Electric Ireland, Ltd
+#define UHS_VID_INTEGRATED_TECHNOLOGY_EXPRESS 0x048dU // Integrated Technology Express, Inc.
+#define UHS_VID_EICON_TECH 0x048fU // Eicon Tech.
+#define UHS_VID_UNITED_MICROELECTRONICS 0x0490U // United Microelectronics Corp.
+#define UHS_VID_CAPETRONIC 0x0491U // Capetronic
+#define UHS_VID_SAMSUNG_SEMICONDUCTOR 0x0492U // Samsung SemiConductor, Inc.
+#define UHS_VID_MAG_TECHNOLOGY 0x0493U // MAG Technology Co., Ltd
+#define UHS_VID_ESS_TECHNOLOGY 0x0495U // ESS Technology, Inc.
+#define UHS_VID_MICRON_ELECTRONICS 0x0496U // Micron Electronics
+#define UHS_VID_SMILE_INTERNATIONAL 0x0497U // Smile International
+#define UHS_VID_CAPETRONIC_KAOHSIUNG 0x0498U // Capetronic (Kaohsiung) Corp.
+#define UHS_VID_YAMAHA 0x0499U // Yamaha Corp.
+#define UHS_VID_GANDALF_TECHNOLOGIES 0x049aU // Gandalf Technologies, Ltd
+#define UHS_VID_CURTIS_COMPUTER_PRODUCTS 0x049bU // Curtis Computer Products
+#define UHS_VID_ACER_ADVANCED_LABS 0x049cU // Acer Advanced Labs, Inc.
+#define UHS_VID_VLSI_TECHNOLOGY 0x049dU // VLSI Technology
+#define UHS_VID_COMPAQ_COMPUTER 0x049fU // Compaq Computer Corp.
+#define UHS_VID_DIGITAL_EQUIPMENT 0x04a0U // Digital Equipment Corp.
+#define UHS_VID_SYSTEMSOFT 0x04a1U // SystemSoft Corp.
+#define UHS_VID_FIREPOWER_SYSTEMS 0x04a2U // FirePower Systems
+#define UHS_VID_TRIDENT_MICROSYSTEMS 0x04a3U // Trident Microsystems, Inc.
+#define UHS_VID_HITACHI_1 0x04a4U // Hitachi, Ltd
+#define UHS_VID_ACER_PERIPHERALS_INC_NOW_BENQ 0x04a5U // Acer Peripherals Inc. (now BenQ Corp.)
+#define UHS_VID_NOKIA_DISPLAY_PRODUCTS 0x04a6U // Nokia Display Products
+#define UHS_VID_VISIONEER 0x04a7U // Visioneer
+#define UHS_VID_MULTIVIDEO_LABS 0x04a8U // Multivideo Labs, Inc.
+#define UHS_VID_CANON 0x04a9U // Canon, Inc.
+#define UHS_VID_DAEWOO_TELECOM 0x04aaU // DaeWoo Telecom, Ltd
+#define UHS_VID_CHROMATIC_RESEARCH 0x04abU // Chromatic Research
+#define UHS_VID_MICRO_AUDIOMETRICS 0x04acU // Micro Audiometrics Corp.
+#define UHS_VID_DOOIN_ELECTRONICS 0x04adU // Dooin Electronics
+#define UHS_VID_WINNOV_LP 0x04afU // Winnov L.P.
+#define UHS_VID_NIKON 0x04b0U // Nikon Corp.
+#define UHS_VID_PAN_INTERNATIONAL 0x04b1U // Pan International
+#define UHS_VID_IBM 0x04b3U // IBM Corp.
+#define UHS_VID_CYPRESS_SEMICONDUCTOR 0x04b4U // Cypress Semiconductor Corp.
+#define UHS_VID_ROHM_LSI_SYSTEMS_USA 0x04b5U // ROHM LSI Systems USA, LLC
+#define UHS_VID_HINT 0x04b6U // Hint Corp.
+#define UHS_VID_COMPAL_ELECTRONICS 0x04b7U // Compal Electronics, Inc.
+#define UHS_VID_SEIKO_EPSON 0x04b8U // Seiko Epson Corp.
+#define UHS_VID_RAINBOW_TECHNOLOGIES 0x04b9U // Rainbow Technologies, Inc.
+#define UHS_VID_TOUCAN_SYSTEMS 0x04baU // Toucan Systems, Ltd
+#define UHS_VID_I_O_DATA_DEVICE 0x04bbU // I-O Data Device, Inc.
+#define UHS_VID_TOSHIBA_ELECTRONICS_TAIWAN 0x04bdU // Toshiba Electronics Taiwan Corp.
+#define UHS_VID_TELIA_RESEARCH 0x04beU // Telia Research AB
+#define UHS_VID_TDK 0x04bfU // TDK Corp.
+#define UHS_VID_US_ROBOTICS_3COM 0x04c1U // U.S. Robotics (3Com)
+#define UHS_VID_METHODE_ELECTRONICS_FAR_EAST_PTE 0x04c2U // Methode Electronics Far East PTE, Ltd
+#define UHS_VID_MAXI_SWITCH 0x04c3U // Maxi Switch, Inc.
+#define UHS_VID_LOCKHEED_MARTIN_ENERGY_RESEARCH 0x04c4U // Lockheed Martin Energy Research
+#define UHS_VID_FUJITSU 0x04c5U // Fujitsu, Ltd
+#define UHS_VID_TOSHIBA_AMERICA_ELECTRONIC_COMPONENTS 0x04c6U // Toshiba America Electronic Components
+#define UHS_VID_MICRO_MACRO_TECHNOLOGIES 0x04c7U // Micro Macro Technologies
+#define UHS_VID_KONICA 0x04c8U // Konica Corp.
+#define UHS_VID_LITE_ON_TECHNOLOGY 0x04caU // Lite-On Technology Corp.
+#define UHS_VID_FUJI_PHOTO_FILM 0x04cbU // Fuji Photo Film Co., Ltd
+#define UHS_VID_ST_ERICSSON 0x04ccU // ST-Ericsson
+#define UHS_VID_TATUNG_CO_OF_AMERICA 0x04cdU // Tatung Co. Of America
+#define UHS_VID_SCANLOGIC 0x04ceU // ScanLogic Corp.
+#define UHS_VID_MYSON_CENTURY 0x04cfU // Myson Century, Inc.
+#define UHS_VID_DIGI_INTERNATIONAL 0x04d0U // Digi International
+#define UHS_VID_ITT_CANON 0x04d1U // ITT Canon
+#define UHS_VID_ALTEC_LANSING_TECHNOLOGIES 0x04d2U // Altec Lansing Technologies
+#define UHS_VID_VIDUS 0x04d3U // VidUS, Inc.
+#define UHS_VID_LSI_LOGIC 0x04d4U // LSI Logic, Inc.
+#define UHS_VID_FORTE_TECHNOLOGIES 0x04d5U // Forte Technologies, Inc.
+#define UHS_VID_MENTOR_GRAPHICS 0x04d6U // Mentor Graphics
+#define UHS_VID_OKI_SEMICONDUCTOR 0x04d7U // Oki Semiconductor
+#define UHS_VID_MICROCHIP_TECHNOLOGY 0x04d8U // Microchip Technology, Inc.
+#define UHS_VID_HOLTEK_SEMICONDUCTOR 0x04d9U // Holtek Semiconductor, Inc.
+#define UHS_VID_PANASONIC_MATSUSHITA 0x04daU // Panasonic (Matsushita)
+#define UHS_VID_HYPERTEC_PTY 0x04dbU // Hypertec Pty, Ltd
+#define UHS_VID_HUAN_HSIN_HOLDINGS 0x04dcU // Huan Hsin Holdings, Ltd
+#define UHS_VID_SHARP 0x04ddU // Sharp Corp.
+#define UHS_VID_MINDSHARE 0x04deU // MindShare, Inc.
+#define UHS_VID_INTERLINK_ELECTRONICS 0x04dfU // Interlink Electronics
+#define UHS_VID_IIYAMA_NORTH_AMERICA 0x04e1U // Iiyama North America, Inc.
+#define UHS_VID_EXAR 0x04e2U // Exar Corp.
+#define UHS_VID_ZILOG 0x04e3U // Zilog, Inc.
+#define UHS_VID_ACC_MICROELECTRONICS 0x04e4U // ACC Microelectronics
+#define UHS_VID_PROMISE_TECHNOLOGY 0x04e5U // Promise Technology
+#define UHS_VID_SCM_MICROSYSTEMS 0x04e6U // SCM Microsystems, Inc.
+#define UHS_VID_ELO_TOUCHSYSTEMS 0x04e7U // Elo TouchSystems
+#define UHS_VID_SAMSUNG_ELECTRONICS 0x04e8U // Samsung Electronics Co., Ltd
+#define UHS_VID_PC_TEL 0x04e9U // PC-Tel, Inc.
+#define UHS_VID_BROOKTREE 0x04eaU // Brooktree Corp.
+#define UHS_VID_NORTHSTAR_SYSTEMS 0x04ebU // Northstar Systems, Inc.
+#define UHS_VID_TOKYO_ELECTRON_DEVICE 0x04ecU // Tokyo Electron Device, Ltd
+#define UHS_VID_ANNABOOKS 0x04edU // Annabooks
+#define UHS_VID_PACIFIC_ELECTRONIC_INTERNATIONAL 0x04efU // Pacific Electronic International, Inc.
+#define UHS_VID_DAEWOO_ELECTRONICS 0x04f0U // Daewoo Electronics Co., Ltd
+#define UHS_VID_VICTOR_COMPANY_OF_JAPAN 0x04f1U // Victor Company of Japan, Ltd
+#define UHS_VID_CHICONY_ELECTRONICS_1 0x04f2U // Chicony Electronics Co., Ltd
+#define UHS_VID_ELAN_MICROELECTRONICS 0x04f3U // Elan Microelectronics Corp.
+#define UHS_VID_HARTING_ELEKTRONIK 0x04f4U // Harting Elektronik, Inc.
+#define UHS_VID_FUJITSU_ICL_SYSTEMS 0x04f5U // Fujitsu-ICL Systems, Inc.
+#define UHS_VID_NORAND 0x04f6U // Norand Corp.
+#define UHS_VID_NEWNEX_TECHNOLOGY 0x04f7U // Newnex Technology Corp.
+#define UHS_VID_FUTUREPLUS_SYSTEMS 0x04f8U // FuturePlus Systems
+#define UHS_VID_BROTHER_INDUSTRIES 0x04f9U // Brother Industries, Ltd
+#define UHS_VID_DALLAS_SEMICONDUCTOR 0x04faU // Dallas Semiconductor
+#define UHS_VID_BIOSTAR_MICROTECH_INTERNATIONAL 0x04fbU // Biostar Microtech International Corp.
+#define UHS_VID_SUNPLUS_TECHNOLOGY 0x04fcU // Sunplus Technology Co., Ltd
+#define UHS_VID_SOLITON_SYSTEMS_KK 0x04fdU // Soliton Systems, K.K.
+#define UHS_VID_PFU 0x04feU // PFU, Ltd
+#define UHS_VID_E_CMOS 0x04ffU // E-CMOS Corp.
+#define UHS_VID_SIAM_UNITED_HI_TECH 0x0500U // Siam United Hi-Tech
+#define UHS_VID_FUJIKURA_DDK 0x0501U // Fujikura DDK, Ltd
+#define UHS_VID_ACER_1 0x0502U // Acer, Inc.
+#define UHS_VID_HITACHI_AMERICA 0x0503U // Hitachi America, Ltd
+#define UHS_VID_HAYES_MICROCOMPUTER_PRODUCTS 0x0504U // Hayes Microcomputer Products
+#define UHS_VID_3COM 0x0506U // 3Com Corp.
+#define UHS_VID_HOSIDEN 0x0507U // Hosiden Corp.
+#define UHS_VID_CLARION 0x0508U // Clarion Co., Ltd
+#define UHS_VID_AZTECH_SYSTEMS 0x0509U // Aztech Systems, Ltd
+#define UHS_VID_CINCH_CONNECTORS 0x050aU // Cinch Connectors
+#define UHS_VID_CABLE_SYSTEM_INTERNATIONAL 0x050bU // Cable System International
+#define UHS_VID_INNOMEDIA 0x050cU // InnoMedia, Inc.
+#define UHS_VID_BELKIN_COMPONENTS 0x050dU // Belkin Components
+#define UHS_VID_NEON_TECHNOLOGY 0x050eU // Neon Technology, Inc.
+#define UHS_VID_KC_TECHNOLOGY 0x050fU // KC Technology, Inc.
+#define UHS_VID_SEJIN_ELECTRON 0x0510U // Sejin Electron, Inc.
+#define UHS_VID_NABLE_DATABOOK_TECHNOLOGIES 0x0511U // N'Able (DataBook) Technologies, Inc.
+#define UHS_VID_HUALON_MICROELECTRONICS 0x0512U // Hualon Microelectronics Corp.
+#define UHS_VID_DIGITAL_X 0x0513U // digital-X, Inc.
+#define UHS_VID_FCI_ELECTRONICS 0x0514U // FCI Electronics
+#define UHS_VID_ACTC 0x0515U // ACTC
+#define UHS_VID_LONGWELL_ELECTRONICS 0x0516U // Longwell Electronics
+#define UHS_VID_BUTTERFLY_COMMUNICATIONS 0x0517U // Butterfly Communications
+#define UHS_VID_EZKEY 0x0518U // EzKEY Corp.
+#define UHS_VID_STAR_MICRONICS 0x0519U // Star Micronics Co., Ltd
+#define UHS_VID_WYSE_TECHNOLOGY 0x051aU // WYSE Technology
+#define UHS_VID_SILICON_GRAPHICS 0x051bU // Silicon Graphics
+#define UHS_VID_SHUTTLE 0x051cU // Shuttle, Inc.
+#define UHS_VID_AMERICAN_POWER_CONVERSION 0x051dU // American Power Conversion
+#define UHS_VID_SCIENTIFIC_ATLANTA 0x051eU // Scientific Atlanta, Inc.
+#define UHS_VID_IO_SYSTEMS_ELITE_ELECTRONICS 0x051fU // IO Systems (Elite Electronics), Inc.
+#define UHS_VID_TAIWAN_SEMICONDUCTOR_MANUFACTURING 0x0520U // Taiwan Semiconductor Manufacturing Co.
+#define UHS_VID_AIRBORN_CONNECTORS 0x0521U // Airborn Connectors
+#define UHS_VID_ADVANCED_CONNECTEK 0x0522U // Advanced Connectek, Inc.
+#define UHS_VID_ATEN 0x0523U // ATEN GmbH
+#define UHS_VID_SOLA_ELECTRONICS 0x0524U // Sola Electronics
+#define UHS_VID_NETCHIP_TECHNOLOGY 0x0525U // Netchip Technology, Inc.
+#define UHS_VID_TEMIC_MHS 0x0526U // Temic MHS S.A.
+#define UHS_VID_ALTRA 0x0527U // ALTRA
+#define UHS_VID_ATI_TECHNOLOGIES 0x0528U // ATI Technologies, Inc.
+#define UHS_VID_ALADDIN_KNOWLEDGE_SYSTEMS 0x0529U // Aladdin Knowledge Systems
+#define UHS_VID_CRESCENT_HEART_SOFTWARE 0x052aU // Crescent Heart Software
+#define UHS_VID_TEKOM_TECHNOLOGIES 0x052bU // Tekom Technologies, Inc.
+#define UHS_VID_CANON_INFORMATION_SYSTEMS 0x052cU // Canon Information Systems, Inc.
+#define UHS_VID_AVID_ELECTRONICS 0x052dU // Avid Electronics Corp.
+#define UHS_VID_STANDARD_MICROSYSTEMS_1 0x052eU // Standard Microsystems Corp.
+#define UHS_VID_UNICORE_SOFTWARE 0x052fU // Unicore Software, Inc.
+#define UHS_VID_AMERICAN_MICROSYSTEMS 0x0530U // American Microsystems, Inc.
+#define UHS_VID_WACOM_TECHNOLOGY 0x0531U // Wacom Technology Corp.
+#define UHS_VID_SYSTECH 0x0532U // Systech Corp.
+#define UHS_VID_ALCATEL_MOBILE_PHONES 0x0533U // Alcatel Mobile Phones
+#define UHS_VID_MOTOROLA 0x0534U // Motorola, Inc.
+#define UHS_VID_LIH_TZU_ELECTRIC 0x0535U // LIH TZU Electric Co., Ltd
+#define UHS_VID_HAND_HELD_PRODUCTS_WELCH_ALLYN 0x0536U // Hand Held Products (Welch Allyn, Inc.)
+#define UHS_VID_INVENTEC 0x0537U // Inventec Corp.
+#define UHS_VID_CALDERA_INTERNATIONAL_INC_SCO 0x0538U // Caldera International, Inc. (SCO)
+#define UHS_VID_SHYH_SHIUN_TERMINALS 0x0539U // Shyh Shiun Terminals Co., Ltd
+#define UHS_VID_PREHKEYTEC 0x053aU // PrehKeyTec GmbH
+#define UHS_VID_GLOBAL_VILLAGE_COMMUNICATION 0x053bU // Global Village Communication
+#define UHS_VID_INSTITUT_OF_MICROELECTRONIC_AND_MECHATRONIC_SYSTEMS 0x053cU // Institut of Microelectronic & Mechatronic Systems
+#define UHS_VID_SILICON_ARCHITECT 0x053dU // Silicon Architect
+#define UHS_VID_MOBILITY_ELECTRONICS 0x053eU // Mobility Electronics
+#define UHS_VID_SYNOPSYS_1 0x053fU // Synopsys, Inc.
+#define UHS_VID_UNIACCESS 0x0540U // UniAccess AB
+#define UHS_VID_SIRF_TECHNOLOGY 0x0541U // Sirf Technology, Inc.
+#define UHS_VID_VIEWSONIC 0x0543U // ViewSonic Corp.
+#define UHS_VID_CRISTIE_ELECTRONICS 0x0544U // Cristie Electronics, Ltd
+#define UHS_VID_XIRLINK 0x0545U // Xirlink, Inc.
+#define UHS_VID_POLAROID 0x0546U // Polaroid Corp.
+#define UHS_VID_ANCHOR_CHIPS 0x0547U // Anchor Chips, Inc.
+#define UHS_VID_TYAN_COMPUTER 0x0548U // Tyan Computer Corp.
+#define UHS_VID_PIXERA 0x0549U // Pixera Corp.
+#define UHS_VID_FUJITSU_MICROELECTRONICS 0x054aU // Fujitsu Microelectronics, Inc.
+#define UHS_VID_NEW_MEDIA 0x054bU // New Media Corp.
+#define UHS_VID_SONY 0x054cU // Sony Corp.
+#define UHS_VID_TRY 0x054dU // Try Corp.
+#define UHS_VID_PROSIDE 0x054eU // Proside Corp.
+#define UHS_VID_WYSE_TECHNOLOGY_TAIWAN 0x054fU // WYSE Technology Taiwan
+#define UHS_VID_FUJI_XEROX 0x0550U // Fuji Xerox Co., Ltd
+#define UHS_VID_COMPUTREND_SYSTEMS 0x0551U // CompuTrend Systems, Inc.
+#define UHS_VID_PHILIPS_MONITORS 0x0552U // Philips Monitors
+#define UHS_VID_STMICROELECTRONICS_IMAGING_DIVISION_VLSI_VISION 0x0553U // STMicroelectronics Imaging Division (VLSI Vision)
+#define UHS_VID_DICTAPHONE 0x0554U // Dictaphone Corp.
+#define UHS_VID_ANAM_SANDT 0x0555U // ANAM S&T Co., Ltd
+#define UHS_VID_ASAHI_KASEI_MICROSYSTEMS 0x0556U // Asahi Kasei Microsystems Co., Ltd
+#define UHS_VID_ATEN_INTERNATIONAL 0x0557U // ATEN International Co., Ltd
+#define UHS_VID_TRUEVISION 0x0558U // Truevision, Inc.
+#define UHS_VID_CADENCE_DESIGN_SYSTEMS 0x0559U // Cadence Design Systems, Inc.
+#define UHS_VID_KENWOOD_USA 0x055aU // Kenwood USA
+#define UHS_VID_KNOWLEDGETEK 0x055bU // KnowledgeTek, Inc.
+#define UHS_VID_PROTON_ELECTRONIC_IND 0x055cU // Proton Electronic Ind.
+#define UHS_VID_SAMSUNG_ELECTRO_MECHANICS 0x055dU // Samsung Electro-Mechanics Co.
+#define UHS_VID_CTX_OPTO_ELECTRONICS 0x055eU // CTX Opto-Electronics Corp.
+#define UHS_VID_MUSTEK_SYSTEMS 0x055fU // Mustek Systems, Inc.
+#define UHS_VID_INTERFACE 0x0560U // Interface Corp.
+#define UHS_VID_OASIS_DESIGN 0x0561U // Oasis Design, Inc.
+#define UHS_VID_TELEX_COMMUNICATIONS 0x0562U // Telex Communications, Inc.
+#define UHS_VID_IMMERSION 0x0563U // Immersion Corp.
+#define UHS_VID_KODAK_DIGITAL_PRODUCT_CENTER_JAPAN_LTD_FORMERLY_CHINON_INDUSTRIES 0x0564U // Kodak Digital Product Center, Japan Ltd. (formerly Chinon Industries Inc.)
+#define UHS_VID_PERACOM_NETWORKS 0x0565U // Peracom Networks, Inc.
+#define UHS_VID_MONTEREY_INTERNATIONAL 0x0566U // Monterey International Corp.
+#define UHS_VID_XYRATEX_INTERNATIONAL 0x0567U // Xyratex International, Ltd
+#define UHS_VID_QUARTZ_INGENIERIE 0x0568U // Quartz Ingenierie
+#define UHS_VID_SEGASOFT 0x0569U // SegaSoft
+#define UHS_VID_WACOM 0x056aU // Wacom Co., Ltd
+#define UHS_VID_DECICON 0x056bU // Decicon, Inc.
+#define UHS_VID_ETEK_LABS 0x056cU // eTEK Labs
+#define UHS_VID_EIZO 0x056dU // EIZO Corp.
+#define UHS_VID_ELECOM 0x056eU // Elecom Co., Ltd
+#define UHS_VID_KOREA_DATA_SYSTEMS 0x056fU // Korea Data Systems Co., Ltd
+#define UHS_VID_EPSON_AMERICA 0x0570U // Epson America
+#define UHS_VID_INTEREX 0x0571U // Interex, Inc.
+#define UHS_VID_CONEXANT_SYSTEMS_ROCKWELL 0x0572U // Conexant Systems (Rockwell), Inc.
+#define UHS_VID_ZORAN_CO_PERSONAL_MEDIA_DIVISION_NOGATECH 0x0573U // Zoran Co. Personal Media Division (Nogatech)
+#define UHS_VID_CITY_UNIVERSITY_OF_HONG_KONG 0x0574U // City University of Hong Kong
+#define UHS_VID_PHILIPS_CREATIVE_DISPLAY_SOLUTIONS 0x0575U // Philips Creative Display Solutions
+#define UHS_VID_BAFOQUALITY_COMPUTER_ACCESSORIES 0x0576U // BAFO/Quality Computer Accessories
+#define UHS_VID_ELSA 0x0577U // ELSA
+#define UHS_VID_INTRINSIX 0x0578U // Intrinsix Corp.
+#define UHS_VID_GVC 0x0579U // GVC Corp.
+#define UHS_VID_SAMSUNG_ELECTRONICS_AMERICA 0x057aU // Samsung Electronics America
+#define UHS_VID_Y_E_DATA 0x057bU // Y-E Data, Inc.
+#define UHS_VID_AVM 0x057cU // AVM GmbH
+#define UHS_VID_SHARK_MULTIMEDIA 0x057dU // Shark Multimedia, Inc.
+#define UHS_VID_NINTENDO 0x057eU // Nintendo Co., Ltd
+#define UHS_VID_QUICKSHOT 0x057fU // QuickShot, Ltd
+#define UHS_VID_DENRON 0x0580U // Denron, Inc.
+#define UHS_VID_RACAL_DATA_GROUP 0x0581U // Racal Data Group
+#define UHS_VID_ROLAND 0x0582U // Roland Corp.
+#define UHS_VID_PADIX_CO_LTD_ROCKFIRE 0x0583U // Padix Co., Ltd (Rockfire)
+#define UHS_VID_RATOC_SYSTEM 0x0584U // RATOC System, Inc.
+#define UHS_VID_FLASHPOINT_TECHNOLOGY 0x0585U // FlashPoint Technology, Inc.
+#define UHS_VID_ZYXEL_COMMUNICATIONS 0x0586U // ZyXEL Communications Corp.
+#define UHS_VID_AMERICA_KOTOBUKI_ELECTRONICS_INDUSTRIES 0x0587U // America Kotobuki Electronics Industries, Inc.
+#define UHS_VID_SAPIEN_DESIGN 0x0588U // Sapien Design
+#define UHS_VID_VICTRON 0x0589U // Victron
+#define UHS_VID_NOHAU 0x058aU // Nohau Corp.
+#define UHS_VID_INFINEON_TECHNOLOGIES 0x058bU // Infineon Technologies
+#define UHS_VID_IN_FOCUS_SYSTEMS 0x058cU // In Focus Systems
+#define UHS_VID_MICREL_SEMICONDUCTOR 0x058dU // Micrel Semiconductor
+#define UHS_VID_TRIPATH_TECHNOLOGY 0x058eU // Tripath Technology, Inc.
+#define UHS_VID_ALCOR_MICRO 0x058fU // Alcor Micro Corp.
+#define UHS_VID_OMRON 0x0590U // Omron Corp.
+#define UHS_VID_QUESTRA_CONSULTING 0x0591U // Questra Consulting
+#define UHS_VID_POWERWARE 0x0592U // Powerware Corp.
+#define UHS_VID_INCITE 0x0593U // Incite
+#define UHS_VID_PRINCETON_GRAPHIC_SYSTEMS 0x0594U // Princeton Graphic Systems
+#define UHS_VID_ZORAN_MICROELECTRONICS 0x0595U // Zoran Microelectronics, Ltd
+#define UHS_VID_MICROTOUCH_SYSTEMS 0x0596U // MicroTouch Systems, Inc.
+#define UHS_VID_TRISIGNAL_COMMUNICATIONS 0x0597U // Trisignal Communications
+#define UHS_VID_NIIGATA_CANOTEC 0x0598U // Niigata Canotec Co., Inc.
+#define UHS_VID_BRILLIANCE_SEMICONDUCTOR 0x0599U // Brilliance Semiconductor, Inc.
+#define UHS_VID_SPECTRUM_SIGNAL_PROCESSING 0x059aU // Spectrum Signal Processing, Inc.
+#define UHS_VID_IOMEGA 0x059bU // Iomega Corp.
+#define UHS_VID_A_TREND_TECHNOLOGY 0x059cU // A-Trend Technology Co., Ltd
+#define UHS_VID_ADVANCED_INPUT_DEVICES 0x059dU // Advanced Input Devices
+#define UHS_VID_INTELLIGENT_INSTRUMENTATION 0x059eU // Intelligent Instrumentation
+#define UHS_VID_LACIE 0x059fU // LaCie, Ltd
+#define UHS_VID_VETRONIX 0x05a0U // Vetronix Corp.
+#define UHS_VID_USC 0x05a1U // USC Corp.
+#define UHS_VID_FUJI_FILM_MICRODEVICES 0x05a2U // Fuji Film Microdevices Co., Ltd
+#define UHS_VID_ARC_INTERNATIONAL 0x05a3U // ARC International
+#define UHS_VID_ORTEK_TECHNOLOGY 0x05a4U // Ortek Technology, Inc.
+#define UHS_VID_SAMPO_TECHNOLOGY 0x05a5U // Sampo Technology Corp.
+#define UHS_VID_CISCO_SYSTEMS 0x05a6U // Cisco Systems, Inc.
+#define UHS_VID_BOSE 0x05a7U // Bose Corp.
+#define UHS_VID_SPACETEC_IMC 0x05a8U // Spacetec IMC Corp.
+#define UHS_VID_OMNIVISION_TECHNOLOGIES 0x05a9U // OmniVision Technologies, Inc.
+#define UHS_VID_UTILUX_SOUTH_CHINA 0x05aaU // Utilux South China, Ltd
+#define UHS_VID_IN_SYSTEM_DESIGN 0x05abU // In-System Design
+#define UHS_VID_APPLE 0x05acU // Apple, Inc.
+#define UHS_VID_YC_CABLE_USA 0x05adU // Y.C. Cable U.S.A., Inc.
+#define UHS_VID_SYNOPSYS_2 0x05aeU // Synopsys, Inc.
+#define UHS_VID_JING_MOLD_ENTERPRISE 0x05afU // Jing-Mold Enterprise Co., Ltd
+#define UHS_VID_FOUNTAIN_TECHNOLOGIES 0x05b0U // Fountain Technologies, Inc.
+#define UHS_VID_FIRST_INTERNATIONAL_COMPUTER 0x05b1U // First International Computer, Inc.
+#define UHS_VID_LG_SEMICON 0x05b4U // LG Semicon Co., Ltd
+#define UHS_VID_DIALOGIC 0x05b5U // Dialogic Corp.
+#define UHS_VID_PROXIMA 0x05b6U // Proxima Corp.
+#define UHS_VID_MEDIANIX_SEMICONDUCTOR 0x05b7U // Medianix Semiconductor, Inc.
+#define UHS_VID_AGILER 0x05b8U // Agiler, Inc.
+#define UHS_VID_PHILIPS_RESEARCH_LABORATORIES 0x05b9U // Philips Research Laboratories
+#define UHS_VID_DIGITALPERSONA 0x05baU // DigitalPersona, Inc.
+#define UHS_VID_GREY_CELL_SYSTEMS 0x05bbU // Grey Cell Systems
+#define UHS_VID_3G_GREEN_GREEN_GLOBE 0x05bcU // 3G Green Green Globe Co., Ltd
+#define UHS_VID_RAFI_GMBH_AND_CO_KG 0x05bdU // RAFI GmbH & Co. KG
+#define UHS_VID_TYCO_ELECTRONICS_RAYCHEM 0x05beU // Tyco Electronics (Raychem)
+#define UHS_VID_S_AND_S_RESEARCH 0x05bfU // S & S Research
+#define UHS_VID_KEIL_SOFTWARE 0x05c0U // Keil Software
+#define UHS_VID_KAWASAKI_MICROELECTRONICS 0x05c1U // Kawasaki Microelectronics, Inc.
+#define UHS_VID_MEDIA_PHONICS_SUISSE 0x05c2U // Media Phonics (Suisse) S.A.
+#define UHS_VID_DIGI_INTERNATIONAL_1 0x05c5U // Digi International, Inc.
+#define UHS_VID_QUALCOMM 0x05c6U // Qualcomm, Inc.
+#define UHS_VID_QTRONIX 0x05c7U // Qtronix Corp.
+#define UHS_VID_CHENG_UEI_PRECISION_INDUSTRY_CO_LTD_FOXLINK 0x05c8U // Cheng Uei Precision Industry Co., Ltd (Foxlink)
+#define UHS_VID_SEMTECH_1 0x05c9U // Semtech Corp.
+#define UHS_VID_RICOH 0x05caU // Ricoh Co., Ltd
+#define UHS_VID_POWERVISION_TECHNOLOGIES 0x05cbU // PowerVision Technologies, Inc.
+#define UHS_VID_ELSA_AG 0x05ccU // ELSA AG
+#define UHS_VID_SILICOM 0x05cdU // Silicom, Ltd
+#define UHS_VID_SCI_WORX 0x05ceU // sci-worx GmbH
+#define UHS_VID_SUNG_FORN 0x05cfU // Sung Forn Co., Ltd
+#define UHS_VID_GE_MEDICAL_SYSTEMS_LUNAR 0x05d0U // GE Medical Systems Lunar
+#define UHS_VID_BRAINBOXES 0x05d1U // Brainboxes, Ltd
+#define UHS_VID_WAVE_SYSTEMS 0x05d2U // Wave Systems Corp.
+#define UHS_VID_TOHOKU_RICOH 0x05d3U // Tohoku Ricoh Co., Ltd
+#define UHS_VID_SUPER_GATE_TECHNOLOGY 0x05d5U // Super Gate Technology Co., Ltd
+#define UHS_VID_PHILIPS_SEMICONDUCTORS_CICT 0x05d6U // Philips Semiconductors, CICT
+#define UHS_VID_THOMAS_AND_BETTS 0x05d7U // Thomas & Betts Corp.
+#define UHS_VID_ULTIMA_ELECTRONICS 0x05d8U // Ultima Electronics Corp.
+#define UHS_VID_AXIOHM_TRANSACTION_SOLUTIONS 0x05d9U // Axiohm Transaction Solutions
+#define UHS_VID_MICROTEK_INTERNATIONAL 0x05daU // Microtek International, Inc.
+#define UHS_VID_SUN_CORP_SUNTAC_UNKNOWN 0x05dbU // Sun Corp. (Suntac?)
+#define UHS_VID_LEXAR_MEDIA 0x05dcU // Lexar Media, Inc.
+#define UHS_VID_DELTA_ELECTRONICS 0x05ddU // Delta Electronics, Inc.
+#define UHS_VID_SILICON_VISION 0x05dfU // Silicon Vision, Inc.
+#define UHS_VID_SYMBOL_TECHNOLOGIES 0x05e0U // Symbol Technologies
+#define UHS_VID_SYNTEK_SEMICONDUCTOR 0x05e1U // Syntek Semiconductor Co., Ltd
+#define UHS_VID_ELECVISION 0x05e2U // ElecVision, Inc.
+#define UHS_VID_GENESYS_LOGIC 0x05e3U // Genesys Logic, Inc.
+#define UHS_VID_RED_WING 0x05e4U // Red Wing Corp.
+#define UHS_VID_FUJI_ELECTRIC 0x05e5U // Fuji Electric Co., Ltd
+#define UHS_VID_KEITHLEY_INSTRUMENTS 0x05e6U // Keithley Instruments
+#define UHS_VID_ICC 0x05e8U // ICC, Inc.
+#define UHS_VID_KAWASAKI_LSI 0x05e9U // Kawasaki LSI
+#define UHS_VID_FFC 0x05ebU // FFC, Ltd
+#define UHS_VID_COM21 0x05ecU // COM21, Inc.
+#define UHS_VID_CYTECHINFO 0x05eeU // Cytechinfo Inc.
+#define UHS_VID_AVB_INC_ANKO_UNKNOWN_ 0x05efU // AVB, Inc. [anko?]
+#define UHS_VID_CANOPUS 0x05f0U // Canopus Co., Ltd
+#define UHS_VID_COMPASS_COMMUNICATIONS 0x05f1U // Compass Communications
+#define UHS_VID_DEXIN 0x05f2U // Dexin Corp., Ltd
+#define UHS_VID_PI_ENGINEERING 0x05f3U // PI Engineering, Inc.
+#define UHS_VID_UNIXTAR_TECHNOLOGY 0x05f5U // Unixtar Technology, Inc.
+#define UHS_VID_AOC_INTERNATIONAL 0x05f6U // AOC International
+#define UHS_VID_RFC_DISTRIBUTIONS_PTE 0x05f7U // RFC Distribution(s) PTE, Ltd
+#define UHS_VID_PSC_SCANNING 0x05f9U // PSC Scanning, Inc.
+#define UHS_VID_SIEMENS_TELECOMMUNICATIONS_SYSTEMS 0x05faU // Siemens Telecommunications Systems, Ltd
+#define UHS_VID_HARMAN 0x05fcU // Harman
+#define UHS_VID_INTERACT 0x05fdU // InterAct, Inc.
+#define UHS_VID_CHIC_TECHNOLOGY 0x05feU // Chic Technology Corp.
+#define UHS_VID_LECROY 0x05ffU // LeCroy Corp.
+#define UHS_VID_BARCO_DISPLAY_SYSTEMS 0x0600U // Barco Display Systems
+#define UHS_VID_JAZZ_HIPSTER 0x0601U // Jazz Hipster Corp.
+#define UHS_VID_VISTA_IMAGING 0x0602U // Vista Imaging, Inc.
+#define UHS_VID_NOVATEK_MICROELECTRONICS 0x0603U // Novatek Microelectronics Corp.
+#define UHS_VID_JEAN 0x0604U // Jean Co., Ltd
+#define UHS_VID_ANCHOR_CANDC 0x0605U // Anchor C&C Co., Ltd
+#define UHS_VID_ROYAL_INFORMATION_ELECTRONICS 0x0606U // Royal Information Electronics Co., Ltd
+#define UHS_VID_BRIDGE_INFORMATION 0x0607U // Bridge Information Co., Ltd
+#define UHS_VID_GENRAD_ADS 0x0608U // Genrad Ads
+#define UHS_VID_SMK_MANUFACTURING 0x0609U // SMK Manufacturing, Inc.
+#define UHS_VID_WORTHINGTON_DATA_SOLUTIONS 0x060aU // Worthington Data Solutions, Inc.
+#define UHS_VID_SOLID_YEAR 0x060bU // Solid Year
+#define UHS_VID_EEH_DATALINK 0x060cU // EEH Datalink GmbH
+#define UHS_VID_AUCTOR 0x060dU // Auctor Corp.
+#define UHS_VID_TRANSMONDE_TECHNOLOGIES 0x060eU // Transmonde Technologies, Inc.
+#define UHS_VID_JOINSOON_ELECTRONICS_MFG 0x060fU // Joinsoon Electronics Mfg. Co., Ltd
+#define UHS_VID_COSTAR_ELECTRONICS 0x0610U // Costar Electronics, Inc.
+#define UHS_VID_TOTOKU_ELECTRIC 0x0611U // Totoku Electric Co., Ltd
+#define UHS_VID_TRANSACT_TECHNOLOGIES 0x0613U // TransAct Technologies, Inc.
+#define UHS_VID_BIO_RAD_LABORATORIES 0x0614U // Bio-Rad Laboratories
+#define UHS_VID_QUABBIN_WIRE_AND_CABLE 0x0615U // Quabbin Wire & Cable Co., Inc.
+#define UHS_VID_FUTURE_TECHNO_DESIGNS_PVT 0x0616U // Future Techno Designs PVT, Ltd
+#define UHS_VID_SWISS_FEDERAL_INSITUTE_OF_TECHNOLOGY 0x0617U // Swiss Federal Insitute of Technology
+#define UHS_VID_MACALLY 0x0618U // MacAlly
+#define UHS_VID_SEIKO_INSTRUMENTS 0x0619U // Seiko Instruments, Inc.
+#define UHS_VID_VERIDICOM_INTERNATIONAL 0x061aU // Veridicom International, Inc.
+#define UHS_VID_PROMPTUS_COMMUNICATIONS 0x061bU // Promptus Communications, Inc.
+#define UHS_VID_ACT_LABS 0x061cU // Act Labs, Ltd
+#define UHS_VID_QUATECH 0x061dU // Quatech, Inc.
+#define UHS_VID_NISSEI_ELECTRIC 0x061eU // Nissei Electric Co.
+#define UHS_VID_ALARIS 0x0620U // Alaris, Inc.
+#define UHS_VID_ODU_STECKVERBINDUNGSSYSTEME_GMBH_AND_CO_KG 0x0621U // ODU-Steckverbindungssysteme GmbH & Co. KG
+#define UHS_VID_IOTECH 0x0622U // Iotech, Inc.
+#define UHS_VID_LITTELFUSE 0x0623U // Littelfuse, Inc.
+#define UHS_VID_AVOCENT 0x0624U // Avocent Corp.
+#define UHS_VID_TIMEDIA_TECHNOLOGY 0x0625U // TiMedia Technology Co., Ltd
+#define UHS_VID_NIPPON_SYSTEMS_DEVELOPMENT 0x0626U // Nippon Systems Development Co., Ltd
+#define UHS_VID_ADOMAX_TECHNOLOGY 0x0627U // Adomax Technology Co., Ltd
+#define UHS_VID_TASKING_SOFTWARE 0x0628U // Tasking Software, Inc.
+#define UHS_VID_ZIDA_TECHNOLOGIES 0x0629U // Zida Technologies, Ltd
+#define UHS_VID_CREATIVE_LABS 0x062aU // Creative Labs
+#define UHS_VID_GREATLINK_ELECTRONICS_TAIWAN 0x062bU // Greatlink Electronics Taiwan, Ltd
+#define UHS_VID_INSTITUTE_FOR_INFORMATION_INDUSTRY 0x062cU // Institute for Information Industry
+#define UHS_VID_TAIWAN_TAI_HAO_ENTERPRISES 0x062dU // Taiwan Tai-Hao Enterprises Co., Ltd
+#define UHS_VID_MAINSUPER_ENTERPRISES 0x062eU // Mainsuper Enterprises Co., Ltd
+#define UHS_VID_SIN_SHENG_TERMINAL_AND_MACHINE 0x062fU // Sin Sheng Terminal & Machine, Inc.
+#define UHS_VID_JUJO_ELECTRONICS 0x0631U // JUJO Electronics Corp.
+#define UHS_VID_CYRIX 0x0633U // Cyrix Corp.
+#define UHS_VID_MICRON_TECHNOLOGY 0x0634U // Micron Technology, Inc.
+#define UHS_VID_METHODE_ELECTRONICS 0x0635U // Methode Electronics, Inc.
+#define UHS_VID_SIERRA_IMAGING 0x0636U // Sierra Imaging, Inc.
+#define UHS_VID_AVISION 0x0638U // Avision, Inc.
+#define UHS_VID_CHRONTEL 0x0639U // Chrontel, Inc.
+#define UHS_VID_TECHWIN 0x063aU // Techwin Corp.
+#define UHS_VID_TAUGAGREINING_HF_1 0x063bU // Taugagreining HF
+#define UHS_VID_YAMAICHI_ELECTRONICS_CO_LTD_SAKURA 0x063cU // Yamaichi Electronics Co., Ltd (Sakura)
+#define UHS_VID_FONG_KAI_INDUSTRIAL 0x063dU // Fong Kai Industrial Co., Ltd
+#define UHS_VID_REALMEDIA_TECHNOLOGY 0x063eU // RealMedia Technology, Inc.
+#define UHS_VID_NEW_TECHNOLOGY_CABLE 0x063fU // New Technology Cable, Ltd
+#define UHS_VID_HITEX_DEVELOPMENT_TOOLS 0x0640U // Hitex Development Tools
+#define UHS_VID_WOODS_INDUSTRIES 0x0641U // Woods Industries, Inc.
+#define UHS_VID_VIA_MEDICAL 0x0642U // VIA Medical Corp.
+#define UHS_VID_TEAC 0x0644U // TEAC Corp.
+#define UHS_VID_WHO_UNKNOWN_VISION_SYSTEMS 0x0645U // Who? Vision Systems, Inc.
+#define UHS_VID_UMAX 0x0646U // UMAX
+#define UHS_VID_ACTON_RESEARCH 0x0647U // Acton Research Corp.
+#define UHS_VID_INSIDE_OUT_NETWORKS 0x0648U // Inside Out Networks
+#define UHS_VID_WELI_SCIENCE 0x0649U // Weli Science Co., Ltd
+#define UHS_VID_ANALOG_DEVICES_INC_WHITE_MOUNTAIN_DSP 0x064bU // Analog Devices, Inc. (White Mountain DSP)
+#define UHS_VID_JI_HAW_INDUSTRIAL 0x064cU // Ji-Haw Industrial Co., Ltd
+#define UHS_VID_TRITECH_MICROELECTRONICS 0x064dU // TriTech Microelectronics, Ltd
+#define UHS_VID_SUYIN 0x064eU // Suyin Corp.
+#define UHS_VID_WIBU_SYSTEMS_AG 0x064fU // WIBU-Systems AG
+#define UHS_VID_DYNAPRO_SYSTEMS 0x0650U // Dynapro Systems
+#define UHS_VID_LIKOM_TECHNOLOGY_SDN_BHD 0x0651U // Likom Technology Sdn. Bhd.
+#define UHS_VID_STARGATE_SOLUTIONS 0x0652U // Stargate Solutions, Inc.
+#define UHS_VID_CNF 0x0653U // CNF, Inc.
+#define UHS_VID_GRANITE_MICROSYSTEMS 0x0654U // Granite Microsystems, Inc.
+#define UHS_VID_SPACE_SHUTTLE_HI_TECH 0x0655U // Space Shuttle Hi-Tech Co., Ltd
+#define UHS_VID_GLORY_MARK_ELECTRONIC 0x0656U // Glory Mark Electronic, Ltd
+#define UHS_VID_TEKCON_ELECTRONICS 0x0657U // Tekcon Electronics Corp.
+#define UHS_VID_SIGMA_DESIGNS 0x0658U // Sigma Designs, Inc.
+#define UHS_VID_AETHRA 0x0659U // Aethra
+#define UHS_VID_OPTOELECTRONICS 0x065aU // Optoelectronics Co., Ltd
+#define UHS_VID_TRACEWELL_SYSTEMS 0x065bU // Tracewell Systems
+#define UHS_VID_SILICON_GRAPHICS_1 0x065eU // Silicon Graphics
+#define UHS_VID_GOOD_WAY_TECHNOLOGY_CO_LTD_AND_GWC_TECHNOLOGY 0x065fU // Good Way Technology Co., Ltd & GWC technology Inc.
+#define UHS_VID_TSAY_E_BVI_INTERNATIONAL 0x0660U // TSAY-E (BVI) International, Inc.
+#define UHS_VID_HAMAMATSU_PHOTONICS_KK 0x0661U // Hamamatsu Photonics K.K.
+#define UHS_VID_KANSAI_ELECTRIC 0x0662U // Kansai Electric Co., Ltd
+#define UHS_VID_TOPMAX_ELECTRONIC 0x0663U // Topmax Electronic Co., Ltd
+#define UHS_VID_ETANDT_TECHNOLOGY 0x0664U // ET&T Technology Co., Ltd.
+#define UHS_VID_CYPRESS_SEMICONDUCTOR_1 0x0665U // Cypress Semiconductor
+#define UHS_VID_AIWA 0x0667U // Aiwa Co., Ltd
+#define UHS_VID_WORDWAND 0x0668U // WordWand
+#define UHS_VID_OCE_PRINTING_SYSTEMS 0x0669U // Oce' Printing Systems GmbH
+#define UHS_VID_TOTAL_TECHNOLOGIES 0x066aU // Total Technologies, Ltd
+#define UHS_VID_LINKSYS 0x066bU // Linksys, Inc.
+#define UHS_VID_ENTREGA 0x066dU // Entrega, Inc.
+#define UHS_VID_ACER_SEMICONDUCTOR_AMERICA 0x066eU // Acer Semiconductor America, Inc.
+#define UHS_VID_SIGMATEL 0x066fU // SigmaTel, Inc.
+#define UHS_VID_SEQUEL_IMAGING 0x0670U // Sequel Imaging
+#define UHS_VID_LABTEC 0x0672U // Labtec, Inc.
+#define UHS_VID_HCL 0x0673U // HCL
+#define UHS_VID_KEY_MOUSE_ELECTRONIC_ENTERPRISE 0x0674U // Key Mouse Electronic Enterprise Co., Ltd
+#define UHS_VID_DRAYTEK 0x0675U // DrayTek Corp.
+#define UHS_VID_TELES_AG 0x0676U // Teles AG
+#define UHS_VID_AIWA_1 0x0677U // Aiwa Co., Ltd
+#define UHS_VID_ACARD_TECHNOLOGY 0x0678U // ACard Technology Corp.
+#define UHS_VID_PROLIFIC_TECHNOLOGY 0x067bU // Prolific Technology, Inc.
+#define UHS_VID_EFFICIENT_NETWORKS 0x067cU // Efficient Networks, Inc.
+#define UHS_VID_HOHNER 0x067dU // Hohner Corp.
+#define UHS_VID_INTERMEC_TECHNOLOGIES 0x067eU // Intermec Technologies Corp.
+#define UHS_VID_VIRATA 0x067fU // Virata, Ltd
+#define UHS_VID_REALTEK_SEMICONDUCTOR_CORP_CPP_DIV_AVANCE_LOGIC 0x0680U // Realtek Semiconductor Corp., CPP Div. (Avance Logic)
+#define UHS_VID_SIEMENS_INFORMATION_AND_COMMUNICATION_PRODUCTS 0x0681U // Siemens Information and Communication Products
+#define UHS_VID_VICTOR_COMPANY_OF_JAPAN_1 0x0682U // Victor Company of Japan, Ltd
+#define UHS_VID_ACTIONTEC_ELECTRONICS 0x0684U // Actiontec Electronics, Inc.
+#define UHS_VID_ZD_INCORPORATED 0x0685U // ZD Incorporated
+#define UHS_VID_MINOLTA 0x0686U // Minolta Co., Ltd
+#define UHS_VID_PERTECH 0x068aU // Pertech, Inc.
+#define UHS_VID_POTRANS_INTERNATIONAL 0x068bU // Potrans International, Inc.
+#define UHS_VID_CH_PRODUCTS 0x068eU // CH Products, Inc.
+#define UHS_VID_GOLDEN_BRIDGE_ELECTECH 0x0690U // Golden Bridge Electech, Inc.
+#define UHS_VID_HAGIWARA_SYS_COM 0x0693U // Hagiwara Sys-Com Co., Ltd
+#define UHS_VID_LEGO_GROUP 0x0694U // Lego Group
+#define UHS_VID_CHUNTEX_CTX 0x0698U // Chuntex (CTX)
+#define UHS_VID_TEKTRONIX 0x0699U // Tektronix, Inc.
+#define UHS_VID_ASKEY_COMPUTER 0x069aU // Askey Computer Corp.
+#define UHS_VID_THOMSON 0x069bU // Thomson, Inc.
+#define UHS_VID_HUGHES_NETWORK_SYSTEMS_HNS 0x069dU // Hughes Network Systems (HNS)
+#define UHS_VID_WELCAT 0x069eU // Welcat Inc.
+#define UHS_VID_ALLIED_DATA_TECHNOLOGIES_BV 0x069fU // Allied Data Technologies BV
+#define UHS_VID_TOPRO_TECHNOLOGY 0x06a2U // Topro Technology, Inc.
+#define UHS_VID_SAITEK_PLC 0x06a3U // Saitek PLC
+#define UHS_VID_XIAMEN_DOOWELL_ELECTRON 0x06a4U // Xiamen Doowell Electron Co., Ltd
+#define UHS_VID_DIVIO 0x06a5U // Divio
+#define UHS_VID_MICROSTORE 0x06a7U // MicroStore, Inc.
+#define UHS_VID_TOPAZ_SYSTEMS 0x06a8U // Topaz Systems, Inc.
+#define UHS_VID_WESTELL 0x06a9U // Westell
+#define UHS_VID_SYSGRATION 0x06aaU // Sysgration, Ltd
+#define UHS_VID_FUJITSU_LABORATORIES_OF_AMERICA 0x06acU // Fujitsu Laboratories of America, Inc.
+#define UHS_VID_GREATLAND_ELECTRONICS_TAIWAN 0x06adU // Greatland Electronics Taiwan, Ltd
+#define UHS_VID_PROFESSIONAL_MULTIMEDIA_TESTING_CENTRE 0x06aeU // Professional Multimedia Testing Centre
+#define UHS_VID_HARTING_INC_OF_NORTH_AMERICA 0x06afU // Harting, Inc. of North America
+#define UHS_VID_PIXELA 0x06b8U // Pixela Corp.
+#define UHS_VID_ALCATEL_TELECOM 0x06b9U // Alcatel Telecom
+#define UHS_VID_SMOOTH_CORD_AND_CONNECTOR 0x06baU // Smooth Cord & Connector Co., Ltd
+#define UHS_VID_EDA 0x06bbU // EDA, Inc.
+#define UHS_VID_OKI_DATA 0x06bcU // Oki Data Corp.
+#define UHS_VID_AGFA_GEVAERT_NV 0x06bdU // AGFA-Gevaert NV
+#define UHS_VID_AME_OPTIMEDIA_TECHNOLOGY 0x06beU // AME Optimedia Technology Co., Ltd
+#define UHS_VID_LEOCO 0x06bfU // Leoco Corp.
+#define UHS_VID_PHIDGETS_INC_FORMERLY_GLAB 0x06c2U // Phidgets Inc. (formerly GLAB)
+#define UHS_VID_BIZLINK_INTERNATIONAL 0x06c4U // Bizlink International Corp.
+#define UHS_VID_HAGENUK 0x06c5U // Hagenuk, GmbH
+#define UHS_VID_INFOWAVE_SOFTWARE 0x06c6U // Infowave Software, Inc.
+#define UHS_VID_SIIG 0x06c8U // SIIG, Inc.
+#define UHS_VID_TAXAN_EUROPE 0x06c9U // Taxan (Europe), Ltd
+#define UHS_VID_NEWER_TECHNOLOGY 0x06caU // Newer Technology, Inc.
+#define UHS_VID_SYNAPTICS 0x06cbU // Synaptics, Inc.
+#define UHS_VID_TERAYON_COMMUNICATION_SYSTEMS 0x06ccU // Terayon Communication Systems
+#define UHS_VID_KEYSPAN 0x06cdU // Keyspan
+#define UHS_VID_CONTEC 0x06ceU // Contec
+#define UHS_VID_SPHERONVR_AG 0x06cfU // SpheronVR AG
+#define UHS_VID_LAPLINK 0x06d0U // LapLink, Inc.
+#define UHS_VID_DAEWOO_ELECTRONICS_1 0x06d1U // Daewoo Electronics Co., Ltd
+#define UHS_VID_MITSUBISHI_ELECTRIC 0x06d3U // Mitsubishi Electric Corp.
+#define UHS_VID_CISCO_SYSTEMS_1 0x06d4U // Cisco Systems
+#define UHS_VID_TOSHIBA 0x06d5U // Toshiba
+#define UHS_VID_AASHIMA_TECHNOLOGY_BV 0x06d6U // Aashima Technology B.V.
+#define UHS_VID_NETWORK_COMPUTING_DEVICES_NCD 0x06d7U // Network Computing Devices (NCD)
+#define UHS_VID_TECHNICAL_MARKETING_RESEARCH 0x06d8U // Technical Marketing Research, Inc.
+#define UHS_VID_PHOENIXTEC_POWER 0x06daU // Phoenixtec Power Co., Ltd
+#define UHS_VID_PARADYNE 0x06dbU // Paradyne
+#define UHS_VID_FOXLINK_IMAGE_TECHNOLOGY 0x06dcU // Foxlink Image Technology Co., Ltd
+#define UHS_VID_HEISEI_ELECTRONICS 0x06deU // Heisei Electronics Co., Ltd
+#define UHS_VID_MULTI_TECH_SYSTEMS 0x06e0U // Multi-Tech Systems, Inc.
+#define UHS_VID_ADS_TECHNOLOGIES 0x06e1U // ADS Technologies, Inc.
+#define UHS_VID_ALCATEL_MICROELECTRONICS 0x06e4U // Alcatel Microelectronics
+#define UHS_VID_TIGER_JET_NETWORK 0x06e6U // Tiger Jet Network, Inc.
+#define UHS_VID_SIRIUS_TECHNOLOGIES 0x06eaU // Sirius Technologies
+#define UHS_VID_PC_EXPERT_TECH 0x06ebU // PC Expert Tech. Co., Ltd
+#define UHS_VID_IAC_GEOMETRISCHE_INGENIEURS_BV 0x06efU // I.A.C. Geometrische Ingenieurs B.V.
+#define UHS_VID_TNC_INDUSTRIAL 0x06f0U // T.N.C Industrial Co., Ltd
+#define UHS_VID_OPCODE_SYSTEMS 0x06f1U // Opcode Systems, Inc.
+#define UHS_VID_EMINE_TECHNOLOGY 0x06f2U // Emine Technology Co.
+#define UHS_VID_WINTREND_TECHNOLOGY 0x06f6U // Wintrend Technology Co., Ltd
+#define UHS_VID_WAILLY_TECHNOLOGY 0x06f7U // Wailly Technology Ltd
+#define UHS_VID_GUILLEMOT 0x06f8U // Guillemot Corp.
+#define UHS_VID_ASYST_ELECTRONIC_DOO 0x06f9U // ASYST electronic d.o.o.
+#define UHS_VID_HSD_SRL 0x06faU // HSD S.r.L
+#define UHS_VID_MOTOROLA_SEMICONDUCTOR_PRODUCTS_SECTOR 0x06fcU // Motorola Semiconductor Products Sector
+#define UHS_VID_BOSTON_ACOUSTICS 0x06fdU // Boston Acoustics
+#define UHS_VID_GALLANT_COMPUTER 0x06feU // Gallant Computer, Inc.
+#define UHS_VID_SUPERCOMAL_WIRE_AND_CABLE_SDN_BHD 0x0701U // Supercomal Wire & Cable SDN. BHD.
+#define UHS_VID_BVTECH_INDUSTRY 0x0703U // Bvtech Industry, Inc.
+#define UHS_VID_NKK 0x0705U // NKK Corp.
+#define UHS_VID_ARIEL 0x0706U // Ariel Corp.
+#define UHS_VID_STANDARD_MICROSYSTEMS_2 0x0707U // Standard Microsystems Corp.
+#define UHS_VID_PUTERCOM 0x0708U // Putercom Co., Ltd
+#define UHS_VID_SILICON_SYSTEMS_LTD_SSL 0x0709U // Silicon Systems, Ltd (SSL)
+#define UHS_VID_OKI_ELECTRIC_INDUSTRY 0x070aU // Oki Electric Industry Co., Ltd
+#define UHS_VID_COMOSS_ELECTRONIC 0x070dU // Comoss Electronic Co., Ltd
+#define UHS_VID_EXCEL_CELL_ELECTRONIC 0x070eU // Excel Cell Electronic Co., Ltd
+#define UHS_VID_CONNECT_TECH 0x0710U // Connect Tech, Inc.
+#define UHS_VID_MAGIC_CONTROL_TECHNOLOGY 0x0711U // Magic Control Technology Corp.
+#define UHS_VID_INTERVAL_RESEARCH 0x0713U // Interval Research Corp.
+#define UHS_VID_NEWMOTION 0x0714U // NewMotion, Inc.
+#define UHS_VID_ZNK 0x0717U // ZNK Corp.
+#define UHS_VID_IMATION 0x0718U // Imation Corp.
+#define UHS_VID_TREMON_ENTERPRISES 0x0719U // Tremon Enterprises Co., Ltd
+#define UHS_VID_DOMAIN_TECHNOLOGIES 0x071bU // Domain Technologies, Inc.
+#define UHS_VID_XIONICS_DOCUMENT_TECHNOLOGIES 0x071cU // Xionics Document Technologies, Inc.
+#define UHS_VID_EICON_NETWORKS 0x071dU // Eicon Networks Corp.
+#define UHS_VID_ARISTON_TECHNOLOGIES 0x071eU // Ariston Technologies
+#define UHS_VID_CENTILLIUM_COMMUNICATIONS 0x0723U // Centillium Communications Corp.
+#define UHS_VID_VANGUARD_INTERNATIONAL_SEMICONDUCTOR_AMERICA 0x0726U // Vanguard International Semiconductor-America
+#define UHS_VID_AMITM 0x0729U // Amitm
+#define UHS_VID_SUNIX 0x072eU // Sunix Co., Ltd
+#define UHS_VID_ADVANCED_CARD_SYSTEMS 0x072fU // Advanced Card Systems, Ltd
+#define UHS_VID_SUSTEEN 0x0731U // Susteen, Inc.
+#define UHS_VID_GOLDFULL_ELECTRONICS_AND_TELECOMMUNICATIONS 0x0732U // Goldfull Electronics & Telecommunications Corp.
+#define UHS_VID_VIEWQUEST_TECHNOLOGIES 0x0733U // ViewQuest Technologies, Inc.
+#define UHS_VID_LASAT_COMMUNICATIONS_AS 0x0734U // Lasat Communications A/S
+#define UHS_VID_ASUSCOM_NETWORK 0x0735U // Asuscom Network
+#define UHS_VID_LOROM_INDUSTRIAL 0x0736U // Lorom Industrial Co., Ltd
+#define UHS_VID_MAD_CATZ 0x0738U // Mad Catz, Inc.
+#define UHS_VID_CHAPLET_SYSTEMS 0x073aU // Chaplet Systems, Inc.
+#define UHS_VID_SUNCOM_TECHNOLOGIES 0x073bU // Suncom Technologies
+#define UHS_VID_INDUSTRIAL_ELECTRONIC_ENGINEERS 0x073cU // Industrial Electronic Engineers, Inc.
+#define UHS_VID_EUTRON_SPA 0x073dU // Eutron S.p.a.
+#define UHS_VID_NEC_1 0x073eU // NEC, Inc.
+#define UHS_VID_STOLLMANN 0x0742U // Stollmann
+#define UHS_VID_SYNTECH_INFORMATION 0x0745U // Syntech Information Co., Ltd
+#define UHS_VID_ONKYO 0x0746U // Onkyo Corp.
+#define UHS_VID_LABWAY 0x0747U // Labway Corp.
+#define UHS_VID_STRONG_MAN_ENTERPRISE 0x0748U // Strong Man Enterprise Co., Ltd
+#define UHS_VID_EVER_ELECTRONICS 0x0749U // EVer Electronics Corp.
+#define UHS_VID_MING_FORTUNE_INDUSTRY 0x074aU // Ming Fortune Industry Co., Ltd
+#define UHS_VID_POLESTAR_TECH 0x074bU // Polestar Tech. Corp.
+#define UHS_VID_C_C_C_GROUP_PLC 0x074cU // C-C-C Group PLC
+#define UHS_VID_MICRONAS 0x074dU // Micronas GmbH
+#define UHS_VID_DIGITAL_STREAM 0x074eU // Digital Stream Corp.
+#define UHS_VID_AUREAL_SEMICONDUCTOR 0x0755U // Aureal Semiconductor
+#define UHS_VID_NETWORK_TECHNOLOGIES 0x0757U // Network Technologies, Inc.
+#define UHS_VID_SOPHISTICATED_CIRCUITS 0x075bU // Sophisticated Circuits, Inc.
+#define UHS_VID_MIDIMAN 0x0763U // Midiman
+#define UHS_VID_CYBER_POWER_SYSTEM 0x0764U // Cyber Power System, Inc.
+#define UHS_VID_X_RITE 0x0765U // X-Rite, Inc.
+#define UHS_VID_JESS_LINK_PRODUCTS 0x0766U // Jess-Link Products Co., Ltd
+#define UHS_VID_TOKHEIM 0x0767U // Tokheim Corp.
+#define UHS_VID_CAMTEL_TECHNOLOGY 0x0768U // Camtel Technology Corp.
+#define UHS_VID_SURECOM_TECHNOLOGY 0x0769U // Surecom Technology Corp.
+#define UHS_VID_SMART_TECHNOLOGY_ENABLERS 0x076aU // Smart Technology Enablers, Inc.
+#define UHS_VID_OMNIKEY_AG 0x076bU // OmniKey AG
+#define UHS_VID_PARTNER_TECH 0x076cU // Partner Tech
+#define UHS_VID_DENSO 0x076dU // Denso Corp.
+#define UHS_VID_KUAN_TECH_ENTERPRISE 0x076eU // Kuan Tech Enterprise Co., Ltd
+#define UHS_VID_JHEN_VEI_ELECTRONIC 0x076fU // Jhen Vei Electronic Co., Ltd
+#define UHS_VID_WELCH_ALLYN_INC__MEDICAL_DIVISION 0x0770U // Welch Allyn, Inc - Medical Division
+#define UHS_VID_OBSERVATOR_INSTRUMENTS_BV 0x0771U // Observator Instruments BV
+#define UHS_VID_YOUR_DATA_OUR_CARE 0x0772U // Your data Our Care
+#define UHS_VID_AMTRAN_TECHNOLOGY 0x0774U // AmTRAN Technology Co., Ltd
+#define UHS_VID_LONGSHINE_ELECTRONICS 0x0775U // Longshine Electronics Corp.
+#define UHS_VID_INALWAYS 0x0776U // Inalways Corp.
+#define UHS_VID_COMDA_ENTERPRISE 0x0777U // Comda Enterprise Corp.
+#define UHS_VID_VOLEX 0x0778U // Volex, Inc.
+#define UHS_VID_FAIRCHILD_SEMICONDUCTOR 0x0779U // Fairchild Semiconductor
+#define UHS_VID_SANKYO_SEIKI_MFG 0x077aU // Sankyo Seiki Mfg. Co., Ltd
+#define UHS_VID_LINKSYS_1 0x077bU // Linksys
+#define UHS_VID_FORWARD_ELECTRONICS 0x077cU // Forward Electronics Co., Ltd
+#define UHS_VID_GRIFFIN_TECHNOLOGY 0x077dU // Griffin Technology
+#define UHS_VID_WELL_EXCELLENT_AND_MOST 0x077fU // Well Excellent & Most Corp.
+#define UHS_VID_SAGEM_MONETEL 0x0780U // Sagem Monetel GmbH
+#define UHS_VID_SANDISK 0x0781U // SanDisk Corp.
+#define UHS_VID_TRACKERBALL 0x0782U // Trackerball
+#define UHS_VID_C3PO 0x0783U // C3PO
+#define UHS_VID_VIVITAR 0x0784U // Vivitar, Inc.
+#define UHS_VID_NTT_ME 0x0785U // NTT-ME
+#define UHS_VID_LOGITEC 0x0789U // Logitec Corp.
+#define UHS_VID_HAPP_CONTROLS 0x078bU // Happ Controls, Inc.
+#define UHS_VID_GTCOCALCOMP 0x078cU // GTCO/CalComp
+#define UHS_VID_BRINCOM 0x078eU // Brincom, Inc.
+#define UHS_VID_PRO_IMAGE_MANUFACTURING 0x0790U // Pro-Image Manufacturing Co., Ltd
+#define UHS_VID_COPARTNER_WIRE_AND_CABLE_MFG 0x0791U // Copartner Wire and Cable Mfg. Corp.
+#define UHS_VID_AXIS_COMMUNICATIONS 0x0792U // Axis Communications AB
+#define UHS_VID_WHA_YU_INDUSTRIAL 0x0793U // Wha Yu Industrial Co., Ltd
+#define UHS_VID_ABL_ELECTRONICS 0x0794U // ABL Electronics Corp.
+#define UHS_VID_REALCHIP 0x0795U // RealChip, Inc.
+#define UHS_VID_CERTICOM 0x0796U // Certicom Corp.
+#define UHS_VID_GRANDTECH_SEMICONDUCTOR 0x0797U // Grandtech Semiconductor Corp.
+#define UHS_VID_OPTELEC 0x0798U // Optelec
+#define UHS_VID_ALTERA 0x0799U // Altera
+#define UHS_VID_SAGEM 0x079bU // Sagem
+#define UHS_VID_ALFADATA_COMPUTER 0x079dU // Alfadata Computer Corp.
+#define UHS_VID_DIGICOM_SPA 0x07a1U // Digicom S.p.A.
+#define UHS_VID_NATIONAL_TECHNICAL_SYSTEMS 0x07a2U // National Technical Systems
+#define UHS_VID_ONNTO 0x07a3U // Onnto Corp.
+#define UHS_VID_BE 0x07a4U // Be, Inc.
+#define UHS_VID_ADMTEK 0x07a6U // ADMtek, Inc.
+#define UHS_VID_COREGA_KK 0x07aaU // Corega K.K.
+#define UHS_VID_FREECOM_TECHNOLOGIES 0x07abU // Freecom Technologies
+#define UHS_VID_MICROTECH 0x07afU // Microtech
+#define UHS_VID_TRUST_TECHNOLOGIES 0x07b0U // Trust Technologies
+#define UHS_VID_IMP 0x07b1U // IMP, Inc.
+#define UHS_VID_MOTOROLA_BCS 0x07b2U // Motorola BCS, Inc.
+#define UHS_VID_PLUSTEK 0x07b3U // Plustek, Inc.
+#define UHS_VID_OLYMPUS_OPTICAL 0x07b4U // Olympus Optical Co., Ltd
+#define UHS_VID_MEGA_WORLD_INTERNATIONAL 0x07b5U // Mega World International, Ltd
+#define UHS_VID_MARUBUN 0x07b6U // Marubun Corp.
+#define UHS_VID_TIME_INTERCONNECT 0x07b7U // TIME Interconnect, Ltd
+#define UHS_VID_ABOCOM_SYSTEMS 0x07b8U // AboCom Systems Inc
+#define UHS_VID_CANON_COMPUTER_SYSTEMS 0x07bcU // Canon Computer Systems, Inc.
+#define UHS_VID_WEBGEAR 0x07bdU // Webgear, Inc.
+#define UHS_VID_VERIDICOM 0x07beU // Veridicom
+#define UHS_VID_CODE_MERCENARIES_HARD_UND_SOFTWARE 0x07c0U // Code Mercenaries Hard- und Software GmbH
+#define UHS_VID_KEISOKUGIKEN 0x07c1U // Keisokugiken
+#define UHS_VID_DATAFAB_SYSTEMS 0x07c4U // Datafab Systems, Inc.
+#define UHS_VID_APG_CASH_DRAWER 0x07c5U // APG Cash Drawer
+#define UHS_VID_SHAREWAVE 0x07c6U // ShareWave, Inc.
+#define UHS_VID_POWERTECH_INDUSTRIAL 0x07c7U // Powertech Industrial Co., Ltd
+#define UHS_VID_BUG 0x07c8U // B.U.G., Inc.
+#define UHS_VID_ALLIED_TELESYN_INTERNATIONAL 0x07c9U // Allied Telesyn International
+#define UHS_VID_AVERMEDIA_TECHNOLOGIES 0x07caU // AVerMedia Technologies, Inc.
+#define UHS_VID_KINGMAX_TECHNOLOGY 0x07cbU // Kingmax Technology, Inc.
+#define UHS_VID_CARRY_COMPUTER_ENG 0x07ccU // Carry Computer Eng., Co., Ltd
+#define UHS_VID_ELEKTOR 0x07cdU // Elektor
+#define UHS_VID_CASIO_COMPUTER 0x07cfU // Casio Computer Co., Ltd
+#define UHS_VID_DAZZLE 0x07d0U // Dazzle
+#define UHS_VID_D_LINK_SYSTEM 0x07d1U // D-Link System
+#define UHS_VID_APTIO_PRODUCTS 0x07d2U // Aptio Products, Inc.
+#define UHS_VID_CYBERDATA 0x07d3U // Cyberdata Corp.
+#define UHS_VID_RADIANT_SYSTEMS 0x07d5U // Radiant Systems
+#define UHS_VID_GCC_TECHNOLOGIES 0x07d7U // GCC Technologies, Inc.
+#define UHS_VID_ARASAN_CHIP_SYSTEMS 0x07daU // Arasan Chip Systems
+#define UHS_VID_DIAMOND_MULTIMEDIA 0x07deU // Diamond Multimedia
+#define UHS_VID_DAVID_ELECTRONICS 0x07dfU // David Electronics Co., Ltd
+#define UHS_VID_AMBIENT_TECHNOLOGIES 0x07e1U // Ambient Technologies, Inc.
+#define UHS_VID_ELMEG_GMBH_AND 0x07e2U // Elmeg GmbH & Co., Ltd
+#define UHS_VID_PLANEX_COMMUNICATIONS 0x07e3U // Planex Communications, Inc.
+#define UHS_VID_MOVADO_ENTERPRISE 0x07e4U // Movado Enterprise Co., Ltd
+#define UHS_VID_QPS 0x07e5U // QPS, Inc.
+#define UHS_VID_ALLIED_CABLE 0x07e6U // Allied Cable Corp.
+#define UHS_VID_MIRVO_TOYS 0x07e7U // Mirvo Toys, Inc.
+#define UHS_VID_LABSYSTEMS 0x07e8U // Labsystems
+#define UHS_VID_IWATSU_ELECTRIC 0x07eaU // Iwatsu Electric Co., Ltd
+#define UHS_VID_DOUBLE_H_TECHNOLOGY 0x07ebU // Double-H Technology Co., Ltd
+#define UHS_VID_TAIYO_ELECTRIC_WIRE_AND_CABLE 0x07ecU // Taiyo Electric Wire & Cable Co., Ltd
+#define UHS_VID_TOREX_RETAIL_FORMERLY_LOGWARE 0x07eeU // Torex Retail (formerly Logware)
+#define UHS_VID_STSN 0x07efU // STSN
+#define UHS_VID_MICROCOMPUTER_APPLICATIONS 0x07f2U // Microcomputer Applications, Inc.
+#define UHS_VID_CIRCUIT_ASSEMBLY 0x07f6U // Circuit Assembly Corp.
+#define UHS_VID_CENTURY 0x07f7U // Century Corp.
+#define UHS_VID_DOTOP_TECHNOLOGY 0x07f9U // Dotop Technology, Inc.
+#define UHS_VID_DRAYTEK_1 0x07faU // DrayTek Corp.
+#define UHS_VID_MARK_OF_THE_UNICORN 0x07fdU // Mark of the Unicorn
+#define UHS_VID_UNKNOWN_2 0x07ffU // Unknown
+#define UHS_VID_MAGTEK 0x0801U // MagTek
+#define UHS_VID_MAKO_TECHNOLOGIES 0x0802U // Mako Technologies, LLC
+#define UHS_VID_ZOOM_TELEPHONICS 0x0803U // Zoom Telephonics, Inc.
+#define UHS_VID_GENICOM_TECHNOLOGY 0x0809U // Genicom Technology, Inc.
+#define UHS_VID_EVERMUCH_TECHNOLOGY 0x080aU // Evermuch Technology Co., Ltd
+#define UHS_VID_CROSS_MATCH_TECHNOLOGIES 0x080bU // Cross Match Technologies
+#define UHS_VID_DATALOGIC_SPA 0x080cU // Datalogic S.p.A.
+#define UHS_VID_TECO_IMAGE_SYSTEMS 0x080dU // Teco Image Systems Co., Ltd
+#define UHS_VID_PERSONAL_COMMUNICATION_SYSTEMS 0x0810U // Personal Communication Systems, Inc.
+#define UHS_VID_MATTEL 0x0813U // Mattel, Inc.
+#define UHS_VID_ELICENSER 0x0819U // eLicenser
+#define UHS_VID_MG_LOGIC 0x081aU // MG Logic
+#define UHS_VID_INDIGITA 0x081bU // Indigita Corp.
+#define UHS_VID_MIPSYS 0x081cU // Mipsys
+#define UHS_VID_ALPHASMART 0x081eU // AlphaSmart, Inc.
+#define UHS_VID_REUDO 0x0822U // Reudo Corp.
+#define UHS_VID_GC_PROTRONICS 0x0825U // GC Protronics
+#define UHS_VID_DATA_TRANSIT 0x0826U // Data Transit
+#define UHS_VID_BROADLOGIC 0x0827U // BroadLogic, Inc.
+#define UHS_VID_SATO 0x0828U // Sato Corp.
+#define UHS_VID_DIRECTV_BROADBAND_INC_TELOCITY 0x0829U // DirecTV Broadband, Inc. (Telocity)
+#define UHS_VID_HANDSPRING 0x082dU // Handspring
+#define UHS_VID_PALM 0x0830U // Palm, Inc.
+#define UHS_VID_KOUWELL_ELECTRONICS 0x0832U // Kouwell Electronics Corp.
+#define UHS_VID_SOURCENEXT 0x0833U // Sourcenext Corp.
+#define UHS_VID_ACTION_STAR_ENTERPRISE 0x0835U // Action Star Enterprise Co., Ltd
+#define UHS_VID_TREKSTOR 0x0836U // TrekStor
+#define UHS_VID_SAMSUNG_TECHWIN 0x0839U // Samsung Techwin Co., Ltd
+#define UHS_VID_ACCTON_TECHNOLOGY 0x083aU // Accton Technology Corp.
+#define UHS_VID_GLOBAL_VILLAGE 0x083fU // Global Village
+#define UHS_VID_ARGOSY_RESEARCH 0x0840U // Argosy Research, Inc.
+#define UHS_VID_RIOPORTCOM 0x0841U // Rioport.com, Inc.
+#define UHS_VID_WELLAND_INDUSTRIAL 0x0844U // Welland Industrial Co., Ltd
+#define UHS_VID_NETGEAR 0x0846U // NetGear, Inc.
+#define UHS_VID_MINTON_OPTIC_INDUSTRY 0x084dU // Minton Optic Industry Co., Inc.
+#define UHS_VID_KB_GEAR 0x084eU // KB Gear
+#define UHS_VID_EMPEG 0x084fU // Empeg
+#define UHS_VID_FAST_POINT_TECHNOLOGIES 0x0850U // Fast Point Technologies, Inc.
+#define UHS_VID_MACRONIX_INTERNATIONAL 0x0851U // Macronix International Co., Ltd
+#define UHS_VID_CSEM 0x0852U // CSEM
+#define UHS_VID_TOPRE_CORPORATION 0x0853U // Topre Corporation
+#define UHS_VID_ACTIVEWIRE 0x0854U // ActiveWire, Inc.
+#define UHS_VID_BANDB_ELECTRONICS 0x0856U // B&B Electronics
+#define UHS_VID_HITACHI_MAXELL 0x0858U // Hitachi Maxell, Ltd
+#define UHS_VID_MINOLTA_SYSTEMS_LABORATORY 0x0859U // Minolta Systems Laboratory, Inc.
+#define UHS_VID_XIRCOM 0x085aU // Xircom
+#define UHS_VID_COLORVISION 0x085cU // ColorVision, Inc.
+#define UHS_VID_TELETROL_SYSTEMS 0x0862U // Teletrol Systems, Inc.
+#define UHS_VID_FILANET 0x0863U // Filanet Corp.
+#define UHS_VID_NETGEAR_1 0x0864U // NetGear, Inc.
+#define UHS_VID_DATA_TRANSLATION 0x0867U // Data Translation, Inc.
+#define UHS_VID_EMAGIC_SOFT_UND_HARDWARE 0x086aU // Emagic Soft- und Hardware GmbH
+#define UHS_VID_DETEWE__DEUTSCHE_TELEPHONWERKE_AG_AND 0x086cU // DeTeWe - Deutsche Telephonwerke AG & Co.
+#define UHS_VID_SYSTEM_TALKS 0x086eU // System TALKS, Inc.
+#define UHS_VID_MEC_IMEX 0x086fU // MEC IMEX, Inc.
+#define UHS_VID_METRICOM 0x0870U // Metricom
+#define UHS_VID_SANDISK_1 0x0871U // SanDisk, Inc.
+#define UHS_VID_XPEED 0x0873U // Xpeed, Inc.
+#define UHS_VID_A_TEC_SUBSYSTEM 0x0874U // A-Tec Subsystem, Inc.
+#define UHS_VID_COMTROL 0x0879U // Comtrol Corp.
+#define UHS_VID_ADESSOKBTEK_AMERICA 0x087cU // Adesso/Kbtek America, Inc.
+#define UHS_VID_JATON 0x087dU // Jaton Corp.
+#define UHS_VID_FUJITSU_COMPUTER_PRODUCTS_OF_AMERICA 0x087eU // Fujitsu Computer Products of America
+#define UHS_VID_QUALCORE_LOGIC 0x087fU // QualCore Logic Inc.
+#define UHS_VID_APT_TECHNOLOGIES 0x0880U // APT Technologies, Inc.
+#define UHS_VID_RECORDING_INDUSTRY_ASSOCIATION_OF_AMERICA_RIAA 0x0883U // Recording Industry Association of America (RIAA)
+#define UHS_VID_BOCA_RESEARCH 0x0885U // Boca Research, Inc.
+#define UHS_VID_XAC_AUTOMATION 0x0886U // XAC Automation Corp.
+#define UHS_VID_HANNSTAR_ELECTRONICS 0x0887U // Hannstar Electronics Corp.
+#define UHS_VID_TECHTOOLS 0x088aU // TechTools
+#define UHS_VID_MASSWORKS 0x088bU // MassWorks, Inc.
+#define UHS_VID_SWECOIN 0x088cU // Swecoin AB
+#define UHS_VID_ILOK 0x088eU // iLok
+#define UHS_VID_DIOGRAPHY 0x0892U // DioGraphy, Inc.
+#define UHS_VID_TSI_INCORPORATED 0x0894U // TSI Incorporated
+#define UHS_VID_LAUTERBACH 0x0897U // Lauterbach
+#define UHS_VID_UNITED_TECHNOLOGIES_RESEARCH_CNTR 0x089cU // United Technologies Research Cntr.
+#define UHS_VID_ICRON_TECHNOLOGIES 0x089dU // Icron Technologies Corp.
+#define UHS_VID_NST 0x089eU // NST Co., Ltd
+#define UHS_VID_PRIMEX_AEROSPACE 0x089fU // Primex Aerospace Co.
+#define UHS_VID_E9 0x08a5U // e9, Inc.
+#define UHS_VID_TOSHIBA_TEC 0x08a6U // Toshiba TEC
+#define UHS_VID_ANDREA_ELECTRONICS 0x08a8U // Andrea Electronics
+#define UHS_VID_CWAV 0x08a9U // CWAV Inc.
+#define UHS_VID_MACRAIGOR_SYSTEMS 0x08acU // Macraigor Systems LLC
+#define UHS_VID_MACALLY_MACE_GROUP 0x08aeU // Macally (Mace Group, Inc.)
+#define UHS_VID_METROHM 0x08b0U // Metrohm
+#define UHS_VID_SORENSON_VISION 0x08b4U // Sorenson Vision, Inc.
+#define UHS_VID_NATSU 0x08b7U // NATSU
+#define UHS_VID_J_GORDON_ELECTRONIC_DESIGN 0x08b8U // J. Gordon Electronic Design, Inc.
+#define UHS_VID_RADIOSHACK_CORP_TANDY 0x08b9U // RadioShack Corp. (Tandy)
+#define UHS_VID_TEXAS_INSTRUMENTS_1 0x08bbU // Texas Instruments
+#define UHS_VID_CITIZEN_WATCH 0x08bdU // Citizen Watch Co., Ltd
+#define UHS_VID_PRECISE_BIOMETRICS 0x08c3U // Precise Biometrics
+#define UHS_VID_PROXIM 0x08c4U // Proxim, Inc.
+#define UHS_VID_KEY_NICE_ENTERPRISE 0x08c7U // Key Nice Enterprise Co., Ltd
+#define UHS_VID_2WIRE 0x08c8U // 2Wire, Inc.
+#define UHS_VID_NIPPON_TELEGRAPH_AND_TELEPHONE 0x08c9U // Nippon Telegraph and Telephone Corp.
+#define UHS_VID_AIPTEK_INTERNATIONAL 0x08caU // Aiptek International, Inc.
+#define UHS_VID_JUE_HSUN_IND 0x08cdU // Jue Hsun Ind. Corp.
+#define UHS_VID_LONG_WELL_ELECTRONICS 0x08ceU // Long Well Electronics Corp.
+#define UHS_VID_PRODUCTIVITY_ENHANCEMENT_PRODUCTS 0x08cfU // Productivity Enhancement Products
+#define UHS_VID_SMARTBRIDGES 0x08d1U // smartBridges, Inc.
+#define UHS_VID_VIRTUAL_INK 0x08d3U // Virtual Ink
+#define UHS_VID_FUJITSU_SIEMENS_COMPUTERS 0x08d4U // Fujitsu Siemens Computers
+#define UHS_VID_IXXAT_AUTOMATION 0x08d8U // IXXAT Automation GmbH
+#define UHS_VID_INCREMENT_P 0x08d9U // Increment P Corp.
+#define UHS_VID_BILLIONTON_SYSTEMS 0x08ddU // Billionton Systems, Inc.
+#define UHS_VID__UNKNOWN 0x08deU // ?
+#define UHS_VID_SPYRUS 0x08dfU // Spyrus, Inc.
+#define UHS_VID_OLITEC 0x08e3U // Olitec, Inc.
+#define UHS_VID_PIONEER 0x08e4U // Pioneer Corp.
+#define UHS_VID_LITRONIC 0x08e5U // Litronic
+#define UHS_VID_GEMALTO_WAS_GEMPLUS 0x08e6U // Gemalto (was Gemplus)
+#define UHS_VID_PAN_INTERNATIONAL_WIRE_AND_CABLE 0x08e7U // Pan-International Wire & Cable
+#define UHS_VID_INTEGRATED_MEMORY_LOGIC 0x08e8U // Integrated Memory Logic
+#define UHS_VID_EXTENDED_SYSTEMS 0x08e9U // Extended Systems, Inc.
+#define UHS_VID_ERICSSON_INC_BLUE_RIDGE_LABS 0x08eaU // Ericsson, Inc., Blue Ridge Labs
+#define UHS_VID_M_SYSTEMS_FLASH_DISK_PIONEERS 0x08ecU // M-Systems Flash Disk Pioneers
+#define UHS_VID_MEDIATEK 0x08edU // MediaTek Inc.
+#define UHS_VID_CCSIHESSO 0x08eeU // CCSI/Hesso
+#define UHS_VID_COREX_TECHNOLOGIES 0x08f0U // Corex Technologies
+#define UHS_VID_CTI_ELECTRONICS 0x08f1U // CTI Electronics Corp.
+#define UHS_VID_GOTOP_INFORMATION 0x08f2U // Gotop Information Inc.
+#define UHS_VID_SYSTEC 0x08f5U // SysTec Co., Ltd
+#define UHS_VID_LOGIC_3_INTERNATIONAL 0x08f6U // Logic 3 International, Ltd
+#define UHS_VID_VERNIER 0x08f7U // Vernier
+#define UHS_VID_KEEN_TOP_INTERNATIONAL_ENTERPRISE 0x08f8U // Keen Top International Enterprise Co., Ltd
+#define UHS_VID_WIPRO_TECHNOLOGIES 0x08f9U // Wipro Technologies
+#define UHS_VID_CAERE 0x08faU // Caere
+#define UHS_VID_SOCKET_COMMUNICATIONS 0x08fbU // Socket Communications
+#define UHS_VID_SICON_CABLE_TECHNOLOGY 0x08fcU // Sicon Cable Technology Co., Ltd
+#define UHS_VID_DIGIANSWER_AS 0x08fdU // Digianswer A/S
+#define UHS_VID_AUTHENTEC 0x08ffU // AuthenTec, Inc.
+#define UHS_VID_PINNACLE_SYSTEMS 0x0900U // Pinnacle Systems, Inc.
+#define UHS_VID_VST_TECHNOLOGIES 0x0901U // VST Technologies
+#define UHS_VID_FARADAY_TECHNOLOGY 0x0906U // Faraday Technology Corp.
+#define UHS_VID_SIEMENS_AG 0x0908U // Siemens AG
+#define UHS_VID_AUDIO_TECHNICA 0x0909U // Audio-Technica Corp.
+#define UHS_VID_TRUMPION_MICROELECTRONICS 0x090aU // Trumpion Microelectronics, Inc.
+#define UHS_VID_NEUROSMITH 0x090bU // Neurosmith
+#define UHS_VID_SILICON_MOTION_INC__TAIWAN_FORMERLY_FEIYA_TECHNOLOGY 0x090cU // Silicon Motion, Inc. - Taiwan (formerly Feiya Technology Corp.)
+#define UHS_VID_MULTIPORT_COMPUTER_VERTRIEBS 0x090dU // Multiport Computer Vertriebs GmbH
+#define UHS_VID_SHINING_TECHNOLOGY 0x090eU // Shining Technology, Inc.
+#define UHS_VID_FUJITSU_DEVICES 0x090fU // Fujitsu Devices, Inc.
+#define UHS_VID_ALATION_SYSTEMS 0x0910U // Alation Systems, Inc.
+#define UHS_VID_PHILIPS_SPEECH_PROCESSING 0x0911U // Philips Speech Processing
+#define UHS_VID_VOQUETTE 0x0912U // Voquette, Inc.
+#define UHS_VID_GLOBESPAN 0x0915U // GlobeSpan, Inc.
+#define UHS_VID_SMARTDISK 0x0917U // SmartDisk Corp.
+#define UHS_VID_TIGER_ELECTRONICS 0x0919U // Tiger Electronics
+#define UHS_VID_GARMIN_INTERNATIONAL 0x091eU // Garmin International
+#define UHS_VID_ECHELON 0x0920U // Echelon Co.
+#define UHS_VID_GOHUBS 0x0921U // GoHubs, Inc.
+#define UHS_VID_DYMO_COSTAR 0x0922U // Dymo-CoStar Corp.
+#define UHS_VID_IC_MEDIA 0x0923U // IC Media Corp.
+#define UHS_VID_XEROX 0x0924U // Xerox
+#define UHS_VID_LAKEVIEW_RESEARCH 0x0925U // Lakeview Research
+#define UHS_VID_SUMMUS 0x0927U // Summus, Ltd
+#define UHS_VID_PLX_TECHNOLOGY_INC_FORMERLY_OXFORD_SEMICONDUCTOR 0x0928U // PLX Technology, Inc. (formerly Oxford Semiconductor, Ltd)
+#define UHS_VID_AMERICAN_BIOMETRIC 0x0929U // American Biometric Co.
+#define UHS_VID_TOSHIBA_INFORMATION_AND_INDUSTRIAL_SYS_AND_SERVICES 0x092aU // Toshiba Information & Industrial Sys. And Services
+#define UHS_VID_SENA_TECHNOLOGIES 0x092bU // Sena Technologies, Inc.
+#define UHS_VID_NORTHERN_EMBEDDED_SCIENCECAVNEX 0x092fU // Northern Embedded Science/CAVNEX
+#define UHS_VID_TOSHIBA_1 0x0930U // Toshiba Corp.
+#define UHS_VID_HARMONIC_DATA_SYSTEMS 0x0931U // Harmonic Data Systems, Ltd
+#define UHS_VID_CRESCENTEC 0x0932U // Crescentec Corp.
+#define UHS_VID_QUANTUM 0x0933U // Quantum Corp.
+#define UHS_VID_SPIRENT_COMMUNICATIONS 0x0934U // Spirent Communications
+#define UHS_VID_NUTESLA 0x0936U // NuTesla
+#define UHS_VID_LUMBERG 0x0939U // Lumberg, Inc.
+#define UHS_VID_PIXART_IMAGING 0x093aU // Pixart Imaging, Inc.
+#define UHS_VID_PLEXTOR 0x093bU // Plextor Corp.
+#define UHS_VID_INTREPID_CONTROL_SYSTEMS 0x093cU // Intrepid Control Systems, Inc.
+#define UHS_VID_INNOSYNC 0x093dU // InnoSync, Inc.
+#define UHS_VID_JST_MFG 0x093eU // J.S.T. Mfg. Co., Ltd
+#define UHS_VID_OLYMPIA_TELECOM_VERTRIEBS 0x093fU // Olympia Telecom Vertriebs GmbH
+#define UHS_VID_JAPAN_STORAGE_BATTERY 0x0940U // Japan Storage Battery Co., Ltd
+#define UHS_VID_PHOTOBIT 0x0941U // Photobit Corp.
+#define UHS_VID_I2GOCOM 0x0942U // i2Go.com, LLC
+#define UHS_VID_HCL_TECHNOLOGIES_INDIA_PRIVATE 0x0943U // HCL Technologies India Private, Ltd
+#define UHS_VID_KORG 0x0944U // KORG, Inc.
+#define UHS_VID_PASCO_SCIENTIFIC 0x0945U // Pasco Scientific
+#define UHS_VID_KRONAUER_MUSIC_IN_DIGITAL 0x0948U // Kronauer music in digital
+#define UHS_VID_LINKUP_SYSTEMS 0x094bU // Linkup Systems Corp.
+#define UHS_VID_CABLE_TELEVISION_LABORATORIES 0x094dU // Cable Television Laboratories
+#define UHS_VID_YANO 0x094fU // Yano
+#define UHS_VID_KINGSTON_TECHNOLOGY 0x0951U // Kingston Technology
+#define UHS_VID_RPM_SYSTEMS 0x0954U // RPM Systems Corp.
+#define UHS_VID_NVIDIA 0x0955U // NVidia Corp.
+#define UHS_VID_BSQUARE 0x0956U // BSquare Corp.
+#define UHS_VID_AGILENT_TECHNOLOGIES 0x0957U // Agilent Technologies, Inc.
+#define UHS_VID_COMPULINK_RESEARCH 0x0958U // CompuLink Research, Inc.
+#define UHS_VID_COLOGNE_CHIP_AG 0x0959U // Cologne Chip AG
+#define UHS_VID_PORTSMITH 0x095aU // Portsmith
+#define UHS_VID_MEDIALOGIC 0x095bU // Medialogic Corp.
+#define UHS_VID_K_TEC_ELECTRONICS 0x095cU // K-Tec Electronics
+#define UHS_VID_POLYCOM 0x095dU // Polycom, Inc.
+#define UHS_VID_ACER_NEWEB 0x0967U // Acer NeWeb Corp.
+#define UHS_VID_CATALYST_ENTERPRISES 0x0968U // Catalyst Enterprises, Inc.
+#define UHS_VID_FEITIAN_TECHNOLOGIES 0x096eU // Feitian Technologies, Inc.
+#define UHS_VID_GRETAG_MACBETH_AG 0x0971U // Gretag-Macbeth AG
+#define UHS_VID_SCHLUMBERGER 0x0973U // Schlumberger
+#define UHS_VID_DATAGRAPHIX_A_BUSINESS_UNIT_OF_ANACOMP 0x0974U // Datagraphix, a business unit of Anacomp
+#define UHS_VID_OLE_COMMUNICATIONS 0x0975U // OL'E Communications, Inc.
+#define UHS_VID_ADIRONDACK_WIRE_AND_CABLE 0x0976U // Adirondack Wire & Cable
+#define UHS_VID_LIGHTSURF_TECHNOLOGIES 0x0977U // Lightsurf Technologies
+#define UHS_VID_BECKHOFF 0x0978U // Beckhoff GmbH
+#define UHS_VID_JEILIN_TECHNOLOGY 0x0979U // Jeilin Technology Corp., Ltd
+#define UHS_VID_MINDS_AT_WORK 0x097aU // Minds At Work LLC
+#define UHS_VID_KNUDSEN_ENGINEERING 0x097bU // Knudsen Engineering, Ltd
+#define UHS_VID_MARUNIX 0x097cU // Marunix Co., Ltd
+#define UHS_VID_ROSUN_TECHNOLOGIES 0x097dU // Rosun Technologies, Inc.
+#define UHS_VID_BIOPAC_SYSTEMS 0x097eU // Biopac Systems Inc.
+#define UHS_VID_BARUN_ELECTRONICS 0x097fU // Barun Electronics Co., Ltd
+#define UHS_VID_OAK_TECHNOLOGY_1 0x0981U // Oak Technology, Ltd
+#define UHS_VID_APRICORN 0x0984U // Apricorn
+#define UHS_VID_CAB_PRODUKTTECHNIK_GMBH_AND_CO_KG 0x0985U // cab Produkttechnik GmbH & Co KG
+#define UHS_VID_MATSUSHITA_ELECTRIC_WORKS 0x0986U // Matsushita Electric Works, Ltd.
+#define UHS_VID_VITANA 0x098cU // Vitana Corp.
+#define UHS_VID_INDESIGN 0x098dU // INDesign
+#define UHS_VID_INTEGRATED_INTELLECTUAL_PROPERTY 0x098eU // Integrated Intellectual Property, Inc.
+#define UHS_VID_KENWOOD_TMI 0x098fU // Kenwood TMI Corp.
+#define UHS_VID_GEMSTAR_EBOOK_GROUP 0x0993U // Gemstar eBook Group, Ltd
+#define UHS_VID_INTEGRATED_TELECOM_EXPRESS 0x0996U // Integrated Telecom Express, Inc.
+#define UHS_VID_ZIPPY_TECHNOLOGY 0x099aU // Zippy Technology Corp.
+#define UHS_VID_PAIRGAIN_TECHNOLOGIES 0x09a3U // PairGain Technologies
+#define UHS_VID_CONTECH_RESEARCH 0x09a4U // Contech Research, Inc.
+#define UHS_VID_VCON_TELECOMMUNICATIONS 0x09a5U // VCON Telecommunications
+#define UHS_VID_POINCHIPS 0x09a6U // Poinchips
+#define UHS_VID_DATA_TRANSMISSION_NETWORK 0x09a7U // Data Transmission Network Corp.
+#define UHS_VID_LIN_SHIUNG_ENTERPRISE 0x09a8U // Lin Shiung Enterprise Co., Ltd
+#define UHS_VID_SMART_CARD_TECHNOLOGIES 0x09a9U // Smart Card Technologies Co., Ltd
+#define UHS_VID_INTERSIL 0x09aaU // Intersil Corp.
+#define UHS_VID_JAPAN_CASH_MACHINE 0x09abU // Japan Cash Machine Co., Ltd.
+#define UHS_VID_TRIPP_LITE 0x09aeU // Tripp Lite
+#define UHS_VID_FRANKLIN_ELECTRONIC_PUBLISHERS 0x09b2U // Franklin Electronic Publishers, Inc.
+#define UHS_VID_ALTIUS_SOLUTIONS 0x09b3U // Altius Solutions, Inc.
+#define UHS_VID_MDS_TELEPHONE_SYSTEMS 0x09b4U // MDS Telephone Systems
+#define UHS_VID_CELLTRIX_TECHNOLOGY 0x09b5U // Celltrix Technology Co., Ltd
+#define UHS_VID_GRUNDIG 0x09bcU // Grundig
+#define UHS_VID_MYSMARTCOM 0x09beU // MySmart.Com
+#define UHS_VID_AUERSWALD_GMBH_AND_CO_KG 0x09bfU // Auerswald GmbH & Co. KG
+#define UHS_VID_GENPIX_ELECTRONICS 0x09c0U // Genpix Electronics, LLC
+#define UHS_VID_ARRIS_INTERACTIVE 0x09c1U // Arris Interactive LLC
+#define UHS_VID_NISCA 0x09c2U // Nisca Corp.
+#define UHS_VID_ACTIVCARD 0x09c3U // ActivCard, Inc.
+#define UHS_VID_ACTISYS 0x09c4U // ACTiSYS Corp.
+#define UHS_VID_MEMORY 0x09c5U // Memory Corp.
+#define UHS_VID_BMC_MESSSYSTEME 0x09caU // BMC Messsysteme GmbH
+#define UHS_VID_WORKBIT 0x09ccU // Workbit Corp.
+#define UHS_VID_PSION_DACOM_HOME_NETWORKS 0x09cdU // Psion Dacom Home Networks, Ltd
+#define UHS_VID_CITY_ELECTRONICS 0x09ceU // City Electronics, Ltd
+#define UHS_VID_ELECTRONICS_TESTING_CENTER_TAIWAN 0x09cfU // Electronics Testing Center, Taiwan
+#define UHS_VID_NEOMAGIC 0x09d1U // NeoMagic, Inc.
+#define UHS_VID_VREELIN_ENGINEERING 0x09d2U // Vreelin Engineering, Inc.
+#define UHS_VID_COM_ONE 0x09d3U // Com One
+#define UHS_VID_NOVATEL_WIRELESS 0x09d7U // Novatel Wireless
+#define UHS_VID_KRF_TECH 0x09d9U // KRF Tech, Ltd
+#define UHS_VID_A4TECH 0x09daU // A4Tech Co., Ltd.
+#define UHS_VID_MEASUREMENT_COMPUTING 0x09dbU // Measurement Computing Corp.
+#define UHS_VID_AIMEX 0x09dcU // Aimex Corp.
+#define UHS_VID_FELLOWES 0x09ddU // Fellowes, Inc.
+#define UHS_VID_ADDONICS_TECHNOLOGIES 0x09dfU // Addonics Technologies Corp.
+#define UHS_VID_INTELLON 0x09e1U // Intellon Corp.
+#define UHS_VID_JO_DAN_INTERNATIONAL 0x09e5U // Jo-Dan International, Inc.
+#define UHS_VID_SILUTIA 0x09e6U // Silutia, Inc.
+#define UHS_VID_REAL_3D 0x09e7U // Real 3D, Inc.
+#define UHS_VID_AKAI_PROFESSIONAL_MI 0x09e8U // AKAI Professional M.I. Corp.
+#define UHS_VID_CHEN_SOURCE 0x09e9U // Chen-Source, Inc.
+#define UHS_VID_IM_NETWORKS 0x09ebU // IM Networks, Inc.
+#define UHS_VID_XITEL 0x09efU // Xitel
+#define UHS_VID_GOFLIGHT 0x09f3U // GoFlight, Inc.
+#define UHS_VID_ARESCOM 0x09f5U // AresCom
+#define UHS_VID_ROCKETCHIPS 0x09f6U // RocketChips, Inc.
+#define UHS_VID_EDU_SCIENCE_HK 0x09f7U // Edu-Science (H.K.), Ltd
+#define UHS_VID_SOFTCONNEX_TECHNOLOGIES 0x09f8U // SoftConnex Technologies, Inc.
+#define UHS_VID_BAY_ASSOCIATES 0x09f9U // Bay Associates
+#define UHS_VID_MTEK_VISION 0x09faU // Mtek Vision
+#define UHS_VID_ALTERA_1 0x09fbU // Altera
+#define UHS_VID_GAIN_TECHNOLOGY 0x09ffU // Gain Technology Corp.
+#define UHS_VID_LIQUID_AUDIO 0x0a00U // Liquid Audio
+#define UHS_VID_VIA 0x0a01U // ViA, Inc.
+#define UHS_VID_UNKNOWN_MANUFACTURER 0x0a05U // Unknown Manufacturer
+#define UHS_VID_ONTRAK_CONTROL_SYSTEMS 0x0a07U // Ontrak Control Systems Inc.
+#define UHS_VID_CYBEX_COMPUTER_PRODUCTS 0x0a0bU // Cybex Computer Products Co.
+#define UHS_VID_SERVERGY 0x0a0dU // Servergy, Inc
+#define UHS_VID_XENTEC 0x0a11U // Xentec, Inc.
+#define UHS_VID_CAMBRIDGE_SILICON_RADIO 0x0a12U // Cambridge Silicon Radio, Ltd
+#define UHS_VID_TELEBYTE 0x0a13U // Telebyte, Inc.
+#define UHS_VID_SPACELABS_MEDICAL 0x0a14U // Spacelabs Medical, Inc.
+#define UHS_VID_SCALAR 0x0a15U // Scalar Corp.
+#define UHS_VID_TREK_TECHNOLOGY_S_PTE 0x0a16U // Trek Technology (S) PTE, Ltd
+#define UHS_VID_PENTAX 0x0a17U // Pentax Corp.
+#define UHS_VID_HEIDELBERGER_DRUCKMASCHINEN_AG 0x0a18U // Heidelberger Druckmaschinen AG
+#define UHS_VID_HUA_GENG_TECHNOLOGIES 0x0a19U // Hua Geng Technologies, Inc.
+#define UHS_VID_MEDTRONIC_PHYSIO_CONTROL 0x0a21U // Medtronic Physio Control Corp.
+#define UHS_VID_CENTURY_SEMICONDUCTOR_USA 0x0a22U // Century Semiconductor USA, Inc.
+#define UHS_VID_DATACARD_GROUP 0x0a27U // Datacard Group
+#define UHS_VID_AK_MODUL_BUS_COMPUTER 0x0a2cU // AK-Modul-Bus Computer GmbH
+#define UHS_VID_TG3_ELECTRONICS 0x0a34U // TG3 Electronics, Inc.
+#define UHS_VID_RADIKAL_TECHNOLOGIES 0x0a35U // Radikal Technologies
+#define UHS_VID_GILAT_SATELLITE_NETWORKS 0x0a39U // Gilat Satellite Networks, Ltd
+#define UHS_VID_PENTAMEDIA 0x0a3aU // PentaMedia Co., Ltd
+#define UHS_VID_NTT_DOCOMO 0x0a3cU // NTT DoCoMo, Inc.
+#define UHS_VID_VARO_VISION 0x0a3dU // Varo Vision
+#define UHS_VID_SWISSONIC_AG 0x0a3fU // Swissonic AG
+#define UHS_VID_BOCA_SYSTEMS 0x0a43U // Boca Systems, Inc.
+#define UHS_VID_DAVICOM_SEMICONDUCTOR 0x0a46U // Davicom Semiconductor, Inc.
+#define UHS_VID_HIROSE_ELECTRIC 0x0a47U // Hirose Electric
+#define UHS_VID_IO_INTERCONNECT 0x0a48U // I/O Interconnect
+#define UHS_VID_PLOYTEC 0x0a4aU // Ploytec GmbH
+#define UHS_VID_FUJITSU_MEDIA_DEVICES 0x0a4bU // Fujitsu Media Devices, Ltd
+#define UHS_VID_COMPUTEX 0x0a4cU // Computex Co., Ltd
+#define UHS_VID_EVOLUTION_ELECTRONICS 0x0a4dU // Evolution Electronics, Ltd
+#define UHS_VID_STEINBERG_SOFT_UND_HARDWARE 0x0a4eU // Steinberg Soft-und Hardware GmbH
+#define UHS_VID_LITTON_SYSTEMS 0x0a4fU // Litton Systems, Inc.
+#define UHS_VID_MIMAKI_ENGINEERING 0x0a50U // Mimaki Engineering Co., Ltd
+#define UHS_VID_SONY_ELECTRONICS 0x0a51U // Sony Electronics, Inc.
+#define UHS_VID_JEBSEE_ELECTRONICS 0x0a52U // Jebsee Electronics Co., Ltd
+#define UHS_VID_PORTABLE_PERIPHERAL 0x0a53U // Portable Peripheral Co., Ltd
+#define UHS_VID_ELECTRONICS_FOR_IMAGING 0x0a5aU // Electronics For Imaging, Inc.
+#define UHS_VID_EASICS_NV 0x0a5bU // EAsics NV
+#define UHS_VID_BROADCOM 0x0a5cU // Broadcom Corp.
+#define UHS_VID_DIATREND 0x0a5dU // Diatrend Corp.
+#define UHS_VID_ZEBRA 0x0a5fU // Zebra
+#define UHS_VID_MPMAN 0x0a62U // MPMan
+#define UHS_VID_CLEARCUBE_TECHNOLOGY 0x0a66U // ClearCube Technology
+#define UHS_VID_MEDELI_ELECTRONICS 0x0a67U // Medeli Electronics Co., Ltd
+#define UHS_VID_COMAIDE 0x0a68U // Comaide Corp.
+#define UHS_VID_CHROMA_ATE 0x0a69U // Chroma ate, Inc.
+#define UHS_VID_GREEN_HOUSE 0x0a6bU // Green House Co., Ltd
+#define UHS_VID_INTEGRATED_CIRCUIT_SYSTEMS 0x0a6cU // Integrated Circuit Systems, Inc.
+#define UHS_VID_UPS_MANUFACTURING 0x0a6dU // UPS Manufacturing
+#define UHS_VID_BENWIN 0x0a6eU // Benwin
+#define UHS_VID_CORE_TECHNOLOGY 0x0a6fU // Core Technology, Inc.
+#define UHS_VID_INTERNATIONAL_GAME_TECHNOLOGY 0x0a70U // International Game Technology
+#define UHS_VID_VIPCOLOR_TECHNOLOGIES_USA 0x0a71U // VIPColor Technologies USA, Inc.
+#define UHS_VID_SANWA_DENSHI 0x0a72U // Sanwa Denshi
+#define UHS_VID_MACKIE_DESIGNS 0x0a73U // Mackie Designs
+#define UHS_VID_NSTL 0x0a7dU // NSTL, Inc.
+#define UHS_VID_OCTAGON_SYSTEMS 0x0a7eU // Octagon Systems Corp.
+#define UHS_VID_REXON_TECHNOLOGY 0x0a80U // Rexon Technology Corp., Ltd
+#define UHS_VID_CHESEN_ELECTRONICS 0x0a81U // Chesen Electronics Corp.
+#define UHS_VID_SYSCAN 0x0a82U // Syscan
+#define UHS_VID_NEXTCOMM 0x0a83U // NextComm, Inc.
+#define UHS_VID_MAUI_INNOVATIVE_PERIPHERALS 0x0a84U // Maui Innovative Peripherals
+#define UHS_VID_IDEXX_LABS 0x0a85U // Idexx Labs
+#define UHS_VID_NITGEN 0x0a86U // NITGen Co., Ltd
+#define UHS_VID_AKTIV 0x0a89U // Aktiv
+#define UHS_VID_PICTURETEL 0x0a8dU // Picturetel
+#define UHS_VID_JAPAN_AVIATION_ELECTRONICS_INDUSTRY 0x0a8eU // Japan Aviation Electronics Industry, Ltd
+#define UHS_VID_CANDY_TECHNOLOGY 0x0a90U // Candy Technology Co., Ltd
+#define UHS_VID_GLOBLINK_TECHNOLOGY 0x0a91U // Globlink Technology, Inc.
+#define UHS_VID_EGO_SYSTEMS 0x0a92U // EGO SYStems, Inc.
+#define UHS_VID_C_TECHNOLOGIES 0x0a93U // C Technologies AB
+#define UHS_VID_INTERSENSE 0x0a94U // Intersense
+#define UHS_VID_LAVA_COMPUTER_MFG 0x0aa3U // Lava Computer Mfg., Inc.
+#define UHS_VID_DEVELCO_ELEKTRONIK 0x0aa4U // Develco Elektronik
+#define UHS_VID_FIRST_INTERNATIONAL_DIGITAL 0x0aa5U // First International Digital
+#define UHS_VID_PERCEPTION_DIGITAL 0x0aa6U // Perception Digital, Ltd
+#define UHS_VID_WINCOR_NIXDORF_INTERNATIONAL 0x0aa7U // Wincor Nixdorf International GmbH
+#define UHS_VID_TRIGEM_COMPUTER 0x0aa8U // TriGem Computer, Inc.
+#define UHS_VID_BAROMTEC 0x0aa9U // Baromtec Co.
+#define UHS_VID_JAPAN_CBM 0x0aaaU // Japan CBM Corp.
+#define UHS_VID_VISION_SHAPE_EUROPE 0x0aabU // Vision Shape Europe SA
+#define UHS_VID_ICOMPRESSION 0x0aacU // iCompression, Inc.
+#define UHS_VID_ROHDE_AND_SCHWARZ_GMBH_AND_CO_KG 0x0aadU // Rohde & Schwarz GmbH & Co. KG
+#define UHS_VID_NEC_INFRONTIA_CORP_NITSUKO 0x0aaeU // NEC infrontia Corp. (Nitsuko)
+#define UHS_VID_DIGITALWAY 0x0aafU // Digitalway Co., Ltd
+#define UHS_VID_ARROW_STRONG_ELECTRONICS 0x0ab0U // Arrow Strong Electronics Co., Ltd
+#define UHS_VID_FEIG_ELECTRONIC 0x0ab1U // FEIG ELECTRONIC GmbH
+#define UHS_VID_ELLISYS 0x0abaU // Ellisys
+#define UHS_VID_STEREO_LINK 0x0abeU // Stereo-Link
+#define UHS_VID_DIOLAN 0x0abfU // Diolan
+#define UHS_VID_SANYO_SEMICONDUCTOR_COMPANY_MICRO 0x0ac3U // Sanyo Semiconductor Company Micro
+#define UHS_VID_LECO 0x0ac4U // Leco Corp.
+#define UHS_VID_I_AND_C 0x0ac5U // I & C Corp.
+#define UHS_VID_SINGING_ELECTRONS 0x0ac6U // Singing Electrons, Inc.
+#define UHS_VID_PANWEST 0x0ac7U // Panwest Corp.
+#define UHS_VID_Z_STAR_MICROELECTRONICS 0x0ac8U // Z-Star Microelectronics Corp.
+#define UHS_VID_MICRO_SOLUTIONS 0x0ac9U // Micro Solutions, Inc.
+#define UHS_VID_OPEN_NETWORKS 0x0acaU // OPEN Networks Ltd
+#define UHS_VID_KOGA_ELECTRONICS 0x0accU // Koga Electronics Co.
+#define UHS_VID_ID_TECH 0x0acdU // ID Tech
+#define UHS_VID_ZYDAS 0x0aceU // ZyDAS
+#define UHS_VID_INTOTO 0x0acfU // Intoto, Inc.
+#define UHS_VID_INTELLIX 0x0ad0U // Intellix Corp.
+#define UHS_VID_REMOTEC_TECHNOLOGY 0x0ad1U // Remotec Technology, Ltd
+#define UHS_VID_SERVICE_AND_QUALITY_TECHNOLOGY 0x0ad2U // Service & Quality Technology Co., Ltd
+#define UHS_VID_DATA_ENCRYPTION_SYSTEMS 0x0adaU // Data Encryption Systems Ltd.
+#define UHS_VID_ALLION_COMPUTER 0x0ae3U // Allion Computer, Inc.
+#define UHS_VID_TAITO 0x0ae4U // Taito Corp.
+#define UHS_VID_NEODYM_SYSTEMS 0x0ae7U // Neodym Systems, Inc.
+#define UHS_VID_SYSTEM_SUPPORT 0x0ae8U // System Support Co., Ltd
+#define UHS_VID_NORTH_SHORE_CIRCUIT_DESIGN_LLP 0x0ae9U // North Shore Circuit Design L.L.P.
+#define UHS_VID_SCIESSENCE 0x0aeaU // SciEssence, LLC
+#define UHS_VID_TTP_COMMUNICATIONS 0x0aebU // TTP Communications, Ltd
+#define UHS_VID_NEODIO_TECHNOLOGIES 0x0aecU // Neodio Technologies Corp.
+#define UHS_VID_OPTION 0x0af0U // Option
+#define UHS_VID_SILVER_I 0x0af6U // Silver I Co., Ltd
+#define UHS_VID_B2C2 0x0af7U // B2C2, Inc.
+#define UHS_VID_HAMA 0x0af9U // Hama, Inc.
+#define UHS_VID_DMC 0x0afaU // DMC Co., Ltd.
+#define UHS_VID_ZAPTRONIX 0x0afcU // Zaptronix Ltd
+#define UHS_VID_TATENO_DENNOU 0x0afdU // Tateno Dennou, Inc.
+#define UHS_VID_CUMMINS_ENGINE 0x0afeU // Cummins Engine Co.
+#define UHS_VID_JUMP_ZONE_NETWORK_PRODUCTS 0x0affU // Jump Zone Network Products, Inc.
+#define UHS_VID_INGENICO 0x0b00U // INGENICO
+#define UHS_VID_ASUSTEK_COMPUTER 0x0b05U // ASUSTek Computer, Inc.
+#define UHS_VID_DATAMAX_ONEIL 0x0b0bU // Datamax-O'Neil
+#define UHS_VID_TODOS 0x0b0cU // Todos AB
+#define UHS_VID_PROJECTLAB 0x0b0dU // ProjectLab
+#define UHS_VID_GN_NETCOM 0x0b0eU // GN Netcom
+#define UHS_VID_AVID_TECHNOLOGY 0x0b0fU // AVID Technology
+#define UHS_VID_PCALLY 0x0b10U // Pcally
+#define UHS_VID_I_TECH_SOLUTIONS 0x0b11U // I Tech Solutions Co., Ltd
+#define UHS_VID_ELECTRONIC_WARFARE_ASSOC_INC_EWA 0x0b1eU // Electronic Warfare Assoc., Inc. (EWA)
+#define UHS_VID_INSYDE_SOFTWARE 0x0b1fU // Insyde Software Corp.
+#define UHS_VID_TRANSDIMENSION 0x0b20U // TransDimension, Inc.
+#define UHS_VID_YOKOGAWA_ELECTRIC 0x0b21U // Yokogawa Electric Corp.
+#define UHS_VID_JAPAN_SYSTEM_DEVELOPMENT 0x0b22U // Japan System Development Co., Ltd
+#define UHS_VID_PAN_ASIA_ELECTRONICS 0x0b23U // Pan-Asia Electronics Co., Ltd
+#define UHS_VID_LINK_EVOLUTION 0x0b24U // Link Evolution Corp.
+#define UHS_VID_RITEK 0x0b27U // Ritek Corp.
+#define UHS_VID_KENWOOD 0x0b28U // Kenwood Corp.
+#define UHS_VID_VILLAGE_CENTER 0x0b2cU // Village Center, Inc.
+#define UHS_VID_PNY_TECHNOLOGIES 0x0b30U // PNY Technologies, Inc.
+#define UHS_VID_CONTOUR_DESIGN 0x0b33U // Contour Design, Inc.
+#define UHS_VID_HITACHI_ULSI_SYSTEMS 0x0b37U // Hitachi ULSI Systems Co., Ltd
+#define UHS_VID_GEAR_HEAD 0x0b38U // Gear Head
+#define UHS_VID_OMNIDIRECTIONAL_CONTROL_TECHNOLOGY 0x0b39U // Omnidirectional Control Technology, Inc.
+#define UHS_VID_IPAXESS 0x0b3aU // IPaxess
+#define UHS_VID_TEKRAM_TECHNOLOGY 0x0b3bU // Tekram Technology Co., Ltd
+#define UHS_VID_OLIVETTI_TECHCENTER 0x0b3cU // Olivetti Techcenter
+#define UHS_VID_KIKUSUI_ELECTRONICS 0x0b3eU // Kikusui Electronics Corp.
+#define UHS_VID_HAL 0x0b41U // Hal Corp.
+#define UHS_VID_PLAYCOM 0x0b43U // Play.com, Inc.
+#define UHS_VID_SPORTBUGCOM 0x0b47U // Sportbug.com, Inc.
+#define UHS_VID_TECHNOTREND_AG 0x0b48U // TechnoTrend AG
+#define UHS_VID_ASCII 0x0b49U // ASCII Corp.
+#define UHS_VID_PINE 0x0b4bU // Pine Corp. Ltd.
+#define UHS_VID_GRAPHTEC_AMERICA 0x0b4dU // Graphtec America, Inc.
+#define UHS_VID_MUSICAL_ELECTRONICS 0x0b4eU // Musical Electronics, Ltd
+#define UHS_VID_DUMPRIES 0x0b50U // Dumpries Co., Ltd
+#define UHS_VID_COMFORT_KEYBOARD 0x0b51U // Comfort Keyboard Co.
+#define UHS_VID_COLORADO_MICRODISPLAY 0x0b52U // Colorado MicroDisplay, Inc.
+#define UHS_VID_SINBON_ELECTRONICS 0x0b54U // Sinbon Electronics Co., Ltd
+#define UHS_VID_TYI_SYSTEMS 0x0b56U // TYI Systems, Ltd
+#define UHS_VID_BEIJING_HANWANGTECHNOLOGY 0x0b57U // Beijing HanwangTechnology Co., Ltd
+#define UHS_VID_LAKE_COMMUNICATIONS 0x0b59U // Lake Communications, Ltd
+#define UHS_VID_COREL 0x0b5aU // Corel Corp.
+#define UHS_VID_GREEN_ELECTRONICS 0x0b5fU // Green Electronics Co., Ltd
+#define UHS_VID_NSINE 0x0b60U // Nsine, Ltd
+#define UHS_VID_NEC_VIEWTECHNOLOGY 0x0b61U // NEC Viewtechnology, Ltd
+#define UHS_VID_ORANGE_MICRO 0x0b62U // Orange Micro, Inc.
+#define UHS_VID_ADLINK_TECHNOLOGY 0x0b63U // ADLink Technology, Inc.
+#define UHS_VID_WONDERFUL_WIRE_CABLE 0x0b64U // Wonderful Wire Cable Co., Ltd
+#define UHS_VID_EXPERT_MAGNETICS 0x0b65U // Expert Magnetics Corp.
+#define UHS_VID_CYBIKO 0x0b66U // Cybiko Inc.
+#define UHS_VID_FAIRBANKS_SCALES 0x0b67U // Fairbanks Scales
+#define UHS_VID_CACHEVISION 0x0b69U // CacheVision
+#define UHS_VID_MAXIM_INTEGRATED_PRODUCTS 0x0b6aU // Maxim Integrated Products
+#define UHS_VID_NAGANO_JAPAN_RADIO 0x0b6fU // Nagano Japan Radio Co., Ltd
+#define UHS_VID_PORTALPLAYER 0x0b70U // PortalPlayer, Inc.
+#define UHS_VID_SHIN_EI_SANGYO 0x0b71U // SHIN-EI Sangyo Co., Ltd
+#define UHS_VID_EMBEDDED_WIRELESS_TECHNOLOGY 0x0b72U // Embedded Wireless Technology Co., Ltd
+#define UHS_VID_COMPUTONE 0x0b73U // Computone Corp.
+#define UHS_VID_ROLAND_DG 0x0b75U // Roland DG Corp.
+#define UHS_VID_SUNRISE_TELECOM 0x0b79U // Sunrise Telecom, Inc.
+#define UHS_VID_ZEEVO 0x0b7aU // Zeevo, Inc.
+#define UHS_VID_TAIKO_DENKI 0x0b7bU // Taiko Denki Co., Ltd
+#define UHS_VID_ITRAN_COMMUNICATIONS 0x0b7cU // ITRAN Communications, Ltd
+#define UHS_VID_ASTRODESIGN 0x0b7dU // Astrodesign, Inc.
+#define UHS_VID_ID3_TECHNOLOGIES 0x0b81U // id3 Technologies
+#define UHS_VID_REXTRON_TECHNOLOGY 0x0b84U // Rextron Technology, Inc.
+#define UHS_VID_ELKAT_ELECTRONICS_SDN_BHD 0x0b85U // Elkat Electronics, Sdn., Bhd.
+#define UHS_VID_EXPUTER_SYSTEMS 0x0b86U // Exputer Systems, Inc.
+#define UHS_VID_PLUS_ONE_I_AND_T 0x0b87U // Plus-One I & T, Inc.
+#define UHS_VID_SIGMA_KOKI_CO_LTD_TECHNOLOGY_CENTER 0x0b88U // Sigma Koki Co., Ltd, Technology Center
+#define UHS_VID_ADVANCED_DIGITAL_BROADCAST 0x0b89U // Advanced Digital Broadcast, Ltd
+#define UHS_VID_SMART_TECHNOLOGIES 0x0b8cU // SMART Technologies Inc.
+#define UHS_VID_ASIX_ELECTRONICS 0x0b95U // ASIX Electronics Corp.
+#define UHS_VID_SEWON_TELECOM 0x0b96U // Sewon Telecom
+#define UHS_VID_O2_MICRO 0x0b97U // O2 Micro, Inc.
+#define UHS_VID_PLAYMATES_TOYS 0x0b98U // Playmates Toys, Inc.
+#define UHS_VID_AUDIO_INTERNATIONAL 0x0b99U // Audio International, Inc.
+#define UHS_VID_DIPL_ING_STEFAN_KUNDE 0x0b9bU // Dipl.-Ing. Stefan Kunde
+#define UHS_VID_SOFTPROTEC 0x0b9dU // Softprotec Co.
+#define UHS_VID_CHIPPO_TECHNOLOGIES 0x0b9fU // Chippo Technologies
+#define UHS_VID_US_ROBOTICS 0x0bafU // U.S. Robotics
+#define UHS_VID_CONCORD_CAMERA 0x0bb0U // Concord Camera Corp.
+#define UHS_VID_INFINILINK 0x0bb1U // Infinilink Corp.
+#define UHS_VID_AMBIT_MICROSYSTEMS 0x0bb2U // Ambit Microsystems Corp.
+#define UHS_VID_OFUJI_TECHNOLOGY 0x0bb3U // Ofuji Technology
+#define UHS_VID_HTC_HIGH_TECH_COMPUTER 0x0bb4U // HTC (High Tech Computer Corp.)
+#define UHS_VID_MURATA_MANUFACTURING 0x0bb5U // Murata Manufacturing Co., Ltd
+#define UHS_VID_NETWORK_ALCHEMY 0x0bb6U // Network Alchemy
+#define UHS_VID_JOYTECH_COMPUTER 0x0bb7U // Joytech Computer Co., Ltd
+#define UHS_VID_HITACHI_SEMICONDUCTOR_AND_DEVICES_SALES 0x0bb8U // Hitachi Semiconductor and Devices Sales Co., Ltd
+#define UHS_VID_EIGER_MANDC 0x0bb9U // Eiger M&C Co., Ltd
+#define UHS_VID_ZACCESS_SYSTEMS 0x0bbaU // ZAccess Systems
+#define UHS_VID_GENERAL_METERS 0x0bbbU // General Meters Corp.
+#define UHS_VID_ASSISTIVE_TECHNOLOGY 0x0bbcU // Assistive Technology, Inc.
+#define UHS_VID_SYSTEM_CONNECTION 0x0bbdU // System Connection, Inc.
+#define UHS_VID_KNILINK_TECHNOLOGY 0x0bc0U // Knilink Technology, Inc.
+#define UHS_VID_FUW_YNG_ELECTRONICS 0x0bc1U // Fuw Yng Electronics Co., Ltd
+#define UHS_VID_SEAGATE_RSS 0x0bc2U // Seagate RSS LLC
+#define UHS_VID_IPWIRELESS 0x0bc3U // IPWireless, Inc.
+#define UHS_VID_MICROCUBE 0x0bc4U // Microcube Corp.
+#define UHS_VID_JCN 0x0bc5U // JCN Co., Ltd
+#define UHS_VID_EXWAY 0x0bc6U // ExWAY, Inc.
+#define UHS_VID_X10_WIRELESS_TECHNOLOGY 0x0bc7U // X10 Wireless Technology, Inc.
+#define UHS_VID_TELMAX_COMMUNICATIONS 0x0bc8U // Telmax Communications
+#define UHS_VID_ECI_TELECOM 0x0bc9U // ECI Telecom, Ltd
+#define UHS_VID_STARTEK_ENGINEERING 0x0bcaU // Startek Engineering, Inc.
+#define UHS_VID_PERFECT_TECHNIC_ENTERPRISE 0x0bcbU // Perfect Technic Enterprise Co., Ltd
+#define UHS_VID_ANDREW_PARGETER_AND_ASSOCIATES 0x0bd7U // Andrew Pargeter & Associates
+#define UHS_VID_REALTEK_SEMICONDUCTOR 0x0bdaU // Realtek Semiconductor Corp.
+#define UHS_VID_ERICSSON_BUSINESS_MOBILE_NETWORKS_BV 0x0bdbU // Ericsson Business Mobile Networks BV
+#define UHS_VID_Y_MEDIA 0x0bdcU // Y Media Corp.
+#define UHS_VID_ORANGE_PCS 0x0bddU // Orange PCS
+#define UHS_VID_KANDA_TSUSHIN_KOGYO 0x0be2U // Kanda Tsushin Kogyo Co., Ltd
+#define UHS_VID_TOYO 0x0be3U // TOYO Corp.
+#define UHS_VID_ELKA_INTERNATIONAL 0x0be4U // Elka International, Ltd
+#define UHS_VID_DOME_IMAGING_SYSTEMS 0x0be5U // DOME imaging systems, Inc.
+#define UHS_VID_DONG_GUAN_HUMEN_WONDERFUL_WIRE_CABLE_FACTORY 0x0be6U // Dong Guan Humen Wonderful Wire Cable Factory
+#define UHS_VID_MEI 0x0bedU // MEI
+#define UHS_VID_LTK_INDUSTRIES 0x0beeU // LTK Industries, Ltd
+#define UHS_VID_WAY2CALL_COMMUNICATIONS 0x0befU // Way2Call Communications
+#define UHS_VID_PACE_MICRO_TECHNOLOGY_PLC 0x0bf0U // Pace Micro Technology PLC
+#define UHS_VID_INTRACOM 0x0bf1U // Intracom S.A.
+#define UHS_VID_KONEXX 0x0bf2U // Konexx
+#define UHS_VID_ADDONICS_TECHNOLOGIES_1 0x0bf6U // Addonics Technologies, Inc.
+#define UHS_VID_SUNNY_GIKEN 0x0bf7U // Sunny Giken, Inc.
+#define UHS_VID_FUJITSU_SIEMENS_COMPUTERS_1 0x0bf8U // Fujitsu Siemens Computers
+#define UHS_VID_KVASER 0x0bfdU // Kvaser AB
+#define UHS_VID_MOTO_DEVELOPMENT_GROUP 0x0c04U // MOTO Development Group, Inc.
+#define UHS_VID_APPIAN_GRAPHICS 0x0c05U // Appian Graphics
+#define UHS_VID_HASBRO_GAMES 0x0c06U // Hasbro Games, Inc.
+#define UHS_VID_INFINITE_DATA_STORAGE 0x0c07U // Infinite Data Storage, Ltd
+#define UHS_VID_AGATE 0x0c08U // Agate
+#define UHS_VID_COMJET_INFORMATION_SYSTEM 0x0c09U // Comjet Information System
+#define UHS_VID_HIGHPOINT_TECHNOLOGIES 0x0c0aU // Highpoint Technologies, Inc.
+#define UHS_VID_DURA_MICRO_INC_ACOMDATA 0x0c0bU // Dura Micro, Inc. (Acomdata)
+#define UHS_VID_ZEROPLUS 0x0c12U // Zeroplus
+#define UHS_VID_IRIS_GRAPHICS 0x0c15U // Iris Graphics
+#define UHS_VID_GYRATION 0x0c16U // Gyration, Inc.
+#define UHS_VID_CYBERBOARD_AS 0x0c17U // Cyberboard A/S
+#define UHS_VID_SYNERTEK_KOREA 0x0c18U // SynerTek Korea, Inc.
+#define UHS_VID_CYBERPIXIE 0x0c19U // cyberPIXIE, Inc.
+#define UHS_VID_SILICON_MOTION 0x0c1aU // Silicon Motion, Inc.
+#define UHS_VID_MIPS_TECHNOLOGIES 0x0c1bU // MIPS Technologies
+#define UHS_VID_HANG_ZHOU_SILAN_ELECTRONICS 0x0c1cU // Hang Zhou Silan Electronics Co., Ltd
+#define UHS_VID_TALLY_PRINTER 0x0c22U // Tally Printer Corp.
+#define UHS_VID_LERNOUT__HAUSPIE 0x0c23U // Lernout + Hauspie
+#define UHS_VID_TAIYO_YUDEN 0x0c24U // Taiyo Yuden
+#define UHS_VID_SAMPO 0x0c25U // Sampo Corp.
+#define UHS_VID_PROLIFIC_TECHNOLOGY_1 0x0c26U // Prolific Technology Inc.
+#define UHS_VID_RFIDEAS 0x0c27U // RFIDeas, Inc
+#define UHS_VID_METROLOGIC_INSTRUMENTS 0x0c2eU // Metrologic Instruments
+#define UHS_VID_EAGLETRON 0x0c35U // Eagletron, Inc.
+#define UHS_VID_E_INK 0x0c36U // E Ink Corp.
+#define UHS_VID_EDIGITAL 0x0c37U // e.Digital
+#define UHS_VID_DER_AN_ELECTRIC_WIRE_AND_CABLE 0x0c38U // Der An Electric Wire & Cable Co., Ltd
+#define UHS_VID_IFR 0x0c39U // IFR
+#define UHS_VID_FURUI_PRECISE_COMPONENT_KUNSHAN 0x0c3aU // Furui Precise Component (Kunshan) Co., Ltd
+#define UHS_VID_KOMATSU 0x0c3bU // Komatsu, Ltd
+#define UHS_VID_RADIUS 0x0c3cU // Radius Co., Ltd
+#define UHS_VID_INNOCOM 0x0c3dU // Innocom, Inc.
+#define UHS_VID_NEXTCELL 0x0c3eU // Nextcell, Inc.
+#define UHS_VID_MOTOROLA_IDEN 0x0c44U // Motorola iDEN
+#define UHS_VID_MICRODIA 0x0c45U // Microdia
+#define UHS_VID_WAVERIDER_COMMUNICATIONS 0x0c46U // WaveRider Communications, Inc.
+#define UHS_VID_ALGE_TIMING 0x0c4aU // ALGE-TIMING GmbH
+#define UHS_VID_REINER_SCT_KARTENSYSTEME 0x0c4bU // Reiner SCT Kartensysteme GmbH
+#define UHS_VID_NEEDHAMS_ELECTRONICS 0x0c4cU // Needham's Electronics
+#define UHS_VID_SEALEVEL_SYSTEMS 0x0c52U // Sealevel Systems, Inc.
+#define UHS_VID_VIEWPLUS 0x0c53U // ViewPLUS, Inc.
+#define UHS_VID_GLORY 0x0c54U // Glory, Ltd
+#define UHS_VID_SPECTRUM_DIGITAL 0x0c55U // Spectrum Digital, Inc.
+#define UHS_VID_BILLION_BRIGHT 0x0c56U // Billion Bright, Ltd
+#define UHS_VID_IMAGINATIVE_DESIGN_OPERATION 0x0c57U // Imaginative Design Operation Co., Ltd
+#define UHS_VID_VIDAR_SYSTEMS 0x0c58U // Vidar Systems Corp.
+#define UHS_VID_DONG_GUAN_SHINKO_WIRE 0x0c59U // Dong Guan Shinko Wire Co., Ltd
+#define UHS_VID_TRS_INTERNATIONAL_MFG 0x0c5aU // TRS International Mfg., Inc.
+#define UHS_VID_XYTRONIX_RESEARCH_AND_DESIGN 0x0c5eU // Xytronix Research & Design
+#define UHS_VID_APOGEE_ELECTRONICS 0x0c60U // Apogee Electronics Corp.
+#define UHS_VID_CHANT_SINCERE 0x0c62U // Chant Sincere Co., Ltd
+#define UHS_VID_TOKO 0x0c63U // Toko, Inc.
+#define UHS_VID_SIGNALITY_SYSTEM_ENGINEERING 0x0c64U // Signality System Engineering Co., Ltd
+#define UHS_VID_EMINENCE_ENTERPRISE 0x0c65U // Eminence Enterprise Co., Ltd
+#define UHS_VID_REXON_ELECTRONICS 0x0c66U // Rexon Electronics Corp.
+#define UHS_VID_CONCEPT_TELECOM 0x0c67U // Concept Telecom, Ltd
+#define UHS_VID_ACS 0x0c6aU // ACS
+#define UHS_VID_JETI_TECHNISCHE_INSTRUMENTE 0x0c6cU // JETI Technische Instrumente GmbH
+#define UHS_VID_MCT_ELEKTRONIKLADEN 0x0c70U // MCT Elektronikladen
+#define UHS_VID_PEAK_SYSTEM 0x0c72U // PEAK System
+#define UHS_VID_OPTRONIC_LABORATORIES 0x0c74U // Optronic Laboratories Inc.
+#define UHS_VID_JMTEK 0x0c76U // JMTek, LLC.
+#define UHS_VID_SIPIX_GROUP 0x0c77U // Sipix Group, Ltd
+#define UHS_VID_DETTO 0x0c78U // Detto Corp.
+#define UHS_VID_NUCONNEX_TECHNOLOGIES_PTE 0x0c79U // NuConnex Technologies Pte., Ltd
+#define UHS_VID_WING_SPAN_ENTERPRISE 0x0c7aU // Wing-Span Enterprise Co., Ltd
+#define UHS_VID_NDA_TECHNOLOGIES 0x0c86U // NDA Technologies, Inc.
+#define UHS_VID_KYOCERA_WIRELESS 0x0c88U // Kyocera Wireless Corp.
+#define UHS_VID_HONDA_TSUSHIN_KOGYO 0x0c89U // Honda Tsushin Kogyo Co., Ltd
+#define UHS_VID_PATHWAY_CONNECTIVITY 0x0c8aU // Pathway Connectivity, Inc.
+#define UHS_VID_WAVEFLY 0x0c8bU // Wavefly Corp.
+#define UHS_VID_COACTIVE_NETWORKS 0x0c8cU // Coactive Networks
+#define UHS_VID_TEMPO 0x0c8dU // Tempo
+#define UHS_VID_CESSCOM 0x0c8eU // Cesscom Co., Ltd
+#define UHS_VID_APPLIED_MICROSYSTEMS 0x0c8fU // Applied Microsystems
+#define UHS_VID_CRYPTERA 0x0c94U // Cryptera
+#define UHS_VID_BERKSHIRE_PRODUCTS 0x0c98U // Berkshire Products, Inc.
+#define UHS_VID_INNOCHIPS 0x0c99U // Innochips Co., Ltd
+#define UHS_VID_HANWOOL_ROBOTICS 0x0c9aU // Hanwool Robotics Corp.
+#define UHS_VID_JOBIN_YVON 0x0c9bU // Jobin Yvon, Inc.
+#define UHS_VID_SEMTEK 0x0c9dU // SemTek
+#define UHS_VID_ZYFER 0x0ca2U // Zyfer
+#define UHS_VID_SEGA 0x0ca3U // Sega Corp.
+#define UHS_VID_STANDT_INSTRUMENT 0x0ca4U // ST&T Instrument Corp.
+#define UHS_VID_BAE_SYSTEMS_CANADA 0x0ca5U // BAE Systems Canada, Inc.
+#define UHS_VID_CASTLES_TECHNOLOGY 0x0ca6U // Castles Technology Co., Ltd
+#define UHS_VID_INFORMATION_SYSTEMS_LABORATORIES 0x0ca7U // Information Systems Laboratories
+#define UHS_VID_MOTOROLA_CGISS 0x0cadU // Motorola CGISS
+#define UHS_VID_ASCOM_BUSINESS_SYSTEMS 0x0caeU // Ascom Business Systems, Ltd
+#define UHS_VID_BUSLINK 0x0cafU // Buslink
+#define UHS_VID_FLYING_PIG_SYSTEMS 0x0cb0U // Flying Pig Systems
+#define UHS_VID_INNOVONICS 0x0cb1U // Innovonics, Inc.
+#define UHS_VID_CELESTIX_NETWORKS_PTE 0x0cb6U // Celestix Networks, Pte., Ltd
+#define UHS_VID_SINGATRON_ENTERPRISE 0x0cb7U // Singatron Enterprise Co., Ltd
+#define UHS_VID_OPTICIS 0x0cb8U // Opticis Co., Ltd
+#define UHS_VID_TRUST_ELECTRONIC_SHANGHAI 0x0cbaU // Trust Electronic (Shanghai) Co., Ltd
+#define UHS_VID_SHANGHAI_DARONG_ELECTRONICS 0x0cbbU // Shanghai Darong Electronics Co., Ltd
+#define UHS_VID_PALMAX_TECHNOLOGY 0x0cbcU // Palmax Technology Co., Ltd
+#define UHS_VID_PENTEL_CO_LTD_ELECTRONICS_EQUIPMENT_DIV 0x0cbdU // Pentel Co., Ltd (Electronics Equipment Div.)
+#define UHS_VID_KERYX_TECHNOLOGIES 0x0cbeU // Keryx Technologies, Inc.
+#define UHS_VID_UNION_GENIUS_COMPUTER 0x0cbfU // Union Genius Computer Co., Ltd
+#define UHS_VID_KUON_YI_INDUSTRIAL 0x0cc0U // Kuon Yi Industrial Corp.
+#define UHS_VID_GIVEN_IMAGING 0x0cc1U // Given Imaging, Ltd
+#define UHS_VID_TIMEX 0x0cc2U // Timex Corp.
+#define UHS_VID_RIMAGE 0x0cc3U // Rimage Corp.
+#define UHS_VID_EMSYS 0x0cc4U // emsys GmbH
+#define UHS_VID_SENDO 0x0cc5U // Sendo
+#define UHS_VID_INTERMAGIC 0x0cc6U // Intermagic Corp.
+#define UHS_VID_KONTRON_MEDICAL_AG 0x0cc7U // Kontron Medical AG
+#define UHS_VID_TECHNOTOOLS 0x0cc8U // Technotools Corp.
+#define UHS_VID_BROADMAX_TECHNOLOGIES 0x0cc9U // BroadMAX Technologies, Inc.
+#define UHS_VID_AMPHENOL 0x0ccaU // Amphenol
+#define UHS_VID_SKNET 0x0ccbU // SKNet Co., Ltd
+#define UHS_VID_DOMEX_TECHNOLOGY 0x0cccU // Domex Technology Corp.
+#define UHS_VID_TERRATEC_ELECTRONIC 0x0ccdU // TerraTec Electronic GmbH
+#define UHS_VID_BANG_OLUFSEN 0x0cd4U // Bang Olufsen
+#define UHS_VID_LABJACK_CORPORATION 0x0cd5U // LabJack Corporation
+#define UHS_VID_NEWCHIP_SRL 0x0cd7U // NewChip S.r.l.
+#define UHS_VID_JS_DIGITECH 0x0cd8U // JS Digitech, Inc.
+#define UHS_VID_HITACHI_SHIN_DIN_CABLE 0x0cd9U // Hitachi Shin Din Cable, Ltd
+#define UHS_VID_Z_COM 0x0cdeU // Z-Com
+#define UHS_VID_VALIDATION_TECHNOLOGIES_INTERNATIONAL 0x0ce5U // Validation Technologies International
+#define UHS_VID_PICO_TECHNOLOGY 0x0ce9U // Pico Technology
+#define UHS_VID_E_CONN_ELECTRONIC 0x0cf1U // e-Conn Electronic Co., Ltd
+#define UHS_VID_ENE_TECHNOLOGY 0x0cf2U // ENE Technology, Inc.
+#define UHS_VID_ATHEROS_COMMUNICATIONS 0x0cf3U // Atheros Communications, Inc.
+#define UHS_VID_FOMTEX 0x0cf4U // Fomtex Corp.
+#define UHS_VID_CELLINK 0x0cf5U // Cellink Co., Ltd
+#define UHS_VID_COMPUCABLE 0x0cf6U // Compucable Corp.
+#define UHS_VID_ISHONI_NETWORKS 0x0cf7U // ishoni Networks
+#define UHS_VID_CLARISYS 0x0cf8U // Clarisys, Inc.
+#define UHS_VID_CENTRAL_SYSTEM_RESEARCH 0x0cf9U // Central System Research Co., Ltd
+#define UHS_VID_INVISO 0x0cfaU // Inviso, Inc.
+#define UHS_VID_MINOLTA_QMS 0x0cfcU // Minolta-QMS, Inc.
+#define UHS_VID_SAFA_MEDIA 0x0cffU // SAFA MEDIA Co., Ltd.
+#define UHS_VID_TELOS_EDV_SYSTEMENTWICKLUNG 0x0d06U // telos EDV Systementwicklung GmbH
+#define UHS_VID_UTSTARCOM 0x0d08U // UTStarcom
+#define UHS_VID_CONTEMPORARY_CONTROLS 0x0d0bU // Contemporary Controls
+#define UHS_VID_ASTRON_ELECTRONICS 0x0d0cU // Astron Electronics Co., Ltd
+#define UHS_VID_MKNET 0x0d0dU // MKNet Corp.
+#define UHS_VID_HYBRID_NETWORKS 0x0d0eU // Hybrid Networks, Inc.
+#define UHS_VID_FENG_SHIN_CABLE 0x0d0fU // Feng Shin Cable Co., Ltd
+#define UHS_VID_ELASTIC_NETWORKS 0x0d10U // Elastic Networks
+#define UHS_VID_MASPRO_DENKOH 0x0d11U // Maspro Denkoh Corp.
+#define UHS_VID_HANSOL_ELECTRONICS 0x0d12U // Hansol Electronics, Inc.
+#define UHS_VID_BMF 0x0d13U // BMF Corp.
+#define UHS_VID_ARRAY_COMM 0x0d14U // Array Comm, Inc.
+#define UHS_VID_ONSTREAM_BV 0x0d15U // OnStream b.v.
+#define UHS_VID_HI_TOUCH_IMAGING_TECHNOLOGIES 0x0d16U // Hi-Touch Imaging Technologies Co., Ltd
+#define UHS_VID_NALTEC 0x0d17U // NALTEC, Inc.
+#define UHS_VID_COAXMEDIA 0x0d18U // coaXmedia
+#define UHS_VID_HANK_CONNECTION_INDUSTRIAL 0x0d19U // Hank Connection Industrial Co., Ltd
+#define UHS_VID_NXP 0x0d28U // NXP
+#define UHS_VID_LEO_HUI_ELECTRIC_WIRE_AND_CABLE 0x0d32U // Leo Hui Electric Wire & Cable Co., Ltd
+#define UHS_VID_AIRSPEAK 0x0d33U // AirSpeak, Inc.
+#define UHS_VID_REARDEN_STEEL_TECHNOLOGIES 0x0d34U // Rearden Steel Technologies
+#define UHS_VID_DAH_KUN 0x0d35U // Dah Kun Co., Ltd
+#define UHS_VID_POSIFLEX_TECHNOLOGIES 0x0d3aU // Posiflex Technologies, Inc.
+#define UHS_VID_SRI_CABLE_TECHNOLOGY 0x0d3cU // Sri Cable Technology, Ltd
+#define UHS_VID_TANGTOP_TECHNOLOGY 0x0d3dU // Tangtop Technology Co., Ltd
+#define UHS_VID_FITCOM 0x0d3eU // Fitcom, inc.
+#define UHS_VID_MTS_SYSTEMS 0x0d3fU // MTS Systems Corp.
+#define UHS_VID_ASCOR 0x0d40U // Ascor, Inc.
+#define UHS_VID_TA_YUN_TERMINALS_INDUSTRIAL 0x0d41U // Ta Yun Terminals Industrial Co., Ltd
+#define UHS_VID_FULL_DER 0x0d42U // Full Der Co., Ltd
+#define UHS_VID_KOBIL_SYSTEMS 0x0d46U // Kobil Systems GmbH
+#define UHS_VID_PROMETHEAN_LIMITED 0x0d48U // Promethean Limited
+#define UHS_VID_MAXTOR 0x0d49U // Maxtor
+#define UHS_VID_NF 0x0d4aU // NF Corp.
+#define UHS_VID_GRAPE_SYSTEMS 0x0d4bU // Grape Systems, Inc.
+#define UHS_VID_TEDAS_AG 0x0d4cU // Tedas AG
+#define UHS_VID_COHERENT 0x0d4dU // Coherent, Inc.
+#define UHS_VID_AGERE_SYSTEMS_NETHERLAND_BV 0x0d4eU // Agere Systems Netherland BV
+#define UHS_VID_EADS_AIRBUS_FRANCE 0x0d4fU // EADS Airbus France
+#define UHS_VID_CLEWARE 0x0d50U // Cleware GmbH
+#define UHS_VID_VOLEX_ASIA_PTE 0x0d51U // Volex (Asia) Pte., Ltd
+#define UHS_VID_HMI 0x0d53U // HMI Co., Ltd
+#define UHS_VID_HOLON 0x0d54U // Holon Corp.
+#define UHS_VID_ASKA_TECHNOLOGIES 0x0d55U // ASKA Technologies, Inc.
+#define UHS_VID_AVLAB_TECHNOLOGY 0x0d56U // AVLAB Technology, Inc.
+#define UHS_VID_SOLOMON_MICROTECH 0x0d57U // Solomon Microtech, Ltd
+#define UHS_VID_SMC_NETWORKS 0x0d5cU // SMC Networks, Inc.
+#define UHS_VID_MYACOM 0x0d5eU // Myacom, Ltd
+#define UHS_VID_CSI 0x0d5fU // CSI, Inc.
+#define UHS_VID_IVL_TECHNOLOGIES 0x0d60U // IVL Technologies, Ltd
+#define UHS_VID_MEILU_ELECTRONICS_SHENZHEN 0x0d61U // Meilu Electronics (Shenzhen) Co., Ltd
+#define UHS_VID_DARFON_ELECTRONICS 0x0d62U // Darfon Electronics Corp.
+#define UHS_VID_FRITZ_GEGAUF_AG 0x0d63U // Fritz Gegauf AG
+#define UHS_VID_DXG_TECHNOLOGY 0x0d64U // DXG Technology Corp.
+#define UHS_VID_KMJP 0x0d65U // KMJP Co., Ltd
+#define UHS_VID_TMT 0x0d66U // TMT
+#define UHS_VID_ADVANET 0x0d67U // Advanet, Inc.
+#define UHS_VID_SUPER_LINK_ELECTRONICS 0x0d68U // Super Link Electronics Co., Ltd
+#define UHS_VID_NSI 0x0d69U // NSI
+#define UHS_VID_MEGAPOWER_INTERNATIONAL 0x0d6aU // Megapower International Corp.
+#define UHS_VID_AND_OR_LOGIC 0x0d6bU // And-Or Logic
+#define UHS_VID_TRY_COMPUTER 0x0d70U // Try Computer Co., Ltd
+#define UHS_VID_HIRAKAWA_HEWTECH 0x0d71U // Hirakawa Hewtech Corp.
+#define UHS_VID_WINMATE_COMMUNICATION 0x0d72U // Winmate Communication, Inc.
+#define UHS_VID_HITS_COMMUNICATIONS 0x0d73U // Hit's Communications, Inc.
+#define UHS_VID_MFP_KOREA 0x0d76U // MFP Korea, Inc.
+#define UHS_VID_POWER_SENTRYNEWPOINT 0x0d77U // Power Sentry/Newpoint
+#define UHS_VID_JAPAN_DISTRIBUTOR 0x0d78U // Japan Distributor Corp.
+#define UHS_VID_MARX_DATENTECHNIK 0x0d7aU // MARX Datentechnik GmbH
+#define UHS_VID_WELLCO_TECHNOLOGY 0x0d7bU // Wellco Technology Co., Ltd
+#define UHS_VID_TAIWAN_LINE_TEK_ELECTRONIC 0x0d7cU // Taiwan Line Tek Electronic Co., Ltd
+#define UHS_VID_PHISON_ELECTRONICS 0x0d7dU // Phison Electronics Corp.
+#define UHS_VID_AMERICAN_COMPUTER_AND_DIGITAL_COMPONENTS 0x0d7eU // American Computer & Digital Components
+#define UHS_VID_ESSENTIAL_REALITY 0x0d7fU // Essential Reality LLC
+#define UHS_VID_HR_SILVINE_ELECTRONICS 0x0d80U // H.R. Silvine Electronics, Inc.
+#define UHS_VID_TECHNOVISION 0x0d81U // TechnoVision
+#define UHS_VID_THINK_OUTSIDE 0x0d83U // Think Outside, Inc.
+#define UHS_VID_DOLBY_LABORATORIES 0x0d87U // Dolby Laboratories Inc.
+#define UHS_VID_OZ_SOFTWARE 0x0d89U // Oz Software
+#define UHS_VID_KING_JIM 0x0d8aU // King Jim Co., Ltd
+#define UHS_VID_ASCOM_TELECOMMUNICATIONS 0x0d8bU // Ascom Telecommunications, Ltd
+#define UHS_VID_C_MEDIA_ELECTRONICS 0x0d8cU // C-Media Electronics, Inc.
+#define UHS_VID_PROMOTION_AND_DISPLAY_TECHNOLOGY 0x0d8dU // Promotion & Display Technology, Ltd
+#define UHS_VID_GLOBAL_SUN_TECHNOLOGY 0x0d8eU // Global Sun Technology, Inc.
+#define UHS_VID_PITNEY_BOWES 0x0d8fU // Pitney Bowes
+#define UHS_VID_SURE_FIRE_ELECTRICAL 0x0d90U // Sure-Fire Electrical Corp.
+#define UHS_VID_SKANHEX_TECHNOLOGY 0x0d96U // Skanhex Technology, Inc.
+#define UHS_VID_SANTA_BARBARA_INSTRUMENT_GROUP 0x0d97U // Santa Barbara Instrument Group
+#define UHS_VID_MARS_SEMICONDUCTOR 0x0d98U // Mars Semiconductor Corp.
+#define UHS_VID_TRAZER_TECHNOLOGIES 0x0d99U // Trazer Technologies, Inc.
+#define UHS_VID_RTX_TELECOM_AS 0x0d9aU // RTX Telecom AS
+#define UHS_VID_TAT_SHING_ELECTRICAL 0x0d9bU // Tat Shing Electrical Co.
+#define UHS_VID_CHEE_CHEN_HI_TECHNOLOGY 0x0d9cU // Chee Chen Hi-Technology Co., Ltd
+#define UHS_VID_SANWA_SUPPLY 0x0d9dU // Sanwa Supply, Inc.
+#define UHS_VID_AVAYA 0x0d9eU // Avaya
+#define UHS_VID_POWERCOM 0x0d9fU // Powercom Co., Ltd
+#define UHS_VID_DANGER_RESEARCH 0x0da0U // Danger Research
+#define UHS_VID_SUZHOU_PETERS_PRECISE_INDUSTRIAL 0x0da1U // Suzhou Peter's Precise Industrial Co., Ltd
+#define UHS_VID_LAND_INSTRUMENTS_INTERNATIONAL 0x0da2U // Land Instruments International, Ltd
+#define UHS_VID_NIPPON_ELECTRO_SENSORY_DEVICES 0x0da3U // Nippon Electro-Sensory Devices Corp.
+#define UHS_VID_POLAR_ELECTRO_OY 0x0da4U // Polar Electro Oy
+#define UHS_VID_IOGEAR 0x0da7U // IOGear, Inc.
+#define UHS_VID_SOFTDSP 0x0da8U // softDSP Co., Ltd
+#define UHS_VID_CUBIG_GROUP 0x0dabU // Cubig Group
+#define UHS_VID_WESTOVER_SCIENTIFIC 0x0dadU // Westover Scientific
+#define UHS_VID_MICRO_STAR_INTERNATIONAL 0x0db0U // Micro Star International
+#define UHS_VID_WEN_TE_ELECTRONICS 0x0db1U // Wen Te Electronics Co., Ltd
+#define UHS_VID_SHIAN_HWI_PLUG_PARTS_PLASTIC_FACTORY 0x0db2U // Shian Hwi Plug Parts, Plastic Factory
+#define UHS_VID_TEKRAM_TECHNOLOGY_1 0x0db3U // Tekram Technology Co., Ltd
+#define UHS_VID_CHUNG_FU_CHEN_YEH_ENTERPRISE 0x0db4U // Chung Fu Chen Yeh Enterprise Corp.
+#define UHS_VID_ACCESS_IS 0x0db5U // Access IS
+#define UHS_VID_ELCON_SYSTEMTECHNIK 0x0db7U // ELCON Systemtechnik
+#define UHS_VID_DIGIDESIGN 0x0dbaU // Digidesign
+#define UHS_VID_AANDD_MEDICAL 0x0dbcU // A&D Medical
+#define UHS_VID_JIUH_SHIUH_PRECISION_INDUSTRY 0x0dbeU // Jiuh Shiuh Precision Industry Co., Ltd
+#define UHS_VID_JESS_LINK_INTERNATIONAL 0x0dbfU // Jess-Link International
+#define UHS_VID_G7_SOLUTIONS_FORMERLY_GREAT_NOTIONS 0x0dc0U // G7 Solutions (formerly Great Notions)
+#define UHS_VID_TAMAGAWA_SEIKI 0x0dc1U // Tamagawa Seiki Co., Ltd
+#define UHS_VID_ATHENA_SMARTCARD_SOLUTIONS 0x0dc3U // Athena Smartcard Solutions, Inc.
+#define UHS_VID_MACPOWER_PERIPHERALS 0x0dc4U // Macpower Peripherals, Ltd
+#define UHS_VID_SDK 0x0dc5U // SDK Co., Ltd
+#define UHS_VID_PRECISION_SQUARED_TECHNOLOGY 0x0dc6U // Precision Squared Technology Corp.
+#define UHS_VID_FIRST_CABLE_LINE 0x0dc7U // First Cable Line, Inc.
+#define UHS_VID_NETWORKFAB 0x0dcdU // NetworkFab Corp.
+#define UHS_VID_ACCESS_SOLUTIONS 0x0dd0U // Access Solutions
+#define UHS_VID_CONTEK_ELECTRONICS 0x0dd1U // Contek Electronics Co., Ltd
+#define UHS_VID_POWER_QUOTIENT_INTERNATIONAL 0x0dd2U // Power Quotient International Co., Ltd
+#define UHS_VID_MEDIAQ 0x0dd3U // MediaQ
+#define UHS_VID_CUSTOM_ENGINEERING_SPA 0x0dd4U // Custom Engineering SPA
+#define UHS_VID_CALIFORNIA_MICRO_DEVICES 0x0dd5U // California Micro Devices
+#define UHS_VID_KOCOM 0x0dd7U // Kocom Co., Ltd
+#define UHS_VID_NETAC_TECHNOLOGY 0x0dd8U // Netac Technology Co., Ltd
+#define UHS_VID_HIGHSPEED_SURFING 0x0dd9U // HighSpeed Surfing
+#define UHS_VID_INTEGRATED_CIRCUIT_SOLUTION 0x0ddaU // Integrated Circuit Solution, Inc.
+#define UHS_VID_TAMARACK 0x0ddbU // Tamarack, Inc.
+#define UHS_VID_DATELINK_TECHNOLOGY 0x0dddU // Datelink Technology Co., Ltd
+#define UHS_VID_UBICOM 0x0ddeU // Ubicom, Inc.
+#define UHS_VID_BD_CONSUMER_HEALTHCARE 0x0de0U // BD Consumer Healthcare
+#define UHS_VID_USBMICRO 0x0de7U // USBmicro
+#define UHS_VID_UTECH_ELECTRONIC_DG 0x0deaU // UTECH Electronic (D.G.) Co., Ltd.
+#define UHS_VID_NOVASONICS 0x0dedU // Novasonics
+#define UHS_VID_LIFETIME_MEMORY_PRODUCTS 0x0deeU // Lifetime Memory Products
+#define UHS_VID_FULL_RISE_ELECTRONIC 0x0defU // Full Rise Electronic Co., Ltd
+#define UHS_VID_NETANDSYS 0x0df4U // NET&SYS
+#define UHS_VID_SITECOM_EUROPE_BV 0x0df6U // Sitecom Europe B.V.
+#define UHS_VID_MOBILE_ACTION_TECHNOLOGY 0x0df7U // Mobile Action Technology, Inc.
+#define UHS_VID_TOYO_COMMUNICATION_EQUIPMENT 0x0dfaU // Toyo Communication Equipment Co., Ltd
+#define UHS_VID_GENERALTOUCH_TECHNOLOGY 0x0dfcU // GeneralTouch Technology Co., Ltd
+#define UHS_VID_NIPPON_SYSTEMWARE 0x0e03U // Nippon Systemware Co., Ltd
+#define UHS_VID_WINBEST_TECHNOLOGY 0x0e08U // Winbest Technology Co., Ltd
+#define UHS_VID_AMIGO_TECHNOLOGY 0x0e0bU // Amigo Technology Inc.
+#define UHS_VID_GESYTEC 0x0e0cU // Gesytec
+#define UHS_VID_PICOQUANT 0x0e0dU // PicoQuant GmbH
+#define UHS_VID_VMWARE 0x0e0fU // VMware, Inc.
+#define UHS_VID_JMTEK_1 0x0e16U // JMTek, LLC
+#define UHS_VID_WALEX_ELECTRONIC 0x0e17U // Walex Electronic, Ltd
+#define UHS_VID_UNISYS_1 0x0e1aU // Unisys
+#define UHS_VID_CREWAVE 0x0e1bU // Crewave
+#define UHS_VID_PEGASUS_TECHNOLOGIES 0x0e20U // Pegasus Technologies Ltd.
+#define UHS_VID_COWON_SYSTEMS 0x0e21U // Cowon Systems, Inc.
+#define UHS_VID_SYMBIAN 0x0e22U // Symbian Ltd.
+#define UHS_VID_LIOU_YUANE_ENTERPRISE 0x0e23U // Liou Yuane Enterprise Co., Ltd
+#define UHS_VID_VINCHIP_SYSTEMS 0x0e25U // VinChip Systems, Inc.
+#define UHS_VID_J_PHONE_EAST 0x0e26U // J-Phone East Co., Ltd
+#define UHS_VID_HEARTMATH 0x0e30U // HeartMath LLC
+#define UHS_VID_MICRO_COMPUTER_CONTROL 0x0e34U // Micro Computer Control Corp.
+#define UHS_VID_3PEA_TECHNOLOGIES 0x0e35U // 3Pea Technologies, Inc.
+#define UHS_VID_TIEPIE_ENGINEERING 0x0e36U // TiePie engineering
+#define UHS_VID_STRATITEC 0x0e38U // Stratitec, Inc.
+#define UHS_VID_SMART_MODULAR_TECHNOLOGIES 0x0e39U // Smart Modular Technologies, Inc.
+#define UHS_VID_NEOSTAR_TECHNOLOGY 0x0e3aU // Neostar Technology Co., Ltd
+#define UHS_VID_MANSELLA 0x0e3bU // Mansella, Ltd
+#define UHS_VID_LINE6 0x0e41U // Line6, Inc.
+#define UHS_VID_SUN_RISEFUL_TECHNOLOGY 0x0e44U // Sun-Riseful Technology Co., Ltd.
+#define UHS_VID_JULIA 0x0e48U // Julia Corp., Ltd
+#define UHS_VID_SHENZHEN_BAO_HING_ELECTRIC_WIRE_AND_CABLE_MFR 0x0e4aU // Shenzhen Bao Hing Electric Wire & Cable Mfr. Co.
+#define UHS_VID_RADICA_GAMES 0x0e4cU // Radica Games, Ltd
+#define UHS_VID_TECHNODATA_INTERWARE 0x0e50U // TechnoData Interware
+#define UHS_VID_SPEED_DRAGON_MULTIMEDIA 0x0e55U // Speed Dragon Multimedia, Ltd
+#define UHS_VID_KINGSTON_TECHNOLOGY_COMPANY 0x0e56U // Kingston Technology Company, Inc.
+#define UHS_VID_ACTIVE 0x0e5aU // Active Co., Ltd
+#define UHS_VID_UNION_POWER_INFORMATION_INDUSTRIAL 0x0e5bU // Union Power Information Industrial Co., Ltd
+#define UHS_VID_BITLAND_INFORMATION_TECHNOLOGY 0x0e5cU // Bitland Information Technology Co., Ltd
+#define UHS_VID_NELTRON_INDUSTRIAL 0x0e5dU // Neltron Industrial Co., Ltd
+#define UHS_VID_CONWISE_TECHNOLOGY 0x0e5eU // Conwise Technology Co., Ltd.
+#define UHS_VID_HAWKING_TECHNOLOGIES 0x0e66U // Hawking Technologies
+#define UHS_VID_FOSSIL 0x0e67U // Fossil, Inc.
+#define UHS_VID_MEGAWIN_TECHNOLOGY 0x0e6aU // Megawin Technology Co., Ltd
+#define UHS_VID_LOGIC3 0x0e6fU // Logic3
+#define UHS_VID_TOKYO_ELECTRONIC_INDUSTRY 0x0e70U // Tokyo Electronic Industry Co., Ltd
+#define UHS_VID_HSI_CHIN_ELECTRONICS 0x0e72U // Hsi-Chin Electronics Co., Ltd
+#define UHS_VID_TVS_ELECTRONICS 0x0e75U // TVS Electronics, Ltd
+#define UHS_VID_ARCHOS 0x0e79U // Archos, Inc.
+#define UHS_VID_ON_TECH_INDUSTRY 0x0e7bU // On-Tech Industry Co., Ltd
+#define UHS_VID_GMATE 0x0e7eU // Gmate, Inc.
+#define UHS_VID_CHING_TAI_ELECTRIC_WIRE_AND_CABLE 0x0e82U // Ching Tai Electric Wire & Cable Co., Ltd
+#define UHS_VID_SHIN_AN_WIRE_AND_CABLE 0x0e83U // Shin An Wire & Cable Co.
+#define UHS_VID_WELL_FORCE_ELECTRONIC 0x0e8cU // Well Force Electronic Co., Ltd
+#define UHS_VID_MEDIATEK_1 0x0e8dU // MediaTek Inc.
+#define UHS_VID_GREENASIA 0x0e8fU // GreenAsia Inc.
+#define UHS_VID_WIEBETECH 0x0e90U // WiebeTech, LLC
+#define UHS_VID_VTECH_ENGINEERING_CANADA 0x0e91U // VTech Engineering Canada, Ltd
+#define UHS_VID_CS_GLORY_ENTERPRISE 0x0e92U // C's Glory Enterprise Co., Ltd
+#define UHS_VID_EM_TECHNICS 0x0e93U // eM Technics Co., Ltd
+#define UHS_VID_FUTURE_TECHNOLOGY 0x0e95U // Future Technology Co., Ltd
+#define UHS_VID_APLUX_COMMUNICATIONS 0x0e96U // Aplux Communications, Ltd
+#define UHS_VID_FINGERWORKS 0x0e97U // Fingerworks, Inc.
+#define UHS_VID_ADVANCED_ANALOGIC_TECHNOLOGIES 0x0e98U // Advanced Analogic Technologies, Inc.
+#define UHS_VID_PARALLEL_DICE 0x0e99U // Parallel Dice Co., Ltd
+#define UHS_VID_TA_HSING_INDUSTRIES 0x0e9aU // TA HSING Industries, Ltd
+#define UHS_VID_ADTEC 0x0e9bU // ADTEC Corp.
+#define UHS_VID_STREAMZAP 0x0e9cU // Streamzap, Inc.
+#define UHS_VID_TAMURA 0x0e9fU // Tamura Corp.
+#define UHS_VID_OURS_TECHNOLOGY 0x0ea0U // Ours Technology, Inc.
+#define UHS_VID_NIHON_COMPUTER 0x0ea6U // Nihon Computer Co., Ltd
+#define UHS_VID_MSL_ENTERPRISES 0x0ea7U // MSL Enterprises Corp.
+#define UHS_VID_CENDYNE 0x0ea8U // CenDyne, Inc.
+#define UHS_VID_HUMAX_1 0x0eadU // Humax Co., Ltd
+#define UHS_VID_NOVATECH 0x0eb0U // NovaTech
+#define UHS_VID_WIS_TECHNOLOGIES 0x0eb1U // WIS Technologies, Inc.
+#define UHS_VID_Y_S_ELECTRONIC 0x0eb2U // Y-S Electronic Co., Ltd
+#define UHS_VID_SAINT_TECHNOLOGY 0x0eb3U // Saint Technology Corp.
+#define UHS_VID_ENDOR_AG 0x0eb7U // Endor AG
+#define UHS_VID_METTLER_TOLEDO 0x0eb8U // Mettler Toledo
+#define UHS_VID_THERMO_FISHER_SCIENTIFIC 0x0ebbU // Thermo Fisher Scientific
+#define UHS_VID_VWEB 0x0ebeU // VWeb Corp.
+#define UHS_VID_OMEGA_TECHNOLOGY_OF_TAIWAN 0x0ebfU // Omega Technology of Taiwan, Inc.
+#define UHS_VID_LHI_TECHNOLOGY_CHINA 0x0ec0U // LHI Technology (China) Co., Ltd
+#define UHS_VID_ABIT_COMPUTER 0x0ec1U // Abit Computer Corp.
+#define UHS_VID_SWEETRAY_INDUSTRIAL 0x0ec2U // Sweetray Industrial, Ltd
+#define UHS_VID_AXELL 0x0ec3U // Axell Co., Ltd
+#define UHS_VID_BALLRACING_DEVELOPMENTS 0x0ec4U // Ballracing Developments, Ltd
+#define UHS_VID_GT_INFORMATION_SYSTEM 0x0ec5U // GT Information System Co., Ltd
+#define UHS_VID_INNOVISION_MULTIMEDIA 0x0ec6U // InnoVISION Multimedia, Ltd
+#define UHS_VID_THETA_LINK 0x0ec7U // Theta Link Corp.
+#define UHS_VID_LITE_ON_IT 0x0ecdU // Lite-On IT Corp.
+#define UHS_VID_TAISOL_ELECTRONICS 0x0eceU // TaiSol Electronics Co., Ltd
+#define UHS_VID_PHOGENIX_IMAGING 0x0ecfU // Phogenix Imaging, LLC
+#define UHS_VID_WINMAXGROUP 0x0ed1U // WinMaxGroup
+#define UHS_VID_KYOTO_MICRO_COMPUTER 0x0ed2U // Kyoto Micro Computer Co., Ltd
+#define UHS_VID_WING_TECH_ENTERPRISE 0x0ed3U // Wing-Tech Enterprise Co., Ltd
+#define UHS_VID_FIBERBYTE 0x0ed5U // Fiberbyte
+#define UHS_VID_NORIAKE_ITRON 0x0edaU // Noriake Itron Corp.
+#define UHS_VID_E_MDT 0x0edfU // e-MDT Co., Ltd
+#define UHS_VID_SHIMA_SEIKI_MFG 0x0ee0U // Shima Seiki Mfg., Ltd
+#define UHS_VID_SAROTECH 0x0ee1U // Sarotech Co., Ltd
+#define UHS_VID_AMI_SEMICONDUCTOR 0x0ee2U // AMI Semiconductor, Inc.
+#define UHS_VID_COMTRUE_TECHNOLOGY 0x0ee3U // ComTrue Technology Corp.
+#define UHS_VID_SUNRICH_TECHNOLOGY 0x0ee4U // Sunrich Technology, Ltd
+#define UHS_VID_DIGITAL_STREAM_TECHNOLOGY 0x0eeeU // Digital Stream Technology, Inc.
+#define UHS_VID_D_WAV_SCIENTIFIC 0x0eefU // D-WAV Scientific Co., Ltd
+#define UHS_VID_HITACHI_CABLE 0x0ef0U // Hitachi Cable, Ltd
+#define UHS_VID_AICHI_MICRO_INTELLIGENT 0x0ef1U // Aichi Micro Intelligent Corp.
+#define UHS_VID_IO_MAGIC 0x0ef2U // I/O Magic Corp.
+#define UHS_VID_LYNN_PRODUCTS 0x0ef3U // Lynn Products, Inc.
+#define UHS_VID_DSI_DATOTECH 0x0ef4U // DSI Datotech
+#define UHS_VID_POINTCHIPS 0x0ef5U // PointChips
+#define UHS_VID_YIELD_MICROELECTRONICS 0x0ef6U // Yield Microelectronics Corp.
+#define UHS_VID_SM_TECH_CO_LTD_TULIP 0x0ef7U // SM Tech Co., Ltd (Tulip)
+#define UHS_VID_OASIS_SEMICONDUCTOR 0x0efdU // Oasis Semiconductor
+#define UHS_VID_WEM_TECHNOLOGY 0x0efeU // Wem Technology, Inc.
+#define UHS_VID_UNITEK_UPS_SYSTEMS 0x0f03U // Unitek UPS Systems
+#define UHS_VID_VISUAL_FRONTIER_ENTERPRISE 0x0f06U // Visual Frontier Enterprise Co., Ltd
+#define UHS_VID_CSL_WIRE_AND_PLUG_SHEN_ZHEN 0x0f08U // CSL Wire & Plug (Shen Zhen) Co.
+#define UHS_VID_CAS 0x0f0cU // CAS Corp.
+#define UHS_VID_HORI 0x0f0dU // Hori Co., Ltd
+#define UHS_VID_ENERGY_FULL 0x0f0eU // Energy Full Corp.
+#define UHS_VID_LD_DIDACTIC 0x0f11U // LD Didactic GmbH
+#define UHS_VID_MARS_ENGINEERING 0x0f12U // Mars Engineering Corp.
+#define UHS_VID_ACETEK_TECHNOLOGY 0x0f13U // Acetek Technology Co., Ltd
+#define UHS_VID_INGENICO_1 0x0f14U // Ingenico
+#define UHS_VID_FINGER_LAKES_INSTRUMENTATION 0x0f18U // Finger Lakes Instrumentation
+#define UHS_VID_ORACOM 0x0f19U // Oracom Co., Ltd
+#define UHS_VID_ONSET_COMPUTER 0x0f1bU // Onset Computer Corp.
+#define UHS_VID_FUNAI_ELECTRIC 0x0f1cU // Funai Electric Co., Ltd
+#define UHS_VID_IWILL 0x0f1dU // Iwill Corp.
+#define UHS_VID_IOI_TECHNOLOGY 0x0f21U // IOI Technology Corp.
+#define UHS_VID_SENIOR_INDUSTRIES 0x0f22U // Senior Industries, Inc.
+#define UHS_VID_LEADER_TECH_MANUFACTURER 0x0f23U // Leader Tech Manufacturer Co., Ltd
+#define UHS_VID_FLEX_P_INDUSTRIES_SND_BHD 0x0f24U // Flex-P Industries, Snd., Bhd.
+#define UHS_VID_VIPOWER 0x0f2dU // ViPower, Inc.
+#define UHS_VID_GENIALITY_MAPLE_TECHNOLOGY 0x0f2eU // Geniality Maple Technology Co., Ltd
+#define UHS_VID_PRIVA_DESIGN_SERVICES 0x0f2fU // Priva Design Services
+#define UHS_VID_JESS_TECHNOLOGY 0x0f30U // Jess Technology Co., Ltd
+#define UHS_VID_CHRYSALIS_DEVELOPMENT 0x0f31U // Chrysalis Development
+#define UHS_VID_YFC_BONEAGLE_ELECTRIC 0x0f32U // YFC-BonEagle Electric Co., Ltd
+#define UHS_VID_KOKUYO 0x0f37U // Kokuyo Co., Ltd
+#define UHS_VID_NIEN_YI_INDUSTRIAL 0x0f38U // Nien-Yi Industrial Corp.
+#define UHS_VID_TG3_ELECTRONICS_1 0x0f39U // TG3 Electronics
+#define UHS_VID_AIRPRIME_INCORPORATED 0x0f3dU // Airprime, Incorporated
+#define UHS_VID_RDC_SEMICONDUCTOR 0x0f41U // RDC Semiconductor Co., Ltd
+#define UHS_VID_NITAL_CONSULTING_SERVICES 0x0f42U // Nital Consulting Services, Inc.
+#define UHS_VID_POLHEMUS 0x0f44U // Polhemus
+#define UHS_VID_ST_JOHN_TECHNOLOGY 0x0f4bU // St. John Technology Co., Ltd
+#define UHS_VID_WORLDWIDE_CABLE_OPTO 0x0f4cU // WorldWide Cable Opto Corp.
+#define UHS_VID_MICROTUNE 0x0f4dU // Microtune, Inc.
+#define UHS_VID_FREEDOM_SCIENTIFIC 0x0f4eU // Freedom Scientific
+#define UHS_VID_WING_KEY_ELECTRICAL 0x0f52U // Wing Key Electrical Co., Ltd
+#define UHS_VID_DONGGUAN_WHITE_HORSE_CABLE_FACTORY 0x0f53U // Dongguan White Horse Cable Factory, Ltd
+#define UHS_VID_KAWAI_MUSICAL_INSTRUMENTS_MFG 0x0f54U // Kawai Musical Instruments Mfg. Co., Ltd
+#define UHS_VID_AMBICOM 0x0f55U // AmbiCom, Inc.
+#define UHS_VID_PRAIRIECOMM 0x0f5cU // Prairiecomm, Inc.
+#define UHS_VID_NEWAGE_INTERNATIONAL 0x0f5dU // NewAge International, LLC
+#define UHS_VID_KEY_TECHNOLOGY 0x0f5fU // Key Technology Corp.
+#define UHS_VID_NTK 0x0f60U // NTK, Ltd
+#define UHS_VID_VARIAN 0x0f61U // Varian, Inc.
+#define UHS_VID_ACROX_TECHNOLOGIES 0x0f62U // Acrox Technologies Co., Ltd
+#define UHS_VID_LEAPFROG_ENTERPRISES 0x0f63U // LeapFrog Enterprises
+#define UHS_VID_KOBE_STEEL 0x0f68U // Kobe Steel, Ltd
+#define UHS_VID_DIONEX 0x0f69U // Dionex Corp.
+#define UHS_VID_VIBREN_TECHNOLOGIES 0x0f6aU // Vibren Technologies, Inc.
+#define UHS_VID_INTELLIGENT_SYSTEMS 0x0f6eU // INTELLIGENT SYSTEMS
+#define UHS_VID_DFI_1 0x0f73U // DFI
+#define UHS_VID_GUNTERMANN_AND_DRUNCK 0x0f78U // Guntermann & Drunck GmbH
+#define UHS_VID_DQ_TECHNOLOGY 0x0f7cU // DQ Technology, Inc.
+#define UHS_VID_NETBOTZ 0x0f7dU // NetBotz, Inc.
+#define UHS_VID_FLUKE 0x0f7eU // Fluke Corp.
+#define UHS_VID_VTECH_HOLDINGS 0x0f88U // VTech Holdings, Ltd
+#define UHS_VID_YAZAKI 0x0f8bU // Yazaki Corp.
+#define UHS_VID_YOUNG_GENERATION_INTERNATIONAL 0x0f8cU // Young Generation International Corp.
+#define UHS_VID_UNIWILL_COMPUTER 0x0f8dU // Uniwill Computer Corp.
+#define UHS_VID_KINGNET_TECHNOLOGY 0x0f8eU // Kingnet Technology Co., Ltd
+#define UHS_VID_SOMA_NETWORKS 0x0f8fU // Soma Networks
+#define UHS_VID_CVILUX 0x0f97U // CviLux Corp.
+#define UHS_VID_CYBERBANK 0x0f98U // CyberBank Corp.
+#define UHS_VID_HYUN_WON 0x0f9cU // Hyun Won, Inc.
+#define UHS_VID_LUCENT_TECHNOLOGIES_1 0x0f9eU // Lucent Technologies
+#define UHS_VID_STARCONN_ELECTRONIC 0x0fa3U // Starconn Electronic Co., Ltd
+#define UHS_VID_ATL_TECHNOLOGY 0x0fa4U // ATL Technology
+#define UHS_VID_SOTEC 0x0fa5U // Sotec Co., Ltd
+#define UHS_VID_EPOX_COMPUTER 0x0fa7U // Epox Computer Co., Ltd
+#define UHS_VID_LOGIC_CONTROLS 0x0fa8U // Logic Controls, Inc.
+#define UHS_VID_WINPOINT_ELECTRONIC 0x0fafU // Winpoint Electronic Corp.
+#define UHS_VID_HAURTIAN_WIRE_AND_CABLE 0x0fb0U // Haurtian Wire & Cable Co., Ltd
+#define UHS_VID_INCLOSE_DESIGN 0x0fb1U // Inclose Design, Inc.
+#define UHS_VID_JUAN_CHERN_INDUSTRIAL 0x0fb2U // Juan-Chern Industrial Co., Ltd
+#define UHS_VID_HEBER 0x0fb6U // Heber Ltd
+#define UHS_VID_WISTRON 0x0fb8U // Wistron Corp.
+#define UHS_VID_AACOM 0x0fb9U // AACom Corp.
+#define UHS_VID_SAN_SHING_ELECTRONICS 0x0fbaU // San Shing Electronics Co., Ltd
+#define UHS_VID_BITWISE_SYSTEMS 0x0fbbU // Bitwise Systems, Inc.
+#define UHS_VID_MITAC_INTERNATINAL 0x0fc1U // Mitac Internatinal Corp.
+#define UHS_VID_PLUG_AND_JACK_INDUSTRIAL 0x0fc2U // Plug and Jack Industrial, Inc.
+#define UHS_VID_DELCOM_ENGINEERING 0x0fc5U // Delcom Engineering
+#define UHS_VID_DATAPLUS_SUPPLIES 0x0fc6U // Dataplus Supplies, Inc.
+#define UHS_VID_RESEARCH_IN_MOTION 0x0fcaU // Research In Motion, Ltd.
+#define UHS_VID_SONY_ERICSSON_MOBILE_COMMUNICATIONS 0x0fceU // Sony Ericsson Mobile Communications AB
+#define UHS_VID_DYNASTREAM_INNOVATIONS 0x0fcfU // Dynastream Innovations, Inc.
+#define UHS_VID_TULIP_COMPUTERS_BV 0x0fd0U // Tulip Computers B.V.
+#define UHS_VID_GIANT_ELECTRONICS 0x0fd1U // Giant Electronics Ltd.
+#define UHS_VID_SEAC_BANCHE 0x0fd2U // Seac Banche
+#define UHS_VID_TENOVIS_GMBH_AND_CO_KG 0x0fd4U // Tenovis GmbH & Co., KG
+#define UHS_VID_DIRECT_ACCESS_TECHNOLOGY 0x0fd5U // Direct Access Technology, Inc.
+#define UHS_VID_ELGATO_SYSTEMS 0x0fd9U // Elgato Systems GmbH
+#define UHS_VID_QUANTEC_NETWORKS 0x0fdaU // Quantec Networks GmbH
+#define UHS_VID_MICRO_PLUS 0x0fdcU // Micro Plus
+#define UHS_VID_OREGON_SCIENTIFIC 0x0fdeU // Oregon Scientific
+#define UHS_VID_OSTERHOUT_DESIGN_GROUP 0x0fe0U // Osterhout Design Group
+#define UHS_VID_IN_TECH_ELECTRONICS 0x0fe4U // IN-Tech Electronics, Ltd
+#define UHS_VID_GREENCONN_USA 0x0fe5U // Greenconn (U.S.A.), Inc.
+#define UHS_VID_KONTRON_INDUSTRIAL_COMPUTER_SOURCE_ICS_ADVENT 0x0fe6U // Kontron (Industrial Computer Source / ICS Advent)
+#define UHS_VID_DVICO 0x0fe9U // DVICO
+#define UHS_VID_UNITED_COMPUTER_ACCESSORIES 0x0feaU // United Computer Accessories
+#define UHS_VID_CRS_ELECTRONIC 0x0febU // CRS Electronic Co., Ltd
+#define UHS_VID_UMC_ELECTRONICS 0x0fecU // UMC Electronics Co., Ltd
+#define UHS_VID_ACCESS 0x0fedU // Access Co., Ltd
+#define UHS_VID_XSIDO 0x0feeU // Xsido Corp.
+#define UHS_VID_MJ_RESEARCH 0x0fefU // MJ Research, Inc.
+#define UHS_VID_CORE_VALLEY 0x0ff6U // Core Valley Co., Ltd
+#define UHS_VID_CHI_SHING_COMPUTER_ACCESSORIES 0x0ff7U // CHI SHING Computer Accessories Co., Ltd
+#define UHS_VID_CLAVIA_DMI 0x0ffcU // Clavia DMI AB
+#define UHS_VID_EARLYSENSE 0x0ffdU // EarlySense
+#define UHS_VID_AOPEN 0x0fffU // Aopen, Inc.
+#define UHS_VID_SPEED_TECH 0x1000U // Speed Tech Corp.
+#define UHS_VID_RITRONICS_COMPONENTS_S_PTE 0x1001U // Ritronics Components (S) Pte., Ltd
+#define UHS_VID_SIGMA 0x1003U // Sigma Corp.
+#define UHS_VID_LG_ELECTRONICS 0x1004U // LG Electronics, Inc.
+#define UHS_VID_APACER_TECHNOLOGY 0x1005U // Apacer Technology, Inc.
+#define UHS_VID_IRIVER 0x1006U // iRiver, Ltd.
+#define UHS_VID_EMUZED 0x1009U // Emuzed, Inc.
+#define UHS_VID_AV_CHASEWAY 0x100aU // AV Chaseway, Ltd
+#define UHS_VID_CHOU_CHIN_INDUSTRIAL 0x100bU // Chou Chin Industrial Co., Ltd
+#define UHS_VID_NETOPIA 0x100dU // Netopia, Inc.
+#define UHS_VID_FUKUDA_DENSHI 0x1010U // Fukuda Denshi Co., Ltd
+#define UHS_VID_MOBILE_MEDIA_TECH 0x1011U // Mobile Media Tech.
+#define UHS_VID_SDKM_FIBRES_WIRES_AND_CABLES_BERHAD 0x1012U // SDKM Fibres, Wires & Cables Berhad
+#define UHS_VID_TST_TOUCHLESS_SENSOR_TECHNOLOGY_AG 0x1013U // TST-Touchless Sensor Technology AG
+#define UHS_VID_DENSITRON_TECHNOLOGIES_PLC 0x1014U // Densitron Technologies PLC
+#define UHS_VID_SOFTRONICS_PTY 0x1015U // Softronics Pty., Ltd
+#define UHS_VID_XIAMEN_HUNGS_ENTERPRISE 0x1016U // Xiamen Hung's Enterprise Co., Ltd
+#define UHS_VID_SPEEDY_INDUSTRIAL_SUPPLIES_PTE 0x1017U // Speedy Industrial Supplies, Pte., Ltd
+#define UHS_VID_ELITEGROUP_COMPUTER_SYSTEMS_ECS 0x1019U // Elitegroup Computer Systems (ECS)
+#define UHS_VID_LABTEC_1 0x1020U // Labtec
+#define UHS_VID_SHINKO_SHOJI 0x1022U // Shinko Shoji Co., Ltd
+#define UHS_VID_HYPER_PALTEK 0x1025U // Hyper-Paltek
+#define UHS_VID_NEWLY 0x1026U // Newly Corp.
+#define UHS_VID_TIME_DOMAIN 0x1027U // Time Domain
+#define UHS_VID_INOVYS 0x1028U // Inovys Corp.
+#define UHS_VID_ATLANTIC_COAST_TELESYS 0x1029U // Atlantic Coast Telesys
+#define UHS_VID_RAMOS_TECHNOLOGY 0x102aU // Ramos Technology Co., Ltd
+#define UHS_VID_INFOTRONIC_AMERICA 0x102bU // Infotronic America, Inc.
+#define UHS_VID_ETOMS_ELECTRONICS 0x102cU // Etoms Electronics Corp.
+#define UHS_VID_WINIC 0x102dU // Winic Corp.
+#define UHS_VID_COMAX_TECHNOLOGY 0x1031U // Comax Technology, Inc.
+#define UHS_VID_C_ONE_TECHNOLOGY 0x1032U // C-One Technology Corp.
+#define UHS_VID_NUCAM 0x1033U // Nucam Corp.
+#define UHS_VID_STEELSERIES_APS 0x1038U // SteelSeries ApS
+#define UHS_VID_DEVOLO_AG 0x1039U // devolo AG
+#define UHS_VID_PSA 0x103aU // PSA
+#define UHS_VID_STANTON 0x103dU // Stanton
+#define UHS_VID_ICREATE_TECHNOLOGIES 0x1043U // iCreate Technologies Corp.
+#define UHS_VID_CHU_YUEN_ENTERPRISE 0x1044U // Chu Yuen Enterprise Co., Ltd
+#define UHS_VID_WINBOND_ELECTRONICS_CORP_HEX_ 0x1046U // Winbond Electronics Corp. [hex]
+#define UHS_VID_TARGUS_GROUP_INTERNATIONAL 0x1048U // Targus Group International
+#define UHS_VID_MYLEX_BUSLOGIC 0x104bU // Mylex / Buslogic
+#define UHS_VID_AMCO_TEC_INTERNATIONAL 0x104cU // AMCO TEC International, Inc.
+#define UHS_VID_NEWPORT_CORPORATION 0x104dU // Newport Corporation
+#define UHS_VID_WB_ELECTRONICS 0x104fU // WB Electronics
+#define UHS_VID_YUBICOCOM 0x1050U // Yubico.com
+#define UHS_VID_IMMANUEL_ELECTRONICS 0x1053U // Immanuel Electronics Co., Ltd
+#define UHS_VID_BMS_INTERNATIONAL_BEHEER_NV 0x1054U // BMS International Beheer N.V.
+#define UHS_VID_COMPLEX_MICRO_INTERCONNECTION 0x1055U // Complex Micro Interconnection Co., Ltd
+#define UHS_VID_HSIN_CHEN_ENT 0x1056U // Hsin Chen Ent Co., Ltd
+#define UHS_VID_ON_SEMICONDUCTOR 0x1057U // ON Semiconductor
+#define UHS_VID_WESTERN_DIGITAL_TECHNOLOGIES 0x1058U // Western Digital Technologies, Inc.
+#define UHS_VID_GIESECKE_AND_DEVRIENT 0x1059U // Giesecke & Devrient GmbH
+#define UHS_VID_FOXCONN_INTERNATIONAL 0x105bU // Foxconn International, Inc.
+#define UHS_VID_HONG_JI_ELECTRIC_WIRE_AND_CABLE_DONGGUAN 0x105cU // Hong Ji Electric Wire & Cable (Dongguan) Co., Ltd
+#define UHS_VID_DELKIN_DEVICES 0x105dU // Delkin Devices, Inc.
+#define UHS_VID_VALENCE_SEMICONDUCTOR_DESIGN 0x105eU // Valence Semiconductor Design, Ltd
+#define UHS_VID_CHIN_SHONG_ENTERPRISE 0x105fU // Chin Shong Enterprise Co., Ltd
+#define UHS_VID_EASTHOME_INDUSTRIAL 0x1060U // Easthome Industrial Co., Ltd
+#define UHS_VID_MOTOROLA_ELECTRONICS_TAIWAN_LTD_HEX_ 0x1063U // Motorola Electronics Taiwan, Ltd [hex]
+#define UHS_VID_CCYU_TECHNOLOGY 0x1065U // CCYU Technology
+#define UHS_VID_LOYAL_LEGEND 0x106aU // Loyal Legend, Ltd
+#define UHS_VID_CURITEL_COMMUNICATIONS 0x106cU // Curitel Communications, Inc.
+#define UHS_VID_SAN_CHIEH_MANUFACTURING 0x106dU // San Chieh Manufacturing, Ltd
+#define UHS_VID_CONECTL 0x106eU // ConectL
+#define UHS_VID_MONEY_CONTROLS 0x106fU // Money Controls
+#define UHS_VID_GCT_SEMICONDUCTOR 0x1076U // GCT Semiconductor, Inc.
+#define UHS_VID_GATEWAY_1 0x107bU // Gateway, Inc.
+#define UHS_VID_ARLEC_AUSTRALIA 0x107dU // Arlec Australia, Ltd
+#define UHS_VID_MIDORIYA_ELECTRIC 0x107eU // Midoriya Electric Co., Ltd
+#define UHS_VID_KIDZMOUSE 0x107fU // KidzMouse, Inc.
+#define UHS_VID_SHIN_ETSUKAKEN 0x1082U // Shin-Etsukaken Co., Ltd
+#define UHS_VID_CANON_ELECTRONICS 0x1083U // Canon Electronics, Inc.
+#define UHS_VID_PANTECH 0x1084U // Pantech Co., Ltd
+#define UHS_VID_CHLORIDE_POWER_PROTECTION 0x108aU // Chloride Power Protection
+#define UHS_VID_GRAND_TEK_TECHNOLOGY 0x108bU // Grand-tek Technology Co., Ltd
+#define UHS_VID_ROBERT_BOSCH 0x108cU // Robert Bosch GmbH
+#define UHS_VID_LOTES 0x108eU // Lotes Co., Ltd.
+#define UHS_VID_SURFACE_OPTICS 0x1099U // Surface Optics Corp.
+#define UHS_VID_DATASOFT_SYSTEMS 0x109aU // DATASOFT Systems GmbH
+#define UHS_VID_HISENSE 0x109bU // Hisense
+#define UHS_VID_ESOL 0x109fU // eSOL Co., Ltd
+#define UHS_VID_HIROTECH 0x10a0U // Hirotech, Inc.
+#define UHS_VID_MITSUBISHI_MATERIALS 0x10a3U // Mitsubishi Materials Corp.
+#define UHS_VID_SK_TELETECH 0x10a9U // SK Teletech Co., Ltd
+#define UHS_VID_CABLES_TO_GO 0x10aaU // Cables To Go
+#define UHS_VID_USI 0x10abU // USI Co., Ltd
+#define UHS_VID_HONEYWELL 0x10acU // Honeywell, Inc.
+#define UHS_VID_PRINCETON_TECHNOLOGY 0x10aeU // Princeton Technology Corp.
+#define UHS_VID_LIEBERT 0x10afU // Liebert Corp.
+#define UHS_VID_COMODO_PLX_UNKNOWN 0x10b5U // Comodo (PLX?)
+#define UHS_VID_DIBCOM 0x10b8U // DiBcom
+#define UHS_VID_TM_TECHNOLOGY 0x10bbU // TM Technology, Inc.
+#define UHS_VID_DINGING_TECHNOLOGY 0x10bcU // Dinging Technology Co., Ltd
+#define UHS_VID_TMT_TECHNOLOGY 0x10bdU // TMT Technology, Inc.
+#define UHS_VID_SMARTHOME 0x10bfU // SmartHome
+#define UHS_VID_UNIVERSAL_LASER_SYSTEMS 0x10c3U // Universal Laser Systems, Inc.
+#define UHS_VID_CYGNAL_INTEGRATED_PRODUCTS 0x10c4U // Cygnal Integrated Products, Inc.
+#define UHS_VID_SANEI_ELECTRIC 0x10c5U // Sanei Electric, Inc.
+#define UHS_VID_INTEC 0x10c6U // Intec, Inc.
+#define UHS_VID_ERATECH 0x10cbU // Eratech
+#define UHS_VID_GBM_CONNECTOR 0x10ccU // GBM Connector Co., Ltd
+#define UHS_VID_KYCON 0x10cdU // Kycon, Inc.
+#define UHS_VID_SILICON_LABS 0x10ceU // Silicon Labs
+#define UHS_VID_VELLEMAN_COMPONENTS 0x10cfU // Velleman Components, Inc.
+#define UHS_VID_HOTTINGER_BALDWIN_MEASUREMENT 0x10d1U // Hottinger Baldwin Measurement
+#define UHS_VID_RAYCOMPOSER__R_ADAMS 0x10d2U // RayComposer - R. Adams
+#define UHS_VID_MAN_BOON_MANUFACTORY 0x10d4U // Man Boon Manufactory, Ltd
+#define UHS_VID_UNI_CLASS_TECHNOLOGY 0x10d5U // Uni Class Technology Co., Ltd
+#define UHS_VID_ACTIONS_SEMICONDUCTOR 0x10d6U // Actions Semiconductor Co., Ltd
+#define UHS_VID_AUTHENEX 0x10deU // Authenex, Inc.
+#define UHS_VID_IN_WIN_DEVELOPMENT 0x10dfU // In-Win Development, Inc.
+#define UHS_VID_POST_OP_VIDEO 0x10e0U // Post-Op Video, Inc.
+#define UHS_VID_CABLEPLUS 0x10e1U // CablePlus, Ltd
+#define UHS_VID_NADA_ELECTRONICS 0x10e2U // Nada Electronics, Ltd
+#define UHS_VID_VAST_TECHNOLOGIES 0x10ecU // Vast Technologies, Inc.
+#define UHS_VID_NEXIO 0x10f0U // Nexio Co., Ltd
+#define UHS_VID_IMPORTEK 0x10f1U // Importek
+#define UHS_VID_TURTLE_BEACH 0x10f5U // Turtle Beach
+#define UHS_VID_PICTOS_TECHNOLOGIES 0x10fbU // Pictos Technologies, Inc.
+#define UHS_VID_ANUBIS_ELECTRONICS 0x10fdU // Anubis Electronics, Ltd
+#define UHS_VID_THRANE_AND_THRANE 0x10feU // Thrane & Thrane
+#define UHS_VID_VIRTOUCH 0x1100U // VirTouch, Ltd
+#define UHS_VID_EASYPASS_INDUSTRIAL 0x1101U // EasyPass Industrial Co., Ltd
+#define UHS_VID_BRIGHTCOM_TECHNOLOGIES 0x1108U // Brightcom Technologies, Ltd
+#define UHS_VID_MOXA_TECHNOLOGIES 0x110aU // Moxa Technologies Co., Ltd.
+#define UHS_VID_ANALOG_DEVICES_CANADA_LTD_ALLIED_TELESYN 0x1110U // Analog Devices Canada, Ltd (Allied Telesyn)
+#define UHS_VID_PANDORA_INTERNATIONAL 0x1111U // Pandora International Ltd.
+#define UHS_VID_YM_ELECTRIC 0x1112U // YM ELECTRIC CO., Ltd
+#define UHS_VID_MEDION_AG 0x1113U // Medion AG
+#define UHS_VID_VSO_ELECTRIC 0x111eU // VSO Electric Co., Ltd
+#define UHS_VID_REDRAT 0x112aU // RedRat
+#define UHS_VID_MASTER_HILL_ELECTRIC_WIRE_AND_CABLE 0x112eU // Master Hill Electric Wire and Cable Co., Ltd
+#define UHS_VID_CELLON_INTERNATIONAL 0x112fU // Cellon International, Inc.
+#define UHS_VID_TENX_TECHNOLOGY 0x1130U // Tenx Technology, Inc.
+#define UHS_VID_INTEGRATED_SYSTEM_SOLUTION 0x1131U // Integrated System Solution Corp.
+#define UHS_VID_TOSHIBA_CORP_DIGITAL_MEDIA_EQUIPMENT_HEX_ 0x1132U // Toshiba Corp., Digital Media Equipment [hex]
+#define UHS_VID_CTS_ELECTRONINCS 0x1136U // CTS Electronincs
+#define UHS_VID_ARIN_TECH 0x113cU // Arin Tech Co., Ltd
+#define UHS_VID_MAPOWER_ELECTRONICS 0x113dU // Mapower Electronics Co., Ltd
+#define UHS_VID_V_ONE_MULTIMEDIA_PTE 0x1141U // V One Multimedia, Pte., Ltd
+#define UHS_VID_CYBERSCAN_TECHNOLOGIES 0x1142U // CyberScan Technologies, Inc.
+#define UHS_VID_JAPAN_RADIO_COMPANY 0x1145U // Japan Radio Company
+#define UHS_VID_SHIMANE_SANYO_ELECTRIC 0x1146U // Shimane SANYO Electric Co., Ltd.
+#define UHS_VID_EVER_GREAT_ELECTRIC_WIRE_AND_CABLE 0x1147U // Ever Great Electric Wire and Cable Co., Ltd
+#define UHS_VID_SPHAIRON_ACCESS_SYSTEMS 0x114bU // Sphairon Access Systems GmbH
+#define UHS_VID_TINIUS_OLSEN_TESTING_MACHINE 0x114cU // Tinius Olsen Testing Machine Co., Inc.
+#define UHS_VID_ALPHA_IMAGING_TECHNOLOGY 0x114dU // Alpha Imaging Technology Corp.
+#define UHS_VID_WAVECOM 0x114fU // Wavecom
+#define UHS_VID_SALIX_TECHNOLOGY 0x115bU // Salix Technology Co., Ltd.
+#define UHS_VID_SECUGEN 0x1162U // Secugen Corp.
+#define UHS_VID_DELORME_PUBLISHING 0x1163U // DeLorme Publishing, Inc.
+#define UHS_VID_YUAN_HIGH_TECH_DEVELOPMENT 0x1164U // YUAN High-Tech Development Co., Ltd
+#define UHS_VID_TELSON_ELECTRONICS 0x1165U // Telson Electronics Co., Ltd
+#define UHS_VID_BANTAM_INTERACTIVE_TECHNOLOGIES 0x1166U // Bantam Interactive Technologies
+#define UHS_VID_SALIENT_SYSTEMS 0x1167U // Salient Systems Corp.
+#define UHS_VID_BIZCONN_INTERNATIONAL 0x1168U // BizConn International Corp.
+#define UHS_VID_GIGASTORAGE 0x116eU // Gigastorage Corp.
+#define UHS_VID_SILICON_10_TECHNOLOGY 0x116fU // Silicon 10 Technology Corp.
+#define UHS_VID_SHENGYIH_STEEL_MOLD 0x1175U // Shengyih Steel Mold Co., Ltd
+#define UHS_VID_SANTA_ELECTRONIC 0x117dU // Santa Electronic, Inc.
+#define UHS_VID_JNC 0x117eU // JNC, Inc.
+#define UHS_VID_VENTURE 0x1182U // Venture Corp., Ltd
+#define UHS_VID_COMPAQ_COMPUTER_CORP_HEX_DIGITAL_DREAM_UNKNOWN 0x1183U // Compaq Computer Corp. [hex] (Digital Dream ?)
+#define UHS_VID_KYOCERA_ELCO 0x1184U // Kyocera Elco Corp.
+#define UHS_VID_BLOOMBERG_LP 0x1188U // Bloomberg L.P.
+#define UHS_VID_ACER_COMMUNICATIONS_AND_MULTIMEDIA 0x1189U // Acer Communications & Multimedia
+#define UHS_VID_YOU_YANG_TECHNOLOGY 0x118fU // You Yang Technology Co., Ltd
+#define UHS_VID_TRIPACE 0x1190U // Tripace
+#define UHS_VID_LOYALTY_FOUNDER_ENTERPRISE 0x1191U // Loyalty Founder Enterprise Co., Ltd
+#define UHS_VID_YANKEE_ROBOTICS 0x1196U // Yankee Robotics, LLC
+#define UHS_VID_TECHNOIMAGIA 0x1197U // Technoimagia Co., Ltd
+#define UHS_VID_STARSHINE_TECHNOLOGY 0x1198U // StarShine Technology Corp.
+#define UHS_VID_SIERRA_WIRELESS 0x1199U // Sierra Wireless, Inc.
+#define UHS_VID_ZHAN_QI_TECHNOLOGY 0x119aU // ZHAN QI Technology Co., Ltd
+#define UHS_VID_RUWIDO_AUSTRIA 0x119bU // ruwido austria GmbH
+#define UHS_VID_CHIPCON_AS 0x11a0U // Chipcon AS
+#define UHS_VID_TECHNOVAS 0x11a3U // Technovas Co., Ltd
+#define UHS_VID_GLOBALMEDIA_GROUP 0x11aaU // GlobalMedia Group, LLC
+#define UHS_VID_EXITO_ELECTRONICS 0x11abU // Exito Electronics Co., Ltd
+#define UHS_VID_NIKE 0x11acU // Nike
+#define UHS_VID_ATECH_FLASH_TECHNOLOGY 0x11b0U // ATECH FLASH TECHNOLOGY
+#define UHS_VID_RANDD_INTERNATIONAL_NV 0x11beU // R&D International NV
+#define UHS_VID_INMAX 0x11c5U // Inmax
+#define UHS_VID_VERIFONE 0x11caU // VeriFone Inc
+#define UHS_VID_TOPFIELD 0x11dbU // Topfield Co., Ltd.
+#define UHS_VID_KI_TECHNOLOGY 0x11e6U // K.I. Technology Co. Ltd.
+#define UHS_VID_SIEMENS_AG_1 0x11f5U // Siemens AG
+#define UHS_VID_PROLIFIC 0x11f6U // Prolific
+#define UHS_VID_ALCATEL_UNKNOWN 0x11f7U // Alcatel (?)
+#define UHS_VID_TSC_AUTO_ID_TECHNOLOGY 0x1203U // TSC Auto ID Technology Co., Ltd
+#define UHS_VID_INTERBIOMETRICS 0x1209U // InterBiometrics
+#define UHS_VID_HUDSON_SOFT 0x120eU // Hudson Soft Co., Ltd
+#define UHS_VID_MAGELLAN 0x120fU // Magellan
+#define UHS_VID_DIGITECH 0x1210U // DigiTech
+#define UHS_VID_JUNGSOFT 0x121eU // Jungsoft Co., Ltd
+#define UHS_VID_UNKNOWN_MANUFACTURER_1 0x1221U // Unknown manufacturer
+#define UHS_VID_SKYCABLE_ENTERPRISE 0x1223U // SKYCABLE ENTERPRISE. CO., LTD.
+#define UHS_VID_DATAPAQ_LIMITED 0x1228U // Datapaq Limited
+#define UHS_VID_CHIPIDEA_MICROELECTRONICA 0x1230U // Chipidea-Microelectronica, S.A.
+#define UHS_VID_DENVER_ELECTRONICS 0x1233U // Denver Electronics
+#define UHS_VID_BRAIN_ACTUATED_TECHNOLOGIES 0x1234U // Brain Actuated Technologies
+#define UHS_VID_FOCUSRITE_NOVATION 0x1235U // Focusrite-Novation
+#define UHS_VID_BELKIN 0x1241U // Belkin
+#define UHS_VID_AIRVAST 0x124aU // AirVast
+#define UHS_VID_NYKO_HONEY_BEE 0x124bU // Nyko (Honey Bee)
+#define UHS_VID_MXI__MEMORY_EXPERTS_INTERNATIONAL 0x124cU // MXI - Memory Experts International, Inc.
+#define UHS_VID_APOGEE 0x125cU // Apogee Inc.
+#define UHS_VID_A_DATA_TECHNOLOGY 0x125fU // A-DATA Technology Co., Ltd.
+#define UHS_VID_STANDARD_MICROSYSTEMS_3 0x1260U // Standard Microsystems Corp.
+#define UHS_VID_COVIDIEN_ENERGY_BASED_DEVICES 0x1264U // Covidien Energy-based Devices
+#define UHS_VID_PIRELLI_BROADBAND_SOLUTIONS 0x1266U // Pirelli Broadband Solutions
+#define UHS_VID_LOGIC3_SPECTRAVIDEO_PLC 0x1267U // Logic3 / SpectraVideo plc
+#define UHS_VID_ARISTOCRAT_TECHNOLOGIES 0x126cU // Aristocrat Technologies
+#define UHS_VID_BEL_STEWART 0x126dU // Bel Stewart
+#define UHS_VID_STROBE_DATA 0x126eU // Strobe Data, Inc.
+#define UHS_VID_TWINMOS 0x126fU // TwinMOS
+#define UHS_VID_ENSONIQ 0x1274U // Ensoniq
+#define UHS_VID_XAXERO_MARINE_SOFTWARE_ENGINEERING 0x1275U // Xaxero Marine Software Engineering, Ltd.
+#define UHS_VID_STARLIGHT_XPRESS 0x1278U // Starlight Xpress
+#define UHS_VID_ZEBRIS_MEDICAL 0x1283U // zebris Medical GmbH
+#define UHS_VID_MARVELL_SEMICONDUCTOR 0x1286U // Marvell Semiconductor, Inc.
+#define UHS_VID_QUALCOMM_FLARION_TECHNOLOGIES_INC_LEADTEK_RESEARCH 0x1291U // Qualcomm Flarion Technologies, Inc. / Leadtek Research, Inc.
+#define UHS_VID_INNOMEDIA_1 0x1292U // Innomedia
+#define UHS_VID_BELKIN_COMPONENTS_HEX_ 0x1293U // Belkin Components [hex]
+#define UHS_VID_RISO_KAGAKU 0x1294U // RISO KAGAKU CORP.
+#define UHS_VID_CYBERTAN_TECHNOLOGY 0x129bU // CyberTAN Technology
+#define UHS_VID_TRENDCHIP_TECHNOLOGIES 0x12a7U // Trendchip Technologies Corp.
+#define UHS_VID_HONEY_BEE_ELECTRONIC_INTERNATIONAL 0x12abU // Honey Bee Electronic International Ltd.
+#define UHS_VID_ZHEJIANG_XINYA_ELECTRONIC_TECHNOLOGY 0x12b8U // Zhejiang Xinya Electronic Technology Co., Ltd.
+#define UHS_VID_E28 0x12b9U // E28
+#define UHS_VID_LICENSED_BY_SONY_COMPUTER_ENTERTAINMENT_AMERICA 0x12baU // Licensed by Sony Computer Entertainment America
+#define UHS_VID_GEMBIRD 0x12bdU // Gembird
+#define UHS_VID_AUTOCUE_GROUP 0x12c4U // Autocue Group Ltd
+#define UHS_VID_DEXIN_1 0x12cfU // DEXIN
+#define UHS_VID_HUAWEI_TECHNOLOGIES 0x12d1U // Huawei Technologies Co., Ltd.
+#define UHS_VID_LINE_TECH_INDUSTRIAL 0x12d2U // LINE TECH INDUSTRIAL CO., LTD.
+#define UHS_VID_EMS_DR_THOMAS_WUENSCHE 0x12d6U // EMS Dr. Thomas Wuensche
+#define UHS_VID_BETTER_WIRE_FACTORY 0x12d7U // BETTER WIRE FACTORY CO., LTD.
+#define UHS_VID_ARANEUS_INFORMATION_SYSTEMS_OY 0x12d8U // Araneus Information Systems Oy
+#define UHS_VID_WALDORF_MUSIC 0x12e6U // Waldorf Music GmbH
+#define UHS_VID_TAPWAVE 0x12efU // Tapwave, Inc.
+#define UHS_VID_DYNAMIC_SYSTEM_ELECTRONICS 0x12f5U // Dynamic System Electronics Corp.
+#define UHS_VID_MEMOREX_PRODUCTS 0x12f7U // Memorex Products, Inc.
+#define UHS_VID_AIN_COMM_TECHNOLOGY 0x12fdU // AIN Comm. Technology Co., Ltd
+#define UHS_VID_FASCINATING_ELECTRONICS 0x12ffU // Fascinating Electronics, Inc.
+#define UHS_VID_TRANSCEND_INFORMATION 0x1307U // Transcend Information, Inc.
+#define UHS_VID_SHUTTLE_1 0x1308U // Shuttle, Inc.
+#define UHS_VID_ROPER 0x1310U // Roper
+#define UHS_VID_ICS_ELECTRONICS 0x1312U // ICS Electronics
+#define UHS_VID_THORLABS 0x1313U // ThorLabs
+#define UHS_VID_NATURAL_POINT 0x131dU // Natural Point
+#define UHS_VID_ENVARA 0x132aU // Envara Inc.
+#define UHS_VID_KONICA_MINOLTA 0x132bU // Konica Minolta
+#define UHS_VID_KEMPER_DIGITAL 0x133eU // Kemper Digital GmbH
+#define UHS_VID_MOBILITY 0x1342U // Mobility
+#define UHS_VID_CITIZEN_SYSTEMS 0x1343U // Citizen Systems
+#define UHS_VID_SINO_LITE_TECHNOLOGY 0x1345U // Sino Lite Technology Corp.
+#define UHS_VID_MORAVIAN_INSTRUMENTS 0x1347U // Moravian Instruments
+#define UHS_VID_KATSURAGAWA_ELECTRIC 0x1348U // Katsuragawa Electric Co., Ltd.
+#define UHS_VID_PANJIT_INTERNATIONAL 0x134cU // PanJit International Inc.
+#define UHS_VID_DIGBYS_BITPILE_INC_DBA_D_BIT 0x134eU // Digby's Bitpile, Inc. DBA D Bit
+#define UHS_VID_PANDE_MICROCOMPUTER_SYSTEMS 0x1357U // P&E Microcomputer Systems
+#define UHS_VID_CONTROL_DEVELOPMENT 0x135fU // Control Development Inc.
+#define UHS_VID_SEGGER 0x1366U // SEGGER
+#define UHS_VID_STEC 0x136bU // STEC
+#define UHS_VID_ANDOR_TECHNOLOGY 0x136eU // Andor Technology Ltd.
+#define UHS_VID_SWISSBIT 0x1370U // Swissbit
+#define UHS_VID_CNET_TECHNOLOGY 0x1371U // CNet Technology Inc.
+#define UHS_VID_VIMTRON_ELECTRONICS 0x1376U // Vimtron Electronics Co., Ltd.
+#define UHS_VID_SCAPS 0x137bU // SCAPS GmbH
+#define UHS_VID_NETGEAR_2 0x1385U // Netgear, Inc
+#define UHS_VID_VALIDITY_SENSORS 0x138aU // Validity Sensors, Inc.
+#define UHS_VID_JUNGO 0x138eU // Jungo LTD
+#define UHS_VID_TOMTOM_BV 0x1390U // TOMTOM B.V.
+#define UHS_VID_IDEALTEK 0x1391U // IdealTEK, Inc.
+#define UHS_VID_SENNHEISER_COMMUNICATIONS 0x1395U // Sennheiser Communications
+#define UHS_VID_BEHRINGER_INTERNATIONAL 0x1397U // BEHRINGER International GmbH
+#define UHS_VID_Q_TEC 0x1398U // Q-tec
+#define UHS_VID_BALTECH 0x13adU // Baltech
+#define UHS_VID_PERKINELMER_OPTOELECTRONICS 0x13b0U // PerkinElmer Optoelectronics
+#define UHS_VID_LINKSYS_2 0x13b1U // Linksys
+#define UHS_VID_ALESIS 0x13b2U // Alesis
+#define UHS_VID_NIPPON_DICS 0x13b3U // Nippon Dics Co., Ltd.
+#define UHS_VID_PCPLAY 0x13baU // PCPlay
+#define UHS_VID_RICOH_PRINTING_SYSTEMS 0x13beU // Ricoh Printing Systems, Ltd.
+#define UHS_VID_JYETAI_PRECISION_INDUSTRIAL 0x13caU // JyeTai Precision Industrial Co., Ltd.
+#define UHS_VID_WISAIR 0x13cfU // Wisair Ltd.
+#define UHS_VID_TECHSAN_ELECTRONICS 0x13d0U // Techsan Electronics Co., Ltd.
+#define UHS_VID_A_MAX_TECHNOLOGY_MACAO_COMMERCIAL_OFFSHORE 0x13d1U // A-Max Technology Macao Commercial Offshore Co. Ltd.
+#define UHS_VID_SHARK_MULTIMEDIA_1 0x13d2U // Shark Multimedia
+#define UHS_VID_IMC_NETWORKS 0x13d3U // IMC Networks
+#define UHS_VID_GUIDANCE_SOFTWARE 0x13d7U // Guidance Software, Inc.
+#define UHS_VID_ALEREON 0x13dcU // ALEREON, INC.
+#define UHS_VID_ITECH_DYNAMIC_LIMITED 0x13ddU // i.Tech Dynamic Limited
+#define UHS_VID_KAIBO_WIRE_AND_CABLE_SHENZHEN 0x13e1U // Kaibo Wire & Cable (Shenzhen) Co., Ltd.
+#define UHS_VID_RANE 0x13e5U // Rane
+#define UHS_VID_TECHNOSCOPE 0x13e6U // TechnoScope Co., Ltd.
+#define UHS_VID_HENGSTLER 0x13eaU // Hengstler
+#define UHS_VID_ZYDACRON 0x13ecU // Zydacron
+#define UHS_VID_MOSART 0x13eeU // MosArt
+#define UHS_VID_INITIO_CORPORATION 0x13fdU // Initio Corporation
+#define UHS_VID_KINGSTON_TECHNOLOGY_COMPANY_1 0x13feU // Kingston Technology Company Inc.
+#define UHS_VID_AXXION_GROUP 0x1400U // Axxion Group Corp.
+#define UHS_VID_BOWE_BELL_AND_HOWELL 0x1402U // Bowe Bell & Howell
+#define UHS_VID_SITRONIX 0x1403U // Sitronix
+#define UHS_VID_IDS_IMAGING_DEVELOPMENT_SYSTEMS 0x1409U // IDS Imaging Development Systems GmbH
+#define UHS_VID_TELECHIPS 0x140eU // Telechips, Inc.
+#define UHS_VID_NOVATEL_WIRELESS_1 0x1410U // Novatel Wireless
+#define UHS_VID_NAM_TAI_EANDE_PRODUCTS_LTD_OR_OMNIVISION_TECHNOLOGIES 0x1415U // Nam Tai E&E Products Ltd. or OmniVision Technologies, Inc.
+#define UHS_VID_ABILITY_ENTERPRISE 0x1419U // ABILITY ENTERPRISE CO., LTD.
+#define UHS_VID_SENSOR_TECHNOLOGY 0x1421U // Sensor Technology
+#define UHS_VID_VEGA_TECHNOLOGIES_INDUSTRIAL_AUSTRIA 0x1429U // Vega Technologies Industrial (Austria) Co.
+#define UHS_VID_THALES_E_TRANSACTIONS 0x142aU // Thales E-Transactions
+#define UHS_VID_ARBITER_SYSTEMS 0x142bU // Arbiter Systems, Inc.
+#define UHS_VID_REDOCTANE 0x1430U // RedOctane
+#define UHS_VID_PERTECH_RESOURCES 0x1431U // Pertech Resources, Inc.
+#define UHS_VID_WISTRON_NEWEB 0x1435U // Wistron NeWeb
+#define UHS_VID_DENALI_SOFTWARE 0x1436U // Denali Software, Inc.
+#define UHS_VID_ALTEK_CORPORATION 0x143cU // Altek Corporation
+#define UHS_VID_DIGILENT 0x1443U // Digilent
+#define UHS_VID_XJGROUP 0x1446U // X.J.GROUP
+#define UHS_VID_RADIO_SHACK 0x1453U // Radio Shack
+#define UHS_VID_EXTENDING_WIRE_AND_CABLE 0x1456U // Extending Wire & Cable Co., Ltd.
+#define UHS_VID_FIRST_INTERNATIONAL_COMPUTER_1 0x1457U // First International Computer, Inc.
+#define UHS_VID_TRUST 0x145fU // Trust
+#define UHS_VID_TATUNG 0x1460U // Tatung Co.
+#define UHS_VID_STACCATO_COMMUNICATIONS 0x1461U // Staccato Communications
+#define UHS_VID_MICRO_STAR_INTERNATIONAL_1 0x1462U // Micro Star International
+#define UHS_VID_HUAWEI_3COM 0x1472U // Huawei-3Com
+#define UHS_VID_FORMOSA_INDUSTRIAL_COMPUTING 0x147aU // Formosa Industrial Computing, Inc.
+#define UHS_VID_UPEK 0x147eU // Upek
+#define UHS_VID_HAMA_GMBH_AND_CO_KG 0x147fU // Hama GmbH & Co., KG
+#define UHS_VID_VAILLANT 0x1482U // Vaillant
+#define UHS_VID_ELSA_AG_HEX_ 0x1484U // Elsa AG [hex]
+#define UHS_VID_SILICOM_1 0x1485U // Silicom
+#define UHS_VID_DSP_GROUP 0x1487U // DSP Group, Ltd.
+#define UHS_VID_EVATRONIX 0x148eU // EVATRONIX SA
+#define UHS_VID_RALINK_TECHNOLOGY 0x148fU // Ralink Technology, Corp.
+#define UHS_VID_FUTRONIC_TECHNOLOGY 0x1491U // Futronic Technology Co. Ltd.
+#define UHS_VID_SUUNTO 0x1493U // Suunto
+#define UHS_VID_PANSTRONG_COMPANY 0x1497U // Panstrong Company Ltd.
+#define UHS_VID_MICROTEK_INTERNATIONAL_1 0x1498U // Microtek International Inc.
+#define UHS_VID_IMAGINATION_TECHNOLOGIES 0x149aU // Imagination Technologies
+#define UHS_VID_WIDEVIEW_TECHNOLOGY 0x14aaU // WideView Technology Inc.
+#define UHS_VID_CTK_CORPORATION 0x14adU // CTK Corporation
+#define UHS_VID_PRINTRONIX 0x14aeU // Printronix Inc.
+#define UHS_VID_ATP_ELECTRONICS 0x14afU // ATP Electronics Inc.
+#define UHS_VID_STARTECHCOM 0x14b0U // StarTech.com Ltd.
+#define UHS_VID_RALINK_TECHNOLOGY_1 0x14b2U // Ralink Technology, Corp.
+#define UHS_VID_ROCKWELL_AUTOMATION 0x14c0U // Rockwell Automation, Inc.
+#define UHS_VID_GEMLIGHT_COMPUTER 0x14c2U // Gemlight Computer, Ltd
+#define UHS_VID_ZYTRONIC 0x14c8U // Zytronic
+#define UHS_VID_SUPER_TOP 0x14cdU // Super Top
+#define UHS_VID_JAMER_INDUSTRIES 0x14d8U // JAMER INDUSTRIES CO., LTD.
+#define UHS_VID_RARITAN_COMPUTER 0x14ddU // Raritan Computer, Inc.
+#define UHS_VID_WINRADIO_COMMUNICATIONS 0x14e0U // WiNRADiO Communications
+#define UHS_VID_DIALOGUE_TECHNOLOGY 0x14e1U // Dialogue Technology Corp.
+#define UHS_VID_SAIN_INFORMATION_AND_COMMUNICATIONS 0x14e5U // SAIN Information & Communications Co., Ltd.
+#define UHS_VID_PLANEX_COMMUNICATIONS_1 0x14eaU // Planex Communications
+#define UHS_VID_SHURE 0x14edU // Shure Inc.
+#define UHS_VID_TECHNISAT_DIGITAL 0x14f7U // TechniSat Digital GmbH
+#define UHS_VID_ELLISYS_1 0x1500U // Ellisys
+#define UHS_VID_PINE_TUM_ENTERPRISE 0x1501U // Pine-Tum Enterprise Co., Ltd.
+#define UHS_VID_FIRST_INTERNATIONAL_COMPUTER_2 0x1509U // First International Computer, Inc.
+#define UHS_VID_MEDMOBILE 0x1513U // medMobile
+#define UHS_VID_ACTEL 0x1514U // Actel
+#define UHS_VID_COMPUSA 0x1516U // CompUSA
+#define UHS_VID_CHESHIRE_ENGINEERING 0x1518U // Cheshire Engineering Corp.
+#define UHS_VID_COMNEON 0x1519U // Comneon
+#define UHS_VID_BITWIRE 0x1520U // Bitwire Corp.
+#define UHS_VID_ENE_TECHNOLOGY_1 0x1524U // ENE Technology Inc
+#define UHS_VID_SILICON_PORTALS 0x1527U // Silicon Portals
+#define UHS_VID_UBIQUAM 0x1529U // UBIQUAM Co., Ltd.
+#define UHS_VID_THESYCON_SYSTEMSOFTWARE_AND_CONSULTING 0x152aU // Thesycon Systemsoftware & Consulting GmbH
+#define UHS_VID_MIR_SRL 0x152bU // MIR Srl
+#define UHS_VID_JMICRON_TECHNOLOGY_CORP_JMICRON_USA_TECHNOLOGY 0x152dU // JMicron Technology Corp. / JMicron USA Technology Corp.
+#define UHS_VID_LG_HLDS 0x152eU // LG (HLDS)
+#define UHS_VID_RAZER_USA 0x1532U // Razer USA, Ltd
+#define UHS_VID_TERRATEC_ELECTRONIC_1 0x153bU // TerraTec Electronic GmbH
+#define UHS_VID_U_BLOX_AG 0x1546U // U-Blox AG
+#define UHS_VID_SG_INTEC_LTD_AND_CO_KG 0x1547U // SG Intec Ltd & Co KG
+#define UHS_VID_CELECTRONIC 0x154aU // Celectronic GmbH
+#define UHS_VID_PNY 0x154bU // PNY
+#define UHS_VID_CONNECTCOUNTY_HOLDINGS_BERHAD 0x154dU // ConnectCounty Holdings Berhad
+#define UHS_VID_DANDM_HOLDINGS_INC_DENONMARANTZ 0x154eU // D&M Holdings, Inc. (Denon/Marantz)
+#define UHS_VID_SNBC 0x154fU // SNBC CO., Ltd
+#define UHS_VID_PROLINK_MICROSYSTEMS 0x1554U // Prolink Microsystems Corp.
+#define UHS_VID_OQO 0x1557U // OQO
+#define UHS_VID_SUNF_PU_TECHNOLOGY 0x1568U // Sunf Pu Technology Co., Ltd
+#define UHS_VID_QUANTUM_CORPORATION 0x156fU // Quantum Corporation
+#define UHS_VID_ALLTOP_TECHNOLOGY 0x1570U // ALLTOP TECHNOLOGY CO., LTD.
+#define UHS_VID_KETRON_SRL 0x157bU // Ketron SRL
+#define UHS_VID_TRENDNET 0x157eU // TRENDnet
+#define UHS_VID_FIBERLINE 0x1582U // Fiberline
+#define UHS_VID_SMA_TECHNOLOGIE_AG 0x1587U // SMA Technologie AG
+#define UHS_VID_OAKLEY 0x158dU // Oakley Inc.
+#define UHS_VID_JDS_UNIPHASE_CORPORATION_JDSU 0x158eU // JDS Uniphase Corporation (JDSU)
+#define UHS_VID_KUNSHAN_GUOJI_ELECTRONICS 0x1598U // Kunshan Guoji Electronics Co., Ltd.
+#define UHS_VID_FREESCALE_SEMICONDUCTOR 0x15a2U // Freescale Semiconductor, Inc.
+#define UHS_VID_AFATECH_TECHNOLOGIES 0x15a4U // Afatech Technologies, Inc.
+#define UHS_VID_TEAMS_POWER_LIMITED 0x15a8U // Teams Power Limited
+#define UHS_VID_GEMTEK 0x15a9U // Gemtek
+#define UHS_VID_GEARWAY_ELECTRONICS_DONG_GUAN 0x15aaU // Gearway Electronics (Dong Guan) Co., Ltd.
+#define UHS_VID_VMWARE_1 0x15adU // VMware Inc.
+#define UHS_VID_OLIMEX 0x15baU // Olimex Ltd.
+#define UHS_VID_XL_IMAGING 0x15c0U // XL Imaging
+#define UHS_VID_SOUNDGRAPH 0x15c2U // SoundGraph Inc.
+#define UHS_VID_ADVANCE_MULTIMEDIA_INTERNET_TECHNOLOGY_INC_AMIT 0x15c5U // Advance Multimedia Internet Technology Inc. (AMIT)
+#define UHS_VID_LABORATOIRES_MXM 0x15c6U // Laboratoires MXM
+#define UHS_VID_KTF_TECHNOLOGIES 0x15c8U // KTF Technologies
+#define UHS_VID_D_BOX_TECHNOLOGIES 0x15c9U // D-Box Technologies
+#define UHS_VID_TEXTECH_INTERNATIONAL 0x15caU // Textech International Ltd.
+#define UHS_VID_COULOMB_ELECTRONICS 0x15d5U // Coulomb Electronics Ltd.
+#define UHS_VID_TRUST_INTERNATIONAL_BV_1 0x15d9U // Trust International B.V.
+#define UHS_VID_HYNIX_SEMICONDUCTOR 0x15dcU // Hynix Semiconductor Inc.
+#define UHS_VID_SEONG_JI_INDUSTRIAL 0x15e0U // Seong Ji Industrial Co., Ltd.
+#define UHS_VID_RSA 0x15e1U // RSA
+#define UHS_VID_NUMARK 0x15e4U // Numark
+#define UHS_VID_SOHOWARE 0x15e8U // SohoWare
+#define UHS_VID_PACIFIC_DIGITAL 0x15e9U // Pacific Digital Corp.
+#define UHS_VID_BELCARRA_TECHNOLOGIES 0x15ecU // Belcarra Technologies Corp.
+#define UHS_VID_HANFTEK 0x15f4U // HanfTek
+#define UHS_VID_TASCAM 0x1604U // Tascam
+#define UHS_VID_UMAX_1 0x1606U // Umax
+#define UHS_VID_INSIDE_OUT_NETWORKS_HEX_ 0x1608U // Inside Out Networks [hex]
+#define UHS_VID_VIA_TECHNOLOGIES_1 0x160aU // VIA Technologies, Inc.
+#define UHS_VID_INRO 0x160eU // INRO
+#define UHS_VID_AMOI_ELECTRONICS 0x1614U // Amoi Electronics
+#define UHS_VID_SONY_1 0x1617U // Sony Corp.
+#define UHS_VID_L_AND_K_PRECISION_TECHNOLOGY 0x1619U // L & K Precision Technology Co., Ltd.
+#define UHS_VID_WIONICS_RESEARCH 0x1621U // Wionics Research
+#define UHS_VID_STONESTREET_ONE 0x1628U // Stonestreet One, Inc.
+#define UHS_VID_AIRGO_NETWORKS 0x162aU // Airgo Networks Inc.
+#define UHS_VID_WIQUEST_COMMUNICATIONS 0x162fU // WiQuest Communications, Inc.
+#define UHS_VID_2WIRE_1 0x1630U // 2Wire, Inc.
+#define UHS_VID_GOOD_WAY_TECHNOLOGY 0x1631U // Good Way Technology
+#define UHS_VID_ENTREGA_HEX_ 0x1645U // Entrega [hex]
+#define UHS_VID_SOFTEC_MICROSYSTEMS 0x1649U // SofTec Microsystems
+#define UHS_VID_CHIPX 0x164aU // ChipX
+#define UHS_VID_MATRIX_VISION 0x164cU // Matrix Vision GmbH
+#define UHS_VID_STRUCK_INNOVATIVE_SYSTEME 0x1657U // Struck Innovative Systeme GmbH
+#define UHS_VID_FRONTIER_DESIGN_GROUP 0x165bU // Frontier Design Group
+#define UHS_VID_KONDO_KAGAKU 0x165cU // Kondo Kagaku
+#define UHS_VID_CREATIX_POLYMEDIA 0x1660U // Creatix Polymedia GmbH
+#define UHS_VID_GIGA_TMS 0x1667U // GIGA-TMS INC.
+#define UHS_VID_ACTIONTEC_ELECTRONICS_INC_HEX_ 0x1668U // Actiontec Electronics, Inc. [hex]
+#define UHS_VID_PIKRON_LTD_HEX_ 0x1669U // PiKRON Ltd. [hex]
+#define UHS_VID_CLIPSAL 0x166aU // Clipsal
+#define UHS_VID_CHINA_HUADA_INTEGRATED_CIRCUIT_DESIGN_GROUP_CO_LTD_CIDC_GROUP 0x1677U // China Huada Integrated Circuit Design (Group) Co., Ltd. (CIDC Group)
+#define UHS_VID_TOTAL_PHASE 0x1679U // Total Phase
+#define UHS_VID_GOLDEN_BRIDGE_ELECTECH_1 0x1680U // Golden Bridge Electech Inc.
+#define UHS_VID_PREVO_TECHNOLOGIES 0x1681U // Prevo Technologies, Inc.
+#define UHS_VID_MAXWISE_PRODUCTION_ENTERPRISE 0x1682U // Maxwise Production Enterprise Ltd.
+#define UHS_VID_GODSPEED_COMPUTER 0x1684U // Godspeed Computer Corp.
+#define UHS_VID_DELOCK 0x1685U // Delock
+#define UHS_VID_ZOOM_CORPORATION 0x1686U // ZOOM Corporation
+#define UHS_VID_KINGMAX_DIGITAL 0x1687U // Kingmax Digital Inc.
+#define UHS_VID_SAAB 0x1688U // Saab AB
+#define UHS_VID_RAZER_USA_1 0x1689U // Razer USA, Ltd
+#define UHS_VID_ATHEROS_COMMUNICATIONS_1 0x168cU // Atheros Communications
+#define UHS_VID_ASKEY_COMPUTER_CORP_HEX_ 0x1690U // Askey Computer Corp. [hex]
+#define UHS_VID_HITACHI_VIDEO_AND_INFORMATION_SYSTEM 0x1696U // Hitachi Video and Information System, Inc.
+#define UHS_VID_VTEC_TEST 0x1697U // VTec Test, Inc.
+#define UHS_VID_SHENZHEN_ZHENGERYA_CABLE 0x16a5U // Shenzhen Zhengerya Cable Co., Ltd.
+#define UHS_VID_UNIGRAF 0x16a6U // Unigraf
+#define UHS_VID_GLOBAL_SUN_TECHNOLOGY_1 0x16abU // Global Sun Technology
+#define UHS_VID_DONGGUAN_CHINGLUNG_WIRE_AND_CABLE 0x16acU // Dongguan ChingLung Wire & Cable Co., Ltd.
+#define UHS_VID_ISTATION 0x16b4U // iStation
+#define UHS_VID_PERSENTEC 0x16b5U // Persentec, Inc.
+#define UHS_VID_VAN_OOIJEN_TECHNISCHE_INFORMATICA 0x16c0U // Van Ooijen Technische Informatica
+#define UHS_VID_WIRELESS_CABLES 0x16caU // Wireless Cables, Inc.
+#define UHS_VID_SILEX_TECHNOLOGY 0x16ccU // silex technology, Inc.
+#define UHS_VID_MCS 0x16d0U // MCS
+#define UHS_VID_SUPREMA 0x16d1U // Suprema Inc.
+#define UHS_VID_FRONTLINE_TEST_EQUIPMENT 0x16d3U // Frontline Test Equipment, Inc.
+#define UHS_VID_ANYDATA_CORPORATION 0x16d5U // AnyDATA Corporation
+#define UHS_VID_JABLOCOM_SRO 0x16d6U // JABLOCOM s.r.o.
+#define UHS_VID_CMOTECH 0x16d8U // CMOTECH Co., Ltd.
+#define UHS_VID_WIENER_PLEIN_AND_BAUS 0x16dcU // Wiener, Plein & Baus
+#define UHS_VID_KING_BILLION_ELECTRONICS 0x16dfU // King Billion Electronics Co., Ltd.
+#define UHS_VID_GN_RESOUND_AS 0x16f0U // GN ReSound A/S
+#define UHS_VID_FUTURELOGIC 0x16f5U // Futurelogic Inc.
+#define UHS_VID_BLUEVIEW_TECHNOLOGIES 0x1706U // BlueView Technologies, Inc.
+#define UHS_VID_ARTIMI 0x1707U // ARTIMI
+#define UHS_VID_SWISSONIC 0x170bU // Swissonic
+#define UHS_VID_AVNERA 0x170dU // Avnera
+#define UHS_VID_LEICA_MICROSYSTEMS 0x1711U // Leica Microsystems
+#define UHS_VID_MEYER_INSTRUMENTS_MIS 0x1724U // Meyer Instruments (MIS)
+#define UHS_VID_VITESSE_SEMICONDUCTOR 0x1725U // Vitesse Semiconductor
+#define UHS_VID_AXESSTEL 0x1726U // Axesstel, Inc.
+#define UHS_VID_WALTOP_INTERNATIONAL 0x172fU // Waltop International Corp.
+#define UHS_VID_CELLINK_TECHNOLOGY 0x1733U // Cellink Technology Co., Ltd
+#define UHS_VID_CANON_IMAGING_SYSTEM_TECHNOLOGIES 0x1736U // CANON IMAGING SYSTEM TECHNOLOGIES INC.
+#define UHS_VID_LINKSYS_3 0x1737U // Linksys
+#define UHS_VID_QSENN 0x173dU // QSENN
+#define UHS_VID_SENAO 0x1740U // Senao
+#define UHS_VID_GENERAL_ATOMICS 0x1743U // General Atomics
+#define UHS_VID_MQP_ELECTRONICS 0x1748U // MQP Electronics
+#define UHS_VID_ASMEDIA_TECHNOLOGY 0x174cU // ASMedia Technology Inc.
+#define UHS_VID_SYNTEK 0x174fU // Syntek
+#define UHS_VID_GERTEC_TELECOMUNICACOES_LTDA 0x1753U // GERTEC Telecomunicacoes Ltda.
+#define UHS_VID_ENENSYS_TECHNOLOGIES 0x1756U // ENENSYS Technologies
+#define UHS_VID_LUCIDPORT_TECHNOLOGY 0x1759U // LucidPort Technology, Inc.
+#define UHS_VID_ASUSTEK_COMPUTER_INC_WRONG_ID 0x1761U // ASUSTek Computer, Inc. (wrong ID)
+#define UHS_VID_SYSTEM_LEVEL_SOLUTIONS 0x1772U // System Level Solutions, Inc.
+#define UHS_VID_AROWANA 0x1776U // Arowana
+#define UHS_VID_SWEEX 0x177fU // Sweex
+#define UHS_VID_MULTIPLE_VENDORS 0x1781U // Multiple Vendors
+#define UHS_VID_SPREADTRUM_COMMUNICATIONS 0x1782U // Spreadtrum Communications Inc.
+#define UHS_VID_TOPSEED_TECHNOLOGY 0x1784U // TopSeed Technology Corp.
+#define UHS_VID_ATI_AIB 0x1787U // ATI AIB
+#define UHS_VID_SHENZHEN_LITKCONN_TECHNOLOGY 0x1788U // ShenZhen Litkconn Technology Co., Ltd.
+#define UHS_VID_PRINTREX 0x1796U // Printrex, Inc.
+#define UHS_VID_JALCO 0x1797U // JALCO CO., LTD.
+#define UHS_VID_THALES_NORWAY_AS 0x1799U // Thales Norway A/S
+#define UHS_VID_RICAVISION_INTERNATIONAL 0x179dU // Ricavision International, Inc.
+#define UHS_VID_SAMSON_TECHNOLOGIES 0x17a0U // Samson Technologies Corp.
+#define UHS_VID_CONCEPT2 0x17a4U // Concept2
+#define UHS_VID_ADVANCED_CONNECTION_TECHNOLOGY 0x17a5U // Advanced Connection Technology Inc.
+#define UHS_VID_MICOMSOFT 0x17a7U // MICOMSOFT CO., LTD.
+#define UHS_VID_KAMSTRUP_AS 0x17a8U // Kamstrup A/S
+#define UHS_VID_GREY_INNOVATION 0x17b3U // Grey Innovation
+#define UHS_VID_LUNATONE 0x17b5U // Lunatone
+#define UHS_VID_SAURIS 0x17baU // SAURIS GmbH
+#define UHS_VID_SINGIM_INTERNATIONAL 0x17c3U // Singim International Corp.
+#define UHS_VID_NATIVE_INSTRUMENTS 0x17ccU // Native Instruments
+#define UHS_VID_HIP_HING_CABLE_AND_PLUG_MFY 0x17cfU // Hip Hing Cable & Plug Mfy. Ltd.
+#define UHS_VID_SANFORD_LP 0x17d0U // Sanford L.P.
+#define UHS_VID_KOREA_TECHTRON 0x17d3U // Korea Techtron Co., Ltd.
+#define UHS_VID_DISPLAYLINK 0x17e9U // DisplayLink
+#define UHS_VID_CORNICE 0x17ebU // Cornice, Inc.
+#define UHS_VID_LENOVO 0x17efU // Lenovo
+#define UHS_VID_WAVESENSE 0x17f4U // WaveSense
+#define UHS_VID_KK_ROCKY 0x17f5U // K.K. Rocky
+#define UHS_VID_UNICOMP 0x17f6U // Unicomp, Inc
+#define UHS_VID_ADVANTECH 0x1809U // Advantech
+#define UHS_VID_TWINHAN 0x1822U // Twinhan
+#define UHS_VID_GWO_JINN_INDUSTRIES 0x1831U // Gwo Jinn Industries Co., Ltd.
+#define UHS_VID_HUIZHOU_SHENGHUA_INDUSTRIAL 0x1832U // Huizhou Shenghua Industrial Co., Ltd.
+#define UHS_VID_VIVOPHONE 0x183dU // VIVOphone
+#define UHS_VID_VAISALA 0x1843U // Vaisala
+#define UHS_VID_ASROCK_INCORPORATION 0x1849U // ASRock Incorporation
+#define UHS_VID_GYROCOM_CANDC 0x1852U // GYROCOM C&C Co., LTD
+#define UHS_VID_MEMORY_DEVICES 0x1854U // Memory Devices Ltd.
+#define UHS_VID_COMPRO 0x185bU // Compro
+#define UHS_VID_TECH_TECHNOLOGY_INDUSTRIAL_COMPANY 0x1861U // Tech Technology Industrial Company
+#define UHS_VID_TERIDIAN_SEMICONDUCTOR 0x1862U // Teridian Semiconductor Corp.
+#define UHS_VID_NEXIO_1 0x1870U // Nexio Co., Ltd
+#define UHS_VID_AVEO_TECHNOLOGY 0x1871U // Aveo Technology Corp.
+#define UHS_VID_NAVILOCK 0x1873U // Navilock
+#define UHS_VID_ALIENWARE_CORPORATION 0x187cU // Alienware Corporation
+#define UHS_VID_SIANO_MOBILE_SILICON 0x187fU // Siano Mobile Silicon
+#define UHS_VID_VAST_TECHNOLOGIES_1 0x1892U // Vast Technologies, Inc.
+#define UHS_VID_TOPSEED 0x1894U // Topseed
+#define UHS_VID_EVERTOP_WIRE_CABLE 0x1897U // Evertop Wire Cable Co.
+#define UHS_VID_3SHAPE_AS 0x189fU // 3Shape A/S
+#define UHS_VID_CSSN 0x18a4U // CSSN
+#define UHS_VID_VERBATIM 0x18a5U // Verbatim, Ltd
+#define UHS_VID_PETALYNX 0x18b1U // Petalynx
+#define UHS_VID_E3C_TECHNOLOGIES 0x18b4U // e3C Technologies
+#define UHS_VID_MIKKON_TECHNOLOGY_LIMITED 0x18b6U // Mikkon Technology Limited
+#define UHS_VID_ZOTEK_ELECTRONIC 0x18b7U // Zotek Electronic Co., Ltd.
+#define UHS_VID_AMIT_TECHNOLOGY 0x18c5U // AMIT Technology, Inc.
+#define UHS_VID_ECAMM 0x18cdU // Ecamm
+#define UHS_VID_GOOGLE 0x18d1U // Google Inc.
+#define UHS_VID_STARLINE_INTERNATIONAL_GROUP_LIMITED 0x18d5U // Starline International Group Limited
+#define UHS_VID_KABA 0x18d9U // Kaba
+#define UHS_VID_LKC_TECHNOLOGIES 0x18dcU // LKC Technologies, Inc.
+#define UHS_VID_PLANON_SYSTEM_SOLUTIONS 0x18ddU // Planon System Solutions Inc.
+#define UHS_VID_FITIPOWER_INTEGRATED_TECHNOLOGY 0x18e3U // Fitipower Integrated Technology Inc
+#define UHS_VID_QCOM 0x18e8U // Qcom
+#define UHS_VID_MATROX_GRAPHICS 0x18eaU // Matrox Graphics, Inc.
+#define UHS_VID_ARKMICRO_TECHNOLOGIES 0x18ecU // Arkmicro Technologies Inc.
+#define UHS_VID_FINEARCH 0x18fdU // FineArch Inc.
+#define UHS_VID_GEMBIRD_1 0x1908U // GEMBIRD
+#define UHS_VID_MOTOROLA_GSG 0x190dU // Motorola GSG
+#define UHS_VID_ALCO_DIGITAL_DEVICES_LIMITED 0x1914U // Alco Digital Devices Limited
+#define UHS_VID_NORDIC_SEMICONDUCTOR_ASA 0x1915U // Nordic Semiconductor ASA
+#define UHS_VID_FITLINXX 0x1923U // FitLinxx
+#define UHS_VID_NEXTWINDOW 0x1926U // NextWindow
+#define UHS_VID_AVAGO_TECHNOLOGIES_PTE 0x192fU // Avago Technologies, Pte.
+#define UHS_VID_SHENZHEN_XIANHE_TECHNOLOGY 0x1930U // Shenzhen Xianhe Technology Co., Ltd.
+#define UHS_VID_NINGBO_BROAD_TELECOMMUNICATION 0x1931U // Ningbo Broad Telecommunication Co., Ltd.
+#define UHS_VID_FEATURE_INTEGRATION_TECHNOLOGY_INC_FINTEK 0x1934U // Feature Integration Technology Inc. (Fintek)
+#define UHS_VID_DREAM_LINK 0x1941U // Dream Link
+#define UHS_VID_SENSORAY 0x1943U // Sensoray Co., Inc.
+#define UHS_VID_LAB126 0x1949U // Lab126, Inc.
+#define UHS_VID_PRESONUS_AUDIO_ELECTRONICS 0x194fU // PreSonus Audio Electronics, Inc.
+#define UHS_VID_HYPERSTONE_AG 0x1951U // Hyperstone AG
+#define UHS_VID_IRONKEY 0x1953U // Ironkey Inc.
+#define UHS_VID_RADIIENT_TECHNOLOGIES 0x1954U // Radiient Technologies
+#define UHS_VID_ITRON_TECHNOLOGY_IONE 0x195dU // Itron Technology iONE
+#define UHS_VID_UNIDEN_CORPORATION 0x1965U // Uniden Corporation
+#define UHS_VID_CASIO_HITACHI_MOBILE_COMMUNICATIONS 0x1967U // CASIO HITACHI Mobile Communications Co., Ltd.
+#define UHS_VID_WISPRO_TECHNOLOGY 0x196bU // Wispro Technology Inc.
+#define UHS_VID_DANE_ELEC_CORP_USA 0x1970U // Dane-Elec Corp. USA
+#define UHS_VID_DONGGUAN_GUNEETAL_WIRE_AND_CABLE 0x1975U // Dongguan Guneetal Wire & Cable Co., Ltd.
+#define UHS_VID_CHIPSBRAND_MICROELECTRONICS_HK 0x1976U // Chipsbrand Microelectronics (HK) Co., Ltd.
+#define UHS_VID_T_LOGIC 0x1977U // T-Logic
+#define UHS_VID_LEUZE_ELECTRONIC 0x197dU // Leuze electronic
+#define UHS_VID_NUCONN_TECHNOLOGY 0x1989U // Nuconn Technology Corp.
+#define UHS_VID_BECEEM_COMMUNICATIONS 0x198fU // Beceem Communications Inc.
+#define UHS_VID_ACRON_PRECISION_INDUSTRIAL 0x1990U // Acron Precision Industrial Co., Ltd.
+#define UHS_VID_TRILLIUM_TECHNOLOGY_PTY 0x1995U // Trillium Technology Pty. Ltd.
+#define UHS_VID_PIXELINK 0x1996U // PixeLINK
+#define UHS_VID_MICROSTRAIN 0x199bU // MicroStrain, Inc.
+#define UHS_VID_THE_IMAGING_SOURCE_EUROPE 0x199eU // The Imaging Source Europe GmbH
+#define UHS_VID_BENICA_CORPORATION 0x199fU // Benica Corporation
+#define UHS_VID_BIFORST_TECHNOLOGY 0x19a8U // Biforst Technology Inc.
+#define UHS_VID_BODELIN 0x19abU // Bodelin
+#define UHS_VID_S_LIFE 0x19afU // S Life
+#define UHS_VID_BATRONIX 0x19b2U // Batronix
+#define UHS_VID_CELESTRON 0x19b4U // Celestron
+#define UHS_VID_B_AND_W_GROUP 0x19b5U // B & W Group
+#define UHS_VID_INFOTECH_LOGISTIC 0x19b6U // Infotech Logistic, LLC
+#define UHS_VID_DATA_ROBOTICS 0x19b9U // Data Robotics
+#define UHS_VID_FUTUBA 0x19c2U // Futuba
+#define UHS_VID_MINDTRIBE 0x19caU // Mindtribe
+#define UHS_VID_PARROT 0x19cfU // Parrot SA
+#define UHS_VID_ZTE_WCDMA_TECHNOLOGIES_MSM 0x19d2U // ZTE WCDMA Technologies MSM
+#define UHS_VID_KFI_PRINTERS 0x19dbU // KFI Printers
+#define UHS_VID_WEIDUAN_ELECTRONIC_ACCESSORY_SZ 0x19e1U // WeiDuan Electronic Accessory (S.Z.) Co., Ltd.
+#define UHS_VID_INDUSTRIAL_TECHNOLOGY_RESEARCH_INSTITUTE 0x19e8U // Industrial Technology Research Institute
+#define UHS_VID_PAK_HENG_TECHNOLOGY_SHENZHEN 0x19efU // Pak Heng Technology (Shenzhen) Co., Ltd.
+#define UHS_VID_RODE_MICROPHONES 0x19f7U // RODE Microphones
+#define UHS_VID_GAMPAQ_COLTD 0x19faU // Gampaq Co.Ltd
+#define UHS_VID_DYNEX 0x19ffU // Dynex
+#define UHS_VID_BELLWOOD_INTERNATIONAL 0x1a08U // Bellwood International, Inc.
+#define UHS_VID_USB_IF_NON_WORKSHOP 0x1a0aU // USB-IF non-workshop
+#define UHS_VID_KES 0x1a12U // KES Co., Ltd.
+#define UHS_VID_VEHO 0x1a1dU // Veho
+#define UHS_VID_AMPHENOL_EAST_ASIA 0x1a25U // Amphenol East Asia Ltd.
+#define UHS_VID_SEAGATE_BRANDED_SOLUTIONS 0x1a2aU // Seagate Branded Solutions
+#define UHS_VID_CHINA_RESOURCE_SEMICO 0x1a2cU // China Resource Semico Co., Ltd
+#define UHS_VID_QUANTA_MICROSYSTEMS 0x1a32U // Quanta Microsystems, Inc.
+#define UHS_VID_ACRUX 0x1a34U // ACRUX
+#define UHS_VID_BIWIN_TECHNOLOGY 0x1a36U // Biwin Technology Ltd.
+#define UHS_VID_TERMINUS_TECHNOLOGY 0x1a40U // Terminus Technology Inc.
+#define UHS_VID_ACTION_ELECTRONICS 0x1a41U // Action Electronics Co., Ltd.
+#define UHS_VID_VASCO_DATA_SECURITY_INTERNATIONAL 0x1a44U // VASCO Data Security International
+#define UHS_VID_SILICON_IMAGE 0x1a4aU // Silicon Image
+#define UHS_VID_SAFEBOOT_INTERNATIONAL_BV 0x1a4bU // SafeBoot International B.V.
+#define UHS_VID_TANDBERG_DATA 0x1a5aU // Tandberg Data
+#define UHS_VID_ABBOTT_DIABETES_CARE 0x1a61U // Abbott Diabetes Care
+#define UHS_VID_SPANSION 0x1a6aU // Spansion Inc.
+#define UHS_VID_SAMYOUNG_ELECTRONICS 0x1a6dU // SamYoung Electronics Co., Ltd
+#define UHS_VID_GLOBAL_UNICHIP 0x1a6eU // Global Unichip Corp.
+#define UHS_VID_SAGEM_ORGA 0x1a6fU // Sagem Orga GmbH
+#define UHS_VID_PHYSIK_INSTRUMENTE 0x1a72U // Physik Instrumente
+#define UHS_VID_BAYER_HEALTH_CARE 0x1a79U // Bayer Health Care LLC
+#define UHS_VID_LUMBERG_CONNECT_GMBH_AND_CO_KG 0x1a7bU // Lumberg Connect GmbH & Co. KG
+#define UHS_VID_EVOLUENT 0x1a7cU // Evoluent
+#define UHS_VID_HOLTEK_SEMICONDUCTOR_1 0x1a81U // Holtek Semiconductor, Inc.
+#define UHS_VID_QINHENG_ELECTRONICS 0x1a86U // QinHeng Electronics
+#define UHS_VID_DYNALITH_SYSTEMS 0x1a89U // Dynalith Systems Co., Ltd.
+#define UHS_VID_SGS_TAIWAN 0x1a8bU // SGS Taiwan Ltd.
+#define UHS_VID_BANDRICH 0x1a8dU // BandRich, Inc.
+#define UHS_VID_LEICA_CAMERA_AG 0x1a98U // Leica Camera AG
+#define UHS_VID_DATA_DRIVE_THRU 0x1aa4U // Data Drive Thru, Inc.
+#define UHS_VID_UBEACON_TECHNOLOGIES 0x1aa5U // UBeacon Technologies, Inc.
+#define UHS_VID_EFORTUNE_TECHNOLOGY 0x1aa6U // eFortune Technology Corp.
+#define UHS_VID_KEETOUCH 0x1aadU // KeeTouch
+#define UHS_VID_RIGOL_TECHNOLOGIES 0x1ab1U // Rigol Technologies
+#define UHS_VID_SALCOMP_PLC 0x1acbU // Salcomp Plc
+#define UHS_VID_MIDIPLUS 0x1accU // Midiplus Co, Ltd.
+#define UHS_VID_DESAY_WIRE 0x1ad1U // Desay Wire Co., Ltd.
+#define UHS_VID_APS 0x1ad4U // APS
+#define UHS_VID_SEL_C662_SERIAL_CABLE 0x1adbU // SEL C662 Serial Cable
+#define UHS_VID_IC_DESIGN_REINHARD_GOTTINGER 0x1ae4U // ic-design Reinhard Gottinger GmbH
+#define UHS_VID_X_TENSIONS 0x1ae7U // X-TENSIONS
+#define UHS_VID_HIGH_TOP_PRECISION_ELECTRONIC 0x1aedU // High Top Precision Electronic Co., Ltd.
+#define UHS_VID_CONNTECH_ELECTRONIC_SUZHOU_CORPORATION 0x1aefU // Conntech Electronic (Suzhou) Corporation
+#define UHS_VID_CONNECT_ONE 0x1af1U // Connect One Ltd.
+#define UHS_VID_A_EBERLE_GMBH_AND_CO_KG 0x1afeU // A. Eberle GmbH & Co. KG
+#define UHS_VID_MEILHAUS_ELECTRONIC 0x1b04U // Meilhaus Electronic GmbH
+#define UHS_VID_BLUTRONICS_SRL 0x1b0eU // BLUTRONICS S.r.l.
+#define UHS_VID_CORSAIR 0x1b1cU // Corsair
+#define UHS_VID_MSTAR_SEMICONDUCTOR 0x1b20U // MStar Semiconductor, Inc.
+#define UHS_VID_WILINX 0x1b22U // WiLinx Corp.
+#define UHS_VID_CELLEX_POWER_PRODUCTS 0x1b26U // Cellex Power Products, Inc.
+#define UHS_VID_CURRENT_ELECTRONICS 0x1b27U // Current Electronics Inc.
+#define UHS_VID_NAVISIS 0x1b28U // NAVIsis Inc.
+#define UHS_VID_UGOBE_LIFE_FORMS 0x1b32U // Ugobe Life Forms, Inc.
+#define UHS_VID_VIXS_SYSTEMS 0x1b36U // ViXS Systems, Inc.
+#define UHS_VID_IPASSION_TECHNOLOGY 0x1b3bU // iPassion Technology Inc.
+#define UHS_VID_GENERALPLUS_TECHNOLOGY 0x1b3fU // Generalplus Technology Inc.
+#define UHS_VID_ENERGIZER_HOLDINGS 0x1b47U // Energizer Holdings, Inc.
+#define UHS_VID_PLASTRON_PRECISION 0x1b48U // Plastron Precision Co., Ltd.
+#define UHS_VID_ARH 0x1b52U // ARH Inc.
+#define UHS_VID_KS_TERMINALS 0x1b59U // K.S. Terminals Inc.
+#define UHS_VID_CHAO_ZHOU_KAI_YUAN_ELECTRIC 0x1b5aU // Chao Zhou Kai Yuan Electric Co., Ltd.
+#define UHS_VID_THE_HONG_KONG_STANDARDS_AND_TESTING_CENTRE 0x1b65U // The Hong Kong Standards and Testing Centre Ltd.
+#define UHS_VID_FUSHICAI 0x1b71U // Fushicai
+#define UHS_VID_ATERGI_TECHNOLOGY 0x1b72U // ATERGI TECHNOLOGY CO., LTD.
+#define UHS_VID_FRESCO_LOGIC 0x1b73U // Fresco Logic
+#define UHS_VID_OVISLINK 0x1b75U // Ovislink Corp.
+#define UHS_VID_LEGEND_SILICON 0x1b76U // Legend Silicon Corp.
+#define UHS_VID_AFATECH 0x1b80U // Afatech
+#define UHS_VID_DONGGUAN_GUANSHANG_ELECTRONICS 0x1b86U // Dongguan Guanshang Electronics Co., Ltd.
+#define UHS_VID_SHENMING_ELECTRON_DONG_GUAN 0x1b88U // ShenMing Electron (Dong Guan) Co., Ltd.
+#define UHS_VID_ALTIUM_LIMITED 0x1b8cU // Altium Limited
+#define UHS_VID_E_MOVE_TECHNOLOGY 0x1b8dU // e-MOVE Technology Co., Ltd.
+#define UHS_VID_AMLOGIC 0x1b8eU // Amlogic, Inc.
+#define UHS_VID_MA_LABS 0x1b8fU // MA LABS, Inc.
+#define UHS_VID_N_TRIG 0x1b96U // N-Trig
+#define UHS_VID_YMAX_COMMUNICATIONS 0x1b98U // YMax Communications Corp.
+#define UHS_VID_SHENZHEN_YUANCHUAN_ELECTRONIC 0x1b99U // Shenzhen Yuanchuan Electronic
+#define UHS_VID_JINQ_CHERN_ENTERPRISE 0x1ba1U // JINQ CHERN ENTERPRISE CO., LTD.
+#define UHS_VID_LITE_METALS_AND_PLASTIC_SHENZHEN 0x1ba2U // Lite Metals & Plastic (Shenzhen) Co., Ltd.
+#define UHS_VID_EMBER_CORPORATION 0x1ba4U // Ember Corporation
+#define UHS_VID_ABILIS_SYSTEMS 0x1ba6U // Abilis Systems
+#define UHS_VID_CHINA_TELECOMMUNICATION_TECHNOLOGY_LABS 0x1ba8U // China Telecommunication Technology Labs
+#define UHS_VID_HARMONIX_MUSIC 0x1badU // Harmonix Music
+#define UHS_VID_VUZIX_CORPORATION 0x1baeU // Vuzix Corporation
+#define UHS_VID_T_AND_A_MOBILE_PHONES 0x1bbbU // T & A Mobile Phones
+#define UHS_VID_FORD_MOTOR 0x1bc4U // Ford Motor Co.
+#define UHS_VID_AVIXE_TECHNOLOGY_CHINA 0x1bc5U // AVIXE Technology (China) Ltd.
+#define UHS_VID_TELIT_WIRELESS_SOLUTIONS 0x1bc7U // Telit Wireless Solutions
+#define UHS_VID_CONTAC_CABLE_INDUSTRIAL_LIMITED 0x1bceU // Contac Cable Industrial Limited
+#define UHS_VID_SUNPLUS_INNOVATION_TECHNOLOGY 0x1bcfU // Sunplus Innovation Technology Inc.
+#define UHS_VID_HANGZHOU_RIYUE_ELECTRONIC 0x1bd0U // Hangzhou Riyue Electronic Co., Ltd.
+#define UHS_VID_BG_SYSTEMS 0x1bd5U // BG Systems, Inc.
+#define UHS_VID_P_TWO_INDUSTRIES 0x1bdeU // P-TWO INDUSTRIES, INC.
+#define UHS_VID_SHENZHEN_TONGYUAN_NETWORK_COMMUNICATION_CABLES 0x1befU // Shenzhen Tongyuan Network-Communication Cables Co., Ltd
+#define UHS_VID_REALVISION 0x1bf0U // RealVision Inc.
+#define UHS_VID_EXTRANET_SYSTEMS 0x1bf5U // Extranet Systems Inc.
+#define UHS_VID_ORIENT_SEMICONDUCTOR_ELECTRONICS 0x1bf6U // Orient Semiconductor Electronics, Ltd.
+#define UHS_VID_TOUCHPACK 0x1bfdU // TouchPack
+#define UHS_VID_KRETON_CORPORATION 0x1c02U // Kreton Corporation
+#define UHS_VID_QNAP_SYSTEM 0x1c04U // QNAP System Inc.
+#define UHS_VID_IONICS_EMS 0x1c0cU // Ionics EMS, Inc.
+#define UHS_VID_RELM_WIRELESS 0x1c0dU // Relm Wireless
+#define UHS_VID_LANTERRA_INDUSTRIAL 0x1c10U // Lanterra Industrial Co., Ltd.
+#define UHS_VID_ALECTRONIC_LIMITED 0x1c13U // ALECTRONIC LIMITED
+#define UHS_VID_DATEL_ELECTRONICS 0x1c1aU // Datel Electronics Ltd.
+#define UHS_VID_VOLKSWAGEN_OF_AMERICA 0x1c1bU // Volkswagen of America, Inc.
+#define UHS_VID_GOLDVISH 0x1c1fU // Goldvish S.A.
+#define UHS_VID_FUJI_ELECTRIC_DEVICE_TECHNOLOGY 0x1c20U // Fuji Electric Device Technology Co., Ltd.
+#define UHS_VID_ADDMM 0x1c21U // ADDMM LLC
+#define UHS_VID_ZHONGSHAN_CHIANG_YU_ELECTRIC 0x1c22U // ZHONGSHAN CHIANG YU ELECTRIC CO., LTD.
+#define UHS_VID_SHANGHAI_HAIYING_ELECTRONICS 0x1c26U // Shanghai Haiying Electronics Co., Ltd.
+#define UHS_VID_HUIYANG_D_AND_S_CABLE 0x1c27U // HuiYang D & S Cable Co., Ltd.
+#define UHS_VID_ELSTER 0x1c29U // Elster GmbH
+#define UHS_VID_LS_CABLE 0x1c31U // LS Cable Ltd.
+#define UHS_VID_SPRINGCARD 0x1c34U // SpringCard
+#define UHS_VID_AUTHORIZER_TECHNOLOGIES 0x1c37U // Authorizer Technologies, Inc.
+#define UHS_VID_NONIN_MEDICAL 0x1c3dU // NONIN MEDICAL INC.
+#define UHS_VID_WEP_PERIPHERALS 0x1c3eU // Wep Peripherals
+#define UHS_VID_EZPROTOTYPES 0x1c40U // EZPrototypes
+#define UHS_VID_CHERNG_WEEI_TECHNOLOGY 0x1c49U // Cherng Weei Technology Corp.
+#define UHS_VID_SIGMA_MICRO 0x1c4fU // SiGma Micro
+#define UHS_VID_PHILIPS_AND_LITE_ON_DIGITAL_SOLUTIONS_CORPORATION 0x1c6bU // Philips & Lite-ON Digital Solutions Corporation
+#define UHS_VID_SKYDIGITAL 0x1c6cU // Skydigital Inc.
+#define UHS_VID_AMT 0x1c73U // AMT
+#define UHS_VID_KAETAT_INDUSTRIAL 0x1c77U // Kaetat Industrial Co., Ltd.
+#define UHS_VID_DATASCOPE 0x1c78U // Datascope Corp.
+#define UHS_VID_UNIGEN_CORPORATION 0x1c79U // Unigen Corporation
+#define UHS_VID_LIGHTUNING_TECHNOLOGY 0x1c7aU // LighTuning Technology Inc.
+#define UHS_VID_LUXSHARE_PRECISION_INDUSTRY_SHENZHEN 0x1c7bU // LUXSHARE PRECISION INDUSTRY (SHENZHEN) CO., LTD.
+#define UHS_VID_SCHOMAECKER 0x1c83U // Schomaecker GmbH
+#define UHS_VID_2N_TELEKOMUNIKACE_AS 0x1c87U // 2N TELEKOMUNIKACE a.s.
+#define UHS_VID_SOMAGIC 0x1c88U // Somagic, Inc.
+#define UHS_VID_HONGKONG_WEIDIDA_ELECTRON_LIMITED 0x1c89U // HONGKONG WEIDIDA ELECTRON LIMITED
+#define UHS_VID_ASTRON_INTERNATIONAL 0x1c8eU // ASTRON INTERNATIONAL CORP.
+#define UHS_VID_ALPINE_ELECTRONICS 0x1c98U // ALPINE ELECTRONICS, INC.
+#define UHS_VID_OMEGA_TECHNOLOGY 0x1c9eU // OMEGA TECHNOLOGY
+#define UHS_VID_ACCARIO 0x1ca0U // ACCARIO Inc.
+#define UHS_VID_SYMWAVE 0x1ca1U // Symwave
+#define UHS_VID_KINSTONE 0x1cacU // Kinstone
+#define UHS_VID_ACES_ELECTRONIC 0x1cb3U // Aces Electronic Co., Ltd.
+#define UHS_VID_OPEX_CORPORATION 0x1cb4U // OPEX CORPORATION
+#define UHS_VID_IDEACOM_TECHNOLOGY 0x1cb6U // IdeaCom Technology Inc.
+#define UHS_VID_LUMINARY_MICRO 0x1cbeU // Luminary Micro Inc.
+#define UHS_VID_FORTAT_SKYMARK_INDUSTRIAL_COMPANY 0x1cbfU // FORTAT SKYMARK INDUSTRIAL COMPANY
+#define UHS_VID_PLANTSENSE 0x1cc0U // PlantSense
+#define UHS_VID_NEXTWAVE_BROADBAND 0x1ccaU // NextWave Broadband Inc.
+#define UHS_VID_BODATONG_TECHNOLOGY_SHENZHEN 0x1ccdU // Bodatong Technology (Shenzhen) Co., Ltd.
+#define UHS_VID_ADP_CORPORATION 0x1cd4U // adp corporation
+#define UHS_VID_FIRECOMMS 0x1cd5U // Firecomms Ltd.
+#define UHS_VID_ANTONIO_PRECISE_PRODUCTS_MANUFACTORY 0x1cd6U // Antonio Precise Products Manufactory Ltd.
+#define UHS_VID_TELECOMMUNICATIONS_TECHNOLOGY_ASSOCIATION_TTA 0x1cdeU // Telecommunications Technology Association (TTA)
+#define UHS_VID_WONTEN_TECHNOLOGY 0x1cdfU // WonTen Technology Co., Ltd.
+#define UHS_VID_EDIMAX_TECHNOLOGY 0x1ce0U // EDIMAX TECHNOLOGY CO., LTD.
+#define UHS_VID_AMPHENOL_KAE 0x1ce1U // Amphenol KAE
+#define UHS_VID_DRESDEN_ELEKTRONIK 0x1cf1U // Dresden Elektronik
+#define UHS_VID_ANDES_TECHNOLOGY_CORPORATION 0x1cfcU // ANDES TECHNOLOGY CORPORATION
+#define UHS_VID_FLEXTRONICS_DIGITAL_DESIGN_JAPAN 0x1cfdU // Flextronics Digital Design Japan, LTD.
+#define UHS_VID_ICON 0x1d03U // iCON
+#define UHS_VID_SOLID_MOTION 0x1d07U // Solid-Motion
+#define UHS_VID_NINGBO_HENTEK_DRAGON_ELECTRONICS 0x1d08U // NINGBO HENTEK DRAGON ELECTRONICS CO., LTD.
+#define UHS_VID_TECHFAITH_WIRELESS_TECHNOLOGY_LIMITED 0x1d09U // TechFaith Wireless Technology Limited
+#define UHS_VID_JOHNSON_CONTROLS_INC_THE_AUTOMOTIVE_BUSINESS_UNIT 0x1d0aU // Johnson Controls, Inc. The Automotive Business Unit
+#define UHS_VID_HAN_HUA_CABLE_AND_WIRE_TECHNOLOGY_JX 0x1d0bU // HAN HUA CABLE & WIRE TECHNOLOGY (J.X.) CO., LTD.
+#define UHS_VID_SONIX_TECHNOLOGY 0x1d0fU // Sonix Technology Co., Ltd.
+#define UHS_VID_ALPHA_SAT_TECHNOLOGY_LIMITED 0x1d14U // ALPHA-SAT TECHNOLOGY LIMITED
+#define UHS_VID_C_THRU_MUSIC 0x1d17U // C-Thru Music Ltd.
+#define UHS_VID_DEXATEK_TECHNOLOGY 0x1d19U // Dexatek Technology Ltd.
+#define UHS_VID_DIOSTECH 0x1d1fU // Diostech Co., Ltd.
+#define UHS_VID_SAMTACK 0x1d20U // SAMTACK INC.
+#define UHS_VID_ASUS 0x1d27U // ASUS
+#define UHS_VID_DREAM_CHEEKY 0x1d34U // Dream Cheeky
+#define UHS_VID_TOUCH 0x1d45U // Touch
+#define UHS_VID_PEGATRON_CORPORATION 0x1d4dU // PEGATRON CORPORATION
+#define UHS_VID_OPENMOKO 0x1d50U // OpenMoko, Inc.
+#define UHS_VID_XENTA 0x1d57U // Xenta
+#define UHS_VID_SMARTRONIX 0x1d5bU // Smartronix, Inc.
+#define UHS_VID_LINUX_FOUNDATION 0x1d6bU // Linux Foundation
+#define UHS_VID_CITIZEN 0x1d90U // Citizen
+#define UHS_VID_ACTIONS_MICROELECTRONICS 0x1de1U // Actions Microelectronics Co.
+#define UHS_VID_QUALCOMM_OPTION 0x1e0eU // Qualcomm / Option
+#define UHS_VID_POINT_GREY_RESEARCH 0x1e10U // Point Grey Research, Inc.
+#define UHS_VID_MIRION_TECHNOLOGIES_DOSIMETRY_SERVICES_DIVISION 0x1e17U // Mirion Technologies Dosimetry Services Division
+#define UHS_VID_LUMENSION_SECURITY 0x1e1dU // Lumension Security
+#define UHS_VID_INVIA 0x1e1fU // INVIA
+#define UHS_VID_FESTO_AG_AND_CO_KG 0x1e29U // Festo AG & Co. KG
+#define UHS_VID_CHIPSBANK_MICROELECTRONICS_1 0x1e3dU // Chipsbank Microelectronics Co., Ltd
+#define UHS_VID_CLEVERSCOPE 0x1e41U // Cleverscope
+#define UHS_VID_CUBETERNET 0x1e4eU // Cubeternet
+#define UHS_VID_TYPEMATRIX 0x1e54U // TypeMatrix
+#define UHS_VID_TREKSTOR_GMBH_AND_CO_KG 0x1e68U // TrekStor GmbH & Co. KG
+#define UHS_VID_NZXT 0x1e71U // NZXT
+#define UHS_VID_COBY_ELECTRONICS_CORPORATION 0x1e74U // Coby Electronics Corporation
+#define UHS_VID_ROCCAT 0x1e7dU // ROCCAT
+#define UHS_VID_NUCORE_TECHNOLOGY 0x1ebbU // NuCORE Technology, Inc.
+#define UHS_VID_AIRTIES_WIRELESS_NETWORKS 0x1edaU // AirTies Wireless Networks
+#define UHS_VID_BLACKMAGIC_DESIGN 0x1edbU // Blackmagic design
+#define UHS_VID_ONDA_COMMUNICATION_SPA 0x1ee8U // ONDA COMMUNICATION S.p.a.
+#define UHS_VID_EADS_DEUTSCHLAND 0x1ef6U // EADS Deutschland GmbH
+#define UHS_VID_CAL_COMP 0x1f28U // Cal-Comp
+#define UHS_VID_ONDA_UNVERIFIED 0x1f3aU // Onda (unverified)
+#define UHS_VID_THE_NEAT_COMPANY 0x1f44U // The Neat Company
+#define UHS_VID_H_TRONIC 0x1f48U // H-TRONIC GmbH
+#define UHS_VID_G_TEK_ELECTRONICS_GROUP 0x1f4dU // G-Tek Electronics Group
+#define UHS_VID_ALIPH 0x1f6fU // Aliph
+#define UHS_VID_INNOSTOR_TECHNOLOGY_CORPORATION 0x1f75U // Innostor Technology Corporation
+#define UHS_VID_TANDBERG 0x1f82U // TANDBERG
+#define UHS_VID_ALERE 0x1f84U // Alere, Inc.
+#define UHS_VID_STANTUM 0x1f87U // Stantum
+#define UHS_VID_UBIQUITI_NETWORKS 0x1f9bU // Ubiquiti Networks, Inc.
+#define UHS_VID_SAMSUNG_OPTO_ELECTRONCS 0x1fabU // Samsung Opto-Electroncs Co., Ltd.
+#define UHS_VID_DELPHIN_TECHNOLOGY_AG 0x1fbdU // Delphin Technology AG
+#define UHS_VID_NXP_SEMICONDUCTORS 0x1fc9U // NXP Semiconductors
+#define UHS_VID_ILX_LIGHTWAVE_CORPORATION 0x1fdeU // ILX Lightwave Corporation
+#define UHS_VID_VERTEX_WIRELESS 0x1fe7U // Vertex Wireless Co., Ltd.
+#define UHS_VID_CVT_ELECTRONICSCOLTD 0x1ff7U // CVT Electronics.Co.,Ltd
+#define UHS_VID_IDEOFY 0x1fffU // Ideofy Inc.
+#define UHS_VID_D_LINK 0x2001U // D-Link Corp.
+#define UHS_VID_DAP_TECHNOLOGIES 0x2002U // DAP Technologies
+#define UHS_VID_DETECTOMAT 0x2003U // detectomat
+#define UHS_VID_RELOOP 0x200cU // Reloop
+#define UHS_VID_PCTV_SYSTEMS 0x2013U // PCTV Systems
+#define UHS_VID_PLANEX_1 0x2019U // PLANEX
+#define UHS_VID_ENCORE_ELECTRONICS 0x203dU // Encore Electronics Inc.
+#define UHS_VID_HAUPPAUGE 0x2040U // Hauppauge
+#define UHS_VID_TEXAS_INSTRUMENTS_2 0x2047U // Texas Instruments
+#define UHS_VID_NANO_RIVER_TECHNOLOGY 0x2058U // Nano River Technology
+#define UHS_VID_TAICANG_TANDW_ELECTRONICS 0x2077U // Taicang T&W Electronics Co. Ltd
+#define UHS_VID_BARNES_AND_NOBLE 0x2080U // Barnes & Noble
+#define UHS_VID_SIMPASS 0x2086U // SIMPASS
+#define UHS_VID_CANDO 0x2087U // Cando
+#define UHS_VID_CLAY_LOGIC 0x20a0U // Clay Logic
+#define UHS_VID_XMOS 0x20b1U // XMOS Ltd
+#define UHS_VID_HANVON 0x20b3U // Hanvon
+#define UHS_VID_QI_HARDWARE 0x20b7U // Qi Hardware
+#define UHS_VID_MINICIRCUITS 0x20ceU // Minicircuits
+#define UHS_VID_SIMTEC_ELECTRONICS 0x20dfU // Simtec Electronics
+#define UHS_VID_NET_NEW_ELECTRONIC_TECHNOLOGY 0x20f1U // NET New Electronic Technology GmbH
+#define UHS_VID_TRENDNET_1 0x20f4U // TRENDnet
+#define UHS_VID_XIMEA 0x20f7U // XIMEA
+#define UHS_VID_RT_SYSTEMS 0x2100U // RT Systems
+#define UHS_VID_ACTIONSTAR 0x2101U // ActionStar
+#define UHS_VID_VIA_LABS 0x2109U // VIA Labs, Inc.
+#define UHS_VID_SOFTKINETIC 0x2113U // Softkinetic
+#define UHS_VID_ADVANCED_SILICON 0x2149U // Advanced Silicon S.A.
+#define UHS_VID_CREATIVE_UNKNOWN 0x2162U // Creative (?)
+#define UHS_VID_GW_INSTEK 0x2184U // GW Instek
+#define UHS_VID_EMOTIV_SYSTEMS_PTY 0x21a1U // Emotiv Systems Pty. Ltd.
+#define UHS_VID_AGECODAGIS_SARL 0x21d6U // Agecodagis SARL
+#define UHS_VID_MACALLY_1 0x2222U // MacAlly
+#define UHS_VID_SAMWOO_ENTERPRISE 0x2227U // SAMWOO Enterprise
+#define UHS_VID_SILICON_MOTION_1 0x2232U // Silicon Motion
+#define UHS_VID_RADIOSHACK_CORPORATION 0x2233U // RadioShack Corporation
+#define UHS_VID_KOBO 0x2237U // Kobo Inc.
+#define UHS_VID_MORPHO 0x225dU // Morpho
+#define UHS_VID_8D_TECHNOLOGIES 0x228dU // 8D Technologies inc.
+#define UHS_VID_PIE_DIGITAL 0x22a6U // Pie Digital, Inc.
+#define UHS_VID_MOTOROLA_PCS 0x22b8U // Motorola PCS
+#define UHS_VID_ETURBOTOUCH_TECHNOLOGY 0x22b9U // eTurboTouch Technology, Inc.
+#define UHS_VID_TECHNOLOGY_INNOVATION_HOLDINGS 0x22baU // Technology Innovation Holdings, Ltd
+#define UHS_VID_PINNACLE_SYSTEMS_1 0x2304U // Pinnacle Systems, Inc.
+#define UHS_VID_SHINING_TECHNOLOGIES_INC_HEX_ 0x2318U // Shining Technologies, Inc. [hex]
+#define UHS_VID_ARDUINO 0x2341U // Arduino SA
+#define UHS_VID_PUMATRONIX_LTDA 0x2373U // Pumatronix Ltda
+#define UHS_VID_DIGITALWAY_1 0x2375U // Digit@lway, Inc.
+#define UHS_VID_SANHO_DIGITAL_ELECTRONICS 0x2406U // SANHO Digital Electronics Co., Ltd.
+#define UHS_VID_AESSENT_TECHNOLOGY 0x2443U // Aessent Technology Ltd
+#define UHS_VID_TRIPP_LITE_1 0x2478U // Tripp-Lite
+#define UHS_VID_MAXXTER 0x248aU // Maxxter
+#define UHS_VID_M2TECH_SRL 0x249cU // M2Tech s.r.l.
+#define UHS_VID_PARATRONIC 0x24e1U // Paratronic
+#define UHS_VID_TWINMOS_1 0x2632U // TwinMOS
+#define UHS_VID_XSENS 0x2639U // Xsens
+#define UHS_VID_ELECTRONICS_FOR_IMAGING_INC_HEX_ 0x2650U // Electronics For Imaging, Inc. [hex]
+#define UHS_VID_SUNDTEK 0x2659U // Sundtek
+#define UHS_VID_BASLER_AG 0x2676U // Basler AG
+#define UHS_VID_CITIZEN_1 0x2730U // Citizen
+#define UHS_VID_DIGITALWAY_2 0x2735U // DigitalWay
+#define UHS_VID_NHJ 0x2770U // NHJ, Ltd
+#define UHS_VID_THINGM 0x27b8U // ThingM
+#define UHS_VID_ASUSTEK_COMPUTER_1 0x2821U // ASUSTek Computer Inc.
+#define UHS_VID_TOPTRONIC_INDUSTRIAL 0x2899U // Toptronic Industrial Co., Ltd
+#define UHS_VID_DRACALRAPHNET_TECHNOLOGIES 0x289bU // Dracal/Raphnet technologies
+#define UHS_VID_JOLLA_OY 0x2931U // Jolla Oy
+#define UHS_VID_DOG_HUNTER_AG 0x2a03U // dog hunter AG
+#define UHS_VID_RTD_EMBEDDED_TECHNOLOGIES 0x2a37U // RTD Embedded Technologies, Inc.
+#define UHS_VID_MEIZU 0x2a45U // Meizu Corp.
+#define UHS_VID_PLANEX_COMMUNICATIONS_2 0x2c02U // Planex Communications
+#define UHS_VID_DOLPHIN_PERIPHERALS 0x2c1aU // Dolphin Peripherals
+#define UHS_VID_FUJITSU_1 0x2fb2U // Fujitsu, Ltd
+#define UHS_VID_EAGLETRON_1 0x3125U // Eagletron
+#define UHS_VID_NAVINI_NETWORKS 0x3136U // Navini Networks
+#define UHS_VID_WHANAM_ELECTRONICS 0x3176U // Whanam Electronics Co., Ltd
+#define UHS_VID_LINK_INSTRUMENTS 0x3195U // Link Instruments
+#define UHS_VID_VIDZMEDIA_PTE 0x3275U // VidzMedia Pte Ltd
+#define UHS_VID_INLINE 0x3333U // InLine
+#define UHS_VID_AEI 0x3334U // AEI
+#define UHS_VID_YAKUMO 0x3340U // Yakumo
+#define UHS_VID_LEAGUER_MICROELECTRONICS_LME 0x3344U // Leaguer Microelectronics (LME)
+#define UHS_VID_MICRO_STAR 0x3504U // Micro Star
+#define UHS_VID_POWER_QUOTIENT_INTERNATIONAL_1 0x3538U // Power Quotient International Co., Ltd
+#define UHS_VID_DIVA 0x3579U // DIVA
+#define UHS_VID_SHARKOON 0x357dU // Sharkoon
+#define UHS_VID_INVIBRO 0x3636U // InVibro
+#define UHS_VID_WEM 0x3838U // WEM
+#define UHS_VID_NATIONAL_INSTRUMENTS 0x3923U // National Instruments Corp.
+#define UHS_VID_I_O_DATA 0x40bbU // I-O Data
+#define UHS_VID_I_ROCKS 0x4101U // i-rocks
+#define UHS_VID_IRIVER_1 0x4102U // iRiver, Ltd.
+#define UHS_VID_DELL_COMPUTER_1 0x413cU // Dell Computer Corp.
+#define UHS_VID_USBEST_TECHNOLOGY 0x4146U // USBest Technology
+#define UHS_VID_TARGUS 0x4168U // Targus
+#define UHS_VID_USB_DESIGN_BY_EXAMPLE 0x4242U // USB Design by Example
+#define UHS_VID_GOPRO 0x4255U // GoPro
+#define UHS_VID_BROADCOM_1 0x4317U // Broadcom Corp.
+#define UHS_VID_WINCHIPHEAD 0x4348U // WinChipHead
+#define UHS_VID_SHUTTLE_2 0x4572U // Shuttle, Inc.
+#define UHS_VID_PANRAM 0x4586U // Panram
+#define UHS_VID_EMS_PRODUCTION 0x4670U // EMS Production
+#define UHS_VID_MIDITECH 0x4752U // Miditech
+#define UHS_VID_GW_INSTEK_1 0x4757U // GW Instek
+#define UHS_VID_ACEECA 0x4766U // Aceeca
+#define UHS_VID_MEMOREX 0x4855U // Memorex
+#define UHS_VID_SIMPLETECH 0x4971U // SimpleTech
+#define UHS_VID_MUSICAL_FIDELITY 0x4d46U // Musical Fidelity
+#define UHS_VID_GRANDTEC 0x5032U // Grandtec
+#define UHS_VID_LINKSYS_UNKNOWN 0x5041U // Linksys (?)
+#define UHS_VID_AVERATEC_UNKNOWN 0x50c2U // Averatec (?)
+#define UHS_VID_SWEEX_1 0x5173U // Sweex
+#define UHS_VID_I_TETRA 0x5219U // I-Tetra
+#define UHS_VID_OWON 0x5345U // Owon
+#define UHS_VID_SATOSHILABS 0x534cU // SatoshiLabs
+#define UHS_VID_MEYER_INSTRUMENTS_MIS_1 0x5354U // Meyer Instruments (MIS)
+#define UHS_VID_TRANSMETA 0x544dU // Transmeta Corp.
+#define UHS_VID_UC_LOGIC_TECHNOLOGY 0x5543U // UC-Logic Technology Corp.
+#define UHS_VID_EPIPHAN_SYSTEMS 0x5555U // Epiphan Systems Inc.
+#define UHS_VID_ONSPEC_ELECTRONIC 0x55aaU // OnSpec Electronic, Inc.
+#define UHS_VID_GOTVIEW 0x5654U // Gotview
+#define UHS_VID_UNI_TREND_GROUP_LIMITED 0x5656U // Uni-Trend Group Limited
+#define UHS_VID_IRTOUCHSYSTEMS 0x595aU // IRTOUCHSYSTEMS Co. Ltd.
+#define UHS_VID_ACER_2 0x5986U // Acer, Inc
+#define UHS_VID_NONOLITH_LABS 0x59e3U // Nonolith Labs
+#define UHS_VID_ZINWELL 0x5a57U // Zinwell
+#define UHS_VID_BEHOLDER_INTERNATIONAL 0x6000U // Beholder International Ltd.
+#define UHS_VID_INGENIC_SEMICONDUCTOR 0x601aU // Ingenic Semiconductor Ltd.
+#define UHS_VID_SITECOM 0x6189U // Sitecom
+#define UHS_VID_LIGHTINGSOFT_AG 0x6244U // LightingSoft AG
+#define UHS_VID_TWINHAN_TECHNOLOGY 0x6253U // TwinHan Technology Co., Ltd
+#define UHS_VID_CORELOGIC 0x636cU // CoreLogic, Inc.
+#define UHS_VID_UNKNOWN_SONY_UNKNOWN 0x6472U // Unknown (Sony?)
+#define UHS_VID_ARKMICRO_TECHNOLOGIES_1 0x6547U // Arkmicro Technologies Inc.
+#define UHS_VID_IRTOUCHSYSTEMS_1 0x6615U // IRTOUCHSYSTEMS Co. Ltd.
+#define UHS_VID_PROTOTYPE_PRODUCT_VENDOR_ID 0x6666U // Prototype product Vendor ID
+#define UHS_VID_WISEGROUP 0x6677U // WiseGroup, Ltd.
+#define UHS_VID_3COM_1 0x6891U // 3Com
+#define UHS_VID_OPERA1 0x695cU // Opera1
+#define UHS_VID_YEALINK_NETWORK_TECHNOLOGY 0x6993U // Yealink Network Technology Co., Ltd.
+#define UHS_VID_SHANGHAI_JUJO_ELECTRONICS 0x6a75U // Shanghai Jujo Electronics Co., Ltd
+#define UHS_VID_CME_CENTRAL_MUSIC 0x7104U // CME (Central Music Co.)
+#define UHS_VID_STACKFOUNDRY 0x726cU // StackFoundry LLC
+#define UHS_VID_TBS_TECHNOLOGIES_CHINA 0x734cU // TBS Technologies China
+#define UHS_VID_BEIJING_STONE_TECHNOLOGY 0x7373U // Beijing STONE Technology Co. Ltd.
+#define UHS_VID_EDIMAX_TECHNOLOGY_1 0x7392U // Edimax Technology Co., Ltd
+#define UHS_VID_INTEL_1 0x8086U // Intel Corp.
+#define UHS_VID_INTEL_2 0x8087U // Intel Corp.
+#define UHS_VID_VIRTUALBOX 0x80eeU // VirtualBox
+#define UHS_VID_KEIO 0x8282U // Keio
+#define UHS_VID_EGO_SYSTEMS_1 0x8341U // EGO Systems, Inc.
+#define UHS_VID_TRANSCEND_INFORMATION_1 0x8564U // Transcend Information, Inc.
+#define UHS_VID_INTENSO_GMBG 0x8644U // Intenso GmbG
+#define UHS_VID_CH_PRODUCTS_1 0x8e06U // CH Products, Inc.
+#define UHS_VID_SITECOM_1 0x9016U // Sitecom
+#define UHS_VID_TEVII_TECHNOLOGY 0x9022U // TeVii Technology Ltd.
+#define UHS_VID_GEOLAB 0x9148U // GeoLab, Ltd
+#define UHS_VID_MOSCHIP_SEMICONDUCTOR 0x9710U // MosChip Semiconductor
+#define UHS_VID_BESTMEDIA_CD_RECORDABLE_GMBH_AND_CO_KG 0x9849U // Bestmedia CD Recordable GmbH & Co. KG
+#define UHS_VID_ODEON 0x9999U // Odeon
+#define UHS_VID_GRANDTEC_1 0x99faU // Grandtec
+#define UHS_VID_J_WESTHUES 0x9ac4U // J. Westhues
+#define UHS_VID_MARVELL_SEMICONDUCTOR_1 0x9e88U // Marvell Semiconductor, Inc.
+#define UHS_VID_ANMO_ELECTRONICS_CORP_DINO_LITE_UNKNOWN 0xa128U // AnMo Electronics Corp. / Dino-Lite (?)
+#define UHS_VID_ANMO_ELECTRONICS_CORPORATION 0xa168U // AnMo Electronics Corporation
+#define UHS_VID_ASIX 0xa600U // Asix
+#define UHS_VID_3COM_2 0xa727U // 3Com
+#define UHS_VID_MXT 0xaaaaU // MXT
+#define UHS_VID_UNKNOWN_3 0xabcdU // Unknown
+#define UHS_VID_BLUE_MICROPHONES 0xb58eU // Blue Microphones
+#define UHS_VID_CARD_DEVICE_EXPERT 0xc216U // Card Device Expert Co., LTD
+#define UHS_VID_KEIL_SOFTWARE_1 0xc251U // Keil Software, Inc.
+#define UHS_VID_CACE_TECHNOLOGIES 0xcaceU // CACE Technologies Inc.
+#define UHS_VID_SMART_TECHNOLOGY_INDUSTRIAL 0xcd12U // SMART TECHNOLOGY INDUSTRIAL LTD.
+#define UHS_VID_ULTIMARC 0xd208U // Ultimarc
+#define UHS_VID_ULTIMARC_1 0xd209U // Ultimarc
+#define UHS_VID_LOGILINK 0xd904U // LogiLink
+#define UHS_VID_XORCOM 0xe4e4U // Xorcom Ltd.
+#define UHS_VID_MAKINGTHINGS 0xeb03U // MakingThings
+#define UHS_VID_EMPIA_TECHNOLOGY 0xeb1aU // eMPIA Technology, Inc.
+#define UHS_VID_KWORLD 0xeb2aU // KWorld
+#define UHS_VID_SMART_TECHNOLOGY_INDUSTRIAL_1 0xef18U // SMART TECHNOLOGY INDUSTRIAL LTD.
+#define UHS_VID_HEWLETT_PACKARD_1 0xf003U // Hewlett Packard
+#define UHS_VID_LEAP_MOTION 0xf182U // Leap Motion
+#define UHS_VID_ATTEN_ELECTRONICS_SIGLENT_TECHNOLOGIES 0xf4ecU // Atten Electronics / Siglent Technologies
+#define UHS_VID_SHENZHEN_SIGLENT 0xf4edU // Shenzhen Siglent Co., Ltd.
+#define UHS_VID_HAMA_1 0xf766U // Hama
+#define UHS_VID_CONRAD_ELECTRONIC_SE 0xfc08U // Conrad Electronic SE
+#define UHS_VID_FNK_TECH 0xffeeU // FNK Tech
+
+#endif
diff --git a/Marlin/src/sd/usb_flashdrive/lib-uhs3/UHS_host/UHS_UsbCore.h b/Marlin/src/sd/usb_flashdrive/lib-uhs3/UHS_host/UHS_UsbCore.h
new file mode 100644
index 0000000..1591f3b
--- /dev/null
+++ b/Marlin/src/sd/usb_flashdrive/lib-uhs3/UHS_host/UHS_UsbCore.h
@@ -0,0 +1,336 @@
+/* Copyright (C) 2015-2016 Andrew J. Kroll
+ and
+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 : https://www.circuitsathome.com
+e-mail : support@circuitsathome.com
+ */
+
+#if !defined(_UHS_host_h_) || defined(USBCORE_H)
+#error "Never include UHS_UsbCore.h directly; include UHS_Host.h instead"
+#else
+#define USBCORE_H
+
+#ifndef UHS_HOST_MAX_INTERFACE_DRIVERS
+#define UHS_HOST_MAX_INTERFACE_DRIVERS 0x10U // Default maximum number of USB interface drivers
+#endif
+
+#ifndef SYSTEM_OR_SPECIAL_YIELD
+#define SYSTEM_OR_SPECIAL_YIELD(...) VOID0
+#endif
+
+#ifndef SYSTEM_OR_SPECIAL_YIELD_FROM_ISR
+#define SYSTEM_OR_SPECIAL_YIELD_FROM_ISR(...) SYSTEM_OR_SPECIAL_YIELD
+#endif
+
+// As we make extensions to a target interface add to UHS_HOST_MAX_INTERFACE_DRIVERS
+// This offset gets calculated for supporting wide subclasses, such as HID, BT, etc.
+#define UHS_HID_INDEX (UHS_HOST_MAX_INTERFACE_DRIVERS + 1)
+
+/* Common setup data constant combinations */
+//get descriptor request type
+#define UHS_bmREQ_GET_DESCR (USB_SETUP_DEVICE_TO_HOST|USB_SETUP_TYPE_STANDARD|USB_SETUP_RECIPIENT_DEVICE)
+
+//set request type for all but 'set feature' and 'set interface'
+#define UHS_bmREQ_SET (USB_SETUP_HOST_TO_DEVICE|USB_SETUP_TYPE_STANDARD|USB_SETUP_RECIPIENT_DEVICE)
+
+//get interface request type
+#define UHS_bmREQ_CL_GET_INTF (USB_SETUP_DEVICE_TO_HOST|USB_SETUP_TYPE_CLASS|USB_SETUP_RECIPIENT_INTERFACE)
+
+// 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)
+
+
+// TO-DO: Use the python script to generate these.
+// TO-DO: Add _all_ subclasses here.
+// USB Device Classes, Subclasses and Protocols
+////////////////////////////////////////////////////////////////////////////////
+// Use Class Info in the Interface Descriptors
+#define UHS_USB_CLASS_USE_CLASS_INFO 0x00U
+
+////////////////////////////////////////////////////////////////////////////////
+// Audio
+#define UHS_USB_CLASS_AUDIO 0x01U
+// Subclasses
+#define UHS_USB_SUBCLASS_AUDIOCONTROL 0x01U
+#define UHS_USB_SUBCLASS_AUDIOSTREAMING 0x02U
+#define UHS_USB_SUBCLASS_MIDISTREAMING 0x03U
+
+////////////////////////////////////////////////////////////////////////////////
+// Communications and CDC Control
+#define UHS_USB_CLASS_COM_AND_CDC_CTRL 0x02U
+
+////////////////////////////////////////////////////////////////////////////////
+// HID
+#define UHS_USB_CLASS_HID 0x03U
+// Subclasses
+#define UHS_HID_BOOT_SUBCLASS 0x01U
+// Protocols
+#define UHS_HID_PROTOCOL_HIDBOOT_KEYBOARD 0x01U
+#define UHS_HID_PROTOCOL_HIDBOOT_MOUSE 0x02U
+////////////////////////////////////////////////////////////////////////////////
+// Physical
+#define UHS_USB_CLASS_PHYSICAL 0x05U
+
+////////////////////////////////////////////////////////////////////////////////
+// Image
+#define UHS_USB_CLASS_IMAGE 0x06U
+
+////////////////////////////////////////////////////////////////////////////////
+// Printer
+#define UHS_USB_CLASS_PRINTER 0x07U
+
+////////////////////////////////////////////////////////////////////////////////
+// Mass Storage
+#define UHS_USB_CLASS_MASS_STORAGE 0x08
+// Subclasses
+#define UHS_BULK_SUBCLASS_SCSI_NOT_REPORTED 0x00U // De facto use
+#define UHS_BULK_SUBCLASS_RBC 0x01U
+#define UHS_BULK_SUBCLASS_ATAPI 0x02U // MMC-5 (ATAPI)
+#define UHS_BULK_SUBCLASS_OBSOLETE1 0x03U // Was QIC-157
+#define UHS_BULK_SUBCLASS_UFI 0x04U // Specifies how to interface Floppy Disk Drives to USB
+#define UHS_BULK_SUBCLASS_OBSOLETE2 0x05U // Was SFF-8070i
+#define UHS_BULK_SUBCLASS_SCSI 0x06U // SCSI Transparent Command Set
+#define UHS_BULK_SUBCLASS_LSDFS 0x07U // Specifies how host has to negotiate access before trying SCSI
+#define UHS_BULK_SUBCLASS_IEEE1667 0x08U
+// Protocols
+#define UHS_STOR_PROTO_CBI 0x00U // CBI (with command completion interrupt)
+#define UHS_STOR_PROTO_CBI_NO_INT 0x01U // CBI (without command completion interrupt)
+#define UHS_STOR_PROTO_OBSOLETE 0x02U
+#define UHS_STOR_PROTO_BBB 0x50U // Bulk Only Transport
+#define UHS_STOR_PROTO_UAS 0x62U
+
+////////////////////////////////////////////////////////////////////////////////
+// Hub
+#define UHS_USB_CLASS_HUB 0x09U
+
+////////////////////////////////////////////////////////////////////////////////
+// CDC-Data
+#define UHS_USB_CLASS_CDC_DATA 0x0AU
+
+////////////////////////////////////////////////////////////////////////////////
+// Smart-Card
+#define UHS_USB_CLASS_SMART_CARD 0x0BU
+
+////////////////////////////////////////////////////////////////////////////////
+// Content Security
+#define UHS_USB_CLASS_CONTENT_SECURITY 0x0DU
+
+////////////////////////////////////////////////////////////////////////////////
+// Video
+#define UHS_USB_CLASS_VIDEO 0x0EU
+
+////////////////////////////////////////////////////////////////////////////////
+// Personal Healthcare
+#define UHS_USB_CLASS_PERSONAL_HEALTH 0x0FU
+
+////////////////////////////////////////////////////////////////////////////////
+// Diagnostic Device
+#define UHS_USB_CLASS_DIAGNOSTIC_DEVICE 0xDCU
+
+////////////////////////////////////////////////////////////////////////////////
+// Wireless Controller
+#define UHS_USB_CLASS_WIRELESS_CTRL 0xE0U
+
+////////////////////////////////////////////////////////////////////////////////
+// Miscellaneous
+#define UHS_USB_CLASS_MISC 0xEFU
+
+////////////////////////////////////////////////////////////////////////////////
+// Application Specific
+#define UHS_USB_CLASS_APP_SPECIFIC 0xFEU
+
+////////////////////////////////////////////////////////////////////////////////
+// Vendor Specific
+#define UHS_USB_CLASS_VENDOR_SPECIFIC 0xFFU
+
+////////////////////////////////////////////////////////////////////////////////
+
+
+/* USB state machine states */
+#define UHS_USB_HOST_STATE_MASK 0xF0U
+
+// Configure states, MSN == 0 --------------------------V
+#define UHS_USB_HOST_STATE_DETACHED 0x00U
+#define UHS_USB_HOST_STATE_DEBOUNCE 0x01U
+#define UHS_USB_HOST_STATE_DEBOUNCE_NOT_COMPLETE 0x02U
+#define UHS_USB_HOST_STATE_RESET_NOT_COMPLETE 0x03U
+#define UHS_USB_HOST_STATE_WAIT_SOF 0x04U
+#define UHS_USB_HOST_STATE_WAIT_BUS_READY 0x05U
+#define UHS_USB_HOST_STATE_RESET_DEVICE 0x0AU
+#define UHS_USB_HOST_STATE_CONFIGURING 0x0CU // Looks like "CO"nfig (backwards)
+#define UHS_USB_HOST_STATE_CONFIGURING_DONE 0x0DU // Looks like "DO"one (backwards)
+#define UHS_USB_HOST_STATE_CHECK 0x0EU
+#define UHS_USB_HOST_STATE_ILLEGAL 0x0FU // Foo
+
+// Run states, MSN != 0 --------------------------------V
+#define UHS_USB_HOST_STATE_RUNNING 0x60U // Looks like "GO"
+#define UHS_USB_HOST_STATE_IDLE 0x1DU // Looks like "ID"le
+#define UHS_USB_HOST_STATE_ERROR 0xF0U // Looks like "FO"o
+#define UHS_USB_HOST_STATE_INITIALIZE 0x10U // Looks like "I"nit
+
+// Host SE result codes.
+// Common SE results are stored in the low nybble, all interface drivers understand these plus 0x1F.
+// Extended SE results are 0x10-0x1E. SE code only understands these internal to the hardware.
+// Values > 0x1F are driver or other internal error conditions.
+// Return these result codes from your host controller driver to match the error condition
+// ALL Non-zero values are errors.
+// Values not listed in this table are not handled in the base class, or any host driver.
+
+#define UHS_HOST_ERROR_NONE 0x00U // No error
+#define UHS_HOST_ERROR_BUSY 0x01U // transfer pending
+#define UHS_HOST_ERROR_BADREQ 0x02U // Transfer Launch Request was bad
+#define UHS_HOST_ERROR_DMA 0x03U // DMA was too short, or too long
+#define UHS_HOST_ERROR_NAK 0x04U // Peripheral returned NAK
+#define UHS_HOST_ERROR_STALL 0x05U // Peripheral returned STALL
+#define UHS_HOST_ERROR_TOGERR 0x06U // Toggle error/ISO over-underrun
+#define UHS_HOST_ERROR_WRONGPID 0x07U // Received wrong Packet ID
+#define UHS_HOST_ERROR_BADBC 0x08U // Byte count is bad
+#define UHS_HOST_ERROR_PIDERR 0x09U // Received Packet ID is corrupted
+#define UHS_HOST_ERROR_BADRQ 0x0AU // Packet error. Increase max packet.
+#define UHS_HOST_ERROR_CRC 0x0BU // USB CRC was incorrect
+#define UHS_HOST_ERROR_KERR 0x0CU // K-state instead of response, usually indicates wrong speed
+#define UHS_HOST_ERROR_JERR 0x0DU // J-state instead of response, usually indicates wrong speed
+#define UHS_HOST_ERROR_TIMEOUT 0x0EU // Device did not respond in time
+#define UHS_HOST_ERROR_BABBLE 0x0FU // Line noise/unexpected data
+#define UHS_HOST_ERROR_MEM_LAT 0x10U // Error caused by memory latency.
+#define UHS_HOST_ERROR_NYET 0x11U // OUT transfer accepted with NYET
+
+// Addressing error codes
+#define ADDR_ERROR_INVALID_INDEX 0xA0U
+#define ADDR_ERROR_INVALID_ADDRESS 0xA1U
+
+// Common Interface Driver error codes
+#define UHS_HOST_ERROR_DEVICE_NOT_SUPPORTED 0xD1U // Driver doesn't support the device or interfaces
+#define UHS_HOST_ERROR_DEVICE_INIT_INCOMPLETE 0xD2U // Init partially finished, but died.
+#define UHS_HOST_ERROR_CANT_REGISTER_DEVICE_CLASS 0xD3U // There was no driver for the interface requested.
+#define UHS_HOST_ERROR_ADDRESS_POOL_FULL 0xD4U // No addresses left in the address pool.
+#define UHS_HOST_ERROR_HUB_ADDRESS_OVERFLOW 0xD5U // No hub addresses left. The maximum is 7.
+#define UHS_HOST_ERROR_NO_ADDRESS_IN_POOL 0xD6U // Address was not allocated in the pool, thus not found.
+#define UHS_HOST_ERROR_NULL_EPINFO 0xD7U // The supplied endpoint was NULL, indicates a bug or other problem.
+#define UHS_HOST_ERROR_BAD_ARGUMENT 0xD8U // Indicates a range violation bug.
+#define UHS_HOST_ERROR_DEVICE_DRIVER_BUSY 0xD9U // The interface driver is busy or out buffer is full, try again later.
+#define UHS_HOST_ERROR_BAD_MAX_PACKET_SIZE 0xDAU // The maximum packet size was exceeded. Try again with smaller size.
+#define UHS_HOST_ERROR_NO_ENDPOINT_IN_TABLE 0xDBU // The endpoint could not be found in the endpoint table.
+#define UHS_HOST_ERROR_UNPLUGGED 0xDEU // Someone removed the USB device, or Vbus was turned off.
+#define UHS_HOST_ERROR_NOMEM 0xDFU // Out Of Memory.
+
+// Control request stream errors
+#define UHS_HOST_ERROR_FailGetDevDescr 0xE1U
+#define UHS_HOST_ERROR_FailSetDevTblEntry 0xE2U
+#define UHS_HOST_ERROR_FailGetConfDescr 0xE3U
+#define UHS_HOST_ERROR_END_OF_STREAM 0xEFU
+
+// Host base class specific Error codes
+#define UHS_HOST_ERROR_NOT_IMPLEMENTED 0xFEU
+#define UHS_HOST_ERROR_TRANSFER_TIMEOUT 0xFFU
+
+// SEI interaction defaults
+#define UHS_HOST_TRANSFER_MAX_MS 10000 // USB transfer timeout in ms, per section 9.2.6.1 of USB 2.0 spec
+#define UHS_HOST_TRANSFER_RETRY_MAXIMUM 3 // 3 retry limit for a transfer
+#define UHS_HOST_DEBOUNCE_DELAY_MS 500 // settle delay in milliseconds
+#define UHS_HUB_RESET_DELAY_MS 20 // hub port reset delay, 10ms recomended, but can be up to 20ms
+
+//
+// We only provide the minimum needed information for enumeration.
+// Interface drivers should be able to set up what is needed with nothing more.
+// A driver needs to know the following information:
+// 1: address on the USB network, parent and port (aka UsbDeviceAddress)
+// 2: endpoints
+// 3: vid:pid, class, subclass, protocol
+//
+
+struct ENDPOINT_INFO {
+ 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));
+
+struct INTERFACE_INFO {
+ uint8_t bInterfaceNumber;
+ uint8_t bAlternateSetting;
+ uint8_t numep;
+ uint8_t klass;
+ uint8_t subklass;
+ uint8_t protocol;
+ ENDPOINT_INFO epInfo[16];
+} __attribute__((packed));
+
+struct ENUMERATION_INFO {
+ uint16_t vid;
+ uint16_t pid;
+ uint16_t bcdDevice;
+ uint8_t klass;
+ uint8_t subklass;
+ uint8_t protocol;
+ uint8_t bMaxPacketSize0;
+ uint8_t currentconfig;
+ uint8_t parent;
+ uint8_t port;
+ uint8_t address;
+ INTERFACE_INFO interface;
+} __attribute__((packed));
+
+/* USB Setup Packet Structure */
+typedef struct {
+ // offset description
+ // 0 Bit-map of request type
+ union {
+ uint8_t bmRequestType;
+
+ struct {
+ uint8_t recipient : 5; // Recipient of the request
+ uint8_t type : 2; // Type of request
+ uint8_t direction : 1; // Direction of data transfer
+ } __attribute__((packed));
+ } ReqType_u;
+
+ // 1 Request
+ uint8_t bRequest;
+
+ // 2 Depends on bRequest
+ union {
+ uint16_t wValue;
+
+ struct {
+ uint8_t wValueLo;
+ uint8_t wValueHi;
+ } __attribute__((packed));
+ } wVal_u;
+ // 4 Depends on bRequest
+ uint16_t wIndex;
+ // 6 Depends on bRequest
+ uint16_t wLength;
+ // 8 bytes total
+} __attribute__((packed)) SETUP_PKT, *PSETUP_PKT;
+
+
+// little endian :-) 8 8 8 8 16 16
+#define mkSETUP_PKT8(bmReqType, bRequest, wValLo, wValHi, wInd, total) ((uint64_t)(((uint64_t)(bmReqType)))|(((uint64_t)(bRequest))<<8)|(((uint64_t)(wValLo))<<16)|(((uint64_t)(wValHi))<<24)|(((uint64_t)(wInd))<<32)|(((uint64_t)(total)<<48)))
+#define mkSETUP_PKT16(bmReqType, bRequest, wVal, wInd, total) ((uint64_t)(((uint64_t)(bmReqType)))|(((uint64_t)(bRequest))<<8)|(((uint64_t)(wVal ))<<16) |(((uint64_t)(wInd))<<32)|(((uint64_t)(total)<<48)))
+
+// Big endian -- but we aren't able to use this :-/
+//#define mkSETUP_PKT8(bmReqType, bRequest, wValLo, wValHi, wInd, total) ((uint64_t)(((uint64_t)(bmReqType))<<56)|(((uint64_t)(bRequest))<<48)|(((uint64_t)(wValLo))<<40)|(((uint64_t)(wValHi))<<32)|(((uint64_t)(wInd))<<16)|((uint64_t)(total)))
+//#define mkSETUP_PKT16(bmReqType, bRequest, wVal, wInd, total) ((uint64_t)(((uint64_t)(bmReqType))<<56)|(((uint64_t)(bRequest))<<48) |(((uint64_t)(wVal))<<32) |(((uint64_t)(wInd))<<16)|((uint64_t)(total)))
+
+#endif /* USBCORE_H */
diff --git a/Marlin/src/sd/usb_flashdrive/lib-uhs3/UHS_host/UHS_address.h b/Marlin/src/sd/usb_flashdrive/lib-uhs3/UHS_host/UHS_address.h
new file mode 100644
index 0000000..4d9d35b
--- /dev/null
+++ b/Marlin/src/sd/usb_flashdrive/lib-uhs3/UHS_host/UHS_address.h
@@ -0,0 +1,248 @@
+/* Copyright (C) 2015-2016 Andrew J. Kroll
+ and
+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 : https://www.circuitsathome.com
+e-mail : support@circuitsathome.com
+ */
+
+#if !defined(_UHS_host_h_) || defined(__ADDRESS_H__)
+#error "Never include UHS_address.h directly; include UHS_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 UHS_USB_NAK_MAX_POWER 14 // NAK binary order maximum value
+#define UHS_USB_NAK_DEFAULT 13 // default 16K-1 NAKs before giving up
+#define UHS_USB_NAK_NOWAIT 1 // Single NAK stops transfer
+#define UHS_USB_NAK_NONAK 0 // Do not count NAKs, stop retrying after USB Timeout. Try not to use this.
+
+#define bmUSB_DEV_ADDR_PORT 0x07
+#define bmUSB_DEV_ADDR_PARENT 0x78
+#define bmUSB_DEV_ADDR_HUB 0x40
+
+// TODO: embed parent?
+struct UHS_EpInfo {
+ uint8_t epAddr; // Endpoint address
+ uint8_t bIface;
+ uint16_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 bmNeedPing : 1; // 1 == ping protocol needed for next out packet
+ uint8_t bmNakPower : 5; // Binary order for NAK_LIMIT value
+ } __attribute__((packed));
+ };
+} __attribute__((packed));
+
+// TODO: embed parent address and port into epinfo struct,
+// and nuke this address stupidity.
+// This is a compact scheme. Should also support full spec.
+// This produces a 7 hub limit, 49 devices + 7 hubs, 56 total.
+//
+// 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 number
+// A - port number of parent
+//
+
+struct UHS_DeviceAddress {
+
+ union {
+
+ struct {
+ uint8_t bmAddress : 3; // 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));
+
+struct UHS_Device {
+ volatile UHS_EpInfo *epinfo[UHS_HOST_MAX_INTERFACE_DRIVERS]; // endpoint info pointer
+ UHS_DeviceAddress address;
+ uint8_t epcount; // number of endpoints
+ uint8_t speed; // indicates device speed
+} __attribute__((packed));
+
+typedef void (*UsbDeviceHandleFunc)(UHS_Device *pdev);
+
+class AddressPool {
+ UHS_EpInfo dev0ep; //Endpoint data structure used during enumeration for uninitialized device
+
+ // In order to avoid hub address duplication, this should use bits
+ uint8_t hubCounter; // hub counter
+
+ UHS_Device thePool[UHS_HOST_MAX_INTERFACE_DRIVERS];
+
+ // Initializes address pool entry
+
+ void UHS_NI InitEntry(uint8_t index) {
+ thePool[index].address.devAddress = 0;
+ thePool[index].epcount = 1;
+ thePool[index].speed = 0;
+ for(uint8_t i = 0; i < UHS_HOST_MAX_INTERFACE_DRIVERS; i++) {
+ thePool[index].epinfo[i] = &dev0ep;
+ }
+ };
+
+ // Returns thePool index for a given address
+
+ uint8_t UHS_NI FindAddressIndex(uint8_t address = 0) {
+ for(uint8_t i = 1; i < UHS_HOST_MAX_INTERFACE_DRIVERS; i++) {
+ if(thePool[i].address.devAddress == address)
+ return i;
+ }
+ return 0;
+ };
+
+ // Returns thePool child index for a given parent
+
+ uint8_t UHS_NI FindChildIndex(UHS_DeviceAddress addr, uint8_t start = 1) {
+ for(uint8_t i = (start < 1 || start >= UHS_HOST_MAX_INTERFACE_DRIVERS) ? 1 : start; i < UHS_HOST_MAX_INTERFACE_DRIVERS; i++) {
+ if(thePool[i].address.bmParent == addr.bmAddress)
+ return i;
+ }
+ return 0;
+ };
+
+ // Frees address entry specified by index parameter
+
+ void UHS_NI FreeAddressByIndex(uint8_t index) {
+ // Zero field is reserved and should not be affected
+ if(index == 0)
+ return;
+
+ UHS_DeviceAddress 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);
+
+ // FIXME: use BIT MASKS
+ // If the hub had the last allocated address, hubCounter should be decremented
+ if(hubCounter == uda.bmAddress)
+ hubCounter--;
+ }
+ InitEntry(index);
+ }
+
+ void InitAllAddresses() {
+ for(uint8_t i = 1; i < UHS_HOST_MAX_INTERFACE_DRIVERS; i++) InitEntry(i);
+ hubCounter = 0;
+ };
+public:
+
+ AddressPool() {
+ hubCounter = 0;
+ // Zero address is reserved
+ InitEntry(0);
+
+ thePool[0].epinfo[0] = &dev0ep;
+ dev0ep.epAddr = 0;
+#if UHS_DEVICE_WINDOWS_USB_SPEC_VIOLATION_DESCRIPTOR_DEVICE
+ dev0ep.maxPktSize = 0x40; //starting at 0x40 and work down
+#else
+ dev0ep.maxPktSize = 0x08;
+#endif
+ dev0ep.epAttribs = 0; //set DATA0/1 toggles to 0
+ dev0ep.bmNakPower = UHS_USB_NAK_MAX_POWER;
+ InitAllAddresses();
+ };
+
+ // Returns a pointer to a specified address entry
+
+ UHS_Device* UHS_NI GetUsbDevicePtr(uint8_t addr) {
+ if(!addr)
+ return thePool;
+
+ uint8_t index = FindAddressIndex(addr);
+
+ return (!index) ? NULL : &thePool[index];
+ };
+
+
+ // Allocates new address
+
+ uint8_t UHS_NI AllocAddress(uint8_t parent, bool is_hub = false, uint8_t port = 1) {
+ /* if (parent != 0 && port == 0)
+ USB_HOST_SERIAL.println("PRT:0"); */
+ UHS_DeviceAddress _parent;
+ _parent.devAddress = parent;
+ if(_parent.bmReserved || port > 7)
+ //if(parent > 127 || port > 7)
+ return 0;
+
+ // FIXME: use BIT MASKS
+ 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;
+
+ UHS_DeviceAddress addr;
+ addr.devAddress = port;
+ addr.bmParent = _parent.bmAddress;
+
+ // FIXME: use BIT MASKS
+ if(is_hub) {
+ hubCounter++;
+ addr.bmHub = 1;
+ addr.bmAddress = hubCounter;
+ }
+ thePool[index].address = addr;
+#if DEBUG_PRINTF_EXTRA_HUGE
+#ifdef UHS_DEBUG_USB_ADDRESS
+ printf("Address: %x (%x.%x.%x)\r\n", addr.devAddress, addr.bmHub, addr.bmParent, addr.bmAddress);
+#endif
+#endif
+ return thePool[index].address.devAddress;
+ };
+
+ void UHS_NI 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);
+ };
+
+};
+
+#endif // __ADDRESS_H__
diff --git a/Marlin/src/sd/usb_flashdrive/lib-uhs3/UHS_host/UHS_hexdump.h b/Marlin/src/sd/usb_flashdrive/lib-uhs3/UHS_host/UHS_hexdump.h
new file mode 100644
index 0000000..945512c
--- /dev/null
+++ b/Marlin/src/sd/usb_flashdrive/lib-uhs3/UHS_host/UHS_hexdump.h
@@ -0,0 +1,70 @@
+/* Copyright (C) 2015-2016 Andrew J. Kroll
+ and
+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 : https://www.circuitsathome.com
+e-mail : support@circuitsathome.com
+ */
+#if !defined(_usb_h_) || defined(__HEXDUMP_H__)
+#error "Never include UHS_hexdump.h directly; include UHS_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;
+ };
+
+ virtual 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) {
+ 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-uhs3/UHS_host/UHS_host.h b/Marlin/src/sd/usb_flashdrive/lib-uhs3/UHS_host/UHS_host.h
new file mode 100644
index 0000000..5d711c1
--- /dev/null
+++ b/Marlin/src/sd/usb_flashdrive/lib-uhs3/UHS_host/UHS_host.h
@@ -0,0 +1,111 @@
+/* Copyright (C) 2015-2016 Andrew J. Kroll
+ and
+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 : https://www.circuitsathome.com
+e-mail : support@circuitsathome.com
+ */
+/* USB functions */
+#ifndef _UHS_host_h_
+#define _UHS_host_h_
+
+// WARNING: Do not change the order of includes, or stuff will break!
+#include <inttypes.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <stdint.h>
+
+#if DISABLED(USE_UHS3_USB)
+#include <ISR_safe_memory.h>
+#include <Wire.h>
+#include <SPI.h>
+#include <UHS_ByteBuffer.h>
+#endif
+#include "UHS_macros.h"
+
+// None of these should ever be directly included by a driver, or a user's sketch.
+#include "../dyn_SWI/dyn_SWI.h"
+#include "UHS_USB_IDs.h"
+#include "UHS_settings.h"
+#include "UHS_usb_ch9.h"
+#include "UHS_UsbCore.h"
+#include "UHS_address.h"
+#include "UHS_usbhost.h"
+#include "UHS_printhex.h"
+#include "UHS_message.h"
+
+// Load system components as required
+#if defined(LOAD_USB_HOST_SYSTEM) && !defined(USB_HOST_SYSTEM_LOADED)
+#include "UHS_util_INLINE.h"
+#include "UHS_host_INLINE.h"
+#include "UHS_printf_HELPER.h"
+
+#ifdef LOAD_USB_HOST_SHIELD
+#include "USB_HOST_SHIELD/USB_HOST_SHIELD.h"
+#endif
+
+#if defined(LOAD_UHS_KINETIS_FS_HOST) && !defined(UHS_KINETIS_FS_HOST_LOADED)
+#include "UHS_KINETIS_FS_HOST/UHS_KINETIS_FS_HOST.h"
+#endif
+
+#if defined(LOAD_UHS_KINETIS_EHCI) && !defined(UHS_KINETIS_EHCI_LOADED)
+#include "UHS_KINETIS_EHCI/UHS_KINETIS_EHCI.h"
+#endif
+
+// Load USB drivers and multiplexers
+
+#ifdef LOAD_UHS_HUB
+#include "UHS_HUB/UHS_HUB.h"
+#endif // HUB loaded
+
+#ifdef LOAD_UHS_BULK_STORAGE
+#include "UHS_BULK_STORAGE/UHS_BULK_STORAGE.h"
+#endif
+
+#ifdef LOAD_GENERIC_STORAGE
+#include "../UHS_FS/UHS_FS.h"
+#endif
+// Add BT and optionally HID if directed to do so
+#ifdef LOAD_UHS_BT
+#include "UHS_BT/UHS_BT.h"
+#endif // BT and optionally HID loaded
+
+// Add HID
+#ifdef LOAD_UHS_HID
+#include "UHS_HID/UHS_HID.h"
+#endif // HID loaded
+
+// Add CDC multiplexers (currently only ACM)
+#if defined(LOAD_UHS_CDC_ACM) || defined(LOAD_UHS_CDC_ACM_FTDI) || defined(LOAD_UHS_CDC_ACM_PROLIFIC) || defined(LOAD_UHS_CDC_ACM_XR21B1411)
+#include "UHS_CDC/UHS_CDC.h"
+#endif // CDC loaded
+
+#ifdef LOAD_UHS_ADK
+#include "UHS_ADK/UHS_ADK.h"
+#endif
+
+#ifdef LOAD_UHS_MIDI
+#include "UHS_MIDI/UHS_MIDI.h"
+#endif
+
+#endif // System code loaded
+
+#endif // _UHS_host_h_
diff --git a/Marlin/src/sd/usb_flashdrive/lib-uhs3/UHS_host/UHS_host_INLINE.h b/Marlin/src/sd/usb_flashdrive/lib-uhs3/UHS_host/UHS_host_INLINE.h
new file mode 100644
index 0000000..9c7b500
--- /dev/null
+++ b/Marlin/src/sd/usb_flashdrive/lib-uhs3/UHS_host/UHS_host_INLINE.h
@@ -0,0 +1,1222 @@
+/* Copyright (C) 2015-2016 Andrew J. Kroll
+ and
+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 : https://www.circuitsathome.com
+e-mail : support@circuitsathome.com
+ */
+
+#if defined(LOAD_USB_HOST_SYSTEM) && !defined(USB_HOST_SYSTEM_LOADED)
+#define USB_HOST_SYSTEM_LOADED
+
+#ifndef DEBUG_PRINTF_EXTRA_HUGE_UHS_HOST
+#define DEBUG_PRINTF_EXTRA_HUGE_UHS_HOST 0
+#endif
+
+#if DEBUG_PRINTF_EXTRA_HUGE
+#if DEBUG_PRINTF_EXTRA_HUGE_UHS_HOST
+#define HOST_DEBUG(...) printf(__VA_ARGS__)
+#else
+#define HOST_DEBUG(...) VOID0
+#endif
+#else
+#define HOST_DEBUG(...) VOID0
+#endif
+
+UHS_EpInfo* UHS_USB_HOST_BASE::getEpInfoEntry(uint8_t addr, uint8_t ep) {
+ UHS_Device *p = addrPool.GetUsbDevicePtr(addr);
+
+ if(!p || !p->epinfo)
+ return NULL;
+
+
+ UHS_EpInfo *pep;
+ for(uint8_t j = 0; j < UHS_HOST_MAX_INTERFACE_DRIVERS; j++) {
+ pep = (UHS_EpInfo *)(p->epinfo[j]);
+
+ for(uint8_t i = 0; i < p->epcount; i++) {
+ if((pep)->epAddr == ep) {
+ HOST_DEBUG("ep entry for interface %d ep %d max packet size = %d\r\n", pep->bIface, ep, pep->maxPktSize);
+ return pep;
+ }
+
+ pep++;
+ }
+ }
+ return NULL;
+}
+
+/**
+ * Sets a device table entry for a device.
+ * Each device is different and has different number of endpoints.
+ * This function plugs endpoint record structure, defined in application, to devtable
+ *
+ * @param addr device address
+ * @param epcount how many endpoints
+ * @param eprecord pointer to the endpoint structure
+ * @return Zero for success, or error code
+ */
+uint8_t UHS_USB_HOST_BASE::setEpInfoEntry(uint8_t addr, uint8_t iface, uint8_t epcount, volatile UHS_EpInfo* eprecord) {
+ if(!eprecord)
+ return UHS_HOST_ERROR_BAD_ARGUMENT;
+
+ UHS_Device *p = addrPool.GetUsbDevicePtr(addr);
+
+ if(!p)
+ return UHS_HOST_ERROR_NO_ADDRESS_IN_POOL;
+
+ p->address.devAddress = addr;
+ p->epinfo[iface] = eprecord;
+ p->epcount = epcount;
+ return 0;
+}
+
+/**
+ * sets all enpoint addresses to zero.
+ * Sets all max packet sizes to defaults
+ * Clears all endpoint attributes
+ * Sets bmNakPower to USB_NAK_DEFAULT
+ * Sets binterface to zero.
+ * Sets bNumEP to zero.
+ * Sets bAddress to zero.
+ * Clears qNextPollTime and sets bPollEnable to false.
+ *
+ * @param maxep How many endpoints to initialize
+ * @param device pointer to the device driver instance (this)
+ */
+
+void UHS_USB_HOST_BASE::DeviceDefaults(uint8_t maxep, UHS_USBInterface *interface) {
+
+ for(uint8_t i = 0; i < maxep; i++) {
+ interface->epInfo[i].epAddr = 0;
+ interface->epInfo[i].maxPktSize = (i) ? 0 : 8;
+ interface->epInfo[i].epAttribs = 0;
+ interface->epInfo[i].bmNakPower = UHS_USB_NAK_DEFAULT;
+ }
+ interface->pUsb->GetAddressPool()->FreeAddress(interface->bAddress);
+ interface->bIface = 0;
+ interface->bNumEP = 1;
+ interface->bAddress = 0;
+ interface->qNextPollTime = 0;
+ interface->bPollEnable = false;
+}
+
+/**
+ * Perform a bus reset to the port of the connected device
+ *
+ * @param parent index to Parent
+ * @param port what port on the parent
+ * @param address address of the device
+ * @return Zero for success, or error code
+ */
+
+uint8_t UHS_USB_HOST_BASE::doSoftReset(uint8_t parent, uint8_t port, uint8_t address) {
+ uint8_t rcode = 0;
+
+ if(parent == 0) {
+ // Send a bus reset on the root interface.
+ doHostReset();
+ } else {
+ // reset parent port
+ devConfig[parent]->ResetHubPort(port);
+ }
+
+ //
+ // Many devices require a delay before setting the address here...
+ // We loop upon fails for up to 2 seconds instead.
+ // Most devices will be happy without a retry.
+ //
+ uint8_t retries = 0;
+ if(address) {
+ do {
+ rcode = setAddr(0, address);
+ if(!rcode) break;
+ retries++;
+ sof_delay(10);
+ } while(retries < 200);
+ HOST_DEBUG("%i retries.\r\n", retries);
+ } else {
+#if DEBUG_PRINTF_EXTRA_HUGE
+ printf("\r\ndoSoftReset called with address == 0.\r\n");
+#endif
+ }
+ return rcode;
+}
+
+/*
+ * Pseudo code so you may understand the code flow.
+ *
+ * reset; (happens at the lower level)
+ * GetDevDescr();
+ * reset;
+ * If there are no configuration descriptors {
+ * //
+ * // Note: I know of no device that does this.
+ * // I suppose there could be one though.
+ * //
+ * try to enumerate.
+ * } else {
+ * last success count = 0
+ * best config = 0
+ * for each configuration descriptor {
+ * for each interface descriptor {
+ * get the endpoint descriptors for this interface.
+ * Check to see if a driver can handle this interface.
+ * If it can, add 1 to the success count.
+ * }
+ * if success count > last success count {
+ * best config = current config
+ * last success count = success count
+ * }
+ * }
+ * set the device config to the best config
+ * for each best config interface descriptor {
+ * initialize driver that can handle this interface config
+ * }
+ * }
+ *
+ * NOTES:
+ * 1: We do not need to save toggle states anymore and have not
+ * needed to for some time, because the lower level driver
+ * actually corrects wrong toggles on-the-fly for us.
+ *
+ * 2: We always do a second reset, since this stupid bug is
+ * actually part of the specification documents that I
+ * have found all over the net. Even Linux does it, and
+ * many devices actually EXPECT this behavior. Some devices
+ * will not enumerate without it. For devices that do not
+ * need it, the additional reset is harmless. Here is an
+ * example of one of these documents, see page Five:
+ * https://www.ftdichip.com/Support/Documents/TechnicalNotes/TN_113_Simplified%20Description%20of%20USB%20Device%20Enumeration.pdf
+ *
+ */
+
+/**
+ * Enumerates interfaces on devices
+ *
+ * @param parent index to Parent
+ * @param port what port on the parent
+ * @param speed the speed of the device
+ * @return Zero for success, or error code
+ */
+uint8_t UHS_USB_HOST_BASE::Configuring(uint8_t parent, uint8_t port, uint8_t speed) {
+ //uint8_t bAddress = 0;
+ HOST_DEBUG("\r\n\r\n\r\nConfiguring: parent = %i, port = %i, speed = %i\r\n", parent, port, speed);
+ uint8_t rcode = 0;
+ uint8_t retries = 0;
+ uint8_t numinf = 0;
+ uint8_t configs;
+ UHS_Device *p = NULL;
+ //EpInfo epInfo; // cap at 16, this should be fairly reasonable.
+ ENUMERATION_INFO ei;
+ uint8_t bestconf = 0;
+ uint8_t bestsuccess = 0;
+
+ uint8_t devConfigIndex;
+
+#if UHS_DEVICE_WINDOWS_USB_SPEC_VIOLATION_DESCRIPTOR_DEVICE
+ const uint8_t biggest = 0x40;
+ // wrap in {} to throw away the 64 byte buffer when we are done with it
+ {
+ uint8_t buf[biggest];
+ USB_FD_DEVICE_DESCRIPTOR *udd = reinterpret_cast<USB_FD_DEVICE_DESCRIPTOR *>(buf);
+#else
+ const uint8_t biggest = 18;
+ uint8_t buf[biggest];
+ USB_FD_DEVICE_DESCRIPTOR *udd = reinterpret_cast<USB_FD_DEVICE_DESCRIPTOR *>(buf);
+ USB_FD_CONFIGURATION_DESCRIPTOR *ucd = reinterpret_cast<USB_FD_CONFIGURATION_DESCRIPTOR *>(buf);
+#endif
+
+ //for(devConfigIndex = 0; devConfigIndex < UHS_HOST_MAX_INTERFACE_DRIVERS; devConfigIndex++) {
+ // if((devConfig[devConfigIndex]->bAddress) && (!devConfig[devConfigIndex]->bPollEnable)) {
+ // devConfig[devConfigIndex]->bAddress = 0;
+ // }
+ //}
+ // Serial.print("HOST USB Host @ 0x");
+ // Serial.println((uint32_t)this, HEX);
+ // Serial.print("HOST USB Host Address Pool @ 0x");
+ // Serial.println((uint32_t)GetAddressPool(), HEX);
+
+ sof_delay(200);
+ p = addrPool.GetUsbDevicePtr(0);
+ if(!p) {
+ HOST_DEBUG("Configuring error: USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL\r\n");
+ return UHS_HOST_ERROR_NO_ADDRESS_IN_POOL;
+ }
+
+ p->speed = speed;
+#if UHS_DEVICE_WINDOWS_USB_SPEC_VIOLATION_DESCRIPTOR_DEVICE
+
+ p->epinfo[0][0].maxPktSize = 0x40; // Windows bug is expected.
+ // poison data
+ // udd->bMaxPacketSize0 = 0U;
+#else
+ p->epinfo[0][0].maxPktSize = 0x08; // USB Spec, start small, work your way up.
+#endif
+again:
+ memset((void *)buf, 0, biggest);
+ HOST_DEBUG("\r\n\r\nConfiguring PktSize 0x%2.2x, rcode: 0x%2.2x, retries %i,\r\n", p->epinfo[0][0].maxPktSize, rcode, retries);
+ rcode = getDevDescr(0, biggest, (uint8_t*)buf);
+#if UHS_DEVICE_WINDOWS_USB_SPEC_VIOLATION_DESCRIPTOR_DEVICE
+ if(rcode || udd->bMaxPacketSize0 < 8)
+#else
+ if(rcode)
+#endif
+ {
+ if(rcode == UHS_HOST_ERROR_JERR && retries < 4) {
+ //
+ // Some devices return JERR when plugged in.
+ // Attempts to reinitialize the device usually works.
+ //
+ // I have a hub that will refuse to work and acts like
+ // this unless external power is supplied.
+ // So this may not always work, and you may be fooled.
+ //
+ sof_delay(100);
+ retries++;
+ goto again;
+#if UHS_DEVICE_WINDOWS_USB_SPEC_VIOLATION_DESCRIPTOR_DEVICE
+ } else if(((rcode == UHS_HOST_ERROR_DMA || rcode == UHS_HOST_ERROR_MEM_LAT) && retries < 4) || (udd->bMaxPacketSize0 < 8 && !rcode)) {
+
+ if(p->epinfo[0][0].maxPktSize > 8 && rcode == UHS_HOST_ERROR_DMA) p->epinfo[0][0].maxPktSize = p->epinfo[0][0].maxPktSize >> 1;
+#else
+ } else if((rcode == UHS_HOST_ERROR_DMA || rcode == UHS_HOST_ERROR_MEM_LAT) && retries < 4) {
+ if(p->epinfo[0][0].maxPktSize < 32) p->epinfo[0][0].maxPktSize = p->epinfo[0][0].maxPktSize << 1;
+#endif
+ HOST_DEBUG("Configuring error: 0x%2.2x UHS_HOST_ERROR_DMA. Retry with maxPktSize: %i\r\n", rcode, p->epinfo[0][0].maxPktSize);
+ doSoftReset(parent, port, 0);
+ retries++;
+ sof_delay(200);
+ goto again;
+ }
+ HOST_DEBUG("Configuring error: 0x%2.2x Can't get USB_FD_DEVICE_DESCRIPTOR\r\n", rcode);
+ return rcode;
+ }
+
+
+#if UHS_DEVICE_WINDOWS_USB_SPEC_VIOLATION_DESCRIPTOR_DEVICE
+ ei.address = addrPool.AllocAddress(parent, false, port);
+
+ if(!ei.address) {
+ return UHS_HOST_ERROR_ADDRESS_POOL_FULL;
+ }
+
+ p = addrPool.GetUsbDevicePtr(ei.address);
+ // set to 1 if you suspect address table corruption.
+#if 0
+ if(!p) {
+ return UHS_HOST_ERROR_NO_ADDRESS_IN_POOL;
+ }
+#endif
+
+ p->speed = speed;
+
+ rcode = doSoftReset(parent, port, ei.address);
+
+ if(rcode) {
+ addrPool.FreeAddress(ei.address);
+ HOST_DEBUG("Configuring error: %2.2x Can't set USB INTERFACE ADDRESS\r\n", rcode);
+ return rcode;
+ }
+
+ { // the { } wrapper saves on stack.
+ HOST_DEBUG("DevDescr 2nd poll, bMaxPacketSize0:%u\r\n", udd->bMaxPacketSize0);
+ UHS_EpInfo dev1ep;
+ dev1ep.maxPktSize = udd->bMaxPacketSize0;
+ dev1ep.epAddr = 0;
+ dev1ep.epAttribs = 0;
+ dev1ep.bmNakPower = UHS_USB_NAK_MAX_POWER;
+ p->address.devAddress = ei.address;
+ p->epcount = 1;
+ p->epinfo[0] = &dev1ep;
+
+ sof_delay(10);
+ memset((void *)buf, 0, biggest);
+ rcode = getDevDescr(ei.address, 18, (uint8_t*)buf);
+ if(rcode) HOST_DEBUG("getDevDescr err: 0x%x \r\n", rcode);
+
+ addrPool.FreeAddress(ei.address);
+ if(rcode && rcode != UHS_HOST_ERROR_DMA) {
+ return rcode;
+ }
+ sof_delay(10);
+ }
+#endif
+
+ ei.vid = udd->idVendor;
+ ei.pid = udd->idProduct;
+ ei.bcdDevice = udd->bcdDevice;
+ ei.klass = udd->bDeviceClass;
+ ei.subklass = udd->bDeviceSubClass;
+ ei.protocol = udd->bDeviceProtocol;
+ ei.bMaxPacketSize0 = udd->bMaxPacketSize0;
+ ei.currentconfig = 0;
+ ei.parent = parent;
+ ei.port = port;
+ configs = udd->bNumConfigurations;
+#if UHS_DEVICE_WINDOWS_USB_SPEC_VIOLATION_DESCRIPTOR_DEVICE
+ } // unwrapped, old large buf now invalid and discarded.
+
+ uint8_t buf[18];
+ USB_FD_CONFIGURATION_DESCRIPTOR *ucd = reinterpret_cast<USB_FD_CONFIGURATION_DESCRIPTOR *>(buf);
+#endif
+
+ ei.address = addrPool.AllocAddress(parent, IsHub(ei.klass), port);
+
+ if(!ei.address) {
+ return UHS_HOST_ERROR_ADDRESS_POOL_FULL;
+ }
+
+ p = addrPool.GetUsbDevicePtr(ei.address);
+ // set to 1 if you suspect address table corruption.
+#if 0
+ if(!p) {
+ return UHS_HOST_ERROR_NO_ADDRESS_IN_POOL;
+ }
+#endif
+
+ p->speed = speed;
+
+ rcode = doSoftReset(parent, port, ei.address);
+
+ if(rcode) {
+ addrPool.FreeAddress(ei.address);
+ HOST_DEBUG("Configuring error: %2.2x Can't set USB INTERFACE ADDRESS\r\n", rcode);
+ return rcode;
+ }
+
+ if(configs < 1) {
+ HOST_DEBUG("No interfaces?!\r\n");
+ addrPool.FreeAddress(ei.address);
+ // rcode = TestInterface(&ei);
+ // Not implemented (yet)
+ rcode = UHS_HOST_ERROR_DEVICE_NOT_SUPPORTED;
+ } else {
+ HOST_DEBUG("configs: %i\r\n", configs);
+ for(uint8_t conf = 0; (!rcode) && (conf < configs); conf++) {
+ // read the config descriptor into a buffer.
+ rcode = getConfDescr(ei.address, sizeof (USB_FD_CONFIGURATION_DESCRIPTOR), conf, buf);
+ if(rcode) {
+ HOST_DEBUG("Configuring error: %2.2x Can't get USB_FD_INTERFACE_DESCRIPTOR\r\n", rcode);
+ rcode = UHS_HOST_ERROR_FailGetConfDescr;
+ continue;
+ }
+ ei.currentconfig = conf;
+ numinf = ucd->bNumInterfaces; // Does _not_ include alternates!
+ HOST_DEBUG("CONFIGURATION: %i, bNumInterfaces %i, wTotalLength %i\r\n", conf, numinf, ucd->wTotalLength);
+ uint8_t success = 0;
+ uint16_t inf = 0;
+ uint8_t data[ei.bMaxPacketSize0];
+ UHS_EpInfo *pep;
+ pep = ctrlReqOpen(ei.address, mkSETUP_PKT8(UHS_bmREQ_GET_DESCR, USB_REQUEST_GET_DESCRIPTOR, ei.currentconfig, USB_DESCRIPTOR_CONFIGURATION, 0x0000U, ucd->wTotalLength), data);
+ if(!pep) {
+ rcode = UHS_HOST_ERROR_NULL_EPINFO;
+ continue;
+ }
+ uint16_t left;
+ uint16_t read;
+ uint8_t offset;
+ rcode = initDescrStream(&ei, ucd, pep, data, &left, &read, &offset);
+ if(rcode) {
+ HOST_DEBUG("Configuring error: %2.2x Can't get USB_FD_INTERFACE_DESCRIPTOR stream.\r\n", rcode);
+ break;
+ }
+ for(; (numinf) && (!rcode); inf++) {
+ // iterate for each interface on this config
+ rcode = getNextInterface(&ei, pep, data, &left, &read, &offset);
+ if(rcode == UHS_HOST_ERROR_END_OF_STREAM) {
+ HOST_DEBUG("USB_INTERFACE END OF STREAM\r\n");
+ ctrlReqClose(pep, UHS_bmREQ_GET_DESCR, left, ei.bMaxPacketSize0, data);
+ rcode = 0;
+ break;
+ }
+ if(rcode) {
+ HOST_DEBUG("Configuring error: %2.2x Can't close USB_FD_INTERFACE_DESCRIPTOR stream.\r\n", rcode);
+ continue;
+ }
+ rcode = TestInterface(&ei);
+ if(!rcode) success++;
+ rcode = 0;
+ }
+ if(!inf) {
+ rcode = TestInterface(&ei);
+ if(!rcode) success++;
+ rcode = 0;
+ }
+ if(success > bestsuccess) {
+ bestconf = conf;
+ bestsuccess = success;
+ }
+ }
+ if(!bestsuccess) rcode = UHS_HOST_ERROR_DEVICE_NOT_SUPPORTED;
+ }
+ if(!rcode) {
+ rcode = getConfDescr(ei.address, sizeof (USB_FD_CONFIGURATION_DESCRIPTOR), bestconf, buf);
+ if(rcode) {
+ HOST_DEBUG("Configuring error: %2.2x Can't get USB_FD_INTERFACE_DESCRIPTOR\r\n", rcode);
+ rcode = UHS_HOST_ERROR_FailGetConfDescr;
+ }
+ }
+ if(!rcode) {
+ bestconf++;
+ ei.currentconfig = bestconf;
+ numinf = ucd->bNumInterfaces; // Does _not_ include alternates!
+ HOST_DEBUG("CONFIGURATION: %i, bNumInterfaces %i, wTotalLength %i\r\n", bestconf, numinf, ucd->wTotalLength);
+ if(!rcode) {
+ HOST_DEBUG("Best configuration is %i, enumerating interfaces.\r\n", bestconf);
+ uint16_t inf = 0;
+ uint8_t data[ei.bMaxPacketSize0];
+ UHS_EpInfo *pep;
+ pep = ctrlReqOpen(ei.address, mkSETUP_PKT8(UHS_bmREQ_GET_DESCR, USB_REQUEST_GET_DESCRIPTOR, ei.currentconfig - 1, USB_DESCRIPTOR_CONFIGURATION, 0x0000U, ucd->wTotalLength), data);
+ if(!pep) {
+ rcode = UHS_HOST_ERROR_NULL_EPINFO;
+
+ } else {
+ uint16_t left;
+ uint16_t read;
+ uint8_t offset;
+ rcode = initDescrStream(&ei, ucd, pep, data, &left, &read, &offset);
+ if(rcode) {
+ HOST_DEBUG("Configuring error: %2.2x Can't get USB_FD_INTERFACE_DESCRIPTOR stream.\r\n", rcode);
+ } else {
+ for(; (numinf) && (!rcode); inf++) {
+ // iterate for each interface on this config
+ rcode = getNextInterface(&ei, pep, data, &left, &read, &offset);
+ if(rcode == UHS_HOST_ERROR_END_OF_STREAM) {
+ ctrlReqClose(pep, UHS_bmREQ_GET_DESCR, left, ei.bMaxPacketSize0, data);
+ rcode = 0;
+ break;
+ }
+ if(rcode) {
+ HOST_DEBUG("Configuring error: %2.2x Can't close USB_FD_INTERFACE_DESCRIPTOR stream.\r\n", rcode);
+ continue;
+ }
+
+ if(enumerateInterface(&ei) == UHS_HOST_MAX_INTERFACE_DRIVERS) {
+ HOST_DEBUG("No interface driver for this interface.");
+ } else {
+ HOST_DEBUG("Interface Configured\r\n");
+ }
+ }
+ }
+ }
+ } else {
+ HOST_DEBUG("Configuring error: %2.2x Can't set USB_INTERFACE_CONFIG stream.\r\n", rcode);
+ }
+ }
+
+ if(!rcode) {
+ rcode = setConf(ei.address, bestconf);
+ if(rcode) {
+ HOST_DEBUG("Configuring error: %2.2x Can't set Configuration.\r\n", rcode);
+ addrPool.FreeAddress(ei.address);
+ } else {
+ for(devConfigIndex = 0; devConfigIndex < UHS_HOST_MAX_INTERFACE_DRIVERS; devConfigIndex++) {
+ HOST_DEBUG("Driver %i ", devConfigIndex);
+ if(!devConfig[devConfigIndex]) {
+ HOST_DEBUG("no driver at this index.\r\n");
+ continue; // no driver
+ }
+ HOST_DEBUG("@ %2.2x ", devConfig[devConfigIndex]->bAddress);
+ if(devConfig[devConfigIndex]->bAddress) {
+ if(!devConfig[devConfigIndex]->bPollEnable) {
+ HOST_DEBUG("Initialize\r\n");
+ rcode = devConfig[devConfigIndex]->Finalize();
+ rcode = devConfig[devConfigIndex]->Start();
+ if(!rcode) {
+ HOST_DEBUG("Total endpoints = (%i)%i\r\n", p->epcount, devConfig[devConfigIndex]->bNumEP);
+ } else {
+ break;
+ }
+ } else {
+ HOST_DEBUG("Already initialized.\r\n");
+ continue; // consumed
+ }
+ } else {
+ HOST_DEBUG("Skipped\r\n");
+ }
+ }
+#if 0 // defined(UHS_HID_LOADED)
+ // Now do HID
+#endif
+ }
+ } else {
+ addrPool.FreeAddress(ei.address);
+ }
+ return rcode;
+}
+
+/**
+ * Removes a device from the tables
+ *
+ * @param addr address of the device
+ * @return nothing
+ */
+void UHS_USB_HOST_BASE::ReleaseDevice(uint8_t addr) {
+ if(addr) {
+#if 0 // defined(UHS_HID_LOADED)
+ // Release any HID children
+ UHS_HID_Release(this, addr);
+#endif
+ for(uint8_t i = 0; i < UHS_HOST_MAX_INTERFACE_DRIVERS; i++) {
+ if(!devConfig[i]) continue;
+ if(devConfig[i]->bAddress == addr) {
+ devConfig[i]->Release();
+ break;
+ }
+ }
+ }
+}
+
+/**
+ * Gets the device descriptor, or part of it from endpoint Zero.
+ *
+ * @param addr Address of the device
+ * @param nbytes how many bytes to return
+ * @param dataptr pointer to the data to return
+ * @return status of the request, zero is success.
+ */
+uint8_t UHS_USB_HOST_BASE::getDevDescr(uint8_t addr, uint16_t nbytes, uint8_t* dataptr) {
+ return ( ctrlReq(addr, mkSETUP_PKT8(UHS_bmREQ_GET_DESCR, USB_REQUEST_GET_DESCRIPTOR, 0x00, USB_DESCRIPTOR_DEVICE, 0x0000, nbytes), nbytes, dataptr));
+}
+
+/**
+ * Gets the config descriptor, or part of it from endpoint Zero.
+ *
+ * @param addr Address of the device
+ * @param nbytes how many bytes to return
+ * @param conf index to descriptor to return
+ * @param dataptr ointer to the data to return
+ * @return status of the request, zero is success.
+ */
+uint8_t UHS_USB_HOST_BASE::getConfDescr(uint8_t addr, uint16_t nbytes, uint8_t conf, uint8_t* dataptr) {
+ return ( ctrlReq(addr, mkSETUP_PKT8(UHS_bmREQ_GET_DESCR, USB_REQUEST_GET_DESCRIPTOR, conf, USB_DESCRIPTOR_CONFIGURATION, 0x0000, nbytes), nbytes, dataptr));
+}
+
+/**
+ * Get the string descriptor from a device
+ *
+ * @param addr Address of the device
+ * @param ns
+ * @param index
+ * @param langid language ID
+ * @param dataptr pointer to the data to return
+ * @return status of the request, zero is success.
+ */
+uint8_t UHS_USB_HOST_BASE::getStrDescr(uint8_t addr, uint16_t ns, uint8_t index, uint16_t langid, uint8_t* dataptr) {
+ return ( ctrlReq(addr, mkSETUP_PKT8(UHS_bmREQ_GET_DESCR, USB_REQUEST_GET_DESCRIPTOR, index, USB_DESCRIPTOR_STRING, langid, ns), ns, dataptr));
+}
+
+//
+//set address
+//
+
+/**
+ * Set the address of a device to a new address via endpoint Zero.
+ *
+ * @param oldaddr current address
+ * @param newaddr new address
+ * @return status of the request, zero is success.
+ */
+uint8_t UHS_USB_HOST_BASE::setAddr(uint8_t oldaddr, uint8_t newaddr) {
+ uint8_t rcode = ctrlReq(oldaddr, mkSETUP_PKT8(UHS_bmREQ_SET, USB_REQUEST_SET_ADDRESS, newaddr, 0x00, 0x0000, 0x0000), 0x0000, NULL);
+ sof_delay(300); // Older spec says you should wait at least 200ms
+ return rcode;
+}
+
+//
+//set configuration
+//
+
+/**
+ * Set the configuration for the device to use via endpoint Zero.
+ *
+ * @param addr Address of the device
+ * @param conf_value configuration index value
+ * @return status of the request, zero is success.
+ */
+uint8_t UHS_USB_HOST_BASE::setConf(uint8_t addr, uint8_t conf_value) {
+ return ( ctrlReq(addr, mkSETUP_PKT8(UHS_bmREQ_SET, USB_REQUEST_SET_CONFIGURATION, conf_value, 0x00, 0x0000, 0x0000), 0x0000, NULL));
+}
+
+/* rcode 0 if no errors. rcode 01-0f is relayed from HRSL */
+
+/**
+ * Writes data to an interface pipe
+ *
+ * @param addr Address of the device
+ * @param ep Endpoint of the pipe
+ * @param nbytes number of bytes to transfer
+ * @param data pointer to buffer to hold transfer
+ * @return zero for success or error code
+ */
+uint8_t UHS_USB_HOST_BASE::outTransfer(uint8_t addr, uint8_t ep, uint16_t nbytes, uint8_t* data) {
+ UHS_EpInfo *pep = NULL;
+ uint16_t nak_limit = 0;
+ HOST_DEBUG("outTransfer: addr: 0x%2.2x ep: 0x%2.2x nbytes: 0x%4.4x data: 0x%p\r\n", addr, ep, nbytes, data);
+
+ uint8_t rcode = SetAddress(addr, ep, &pep, nak_limit);
+ HOST_DEBUG("outTransfer: SetAddress 0x%2.2x\r\n", rcode);
+ if(!rcode)
+ rcode = OutTransfer(pep, nak_limit, nbytes, data);
+ return rcode;
+};
+
+/**
+ * Reads data from an interface pipe
+ *
+ * @param addr Address of the device
+ * @param ep Endpoint of the pipe
+ * @param nbytesptr number of bytes to transfer
+ * @param data pointer to buffer to hold transfer
+ * @return zero for success or error code
+ */
+uint8_t UHS_USB_HOST_BASE::inTransfer(uint8_t addr, uint8_t ep, uint16_t *nbytesptr, uint8_t* data) {
+ UHS_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;
+ // }
+ if(!rcode)
+ rcode = InTransfer(pep, nak_limit, nbytesptr, data);
+ return rcode;
+
+}
+
+/**
+ * Initialize the descriptor stream, works much like opening a file.
+ *
+ * @param ei
+ * @param ucd
+ * @param pep
+ * @param data
+ * @param left
+ * @param read
+ * @param offset
+ * @return zero for success or error code
+ */
+uint8_t UHS_USB_HOST_BASE::initDescrStream(ENUMERATION_INFO *ei, USB_FD_CONFIGURATION_DESCRIPTOR *ucd, UHS_EpInfo *pep, uint8_t *data, uint16_t *left, uint16_t *read, uint8_t *offset) {
+ if(!ei || !ucd) return UHS_HOST_ERROR_BAD_ARGUMENT;
+ if(!pep) return UHS_HOST_ERROR_NULL_EPINFO;
+ *left = ucd->wTotalLength;
+ *read = 0;
+ *offset = 1;
+ uint8_t rcode;
+ pep->maxPktSize = ei->bMaxPacketSize0;
+ rcode = getone(pep, left, read, data, offset);
+ return rcode;
+}
+
+uint8_t UHS_USB_HOST_BASE::getNextInterface(ENUMERATION_INFO *ei, UHS_EpInfo *pep, uint8_t data[], uint16_t *left, uint16_t *read, uint8_t *offset) {
+ uint16_t remain;
+ uint8_t ty;
+ uint8_t rcode = UHS_HOST_ERROR_END_OF_STREAM;
+ uint8_t *ptr;
+ uint8_t epc = 0;
+ ei->interface.numep = 0;
+ ei->interface.klass = 0;
+ ei->interface.subklass = 0;
+ ei->interface.protocol = 0;
+ while(*left + *read) {
+ remain = data[*offset]; // bLength
+ while(remain < 2) {
+ rcode = getone(pep, left, read, data, offset);
+ if(rcode)
+ return rcode;
+ remain = data[*offset];
+ }
+ rcode = getone(pep, left, read, data, offset);
+ if(rcode)
+ return rcode;
+ ty = data[*offset]; // bDescriptorType
+ HOST_DEBUG("bLength: %i ", remain);
+ HOST_DEBUG("bDescriptorType: %2.2x\r\n", ty);
+ remain--;
+ if(ty == USB_DESCRIPTOR_INTERFACE) {
+ HOST_DEBUG("INTERFACE DESCRIPTOR FOUND\r\n");
+ ptr = (uint8_t *)(&(ei->interface.bInterfaceNumber));
+ for(int i = 0; i < 6; i++) {
+ rcode = getone(pep, left, read, data, offset);
+ if(rcode)
+ return rcode;
+ *ptr = data[*offset];
+ ptr++;
+ }
+ rcode = getone(pep, left, read, data, offset);
+ if(rcode)
+ return rcode;
+ // Now at iInterface
+ // Get endpoints.
+ HOST_DEBUG("Getting %i endpoints\r\n", ei->interface.numep);
+ while(epc < ei->interface.numep) {
+ rcode = getone(pep, left, read, data, offset);
+ if(rcode) {
+ HOST_DEBUG("ENDPOINT DESCRIPTOR DIED WAY EARLY\r\n");
+ return rcode;
+ }
+ remain = data[*offset]; // bLength
+ while(remain < 2) {
+ rcode = getone(pep, left, read, data, offset);
+ if(rcode)
+ return rcode;
+ remain = data[*offset];
+ }
+ rcode = getone(pep, left, read, data, offset);
+ if(rcode) {
+ HOST_DEBUG("ENDPOINT DESCRIPTOR DIED EARLY\r\n");
+ return rcode;
+ }
+ ty = data[*offset]; // bDescriptorType
+ HOST_DEBUG("bLength: %i ", remain);
+ HOST_DEBUG("bDescriptorType: %2.2x\r\n", ty);
+ remain -= 2;
+ if(ty == USB_DESCRIPTOR_ENDPOINT) {
+ HOST_DEBUG("ENDPOINT DESCRIPTOR: %i\r\n", epc);
+ ptr = (uint8_t *)(&(ei->interface.epInfo[epc].bEndpointAddress));
+ for(unsigned int i = 0; i< sizeof (ENDPOINT_INFO); i++) {
+ rcode = getone(pep, left, read, data, offset);
+ if(rcode) {
+ HOST_DEBUG("ENDPOINT DESCRIPTOR DIED LATE\r\n");
+ return rcode;
+ }
+ *ptr = data[*offset];
+ ptr++;
+ remain--;
+ }
+ epc++;
+ HOST_DEBUG("ENDPOINT DESCRIPTOR OK\r\n");
+ }
+ rcode = eat(pep, left, read, data, offset, &remain);
+ if(rcode) {
+ HOST_DEBUG("ENDPOINT DESCRIPTOR DIED EATING\r\n");
+ return rcode;
+ }
+ remain = 0;
+ }
+ remain = 1;
+ // queue ahead, but do not report if error.
+ rcode = eat(pep, left, read, data, offset, &remain);
+ if(!ei->interface.numep && rcode) {
+ return rcode;
+ }
+ HOST_DEBUG("ENDPOINT DESCRIPTORS FILLED\r\n");
+ return 0;
+ } else {
+ rcode = eat(pep, left, read, data, offset, &remain);
+ if(rcode)
+ return rcode;
+ }
+ rcode = UHS_HOST_ERROR_END_OF_STREAM;
+ }
+ return rcode;
+}
+
+uint8_t UHS_USB_HOST_BASE::seekInterface(ENUMERATION_INFO *ei, uint16_t inf, USB_FD_CONFIGURATION_DESCRIPTOR *ucd) {
+ if(!ei || !ucd) return UHS_HOST_ERROR_BAD_ARGUMENT;
+ uint8_t data[ei->bMaxPacketSize0];
+ UHS_EpInfo *pep;
+ pep = ctrlReqOpen(ei->address, mkSETUP_PKT8(UHS_bmREQ_GET_DESCR, USB_REQUEST_GET_DESCRIPTOR, ei->currentconfig,
+ USB_DESCRIPTOR_CONFIGURATION, 0x0000U, ucd->wTotalLength), data);
+ if(!pep) return UHS_HOST_ERROR_NULL_EPINFO;
+ uint16_t left = ucd->wTotalLength;
+ uint8_t cinf = 0;
+ uint8_t ty;
+ uint8_t epc = 0;
+ uint16_t remain = ucd->bLength;
+ uint16_t read = 0;
+ uint8_t offset = remain;
+ uint8_t *ptr;
+ uint8_t rcode;
+ ei->interface.numep = 0;
+ ei->interface.klass = 0;
+ ei->interface.subklass = 0;
+ ei->interface.protocol = 0;
+ pep->maxPktSize = ei->bMaxPacketSize0;
+
+ rcode = getone(pep, &left, &read, data, &offset);
+ if(rcode)
+ return rcode;
+ HOST_DEBUG("\r\nGetting interface: %i\r\n", inf);
+ inf++;
+ while(cinf != inf && (left + read)) {
+ //HOST_DEBUG("getInterface: cinf: %i inf: %i left: %i read: %i offset: %i remain %i\r\n", cinf, inf, left, read, offset, remain);
+ // Go past current descriptor
+ HOST_DEBUG("Skip: %i\r\n", remain);
+ rcode = eat(pep, &left, &read, data, &offset, &remain);
+ if(rcode)
+ return rcode;
+ remain = data[offset]; // bLength
+ while(remain < 2) {
+ rcode = getone(pep, &left, &read, data, &offset);
+ if(rcode)
+ return rcode;
+ remain = data[offset];
+ }
+ rcode = getone(pep, &left, &read, data, &offset);
+ if(rcode)
+ return rcode;
+ ty = data[offset]; // bDescriptorType
+ HOST_DEBUG("bLength: %i ", remain);
+ HOST_DEBUG("bDescriptorType: %2.2x\r\n", ty);
+ remain--;
+ if(ty == USB_DESCRIPTOR_INTERFACE) {
+ HOST_DEBUG("INTERFACE DESCRIPTOR: %i\r\n", cinf);
+ cinf++;
+ if(cinf == inf) {
+ // Get the interface descriptor information.
+ ptr = (uint8_t *)(&(ei->interface.bInterfaceNumber));
+ for(int i = 0; i < 6; i++) {
+ rcode = getone(pep, &left, &read, data, &offset);
+ if(rcode)
+ return rcode;
+ *ptr = data[offset];
+ ptr++;
+ }
+ rcode = getone(pep, &left, &read, data, &offset);
+ if(rcode)
+ return rcode;
+ // Now at iInterface
+ remain = 0;
+ // Get endpoints.
+ HOST_DEBUG("Getting %i endpoints\r\n", ei->interface.numep);
+ while(epc < ei->interface.numep) {
+ rcode = getone(pep, &left, &read, data, &offset);
+ if(rcode)
+ return rcode;
+ remain = data[offset]; // bLength
+ while(remain < 2) {
+ rcode = getone(pep, &left, &read, data, &offset);
+ if(rcode)
+ return rcode;
+ remain = data[offset];
+ }
+ rcode = getone(pep, &left, &read, data, &offset);
+ if(rcode)
+ return rcode;
+ ty = data[offset]; // bDescriptorType
+ HOST_DEBUG("bLength: %i ", remain);
+ HOST_DEBUG("bDescriptorType: %2.2x\r\n", ty);
+ remain--;
+ if(ty == USB_DESCRIPTOR_ENDPOINT) {
+ HOST_DEBUG("ENDPOINT DESCRIPTOR: %i\r\n", epc);
+ ptr = (uint8_t *)(&(ei->interface.epInfo[epc].bEndpointAddress));
+ for(unsigned int i = 0; i< sizeof (ENDPOINT_INFO); i++) {
+ rcode = getone(pep, &left, &read, data, &offset);
+ if(rcode)
+ return rcode;
+ *ptr = data[offset];
+ ptr++;
+ }
+ epc++;
+ remain = 0;
+ } else {
+ rcode = eat(pep, &left, &read, data, &offset, &remain);
+ if(rcode)
+ return rcode;
+ remain = 0;
+ }
+ }
+ }
+ }
+ }
+
+ return ctrlReqClose(pep, UHS_bmREQ_GET_DESCR, left, ei->bMaxPacketSize0, data);
+}
+
+uint8_t UHS_USB_HOST_BASE::getone(UHS_EpInfo *pep, uint16_t *left, uint16_t *read, uint8_t *dataptr, uint8_t *offset) {
+ uint8_t rcode = 0;
+ *offset += 1;
+ if(*offset < *read) {
+ return 0;
+ } else if(*left > 0) {
+ // uint16_t num = *left;
+ uint16_t num = pep->maxPktSize;
+ if(num > *left) num = *left;
+ *offset = 0;
+ rcode = ctrlReqRead(pep, left, read, num, dataptr);
+ if(rcode == 0) {
+ if(*read == 0) {
+ rcode = UHS_HOST_ERROR_END_OF_STREAM;
+ } else if(*read < num) *left = 0;
+ }
+ } else {
+ rcode = UHS_HOST_ERROR_END_OF_STREAM;
+ }
+ return rcode;
+}
+
+uint8_t UHS_USB_HOST_BASE::eat(UHS_EpInfo *pep, uint16_t *left, uint16_t *read, uint8_t *dataptr, uint8_t *offset, uint16_t *yum) {
+ uint8_t rcode = 0;
+ HOST_DEBUG("eating %i\r\n", *yum);
+ while(*yum) {
+ *yum -= 1;
+ rcode = getone(pep, left, read, dataptr, offset);
+ if(rcode) break;
+ }
+ return rcode;
+}
+
+uint8_t UHS_USB_HOST_BASE::ctrlReq(uint8_t addr, uint64_t Request, uint16_t nbytes, uint8_t* dataptr) {
+ //bool direction = bmReqType & 0x80; //request direction, IN or OUT
+ uint8_t rcode = 0;
+
+ // Serial.println("");
+ UHS_EpInfo *pep = ctrlReqOpen(addr, Request, dataptr);
+ if(!pep) {
+ HOST_DEBUG("ctrlReq1: ERROR_NULL_EPINFO addr: %d\r\n", addr);
+ return UHS_HOST_ERROR_NULL_EPINFO;
+ }
+ uint8_t rt = (uint8_t)(Request & 0xFFU);
+
+ // Serial.println("Opened");
+ uint16_t left = (uint16_t)(Request >> 48) /*total*/;
+ if(dataptr != NULL) {
+ //data stage
+ if((rt & 0x80) == 0x80) {
+ //IN transfer
+ while(left) {
+ // Bytes read into buffer
+ uint16_t read = nbytes;
+ HOST_DEBUG("ctrlReq2: left: %i, read:%i, nbytes %i\r\n", left, read, nbytes);
+ rcode = ctrlReqRead(pep, &left, &read, nbytes, dataptr);
+
+#if UHS_DEVICE_WINDOWS_USB_SPEC_VIOLATION_DESCRIPTOR_DEVICE
+ HOST_DEBUG("RESULT: 0x%2.2x 0x%2.2x 0x%2.2x 0x%8.8lx%8.8lx\r\n", rcode, addr, read, (uint32_t)((Request>>32)&0xFFFFFFFFLU), (uint32_t)(Request&0xFFFFFFFFLU));
+ // Should only be used for GET_DESCRIPTOR USB_DESCRIPTOR_DEVICE
+ constexpr uint32_t req_match = ((uint32_t)USB_DESCRIPTOR_DEVICE << 24) |
+ ((uint32_t)USB_REQUEST_GET_DESCRIPTOR << 8);
+ const uint32_t req_found = Request & 0xFF00FF00ul;
+ if(!addr && read && (req_found == req_match)) {
+ HOST_DEBUG("ctrlReq3: acceptBuffer sz %i nbytes %i left %i\n\r", read, nbytes, left);
+ left = 0;
+ rcode = UHS_HOST_ERROR_NONE;
+ break;
+ }
+#endif
+ if(rcode) {
+ return rcode;
+ }
+ }
+ } else {
+ // OUT transfer
+ rcode = OutTransfer(pep, 0, nbytes, dataptr);
+ }
+ if(rcode) {
+ //return error
+ return ( rcode);
+ }
+ }
+
+ // Serial.println("Close Phase");
+ // Serial.flush();
+ // Status stage
+ rcode = ctrlReqClose(pep, rt, left, nbytes, dataptr);
+ // Serial.println("Closed");
+ return rcode;
+}
+
+uint8_t UHS_USB_HOST_BASE::EPClearHalt(uint8_t addr, uint8_t ep) {
+ return ctrlReq(addr, mkSETUP_PKT8(USB_SETUP_HOST_TO_DEVICE | USB_SETUP_TYPE_STANDARD | USB_SETUP_RECIPIENT_ENDPOINT, USB_REQUEST_CLEAR_FEATURE, USB_FEATURE_ENDPOINT_HALT, 0, ep, 0), 0, NULL);
+}
+
+uint8_t UHS_USB_HOST_BASE::TestInterface(ENUMERATION_INFO *ei) {
+
+ uint8_t devConfigIndex;
+ uint8_t rcode = 0;
+ HOST_DEBUG("TestInterface VID:%4.4x PID:%4.4x Class:%2.2x Subclass:%2.2x Protocol %2.2x\r\n", ei->vid, ei->pid, ei->klass, ei->subklass, ei->protocol);
+ HOST_DEBUG("Interface data: Class:%2.2x Subclass:%2.2x Protocol %2.2x, number of endpoints %i\r\n", ei->interface.klass, ei->interface.subklass, ei->interface.subklass, ei->interface.numep);
+ HOST_DEBUG("Parent: %2.2x, bAddress: %2.2x\r\n", ei->parent, ei->address);
+ for(devConfigIndex = 0; devConfigIndex < UHS_HOST_MAX_INTERFACE_DRIVERS; devConfigIndex++) {
+ if(!devConfig[devConfigIndex]) {
+ HOST_DEBUG("No driver at index %i\r\n", devConfigIndex);
+ continue; // no driver
+ }
+ if(devConfig[devConfigIndex]->bAddress) {
+ HOST_DEBUG("Driver %i is already consumed @ %2.2x\r\n", devConfigIndex, devConfig[devConfigIndex]->bAddress);
+ continue; // consumed
+ }
+
+ if(devConfig[devConfigIndex]->OKtoEnumerate(ei)) {
+ HOST_DEBUG("Driver %i supports this interface\r\n", devConfigIndex);
+ break;
+ }
+ }
+ if(devConfigIndex == UHS_HOST_MAX_INTERFACE_DRIVERS) {
+ rcode = UHS_HOST_ERROR_DEVICE_NOT_SUPPORTED;
+#if 0 // defined(UHS_HID_LOADED)
+ // Check HID here, if it is, then lie
+ if(ei->klass == UHS_USB_CLASS_HID) {
+ devConfigIndex = UHS_HID_INDEX; // for debugging, otherwise this has no use.
+ rcode = 0;
+ }
+#endif
+ }
+ if(!rcode) HOST_DEBUG("Driver %i can be used for this interface\r\n", devConfigIndex);
+ else HOST_DEBUG("No driver for this interface.\r\n");
+ return rcode;
+};
+
+uint8_t UHS_USB_HOST_BASE::enumerateInterface(ENUMERATION_INFO *ei) {
+ uint8_t devConfigIndex;
+
+ HOST_DEBUG("AttemptConfig: parent = %i, port = %i\r\n", ei->parent, ei->port);
+
+#if 0 // defined(UHS_HID_LOADED)
+ // Check HID here, if it is, then lie
+ if(ei->klass == UHS_USB_CLASS_HID || ei->interface.klass == UHS_USB_CLASS_HID) {
+ UHS_HID_SetUSBInterface(this, ENUMERATION_INFO * ei);
+ devConfigIndex = UHS_HID_INDEX;
+ } else
+#endif
+ for(devConfigIndex = 0; devConfigIndex < UHS_HOST_MAX_INTERFACE_DRIVERS; devConfigIndex++) {
+ if(!devConfig[devConfigIndex]) {
+ HOST_DEBUG("No driver at index %i\r\n", devConfigIndex);
+ continue; // no driver
+ }
+ if(devConfig[devConfigIndex]->bAddress) {
+ HOST_DEBUG("Driver %i is already consumed @ %2.2x\r\n", devConfigIndex, devConfig[devConfigIndex]->bAddress);
+ continue; // consumed
+ }
+
+ if(devConfig[devConfigIndex]->OKtoEnumerate(ei)) {
+ HOST_DEBUG("Driver %i supports this interface\r\n", devConfigIndex);
+ if(!devConfig[devConfigIndex]->SetInterface(ei)) break;
+ else devConfigIndex = UHS_HOST_MAX_INTERFACE_DRIVERS;
+ }
+ }
+ return devConfigIndex;
+};
+
+
+////////////////////////////////////////////////////////////////////////////////
+// Vendor Specific Interface Class
+////////////////////////////////////////////////////////////////////////////////
+
+#if 0
+/**
+ * Might go away, depends on if it is useful, or not.
+ *
+ * @param ei Enumeration information
+ * @return true if this interface driver can handle this interface description
+ */
+bool UHS_NI UHS_VSI::OKtoEnumerate(ENUMERATION_INFO *ei) {
+ return (
+ (ei->subklass == UHS_USB_CLASS_VENDOR_SPECIFIC) ||
+ (ei->interface.subklass == UHS_USB_CLASS_VENDOR_SPECIFIC)
+ );
+}
+
+/**
+ * Copy the entire ENUMERATION_INFO structure
+ * @param ei Enumeration information
+ * @return 0
+ */
+uint8_t UHS_NI UHS_VSI::SetInterface(ENUMERATION_INFO *ei) {
+ bNumEP = 1;
+ bAddress = ei->address;
+
+ eInfo.address = ei->address;
+ eInfo.bMaxPacketSize0 = ei->bMaxPacketSize0;
+ eInfo.currentconfig = ei->currentconfig;
+ eInfo.interface.bAlternateSetting = ei->interface.bAlternateSetting;
+ eInfo.interface.bInterfaceNumber = ei->interface.bInterfaceNumber;
+ eInfo.interface.numep = ei->interface.numep;
+ eInfo.interface.protocol = ei->interface.protocol;
+ eInfo.interface.subklass = ei->interface.subklass;
+ eInfo.klass = ei->klass;
+ eInfo.parent = ei->parent;
+ eInfo.pid = ei->pid;
+ eInfo.port = ei->port;
+ eInfo.protocol = ei->protocol;
+ eInfo.subklass = ei->subklass;
+ eInfo.vid = ei->vid;
+ for(uint8_t i = 0; i < eInfo.interface.numep; i++) {
+ eInfo.interface.epInfo[i].bEndpointAddress = ei->interface.epInfo[i].bEndpointAddress;
+ eInfo.interface.epInfo[i].bInterval = ei->interface.epInfo[i].bInterval;
+ eInfo.interface.epInfo[i].bmAttributes = ei->interface.epInfo[i].bmAttributes;
+ eInfo.interface.epInfo[i].wMaxPacketSize = ei->interface.epInfo[i].wMaxPacketSize;
+ }
+ return 0;
+}
+#endif
+
+////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+
+
+#if 0
+
+/* TO-DO: Move this silliness to a NONE driver.
+ * When we have a generic NONE driver we can:
+ * o Extract ALL device information to help users with a new device.
+ * o Use an unknown device from a sketch, kind of like usblib does.
+ * This will aid in making more drivers in a faster way.
+ */
+uint8_t UHS_USB_HOST_BASE::DefaultAddressing(uint8_t parent, uint8_t port, uint8_t speed) {
+ uint8_t rcode;
+ UHS_Device *p0 = NULL, *p = NULL;
+
+ // Get pointer to pseudo device with address 0 assigned
+ p0 = addrPool.GetUsbDevicePtr(0);
+
+ if(!p0)
+ return UHS_HOST_ERROR_NO_ADDRESS_IN_POOL;
+
+ if(!p0->epinfo)
+ return UHS_HOST_ERROR_NULL_EPINFO;
+
+ p0->speed = speed;
+
+ // Allocate new address according to device class
+ uint8_t bAddress = addrPool.AllocAddress(parent, false, port);
+
+ if(!bAddress)
+ return UHS_HOST_ERROR_ADDRESS_POOL_FULL;
+
+ p = addrPool.GetUsbDevicePtr(bAddress);
+
+ if(!p)
+ return UHS_HOST_ERROR_NO_ADDRESS_IN_POOL;
+
+ p->speed = speed;
+
+ // Assign new address to the device
+ rcode = setAddr(0, bAddress);
+
+ if(rcode) {
+ addrPool.FreeAddress(bAddress);
+ bAddress = 0;
+ return rcode;
+ }
+ return 0;
+}
+#endif
+
+#else
+#error "Never include UHS_host_INLINE.h, include UHS_host.h instead"
+#endif
diff --git a/Marlin/src/sd/usb_flashdrive/lib-uhs3/UHS_host/UHS_macros.h b/Marlin/src/sd/usb_flashdrive/lib-uhs3/UHS_host/UHS_macros.h
new file mode 100644
index 0000000..fb2e8b3
--- /dev/null
+++ b/Marlin/src/sd/usb_flashdrive/lib-uhs3/UHS_host/UHS_macros.h
@@ -0,0 +1,230 @@
+/* Copyright (C) 2015-2016 Andrew J. Kroll
+ and
+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 : https://www.circuitsathome.com
+e-mail : support@circuitsathome.com
+ */
+
+#ifndef MACROS_H
+#define MACROS_H
+#include "macro_logic.h"
+/*
+ * Universal Arduino(tm) "IDE" fixups.
+ */
+
+
+// Just in case...
+#ifndef SERIAL_PORT_MONITOR
+#define SERIAL_PORT_MONITOR Serial
+#endif
+
+#ifndef INT16_MIN
+#define INT16_MIN -32768
+#endif
+// require 10607+
+#if defined(ARDUINO) && ARDUINO >=10607
+// nop :-)
+#else
+#error "Arduino version too old, and must be at least 1.6.7"
+#endif
+
+// Nuke screwed up macro junk from the IDE.
+#ifdef __cplusplus
+#ifdef true
+#undef true
+#endif
+#ifdef false
+#undef false
+#endif
+#endif
+
+
+#ifndef UHS_DEVICE_WINDOWS_USB_SPEC_VIOLATION_DESCRIPTOR_DEVICE
+
+#ifndef UHS_BIG_FLASH
+
+#if defined(FLASHEND) && defined(FLASHSTART)
+#if (FLASHEND - FLASHSTART) > 0x0FFFFU
+#define UHS_BIG_FLASH 1
+#else
+#define UHS_BIG_FLASH 0
+#endif
+
+#elif defined(__PIC32_FLASH_SIZE)
+#if __PIC32_FLASH_SIZE > 511
+#define UHS_BIG_FLASH 1
+#else
+#define UHS_BIG_FLASH 0
+#endif
+
+#elif defined(FLASHEND) && !defined(FLASHSTART)
+// Assumes flash starts at 0x00000, is this a safe assumption?
+// 192K + should be OK
+#if FLASHEND > 0x02FFFFU
+#define UHS_BIG_FLASH 1
+#else
+#define UHS_BIG_FLASH 0
+#endif
+
+#elif defined(IFLASH_SIZE)
+#if IFLASH_SIZE > 0x0FFFFU
+#define UHS_BIG_FLASH 1
+#else
+#define UHS_BIG_FLASH 0
+#endif
+
+#elif defined(ESP8266)
+#define UHS_BIG_FLASH 1
+#define SYSTEM_OR_SPECIAL_YIELD(...) yield()
+
+#elif defined(__arm__) && defined(CORE_TEENSY)
+#define UHS_BIG_FLASH 1
+
+#elif defined(ARDUINO_spresense_ast)
+#define UHS_BIG_FLASH 1
+#else
+// safe default
+#warning Small flash?
+#define UHS_BIG_FLASH 0
+#endif
+#endif
+
+#if UHS_BIG_FLASH
+#define UHS_DEVICE_WINDOWS_USB_SPEC_VIOLATION_DESCRIPTOR_DEVICE 1
+#else
+#define UHS_DEVICE_WINDOWS_USB_SPEC_VIOLATION_DESCRIPTOR_DEVICE 0
+#endif
+#endif
+
+#if defined(__arm__) && defined(CORE_TEENSY)
+#define UHS_PIN_WRITE(p, v) digitalWriteFast(p, v)
+#define UHS_PIN_READ(p) digitalReadFast(p)
+#endif
+// TODO: Fast inline code for AVR and SAM based microcontrollers
+// This can be done pretty easily.
+// For now, this will just work out-of-the-box.
+#ifndef UHS_PIN_WRITE
+#define UHS_PIN_WRITE(p, v) digitalWrite(p, v)
+#endif
+#ifndef UHS_PIN_READ
+#define UHS_PIN_READ(p) digitalRead(p)
+#endif
+
+#if defined( __PIC32MX__ ) && !defined(interrupts) // compiling with Microchip XC32 compiler
+#define interrupts() __builtin_enable_interrupts()
+#edfine noInterrupts() __builtin_disable_interrupts()
+#endif
+
+#ifndef ARDUINO_SAMD_ZERO
+#ifdef ARDUINO_AVR_ADK
+#define UHS_GET_DPI(x) (x == 54 ? 6 : digitalPinToInterrupt(x))
+#else
+#define UHS_GET_DPI(x) digitalPinToInterrupt(x)
+#endif
+#else
+#define UHS_GET_DPI(x) (x)
+#endif
+
+#include "../../../../HAL/shared/progmem.h"
+
+////////////////////////////////////////////////////////////////////////////////
+// HANDY MACROS
+////////////////////////////////////////////////////////////////////////////////
+
+// Atmoically set/clear single bits using bitbands.
+// Believe it or not, this boils down to a constant,
+// and is less code than using |= &= operators.
+// Bonus, it makes code easier to read too.
+// Bitbanding is a wonderful thing.
+#define BITNR(i) (i&0x1?0:i&0x2?1:i&0x4?2:i&0x8?3:i&0x10?4:i&0x20?5:i&0x40?6:i&0x80?7:i&0x100?8:i&0x200?9:i&0x400?10:i&0x800?11:i&0x1000?12:i&0x2000?13:i&0x4000?14:i&0x8000?15:i&0x10000?16:i&0x20000?17:i&0x40000?18:i&0x80000?19:i&0x100000?20:i&0x200000?21:i&0x400000?22:i&0x800000?23:i&0x1000000?24:i&0x2000000?25:i&0x4000000?26:i&0x8000000?27:i&0x10000000?28:i&0x20000000?29:i&0x40000000?30:i&0x80000000?31:32)
+#define UHS_KIO_BITBAND_ADDR(r, i) (((uint32_t)&(r) - 0x40000000) * 32 + (i) * 4 + 0x42000000)
+#define UHS_KIO_SETBIT_ATOMIC(r, m) (*(uint32_t *)UHS_KIO_BITBAND_ADDR((r), BITNR((m)))) = 1
+#define UHS_KIO_CLRBIT_ATOMIC(r, m) (*(uint32_t *)UHS_KIO_BITBAND_ADDR((r), BITNR((m)))) = 0
+
+
+#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 UHS_SWAP_VALUES(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 UHS_UINT8_BYTE0(__usi__) (((uint8_t *)&(__usi__))[0])
+#define UHS_UINT8_BYTE1(__usi__) (((uint8_t *)&(__usi__))[1])
+#define UHS_UINT8_BYTE2(__usi__) (((uint8_t *)&(__usi__))[2])
+#define UHS_UINT8_BYTE3(__usi__) (((uint8_t *)&(__usi__))[3])
+#define UHS_UINT8_BYTE4(__usi__) (((uint8_t *)&(__usi__))[4])
+#define UHS_UINT8_BYTE5(__usi__) (((uint8_t *)&(__usi__))[5])
+#define UHS_UINT8_BYTE6(__usi__) (((uint8_t *)&(__usi__))[6])
+#define UHS_UINT8_BYTE7(__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 UHS_UINT8_BYTE0(__usi__) ((uint8_t)((__usi__) & 0xFF ))
+#define UHS_UINT8_BYTE1(__usi__) ((uint8_t)(((__usi__) >> 8) & 0xFF))
+#define UHS_UINT8_BYTE2(__usi__) ((uint8_t)(((__usi__) >> 16) & 0xFF))
+#define UHS_UINT8_BYTE3(__usi__) ((uint8_t)(((__usi__) >> 24) & 0xFF))
+#define UHS_UINT8_BYTE4(__usi__) ((uint8_t)(((__usi__) >> 32) & 0xFF))
+#define UHS_UINT8_BYTE5(__usi__) ((uint8_t)(((__usi__) >> 40) & 0xFF))
+#define UHS_UINT8_BYTE6(__usi__) ((uint8_t)(((__usi__) >> 48) & 0xFF))
+#define UHS_UINT8_BYTE7(__usi__) ((uint8_t)(((__usi__) >> 56) & 0xFF))
+#endif
+#define UHS_UINT16_SET_BYTE1(__usi__) ((uint16_t)(__usi__) << 8)
+#define UHS_UINT32_SET_BYTE1(__usi__) ((uint32_t)(__usi__) << 8)
+#define UHS_UINT64_SET_BYTE1(__usi__) ((uint64_t)(__usi__) << 8)
+#define UHS_UINT32_SET_BYTE2(__usi__) ((uint32_t)(__usi__) << 16)
+#define UHS_UINT64_SET_BYTE2(__usi__) ((uint64_t)(__usi__) << 16)
+#define UHS_UINT32_SET_BYTE3(__usi__) ((uint32_t)(__usi__) << 24)
+#define UHS_UINT64_SET_BYTE3(__usi__) ((uint64_t)(__usi__) << 24)
+#define UHS_UINT64_SET_BYTE4(__usi__) ((uint64_t)(__usi__) << 32)
+#define UHS_UINT64_SET_BYTE5(__usi__) ((uint64_t)(__usi__) << 40)
+#define UHS_UINT64_SET_BYTE6(__usi__) ((uint64_t)(__usi__) << 48)
+#define UHS_UINT64_SET_BYTE7(__usi__) ((uint64_t)(__usi__) << 56)
+
+// These are the smallest and fastest ways I have found so far in pure C/C++.
+#define UHS_BYTES_TO_UINT16(__usc1__,__usc0__) ((uint16_t)((uint16_t)(__usc0__) | (uint16_t)UHS_UINT16_SET_BYTE1(__usc1__)))
+#define UHS_BYTES_TO_UINT32(__usc3__,__usc2__,__usc1__,__usc0__) ((uint32_t)((uint32_t)(__usc0__) | UHS_UINT32_SET_BYTE1(__usc1__) | UHS_UINT32_SET_BYTE2(__usc2__) | UHS_UINT32_SET_BYTE3(__usc3__)))
+#define UHS_BYTES_TO_UINT64(__usc7__,__usc6__,__usc5__,__usc4__,__usc3__,__usc2__,__usc1__,__usc0__) ((uint64_t)((uint64_t)__usc0__ | UHS_UINT64_SET_BYTE1(__usc1__) | UHS_UINT64_SET_BYTE2(__usc2__) | UHS_UINT64_SET_BYTE3(__usc3__) | UHS_UINT64_SET_BYTE4(__usc4__) | UHS_UINT64_SET_BYTE5(__usc5__) | UHS_UINT64_SET_BYTE6(__usc6__) | UHS_UINT64_SET_BYTE7(__usc7__)))
+#endif
+/*
+ * Debug macros.
+ * Useful when porting from UHS2.
+ * Do not use these for any new code.
+ * Change to better debugging after port is completed.
+ * Strings are stored in progmem (flash) instead of RAM.
+ */
+#define USBTRACE1(s,l) (Notify(PSTR(s), l))
+#define USBTRACE(s) (USBTRACE1((s), 0x80)); USB_HOST_SERIAL.flush()
+#define USBTRACE3(s,r,l) (Notify(PSTR(s), l), D_PrintHex((r), l), Notify(PSTR("\r\n"), l))
+#define USBTRACE3X(s,r,l) (Notify(PSTR(s), l), D_PrintHex((r), l))
+#define USBTRACE2(s,r) (USBTRACE3((s),(r),0x80)); USB_HOST_SERIAL.flush()
+#define USBTRACE2X(s,r) (USBTRACE3X((s),(r),0x80)); USB_HOST_SERIAL.flush()
+
+#define VOID0 ((void)0)
+#ifndef NOTUSED
+#define NOTUSED(...) __VA_ARGS__ __attribute__((unused))
+#endif
+#endif /* MACROS_H */
diff --git a/Marlin/src/sd/usb_flashdrive/lib-uhs3/UHS_host/UHS_message.h b/Marlin/src/sd/usb_flashdrive/lib-uhs3/UHS_host/UHS_message.h
new file mode 100644
index 0000000..c0cc78d
--- /dev/null
+++ b/Marlin/src/sd/usb_flashdrive/lib-uhs3/UHS_host/UHS_message.h
@@ -0,0 +1,91 @@
+/* Copyright (C) 2015-2016 Andrew J. Kroll
+ and
+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 : https://www.circuitsathome.com
+e-mail : support@circuitsathome.com
+ */
+#if !defined(_UHS_host_h_) || defined(__MESSAGE_H__)
+#error "Never include UHS_message.h directly; include UHS_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 NotifyFailSetDevTblEntry();
+void NotifyFailGetConfDescr();
+void NotifyFailSetConfDescr();
+void NotifyFailUnknownDevice(uint16_t VID, uint16_t PID);
+void NotifyFail(uint8_t rcode);
+#else
+#define Notify(...) VOID0
+#define NotifyStr(...) VOID0
+#define Notifyc(...) VOID0
+#define NotifyFailGetDevDescr(...) VOID0
+#define NotifyFailSetDevTblEntry(...) VOID0
+#define NotifyFailGetConfDescr(...) VOID0
+#define NotifyFailGetDevDescr(...) VOID0
+#define NotifyFailSetDevTblEntry(...) VOID0
+#define NotifyFailGetConfDescr(...) VOID0
+#define NotifyFailSetConfDescr(...) VOID0
+#define NotifyFailUnknownDevice(...) VOID0
+#define NotifyFail(...) VOID0
+#endif
+
+#ifdef DEBUG_USB_HOST
+template <class ERROR_TYPE> void ErrorMessage(uint8_t level, char const * msg, ERROR_TYPE rcode = 0) {
+ Notify(msg, level);
+ Notify(PSTR(": "), level);
+ D_PrintHex<ERROR_TYPE > (rcode, level);
+ Notify(PSTR("\r\n"), level);
+#else
+template <class ERROR_TYPE> void ErrorMessage(NOTUSED(uint8_t level), NOTUSED(char const * msg), ERROR_TYPE rcode = 0) {
+ (void)rcode;
+#endif
+}
+
+#ifdef DEBUG_USB_HOST
+template <class ERROR_TYPE> void ErrorMessage(char const * msg, ERROR_TYPE rcode = 0) {
+ Notify(msg, 0x80);
+ Notify(PSTR(": "), 0x80);
+ D_PrintHex<ERROR_TYPE > (rcode, 0x80);
+ Notify(PSTR("\r\n"), 0x80);
+#else
+template <class ERROR_TYPE> void ErrorMessage(NOTUSED(char const * msg), ERROR_TYPE rcode = 0) {
+ (void)rcode;
+#endif
+}
+
+#endif // __MESSAGE_H__
diff --git a/Marlin/src/sd/usb_flashdrive/lib-uhs3/UHS_host/UHS_printf_HELPER.h b/Marlin/src/sd/usb_flashdrive/lib-uhs3/UHS_host/UHS_printf_HELPER.h
new file mode 100644
index 0000000..4fc9b94
--- /dev/null
+++ b/Marlin/src/sd/usb_flashdrive/lib-uhs3/UHS_host/UHS_printf_HELPER.h
@@ -0,0 +1,200 @@
+/* Copyright (C) 2015-2016 Andrew J. Kroll
+ and
+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 : https://www.circuitsathome.com
+e-mail : support@circuitsathome.com
+ */
+
+#ifndef UHS_PRINTF_HELPER_H
+#define UHS_PRINTF_HELPER_H
+
+#ifdef LOAD_UHS_PRINTF_HELPER
+#include <Arduino.h>
+#ifdef true
+#undef true
+#endif
+#ifdef false
+#undef false
+#endif
+
+#ifndef STDIO_IS_OK_TO_USE_AS_IS
+#if defined(ARDUINO_SAMD_ZERO) || defined(ARDUINO_SAM_DUE) || defined(ARDUINO_spresense_ast)
+// STDIO patching not required.
+#define STDIO_IS_OK_TO_USE_AS_IS
+#endif
+#endif
+
+#ifndef STDIO_IS_OK_TO_USE_AS_IS
+// We need to patch STDIO so it can be used.
+
+#ifndef SERIAL_PORT_MONITOR
+// Some don't define this.
+#define SERIAL_PORT_MONITOR Serial
+#endif
+
+#ifndef SERIAL_PORT_HARDWARE
+// Some don't define this.
+#define SERIAL_PORT_HARDWARE SERIAL_PORT_MONITOR
+#endif
+
+#ifndef USB_HOST_SERIAL
+#if defined(SERIAL_PORT_USBVIRTUAL) && defined(LOAD_UHS_KINETIS_FS_HOST)
+#define USB_HOST_SERIAL SERIAL_PORT_HARDWARE
+#else
+#define USB_HOST_SERIAL SERIAL_PORT_MONITOR
+#endif
+#endif
+
+#ifndef NOTUSED
+#define NOTUSED(...) __VA_ARGS__ __attribute__((unused))
+#endif
+
+#ifndef __AVR__
+#ifndef printf_P
+#define printf_P(...) printf(__VA_ARGS__)
+#endif
+#endif
+
+#ifdef ARDUINO_ARCH_PIC32
+/*
+ * For printf() output with pic32 Arduino
+ */
+extern "C" {
+
+ void _mon_putc(char s) {
+ USB_HOST_SERIAL.write(s);
+ }
+
+ int _mon_getc() {
+ while(!USB_HOST_SERIAL.available());
+ return USB_HOST_SERIAL.read();
+ }
+}
+
+#elif defined(__AVR__)
+extern "C" {
+
+ static FILE tty_stdio;
+ static FILE tty_stderr;
+
+ static int NOTUSED(tty_stderr_putc(char c, NOTUSED(FILE *t)));
+ static int NOTUSED(tty_stderr_flush(NOTUSED(FILE *t)));
+ static int NOTUSED(tty_std_putc(char c, NOTUSED(FILE *t)));
+ static int NOTUSED(tty_std_getc(NOTUSED(FILE *t)));
+ static int NOTUSED(tty_std_flush(NOTUSED(FILE *t)));
+
+ static int tty_stderr_putc(char c, NOTUSED(FILE *t)) {
+ USB_HOST_SERIAL.write(c);
+ return 0;
+ }
+
+ static int tty_stderr_flush(NOTUSED(FILE *t)) {
+ USB_HOST_SERIAL.flush();
+ return 0;
+ }
+
+ static int tty_std_putc(char c, NOTUSED(FILE *t)) {
+ USB_HOST_SERIAL.write(c);
+ return 0;
+ }
+
+ static int tty_std_getc(NOTUSED(FILE *t)) {
+ while(!USB_HOST_SERIAL.available());
+ return USB_HOST_SERIAL.read();
+ }
+
+ static int tty_std_flush(NOTUSED(FILE *t)) {
+ USB_HOST_SERIAL.flush();
+ return 0;
+ }
+}
+#elif defined(CORE_TEENSY)
+extern "C" {
+
+ int _write(int fd, const char *ptr, int len) {
+ int j;
+ for(j = 0; j < len; j++) {
+ if(fd == 1)
+ USB_HOST_SERIAL.write(*ptr++);
+ else if(fd == 2)
+ USB_HOST_SERIAL.write(*ptr++);
+ }
+ return len;
+ }
+
+ int _read(int fd, char *ptr, int len) {
+ if(len > 0 && fd == 0) {
+ while(!USB_HOST_SERIAL.available());
+ *ptr = USB_HOST_SERIAL.read();
+ return 1;
+ }
+ return 0;
+ }
+
+#include <sys/stat.h>
+
+ int _fstat(int fd, struct stat *st) {
+ memset(st, 0, sizeof (*st));
+ st->st_mode = S_IFCHR;
+ st->st_blksize = 1024;
+ return 0;
+ }
+
+ int _isatty(int fd) {
+ return (fd < 3) ? 1 : 0;
+ }
+}
+#else
+#error no STDIO
+#endif // defined(ARDUINO_ARCH_PIC32)
+
+
+
+#ifdef __AVR__
+// The only wierdo in the bunch...
+void UHS_AVR_printf_HELPER_init() {
+ // Set up stdio/stderr
+ tty_stdio.put = tty_std_putc;
+ tty_stdio.get = tty_std_getc;
+ tty_stdio.flags = _FDEV_SETUP_RW;
+ tty_stdio.udata = 0;
+
+ tty_stderr.put = tty_stderr_putc;
+ tty_stderr.get = NULL;
+ tty_stderr.flags = _FDEV_SETUP_WRITE;
+ tty_stderr.udata = 0;
+
+ stdout = &tty_stdio;
+ stdin = &tty_stdio;
+ stderr = &tty_stderr;
+
+}
+#define UHS_printf_HELPER_init() UHS_AVR_printf_HELPER_init()
+#endif
+
+#endif /* STDIO_IS_OK_TO_USE_AS_IS */
+#endif /* load.... */
+
+#ifndef UHS_printf_HELPER_init
+#define UHS_printf_HELPER_init() (void(0))
+#endif
+#endif /* UHS_PRINTF_HELPER_H */
diff --git a/Marlin/src/sd/usb_flashdrive/lib-uhs3/UHS_host/UHS_printhex.h b/Marlin/src/sd/usb_flashdrive/lib-uhs3/UHS_host/UHS_printhex.h
new file mode 100644
index 0000000..bfa052b
--- /dev/null
+++ b/Marlin/src/sd/usb_flashdrive/lib-uhs3/UHS_host/UHS_printhex.h
@@ -0,0 +1,96 @@
+/* Copyright (C) 2015-2016 Andrew J. Kroll
+ and
+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 : https://www.circuitsathome.com
+e-mail : support@circuitsathome.com
+ */
+
+#if !defined(_UHS_host_h_) || defined(__PRINTHEX_H__)
+#error "Never include UHS_printhex.h directly; include UHS_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);
+}
+
+#ifdef DEBUG_USB_HOST
+template <class T> void D_PrintHex(T val, int lvl) {
+ PrintHex<T > (val, lvl);
+#else
+template <class T> void D_PrintHex(NOTUSED(T val), NOTUSED(int lvl)) {
+#endif
+}
+
+#ifdef DEBUG_USB_HOST
+template <class T> void D_PrintBin(T val, int lvl) {
+ PrintBin<T > (val, lvl);
+#else
+template <class T> void D_PrintBin(NOTUSED(T val), NOTUSED(int lvl)) {
+#endif
+}
+
+
+
+#endif // __PRINTHEX_H__
diff --git a/Marlin/src/sd/usb_flashdrive/lib-uhs3/UHS_host/UHS_settings.h b/Marlin/src/sd/usb_flashdrive/lib-uhs3/UHS_host/UHS_settings.h
new file mode 100644
index 0000000..c516599
--- /dev/null
+++ b/Marlin/src/sd/usb_flashdrive/lib-uhs3/UHS_host/UHS_settings.h
@@ -0,0 +1,141 @@
+/* Copyright (C) 2015-2016 Andrew J. Kroll
+ and
+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 : https://www.circuitsathome.com
+e-mail : support@circuitsathome.com
+ */
+
+#ifndef UHS_SETTINGS_H
+#define UHS_SETTINGS_H
+
+// TO-DO: Move specific settings to modules which use them.
+
+////////////////////////////////////////////////////////////////////////////////
+// Define any of these options at the top of your sketch to override
+// the defaults contained herewith. Do NOT do modifications here.
+// Individual Components have their own settings.
+//
+// Macro | Settings and notes | Default
+// -----------------------------+-----------------------+-----------------------
+// | Any class that does |
+// USB_HOST_SERIAL | text streaming | SERIAL_PORT_MONITOR
+// | e.g. Serial2 |
+// -----------------------------+-----------------------+-----------------------
+// ENABLE_UHS_DEBUGGING | 0 = off, 1 = on | 0
+// -----------------------------+-----------------------+-----------------------
+// | 0 = off, 1 = on |
+// | Caution! Can make |
+// DEBUG_PRINTF_EXTRA_HUGE | program too large! | 0
+// | Other modules depend |
+// | on this setting. |
+// -----------------------------+-----------------------+-----------------------
+// USE_UHS_BLACK_WIDDOW | 0 = no, 1 = yes | 0
+// -----------------------------+-----------------------+-----------------------
+// ENABLE_WII_IR_CAMERA | 0 = no, 1 = yes | 0
+// -----------------------------^-----------------------^-----------------------
+//
+////////////////////////////////////////////////////////////////////////////////
+
+
+////////////////////////////////////////////////////////////////////////////////
+// DEBUGGING
+////////////////////////////////////////////////////////////////////////////////
+
+#ifndef USB_HOST_SERIAL
+#if defined(SERIAL_PORT_USBVIRTUAL) && defined(LOAD_UHS_KINETIS_FS_HOST)
+#define USB_HOST_SERIAL SERIAL_PORT_HARDWARE
+#else
+#define USB_HOST_SERIAL SERIAL_PORT_MONITOR
+#endif
+#endif
+
+#ifndef ENABLE_UHS_DEBUGGING
+#define ENABLE_UHS_DEBUGGING 0
+#endif
+
+#ifndef DEBUG_PRINTF_EXTRA_HUGE
+#define DEBUG_PRINTF_EXTRA_HUGE 0
+#endif
+
+////////////////////////////////////////////////////////////////////////////////
+// Manual board activation
+////////////////////////////////////////////////////////////////////////////////
+
+/* Set this to 1 if you are using a Black Widdow */
+#ifndef USE_UHS_BLACK_WIDDOW
+#define USE_UHS_BLACK_WIDDOW 0
+#endif
+
+////////////////////////////////////////////////////////////////////////////////
+// Wii IR camera
+////////////////////////////////////////////////////////////////////////////////
+
+/* Set this to 1 to activate code for the Wii IR camera */
+#ifndef ENABLE_WII_IR_CAMERA
+#define ENABLE_WII_IR_CAMERA 0
+#endif
+
+////////////////////////////////////////////////////////////////////////////////
+// Set to 1 to use the faster spi4teensy3 driver. (not used yet))
+////////////////////////////////////////////////////////////////////////////////
+#ifndef 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!
+
+#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 https://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
+
+#define UHS_SLEEP_MS(v) pUsb->sof_delay(v)
+
+#ifndef UHS_NI
+#define UHS_NI __attribute__((noinline))
+#endif
+
+#endif /* SETTINGS_H */
diff --git a/Marlin/src/sd/usb_flashdrive/lib-uhs3/UHS_host/UHS_usb_ch9.h b/Marlin/src/sd/usb_flashdrive/lib-uhs3/UHS_host/UHS_usb_ch9.h
new file mode 100644
index 0000000..6486482
--- /dev/null
+++ b/Marlin/src/sd/usb_flashdrive/lib-uhs3/UHS_host/UHS_usb_ch9.h
@@ -0,0 +1,222 @@
+/* Copyright (C) 2015-2016 Andrew J. Kroll
+ and
+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 : https://www.circuitsathome.com
+e-mail : support@circuitsathome.com
+ */
+
+#if !defined(_UHS_host_h_) || defined(_UHS_ch9_h_)
+#error "Never include UHS_usb_ch9.h directly; include UHS_Usb.h instead"
+#else
+
+/* USB chapter 9 structures */
+#define _UHS_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
+
+/* Wireless USB Device Requests */
+#define USB_REQ_SET_ENCRYPTION 0x0D
+#define USB_REQ_GET_ENCRYPTION 0x0E
+#define USB_REQ_RPIPE_ABORT 0x0E
+#define USB_REQ_SET_HANDSHAKE 0x0F
+#define USB_REQ_RPIPE_RESET 0x0F
+#define USB_REQ_GET_HANDSHAKE 0x10
+#define USB_REQ_SET_CONNECTION 0x11
+#define USB_REQ_SET_SECURITY_DATA 0x12
+#define USB_REQ_GET_SECURITY_DATA 0x13
+#define USB_REQ_SET_WUSB_DATA 0x14
+#define USB_REQ_LOOPBACK_DATA_WRITE 0x15
+#define USB_REQ_LOOPBACK_DATA_READ 0x16
+#define USB_REQ_SET_INTERFACE_DS 0x17
+
+/* USB feature flags */
+#define USB_DEVICE_SELF_POWERED 0 /* (read only) */
+#define USB_DEVICE_REMOTE_WAKEUP 1 /* dev may initiate wakeup */
+#define USB_DEVICE_TEST_MODE 2 /* (wired high speed only) */
+#define USB_DEVICE_BATTERY 2 /* (wireless) */
+#define USB_DEVICE_B_HNP_ENABLE 3 /* (otg) dev may initiate HNP */
+#define USB_DEVICE_WUSB_DEVICE 3 /* (wireless)*/
+#define USB_DEVICE_A_HNP_SUPPORT 4 /* (otg) RH port supports HNP */
+#define USB_DEVICE_A_ALT_HNP_SUPPORT 5 /* (otg) other RH port does */
+#define USB_DEVICE_DEBUG_MODE 6 /* (special devices only) */
+
+#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
+/* 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
+
+/* 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
+#define USB_SETUP_RECIPIENT_PORT 0x04 // Wireless USB 1.0
+#define USB_SETUP_RECIPIENT_RPIPE 0x05 // Wireless USB 1.0
+
+
+/* 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 USB_DESCRIPTOR_DEBUG 0x0A
+#define USB_DESCRIPTOR_INTERFACE_ASSOCIATION 0x0B
+#define USB_DESCRIPTOR_SECURITY 0x0C
+#define USB_DESCRIPTOR_KEY 0x0D
+#define USB_DESCRIPTOR_ENCRYPTION_TYPE 0x0E
+#define USB_DESCRIPTOR_BOS 0x0F
+#define USB_DESCRIPTOR_DEVICE_CAPABILITY 0x10
+#define USB_DESCRIPTOR_WIRELESS_ENDPOINT_COMP 0x11
+#define USB_DESCRIPTOR_WIRE_ADAPTER 0x21
+#define USB_DESCRIPTOR_RPIPE 0x22
+#define USB_DESCRIPTOR_CS_RADIO_CONTROL 0x23
+#define USB_DESCRIPTOR_SS_ENDPOINT_COMP 0x30
+
+#define USB_HID_DESCRIPTOR 0x21
+
+
+// Conventional codes for class-specific descriptors. "Common Class" Spec (3.11)
+#define USB_DESCRIPTOR_CS_DEVICE 0x21
+#define USB_DESCRIPTOR_CS_CONFIG 0x22
+#define USB_DESCRIPTOR_CS_STRING 0x23
+#define USB_DESCRIPTOR_CS_INTERFACE 0x24
+#define USB_DESCRIPTOR_CS_ENDPOINT 0x25
+
+
+
+/* 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
+#define USB_TRANSFER_DIRECTION_IN 0x80 // Indicate direction is IN
+
+/* 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_FD_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_FD_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_FD_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_FD_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/lib-uhs3/UHS_host/UHS_usbhost.h b/Marlin/src/sd/usb_flashdrive/lib-uhs3/UHS_host/UHS_usbhost.h
new file mode 100644
index 0000000..b289a89
--- /dev/null
+++ b/Marlin/src/sd/usb_flashdrive/lib-uhs3/UHS_host/UHS_usbhost.h
@@ -0,0 +1,449 @@
+/* Copyright (C) 2015-2016 Andrew J. Kroll
+ and
+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 : https://www.circuitsathome.com
+e-mail : support@circuitsathome.com
+ */
+
+#ifndef _UHS_host_h_
+#error "Never include UHS_usbhost.h directly; include UHS_host.h instead"
+#else
+#ifndef _USBHOST_H_
+#define _USBHOST_H_
+
+// Very early prototypes
+#ifdef UHS_LOAD_BT
+void UHS_BT_SetUSBInterface(UHS_USB_HOST_BASE *host, ENUMERATION_INFO *ei);
+void UHS_BT_ScanUninitialized(UHS_USB_HOST_BASE *host);
+void UHS_BT_Poll(UHS_USB_HOST_BASE *host);
+#endif
+#ifdef UHS_LOAD_HID
+void UHS_HID_SetUSBInterface(UHS_USB_HOST_BASE *host, ENUMERATION_INFO *ei);
+void UHS_HID_ScanUninitialized(UHS_USB_HOST_BASE *host);
+void UHS_HID_Poll(UHS_USB_HOST_BASE *host);
+#endif
+
+//#if defined(LOAD_UHS_CDC_ACM) || defined(LOAD_UHS_CDC_ACM_FTDI) || defined(LOAD_UHS_CDC_ACM_PROLIFIC) || defined(LOAD_UHS_CDC_ACM_XR21B1411)
+//void UHS_CDC_ACM_SetUSBInterface(UHS_USB_HOST_BASE *host, ENUMERATION_INFO *ei);
+//void UHS_CDC_ACM_ScanUninitialized(UHS_USB_HOST_BASE *host);
+//void UHS_CDC_ACM_Poll(UHS_USB_HOST_BASE *host);
+//#endif
+
+class UHS_USBInterface; // forward class declaration
+
+// enumerator to turn the VBUS on/off
+
+typedef enum {
+ vbus_on = 0,
+ vbus_off = 1
+} VBUS_t;
+
+// All host SEI use this base class
+
+class UHS_USB_HOST_BASE {
+public:
+ AddressPool addrPool;
+ UHS_USBInterface* devConfig[UHS_HOST_MAX_INTERFACE_DRIVERS];
+ volatile uint8_t usb_error;
+ volatile uint8_t usb_task_state;
+ volatile uint8_t usb_task_polling_disabled;
+ volatile uint8_t usb_host_speed;
+ volatile uint8_t hub_present;
+
+ UHS_USB_HOST_BASE() {
+ for(uint16_t i = 0; i < UHS_HOST_MAX_INTERFACE_DRIVERS; i++) {
+ devConfig[i] = NULL;
+ }
+ usb_task_polling_disabled = 0;
+ usb_task_state = UHS_USB_HOST_STATE_INITIALIZE; //set up state machine
+ usb_host_speed = 0;
+ usb_error = 0;
+ };
+
+ /////////////////////////////////////////////
+ //
+ // Virtual methods that interface to the SIE
+ // Overriding each is mandatory.
+ //
+ /////////////////////////////////////////////
+
+ /**
+ * Delay for x milliseconds
+ * Override if your controller provides an SOF IRQ, which may involve
+ * some sort of reentrant ISR or workaround with interrupts enabled.
+ *
+ * @param x how many milliseconds to delay
+ * @return true if delay completed without a state change, false if delay aborted
+ */
+ virtual bool UHS_NI sof_delay(uint16_t x) {
+ if(!(usb_task_state & UHS_USB_HOST_STATE_MASK)) return false;
+ uint8_t current_state = usb_task_state;
+ while(current_state == usb_task_state && x--) {
+ delay(1);
+ }
+ return (current_state == usb_task_state);
+ };
+
+ virtual UHS_EpInfo * UHS_NI ctrlReqOpen(NOTUSED(uint8_t addr), NOTUSED(uint64_t Request), NOTUSED(uint8_t* dataptr)) {
+ return NULL;
+ };
+
+ virtual void UHS_NI vbusPower(NOTUSED(VBUS_t state)) {
+ };
+
+ virtual void UHS_NI Task() {
+ };
+
+ virtual uint8_t UHS_NI SetAddress(NOTUSED(uint8_t addr), NOTUSED(uint8_t ep), NOTUSED(UHS_EpInfo **ppep), NOTUSED(uint16_t &nak_limit)) {
+ return UHS_HOST_ERROR_NOT_IMPLEMENTED;
+ };
+
+ virtual uint8_t UHS_NI OutTransfer(NOTUSED(UHS_EpInfo *pep), NOTUSED(uint16_t nak_limit), NOTUSED(uint16_t nbytes), NOTUSED(uint8_t *data)) {
+ return UHS_HOST_ERROR_NOT_IMPLEMENTED;
+ };
+
+ virtual uint8_t UHS_NI InTransfer(NOTUSED(UHS_EpInfo *pep), NOTUSED(uint16_t nak_limit), NOTUSED(uint16_t *nbytesptr), NOTUSED(uint8_t *data)) {
+ return UHS_HOST_ERROR_NOT_IMPLEMENTED;
+ };
+
+ virtual uint8_t UHS_NI ctrlReqClose(NOTUSED(UHS_EpInfo *pep), NOTUSED(uint8_t bmReqType), NOTUSED(uint16_t left), NOTUSED(uint16_t nbytes), NOTUSED(uint8_t *dataptr)) {
+ return UHS_HOST_ERROR_NOT_IMPLEMENTED;
+ };
+
+ virtual uint8_t UHS_NI ctrlReqRead(NOTUSED(UHS_EpInfo *pep), NOTUSED(uint16_t *left), NOTUSED(uint16_t *read), NOTUSED(uint16_t nbytes), NOTUSED(uint8_t *dataptr)) {
+ return UHS_HOST_ERROR_NOT_IMPLEMENTED;
+ };
+
+ virtual uint8_t UHS_NI dispatchPkt(NOTUSED(uint8_t token), NOTUSED(uint8_t ep), NOTUSED(uint16_t nak_limit)) {
+ return UHS_HOST_ERROR_NOT_IMPLEMENTED;
+ };
+
+ virtual uint8_t UHS_NI init() {
+ return 0;
+ };
+
+ virtual void UHS_NI doHostReset() {
+ };
+
+ virtual int16_t UHS_NI Init(NOTUSED(int16_t mseconds)) {
+ return -1;
+ };
+
+ virtual int16_t UHS_NI Init() {
+ return Init(INT16_MIN);
+ };
+
+ virtual uint8_t hwlPowerUp() {
+ /* This is for machine specific support to enable/power up the USB HW to operate*/
+ return UHS_HOST_ERROR_NOT_IMPLEMENTED;
+ };
+
+ virtual uint8_t hwPowerDown() {
+ /* This is for machine specific support to disable/powerdown the USB Hw */
+ return UHS_HOST_ERROR_NOT_IMPLEMENTED;
+ };
+
+ virtual bool IsHub(uint8_t klass) {
+ return (klass == UHS_USB_CLASS_HUB);
+ };
+
+ virtual void UHS_NI suspend_host() {
+ // Used on MCU that lack control of IRQ priority (AVR).
+ // Suspends ISRs, for critical code. IRQ will be serviced after it is resumed.
+ // NOTE: you must track the state yourself!
+ };
+
+ virtual void UHS_NI resume_host() {
+ // Used on MCU that lack control of IRQ priority (AVR).
+ // Resumes ISRs.
+ // NOTE: you must track the state yourself!
+ };
+
+ /////////////////////////////////////////////
+ //
+ // Built-ins, No need to override
+ //
+ /////////////////////////////////////////////
+ // these two probably will go away, and won't be used, TBD
+ inline void Poll_Others() {
+#ifdef UHS_LOAD_BT
+ UHS_BT_Poll(this);
+#endif
+#ifdef UHS_LOAD_HID
+ UHS_HID_Poll(this);
+#endif
+ }
+
+ inline void DisablePoll() {
+ noInterrupts();
+ usb_task_polling_disabled++;
+ DDSB();
+ interrupts();
+ }
+
+ inline void EnablePoll() {
+ noInterrupts();
+ usb_task_polling_disabled--;
+ DDSB();
+ interrupts();
+ }
+
+ uint8_t UHS_NI seekInterface(ENUMERATION_INFO *ei, uint16_t inf, USB_FD_CONFIGURATION_DESCRIPTOR *ucd);
+
+ uint8_t UHS_NI setEpInfoEntry(uint8_t addr, uint8_t iface, uint8_t epcount, volatile UHS_EpInfo* eprecord_ptr);
+
+ uint8_t UHS_NI EPClearHalt(uint8_t addr, uint8_t ep);
+
+ uint8_t UHS_NI ctrlReq(uint8_t addr, uint64_t Request, uint16_t nbytes, uint8_t* dataptr);
+
+ uint8_t UHS_NI getDevDescr(uint8_t addr, uint16_t nbytes, uint8_t* dataptr);
+
+ uint8_t UHS_NI getConfDescr(uint8_t addr, uint16_t nbytes, uint8_t conf, uint8_t* dataptr);
+
+ uint8_t UHS_NI setAddr(uint8_t oldaddr, uint8_t newaddr);
+
+ uint8_t UHS_NI setConf(uint8_t addr, uint8_t conf_value);
+
+ uint8_t UHS_NI getStrDescr(uint8_t addr, uint16_t nbytes, uint8_t index, uint16_t langid, uint8_t* dataptr);
+
+ void UHS_NI ReleaseDevice(uint8_t addr);
+
+ uint8_t UHS_NI Configuring(uint8_t parent, uint8_t port, uint8_t speed);
+
+ void UHS_NI DeviceDefaults(uint8_t maxep, UHS_USBInterface *device);
+
+ UHS_EpInfo* UHS_NI getEpInfoEntry(uint8_t addr, uint8_t ep);
+
+ inline uint8_t getUsbTaskState() {
+ return ( usb_task_state);
+ };
+
+ inline AddressPool* GetAddressPool() {
+ return &addrPool;
+ };
+
+ int UHS_NI RegisterDeviceClass(UHS_USBInterface *pdev) {
+ for(uint8_t i = 0; i < UHS_HOST_MAX_INTERFACE_DRIVERS; i++) {
+ if(!devConfig[i]) {
+ devConfig[i] = pdev;
+ return i;
+ }
+ }
+ //return UHS_HOST_ERROR_CANT_REGISTER_DEVICE_CLASS;
+ return -1;
+ };
+#if 0
+
+ inline void ForEachUsbDevice(UsbDeviceHandleFunc pfunc) {
+ addrPool.ForEachUsbDevice(pfunc);
+ };
+#endif
+
+ uint8_t TestInterface(ENUMERATION_INFO *ei);
+ uint8_t enumerateInterface(ENUMERATION_INFO *ei);
+ uint8_t getNextInterface(ENUMERATION_INFO *ei, UHS_EpInfo *pep, uint8_t data[], uint16_t *left, uint16_t *read, uint8_t *offset);
+ uint8_t initDescrStream(ENUMERATION_INFO *ei, USB_FD_CONFIGURATION_DESCRIPTOR *ucd, UHS_EpInfo *pep, uint8_t *data, uint16_t *left, uint16_t *read, uint8_t *offset);
+ uint8_t outTransfer(uint8_t addr, uint8_t ep, uint16_t nbytes, uint8_t* data);
+ uint8_t inTransfer(uint8_t addr, uint8_t ep, uint16_t *nbytesptr, uint8_t* data);
+ uint8_t doSoftReset(uint8_t parent, uint8_t port, uint8_t address);
+ uint8_t getone(UHS_EpInfo *pep, uint16_t *left, uint16_t *read, uint8_t *dataptr, uint8_t *offset);
+ uint8_t eat(UHS_EpInfo *pep, uint16_t *left, uint16_t *read, uint8_t *dataptr, uint8_t *offset, uint16_t *yum);
+
+};
+
+// All device interface drivers use this subclass
+
+class UHS_USBInterface {
+public:
+
+ UHS_USB_HOST_BASE *pUsb; // Parent USB host
+ volatile uint8_t bNumEP; // total number of EP in this interface
+ volatile UHS_EpInfo epInfo[16]; // This is a stub, override in the driver.
+
+ volatile uint8_t bAddress; // address of the device
+ volatile uint8_t bConfNum; // configuration number
+ volatile uint8_t bIface; // interface value
+ volatile bool bPollEnable; // poll enable flag, operating status
+ volatile uint32_t qNextPollTime; // next poll time
+
+ /**
+ * Resets interface driver to unused state. You should override this in
+ * your driver if it requires extra class variable cleanup.
+ */
+ virtual void DriverDefaults() {
+ printf("Default driver defaults.\r\n");
+ pUsb->DeviceDefaults(bNumEP, this);
+ };
+
+ /**
+ * Checks if this interface is supported.
+ * Executed called when new devices are connected.
+ *
+ * @param ei
+ * @return true if the interface is supported
+ */
+ virtual bool OKtoEnumerate(NOTUSED(ENUMERATION_INFO *ei)) {
+ return false;
+ };
+
+ /**
+ * Configures any needed endpoint information for an interface.
+ * You must provide this in your driver.
+ * Executed when new devices are connected and OKtoEnumerate()
+ * returned true.
+ *
+ * @param ei
+ * @return zero on success
+ */
+ virtual uint8_t SetInterface(NOTUSED(ENUMERATION_INFO *ei)) {
+ return UHS_HOST_ERROR_NOT_IMPLEMENTED;
+ };
+
+ /**
+ * Interface specific additional setup and enumeration that
+ * can't occur when the descriptor stream is open.
+ * Also used for collection of unclaimed interfaces, to link to the master.
+ *
+ * @return zero on success
+ */
+ virtual uint8_t Finalize() {
+ return 0;
+ };
+
+ /**
+ * Executed after interface is finalized but, before polling has started.
+ *
+ * @return 0 on success
+ */
+ virtual uint8_t OnStart() {
+ return 0;
+ };
+
+ /**
+ * Start interface polling
+ * @return
+ */
+ virtual uint8_t Start() {
+ uint8_t rcode = OnStart();
+ if(!rcode) bPollEnable = true;
+ return rcode;
+ };
+
+ /**
+ * Executed before anything else in Release().
+ */
+ virtual void OnRelease() {
+ return;
+ };
+
+ /**
+ * Release resources when device is disconnected.
+ * Normally this does not need to be overridden.
+ */
+ virtual void Release() {
+ OnRelease();
+ DriverDefaults();
+ return;
+ };
+
+ /**
+ * Executed After driver polls.
+ * Can be used when there is an important change detected during polling
+ * and you want to handle it elsewhere.
+ * Examples:
+ * Media status change for bulk, e.g. ready, not-ready, media changed, door opened.
+ * Button state/joystick position/etc changes on a HID device.
+ * Flow control status change on a communication device, e.g. CTS on serial
+ */
+ virtual void OnPoll() {
+ return;
+ };
+
+ /**
+ * Poll interface driver. You should override this in your driver if you
+ * require polling faster or slower than every 100 milliseconds, or your
+ * driver requires special housekeeping.
+ */
+ virtual void Poll() {
+ OnPoll();
+ qNextPollTime = millis() + 100;
+ };
+
+ virtual bool UHS_NI Polling() {
+ return bPollEnable;
+ }
+
+ /**
+ * This is only for a hub.
+ * @param port
+ */
+ virtual void ResetHubPort(NOTUSED(uint8_t port)) {
+ return;
+ };
+
+#if 0
+ /**
+ * @return true if this interface is Vendor Specific.
+ */
+ virtual bool IsVSI() {
+ return false;
+ }
+#endif
+};
+
+#if 0
+/**
+ * Vendor Specific interface class.
+ * This is used by a partner interface.
+ * It can also be used to force-enumerate an interface that
+ * can use this interface directly.
+ * You can also add an instance of this class within the interface constructor
+ * if you expect the interface.
+ *
+ * If this is not needed, it may be removed. Nothing I have written needs this.
+ * Let me know if it is not required, then IsVSI method can also be shit-canned.
+ * -- AJK
+ */
+
+class UHS_VSI : public UHS_USBInterface {
+public:
+ volatile UHS_EpInfo epInfo[1];
+ volatile ENUMERATION_INFO eInfo;
+ UHS_VSI(UHS_USB_HOST_BASE *p);
+ bool OKtoEnumerate(ENUMERATION_INFO *ei);
+ uint8_t SetInterface(ENUMERATION_INFO *ei);
+ virtual void DriverDefaults();
+ virtual void Release();
+
+ uint8_t GetAddress() {
+ return bAddress;
+ };
+
+ virtual bool IsVSI() {
+ return true;
+ }
+
+};
+#endif
+
+#endif //_USBHOST_H_
+#endif
diff --git a/Marlin/src/sd/usb_flashdrive/lib-uhs3/UHS_host/UHS_util_INLINE.h b/Marlin/src/sd/usb_flashdrive/lib-uhs3/UHS_host/UHS_util_INLINE.h
new file mode 100644
index 0000000..52015b5
--- /dev/null
+++ b/Marlin/src/sd/usb_flashdrive/lib-uhs3/UHS_host/UHS_util_INLINE.h
@@ -0,0 +1,129 @@
+/* Copyright (C) 2015-2016 Andrew J. Kroll
+ and
+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 : https://www.circuitsathome.com
+e-mail : support@circuitsathome.com
+ */
+
+#if defined(LOAD_USB_HOST_SYSTEM) && !defined(USB_HOST_SYSTEM_UTIL_LOADED)
+#define USB_HOST_SYSTEM_UTIL_LOADED
+
+// 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
+}
+
+void E_Notify(double d, int lvl) {
+ if(UsbDEBUGlvl < lvl) return;
+ USB_HOST_SERIAL.print(d);
+}
+
+#ifdef DEBUG_USB_HOST
+
+void NotifyFailGetDevDescr() {
+ Notify(PSTR("\r\ngetDevDescr "), 0x80);
+}
+
+void NotifyFailSetDevTblEntry() {
+ Notify(PSTR("\r\nsetDevTblEn "), 0x80);
+}
+
+void NotifyFailGetConfDescr() {
+ Notify(PSTR("\r\ngetConf "), 0x80);
+}
+
+void NotifyFailSetConfDescr() {
+ 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
+
+#else
+#error "Never include UHS_util_INLINE.h, include UHS_host.h instead"
+#endif
diff --git a/Marlin/src/sd/usb_flashdrive/lib-uhs3/UHS_host/USB_HOST_SHIELD/UHS_max3421e.h b/Marlin/src/sd/usb_flashdrive/lib-uhs3/UHS_host/USB_HOST_SHIELD/UHS_max3421e.h
new file mode 100644
index 0000000..8ecafd4
--- /dev/null
+++ b/Marlin/src/sd/usb_flashdrive/lib-uhs3/UHS_host/USB_HOST_SHIELD/UHS_max3421e.h
@@ -0,0 +1,226 @@
+/* Copyright (C) 2015-2016 Andrew J. Kroll
+ and
+Copyright (C) 2011 Circuits At Home, LTD. All rights reserved.
+
+This software may be distributed and modified under the terms of the GNU
+General Public License version 2 (GPL2) as published by the Free Software
+Foundation and appearing in the file GPL2.TXT included in the packaging of
+this file. Please note that GPL2 Section 2[b] requires that all works based
+on this software must also be made publicly available under the terms of
+the GPL2 ("Copyleft").
+
+Contact information
+-------------------
+
+Circuits At Home, LTD
+Web : https://www.circuitsathome.com
+e-mail : support@circuitsathome.com
+ */
+#if !defined(USB_HOST_SHIELD_H) || defined(_max3421e_h_)
+#error "Never include UHS_max3421e.h directly; include USB_HOST_SHIELD.h instead"
+#else
+
+#define _max3421e_h_
+
+/* MAX3421E register/bit names and bitmasks */
+
+#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 // Receive FIFO Register
+#define rSNDFIFO 0x10 // Send FIFO Register
+#define rSUDFIFO 0x20 // Set Up Data FIFO Register
+#define rRCVBC 0x30 // Receive FIFO Byte Count Register
+#define rSNDBC 0x38 // Send FIFO Byte Count Register
+
+// USB Interrupt Request Status (USBIRQ)
+#define rUSBIRQ 0x68 // USB Interrupt Request Register
+#define bmVBUSIRQ 0x40 // Vbus Present Interrupt Request
+#define bmNOVBUSIRQ 0x20 // Vbus Absent Interrupt Request
+#define bmOSCOKIRQ 0x01 // Oscillator OK Interrupt Request
+
+// USB Interrupt Request Control (USBIEN)
+#define rUSBIEN 0x70 // USB Interrupt Request Enable Register
+#define bmVBUSIE bmVBUSIRQ // Vbus Present Interrupt Request Enable
+#define bmNOVBUSIE bmNOVBUSIRQ // Vbus Absent Interrupt Request Enable
+#define bmOSCOKIE bmOSCOKIRQ // Oscillator OK Interrupt Request Enable
+
+// (USBCTL)
+#define rUSBCTL 0x78 //15<<3
+#define bmCHIPRES 0x20 //b5
+#define bmPWRDOWN 0x10 //b4
+
+// (CPUCTL)
+#define rCPUCTL 0x80 //16<<3
+#define bmPUSLEWID1 0x80 //b7
+#define bmPULSEWID0 0x40 //b6
+#define bmIE 0x01 //b0
+
+// bmPUSLEWID1 bmPULSEWID0 Pulse width
+// 0 0 10.6uS
+// 0 1 5.3uS
+// 1 0 2.6uS
+// 1 1 1.3uS
+#define PUSLEWIDTH10_6 (0)
+#define PUSLEWIDTH5_3 (bmPULSEWID0)
+#define PUSLEWIDTH2_6 (bmPUSLEWID1)
+#define PUSLEWIDTH1_3 (bmPULSEWID0 | bmPUSLEWID1)
+
+// (PINCTL)
+#define rPINCTL 0x88 //17<<3
+#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
+
+// (IOPINS1)
+#define rIOPINS1 0xA0 //20<<3
+#define bmGPOUT0 0x01 //
+#define bmGPOUT1 0x02 //
+#define bmGPOUT2 0x04 //
+#define bmGPOUT3 0x08 //
+#define bmGPIN0 0x10 //
+#define bmGPIN1 0x20 //
+#define bmGPIN2 0x40 //
+#define bmGPIN3 0x80 //
+
+// (IOPINS2)
+#define rIOPINS2 0xA8 //21<<3
+#define bmGPOUT4 0x01 //
+#define bmGPOUT5 0x02 //
+#define bmGPOUT6 0x04 //
+#define bmGPOUT7 0x08 //
+#define bmGPIN4 0x10 //
+#define bmGPIN5 0x20 //
+#define bmGPIN6 0x40 //
+#define bmGPIN7 0x80 //
+
+// (GPINIRQ)
+#define rGPINIRQ 0xB0 //22<<3
+#define bmGPINIRQ0 0x01 //
+#define bmGPINIRQ1 0x02 //
+#define bmGPINIRQ2 0x04 //
+#define bmGPINIRQ3 0x08 //
+#define bmGPINIRQ4 0x10 //
+#define bmGPINIRQ5 0x20 //
+#define bmGPINIRQ6 0x40 //
+#define bmGPINIRQ7 0x80 //
+
+// (GPINIEN)
+#define rGPINIEN 0xB8 //23<<3
+#define bmGPINIEN0 0x01 //
+#define bmGPINIEN1 0x02 //
+#define bmGPINIEN2 0x04 //
+#define bmGPINIEN3 0x08 //
+#define bmGPINIEN4 0x10 //
+#define bmGPINIEN5 0x20 //
+#define bmGPINIEN6 0x40 //
+#define bmGPINIEN7 0x80 //
+
+// (GPINPOL)
+#define rGPINPOL 0xC0 //24<<3
+#define bmGPINPOL0 0x01 //
+#define bmGPINPOL1 0x02 //
+#define bmGPINPOL2 0x04 //
+#define bmGPINPOL3 0x08 //
+#define bmGPINPOL4 0x10 //
+#define bmGPINPOL5 0x20 //
+#define bmGPINPOL6 0x40 //
+#define bmGPINPOL7 0x80 //
+
+//
+// If any data transfer errors occur, the HXFRDNIRQ asserts, while the RCVDAVIRQ does not.
+//
+// The CPU clears the SNDBAVIRQ by writing the SNDBC register.
+// The CPU should never directly clear the SNDBAVIRQ bit.
+
+// Host Interrupt Request Status (HIRQ)
+#define rHIRQ 0xC8 // Host Interrupt Request Register
+#define bmBUSEVENTIRQ 0x01 // BUS Reset Done or BUS Resume Interrupt Request
+#define bmRWUIRQ 0x02 // Remote Wakeup Interrupt Request
+#define bmRCVDAVIRQ 0x04 // Receive FIFO Data Available Interrupt Request
+#define bmSNDBAVIRQ 0x08 // Send Buffer Available Interrupt Request
+#define bmSUSDNIRQ 0x10 // Suspend operation Done Interrupt Request
+#define bmCONDETIRQ 0x20 // Peripheral Connect/Disconnect Interrupt Request
+#define bmFRAMEIRQ 0x40 // Frame Generator Interrupt Request
+#define bmHXFRDNIRQ 0x80 // Host Transfer Done Interrupt Request
+
+// IRQs that are OK for the CPU to clear
+#define ICLRALLBITS (bmBUSEVENTIRQ | bmRWUIRQ | bmRCVDAVIRQ | bmSUSDNIRQ | bmCONDETIRQ | bmFRAMEIRQ | bmHXFRDNIRQ)
+
+// Host Interrupt Request Control (HIEN)
+#define rHIEN 0xD0 //
+#define bmBUSEVENTIE bmBUSEVENTIRQ // BUS Reset Done or BUS Resume Interrupt Request Enable
+#define bmRWUIE bmRWUIRQ // Remote Wakeup Interrupt Request Enable
+#define bmRCVDAVIE bmRCVDAVIRQ // Receive FIFO Data Available Interrupt Request Enable
+#define bmSNDBAVIE bmSNDBAVIRQ // Send Buffer Available Interrupt Request Enable
+#define bmSUSDNIE bmSUSDNIRQ // Suspend operation Done Interrupt Request Enable
+#define bmCONDETIE bmCONDETIRQ // Peripheral Connect/Disconnect Interrupt Request Enable
+#define bmFRAMEIE bmFRAMEIRQ // Frame Generator Interrupt Request Enable
+#define bmHXFRDNIE bmHXFRDNIRQ // Host Transfer Done Interrupt Request Enable
+
+// (MODE))
+#define rMODE 0xD8 //27<<3
+#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
+
+// (HCTL)
+#define rHCTL 0xE8 //29<<3
+#define bmBUSRST 0x01 //
+#define bmFRMRST 0x02 //
+#define bmSAMPLEBUS 0x04 //
+#define bmSIGRSM 0x08 //
+#define bmRCVTOG0 0x10 //
+#define bmRCVTOG1 0x20 //
+#define bmSNDTOG0 0x40 //
+#define bmSNDTOG1 0x80 //
+
+// Host transfer (HXFR)
+#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 MAX3421E_tokSETUP 0x10 // HS=0, ISO=0, OUTNIN=0, SETUP=1
+#define MAX3421E_tokIN 0x00 // HS=0, ISO=0, OUTNIN=0, SETUP=0
+#define MAX3421E_tokOUT 0x20 // HS=0, ISO=0, OUTNIN=1, SETUP=0
+#define MAX3421E_tokINHS 0x80 // HS=1, ISO=0, OUTNIN=0, SETUP=0
+#define MAX3421E_tokOUTHS 0xA0 // HS=1, ISO=0, OUTNIN=1, SETUP=0
+#define MAX3421E_tokISOIN 0x40 // HS=0, ISO=1, OUTNIN=0, SETUP=0
+#define MAX3421E_tokISOOUT 0x60 // HS=0, ISO=1, OUTNIN=1, SETUP=0
+
+// (HRSL)
+#define rHRSL 0xF8 //31<<3
+#define bmRCVTOGRD 0x10 //
+#define bmSNDTOGRD 0x20 //
+#define bmKSTATUS 0x40 //
+#define bmJSTATUS 0x80 //
+#define bmSE0 0x00 //SE0 - disconnect state
+#define bmSE1 0xC0 //SE1 - illegal state
+
+#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-uhs3/UHS_host/USB_HOST_SHIELD/USB_HOST_SHIELD.h b/Marlin/src/sd/usb_flashdrive/lib-uhs3/UHS_host/USB_HOST_SHIELD/USB_HOST_SHIELD.h
new file mode 100644
index 0000000..56d6400
--- /dev/null
+++ b/Marlin/src/sd/usb_flashdrive/lib-uhs3/UHS_host/USB_HOST_SHIELD/USB_HOST_SHIELD.h
@@ -0,0 +1,519 @@
+/* Copyright (C) 2015-2016 Andrew J. Kroll
+ and
+Copyright (C) 2011 Circuits At Home, LTD. All rights reserved.
+
+This software may be distributed and modified under the terms of the GNU
+General Public License version 2 (GPL2) as published by the Free Software
+Foundation and appearing in the file GPL2.TXT included in the packaging of
+this file. Please note that GPL2 Section 2[b] requires that all works based
+on this software must also be made publicly available under the terms of
+the GPL2 ("Copyleft").
+
+Contact information
+-------------------
+
+Circuits At Home, LTD
+Web : https://www.circuitsathome.com
+e-mail : support@circuitsathome.com
+ */
+
+#ifndef USB_HOST_SHIELD_H
+#define USB_HOST_SHIELD_H
+
+// uncomment to get 'printf' console debugging. NOT FOR UNO!
+//#define DEBUG_PRINTF_EXTRA_HUGE_USB_HOST_SHIELD
+
+#ifdef LOAD_USB_HOST_SHIELD
+#include "UHS_max3421e.h"
+#include <SPI.h>
+
+
+#ifndef SPI_HAS_TRANSACTION
+#error "Your SPI library installation is too old."
+#else
+#ifndef SPI_ATOMIC_VERSION
+#warning "Your SPI library installation lacks 'SPI_ATOMIC_VERSION'. Please complain to the maintainer."
+#elif SPI_ATOMIC_VERSION < 1
+#error "Your SPI library installation is too old."
+#endif
+
+#endif
+#if DEBUG_PRINTF_EXTRA_HUGE
+#ifdef DEBUG_PRINTF_EXTRA_HUGE_USB_HOST_SHIELD
+#define MAX_HOST_DEBUG(...) printf_P(__VA_ARGS__)
+#else
+#define MAX_HOST_DEBUG(...) VOID0
+#endif
+#else
+#define MAX_HOST_DEBUG(...) VOID0
+#endif
+
+#ifndef USB_HOST_SHIELD_USE_ISR
+#ifdef USE_MULTIPLE_APP_API
+#define USB_HOST_SHIELD_USE_ISR 0
+#else
+#define USB_HOST_SHIELD_USE_ISR 1
+#endif
+#else
+#define USB_HOST_SHIELD_USE_ISR 1
+#endif
+
+
+
+#if !USB_HOST_SHIELD_USE_ISR
+#error NOISR Polled mode _NOT SUPPORTED YET_
+
+//
+// Polled defaults
+//
+#ifdef BOARD_BLACK_WIDDOW
+#define UHS_MAX3421E_SS_ 6
+#define UHS_MAX3421E_INT_ 3
+#elif defined(CORE_TEENSY) && (defined(__AVR_AT90USB646__) || defined(__AVR_AT90USB1286__))
+#if EXT_RAM
+// Teensy++ 2.0 with XMEM2
+#define UHS_MAX3421E_SS_ 20
+#define UHS_MAX3421E_INT_ 7
+#else
+#define UHS_MAX3421E_SS_ 9
+#define UHS_MAX3421E_INT_ 8
+#endif
+#define UHS_MAX3421E_SPD
+#elif defined(ARDUINO_AVR_ADK)
+#define UHS_MAX3421E_SS_ 53
+#define UHS_MAX3421E_INT_ 54
+#elif defined(ARDUINO_AVR_BALANDUINO)
+#define UHS_MAX3421E_SS_ 20
+#define UHS_MAX3421E_INT_ 19
+#else
+#define UHS_MAX3421E_SS_ 10
+#define UHS_MAX3421E_INT_ 9
+#endif
+
+#else
+#ifdef ARDUINO_ARCH_PIC32
+// PIC32 only allows edge interrupts, isn't that lovely? We'll emulate it...
+#if CHANGE < 2
+#error core too old.
+#endif
+
+#define IRQ_IS_EDGE 0
+#ifndef digitalPinToInterrupt
+// great, this isn't implemented.
+#warning digitalPinToInterrupt is not defined, complain here https://github.com/chipKIT32/chipKIT-core/issues/114
+#if defined(_BOARD_UNO_) || defined(_BOARD_UC32_)
+#define digitalPinToInterrupt(p) ((p) == 2 ? 1 : ((p) == 7 ? 2 : ((p) == 8 ? 3 : ((p) == 35 ? 4 : ((p) == 38 ? 0 : NOT_AN_INTERRUPT)))))
+#warning digitalPinToInterrupt is now defined until this is taken care of.
+#else
+#error digitalPinToInterrupt not defined for your board, complain here https://github.com/chipKIT32/chipKIT-core/issues/114
+#endif
+#endif
+#else
+#define IRQ_IS_EDGE 0
+#endif
+
+// More stupidity from our friends @ Sony...
+#ifdef ARDUINO_spresense_ast
+#ifndef NOT_AN_INTERRUPT
+#define NOT_AN_INTERRUPT -1
+#endif
+#endif
+
+// SAMD uses an enum for this instead of a define. Isn't that just dandy?
+#if !defined(NOT_AN_INTERRUPT) && !defined(ARDUINO_ARCH_SAMD)
+#warning NOT_AN_INTERRUPT not defined, possible problems ahead.
+#warning If NOT_AN_INTERRUPT is an enum or something else, complain to UHS30 developers on github.
+#warning Otherwise complain to your board core developer/maintainer.
+#define NOT_AN_INTERRUPT -1
+#endif
+
+//
+// Interrupt defaults. Int0 or Int1
+//
+#ifdef BOARD_BLACK_WIDDOW
+#error "HELP! Please send us an email, I don't know the values for Int0 and Int1 on the Black Widow board!"
+#elif defined(ARDUINO_AVR_ADK)
+#define UHS_MAX3421E_SS_ 53
+#define UHS_MAX3421E_INT_ 54
+#elif defined(ARDUINO_spresense_ast)
+#define UHS_MAX3421E_SS_ 21
+#define UHS_MAX3421E_INT_ 20
+#define SPIclass SPI5
+//#define UHS_MAX3421E_SPD 100000
+#elif defined(CORE_TEENSY) && (defined(__AVR_AT90USB646__) || defined(__AVR_AT90USB1286__))
+
+// TO-DO!
+
+#if EXT_RAM
+// Teensy++ 2.0 with XMEM2
+#define UHS_MAX3421E_SS_ 20
+#define UHS_MAX3421E_INT_ 7
+#else
+#define UHS_MAX3421E_SS_ 9
+#define UHS_MAX3421E_INT_ 8
+#endif
+
+#elif defined(ARDUINO_AVR_BALANDUINO)
+#error "ISR mode is currently not supported on the Balanduino. Please set USB_HOST_SHIELD_USE_ISR to 0."
+#else
+#define UHS_MAX3421E_SS_ 10
+#ifdef __AVR__
+#ifdef __AVR_ATmega32U4__
+#define INT_FOR_PIN2 1
+#define INT_FOR_PIN3 0
+#else
+// Everybody else???
+#define INT_FOR_PIN2 0
+#define INT_FOR_PIN3 1
+#endif
+#define UHS_MAX3421E_INT_ 3
+#else
+// Non-avr
+#ifdef ARDUINO_ARCH_PIC32
+// UNO32 External Interrupts:
+// Pin 38 (INT0), Pin 2 (INT1), Pin 7 (INT2), Pin 8 (INT3), Pin 35 (INT4)
+#define UHS_MAX3421E_INT_ 7
+#else
+#define UHS_MAX3421E_INT_ 9
+#endif
+#endif
+#endif
+#endif
+
+
+
+#ifdef NO_AUTO_SPEED
+// Ugly details section...
+// MAX3421E characteristics
+// SPI Serial - Clock Input. An external SPI master supplies SCLK with frequencies up to 26MHz. The
+// logic level is referenced to the voltage on VL. Data is clocked into the SPI slave inter face on the
+// rising edge of SCLK. Data is clocked out of the SPI slave interface on the falling edge of SCLK.
+// Serial Clock (SCLK) Period 38.4ns minimum. 17ns minimum pulse width. VL >2.5V
+// SCLK Fall to MISO Propagation Delay 14.2ns
+// SCLK Fall to MOSI Propagation Delay 14.2ns
+// SCLK Fall to MOSI Drive 3.5ns
+// Theoretical deadline for reply 17.7ns
+// 26MHz 38.4615ns period <-- MAX3421E theoretical maximum
+
+#ifndef UHS_MAX3421E_SPD
+#ifdef ARDUINO_SAMD_ZERO
+// Zero violates spec early, needs a long setup time, or doesn't like high latency.
+#define UHS_MAX3421E_SPD 10000000
+#elif defined(ARDUINO_ARCH_PIC32)
+// PIC MX 5/6/7 characteristics
+// 25MHZ 40ns period <-- PIC MX 5/6/7 theoretical maximum
+// pulse width minimum Tsclk/2ns
+// Trise/fall 10ns maximum. 5ns is typical but not guaranteed.
+// Tsetup minimum for MISO 10ns.
+// We are in violation by 7.7ns @ 25MHz due to latency alone.
+// Even reading at end of data cycle, we only have a 2.3ns window.
+// This is too narrow to to compensate for capacitance, trace lengths, and noise.
+
+// 17.7ns + 10ns = 27.7ns
+// 18MHz fits and has enough slack time to compensate for capacitance, trace lengths, and noise.
+// For high speeds the SMP bit is recommended too, which samples at the end instead of the middle.
+// 20Mhz seems to work.
+
+#define UHS_MAX3421E_SPD 20000000
+#else
+#define UHS_MAX3421E_SPD 25000000
+#endif
+#endif
+#else
+// We start at 25MHz, and back down until hardware can take it.
+// Of course, SPI library can adjust this for us too.
+// Why not 26MHz? Because I have not found any MCU board that
+// can actually go that fast without problems.
+// Could be a shield limitation too.
+#ifndef UHS_MAX3421E_SPD
+#define UHS_MAX3421E_SPD 25000000
+#endif
+#endif
+
+#ifndef UHS_MAX3421E_INT
+#define UHS_MAX3421E_INT UHS_MAX3421E_INT_
+#endif
+
+#ifndef UHS_MAX3421E_SS
+#define UHS_MAX3421E_SS UHS_MAX3421E_SS_
+#endif
+
+// NOTE: On the max3421e the irq enable and irq bits are in the same position.
+
+// IRQs used if CPU polls
+#define ENIBITSPOLLED (bmCONDETIE | bmBUSEVENTIE | bmFRAMEIE)
+// IRQs used if CPU is interrupted
+#define ENIBITSISR (bmCONDETIE | bmBUSEVENTIE | bmFRAMEIE /* | bmRCVDAVIRQ | bmSNDBAVIRQ | bmHXFRDNIRQ */ )
+
+#if !USB_HOST_SHIELD_USE_ISR
+#define IRQ_CHECK_MASK (ENIBITSPOLLED & ICLRALLBITS)
+#define IRQ_IS_EDGE 0
+#else
+#define IRQ_CHECK_MASK (ENIBITSISR & ICLRALLBITS)
+#endif
+
+#if IRQ_IS_EDGE
+// Note: UNO32 Interrupts can only be RISING, or FALLING.
+// This poses an interesting problem, since we want to use a LOW level.
+// The MAX3421E provides for pulse width control for an IRQ.
+// We do need to watch the timing on this, as a second IRQ could cause
+// a missed IRQ, since we read the level of the line to check if the IRQ
+// is actually for this chip. The only other alternative is to add a capacitor
+// and an NPN transistor, and use two lines. We can try this first, though.
+// Worse case, we can ignore reading the pin for verification on UNO32.
+// Too bad there is no minimum low width setting.
+//
+// Single Clear First Second Clear first Clear last
+// IRQ Single IRQ IRQ Second active pending IRQ
+// | | | | | |
+// V V V V V V
+// _____ _________ _ _ _______
+// |______| |______| |______| |______________|
+//
+#define IRQ_SENSE FALLING
+#ifdef ARDUINO_ARCH_PIC32
+//#define bmPULSEWIDTH PUSLEWIDTH10_6
+#define bmPULSEWIDTH 0
+#define bmIRQ_SENSE 0
+#else
+#define bmPULSEWIDTH PUSLEWIDTH1_3
+#define bmIRQ_SENSE 0
+#endif
+#else
+#ifndef IRQ_SENSE
+#define IRQ_SENSE LOW
+#endif
+#ifndef bmPULSEWIDTH
+#define bmPULSEWIDTH 0
+#endif
+#ifndef bmIRQ_SENSE
+#define bmIRQ_SENSE bmINTLEVEL
+#endif
+#endif
+
+class MAX3421E_HOST :
+public UHS_USB_HOST_BASE
+#ifdef SWI_IRQ_NUM
+, public dyn_SWI
+#endif
+{
+ // TO-DO: move these into the parent class.
+ volatile uint8_t vbusState;
+ volatile uint16_t sof_countdown;
+
+ // TO-DO: pack into a struct/union and use one byte
+ volatile bool busevent;
+ volatile bool sofevent;
+ volatile bool counted;
+ volatile bool condet;
+ volatile bool doingreset;
+
+ #ifdef USB_HOST_MANUAL_POLL
+ volatile bool frame_irq_enabled = false;
+
+ bool enable_frame_irq(bool enable) {
+ const bool prev_state = frame_irq_enabled;
+ if(prev_state != enable) {
+ if(enable)
+ regWr(rHIEN, regRd(rHIEN) | bmFRAMEIE);
+ else
+ regWr(rHIEN, regRd(rHIEN) & ~bmFRAMEIE);
+ frame_irq_enabled = enable;
+ }
+ return prev_state;
+ }
+ #endif
+
+public:
+ SPISettings MAX3421E_SPI_Settings;
+ uint8_t ss_pin;
+ uint8_t irq_pin;
+ // Will use the defaults UHS_MAX3421E_SS, UHS_MAX3421E_INT and speed
+
+ UHS_NI MAX3421E_HOST() {
+ sof_countdown = 0;
+ busevent = false;
+ doingreset = false;
+ sofevent = false;
+ condet = false;
+ ss_pin = UHS_MAX3421E_SS;
+ irq_pin = UHS_MAX3421E_INT;
+ MAX3421E_SPI_Settings = SPISettings(UHS_MAX3421E_SPD, MSBFIRST, SPI_MODE0);
+ hub_present = 0;
+ };
+
+ // Will use user supplied pins, and UHS_MAX3421E_SPD
+
+ UHS_NI MAX3421E_HOST(uint8_t pss, uint8_t pirq) {
+ sof_countdown = 0;
+ busevent = false;
+ doingreset = false;
+ sofevent = false;
+ condet = false;
+ ss_pin = pss;
+ irq_pin = pirq;
+ MAX3421E_SPI_Settings = SPISettings(UHS_MAX3421E_SPD, MSBFIRST, SPI_MODE0);
+ hub_present = 0;
+ };
+
+ // Will use user supplied pins, and speed
+
+ UHS_NI MAX3421E_HOST(uint8_t pss, uint8_t pirq, uint32_t pspd) {
+ sof_countdown = 0;
+ doingreset = false;
+ busevent = false;
+ sofevent = false;
+ condet = false;
+ ss_pin = pss;
+ irq_pin = pirq;
+ MAX3421E_SPI_Settings = SPISettings(pspd, MSBFIRST, SPI_MODE0);
+ hub_present = 0;
+ };
+
+ virtual bool UHS_NI sof_delay(uint16_t x) {
+#ifdef USB_HOST_MANUAL_POLL
+ const bool saved_irq_state = enable_frame_irq(true);
+#endif
+ sof_countdown = x;
+ while((sof_countdown != 0) && !condet) {
+ SYSTEM_OR_SPECIAL_YIELD();
+#if !USB_HOST_SHIELD_USE_ISR
+ Task();
+#endif
+ }
+#ifdef USB_HOST_MANUAL_POLL
+ enable_frame_irq(saved_irq_state);
+#endif
+ // Serial.println("...Wake");
+ return (!condet);
+ };
+
+ virtual UHS_EpInfo *ctrlReqOpen(uint8_t addr, uint64_t Request, uint8_t* dataptr);
+
+ virtual void UHS_NI vbusPower(VBUS_t state) {
+ regWr(rPINCTL, (bmFDUPSPI | bmIRQ_SENSE) | (uint8_t)(state));
+ };
+
+ void UHS_NI Task();
+
+ virtual uint8_t SetAddress(uint8_t addr, uint8_t ep, UHS_EpInfo **ppep, uint16_t &nak_limit);
+ virtual uint8_t OutTransfer(UHS_EpInfo *pep, uint16_t nak_limit, uint16_t nbytes, uint8_t *data);
+ virtual uint8_t InTransfer(UHS_EpInfo *pep, uint16_t nak_limit, uint16_t *nbytesptr, uint8_t *data);
+ virtual uint8_t ctrlReqClose(UHS_EpInfo *pep, uint8_t bmReqType, uint16_t left, uint16_t nbytes, uint8_t *dataptr);
+ virtual uint8_t ctrlReqRead(UHS_EpInfo *pep, uint16_t *left, uint16_t *read, uint16_t nbytes, uint8_t *dataptr);
+ virtual uint8_t dispatchPkt(uint8_t token, uint8_t ep, uint16_t nak_limit);
+
+ void UHS_NI ReleaseChildren() {
+ for(uint8_t i = 0; i < UHS_HOST_MAX_INTERFACE_DRIVERS; i++)
+ if(devConfig[i])
+ devConfig[i]->Release();
+ hub_present = 0;
+ };
+
+ virtual bool IsHub(uint8_t klass) {
+ if(klass == UHS_USB_CLASS_HUB) {
+ hub_present = bmHUBPRE;
+ return true;
+ }
+ return false;
+ };
+
+ virtual void VBUS_changed();
+
+ virtual void UHS_NI doHostReset() {
+#if USB_HOST_SHIELD_USE_ISR
+ // Enable interrupts
+ noInterrupts();
+#endif
+ doingreset = true;
+ busevent = true;
+ regWr(rHIRQ, bmBUSEVENTIRQ); // see data sheet.
+ regWr(rHCTL, bmBUSRST); //issue bus reset
+#if USB_HOST_SHIELD_USE_ISR
+ DDSB();
+ // Enable interrupts
+ interrupts();
+#endif
+ while(busevent) {
+ DDSB();
+ SYSTEM_OR_SPECIAL_YIELD();
+ }
+#endif
+#if USB_HOST_SHIELD_USE_ISR
+ // Enable interrupts
+ noInterrupts();
+#endif
+ #ifdef USB_HOST_MANUAL_POLL
+ enable_frame_irq(true);
+ #endif
+ sofevent = true;
+#if USB_HOST_SHIELD_USE_ISR
+ DDSB();
+ // Enable interrupts
+ interrupts();
+#endif
+ // Wait for SOF
+ while(sofevent) {
+ }
+#if USB_HOST_SHIELD_USE_ISR
+ // Enable interrupts
+ noInterrupts();
+#endif
+ doingreset = false;
+#if USB_HOST_SHIELD_USE_ISR
+ DDSB();
+ // Enable interrupts
+ interrupts();
+ };
+
+
+ int16_t UHS_NI Init(int16_t mseconds);
+
+ int16_t UHS_NI Init() {
+ return Init(INT16_MIN);
+ };
+
+ void ISRTask();
+ void ISRbottom();
+ void busprobe();
+ uint16_t reset();
+
+ // MAX3421e specific
+ void regWr(uint8_t reg, uint8_t data);
+ void gpioWr(uint8_t data);
+ uint8_t regRd(uint8_t reg);
+ uint8_t gpioRd();
+ uint8_t* bytesWr(uint8_t reg, uint8_t nbytes, uint8_t* data_p);
+ uint8_t* bytesRd(uint8_t reg, uint8_t nbytes, uint8_t* data_p);
+
+ // ARM/NVIC specific, used to emulate reentrant ISR.
+#ifdef SWI_IRQ_NUM
+
+ void dyn_SWISR() {
+ ISRbottom();
+ };
+#endif
+
+ virtual void UHS_NI suspend_host() {
+ // Used on MCU that lack control of IRQ priority (AVR).
+ // Suspends ISRs, for critical code. IRQ will be serviced after it is resumed.
+ // NOTE: you must track the state yourself!
+#ifdef __AVR__
+ noInterrupts();
+ detachInterrupt(UHS_GET_DPI(irq_pin));
+ interrupts();
+#endif
+ };
+
+ virtual void UHS_NI resume_host();
+};
+#ifndef SPIclass
+#define SPIclass SPI
+#endif
+#ifndef USB_HOST_SHIELD_LOADED
+#include "USB_HOST_SHIELD_INLINE.h"
+#endif
+#else
+#error "define LOAD_USB_HOST_SHIELD in your sketch, never include USB_HOST_SHIELD.h in a driver."
+#endif
+#endif /* USB_HOST_SHIELD_H */
diff --git a/Marlin/src/sd/usb_flashdrive/lib-uhs3/UHS_host/USB_HOST_SHIELD/USB_HOST_SHIELD_INLINE.h b/Marlin/src/sd/usb_flashdrive/lib-uhs3/UHS_host/USB_HOST_SHIELD/USB_HOST_SHIELD_INLINE.h
new file mode 100644
index 0000000..f7dd315
--- /dev/null
+++ b/Marlin/src/sd/usb_flashdrive/lib-uhs3/UHS_host/USB_HOST_SHIELD/USB_HOST_SHIELD_INLINE.h
@@ -0,0 +1,1003 @@
+/* Copyright (C) 2015-2016 Andrew J. Kroll
+ and
+Copyright (C) 2011 Circuits At Home, LTD. All rights reserved.
+
+This software may be distributed and modified under the terms of the GNU
+General Public License version 2 (GPL2) as publishe7d by the Free Software
+Foundation and appearing in the file GPL2.TXT included in the packaging of
+this file. Please note that GPL2 Section 2[b] requires that all works based
+on this software must also be made publicly available under the terms of
+the GPL2 ("Copyleft").
+
+Contact information
+-------------------
+
+Circuits At Home, LTD
+Web : https://www.circuitsathome.com
+e-mail : support@circuitsathome.com
+ */
+
+#if defined(USB_HOST_SHIELD_H) && !defined(USB_HOST_SHIELD_LOADED)
+#define USB_HOST_SHIELD_LOADED
+#include <Arduino.h>
+
+#ifndef digitalPinToInterrupt
+#error digitalPinToInterrupt not defined, complain to your board maintainer.
+#endif
+
+
+#if USB_HOST_SHIELD_USE_ISR
+
+// allow two slots. this makes the maximum allowed shield count TWO
+// for AVRs this is limited to pins 2 and 3 ONLY
+// for all other boards, one odd and one even pin number is allowed.
+static MAX3421E_HOST *ISReven;
+static MAX3421E_HOST *ISRodd;
+
+static void UHS_NI call_ISReven() {
+ ISReven->ISRTask();
+}
+
+static void UHS_NI call_ISRodd() {
+ UHS_PIN_WRITE(LED_BUILTIN, HIGH);
+ ISRodd->ISRTask();
+}
+#endif
+
+
+void UHS_NI MAX3421E_HOST::resume_host() {
+ // Used on MCU that lack control of IRQ priority (AVR).
+ // Resumes ISRs.
+ // NOTE: you must track the state yourself!
+#ifdef __AVR__
+ noInterrupts();
+ if(irq_pin & 1) {
+ ISRodd = this;
+ attachInterrupt(UHS_GET_DPI(irq_pin), call_ISRodd, IRQ_SENSE);
+ } else {
+ ISReven = this;
+ attachInterrupt(UHS_GET_DPI(irq_pin), call_ISReven, IRQ_SENSE);
+ }
+ interrupts();
+#endif
+
+}
+/* write single byte into MAX3421e register */
+void UHS_NI MAX3421E_HOST::regWr(uint8_t reg, uint8_t data) {
+ SPIclass.beginTransaction(MAX3421E_SPI_Settings);
+ MARLIN_UHS_WRITE_SS(LOW);
+ SPIclass.transfer(reg | 0x02);
+ SPIclass.transfer(data);
+ MARLIN_UHS_WRITE_SS(HIGH);
+ SPIclass.endTransaction();
+}
+
+
+/* multiple-byte write */
+
+/* returns a pointer to memory position after last written */
+uint8_t* UHS_NI MAX3421E_HOST::bytesWr(uint8_t reg, uint8_t nbytes, uint8_t* data_p) {
+ SPIclass.beginTransaction(MAX3421E_SPI_Settings);
+ MARLIN_UHS_WRITE_SS(LOW);
+ SPIclass.transfer(reg | 0x02);
+ //printf("%2.2x :", reg);
+
+ while(nbytes) {
+ SPIclass.transfer(*data_p);
+ //printf("%2.2x ", *data_p);
+ nbytes--;
+ data_p++; // advance data pointer
+ }
+ MARLIN_UHS_WRITE_SS(HIGH);
+ SPIclass.endTransaction();
+ //printf("\r\n");
+ 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 nibble. 0-3 in IOPINS1, 4-7 in IOPINS2 */
+void UHS_NI MAX3421E_HOST::gpioWr(uint8_t data) {
+ regWr(rIOPINS1, data);
+ data >>= 4;
+ regWr(rIOPINS2, data);
+ return;
+}
+
+/* single host register read */
+uint8_t UHS_NI MAX3421E_HOST::regRd(uint8_t reg) {
+ SPIclass.beginTransaction(MAX3421E_SPI_Settings);
+ MARLIN_UHS_WRITE_SS(LOW);
+ SPIclass.transfer(reg);
+ uint8_t rv = SPIclass.transfer(0);
+ MARLIN_UHS_WRITE_SS(HIGH);
+ SPIclass.endTransaction();
+ return (rv);
+}
+/* multiple-byte register read */
+
+/* returns a pointer to a memory position after last read */
+uint8_t* UHS_NI MAX3421E_HOST::bytesRd(uint8_t reg, uint8_t nbytes, uint8_t* data_p) {
+ SPIclass.beginTransaction(MAX3421E_SPI_Settings);
+ MARLIN_UHS_WRITE_SS(LOW);
+ SPIclass.transfer(reg);
+ while(nbytes) {
+ *data_p++ = SPIclass.transfer(0);
+ nbytes--;
+ }
+ MARLIN_UHS_WRITE_SS(HIGH);
+ SPIclass.endTransaction();
+ return ( data_p);
+}
+
+/* GPIO read. See gpioWr for explanation */
+
+/* GPIN pins are in high nibbles of IOPINS1, IOPINS2 */
+uint8_t UHS_NI MAX3421E_HOST::gpioRd() {
+ uint8_t gpin = 0;
+ gpin = regRd(rIOPINS2); //pins 4-7
+ gpin &= 0xF0; //clean lower nibble
+ gpin |= (regRd(rIOPINS1) >> 4); //shift low bits and OR with upper from previous operation.
+ return ( gpin);
+}
+
+/* reset MAX3421E. Returns number of microseconds it took for PLL to stabilize after reset
+ or zero if PLL haven't stabilized in 65535 cycles */
+uint16_t UHS_NI MAX3421E_HOST::reset() {
+ uint16_t i = 0;
+
+ // Initiate chip reset
+ regWr(rUSBCTL, bmCHIPRES);
+ regWr(rUSBCTL, 0x00);
+
+ int32_t now;
+ uint32_t expires = micros() + 65535;
+
+ // Enable full-duplex SPI so we can read rUSBIRQ
+ regWr(rPINCTL, bmFDUPSPI);
+ while((int32_t)(micros() - expires) < 0L) {
+ if((regRd(rUSBIRQ) & bmOSCOKIRQ)) {
+ break;
+ }
+ }
+ now = (int32_t)(micros() - expires);
+ if(now < 0L) {
+ i = 65535 + now; // Note this subtracts, as now is negative
+ }
+ return (i);
+}
+
+void UHS_NI MAX3421E_HOST::VBUS_changed() {
+ /* modify USB task state because Vbus changed or unknown */
+ uint8_t speed = 1;
+ //printf("\r\n\r\n\r\n\r\nSTATE %2.2x -> ", usb_task_state);
+ switch(vbusState) {
+ case LSHOST: // Low speed
+
+ speed = 0;
+ // Intentional fall-through
+ case FSHOST: // Full speed
+ // Start device initialization if we are not initializing
+ // Resets to the device cause an IRQ
+ // usb_task_state == UHS_USB_HOST_STATE_RESET_NOT_COMPLETE;
+ //if((usb_task_state & UHS_USB_HOST_STATE_MASK) != UHS_USB_HOST_STATE_DETACHED) {
+ ReleaseChildren();
+ if(!doingreset) {
+ if(usb_task_state == UHS_USB_HOST_STATE_RESET_NOT_COMPLETE) {
+ usb_task_state = UHS_USB_HOST_STATE_WAIT_BUS_READY;
+ } else if(usb_task_state != UHS_USB_HOST_STATE_WAIT_BUS_READY) {
+ usb_task_state = UHS_USB_HOST_STATE_DEBOUNCE;
+ }
+ }
+ sof_countdown = 0;
+ break;
+ case SE1: //illegal state
+ sof_countdown = 0;
+ doingreset = false;
+ ReleaseChildren();
+ usb_task_state = UHS_USB_HOST_STATE_ILLEGAL;
+ break;
+ case SE0: //disconnected
+ default:
+ sof_countdown = 0;
+ doingreset = false;
+ ReleaseChildren();
+ usb_task_state = UHS_USB_HOST_STATE_IDLE;
+ break;
+ }
+ usb_host_speed = speed;
+ //printf("0x%2.2x\r\n\r\n\r\n\r\n", usb_task_state);
+ return;
+};
+
+/**
+ * Probe bus to determine device presence and speed,
+ * then switch host to detected speed.
+ */
+void UHS_NI MAX3421E_HOST::busprobe() {
+ uint8_t bus_sample;
+ uint8_t tmpdata;
+ bus_sample = regRd(rHRSL); //Get J,K status
+ bus_sample &= (bmJSTATUS | bmKSTATUS); //zero the rest of the byte
+ switch(bus_sample) { //start full-speed or low-speed host
+ case(bmJSTATUS):
+ // Serial.println("J");
+ 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;
+ }
+ #ifdef USB_HOST_MANUAL_POLL
+ enable_frame_irq(true);
+ #endif
+ tmpdata = regRd(rMODE) | bmSOFKAENAB; // start SOF generation
+ regWr(rHIRQ, bmFRAMEIRQ); // see data sheet.
+ regWr(rMODE, tmpdata);
+ break;
+ case(bmKSTATUS):
+ // Serial.println("K");
+ 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;
+ }
+ #ifdef USB_HOST_MANUAL_POLL
+ enable_frame_irq(true);
+ #endif
+ tmpdata = regRd(rMODE) | bmSOFKAENAB; // start SOF generation
+ regWr(rHIRQ, bmFRAMEIRQ); // see data sheet.
+ regWr(rMODE, tmpdata);
+ break;
+ case(bmSE1): //illegal state
+ // Serial.println("I");
+ regWr(rMODE, bmDPPULLDN | bmDMPULLDN | bmHOST);
+ vbusState = SE1;
+ // sofevent = false;
+ break;
+ case(bmSE0): //disconnected state
+ // Serial.println("D");
+ regWr(rMODE, bmDPPULLDN | bmDMPULLDN | bmHOST);
+ vbusState = SE0;
+ // sofevent = false;
+ break;
+ }//end switch( bus_sample )
+}
+
+/**
+ * Initialize USB hardware, turn on VBUS
+ *
+ * @param mseconds Delay energizing VBUS after mseconds, A value of INT16_MIN means no delay.
+ * @return 0 on success, -1 on error
+ */
+int16_t UHS_NI MAX3421E_HOST::Init(int16_t mseconds) {
+ usb_task_state = UHS_USB_HOST_STATE_INITIALIZE; //set up state machine
+ // Serial.print("MAX3421E 'this' USB Host @ 0x");
+ // Serial.println((uint32_t)this, HEX);
+ // Serial.print("MAX3421E 'this' USB Host Address Pool @ 0x");
+ // Serial.println((uint32_t)GetAddressPool(), HEX);
+ Init_dyn_SWI();
+ UHS_printf_HELPER_init();
+ noInterrupts();
+#ifdef ARDUINO_AVR_ADK
+ // For Mega ADK, which has a Max3421e on-board,
+ // set MAX_RESET to output mode, and then set it to HIGH
+ // PORTJ bit 2
+ if(irq_pin == 54) {
+ DDRJ |= 0x04; // output
+ PORTJ |= 0x04; // HIGH
+ }
+#endif
+ SPIclass.begin();
+#ifdef ARDUINO_AVR_ADK
+ if(irq_pin == 54) {
+ DDRE &= ~0x20; // input
+ PORTE |= 0x20; // pullup
+ } else
+#endif
+ pinMode(irq_pin, INPUT_PULLUP);
+ //UHS_PIN_WRITE(irq_pin, HIGH);
+ pinMode(ss_pin, OUTPUT);
+ MARLIN_UHS_WRITE_SS(HIGH);
+
+#ifdef USB_HOST_SHIELD_TIMING_PIN
+ pinMode(USB_HOST_SHIELD_TIMING_PIN, OUTPUT);
+ // My counter/timer can't work on an inverted gate signal
+ // so we gate using a high pulse -- AJK
+ UHS_PIN_WRITE(USB_HOST_SHIELD_TIMING_PIN, LOW);
+#endif
+ interrupts();
+
+#if USB_HOST_SHIELD_USE_ISR
+ int intr = digitalPinToInterrupt(irq_pin);
+ if(intr == NOT_AN_INTERRUPT) {
+#ifdef ARDUINO_AVR_ADK
+ if(irq_pin == 54)
+ intr = 6;
+ else
+#endif
+ return (-2);
+ }
+ SPIclass.usingInterrupt(intr);
+#else
+ SPIclass.usingInterrupt(255);
+#endif
+#ifndef NO_AUTO_SPEED
+ // test to get to reset acceptance.
+ uint32_t spd = UHS_MAX3421E_SPD;
+again:
+ MAX3421E_SPI_Settings = SPISettings(spd, MSBFIRST, SPI_MODE0);
+ if(reset() == 0) {
+ MAX_HOST_DEBUG(PSTR("Fail SPI speed %lu\r\n"), spd);
+ if(spd > 1999999) {
+ spd -= 1000000;
+ goto again;
+ }
+ return (-1);
+ } else {
+ // reset passes, does 64k?
+ uint8_t sample_wr = 0;
+ uint8_t sample_rd = 0;
+ uint8_t gpinpol_copy = regRd(rGPINPOL);
+ for(uint16_t j = 0; j < 65535; j++) {
+ regWr(rGPINPOL, sample_wr);
+ sample_rd = regRd(rGPINPOL);
+ if(sample_rd != sample_wr) {
+ MAX_HOST_DEBUG(PSTR("Fail SPI speed %lu\r\n"), spd);
+ if(spd > 1999999) {
+ spd -= 1000000;
+ goto again;
+ }
+ return (-1);
+ }
+ sample_wr++;
+ }
+ regWr(rGPINPOL, gpinpol_copy);
+ }
+
+ MAX_HOST_DEBUG(PSTR("Pass SPI speed %lu\r\n"), spd);
+#endif
+
+ if(reset() == 0) { //OSCOKIRQ hasn't asserted in time
+ MAX_HOST_DEBUG(PSTR("OSCOKIRQ hasn't asserted in time"));
+ return ( -1);
+ }
+
+ /* MAX3421E - full-duplex SPI, interrupt kind, vbus off */
+ regWr(rPINCTL, (bmFDUPSPI | bmIRQ_SENSE | GPX_VBDET));
+
+ // 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!
+ if(mseconds != INT16_MIN) {
+ if(mseconds < 1000) mseconds = 1000;
+ delay(mseconds); // We can't depend on SOF timer here.
+ }
+
+ regWr(rMODE, bmDPPULLDN | bmDMPULLDN | bmHOST); // set pull-downs, Host
+
+ // Enable interrupts on the MAX3421e
+ regWr(rHIEN, IRQ_CHECK_MASK);
+ // Enable interrupt pin on the MAX3421e, set pulse width for edge
+ regWr(rCPUCTL, (bmIE | bmPULSEWIDTH));
+
+ /* check if device is connected */
+ regWr(rHCTL, bmSAMPLEBUS); // sample USB bus
+ while(!(regRd(rHCTL) & bmSAMPLEBUS)); //wait for sample operation to finish
+
+ busprobe(); //check if anything is connected
+ VBUS_changed();
+
+ // GPX pin on. This is done here so that a change is detected if we have a switch connected.
+ /* MAX3421E - full-duplex SPI, interrupt kind, vbus on */
+ regWr(rPINCTL, (bmFDUPSPI | bmIRQ_SENSE));
+ regWr(rHIRQ, bmBUSEVENTIRQ); // see data sheet.
+ regWr(rHCTL, bmBUSRST); // issue bus reset to force generate yet another possible IRQ
+
+
+#if USB_HOST_SHIELD_USE_ISR
+ // Attach ISR to service IRQ from MAX3421e
+ noInterrupts();
+ if(irq_pin & 1) {
+ ISRodd = this;
+ attachInterrupt(UHS_GET_DPI(irq_pin), call_ISRodd, IRQ_SENSE);
+ } else {
+ ISReven = this;
+ attachInterrupt(UHS_GET_DPI(irq_pin), call_ISReven, IRQ_SENSE);
+ }
+ interrupts();
+#endif
+ //printf("\r\nrPINCTL 0x%2.2X\r\n", rPINCTL);
+ //printf("rCPUCTL 0x%2.2X\r\n", rCPUCTL);
+ //printf("rHIEN 0x%2.2X\r\n", rHIEN);
+ //printf("irq_pin %i\r\n", irq_pin);
+ return 0;
+}
+
+/**
+ * Setup UHS_EpInfo structure
+ *
+ * @param addr USB device address
+ * @param ep Endpoint
+ * @param ppep pointer to the pointer to a valid UHS_EpInfo structure
+ * @param nak_limit how many NAKs before aborting
+ * @return 0 on success
+ */
+uint8_t UHS_NI MAX3421E_HOST::SetAddress(uint8_t addr, uint8_t ep, UHS_EpInfo **ppep, uint16_t &nak_limit) {
+ UHS_Device *p = addrPool.GetUsbDevicePtr(addr);
+
+ if(!p)
+ return UHS_HOST_ERROR_NO_ADDRESS_IN_POOL;
+
+ if(!p->epinfo)
+ return UHS_HOST_ERROR_NULL_EPINFO;
+
+ *ppep = getEpInfoEntry(addr, ep);
+
+ if(!*ppep)
+ return UHS_HOST_ERROR_NO_ENDPOINT_IN_TABLE;
+
+ nak_limit = (0x0001UL << (((*ppep)->bmNakPower > UHS_USB_NAK_MAX_POWER) ? UHS_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->speed, HEX);
+
+ // Set bmLOWSPEED and bmHUBPRE in case of low-speed device, reset them otherwise
+ regWr(rMODE, (p->speed) ? mode & ~(bmHUBPRE | bmLOWSPEED) : mode | bmLOWSPEED | hub_present);
+
+ return 0;
+}
+
+/**
+ * Receive a packet
+ *
+ * @param pep pointer to a valid UHS_EpInfo structure
+ * @param nak_limit how many NAKs before aborting
+ * @param nbytesptr pointer to maximum number of bytes of data to receive
+ * @param data pointer to data buffer
+ * @return 0 on success
+ */
+uint8_t UHS_NI MAX3421E_HOST::InTransfer(UHS_EpInfo *pep, uint16_t nak_limit, uint16_t *nbytesptr, uint8_t* data) {
+ uint8_t rcode = 0;
+ uint8_t pktsize;
+
+ uint16_t nbytes = *nbytesptr;
+ MAX_HOST_DEBUG(PSTR("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(MAX3421E_tokIN, pep->epAddr, nak_limit); //IN packet to EP-'endpoint'. Function takes care of NAKS.
+#if 0
+ // This issue should be resolved now.
+ if(rcode == UHS_HOST_ERROR_TOGERR) {
+ //MAX_HOST_DEBUG(PSTR("toggle wrong\r\n"));
+ // yes, we flip it wrong here so that next time it is actually correct!
+ pep->bmRcvToggle = (regRd(rHRSL) & bmSNDTOGRD) ? 0 : 1;
+ regWr(rHCTL, (pep->bmRcvToggle) ? bmRCVTOG1 : bmRCVTOG0); //set toggle value
+ continue;
+ }
+#endif
+ if(rcode) {
+ //MAX_HOST_DEBUG(PSTR(">>>>>>>> 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) {
+ //MAX_HOST_DEBUG(PSTR(">>>>>>>> Problem! NO RCVDAVIRQ!\r\n"));
+ rcode = 0xF0; //receive error
+ break;
+ }
+ pktsize = regRd(rRCVBC); //number of received bytes
+ MAX_HOST_DEBUG(PSTR("Got %i bytes \r\n"), pktsize);
+
+ if(pktsize > nbytes) { //certain devices send more than asked
+ //MAX_HOST_DEBUG(PSTR(">>>>>>>> Warning: 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;
+ //MAX_HOST_DEBUG(PSTR("\r\n"));
+ rcode = 0;
+ break;
+ } // if
+ } //while( 1 )
+ return ( rcode);
+}
+
+/**
+ * Transmit a packet
+ *
+ * @param pep pointer to a valid UHS_EpInfo structure
+ * @param nak_limit how many NAKs before aborting
+ * @param nbytes number of bytes of data to send
+ * @param data pointer to data buffer
+ * @return 0 on success
+ */
+uint8_t UHS_NI MAX3421E_HOST::OutTransfer(UHS_EpInfo *pep, uint16_t nak_limit, uint16_t nbytes, uint8_t *data) {
+ uint8_t rcode = UHS_HOST_ERROR_NONE;
+ uint8_t retry_count;
+ uint8_t *data_p = data; //local copy of the data pointer
+ uint16_t bytes_tosend;
+ uint16_t nak_count;
+ uint16_t bytes_left = nbytes;
+
+ uint8_t maxpktsize = pep->maxPktSize;
+
+ if(maxpktsize < 1 || maxpktsize > 64)
+ return UHS_HOST_ERROR_BAD_MAX_PACKET_SIZE;
+
+ unsigned long timeout = millis() + UHS_HOST_TRANSFER_MAX_MS;
+
+ regWr(rHCTL, (pep->bmSndToggle) ? bmSNDTOG1 : bmSNDTOG0); //set toggle value
+
+ while(bytes_left) {
+ SYSTEM_OR_SPECIAL_YIELD();
+ 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, (MAX3421E_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 && ((long)(millis() - timeout) < 0L)) {
+ switch(rcode) {
+ case UHS_HOST_ERROR_NAK:
+ nak_count++;
+ if(nak_limit && (nak_count == nak_limit))
+ goto breakout;
+ break;
+ case UHS_HOST_ERROR_TIMEOUT:
+ retry_count++;
+ if(retry_count == UHS_HOST_TRANSFER_RETRY_MAXIMUM)
+ goto breakout;
+ break;
+ case UHS_HOST_ERROR_TOGERR:
+ // 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, (MAX3421E_tokOUT | pep->epAddr)); //dispatch packet
+ while(!(regRd(rHIRQ) & bmHXFRDNIRQ)); //wait for the completion IRQ
+ regWr(rHIRQ, bmHXFRDNIRQ); //clear IRQ
+ rcode = (regRd(rHRSL) & 0x0F);
+ SYSTEM_OR_SPECIAL_YIELD();
+ }//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
+}
+
+/**
+ * Send the actual packet.
+ *
+ * @param token
+ * @param ep Endpoint
+ * @param nak_limit how many NAKs before aborting, 0 == exit after timeout
+ * @return 0 on success, 0xFF indicates NAK timeout. @see
+ */
+/* 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 UHS_NI MAX3421E_HOST::dispatchPkt(uint8_t token, uint8_t ep, uint16_t nak_limit) {
+ unsigned long timeout = millis() + UHS_HOST_TRANSFER_MAX_MS;
+ uint8_t tmpdata;
+ uint8_t rcode = UHS_HOST_ERROR_NONE;
+ uint8_t retry_count = 0;
+ uint16_t nak_count = 0;
+
+ for(;;) {
+ regWr(rHXFR, (token | ep)); //launch the transfer
+ while((long)(millis() - timeout) < 0L) //wait for transfer completion
+ {
+ SYSTEM_OR_SPECIAL_YIELD();
+ tmpdata = regRd(rHIRQ);
+
+ if(tmpdata & bmHXFRDNIRQ) {
+ regWr(rHIRQ, bmHXFRDNIRQ); //clear the interrupt
+ //rcode = 0x00;
+ break;
+ }//if( tmpdata & bmHXFRDNIRQ
+
+ }//while ( millis() < timeout
+
+ rcode = (regRd(rHRSL) & 0x0F); //analyze transfer result
+
+ switch(rcode) {
+ case UHS_HOST_ERROR_NAK:
+ nak_count++;
+ if(nak_limit && (nak_count == nak_limit))
+ return (rcode);
+ delayMicroseconds(200);
+ break;
+ case UHS_HOST_ERROR_TIMEOUT:
+ retry_count++;
+ if(retry_count == UHS_HOST_TRANSFER_RETRY_MAXIMUM)
+ return (rcode);
+ break;
+ default:
+ return (rcode);
+ }//switch( rcode
+ }
+}
+
+//
+// NULL is error, we don't need to know the reason.
+//
+
+UHS_EpInfo * UHS_NI MAX3421E_HOST::ctrlReqOpen(uint8_t addr, uint64_t Request, uint8_t *dataptr) {
+ uint8_t rcode;
+ UHS_EpInfo *pep = NULL;
+ uint16_t nak_limit = 0;
+ rcode = SetAddress(addr, 0, &pep, nak_limit);
+
+ if(!rcode) {
+
+ bytesWr(rSUDFIFO, 8, (uint8_t*)(&Request)); //transfer to setup packet FIFO
+
+ rcode = dispatchPkt(MAX3421E_tokSETUP, 0, nak_limit); //dispatch packet
+ if(!rcode) {
+ if(dataptr != NULL) {
+ if(((Request)/* bmReqType*/ & 0x80) == 0x80) {
+ pep->bmRcvToggle = 1; //bmRCVTOG1;
+ } else {
+ pep->bmSndToggle = 1; //bmSNDTOG1;
+ }
+ }
+ } else {
+ pep = NULL;
+ }
+ }
+ return pep;
+}
+
+uint8_t UHS_NI MAX3421E_HOST::ctrlReqRead(UHS_EpInfo *pep, uint16_t *left, uint16_t *read, uint16_t nbytes, uint8_t *dataptr) {
+ *read = 0;
+ uint16_t nak_limit = 0;
+ MAX_HOST_DEBUG(PSTR("ctrlReqRead left: %i\r\n"), *left);
+ if(*left) {
+again:
+ *read = nbytes;
+ uint8_t rcode = InTransfer(pep, nak_limit, read, dataptr);
+ if(rcode == UHS_HOST_ERROR_TOGERR) {
+ // yes, we flip it wrong here so that next time it is actually correct!
+ pep->bmRcvToggle = (regRd(rHRSL) & bmSNDTOGRD) ? 0 : 1;
+ goto again;
+ }
+
+ if(rcode) {
+ MAX_HOST_DEBUG(PSTR("ctrlReqRead ERROR: %2.2x, left: %i, read %i\r\n"), rcode, *left, *read);
+ return rcode;
+ }
+ *left -= *read;
+ MAX_HOST_DEBUG(PSTR("ctrlReqRead left: %i, read %i\r\n"), *left, *read);
+ }
+ return 0;
+}
+
+uint8_t UHS_NI MAX3421E_HOST::ctrlReqClose(UHS_EpInfo *pep, uint8_t bmReqType, uint16_t left, uint16_t nbytes, uint8_t *dataptr) {
+ uint8_t rcode = 0;
+
+ //MAX_HOST_DEBUG(PSTR("Closing"));
+ if(((bmReqType & 0x80) == 0x80) && pep && left && dataptr) {
+ MAX_HOST_DEBUG(PSTR("ctrlReqRead Sinking %i\r\n"), left);
+ // If reading, sink the rest of the data.
+ while(left) {
+ uint16_t read = nbytes;
+ rcode = InTransfer(pep, 0, &read, dataptr);
+ if(rcode == UHS_HOST_ERROR_TOGERR) {
+ // yes, we flip it wrong here so that next time it is actually correct!
+ pep->bmRcvToggle = (regRd(rHRSL) & bmSNDTOGRD) ? 0 : 1;
+ continue;
+ }
+ if(rcode) break;
+ left -= read;
+ if(read < nbytes) break;
+ }
+ }
+ if(!rcode) {
+ // Serial.println("Dispatching");
+ rcode = dispatchPkt(((bmReqType & 0x80) == 0x80) ? MAX3421E_tokOUTHS : MAX3421E_tokINHS, 0, 0); //GET if direction
+ // } else {
+ // Serial.println("Bypassed Dispatch");
+ }
+ return rcode;
+}
+
+/**
+ * Bottom half of the ISR task
+ */
+void UHS_NI MAX3421E_HOST::ISRbottom() {
+ uint8_t x;
+ // Serial.print("Enter ");
+ // Serial.print((uint32_t)this,HEX);
+ // Serial.print(" ");
+ // Serial.println(usb_task_state, HEX);
+
+ DDSB();
+ if(condet) {
+ VBUS_changed();
+#if USB_HOST_SHIELD_USE_ISR
+ noInterrupts();
+#endif
+ condet = false;
+#if USB_HOST_SHIELD_USE_ISR
+ interrupts();
+#endif
+ }
+ switch(usb_task_state) {
+ case UHS_USB_HOST_STATE_INITIALIZE:
+ // should never happen...
+ MAX_HOST_DEBUG(PSTR("UHS_USB_HOST_STATE_INITIALIZE\r\n"));
+ busprobe();
+ VBUS_changed();
+ break;
+ case UHS_USB_HOST_STATE_DEBOUNCE:
+ MAX_HOST_DEBUG(PSTR("UHS_USB_HOST_STATE_DEBOUNCE\r\n"));
+ // This seems to not be needed. The host controller has debounce built in.
+ sof_countdown = UHS_HOST_DEBOUNCE_DELAY_MS;
+ usb_task_state = UHS_USB_HOST_STATE_DEBOUNCE_NOT_COMPLETE;
+ break;
+ case UHS_USB_HOST_STATE_DEBOUNCE_NOT_COMPLETE:
+ MAX_HOST_DEBUG(PSTR("UHS_USB_HOST_STATE_DEBOUNCE_NOT_COMPLETE\r\n"));
+ if(!sof_countdown) usb_task_state = UHS_USB_HOST_STATE_RESET_DEVICE;
+ break;
+ case UHS_USB_HOST_STATE_RESET_DEVICE:
+ MAX_HOST_DEBUG(PSTR("UHS_USB_HOST_STATE_RESET_DEVICE\r\n"));
+ busevent = true;
+ usb_task_state = UHS_USB_HOST_STATE_RESET_NOT_COMPLETE;
+ regWr(rHIRQ, bmBUSEVENTIRQ); // see data sheet.
+ regWr(rHCTL, bmBUSRST); // issue bus reset
+ break;
+ case UHS_USB_HOST_STATE_RESET_NOT_COMPLETE:
+ MAX_HOST_DEBUG(PSTR("UHS_USB_HOST_STATE_RESET_NOT_COMPLETE\r\n"));
+ if(!busevent) usb_task_state = UHS_USB_HOST_STATE_WAIT_BUS_READY;
+ break;
+ case UHS_USB_HOST_STATE_WAIT_BUS_READY:
+ MAX_HOST_DEBUG(PSTR("UHS_USB_HOST_STATE_WAIT_BUS_READY\r\n"));
+ usb_task_state = UHS_USB_HOST_STATE_CONFIGURING;
+ break; // don't fall through
+
+ case UHS_USB_HOST_STATE_CONFIGURING:
+ usb_task_state = UHS_USB_HOST_STATE_CHECK;
+ x = Configuring(0, 1, usb_host_speed);
+ usb_error = x;
+ if(usb_task_state == UHS_USB_HOST_STATE_CHECK) {
+ if(x) {
+ MAX_HOST_DEBUG(PSTR("Error 0x%2.2x"), x);
+ if(x == UHS_HOST_ERROR_JERR) {
+ usb_task_state = UHS_USB_HOST_STATE_IDLE;
+ } else if(x != UHS_HOST_ERROR_DEVICE_INIT_INCOMPLETE) {
+ usb_error = x;
+ usb_task_state = UHS_USB_HOST_STATE_ERROR;
+ }
+ } else
+ usb_task_state = UHS_USB_HOST_STATE_CONFIGURING_DONE;
+ }
+ break;
+
+ case UHS_USB_HOST_STATE_CHECK:
+ // Serial.println((uint32_t)__builtin_return_address(0), HEX);
+ break;
+ case UHS_USB_HOST_STATE_CONFIGURING_DONE:
+ usb_task_state = UHS_USB_HOST_STATE_RUNNING;
+ break;
+ #ifdef USB_HOST_MANUAL_POLL
+ case UHS_USB_HOST_STATE_RUNNING:
+ case UHS_USB_HOST_STATE_ERROR:
+ case UHS_USB_HOST_STATE_IDLE:
+ case UHS_USB_HOST_STATE_ILLEGAL:
+ enable_frame_irq(false);
+ break;
+ #else
+ case UHS_USB_HOST_STATE_RUNNING:
+ Poll_Others();
+ for(x = 0; (usb_task_state == UHS_USB_HOST_STATE_RUNNING) && (x < UHS_HOST_MAX_INTERFACE_DRIVERS); x++) {
+ if(devConfig[x]) {
+ if(devConfig[x]->bPollEnable) devConfig[x]->Poll();
+ }
+ }
+ // fall thru
+ #endif
+ default:
+ // Do nothing
+ break;
+ } // switch( usb_task_state )
+ DDSB();
+#if USB_HOST_SHIELD_USE_ISR
+ if(condet) {
+ VBUS_changed();
+ noInterrupts();
+ condet = false;
+ interrupts();
+ }
+#endif
+#ifdef USB_HOST_SHIELD_TIMING_PIN
+ // My counter/timer can't work on an inverted gate signal
+ // so we gate using a high pulse -- AJK
+ UHS_PIN_WRITE(USB_HOST_SHIELD_TIMING_PIN, LOW);
+#endif
+ //usb_task_polling_disabled--;
+ EnablePoll();
+ DDSB();
+}
+
+
+/* USB main task. Services the MAX3421e */
+#if !USB_HOST_SHIELD_USE_ISR
+
+void UHS_NI MAX3421E_HOST::ISRTask() {
+}
+void UHS_NI MAX3421E_HOST::Task()
+#else
+
+void UHS_NI MAX3421E_HOST::Task() {
+#ifdef USB_HOST_MANUAL_POLL
+ if(usb_task_state == UHS_USB_HOST_STATE_RUNNING) {
+ noInterrupts();
+ for(uint8_t x = 0; x < UHS_HOST_MAX_INTERFACE_DRIVERS; x++)
+ if(devConfig[x] && devConfig[x]->bPollEnable)
+ devConfig[x]->Poll();
+ interrupts();
+ }
+#endif
+}
+
+void UHS_NI MAX3421E_HOST::ISRTask()
+#endif
+{
+ DDSB();
+
+#ifndef SWI_IRQ_NUM
+ suspend_host();
+#if USB_HOST_SHIELD_USE_ISR
+ // Enable interrupts
+ interrupts();
+#endif
+#endif
+
+ counted = false;
+ if(!MARLIN_UHS_READ_IRQ()) {
+ uint8_t HIRQALL = regRd(rHIRQ); //determine interrupt source
+ uint8_t HIRQ = HIRQALL & IRQ_CHECK_MASK;
+ uint8_t HIRQ_sendback = 0x00;
+
+ if((HIRQ & bmCONDETIRQ) || (HIRQ & bmBUSEVENTIRQ)) {
+ MAX_HOST_DEBUG
+ (PSTR("\r\nBEFORE CDIRQ %s BEIRQ %s resetting %s state 0x%2.2x\r\n"),
+ (HIRQ & bmCONDETIRQ) ? "T" : "F",
+ (HIRQ & bmBUSEVENTIRQ) ? "T" : "F",
+ doingreset ? "T" : "F",
+ usb_task_state
+ );
+ }
+ // ALWAYS happens BEFORE or WITH CONDETIRQ
+ if(HIRQ & bmBUSEVENTIRQ) {
+ HIRQ_sendback |= bmBUSEVENTIRQ;
+ if(!doingreset) condet = true;
+ busprobe();
+ busevent = false;
+ }
+
+ if(HIRQ & bmCONDETIRQ) {
+ HIRQ_sendback |= bmCONDETIRQ;
+ if(!doingreset) condet = true;
+ busprobe();
+ }
+
+#if 1
+ if((HIRQ & bmCONDETIRQ) || (HIRQ & bmBUSEVENTIRQ)) {
+ MAX_HOST_DEBUG
+ (PSTR("\r\nAFTER CDIRQ %s BEIRQ %s resetting %s state 0x%2.2x\r\n"),
+ (HIRQ & bmCONDETIRQ) ? "T" : "F",
+ (HIRQ & bmBUSEVENTIRQ) ? "T" : "F",
+ doingreset ? "T" : "F",
+ usb_task_state
+ );
+ }
+#endif
+
+ if(HIRQ & bmFRAMEIRQ) {
+ HIRQ_sendback |= bmFRAMEIRQ;
+ if(sof_countdown) {
+ sof_countdown--;
+ counted = true;
+ }
+ sofevent = false;
+ }
+
+ //MAX_HOST_DEBUG(PSTR("\r\n%s%s%s\r\n"),
+ // sof_countdown ? "T" : "F",
+ // counted ? "T" : "F",
+ // usb_task_polling_disabled? "T" : "F");
+ DDSB();
+ regWr(rHIRQ, HIRQ_sendback);
+#ifndef SWI_IRQ_NUM
+ resume_host();
+#if USB_HOST_SHIELD_USE_ISR
+ // Disable interrupts
+ noInterrupts();
+#endif
+#endif
+ if(!sof_countdown && !counted && !usb_task_polling_disabled) {
+ DisablePoll();
+ //usb_task_polling_disabled++;
+#ifdef USB_HOST_SHIELD_TIMING_PIN
+ // My counter/timer can't work on an inverted gate signal
+ // so we gate using a high pulse -- AJK
+ UHS_PIN_WRITE(USB_HOST_SHIELD_TIMING_PIN, HIGH);
+#endif
+
+#ifdef SWI_IRQ_NUM
+ // MAX_HOST_DEBUG(PSTR("--------------- Doing SWI ----------------"));
+ exec_SWI(this);
+#else
+#if USB_HOST_SHIELD_USE_ISR
+ // Enable interrupts
+ interrupts();
+#endif /* USB_HOST_SHIELD_USE_ISR */
+ ISRbottom();
+#endif /* SWI_IRQ_NUM */
+ }
+ }
+}
+
+#if 0
+DDSB();
+#endif
+#else
+#error "Never include USB_HOST_SHIELD_INLINE.h, include UHS_host.h instead"
+#endif
diff --git a/Marlin/src/sd/usb_flashdrive/lib-uhs3/UHS_host/macro_logic.h b/Marlin/src/sd/usb_flashdrive/lib-uhs3/UHS_host/macro_logic.h
new file mode 100644
index 0000000..0ac90f0
--- /dev/null
+++ b/Marlin/src/sd/usb_flashdrive/lib-uhs3/UHS_host/macro_logic.h
@@ -0,0 +1,152 @@
+/*
+ * File: macro_logic.h
+ * Author: root
+ *
+ * Created on December 22, 2018, 4:49 AM
+ *
+ * To test:
+ * gcc -DAJK_TEST_MACRO_LOGIC -E macro_logic.h
+ */
+
+#ifndef MACRO_LOGIC_H
+#define MACRO_LOGIC_H
+
+#define AJK_CAT(a, ...) AJK_PRIMITIVE_CAT(a, __VA_ARGS__)
+#define AJK_PRIMITIVE_CAT(a, ...) a ## __VA_ARGS__
+
+#define AJK_COMPL(b) AJK_PRIMITIVE_CAT(AJK_COMPL_, b)
+#define AJK_COMPL_0 1
+#define AJK_COMPL_1 0
+
+#define AJK_BITAND(x) AJK_PRIMITIVE_CAT(AJK_BITAND_, x)
+#define AJK_BITAND_0(y) 0
+#define AJK_BITAND_1(y) y
+
+#define AJK_INC(x) AJK_PRIMITIVE_CAT(AJK_INC_, x)
+#define AJK_INC_0 1
+#define AJK_INC_1 2
+#define AJK_INC_2 3
+#define AJK_INC_3 4
+#define AJK_INC_4 5
+#define AJK_INC_5 6
+#define AJK_INC_6 7
+#define AJK_INC_7 8
+#define AJK_INC_8 9
+#define AJK_INC_9 10
+#define AJK_INC_10 10
+
+#define AJK_DEC(x) AJK_PRIMITIVE_CAT(AJK_DEC_, x)
+#define AJK_DEC_0 0
+#define AJK_DEC_1 0
+#define AJK_DEC_2 1
+#define AJK_DEC_3 2
+#define AJK_DEC_4 3
+#define AJK_DEC_5 4
+#define AJK_DEC_6 5
+#define AJK_DEC_7 6
+#define AJK_DEC_8 7
+#define AJK_DEC_9 8
+#define AJK_DEC_10 9
+
+#define AJK_CHECK_N(x, n, ...) n
+#define AJK_CHECK(...) AJK_CHECK_N(__VA_ARGS__, 0,)
+#define AJK_PROBE(x) x, 1,
+
+#define AJK_IS_PAREN(x) AJK_CHECK(AJK_IS_PAREN_PROBE x)
+#define AJK_IS_PAREN_PROBE(...) AJK_PROBE(~)
+
+#define AJK_NOT(x) AJK_CHECK(AJK_PRIMITIVE_CAT(AJK_NOT_, x))
+#define AJK_NOT_0 AJK_PROBE(~)
+
+#define AJK_COMPL(b) AJK_PRIMITIVE_CAT(AJK_COMPL_, b)
+#define AJK_COMPL_0 1
+#define AJK_COMPL_1 0
+
+#define AJK_BOOL(x) AJK_COMPL(AJK_NOT(x))
+
+#define AJK_IIF(c) AJK_PRIMITIVE_CAT(AJK_IIF_, c)
+#define AJK_IIF_0(t, ...) __VA_ARGS__
+#define AJK_IIF_1(t, ...) t
+
+#define AJK_IF(c) AJK_IIF(AJK_BOOL(c))
+
+#define AJK_EAT(...)
+#define AJK_EXPAND(...) __VA_ARGS__
+#define AJK_WHEN(c) AJK_IF(c)(AJK_EXPAND, AJK_EAT)
+
+#define AJK_EMPTY()
+#define AJK_DEFER(id) id AJK_EMPTY()
+#define AJK_OBSTRUCT(id) id AJK_DEFER(AJK_EMPTY)()
+
+#define AJK_EVAL(...) AJK_EVAL1(AJK_EVAL1(AJK_EVAL1(__VA_ARGS__)))
+#define AJK_EVAL1(...) AJK_EVAL2(AJK_EVAL2(AJK_EVAL2(__VA_ARGS__)))
+#define AJK_EVAL2(...) AJK_EVAL3(AJK_EVAL3(AJK_EVAL3(__VA_ARGS__)))
+#define AJK_EVAL3(...) AJK_EVAL4(AJK_EVAL4(AJK_EVAL4(__VA_ARGS__)))
+#define AJK_EVAL4(...) AJK_EVAL5(AJK_EVAL5(AJK_EVAL5(__VA_ARGS__)))
+#define AJK_EVAL5(...) __VA_ARGS__
+
+#define AJK_REPEAT(AJK_count, AJK_macro, ...) \
+ AJK_WHEN(AJK_count) \
+ ( \
+ AJK_OBSTRUCT(AJK_REPEAT_INDIRECT) () \
+ ( \
+ AJK_DEC(AJK_count), AJK_macro, __VA_ARGS__ \
+ ) \
+ AJK_OBSTRUCT(AJK_macro) \
+ ( \
+ AJK_DEC(AJK_count), __VA_ARGS__ \
+ ) \
+ )
+#define AJK_REPEAT_INDIRECT() AJK_REPEAT
+
+#define AJK_WHILE(AJK_pred, AJK_op, ...) \
+ IF(AJK_pred(__VA_ARGS__)) \
+ ( \
+ AJK_OBSTRUCT(AJK_WHILE_INDIRECT) () \
+ ( \
+ AJK_pred, AJK_op, AJK_op(__VA_ARGS__) \
+ ), \
+ __VA_ARGS__ \
+ )
+#define AJK_WHILE_INDIRECT() AJK_WHILE
+
+#define AJK_PRIMITIVE_COMPARE(x, y) AJK_IS_PAREN \
+( \
+ AJK_COMPARE_ ## x ( AJK_COMPARE_ ## y) (()) \
+)
+
+#define AJK_IS_COMPARABLE(x) AJK_IS_PAREN( AJK_CAT(AJK_COMPARE_, x) (()) )
+
+#define AJK_NOT_EQUAL(x, y) \
+AJK_IIF(AJK_BITAND(AJK_IS_COMPARABLE(x))(AJK_IS_COMPARABLE(y)) ) \
+( \
+ AJK_PRIMITIVE_COMPARE, \
+ 1 AJK_EAT \
+)(x, y)
+
+#define AJK_EQUAL(x, y) AJK_COMPL(AJK_NOT_EQUAL(x, y))
+
+
+#define AJK_COMMA() ,
+
+#define AJK_COMMA_IF(n) AJK_IF(n)(AJK_COMMA, AJK_EAT)()
+
+
+#define AJK_COMMA_VAR(AJK_count, AJK_v) AJK_COMMA_IF(AJK_count) AJK_v ## AJK_count
+
+#define AJK_MAKE_LIST(AJK_v, AJK_count) AJK_EVAL(AJK_REPEAT(AJK_count, AJK_COMMA_VAR, AJK_v))
+
+#define AJK_FUN(AJK_count, AJK_v, AJK_args, AJK_body) AJK_v ## AJK_count (AJK_args) { AJK_body(AJK_count) }
+#define AJK_MAKE_FUNS(AJK_v, AJK_args, AJK_count, AJK_body) AJK_EVAL(AJK_REPEAT(AJK_count, AJK_FUN, AJK_v, AJK_args, AJK_body))
+#ifdef AJK_TEST_MACRO_LOGIC
+
+#define BODY(AJKindex) some(C, statement); contaning(a, test[AJKindex]);
+#define ZERO_TIMES_TEST 0
+#define THREE_TIMES_TEST 3
+blank > AJK_MAKE_LIST(VARIABLE_, ZERO_TIMES_TEST) < because zero repeats
+Make 3 comma separated indexed variables : AJK_MAKE_LIST(VARIABLE_, THREE_TIMES_TEST)
+Make 3 bogus function bodies
+AJK_MAKE_FUNS(unsigned Cfunc,(arg1, arg2),3,BODY)
+#endif
+
+#endif /* MACRO_LOGIC_H */
diff --git a/Marlin/src/sd/usb_flashdrive/lib-uhs3/dyn_SWI/SWI_INLINE.h b/Marlin/src/sd/usb_flashdrive/lib-uhs3/dyn_SWI/SWI_INLINE.h
new file mode 100644
index 0000000..f86054c
--- /dev/null
+++ b/Marlin/src/sd/usb_flashdrive/lib-uhs3/dyn_SWI/SWI_INLINE.h
@@ -0,0 +1,244 @@
+/*
+ * File: SWI_INLINE.h
+ * Author: xxxajk@gmail.com
+ *
+ * Created on December 5, 2014, 9:40 AM
+ *
+ * This is the actual library.
+ * There are no 'c' or 'cpp' files.
+ *
+ * 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
+ */
+#ifdef DYN_SWI_H
+#ifndef SWI_INLINE_H
+#define SWI_INLINE_H
+
+#ifndef SWI_MAXIMUM_ALLOWED
+#define SWI_MAXIMUM_ALLOWED 4
+#endif
+
+
+
+#if defined(__arm__) || defined(ARDUINO_ARCH_PIC32)
+static char dyn_SWI_initied = 0;
+static dyn_SWI* dyn_SWI_LIST[SWI_MAXIMUM_ALLOWED];
+static dyn_SWI* dyn_SWI_EXEC[SWI_MAXIMUM_ALLOWED];
+#ifdef __arm__
+#ifdef __USE_CMSIS_VECTORS__
+extern "C" {
+ void (*_VectorsRam[VECTORTABLE_SIZE])(void)__attribute__((aligned(VECTORTABLE_ALIGNMENT)));
+}
+#else
+
+__attribute__((always_inline)) static inline void __DSB() {
+ __asm__ volatile ("dsb");
+}
+#endif // defined(__USE_CMSIS_VECTORS__)
+#else // defined(__arm__)
+__attribute__((always_inline)) static inline void __DSB() {
+ __asm__ volatile ("sync" : : : "memory");
+}
+#endif // defined(__arm__)
+
+/**
+ * Execute queued class ISR routines.
+ */
+#ifdef ARDUINO_ARCH_PIC32
+static p32_regset *ifs = ((p32_regset *) & IFS0) + (SWI_IRQ_NUM / 32); //interrupt flag register set
+static p32_regset *iec = ((p32_regset *) & IEC0) + (SWI_IRQ_NUM / 32); //interrupt enable control reg set
+static uint32_t swibit = 1 << (SWI_IRQ_NUM % 32);
+
+void
+#ifdef __PIC32MZXX__
+ __attribute__((nomips16,at_vector(SWI_VECTOR),interrupt(SWI_IPL)))
+#else
+ __attribute__((interrupt(),nomips16))
+#endif
+ softISR() {
+#else
+#ifdef ARDUINO_spresense_ast
+unsigned int softISR() {
+#else
+void softISR() {
+#endif
+#endif
+
+ //
+ // TO-DO: Perhaps limit to 8, and inline this?
+ //
+
+
+ // Make a working copy, while clearing the queue.
+ noInterrupts();
+#ifdef ARDUINO_ARCH_PIC32
+ //ifs->clr = swibit;
+#endif
+ for(int i = 0; i < SWI_MAXIMUM_ALLOWED; i++) {
+ dyn_SWI_EXEC[i] = dyn_SWI_LIST[i];
+ dyn_SWI_LIST[i] = NULL;
+ }
+ __DSB();
+ interrupts();
+
+ // Execute each class SWI
+ for(int i = 0; i < SWI_MAXIMUM_ALLOWED; i++) {
+ if(dyn_SWI_EXEC[i]) {
+#ifdef __DYN_SWI_DEBUG_LED__
+ digitalWrite(__DYN_SWI_DEBUG_LED__, HIGH);
+#endif
+ dyn_SWI_EXEC[i]->dyn_SWISR();
+#ifdef __DYN_SWI_DEBUG_LED__
+ digitalWrite(__DYN_SWI_DEBUG_LED__, LOW);
+#endif
+ }
+ }
+#ifdef ARDUINO_ARCH_PIC32
+ noInterrupts();
+ if(!dyn_SWI_EXEC[0]) ifs->clr = swibit;
+ interrupts();
+#endif
+#ifdef ARDUINO_spresense_ast
+ return 0;
+#endif
+}
+
+#define DDSB() __DSB()
+#endif
+
+
+#ifdef __arm__
+#ifndef interruptsStatus
+#define interruptsStatus() __interruptsStatus()
+static inline unsigned char __interruptsStatus() __attribute__((always_inline, unused));
+
+static inline unsigned char __interruptsStatus() {
+ unsigned int primask;
+ asm volatile ("mrs %0, primask" : "=r" (primask));
+ if(primask) return 0;
+ return 1;
+}
+#endif
+
+/**
+ * Initialize the Dynamic (class) Software Interrupt
+ */
+static void Init_dyn_SWI() {
+ if(!dyn_SWI_initied) {
+#ifdef __USE_CMSIS_VECTORS__
+ uint32_t *X_Vectors = (uint32_t*)SCB->VTOR;
+ for(int i = 0; i < VECTORTABLE_SIZE; i++) {
+ _VectorsRam[i] = reinterpret_cast<void (*)()>(X_Vectors[i]); /* copy vector table to RAM */
+ }
+ /* relocate vector table */
+ noInterrupts();
+ SCB->VTOR = reinterpret_cast<uint32_t>(&_VectorsRam);
+ DDSB();
+ interrupts();
+#endif
+#ifndef ARDUINO_spresense_ast
+ for(int i = 0; i < SWI_MAXIMUM_ALLOWED; i++) dyn_SWI_LIST[i] = NULL;
+ noInterrupts();
+ _VectorsRam[SWI_IRQ_NUM + 16] = reinterpret_cast<void (*)()>(softISR);
+ DDSB();
+ interrupts();
+ NVIC_SET_PRIORITY(SWI_IRQ_NUM, 255);
+ NVIC_ENABLE_IRQ(SWI_IRQ_NUM);
+#endif
+#ifdef __DYN_SWI_DEBUG_LED__
+ pinMode(__DYN_SWI_DEBUG_LED__, OUTPUT);
+ digitalWrite(__DYN_SWI_DEBUG_LED__, LOW);
+#endif
+ dyn_SWI_initied = 1;
+ }
+}
+
+/**
+ * @param klass class that extends dyn_SWI
+ * @return 0 on queue full, else returns queue position (ones based)
+ */
+int exec_SWI(const dyn_SWI* klass) {
+ int rc = 0;
+
+ uint8_t irestore = interruptsStatus();
+ // Allow use from inside a critical section...
+ // ... and prevent races if also used inside an ISR
+ noInterrupts();
+ for(int i = 0; i < SWI_MAXIMUM_ALLOWED; i++) {
+ if(!dyn_SWI_LIST[i]) {
+ rc = 1 + i; // Success!
+ dyn_SWI_LIST[i] = (dyn_SWI*)klass;
+#ifndef ARDUINO_spresense_ast
+ if(!NVIC_GET_PENDING(SWI_IRQ_NUM)) NVIC_SET_PENDING(SWI_IRQ_NUM);
+#else
+ // Launch 1-shot timer as an emulated SWI
+ // Hopefully the value of Zero is legal.
+ // 1 microsecond latency would suck!
+ attachTimerInterrupt(softISR, 100);
+#endif
+ DDSB();
+ break;
+ }
+ }
+ // Restore interrupts, if they were on.
+ if(irestore) interrupts();
+ return rc;
+}
+#elif defined(ARDUINO_ARCH_PIC32)
+
+/**
+ * Initialize the Dynamic (class) Software Interrupt
+ */
+static void Init_dyn_SWI() {
+ if(!dyn_SWI_initied) {
+ uint32_t sreg = disableInterrupts();
+
+ setIntVector(SWI_VECTOR, softISR);
+ setIntPriority(SWI_VECTOR, 1, 1); // Lowest priority, ever.
+ ifs->clr = swibit;
+ iec->clr = swibit;
+ iec->set = swibit;
+ restoreInterrupts(sreg);
+#ifdef __DYN_SWI_DEBUG_LED__
+ pinMode(__DYN_SWI_DEBUG_LED__, OUTPUT);
+ UHS_PIN_WRITE(__DYN_SWI_DEBUG_LED__, LOW);
+#endif
+ }
+}
+
+/**
+ * @param klass class that extends dyn_SWI
+ * @return 0 on queue full, else returns queue position (ones based)
+ */
+int exec_SWI(const dyn_SWI* klass) {
+ int rc = 0;
+ uint32_t sreg = disableInterrupts();
+ for(int i = 0; i < SWI_MAXIMUM_ALLOWED; i++) {
+ if(!dyn_SWI_LIST[i]) {
+ rc = 1 + i; // Success!
+ dyn_SWI_LIST[i] = (dyn_SWI*)klass;
+ if(!(ifs->reg & swibit)) ifs->set = swibit;
+ ;
+ break;
+ }
+ }
+ restoreInterrupts(sreg);
+ return rc;
+}
+
+#endif /* defined(__arm__) */
+#endif /* SWI_INLINE_H */
+#else
+#error "Never include SWI_INLINE.h directly, include dyn_SWI.h instead"
+#endif
diff --git a/Marlin/src/sd/usb_flashdrive/lib-uhs3/dyn_SWI/dyn_SWI.h b/Marlin/src/sd/usb_flashdrive/lib-uhs3/dyn_SWI/dyn_SWI.h
new file mode 100644
index 0000000..07f4ae0
--- /dev/null
+++ b/Marlin/src/sd/usb_flashdrive/lib-uhs3/dyn_SWI/dyn_SWI.h
@@ -0,0 +1,172 @@
+/*
+ * File: dyn_SWI.h
+ * Author: xxxajk@gmail.com
+ *
+ * Created on December 5, 2014, 9:12 AM
+ *
+ * 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
+ */
+
+#ifndef DYN_SWI_H
+#define DYN_SWI_H
+
+
+#if defined(__arm__) || defined(ARDUINO_ARCH_PIC32)
+#ifdef ARDUINO_ARCH_PIC32
+#include <p32xxxx.h>
+#endif
+#ifdef __cplusplus
+
+#ifdef true
+#undef true
+#endif
+
+#ifdef false
+#undef false
+#endif
+
+#endif
+
+#ifdef ARDUINO_spresense_ast
+#define SWI_IRQ_NUM 666 // because this board is totally evil.
+#elif defined(ARDUINO_ARCH_PIC32)
+#ifndef SWI_IRQ_NUM
+#ifdef _DSPI0_IPL_ISR
+#define SWI_IPL _DSPI0_IPL_ISR
+#define SWI_VECTOR _DSPI0_ERR_IRQ
+#define SWI_IRQ_NUM _DSPI0_ERR_IRQ
+#elif defined(_PMP_ERROR_IRQ)
+#define SWI_IRQ_NUM _PMP_ERROR_IRQ
+#define SWI_VECTOR _PMP_VECTOR
+#else
+#error SWI_IRQ_NUM and SWI_VECTOR need a definition
+#endif
+#ifdef __cplusplus
+extern "C"
+{
+ void
+#ifdef __PIC32MZXX__
+ __attribute__((nomips16,at_vector(SWI_VECTOR),interrupt(SWI_IPL)))
+#else
+ __attribute__((interrupt(),nomips16))
+#endif
+ softISR();
+}
+#endif
+#endif
+#elif !defined(NVIC_NUM_INTERRUPTS)
+// Assume CMSIS
+#define __USE_CMSIS_VECTORS__
+#ifdef NUMBER_OF_INT_VECTORS
+#define NVIC_NUM_INTERRUPTS (NUMBER_OF_INT_VECTORS-16)
+#else
+#define NVIC_NUM_INTERRUPTS ((int)PERIPH_COUNT_IRQn)
+#endif
+#define VECTORTABLE_SIZE (NVIC_NUM_INTERRUPTS+16)
+#define VECTORTABLE_ALIGNMENT (0x100UL)
+#define NVIC_GET_ACTIVE(n) NVIC_GetActive((IRQn_Type)n)
+#define NVIC_GET_PENDING(n) NVIC_GetPendingIRQ((IRQn_Type)n)
+#define NVIC_SET_PENDING(n) NVIC_SetPendingIRQ((IRQn_Type)n)
+#define NVIC_ENABLE_IRQ(n) NVIC_EnableIRQ((IRQn_Type)n)
+#define NVIC_SET_PRIORITY(n ,p) NVIC_SetPriority((IRQn_Type)n, (uint32_t) p)
+//extern "C" {
+// extern uint32_t _VectorsRam[VECTORTABLE_SIZE] __attribute__((aligned(VECTORTABLE_ALIGNMENT)));
+//}
+
+#ifndef SWI_IRQ_NUM
+#if defined(__SAM3X8E__) && defined(_VARIANT_ARDUINO_DUE_X_)
+// DUE
+// Choices available:
+// HSMCI_IRQn Multimedia Card Interface (HSMCI)
+// EMAC_IRQn Ethernet MAC (EMAC)
+// EMAC is not broken out on the official DUE, but is on clones.
+// SPI0_IRQn Serial Peripheral Interface (SPI0)
+// SPI0_IRQn seems to be the best choice, as long as nobody uses an ISR based master
+#define SWI_IRQ_NUM SPI0_IRQn
+#elif defined(ARDUINO_SAMD_ZERO)
+// Just use sercom4's unused IRQ vector.
+#define SWI_IRQ_NUM I2S_IRQn
+//#define SWI_IRQ_NUM SERCOM4_IRQn
+#endif
+#endif
+
+#ifndef SWI_IRQ_NUM
+#error SWI_IRQ_NUM not defined (CMSIS)
+#endif
+
+#elif defined(CORE_TEENSY)
+
+#ifndef NVIC_GET_ACTIVE
+#define NVIC_GET_ACTIVE(n) (*((volatile uint32_t *)0xE000E300 + ((n) >> 5)) & (1 << ((n) & 31)))
+#endif
+#ifndef NVIC_GET_PENDING
+#define NVIC_GET_PENDING(n) (*((volatile uint32_t *)0xE000E200 + ((n) >> 5)) & (1 << ((n) & 31)))
+#ifndef SWI_IRQ_NUM
+#ifdef __MK20DX256__
+#define SWI_IRQ_NUM 17
+#elif defined(__MK20DX128__)
+#define SWI_IRQ_NUM 5
+#elif defined(__MKL26Z64__)
+#define SWI_IRQ_NUM 4
+#elif defined(__MK66FX1M0__)
+#define SWI_IRQ_NUM 30
+#elif defined(__MK64FX512__)
+#define SWI_IRQ_NUM 30
+#elif defined(__IMXRT1052__) || defined(__IMXRT1062__)
+#define SWI_IRQ_NUM 71
+#else
+#error Do not know how to relocate IRQ vectors for this pjrc product
+#endif
+#endif
+#endif
+#else // Not CMSIS or PJRC CORE_TEENSY or PIC32 or SPRESENSE
+#error Do not know how to relocate IRQ vectors or perform SWI
+#endif // SWI_IRQ_NUM
+
+
+#ifndef SWI_IRQ_NUM
+#error SWI_IRQ_NUM not defined
+#else
+/**
+ * Use this class to extend your class, in order to provide
+ * a C++ context callable SWI.
+ */
+class dyn_SWI {
+public:
+
+ /**
+ * Override this method with your code.
+ */
+ virtual void dyn_SWISR() {
+ };
+};
+
+extern int exec_SWI(const dyn_SWI* klass);
+
+#include "SWI_INLINE.h"
+
+// IMPORTANT! Define this so that you do NOT end up with a NULL stub!
+#define SWI_NO_STUB
+#endif /* SWI_IRQ_NUM */
+#endif /* __arm__ */
+
+// if no SWI for CPU (e.g. AVR) make a void stub.
+#ifndef SWI_NO_STUB
+#define Init_dyn_SWI() (void(0))
+#ifndef DDSB
+#define DDSB() (void(0))
+#endif
+#endif
+#endif /* DYN_SWI_H */