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