Initial commit. Unusable Marlin 2.0.5.3 core without any custimization.

This commit is contained in:
Knutwurst
2020-06-02 11:44:35 +02:00
commit 987c858ae4
1519 changed files with 1361431 additions and 0 deletions

View File

@@ -0,0 +1,326 @@
/**
* Marlin 3D Printer Firmware
* Copyright (c) 2020 MarlinFirmware [https://github.com/MarlinFirmware/Marlin]
*
* Based on Sprinter and grbl.
* Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#include "../../inc/MarlinConfigPre.h"
/**
* Adjust USB_DEBUG to select debugging verbosity.
* 0 - no debug messages
* 1 - basic insertion/removal messages
* 2 - show USB state transitions
* 3 - perform block range checking
* 4 - print each block access
*/
#define USB_DEBUG 1
#define USB_STARTUP_DELAY 0
// uncomment to get 'printf' console debugging. NOT FOR UNO!
//#define HOST_DEBUG(...) {char s[255]; sprintf(s,__VA_ARGS__); SERIAL_ECHOLNPAIR("UHS:",s);}
//#define BS_HOST_DEBUG(...) {char s[255]; sprintf(s,__VA_ARGS__); SERIAL_ECHOLNPAIR("UHS:",s);}
//#define MAX_HOST_DEBUG(...) {char s[255]; sprintf(s,__VA_ARGS__); SERIAL_ECHOLNPAIR("UHS:",s);}
#if ENABLED(USB_FLASH_DRIVE_SUPPORT)
#include "../../MarlinCore.h"
#include "../../core/serial.h"
#include "../../module/temperature.h"
static_assert(USB_CS_PIN != -1, "USB_CS_PIN must be defined");
static_assert(USB_INTR_PIN != -1, "USB_INTR_PIN must be defined");
#if ENABLED(USE_UHS3_USB)
#define NO_AUTO_SPEED
#define UHS_MAX3421E_SPD 8000000 >> SPI_SPEED
#define UHS_DEVICE_WINDOWS_USB_SPEC_VIOLATION_DESCRIPTOR_DEVICE 1
#define UHS_HOST_MAX_INTERFACE_DRIVERS 2
#define MASS_MAX_SUPPORTED_LUN 1
#define USB_HOST_SERIAL MYSERIAL0
// Workaround for certain issues with UHS3
#define SKIP_PAGE3F // Required for IOGEAR media adapter
#define USB_NO_TEST_UNIT_READY // Required for removable media adapter
#define USB_HOST_MANUAL_POLL // Optimization to shut off IRQ automatically
// Workarounds for keeping Marlin's watchdog timer from barking...
void marlin_yield() {
thermalManager.manage_heater();
}
#define SYSTEM_OR_SPECIAL_YIELD(...) marlin_yield();
#define delay(x) safe_delay(x)
#define LOAD_USB_HOST_SYSTEM
#define LOAD_USB_HOST_SHIELD
#define LOAD_UHS_BULK_STORAGE
#define MARLIN_UHS_WRITE_SS(v) WRITE(USB_CS_PIN, v)
#define MARLIN_UHS_READ_IRQ() READ(USB_INTR_PIN)
#include "lib-uhs3/UHS_host/UHS_host.h"
MAX3421E_HOST usb(USB_CS_PIN, USB_INTR_PIN);
UHS_Bulk_Storage bulk(&usb);
#define UHS_START (usb.Init() == 0)
#define UHS_STATE(state) UHS_USB_HOST_STATE_##state
#else
#include "lib-uhs2/Usb.h"
#include "lib-uhs2/masstorage.h"
USB usb;
BulkOnly bulk(&usb);
#define UHS_START usb.start()
#define UHS_STATE(state) USB_STATE_##state
#endif
#include "Sd2Card_FlashDrive.h"
#if HAS_DISPLAY
#include "../../lcd/ultralcd.h"
#endif
static enum {
UNINITIALIZED,
DO_STARTUP,
WAIT_FOR_DEVICE,
WAIT_FOR_LUN,
MEDIA_READY,
MEDIA_ERROR
} state;
#if USB_DEBUG >= 3
uint32_t lun0_capacity;
#endif
bool Sd2Card::usbStartup() {
if (state <= DO_STARTUP) {
SERIAL_ECHOPGM("Starting USB host...");
if (!UHS_START) {
SERIAL_ECHOLNPGM(" failed.");
#if EITHER(ULTRA_LCD, EXTENSIBLE_UI)
LCD_MESSAGEPGM(MSG_MEDIA_USB_FAILED);
#endif
return false;
}
// SPI quick test - check revision register
switch (usb.regRd(rREVISION)) {
case 0x01: SERIAL_ECHOLNPGM("rev.01 started"); break;
case 0x12: SERIAL_ECHOLNPGM("rev.02 started"); break;
case 0x13: SERIAL_ECHOLNPGM("rev.03 started"); break;
default: SERIAL_ECHOLNPGM("started. rev unknown."); break;
}
state = WAIT_FOR_DEVICE;
}
return true;
}
// The USB library needs to be called periodically to detect USB thumbdrive
// insertion and removals. Call this idle() function periodically to allow
// the USB library to monitor for such events. This function also takes care
// of initializing the USB library for the first time.
void Sd2Card::idle() {
usb.Task();
const uint8_t task_state = usb.getUsbTaskState();
#if USB_DEBUG >= 2
if (state > DO_STARTUP) {
static uint8_t laststate = 232;
if (task_state != laststate) {
laststate = task_state;
#define UHS_USB_DEBUG(x) case UHS_STATE(x): SERIAL_ECHOLNPGM(#x); break
switch (task_state) {
UHS_USB_DEBUG(IDLE);
UHS_USB_DEBUG(RESET_DEVICE);
UHS_USB_DEBUG(RESET_NOT_COMPLETE);
UHS_USB_DEBUG(DEBOUNCE);
UHS_USB_DEBUG(DEBOUNCE_NOT_COMPLETE);
UHS_USB_DEBUG(WAIT_SOF);
UHS_USB_DEBUG(ERROR);
UHS_USB_DEBUG(CONFIGURING);
UHS_USB_DEBUG(CONFIGURING_DONE);
UHS_USB_DEBUG(RUNNING);
default:
SERIAL_ECHOLNPAIR("UHS_USB_HOST_STATE: ", task_state);
break;
}
}
}
#endif
static millis_t next_state_ms = millis();
#define GOTO_STATE_AFTER_DELAY(STATE, DELAY) do{ state = STATE; next_state_ms = millis() + DELAY; }while(0)
if (ELAPSED(millis(), next_state_ms)) {
GOTO_STATE_AFTER_DELAY(state, 250); // Default delay
switch (state) {
case UNINITIALIZED:
#ifndef MANUAL_USB_STARTUP
GOTO_STATE_AFTER_DELAY( DO_STARTUP, USB_STARTUP_DELAY );
#endif
break;
case DO_STARTUP: usbStartup(); break;
case WAIT_FOR_DEVICE:
if (task_state == UHS_STATE(RUNNING)) {
#if USB_DEBUG >= 1
SERIAL_ECHOLNPGM("USB device inserted");
#endif
GOTO_STATE_AFTER_DELAY( WAIT_FOR_LUN, 250 );
}
break;
case WAIT_FOR_LUN:
/* USB device is inserted, but if it is an SD card,
* adapter it may not have an SD card in it yet. */
if (bulk.LUNIsGood(0)) {
#if USB_DEBUG >= 1
SERIAL_ECHOLNPGM("LUN is good");
#endif
GOTO_STATE_AFTER_DELAY( MEDIA_READY, 100 );
}
else {
#ifdef USB_HOST_MANUAL_POLL
// Make sure we catch disconnect events
usb.busprobe();
usb.VBUS_changed();
#endif
#if USB_DEBUG >= 1
SERIAL_ECHOLNPGM("Waiting for media");
#endif
#if EITHER(ULTRA_LCD, EXTENSIBLE_UI)
LCD_MESSAGEPGM(MSG_MEDIA_WAITING);
#endif
GOTO_STATE_AFTER_DELAY(state, 2000);
}
break;
case MEDIA_READY: break;
case MEDIA_ERROR: break;
}
if (state > WAIT_FOR_DEVICE && task_state != UHS_STATE(RUNNING)) {
// Handle device removal events
#if USB_DEBUG >= 1
SERIAL_ECHOLNPGM("USB device removed");
#endif
#if EITHER(ULTRA_LCD, EXTENSIBLE_UI)
if (state != MEDIA_READY)
LCD_MESSAGEPGM(MSG_MEDIA_USB_REMOVED);
#endif
GOTO_STATE_AFTER_DELAY( WAIT_FOR_DEVICE, 0 );
}
else if (state > WAIT_FOR_LUN && !bulk.LUNIsGood(0)) {
// Handle media removal events
#if USB_DEBUG >= 1
SERIAL_ECHOLNPGM("Media removed");
#endif
#if EITHER(ULTRA_LCD, EXTENSIBLE_UI)
LCD_MESSAGEPGM(MSG_MEDIA_REMOVED);
#endif
GOTO_STATE_AFTER_DELAY( WAIT_FOR_DEVICE, 0 );
}
else if (task_state == UHS_STATE(ERROR)) {
#if EITHER(ULTRA_LCD, EXTENSIBLE_UI)
LCD_MESSAGEPGM(MSG_MEDIA_READ_ERROR);
#endif
GOTO_STATE_AFTER_DELAY( MEDIA_ERROR, 0 );
}
}
}
// Marlin calls this function to check whether an USB drive is inserted.
// This is equivalent to polling the SD_DETECT when using SD cards.
bool Sd2Card::isInserted() {
return state == MEDIA_READY;
}
bool Sd2Card::ready() {
return state > DO_STARTUP;
}
// Marlin calls this to initialize an SD card once it is inserted.
bool Sd2Card::init(const uint8_t, const pin_t) {
if (!isInserted()) return false;
#if USB_DEBUG >= 1
const uint32_t sectorSize = bulk.GetSectorSize(0);
if (sectorSize != 512) {
SERIAL_ECHOLNPAIR("Expecting sector size of 512. Got: ", sectorSize);
return false;
}
#endif
#if USB_DEBUG >= 3
lun0_capacity = bulk.GetCapacity(0);
SERIAL_ECHOLNPAIR("LUN Capacity (in blocks): ", lun0_capacity);
#endif
return true;
}
// Returns the capacity of the card in blocks.
uint32_t Sd2Card::cardSize() {
if (!isInserted()) return false;
#if USB_DEBUG < 3
const uint32_t
#endif
lun0_capacity = bulk.GetCapacity(0);
return lun0_capacity;
}
bool Sd2Card::readBlock(uint32_t block, uint8_t* dst) {
if (!isInserted()) return false;
#if USB_DEBUG >= 3
if (block >= lun0_capacity) {
SERIAL_ECHOLNPAIR("Attempt to read past end of LUN: ", block);
return false;
}
#if USB_DEBUG >= 4
SERIAL_ECHOLNPAIR("Read block ", block);
#endif
#endif
return bulk.Read(0, block, 512, 1, dst) == 0;
}
bool Sd2Card::writeBlock(uint32_t block, const uint8_t* src) {
if (!isInserted()) return false;
#if USB_DEBUG >= 3
if (block >= lun0_capacity) {
SERIAL_ECHOLNPAIR("Attempt to write past end of LUN: ", block);
return false;
}
#if USB_DEBUG >= 4
SERIAL_ECHOLNPAIR("Write block ", block);
#endif
#endif
return bulk.Write(0, block, 512, 1, src) == 0;
}
#endif // USB_FLASH_DRIVE_SUPPORT

View File

@@ -0,0 +1,74 @@
/**
* Marlin 3D Printer Firmware
* Copyright (c) 2020 MarlinFirmware [https://github.com/MarlinFirmware/Marlin]
*
* Based on Sprinter and grbl.
* Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#pragma once
/**
* \file
* \brief Sd2Card class for V2 SD/SDHC cards
*/
#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.
#else // SOFTWARE_SPI
#define SD_CHIP_SELECT_PIN 10 // Software SPI chip select pin for the SD
#endif // SOFTWARE_SPI
class Sd2Card {
private:
uint32_t pos;
static void usbStateDebug();
public:
static bool usbStartup();
bool init(const uint8_t sckRateID=0, const pin_t chipSelectPin=SD_CHIP_SELECT_PIN);
static void idle();
inline bool readStart(const uint32_t block) { pos = block; return ready(); }
inline bool readData(uint8_t* dst) { return readBlock(pos++, dst); }
inline bool readStop() const { return true; }
inline bool writeStart(const uint32_t block, const uint32_t) { pos = block; return ready(); }
inline bool writeData(uint8_t* src) { return writeBlock(pos++, src); }
inline bool writeStop() const { return true; }
bool readBlock(uint32_t block, uint8_t* dst);
bool writeBlock(uint32_t blockNumber, const uint8_t* src);
uint32_t cardSize();
static bool isInserted();
static bool ready();
};

View File

@@ -0,0 +1,46 @@
==== 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.
==== LICENSE SUMMARY ====
Source Path: Repository: License:
------------ ----------- --------
lib-uhs3/ github.com/felis/USB_Host_Shield_2.0 GPLv2 or later
lib-uhs3/lib/masstorage.cpp github.com/greiman/UsbFat [1] MIT
lib-uhs3/lib/settings.h github.com/greiman/UsbFat [1] MIT
[1] Changes related to SKIP_WRITE_PROTECT and DELAY only
==== 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

View File

@@ -0,0 +1,798 @@
/**
* 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) && DISABLED(USE_UHS3_USB)
#include "Usb.h"
static uint8_t usb_error = 0;
static uint8_t usb_task_state;
/* constructor */
USB::USB() : bmHubPre(0) {
usb_task_state = USB_DETACHED_SUBSTATE_INITIALIZE; //set up state machine
init();
}
/* Initialize data structures */
void USB::init() {
//devConfigIndex = 0;
bmHubPre = 0;
}
uint8_t USB::getUsbTaskState() {
return usb_task_state;
}
void USB::setUsbTaskState(uint8_t state) {
usb_task_state = state;
}
EpInfo* USB::getEpInfoEntry(uint8_t addr, uint8_t ep) {
UsbDevice *p = addrPool.GetUsbDevicePtr(addr);
if (!p || !p->epinfo)
return nullptr;
EpInfo *pep = p->epinfo;
for (uint8_t i = 0; i < p->epcount; i++) {
if ((pep)->epAddr == ep)
return pep;
pep++;
}
return nullptr;
}
/* set device table entry */
/* each device is different and has different number of endpoints. This function plugs endpoint record structure, defined in application, to devtable */
uint8_t USB::setEpInfoEntry(uint8_t addr, uint8_t epcount, EpInfo* eprecord_ptr) {
if (!eprecord_ptr)
return USB_ERROR_INVALID_ARGUMENT;
UsbDevice *p = addrPool.GetUsbDevicePtr(addr);
if (!p)
return USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL;
p->address.devAddress = addr;
p->epinfo = eprecord_ptr;
p->epcount = epcount;
return 0;
}
uint8_t USB::SetAddress(uint8_t addr, uint8_t ep, EpInfo **ppep, uint16_t *nak_limit) {
UsbDevice *p = addrPool.GetUsbDevicePtr(addr);
if (!p)
return USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL;
if (!p->epinfo)
return USB_ERROR_EPINFO_IS_NULL;
*ppep = getEpInfoEntry(addr, ep);
if (!*ppep)
return USB_ERROR_EP_NOT_FOUND_IN_TBL;
*nak_limit = (0x0001UL << (((*ppep)->bmNakPower > USB_NAK_MAX_POWER) ? USB_NAK_MAX_POWER : (*ppep)->bmNakPower));
(*nak_limit)--;
/*
USBTRACE2("\r\nAddress: ", addr);
USBTRACE2(" EP: ", ep);
USBTRACE2(" NAK Power: ",(*ppep)->bmNakPower);
USBTRACE2(" NAK Limit: ", nak_limit);
USBTRACE("\r\n");
*/
regWr(rPERADDR, addr); //set peripheral address
uint8_t mode = regRd(rMODE);
//Serial.print("\r\nMode: ");
//Serial.println( mode, HEX);
//Serial.print("\r\nLS: ");
//Serial.println(p->lowspeed, HEX);
// Set bmLOWSPEED and bmHUBPRE in case of low-speed device, reset them otherwise
regWr(rMODE, (p->lowspeed) ? mode | bmLOWSPEED | bmHubPre : mode & ~(bmHUBPRE | bmLOWSPEED));
return 0;
}
/* Control transfer. Sets address, endpoint, fills control packet with necessary data, dispatches control packet, and initiates bulk IN transfer, */
/* depending on request. Actual requests are defined as inlines */
/* return codes: */
/* 00 = success */
/* 01-0f = non-zero HRSLT */
uint8_t USB::ctrlReq(uint8_t addr, uint8_t ep, uint8_t bmReqType, uint8_t bRequest, uint8_t wValLo, uint8_t wValHi,
uint16_t wInd, uint16_t total, uint16_t nbytes, uint8_t* dataptr, USBReadParser *p) {
bool direction = false; //request direction, IN or OUT
uint8_t rcode;
SETUP_PKT setup_pkt;
EpInfo *pep = nullptr;
uint16_t nak_limit = 0;
rcode = SetAddress(addr, ep, &pep, &nak_limit);
if (rcode) return rcode;
direction = ((bmReqType & 0x80) > 0);
/* fill in setup packet */
setup_pkt.ReqType_u.bmRequestType = bmReqType;
setup_pkt.bRequest = bRequest;
setup_pkt.wVal_u.wValueLo = wValLo;
setup_pkt.wVal_u.wValueHi = wValHi;
setup_pkt.wIndex = wInd;
setup_pkt.wLength = total;
bytesWr(rSUDFIFO, 8, (uint8_t*) & setup_pkt); //transfer to setup packet FIFO
rcode = dispatchPkt(tokSETUP, ep, nak_limit); //dispatch packet
if (rcode) return rcode; // Return HRSLT if not zero
if (dataptr != nullptr) { //data stage, if present
if (direction) { //IN transfer
uint16_t left = total;
pep->bmRcvToggle = 1; //bmRCVTOG1;
while (left) {
// Bytes read into buffer
uint16_t read = nbytes;
//uint16_t read = (left<nbytes) ? left : nbytes;
rcode = InTransfer(pep, nak_limit, &read, dataptr);
if (rcode == hrTOGERR) {
// yes, we flip it wrong here so that next time it is actually correct!
pep->bmRcvToggle = (regRd(rHRSL) & bmSNDTOGRD) ? 0 : 1;
continue;
}
if (rcode) return rcode;
// Invoke callback function if inTransfer completed successfully and callback function pointer is specified
if (!rcode && p) ((USBReadParser*)p)->Parse(read, dataptr, total - left);
left -= read;
if (read < nbytes) break;
}
}
else { //OUT transfer
pep->bmSndToggle = 1; //bmSNDTOG1;
rcode = OutTransfer(pep, nak_limit, nbytes, dataptr);
}
if (rcode) return rcode; // return error
}
// Status stage
return dispatchPkt((direction) ? tokOUTHS : tokINHS, ep, nak_limit); //GET if direction
}
/* IN transfer to arbitrary endpoint. Assumes PERADDR is set. Handles multiple packets if necessary. Transfers 'nbytes' bytes. */
/* Keep sending INs and writes data to memory area pointed by 'data' */
/* rcode 0 if no errors. rcode 01-0f is relayed from dispatchPkt(). Rcode f0 means RCVDAVIRQ error,
fe USB xfer timeout */
uint8_t USB::inTransfer(uint8_t addr, uint8_t ep, uint16_t *nbytesptr, uint8_t* data, uint8_t bInterval /*= 0*/) {
EpInfo *pep = nullptr;
uint16_t nak_limit = 0;
uint8_t rcode = SetAddress(addr, ep, &pep, &nak_limit);
if (rcode) {
USBTRACE3("(USB::InTransfer) SetAddress Failed ", rcode, 0x81);
USBTRACE3("(USB::InTransfer) addr requested ", addr, 0x81);
USBTRACE3("(USB::InTransfer) ep requested ", ep, 0x81);
return rcode;
}
return InTransfer(pep, nak_limit, nbytesptr, data, bInterval);
}
uint8_t USB::InTransfer(EpInfo *pep, uint16_t nak_limit, uint16_t *nbytesptr, uint8_t* data, uint8_t bInterval /*= 0*/) {
uint8_t rcode = 0;
uint8_t pktsize;
uint16_t nbytes = *nbytesptr;
//printf("Requesting %i bytes ", nbytes);
uint8_t maxpktsize = pep->maxPktSize;
*nbytesptr = 0;
regWr(rHCTL, (pep->bmRcvToggle) ? bmRCVTOG1 : bmRCVTOG0); //set toggle value
// use a 'break' to exit this loop
for (;;) {
rcode = dispatchPkt(tokIN, pep->epAddr, nak_limit); //IN packet to EP-'endpoint'. Function takes care of NAKS.
if (rcode == hrTOGERR) {
// yes, we flip it wrong here so that next time it is actually correct!
pep->bmRcvToggle = (regRd(rHRSL) & bmRCVTOGRD) ? 0 : 1;
regWr(rHCTL, (pep->bmRcvToggle) ? bmRCVTOG1 : bmRCVTOG0); //set toggle value
continue;
}
if (rcode) {
//printf(">>>>>>>> Problem! dispatchPkt %2.2x\r\n", rcode);
break; //should be 0, indicating ACK. Else return error code.
}
/* check for RCVDAVIRQ and generate error if not present */
/* the only case when absence of RCVDAVIRQ makes sense is when toggle error occurred. Need to add handling for that */
if ((regRd(rHIRQ) & bmRCVDAVIRQ) == 0) {
//printf(">>>>>>>> Problem! NO RCVDAVIRQ!\r\n");
rcode = 0xF0; //receive error
break;
}
pktsize = regRd(rRCVBC); //number of received bytes
//printf("Got %i bytes \r\n", pktsize);
// This would be OK, but...
//assert(pktsize <= nbytes);
if (pktsize > nbytes) {
// This can happen. Use of assert on Arduino locks up the Arduino.
// So I will trim the value, and hope for the best.
//printf(">>>>>>>> Problem! Wanted %i bytes but got %i.\r\n", nbytes, pktsize);
pktsize = nbytes;
}
int16_t mem_left = (int16_t)nbytes - *((int16_t*)nbytesptr);
if (mem_left < 0) mem_left = 0;
data = bytesRd(rRCVFIFO, ((pktsize > mem_left) ? mem_left : pktsize), data);
regWr(rHIRQ, bmRCVDAVIRQ); // Clear the IRQ & free the buffer
*nbytesptr += pktsize; // add this packet's byte count to total transfer length
/* The transfer is complete under two conditions: */
/* 1. The device sent a short packet (L.T. maxPacketSize) */
/* 2. 'nbytes' have been transferred. */
if (pktsize < maxpktsize || *nbytesptr >= nbytes) { // Transferred 'nbytes' bytes?
// Save toggle value
pep->bmRcvToggle = ((regRd(rHRSL) & bmRCVTOGRD)) ? 1 : 0;
//printf("\r\n");
rcode = 0;
break;
}
else if (bInterval > 0)
delay(bInterval); // Delay according to polling interval
}
return rcode;
}
/* OUT transfer to arbitrary endpoint. Handles multiple packets if necessary. Transfers 'nbytes' bytes. */
/* Handles NAK bug per Maxim Application Note 4000 for single buffer transfer */
/* rcode 0 if no errors. rcode 01-0f is relayed from HRSL */
uint8_t USB::outTransfer(uint8_t addr, uint8_t ep, uint16_t nbytes, uint8_t* data) {
EpInfo *pep = nullptr;
uint16_t nak_limit = 0;
uint8_t rcode = SetAddress(addr, ep, &pep, &nak_limit);
if (rcode) return rcode;
return OutTransfer(pep, nak_limit, nbytes, data);
}
uint8_t USB::OutTransfer(EpInfo *pep, uint16_t nak_limit, uint16_t nbytes, uint8_t *data) {
uint8_t rcode = hrSUCCESS, retry_count;
uint8_t *data_p = data; //local copy of the data pointer
uint16_t bytes_tosend, nak_count;
uint16_t bytes_left = nbytes;
uint8_t maxpktsize = pep->maxPktSize;
if (maxpktsize < 1 || maxpktsize > 64)
return USB_ERROR_INVALID_MAX_PKT_SIZE;
uint32_t timeout = (uint32_t)millis() + USB_XFER_TIMEOUT;
regWr(rHCTL, (pep->bmSndToggle) ? bmSNDTOG1 : bmSNDTOG0); //set toggle value
while (bytes_left) {
retry_count = 0;
nak_count = 0;
bytes_tosend = (bytes_left >= maxpktsize) ? maxpktsize : bytes_left;
bytesWr(rSNDFIFO, bytes_tosend, data_p); //filling output FIFO
regWr(rSNDBC, bytes_tosend); //set number of bytes
regWr(rHXFR, (tokOUT | pep->epAddr)); //dispatch packet
while (!(regRd(rHIRQ) & bmHXFRDNIRQ)); //wait for the completion IRQ
regWr(rHIRQ, bmHXFRDNIRQ); //clear IRQ
rcode = (regRd(rHRSL) & 0x0F);
while (rcode && ((int32_t)((uint32_t)millis() - timeout) < 0L)) {
switch (rcode) {
case hrNAK:
nak_count++;
if (nak_limit && (nak_count == nak_limit))
goto breakout;
//return ( rcode);
break;
case hrTIMEOUT:
retry_count++;
if (retry_count == USB_RETRY_LIMIT)
goto breakout;
//return ( rcode);
break;
case hrTOGERR:
// yes, we flip it wrong here so that next time it is actually correct!
pep->bmSndToggle = (regRd(rHRSL) & bmSNDTOGRD) ? 0 : 1;
regWr(rHCTL, (pep->bmSndToggle) ? bmSNDTOG1 : bmSNDTOG0); //set toggle value
break;
default:
goto breakout;
}
/* process NAK according to Host out NAK bug */
regWr(rSNDBC, 0);
regWr(rSNDFIFO, *data_p);
regWr(rSNDBC, bytes_tosend);
regWr(rHXFR, (tokOUT | pep->epAddr)); //dispatch packet
while (!(regRd(rHIRQ) & bmHXFRDNIRQ)); //wait for the completion IRQ
regWr(rHIRQ, bmHXFRDNIRQ); //clear IRQ
rcode = (regRd(rHRSL) & 0x0F);
} // while rcode && ....
bytes_left -= bytes_tosend;
data_p += bytes_tosend;
} // while bytes_left...
breakout:
pep->bmSndToggle = (regRd(rHRSL) & bmSNDTOGRD) ? 1 : 0; //bmSNDTOG1 : bmSNDTOG0; //update toggle
return ( rcode); //should be 0 in all cases
}
/* dispatch USB packet. Assumes peripheral address is set and relevant buffer is loaded/empty */
/* If NAK, tries to re-send up to nak_limit times */
/* If nak_limit == 0, do not count NAKs, exit after timeout */
/* If bus timeout, re-sends up to USB_RETRY_LIMIT times */
/* return codes 0x00-0x0F are HRSLT( 0x00 being success ), 0xFF means timeout */
uint8_t USB::dispatchPkt(uint8_t token, uint8_t ep, uint16_t nak_limit) {
uint32_t timeout = (uint32_t)millis() + USB_XFER_TIMEOUT;
uint8_t tmpdata;
uint8_t rcode = hrSUCCESS;
uint8_t retry_count = 0;
uint16_t nak_count = 0;
while ((int32_t)((uint32_t)millis() - timeout) < 0L) {
#if defined(ESP8266) || defined(ESP32)
yield(); // needed in order to reset the watchdog timer on the ESP8266
#endif
regWr(rHXFR, (token | ep)); //launch the transfer
rcode = USB_ERROR_TRANSFER_TIMEOUT;
while ((int32_t)((uint32_t)millis() - timeout) < 0L) { //wait for transfer completion
#if defined(ESP8266) || defined(ESP32)
yield(); // needed to reset the watchdog timer on the ESP8266
#endif
tmpdata = regRd(rHIRQ);
if (tmpdata & bmHXFRDNIRQ) {
regWr(rHIRQ, bmHXFRDNIRQ); //clear the interrupt
rcode = 0x00;
break;
}
} // while millis() < timeout
//if (rcode != 0x00) //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);
}
} // while timeout > millis()
return rcode;
}
/* USB main task. Performs enumeration/cleanup */
void USB::Task() { //USB state machine
uint8_t rcode;
uint8_t tmpdata;
static uint32_t delay = 0;
//USB_DEVICE_DESCRIPTOR buf;
bool lowspeed = false;
MAX3421E::Task();
tmpdata = getVbusState();
/* modify USB task state if Vbus changed */
switch (tmpdata) {
case SE1: //illegal state
usb_task_state = USB_DETACHED_SUBSTATE_ILLEGAL;
lowspeed = false;
break;
case SE0: //disconnected
if ((usb_task_state & USB_STATE_MASK) != USB_STATE_DETACHED)
usb_task_state = USB_DETACHED_SUBSTATE_INITIALIZE;
lowspeed = false;
break;
case LSHOST:
lowspeed = true;
//intentional fallthrough
case FSHOST: //attached
if ((usb_task_state & USB_STATE_MASK) == USB_STATE_DETACHED) {
delay = (uint32_t)millis() + USB_SETTLE_DELAY;
usb_task_state = USB_ATTACHED_SUBSTATE_SETTLE;
}
break;
}
for (uint8_t i = 0; i < USB_NUMDEVICES; i++)
if (devConfig[i]) rcode = devConfig[i]->Poll();
switch (usb_task_state) {
case USB_DETACHED_SUBSTATE_INITIALIZE:
init();
for (uint8_t i = 0; i < USB_NUMDEVICES; i++)
if (devConfig[i])
rcode = devConfig[i]->Release();
usb_task_state = USB_DETACHED_SUBSTATE_WAIT_FOR_DEVICE;
break;
case USB_DETACHED_SUBSTATE_WAIT_FOR_DEVICE: //just sit here
break;
case USB_DETACHED_SUBSTATE_ILLEGAL: //just sit here
break;
case USB_ATTACHED_SUBSTATE_SETTLE: //settle time for just attached device
if ((int32_t)((uint32_t)millis() - delay) >= 0L)
usb_task_state = USB_ATTACHED_SUBSTATE_RESET_DEVICE;
else break; // don't fall through
case USB_ATTACHED_SUBSTATE_RESET_DEVICE:
regWr(rHCTL, bmBUSRST); //issue bus reset
usb_task_state = USB_ATTACHED_SUBSTATE_WAIT_RESET_COMPLETE;
break;
case USB_ATTACHED_SUBSTATE_WAIT_RESET_COMPLETE:
if ((regRd(rHCTL) & bmBUSRST) == 0) {
tmpdata = regRd(rMODE) | bmSOFKAENAB; //start SOF generation
regWr(rMODE, tmpdata);
usb_task_state = USB_ATTACHED_SUBSTATE_WAIT_SOF;
//delay = (uint32_t)millis() + 20; //20ms wait after reset per USB spec
}
break;
case USB_ATTACHED_SUBSTATE_WAIT_SOF: //todo: change check order
if (regRd(rHIRQ) & bmFRAMEIRQ) {
//when first SOF received _and_ 20ms has passed we can continue
/*
if (delay < (uint32_t)millis()) //20ms passed
usb_task_state = USB_STATE_CONFIGURING;
*/
usb_task_state = USB_ATTACHED_SUBSTATE_WAIT_RESET;
delay = (uint32_t)millis() + 20;
}
break;
case USB_ATTACHED_SUBSTATE_WAIT_RESET:
if ((int32_t)((uint32_t)millis() - delay) >= 0L) usb_task_state = USB_STATE_CONFIGURING;
else break; // don't fall through
case USB_STATE_CONFIGURING:
//Serial.print("\r\nConf.LS: ");
//Serial.println(lowspeed, HEX);
rcode = Configuring(0, 0, lowspeed);
if (!rcode)
usb_task_state = USB_STATE_RUNNING;
else if (rcode != USB_DEV_CONFIG_ERROR_DEVICE_INIT_INCOMPLETE) {
usb_error = rcode;
usb_task_state = USB_STATE_ERROR;
}
break;
case USB_STATE_RUNNING:
break;
case USB_STATE_ERROR:
//MAX3421E::Init();
break;
}
}
uint8_t USB::DefaultAddressing(uint8_t parent, uint8_t port, bool lowspeed) {
//uint8_t buf[12];
uint8_t rcode;
UsbDevice *p0 = nullptr, *p = nullptr;
// Get pointer to pseudo device with address 0 assigned
p0 = addrPool.GetUsbDevicePtr(0);
if (!p0) return USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL;
if (!p0->epinfo) return USB_ERROR_EPINFO_IS_NULL;
p0->lowspeed = lowspeed;
// Allocate new address according to device class
uint8_t bAddress = addrPool.AllocAddress(parent, false, port);
if (!bAddress) return USB_ERROR_OUT_OF_ADDRESS_SPACE_IN_POOL;
p = addrPool.GetUsbDevicePtr(bAddress);
if (!p) return USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL;
p->lowspeed = lowspeed;
// Assign new address to the device
rcode = setAddr(0, 0, bAddress);
if (rcode) {
addrPool.FreeAddress(bAddress);
bAddress = 0;
}
return rcode;
}
uint8_t USB::AttemptConfig(uint8_t driver, uint8_t parent, uint8_t port, bool lowspeed) {
//printf("AttemptConfig: parent = %i, port = %i\r\n", parent, port);
uint8_t retries = 0;
again:
uint8_t rcode = devConfig[driver]->ConfigureDevice(parent, port, lowspeed);
if (rcode == USB_ERROR_CONFIG_REQUIRES_ADDITIONAL_RESET) {
if (parent == 0) {
// Send a bus reset on the root interface.
regWr(rHCTL, bmBUSRST); //issue bus reset
delay(102); // delay 102ms, compensate for clock inaccuracy.
}
else {
// reset parent port
devConfig[parent]->ResetHubPort(port);
}
}
else if (rcode == hrJERR && retries < 3) { // Some devices returns this when plugged in - trying to initialize the device again usually works
delay(100);
retries++;
goto again;
}
else if (rcode)
return rcode;
rcode = devConfig[driver]->Init(parent, port, lowspeed);
if (rcode == hrJERR && retries < 3) { // Some devices returns this when plugged in - trying to initialize the device again usually works
delay(100);
retries++;
goto again;
}
if (rcode) {
// Issue a bus reset, because the device may be in a limbo state
if (parent == 0) {
// Send a bus reset on the root interface.
regWr(rHCTL, bmBUSRST); //issue bus reset
delay(102); // delay 102ms, compensate for clock inaccuracy.
}
else {
// reset parent port
devConfig[parent]->ResetHubPort(port);
}
}
return rcode;
}
/**
* This is broken. It needs to enumerate differently.
* It causes major problems with several devices if detected in an unexpected order.
*
* Oleg - I wouldn't do anything before the newly connected device is considered sane.
* i.e.(delays are not indicated for brevity):
* 1. reset
* 2. GetDevDescr();
* 3a. If ACK, continue with allocating address, addressing, etc.
* 3b. Else reset again, count resets, stop at some number (5?).
* 4. When max.number of resets is reached, toggle power/fail
* If desired, this could be modified by performing two resets with GetDevDescr() in the middle - however, from my experience, if a device answers to GDD()
* it doesn't need to be reset again
* New steps proposal:
* 1: get address pool instance. exit on fail
* 2: pUsb->getDevDescr(0, 0, constBufSize, (uint8_t*)buf). exit on fail.
* 3: bus reset, 100ms delay
* 4: set address
* 5: pUsb->setEpInfoEntry(bAddress, 1, epInfo), exit on fail
* 6: while (configurations) {
* for (each configuration) {
* for (each driver) {
* 6a: Ask device if it likes configuration. Returns 0 on OK.
* If successful, the driver configured device.
* The driver now owns the endpoints, and takes over managing them.
* The following will need codes:
* Everything went well, instance consumed, exit with success.
* Instance already in use, ignore it, try next driver.
* Not a supported device, ignore it, try next driver.
* Not a supported configuration for this device, ignore it, try next driver.
* Could not configure device, fatal, exit with fail.
* }
* }
* }
* 7: for (each driver) {
* 7a: Ask device if it knows this VID/PID. Acts exactly like 6a, but using VID/PID
* 8: if we get here, no driver likes the device plugged in, so exit failure.
*
*/
uint8_t USB::Configuring(uint8_t parent, uint8_t port, bool lowspeed) {
//uint8_t bAddress = 0;
//printf("Configuring: parent = %i, port = %i\r\n", parent, port);
uint8_t devConfigIndex;
uint8_t rcode = 0;
uint8_t buf[sizeof (USB_DEVICE_DESCRIPTOR)];
USB_DEVICE_DESCRIPTOR *udd = reinterpret_cast<USB_DEVICE_DESCRIPTOR *>(buf);
UsbDevice *p = nullptr;
EpInfo *oldep_ptr = nullptr;
EpInfo epInfo;
epInfo.epAddr = 0;
epInfo.maxPktSize = 8;
epInfo.bmSndToggle = 0;
epInfo.bmRcvToggle = 0;
epInfo.bmNakPower = USB_NAK_MAX_POWER;
//delay(2000);
AddressPool &addrPool = GetAddressPool();
// Get pointer to pseudo device with address 0 assigned
p = addrPool.GetUsbDevicePtr(0);
if (!p) {
//printf("Configuring error: USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL\r\n");
return USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL;
}
// Save old pointer to EP_RECORD of address 0
oldep_ptr = p->epinfo;
// Temporary assign new pointer to epInfo to p->epinfo in order to
// avoid toggle inconsistence
p->epinfo = &epInfo;
p->lowspeed = lowspeed;
// Get device descriptor
rcode = getDevDescr(0, 0, sizeof (USB_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, pid = udd->idProduct;
uint8_t klass = udd->bDeviceClass, subklass = udd->bDeviceSubClass;
// Attempt to configure if VID/PID or device class matches with a driver
// Qualify with subclass too.
//
// VID/PID & class tests default to false for drivers not yet ported
// subclass defaults to true, so you don't have to define it if you don't have to.
//
for (devConfigIndex = 0; devConfigIndex < USB_NUMDEVICES; devConfigIndex++) {
if (!devConfig[devConfigIndex]) continue; // no driver
if (devConfig[devConfigIndex]->GetAddress()) continue; // consumed
if (devConfig[devConfigIndex]->DEVSUBCLASSOK(subklass) && (devConfig[devConfigIndex]->VIDPIDOK(vid, pid) || devConfig[devConfigIndex]->DEVCLASSOK(klass))) {
rcode = AttemptConfig(devConfigIndex, parent, port, lowspeed);
if (rcode != USB_DEV_CONFIG_ERROR_DEVICE_NOT_SUPPORTED)
break;
}
}
if (devConfigIndex < USB_NUMDEVICES) return rcode;
// blindly attempt to configure
for (devConfigIndex = 0; devConfigIndex < USB_NUMDEVICES; devConfigIndex++) {
if (!devConfig[devConfigIndex]) continue;
if (devConfig[devConfigIndex]->GetAddress()) continue; // consumed
if (devConfig[devConfigIndex]->DEVSUBCLASSOK(subklass) && (devConfig[devConfigIndex]->VIDPIDOK(vid, pid) || devConfig[devConfigIndex]->DEVCLASSOK(klass))) continue; // If this is true it means it must have returned USB_DEV_CONFIG_ERROR_DEVICE_NOT_SUPPORTED above
rcode = AttemptConfig(devConfigIndex, parent, port, lowspeed);
//printf("ERROR ENUMERATING %2.2x\r\n", rcode);
if (!(rcode == USB_DEV_CONFIG_ERROR_DEVICE_NOT_SUPPORTED || rcode == USB_ERROR_CLASS_INSTANCE_ALREADY_IN_USE)) {
// in case of an error dev_index should be reset to 0
// in order to start from the very beginning the
// next time the program gets here
//if (rcode != USB_DEV_CONFIG_ERROR_DEVICE_INIT_INCOMPLETE)
// devConfigIndex = 0;
return rcode;
}
}
// Arriving here means the device class is unsupported by registered classes
return DefaultAddressing(parent, port, lowspeed);
}
uint8_t USB::ReleaseDevice(uint8_t addr) {
if (addr) {
for (uint8_t i = 0; i < USB_NUMDEVICES; i++) {
if (!devConfig[i]) continue;
if (devConfig[i]->GetAddress() == addr)
return devConfig[i]->Release();
}
}
return 0;
}
#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, nullptr);
}
//get configuration descriptor
uint8_t USB::getConfDescr(uint8_t addr, uint8_t ep, uint16_t nbytes, uint8_t conf, uint8_t* dataptr) {
return ctrlReq(addr, ep, bmREQ_GET_DESCR, USB_REQUEST_GET_DESCRIPTOR, conf, USB_DESCRIPTOR_CONFIGURATION, 0x0000, nbytes, nbytes, dataptr, nullptr);
}
/* Requests Configuration Descriptor. Sends two Get Conf Descr requests. The first one gets the total length of all descriptors, then the second one requests this
total length. The length of the first request can be shorter ( 4 bytes ), however, there are devices which won't work unless this length is set to 9 */
uint8_t USB::getConfDescr(uint8_t addr, uint8_t ep, uint8_t conf, USBReadParser *p) {
const uint8_t bufSize = 64;
uint8_t buf[bufSize];
USB_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, nullptr);
}
//set address
uint8_t USB::setAddr(uint8_t oldaddr, uint8_t ep, uint8_t newaddr) {
uint8_t rcode = ctrlReq(oldaddr, ep, bmREQ_SET, USB_REQUEST_SET_ADDRESS, newaddr, 0x00, 0x0000, 0x0000, 0x0000, nullptr, nullptr);
//delay(2); //per USB 2.0 sect.9.2.6.3
delay(300); // Older spec says you should wait at least 200ms
return rcode;
//return ctrlReq(oldaddr, ep, bmREQ_SET, USB_REQUEST_SET_ADDRESS, newaddr, 0x00, 0x0000, 0x0000, 0x0000, nullptr, nullptr);
}
//set configuration
uint8_t USB::setConf(uint8_t addr, uint8_t ep, uint8_t conf_value) {
return ctrlReq(addr, ep, bmREQ_SET, USB_REQUEST_SET_CONFIGURATION, conf_value, 0x00, 0x0000, 0x0000, 0x0000, nullptr, nullptr);
}
#endif // defined(USB_METHODS_INLINE)
#endif // USB_FLASH_DRIVE_SUPPORT

View File

@@ -0,0 +1,53 @@
/**
* Copyright (C) 2011 Circuits At Home, LTD. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* Contact information
* -------------------
*
* Circuits At Home, LTD
* Web : http://www.circuitsathome.com
* e-mail : support@circuitsathome.com
*/
#pragma once
/* USB functions */
#define _usb_h_
#include "../../../inc/MarlinConfigPre.h"
// WARNING: Do not change the order of includes, or stuff will break!
#include <inttypes.h>
#include <stddef.h>
#include <stdio.h>
// None of these should ever be included by a driver, or a user's sketch.
#include "settings.h"
#include "printhex.h"
#include "message.h"
#include "hexdump.h"
//#include "sink_parser.h"
#include "max3421e.h"
#include "address.h"
//#include "avrpins.h"
#include "usb_ch9.h"
#include "usbhost.h"
#include "UsbCore.h"
#include "parsetools.h"
#include "confdescparser.h"
#undef _usb_h_

View File

@@ -0,0 +1,312 @@
/**
* Copyright (C) 2011 Circuits At Home, LTD. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* Contact information
* -------------------
*
* Circuits At Home, LTD
* Web : http://www.circuitsathome.com
* e-mail : support@circuitsathome.com
*/
#ifndef _usb_h_
#error "Never include UsbCore.h directly; include Usb.h instead"
#endif
#pragma once
// Not used anymore? If anyone uses this, please let us know so that this may be
// moved to the proper place, settings.h.
//#define USB_METHODS_INLINE
/* shield pins. First parameter - SS pin, second parameter - INT pin */
#ifdef __MARLIN_FIRMWARE__
typedef MAX3421e MAX3421E; // Marlin redefines this class in "../usb_host.h"
#elif defined(BOARD_BLACK_WIDDOW)
typedef MAX3421e<P6, P3> MAX3421E; // Black Widow
#elif defined(CORE_TEENSY) && (defined(__AVR_AT90USB646__) || defined(__AVR_AT90USB1286__))
#if EXT_RAM
typedef MAX3421e<P20, P7> MAX3421E; // Teensy++ 2.0 with XMEM2
#else
typedef MAX3421e<P9, P8> MAX3421E; // Teensy++ 1.0 and 2.0
#endif
#elif defined(BOARD_MEGA_ADK)
typedef MAX3421e<P53, P54> MAX3421E; // Arduino Mega ADK
#elif defined(ARDUINO_AVR_BALANDUINO)
typedef MAX3421e<P20, P19> MAX3421E; // Balanduino
#elif defined(__ARDUINO_X86__) && PLATFORM_ID == 0x06
typedef MAX3421e<P3, P2> MAX3421E; // The Intel Galileo supports much faster read and write speed at pin 2 and 3
#elif defined(ESP8266)
typedef MAX3421e<P15, P5> MAX3421E; // ESP8266 boards
#elif defined(ESP32)
typedef MAX3421e<P5, P17> MAX3421E; // ESP32 boards
#else
typedef MAX3421e<P10, P9> MAX3421E; // Official Arduinos (UNO, Duemilanove, Mega, 2560, Leonardo, Due etc.), Intel Edison, Intel Galileo 2 or Teensy 2.0 and 3.x
#endif
/* Common setup data constant combinations */
#define bmREQ_GET_DESCR USB_SETUP_DEVICE_TO_HOST|USB_SETUP_TYPE_STANDARD|USB_SETUP_RECIPIENT_DEVICE //get descriptor request type
#define bmREQ_SET USB_SETUP_HOST_TO_DEVICE|USB_SETUP_TYPE_STANDARD|USB_SETUP_RECIPIENT_DEVICE //set request type for all but 'set feature' and 'set interface'
#define bmREQ_CL_GET_INTF USB_SETUP_DEVICE_TO_HOST|USB_SETUP_TYPE_CLASS|USB_SETUP_RECIPIENT_INTERFACE //get interface request type
// D7 data transfer direction (0 - host-to-device, 1 - device-to-host)
// D6-5 Type (0- standard, 1 - class, 2 - vendor, 3 - reserved)
// D4-0 Recipient (0 - device, 1 - interface, 2 - endpoint, 3 - other, 4..31 - reserved)
// USB Device Classes
#define USB_CLASS_USE_CLASS_INFO 0x00 // Use Class Info in the Interface Descriptors
#define USB_CLASS_AUDIO 0x01 // Audio
#define USB_CLASS_COM_AND_CDC_CTRL 0x02 // Communications and CDC Control
#define USB_CLASS_HID 0x03 // HID
#define USB_CLASS_PHYSICAL 0x05 // Physical
#define USB_CLASS_IMAGE 0x06 // Image
#define USB_CLASS_PRINTER 0x07 // Printer
#define USB_CLASS_MASS_STORAGE 0x08 // Mass Storage
#define USB_CLASS_HUB 0x09 // Hub
#define USB_CLASS_CDC_DATA 0x0a // CDC-Data
#define USB_CLASS_SMART_CARD 0x0b // Smart-Card
#define USB_CLASS_CONTENT_SECURITY 0x0d // Content Security
#define USB_CLASS_VIDEO 0x0e // Video
#define USB_CLASS_PERSONAL_HEALTH 0x0f // Personal Healthcare
#define USB_CLASS_DIAGNOSTIC_DEVICE 0xdc // Diagnostic Device
#define USB_CLASS_WIRELESS_CTRL 0xe0 // Wireless Controller
#define USB_CLASS_MISC 0xef // Miscellaneous
#define USB_CLASS_APP_SPECIFIC 0xfe // Application Specific
#define USB_CLASS_VENDOR_SPECIFIC 0xff // Vendor Specific
// Additional Error Codes
#define USB_DEV_CONFIG_ERROR_DEVICE_NOT_SUPPORTED 0xD1
#define USB_DEV_CONFIG_ERROR_DEVICE_INIT_INCOMPLETE 0xD2
#define USB_ERROR_UNABLE_TO_REGISTER_DEVICE_CLASS 0xD3
#define USB_ERROR_OUT_OF_ADDRESS_SPACE_IN_POOL 0xD4
#define USB_ERROR_HUB_ADDRESS_OVERFLOW 0xD5
#define USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL 0xD6
#define USB_ERROR_EPINFO_IS_NULL 0xD7
#define USB_ERROR_INVALID_ARGUMENT 0xD8
#define USB_ERROR_CLASS_INSTANCE_ALREADY_IN_USE 0xD9
#define USB_ERROR_INVALID_MAX_PKT_SIZE 0xDA
#define USB_ERROR_EP_NOT_FOUND_IN_TBL 0xDB
#define USB_ERROR_CONFIG_REQUIRES_ADDITIONAL_RESET 0xE0
#define USB_ERROR_FailGetDevDescr 0xE1
#define USB_ERROR_FailSetDevTblEntry 0xE2
#define USB_ERROR_FailGetConfDescr 0xE3
#define USB_ERROR_TRANSFER_TIMEOUT 0xFF
#define USB_XFER_TIMEOUT 5000 // (5000) USB transfer timeout in milliseconds, per section 9.2.6.1 of USB 2.0 spec
//#define USB_NAK_LIMIT 32000 // NAK limit for a transfer. 0 means NAKs are not counted
#define USB_RETRY_LIMIT 3 // 3 retry limit for a transfer
#define USB_SETTLE_DELAY 200 // settle delay in milliseconds
#define USB_NUMDEVICES 16 //number of USB devices
//#define HUB_MAX_HUBS 7 // maximum number of hubs that can be attached to the host controller
#define HUB_PORT_RESET_DELAY 20 // hub port reset delay 10 ms recomended, can be up to 20 ms
/* USB state machine states */
#define USB_STATE_MASK 0xf0
#define USB_STATE_DETACHED 0x10
#define USB_DETACHED_SUBSTATE_INITIALIZE 0x11
#define USB_DETACHED_SUBSTATE_WAIT_FOR_DEVICE 0x12
#define USB_DETACHED_SUBSTATE_ILLEGAL 0x13
#define USB_ATTACHED_SUBSTATE_SETTLE 0x20
#define USB_ATTACHED_SUBSTATE_RESET_DEVICE 0x30
#define USB_ATTACHED_SUBSTATE_WAIT_RESET_COMPLETE 0x40
#define USB_ATTACHED_SUBSTATE_WAIT_SOF 0x50
#define USB_ATTACHED_SUBSTATE_WAIT_RESET 0x51
#define USB_ATTACHED_SUBSTATE_GET_DEVICE_DESCRIPTOR_SIZE 0x60
#define USB_STATE_ADDRESSING 0x70
#define USB_STATE_CONFIGURING 0x80
#define USB_STATE_RUNNING 0x90
#define USB_STATE_ERROR 0xa0
class USBDeviceConfig {
public:
virtual uint8_t Init(uint8_t parent __attribute__((unused)), uint8_t port __attribute__((unused)), bool lowspeed __attribute__((unused))) {
return 0;
}
virtual uint8_t ConfigureDevice(uint8_t parent __attribute__((unused)), uint8_t port __attribute__((unused)), bool lowspeed __attribute__((unused))) {
return 0;
}
virtual uint8_t Release() {
return 0;
}
virtual uint8_t Poll() {
return 0;
}
virtual uint8_t GetAddress() {
return 0;
}
virtual void ResetHubPort(uint8_t port __attribute__((unused))) {
return;
} // Note used for hubs only!
virtual bool VIDPIDOK(uint16_t vid __attribute__((unused)), uint16_t pid __attribute__((unused))) {
return false;
}
virtual bool DEVCLASSOK(uint8_t klass __attribute__((unused))) {
return false;
}
virtual bool DEVSUBCLASSOK(uint8_t subklass __attribute__((unused))) {
return true;
}
};
/* USB Setup Packet Structure */
typedef struct {
union { // offset description
uint8_t bmRequestType; // 0 Bit-map of request type
struct {
uint8_t recipient : 5; // Recipient of the request
uint8_t type : 2; // Type of request
uint8_t direction : 1; // Direction of data X-fer
} __attribute__((packed));
} ReqType_u;
uint8_t bRequest; // 1 Request
union {
uint16_t wValue; // 2 Depends on bRequest
struct {
uint8_t wValueLo;
uint8_t wValueHi;
} __attribute__((packed));
} wVal_u;
uint16_t wIndex; // 4 Depends on bRequest
uint16_t wLength; // 6 Depends on bRequest
} __attribute__((packed)) SETUP_PKT, *PSETUP_PKT;
// Base class for incoming data parser
class USBReadParser {
public:
virtual void Parse(const uint16_t len, const uint8_t *pbuf, const uint16_t &offset) = 0;
};
class USB : public MAX3421E {
AddressPoolImpl<USB_NUMDEVICES> addrPool;
USBDeviceConfig* devConfig[USB_NUMDEVICES];
uint8_t bmHubPre;
public:
USB();
void SetHubPreMask() {
bmHubPre |= bmHUBPRE;
};
void ResetHubPreMask() {
bmHubPre &= (~bmHUBPRE);
};
AddressPool& GetAddressPool() {
return (AddressPool&)addrPool;
};
uint8_t RegisterDeviceClass(USBDeviceConfig *pdev) {
for (uint8_t i = 0; i < USB_NUMDEVICES; i++) {
if (!devConfig[i]) {
devConfig[i] = pdev;
return 0;
}
}
return USB_ERROR_UNABLE_TO_REGISTER_DEVICE_CLASS;
};
void ForEachUsbDevice(UsbDeviceHandleFunc pfunc) {
addrPool.ForEachUsbDevice(pfunc);
};
uint8_t getUsbTaskState();
void setUsbTaskState(uint8_t state);
EpInfo* getEpInfoEntry(uint8_t addr, uint8_t ep);
uint8_t setEpInfoEntry(uint8_t addr, uint8_t epcount, EpInfo* eprecord_ptr);
/* Control requests */
uint8_t getDevDescr(uint8_t addr, uint8_t ep, uint16_t nbytes, uint8_t* dataptr);
uint8_t getConfDescr(uint8_t addr, uint8_t ep, uint16_t nbytes, uint8_t conf, uint8_t* dataptr);
uint8_t getConfDescr(uint8_t addr, uint8_t ep, uint8_t conf, USBReadParser *p);
uint8_t getStrDescr(uint8_t addr, uint8_t ep, uint16_t nbytes, uint8_t index, uint16_t langid, uint8_t* dataptr);
uint8_t setAddr(uint8_t oldaddr, uint8_t ep, uint8_t newaddr);
uint8_t setConf(uint8_t addr, uint8_t ep, uint8_t conf_value);
/**/
uint8_t ctrlData(uint8_t addr, uint8_t ep, uint16_t nbytes, uint8_t* dataptr, bool direction);
uint8_t ctrlStatus(uint8_t ep, bool direction, uint16_t nak_limit);
uint8_t inTransfer(uint8_t addr, uint8_t ep, uint16_t *nbytesptr, uint8_t* data, uint8_t bInterval = 0);
uint8_t outTransfer(uint8_t addr, uint8_t ep, uint16_t nbytes, uint8_t* data);
uint8_t dispatchPkt(uint8_t token, uint8_t ep, uint16_t nak_limit);
void Task();
uint8_t DefaultAddressing(uint8_t parent, uint8_t port, bool lowspeed);
uint8_t Configuring(uint8_t parent, uint8_t port, bool lowspeed);
uint8_t ReleaseDevice(uint8_t addr);
uint8_t ctrlReq(uint8_t addr, uint8_t ep, uint8_t bmReqType, uint8_t bRequest, uint8_t wValLo, uint8_t wValHi,
uint16_t wInd, uint16_t total, uint16_t nbytes, uint8_t* dataptr, USBReadParser *p);
private:
void init();
uint8_t SetAddress(uint8_t addr, uint8_t ep, EpInfo **ppep, uint16_t *nak_limit);
uint8_t OutTransfer(EpInfo *pep, uint16_t nak_limit, uint16_t nbytes, uint8_t *data);
uint8_t InTransfer(EpInfo *pep, uint16_t nak_limit, uint16_t *nbytesptr, uint8_t *data, uint8_t bInterval = 0);
uint8_t AttemptConfig(uint8_t driver, uint8_t parent, uint8_t port, bool lowspeed);
};
#if 0 //defined(USB_METHODS_INLINE)
//get device descriptor
inline uint8_t USB::getDevDescr(uint8_t addr, uint8_t ep, uint16_t nbytes, uint8_t* dataptr) {
return ( ctrlReq(addr, ep, bmREQ_GET_DESCR, USB_REQUEST_GET_DESCRIPTOR, 0x00, USB_DESCRIPTOR_DEVICE, 0x0000, nbytes, dataptr));
}
//get configuration descriptor
inline uint8_t USB::getConfDescr(uint8_t addr, uint8_t ep, uint16_t nbytes, uint8_t conf, uint8_t* dataptr) {
return ( ctrlReq(addr, ep, bmREQ_GET_DESCR, USB_REQUEST_GET_DESCRIPTOR, conf, USB_DESCRIPTOR_CONFIGURATION, 0x0000, nbytes, dataptr));
}
//get string descriptor
inline uint8_t USB::getStrDescr(uint8_t addr, uint8_t ep, uint16_t nuint8_ts, uint8_t index, uint16_t langid, uint8_t* dataptr) {
return ( ctrlReq(addr, ep, bmREQ_GET_DESCR, USB_REQUEST_GET_DESCRIPTOR, index, USB_DESCRIPTOR_STRING, langid, nuint8_ts, dataptr));
}
//set address
inline uint8_t USB::setAddr(uint8_t oldaddr, uint8_t ep, uint8_t newaddr) {
return ( ctrlReq(oldaddr, ep, bmREQ_SET, USB_REQUEST_SET_ADDRESS, newaddr, 0x00, 0x0000, 0x0000, nullptr));
}
//set configuration
inline uint8_t USB::setConf(uint8_t addr, uint8_t ep, uint8_t conf_value) {
return ( ctrlReq(addr, ep, bmREQ_SET, USB_REQUEST_SET_CONFIGURATION, conf_value, 0x00, 0x0000, 0x0000, nullptr));
}
#endif // defined(USB_METHODS_INLINE)

View File

@@ -0,0 +1,271 @@
/**
* Copyright (C) 2011 Circuits At Home, LTD. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* Contact information
* -------------------
*
* Circuits At Home, LTD
* Web : http://www.circuitsathome.com
* e-mail : support@circuitsathome.com
*/
#pragma once
#ifndef _usb_h_
#error "Never include address.h directly; include Usb.h instead"
#endif
/* NAK powers. To save space in endpoint data structure, amount of retries before giving up and returning 0x4 is stored in */
/* bmNakPower as a power of 2. The actual nak_limit is then calculated as nak_limit = ( 2^bmNakPower - 1) */
#define USB_NAK_MAX_POWER 15 //NAK binary order maximum value
#define USB_NAK_DEFAULT 14 //default 32K-1 NAKs before giving up
#define USB_NAK_NOWAIT 1 //Single NAK stops transfer
#define USB_NAK_NONAK 0 //Do not count NAKs, stop retrying after USB Timeout
struct EpInfo {
uint8_t epAddr; // Endpoint address
uint8_t maxPktSize; // Maximum packet size
union {
uint8_t epAttribs;
struct {
uint8_t bmSndToggle : 1; // Send toggle, when zero bmSNDTOG0, bmSNDTOG1 otherwise
uint8_t bmRcvToggle : 1; // Send toggle, when zero bmRCVTOG0, bmRCVTOG1 otherwise
uint8_t bmNakPower : 6; // Binary order for NAK_LIMIT value
} __attribute__((packed));
};
} __attribute__((packed));
// 7 6 5 4 3 2 1 0
// ---------------------------------
// | | H | P | P | P | A | A | A |
// ---------------------------------
//
// H - if 1 the address is a hub address
// P - parent hub address
// A - device address / port number in case of hub
//
struct UsbDeviceAddress {
union {
struct {
uint8_t bmAddress : 3; // device address/port number
uint8_t bmParent : 3; // parent hub address
uint8_t bmHub : 1; // hub flag
uint8_t bmReserved : 1; // reserved, must be zero
} __attribute__((packed));
uint8_t devAddress;
};
} __attribute__((packed));
#define bmUSB_DEV_ADDR_ADDRESS 0x07
#define bmUSB_DEV_ADDR_PARENT 0x38
#define bmUSB_DEV_ADDR_HUB 0x40
struct UsbDevice {
EpInfo *epinfo; // endpoint info pointer
UsbDeviceAddress address;
uint8_t epcount; // number of endpoints
bool lowspeed; // indicates if a device is the low speed one
// uint8_t devclass; // device class
} __attribute__((packed));
class AddressPool {
public:
virtual UsbDevice* GetUsbDevicePtr(uint8_t addr) = 0;
virtual uint8_t AllocAddress(uint8_t parent, bool is_hub = false, uint8_t port = 0) = 0;
virtual void FreeAddress(uint8_t addr) = 0;
};
typedef void (*UsbDeviceHandleFunc)(UsbDevice *pdev);
#define ADDR_ERROR_INVALID_INDEX 0xFF
#define ADDR_ERROR_INVALID_ADDRESS 0xFF
template <const uint8_t MAX_DEVICES_ALLOWED>
class AddressPoolImpl : public AddressPool {
EpInfo dev0ep; //Endpoint data structure used during enumeration for uninitialized device
uint8_t hubCounter; // hub counter is kept
// in order to avoid hub address duplication
UsbDevice thePool[MAX_DEVICES_ALLOWED];
// Initialize address pool entry
void InitEntry(uint8_t index) {
thePool[index].address.devAddress = 0;
thePool[index].epcount = 1;
thePool[index].lowspeed = 0;
thePool[index].epinfo = &dev0ep;
}
// Return thePool index for a given address
uint8_t FindAddressIndex(uint8_t address = 0) {
for (uint8_t i = 1; i < MAX_DEVICES_ALLOWED; i++)
if (thePool[i].address.devAddress == address)
return i;
return 0;
}
// Return thePool child index for a given parent
uint8_t FindChildIndex(UsbDeviceAddress addr, uint8_t start = 1) {
for (uint8_t i = (start < 1 || start >= MAX_DEVICES_ALLOWED) ? 1 : start; i < MAX_DEVICES_ALLOWED; i++) {
if (thePool[i].address.bmParent == addr.bmAddress)
return i;
}
return 0;
}
// Frees address entry specified by index parameter
void FreeAddressByIndex(uint8_t index) {
// Zero field is reserved and should not be affected
if (index == 0) return;
UsbDeviceAddress uda = thePool[index].address;
// If a hub was switched off all port addresses should be freed
if (uda.bmHub == 1) {
for (uint8_t i = 1; (i = FindChildIndex(uda, i));)
FreeAddressByIndex(i);
// If the hub had the last allocated address, hubCounter should be decremented
if (hubCounter == uda.bmAddress) hubCounter--;
}
InitEntry(index);
}
// Initialize the whole address pool at once
void InitAllAddresses() {
for (uint8_t i = 1; i < MAX_DEVICES_ALLOWED; i++)
InitEntry(i);
hubCounter = 0;
}
public:
AddressPoolImpl() : hubCounter(0) {
// Zero address is reserved
InitEntry(0);
thePool[0].address.devAddress = 0;
thePool[0].epinfo = &dev0ep;
dev0ep.epAddr = 0;
dev0ep.maxPktSize = 8;
dev0ep.bmSndToggle = 0; // Set DATA0/1 toggles to 0
dev0ep.bmRcvToggle = 0;
dev0ep.bmNakPower = USB_NAK_MAX_POWER;
InitAllAddresses();
}
// Return a pointer to a specified address entry
virtual UsbDevice* GetUsbDevicePtr(uint8_t addr) {
if (!addr) return thePool;
uint8_t index = FindAddressIndex(addr);
return index ? thePool + index : nullptr;
}
// Perform an operation specified by pfunc for each addressed device
void ForEachUsbDevice(UsbDeviceHandleFunc pfunc) {
if (pfunc) {
for (uint8_t i = 1; i < MAX_DEVICES_ALLOWED; i++)
if (thePool[i].address.devAddress)
pfunc(thePool + i);
}
}
// Allocate new address
virtual uint8_t AllocAddress(uint8_t parent, bool is_hub = false, uint8_t port = 0) {
/* if (parent != 0 && port == 0)
USB_HOST_SERIAL.println("PRT:0"); */
UsbDeviceAddress _parent;
_parent.devAddress = parent;
if (_parent.bmReserved || port > 7)
//if(parent > 127 || port > 7)
return 0;
if (is_hub && hubCounter == 7) return 0;
// finds first empty address entry starting from one
uint8_t index = FindAddressIndex(0);
if (!index) return 0; // if empty entry is not found
if (_parent.devAddress == 0) {
if (is_hub) {
thePool[index].address.devAddress = 0x41;
hubCounter++;
}
else
thePool[index].address.devAddress = 1;
return thePool[index].address.devAddress;
}
UsbDeviceAddress addr;
addr.devAddress = 0; // Ensure all bits are zero
addr.bmParent = _parent.bmAddress;
if (is_hub) {
addr.bmHub = 1;
addr.bmAddress = ++hubCounter;
}
else {
addr.bmHub = 0;
addr.bmAddress = port;
}
thePool[index].address = addr;
/*
USB_HOST_SERIAL.print("Addr:");
USB_HOST_SERIAL.print(addr.bmHub, HEX);
USB_HOST_SERIAL.print(".");
USB_HOST_SERIAL.print(addr.bmParent, HEX);
USB_HOST_SERIAL.print(".");
USB_HOST_SERIAL.println(addr.bmAddress, HEX);
*/
return thePool[index].address.devAddress;
}
// Empty the pool entry
virtual void FreeAddress(uint8_t addr) {
// if the root hub is disconnected all the addresses should be initialized
if (addr == 0x41) {
InitAllAddresses();
return;
}
FreeAddressByIndex(FindAddressIndex(addr));
}
// Return number of hubs attached
// It can be helpful to find out if hubs are attached when getting the exact number of hubs.
//uint8_t GetNumHubs() { return hubCounter; }
//uint8_t GetNumDevices() {
// uint8_t counter = 0;
// for (uint8_t i = 1; i < MAX_DEVICES_ALLOWED; i++)
// if (thePool[i].address != 0); counter++;
// return counter;
//}
};

View File

@@ -0,0 +1,201 @@
/**
* Copyright (C) 2011 Circuits At Home, LTD. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* Contact information
* -------------------
*
* Circuits At Home, LTD
* Web : http://www.circuitsathome.com
* e-mail : support@circuitsathome.com
*/
#pragma once
#ifndef _usb_h_
#error "Never include confdescparser.h directly; include Usb.h instead"
#endif
class UsbConfigXtracter {
public:
//virtual void ConfigXtract(const USB_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() { 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 && 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);
}

View File

@@ -0,0 +1,68 @@
/**
* Copyright (C) 2011 Circuits At Home, LTD. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* Contact information
* -------------------
*
* Circuits At Home, LTD
* Web : http://www.circuitsathome.com
* e-mail : support@circuitsathome.com
*/
#pragma once
#ifndef _usb_h_
#error "Never include hexdump.h directly; include Usb.h instead"
#endif
extern int UsbDEBUGlvl;
template <class BASE_CLASS, class LEN_TYPE, class OFFSET_TYPE>
class HexDumper : public BASE_CLASS {
uint8_t byteCount;
OFFSET_TYPE byteTotal;
public:
HexDumper() : byteCount(0), byteTotal(0) {
};
void Initialize() {
byteCount = 0;
byteTotal = 0;
};
void Parse(const LEN_TYPE len, const uint8_t *pbuf, const OFFSET_TYPE &offset);
};
template <class BASE_CLASS, class LEN_TYPE, class OFFSET_TYPE>
void HexDumper<BASE_CLASS, LEN_TYPE, OFFSET_TYPE>::Parse(const LEN_TYPE len, const uint8_t *pbuf, const OFFSET_TYPE &offset __attribute__((unused))) {
if (UsbDEBUGlvl >= 0x80) { // Fully bypass this block of code if we do not debug.
for (LEN_TYPE j = 0; j < len; j++, byteCount++, byteTotal++) {
if (!byteCount) {
PrintHex<OFFSET_TYPE > (byteTotal, 0x80);
E_Notify(PSTR(": "), 0x80);
}
PrintHex<uint8_t > (pbuf[j], 0x80);
E_Notify(PSTR(" "), 0x80);
if (byteCount == 15) {
E_Notify(PSTR("\r\n"), 0x80);
byteCount = 0xFF;
}
}
}
}

View File

@@ -0,0 +1,86 @@
/**
* Copyright (C) 2011 Circuits At Home, LTD. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* Contact information
* -------------------
*
* Circuits At Home, LTD
* Web : http://www.circuitsathome.com
* e-mail : support@circuitsathome.com
*/
#pragma once
#ifndef _usb_h_
#error "Never include macros.h directly; include Usb.h instead"
#endif
////////////////////////////////////////////////////////////////////////////////
// HANDY MACROS
////////////////////////////////////////////////////////////////////////////////
#define VALUE_BETWEEN(v,l,h) (((v)>(l)) && ((v)<(h)))
#define VALUE_WITHIN(v,l,h) (((v)>=(l)) && ((v)<=(h)))
#define output_pgm_message(wa,fp,mp,el) wa = &mp, fp((char *)pgm_read_pointer(wa), el)
#define output_if_between(v,l,h,wa,fp,mp,el) if (VALUE_BETWEEN(v,l,h)) output_pgm_message(wa,fp,mp[v-(l+1)],el);
#define SWAP(a, b) (((a) ^= (b)), ((b) ^= (a)), ((a) ^= (b)))
#ifndef __BYTE_GRABBING_DEFINED__
#define __BYTE_GRABBING_DEFINED__ 1
#ifdef BROKEN_OPTIMIZER_LITTLE_ENDIAN
// Note: Use this if your compiler generates horrible assembler!
#define BGRAB0(__usi__) (((uint8_t *)&(__usi__))[0])
#define BGRAB1(__usi__) (((uint8_t *)&(__usi__))[1])
#define BGRAB2(__usi__) (((uint8_t *)&(__usi__))[2])
#define BGRAB3(__usi__) (((uint8_t *)&(__usi__))[3])
#define BGRAB4(__usi__) (((uint8_t *)&(__usi__))[4])
#define BGRAB5(__usi__) (((uint8_t *)&(__usi__))[5])
#define BGRAB6(__usi__) (((uint8_t *)&(__usi__))[6])
#define BGRAB7(__usi__) (((uint8_t *)&(__usi__))[7])
#else
// Note: The cast alone to uint8_t is actually enough.
// GCC throws out the "& 0xff", and the size is no different.
// Some compilers need it.
#define BGRAB0(__usi__) ((uint8_t)((__usi__) & 0xff ))
#define BGRAB1(__usi__) ((uint8_t)(((__usi__) >> 8) & 0xff))
#define BGRAB2(__usi__) ((uint8_t)(((__usi__) >> 16) & 0xff))
#define BGRAB3(__usi__) ((uint8_t)(((__usi__) >> 24) & 0xff))
#define BGRAB4(__usi__) ((uint8_t)(((__usi__) >> 32) & 0xff))
#define BGRAB5(__usi__) ((uint8_t)(((__usi__) >> 40) & 0xff))
#define BGRAB6(__usi__) ((uint8_t)(((__usi__) >> 48) & 0xff))
#define BGRAB7(__usi__) ((uint8_t)(((__usi__) >> 56) & 0xff))
#endif
#define BOVER1(__usi__) ((uint16_t)(__usi__) << 8)
#define BOVER2(__usi__) ((uint32_t)(__usi__) << 16)
#define BOVER3(__usi__) ((uint32_t)(__usi__) << 24)
#define BOVER4(__usi__) ((uint64_t)(__usi__) << 32)
#define BOVER5(__usi__) ((uint64_t)(__usi__) << 40)
#define BOVER6(__usi__) ((uint64_t)(__usi__) << 48)
#define BOVER7(__usi__) ((uint64_t)(__usi__) << 56)
// These are the smallest and fastest ways I have found so far in pure C/C++.
#define BMAKE16(__usc1__,__usc0__) ((uint16_t)((uint16_t)(__usc0__) | (uint16_t)BOVER1(__usc1__)))
#define BMAKE32(__usc3__,__usc2__,__usc1__,__usc0__) ((uint32_t)((uint32_t)(__usc0__) | (uint32_t)BOVER1(__usc1__) | (uint32_t)BOVER2(__usc2__) | (uint32_t)BOVER3(__usc3__)))
#define BMAKE64(__usc7__,__usc6__,__usc5__,__usc4__,__usc3__,__usc2__,__usc1__,__usc0__) ((uint64_t)((uint64_t)__usc0__ | (uint64_t)BOVER1(__usc1__) | (uint64_t)BOVER2(__usc2__) | (uint64_t)BOVER3(__usc3__) | (uint64_t)BOVER4(__usc4__) | (uint64_t)BOVER5(__usc5__) | (uint64_t)BOVER6(__usc6__) | (uint64_t)BOVER1(__usc7__)))
#endif
/*
* Debug macros: Strings are stored in progmem (flash) instead of RAM.
*/
#define USBTRACE(s) (Notify(PSTR(s), 0x80))
#define USBTRACE1(s,l) (Notify(PSTR(s), l))
#define USBTRACE2(s,r) (Notify(PSTR(s), 0x80), D_PrintHex((r), 0x80), Notify(PSTR("\r\n"), 0x80))
#define USBTRACE3(s,r,l) (Notify(PSTR(s), l), D_PrintHex((r), l), Notify(PSTR("\r\n"), l))

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,562 @@
/**
* Copyright (C) 2011 Circuits At Home, LTD. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* Contact information
* -------------------
*
* Circuits At Home, LTD
* Web : http://www.circuitsathome.com
* e-mail : support@circuitsathome.com
*/
#pragma once
// Cruft removal, makes driver smaller, faster.
#ifndef MS_WANT_PARSER
#define MS_WANT_PARSER 0
#endif
#include "Usb.h"
#define bmREQ_MASSOUT USB_SETUP_HOST_TO_DEVICE|USB_SETUP_TYPE_CLASS|USB_SETUP_RECIPIENT_INTERFACE
#define bmREQ_MASSIN USB_SETUP_DEVICE_TO_HOST|USB_SETUP_TYPE_CLASS|USB_SETUP_RECIPIENT_INTERFACE
// Mass Storage Subclass Constants
#define MASS_SUBCLASS_SCSI_NOT_REPORTED 0x00 // De facto use
#define MASS_SUBCLASS_RBC 0x01
#define MASS_SUBCLASS_ATAPI 0x02 // MMC-5 (ATAPI)
#define MASS_SUBCLASS_OBSOLETE1 0x03 // Was QIC-157
#define MASS_SUBCLASS_UFI 0x04 // Specifies how to interface Floppy Disk Drives to USB
#define MASS_SUBCLASS_OBSOLETE2 0x05 // Was SFF-8070i
#define MASS_SUBCLASS_SCSI 0x06 // SCSI Transparent Command Set
#define MASS_SUBCLASS_LSDFS 0x07 // Specifies how host has to negotiate access before trying SCSI
#define MASS_SUBCLASS_IEEE1667 0x08
// Mass Storage Class Protocols
#define MASS_PROTO_CBI 0x00 // CBI (with command completion interrupt)
#define MASS_PROTO_CBI_NO_INT 0x01 // CBI (without command completion interrupt)
#define MASS_PROTO_OBSOLETE 0x02
#define MASS_PROTO_BBB 0x50 // Bulk Only Transport
#define MASS_PROTO_UAS 0x62
// Request Codes
#define MASS_REQ_ADSC 0x00
#define MASS_REQ_GET 0xFC
#define MASS_REQ_PUT 0xFD
#define MASS_REQ_GET_MAX_LUN 0xFE
#define MASS_REQ_BOMSR 0xFF // Bulk-Only Mass Storage Reset
#define MASS_CBW_SIGNATURE 0x43425355
#define MASS_CSW_SIGNATURE 0x53425355
#define MASS_CMD_DIR_OUT 0 // (0 << 7)
#define MASS_CMD_DIR_IN 0x80 //(1 << 7)
/*
* Reference documents from T10 (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);
};

View File

@@ -0,0 +1,242 @@
/**
* Copyright (C) 2011 Circuits At Home, LTD. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* Contact information
* -------------------
*
* Circuits At Home, LTD
* Web : http://www.circuitsathome.com
* e-mail : support@circuitsathome.com
*/
#pragma once
#ifndef _usb_h_
#error "Never include max3421e.h directly; include Usb.h instead"
#endif
/* MAX3421E register/bit names and bitmasks */
/* Arduino pin definitions */
/* pin numbers to port numbers */
#define SE0 0
#define SE1 1
#define FSHOST 2
#define LSHOST 3
/* MAX3421E command byte format: rrrrr0wa where 'r' is register number */
//
// MAX3421E Registers in HOST mode.
//
#define rRCVFIFO 0x08 //1<<3
#define rSNDFIFO 0x10 //2<<3
#define rSUDFIFO 0x20 //4<<3
#define rRCVBC 0x30 //6<<3
#define rSNDBC 0x38 //7<<3
#define rUSBIRQ 0x68 //13<<3
/* USBIRQ Bits */
#define bmVBUSIRQ 0x40 //b6
#define bmNOVBUSIRQ 0x20 //b5
#define bmOSCOKIRQ 0x01 //b0
#define rUSBIEN 0x70 //14<<3
/* USBIEN Bits */
#define bmVBUSIE 0x40 //b6
#define bmNOVBUSIE 0x20 //b5
#define bmOSCOKIE 0x01 //b0
#define rUSBCTL 0x78 //15<<3
/* USBCTL Bits */
#define bmCHIPRES 0x20 //b5
#define bmPWRDOWN 0x10 //b4
#define rCPUCTL 0x80 //16<<3
/* CPUCTL Bits */
#define bmPUSLEWID1 0x80 //b7
#define bmPULSEWID0 0x40 //b6
#define bmIE 0x01 //b0
#define rPINCTL 0x88 //17<<3
/* PINCTL Bits */
#define bmFDUPSPI 0x10 //b4
#define bmINTLEVEL 0x08 //b3
#define bmPOSINT 0x04 //b2
#define bmGPXB 0x02 //b1
#define bmGPXA 0x01 //b0
// GPX pin selections
#define GPX_OPERATE 0x00
#define GPX_VBDET 0x01
#define GPX_BUSACT 0x02
#define GPX_SOF 0x03
#define rREVISION 0x90 //18<<3
#define rIOPINS1 0xa0 //20<<3
/* IOPINS1 Bits */
#define bmGPOUT0 0x01
#define bmGPOUT1 0x02
#define bmGPOUT2 0x04
#define bmGPOUT3 0x08
#define bmGPIN0 0x10
#define bmGPIN1 0x20
#define bmGPIN2 0x40
#define bmGPIN3 0x80
#define rIOPINS2 0xa8 //21<<3
/* IOPINS2 Bits */
#define bmGPOUT4 0x01
#define bmGPOUT5 0x02
#define bmGPOUT6 0x04
#define bmGPOUT7 0x08
#define bmGPIN4 0x10
#define bmGPIN5 0x20
#define bmGPIN6 0x40
#define bmGPIN7 0x80
#define rGPINIRQ 0xb0 //22<<3
/* GPINIRQ Bits */
#define bmGPINIRQ0 0x01
#define bmGPINIRQ1 0x02
#define bmGPINIRQ2 0x04
#define bmGPINIRQ3 0x08
#define bmGPINIRQ4 0x10
#define bmGPINIRQ5 0x20
#define bmGPINIRQ6 0x40
#define bmGPINIRQ7 0x80
#define rGPINIEN 0xb8 //23<<3
/* GPINIEN Bits */
#define bmGPINIEN0 0x01
#define bmGPINIEN1 0x02
#define bmGPINIEN2 0x04
#define bmGPINIEN3 0x08
#define bmGPINIEN4 0x10
#define bmGPINIEN5 0x20
#define bmGPINIEN6 0x40
#define bmGPINIEN7 0x80
#define rGPINPOL 0xc0 //24<<3
/* GPINPOL Bits */
#define bmGPINPOL0 0x01
#define bmGPINPOL1 0x02
#define bmGPINPOL2 0x04
#define bmGPINPOL3 0x08
#define bmGPINPOL4 0x10
#define bmGPINPOL5 0x20
#define bmGPINPOL6 0x40
#define bmGPINPOL7 0x80
#define rHIRQ 0xc8 //25<<3
/* HIRQ Bits */
#define bmBUSEVENTIRQ 0x01 // indicates BUS Reset Done or BUS Resume
#define bmRWUIRQ 0x02
#define bmRCVDAVIRQ 0x04
#define bmSNDBAVIRQ 0x08
#define bmSUSDNIRQ 0x10
#define bmCONDETIRQ 0x20
#define bmFRAMEIRQ 0x40
#define bmHXFRDNIRQ 0x80
#define rHIEN 0xd0 //26<<3
/* HIEN Bits */
#define bmBUSEVENTIE 0x01
#define bmRWUIE 0x02
#define bmRCVDAVIE 0x04
#define bmSNDBAVIE 0x08
#define bmSUSDNIE 0x10
#define bmCONDETIE 0x20
#define bmFRAMEIE 0x40
#define bmHXFRDNIE 0x80
#define rMODE 0xd8 //27<<3
/* MODE Bits */
#define bmHOST 0x01
#define bmLOWSPEED 0x02
#define bmHUBPRE 0x04
#define bmSOFKAENAB 0x08
#define bmSEPIRQ 0x10
#define bmDELAYISO 0x20
#define bmDMPULLDN 0x40
#define bmDPPULLDN 0x80
#define rPERADDR 0xe0 //28<<3
#define rHCTL 0xe8 //29<<3
/* HCTL Bits */
#define bmBUSRST 0x01
#define bmFRMRST 0x02
#define bmSAMPLEBUS 0x04
#define bmSIGRSM 0x08
#define bmRCVTOG0 0x10
#define bmRCVTOG1 0x20
#define bmSNDTOG0 0x40
#define bmSNDTOG1 0x80
#define rHXFR 0xf0 //30<<3
#undef tokSETUP
#undef tokIN
#undef tokOUT
#undef tokINHS
#undef tokOUTHS
#undef tokISOIN
#undef tokISOOUT
/* Host transfer token values for writing the HXFR register (R30) */
/* OR this bit field with the endpoint number in bits 3:0 */
#define tokSETUP 0x10 // HS=0, ISO=0, OUTNIN=0, SETUP=1
#define tokIN 0x00 // HS=0, ISO=0, OUTNIN=0, SETUP=0
#define tokOUT 0x20 // HS=0, ISO=0, OUTNIN=1, SETUP=0
#define tokINHS 0x80 // HS=1, ISO=0, OUTNIN=0, SETUP=0
#define tokOUTHS 0xA0 // HS=1, ISO=0, OUTNIN=1, SETUP=0
#define tokISOIN 0x40 // HS=0, ISO=1, OUTNIN=0, SETUP=0
#define tokISOOUT 0x60 // HS=0, ISO=1, OUTNIN=1, SETUP=0
#define rHRSL 0xf8 //31<<3
/* HRSL Bits */
#define bmRCVTOGRD 0x10
#define bmSNDTOGRD 0x20
#define bmKSTATUS 0x40
#define bmJSTATUS 0x80
#define bmSE0 0x00 //SE0 - disconnect state
#define bmSE1 0xc0 //SE1 - illegal state
/* Host error result codes, the 4 LSB's in the HRSL register */
#define hrSUCCESS 0x00
#define hrBUSY 0x01
#define hrBADREQ 0x02
#define hrUNDEF 0x03
#define hrNAK 0x04
#define hrSTALL 0x05
#define hrTOGERR 0x06
#define hrWRONGPID 0x07
#define hrBADBC 0x08
#define hrPIDERR 0x09
#define hrPKTERR 0x0A
#define hrCRCERR 0x0B
#define hrKERR 0x0C
#define hrJERR 0x0D
#define hrTIMEOUT 0x0E
#define hrBABBLE 0x0F
#define MODE_FS_HOST (bmDPPULLDN|bmDMPULLDN|bmHOST|bmSOFKAENAB)
#define MODE_LS_HOST (bmDPPULLDN|bmDMPULLDN|bmHOST|bmLOWSPEED|bmSOFKAENAB)

View File

@@ -0,0 +1,128 @@
/**
* Copyright (C) 2011 Circuits At Home, LTD. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* Contact information
* -------------------
*
* Circuits At Home, LTD
* Web : http://www.circuitsathome.com
* e-mail : support@circuitsathome.com
*/
#include "../../../inc/MarlinConfigPre.h"
#if ENABLED(USB_FLASH_DRIVE_SUPPORT) && DISABLED(USE_UHS3_USB)
#include "Usb.h"
// 0x80 is the default (i.e. trace) to turn off set this global to something lower.
// this allows for 126 other debugging levels.
// TO-DO: Allow assignment to a different serial port by software
int UsbDEBUGlvl = 0x80;
void E_Notifyc(char c, int lvl) {
if (UsbDEBUGlvl < lvl) return;
USB_HOST_SERIAL.print(c
#if !defined(ARDUINO) || ARDUINO < 100
, BYTE
#endif
);
//USB_HOST_SERIAL.flush();
}
void E_Notify(char const * msg, int lvl) {
if (UsbDEBUGlvl < lvl) return;
if (!msg) return;
while (const char c = pgm_read_byte(msg++)) E_Notifyc(c, lvl);
}
void E_NotifyStr(char const * msg, int lvl) {
if (UsbDEBUGlvl < lvl) return;
if (!msg) return;
while (const char c = *msg++) E_Notifyc(c, lvl);
}
void E_Notify(uint8_t b, int lvl) {
if (UsbDEBUGlvl < lvl) return;
USB_HOST_SERIAL.print(b
#if !defined(ARDUINO) || ARDUINO < 100
, DEC
#endif
);
//USB_HOST_SERIAL.flush();
}
void E_Notify(double d, int lvl) {
if (UsbDEBUGlvl < lvl) return;
USB_HOST_SERIAL.print(d);
//USB_HOST_SERIAL.flush();
}
#ifdef DEBUG_USB_HOST
void NotifyFailGetDevDescr() {
Notify(PSTR("\r\ngetDevDescr "), 0x80);
}
void NotifyFailSetDevTblEntry() {
Notify(PSTR("\r\nsetDevTblEn "), 0x80);
}
void NotifyFailGetConfDescr() {
Notify(PSTR("\r\ngetConf "), 0x80);
}
void NotifyFailSetConfDescr() {
Notify(PSTR("\r\nsetConf "), 0x80);
}
void NotifyFailGetDevDescr(uint8_t reason) {
NotifyFailGetDevDescr();
NotifyFail(reason);
}
void NotifyFailSetDevTblEntry(uint8_t reason) {
NotifyFailSetDevTblEntry();
NotifyFail(reason);
}
void NotifyFailGetConfDescr(uint8_t reason) {
NotifyFailGetConfDescr();
NotifyFail(reason);
}
void NotifyFailSetConfDescr(uint8_t reason) {
NotifyFailSetConfDescr();
NotifyFail(reason);
}
void NotifyFailUnknownDevice(uint16_t VID, uint16_t PID) {
Notify(PSTR("\r\nUnknown Device Connected - VID: "), 0x80);
D_PrintHex<uint16_t > (VID, 0x80);
Notify(PSTR(" PID: "), 0x80);
D_PrintHex<uint16_t > (PID, 0x80);
}
void NotifyFail(uint8_t rcode) {
D_PrintHex<uint8_t > (rcode, 0x80);
Notify(PSTR("\r\n"), 0x80);
}
#endif // DEBUG_USB_HOST
#endif // USB_FLASH_DRIVE_SUPPORT

View 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
*/
#pragma once
#ifndef _usb_h_
#error "Never include message.h directly; include Usb.h instead"
#endif
extern int UsbDEBUGlvl;
void E_Notify(char const * msg, int lvl);
void E_Notify(uint8_t b, int lvl);
void E_NotifyStr(char const * msg, int lvl);
void E_Notifyc(char c, int lvl);
#ifdef DEBUG_USB_HOST
#define Notify E_Notify
#define NotifyStr E_NotifyStr
#define Notifyc E_Notifyc
void NotifyFailGetDevDescr(uint8_t reason);
void NotifyFailSetDevTblEntry(uint8_t reason);
void NotifyFailGetConfDescr(uint8_t reason);
void NotifyFailSetConfDescr(uint8_t reason);
void NotifyFailGetDevDescr();
void NotifyFailSetDevTblEntry();
void NotifyFailGetConfDescr();
void NotifyFailSetConfDescr();
void NotifyFailUnknownDevice(uint16_t VID, uint16_t PID);
void NotifyFail(uint8_t rcode);
#else
#define Notify(...) ((void)0)
#define NotifyStr(...) ((void)0)
#define Notifyc(...) ((void)0)
#define NotifyFailGetDevDescr(...) ((void)0)
#define NotifyFailSetDevTblEntry(...) ((void)0)
#define NotifyFailGetConfDescr(...) ((void)0)
#define NotifyFailGetDevDescr(...) ((void)0)
#define NotifyFailSetDevTblEntry(...) ((void)0)
#define NotifyFailGetConfDescr(...) ((void)0)
#define NotifyFailSetConfDescr(...) ((void)0)
#define NotifyFailUnknownDevice(...) ((void)0)
#define NotifyFail(...) ((void)0)
#endif
template <class ERROR_TYPE>
void ErrorMessage(uint8_t level, char const * msg, ERROR_TYPE rcode = 0) {
#ifdef DEBUG_USB_HOST
Notify(msg, level);
Notify(PSTR(": "), level);
D_PrintHex<ERROR_TYPE > (rcode, level);
Notify(PSTR("\r\n"), level);
#endif
}
template <class ERROR_TYPE>
void ErrorMessage(char const * msg __attribute__((unused)), ERROR_TYPE rcode __attribute__((unused)) = 0) {
#ifdef DEBUG_USB_HOST
Notify(msg, 0x80);
Notify(PSTR(": "), 0x80);
D_PrintHex<ERROR_TYPE > (rcode, 0x80);
Notify(PSTR("\r\n"), 0x80);
#endif
}

View File

@@ -0,0 +1,77 @@
/**
* Copyright (C) 2011 Circuits At Home, LTD. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* Contact information
* -------------------
*
* Circuits At Home, LTD
* Web : http://www.circuitsathome.com
* e-mail : support@circuitsathome.com
*/
#include "../../../inc/MarlinConfigPre.h"
#if ENABLED(USB_FLASH_DRIVE_SUPPORT) && DISABLED(USE_UHS3_USB)
#include "Usb.h"
bool MultiByteValueParser::Parse(uint8_t **pp, uint16_t *pcntdn) {
if (!pBuf) {
Notify(PSTR("Buffer pointer is NULL!\r\n"), 0x80);
return false;
}
for (; countDown && (*pcntdn); countDown--, (*pcntdn)--, (*pp)++)
pBuf[valueSize - countDown] = (**pp);
if (countDown) return false;
countDown = valueSize;
return true;
}
bool PTPListParser::Parse(uint8_t **pp, uint16_t *pcntdn, PTP_ARRAY_EL_FUNC pf, const void *me) {
switch (nStage) {
case 0:
pBuf->valueSize = lenSize;
theParser.Initialize(pBuf);
nStage = 1;
case 1:
if (!theParser.Parse(pp, pcntdn)) return false;
arLen = 0;
arLen = (pBuf->valueSize >= 4) ? *((uint32_t*)pBuf->pValue) : (uint32_t)(*((uint16_t*)pBuf->pValue));
arLenCntdn = arLen;
nStage = 2;
case 2:
pBuf->valueSize = valSize;
theParser.Initialize(pBuf);
nStage = 3;
case 3:
for (; arLenCntdn; arLenCntdn--) {
if (!theParser.Parse(pp, pcntdn)) return false;
if (pf) pf(pBuf, (arLen - arLenCntdn), me);
}
nStage = 0;
}
return true;
}
#endif // USB_FLASH_DRIVE_SUPPORT

View File

@@ -0,0 +1,145 @@
/**
* Copyright (C) 2011 Circuits At Home, LTD. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* Contact information
* -------------------
*
* Circuits At Home, LTD
* Web : http://www.circuitsathome.com
* e-mail : support@circuitsathome.com
*/
#pragma once
#ifndef _usb_h_
#error "Never include parsetools.h directly; include Usb.h instead"
#endif
struct MultiValueBuffer {
uint8_t valueSize;
void *pValue;
} __attribute__((packed));
class MultiByteValueParser {
uint8_t * pBuf;
uint8_t countDown;
uint8_t valueSize;
public:
MultiByteValueParser() : pBuf(nullptr), countDown(0), valueSize(0) {
};
const uint8_t* GetBuffer() { return pBuf; }
void Initialize(MultiValueBuffer * const pbuf) {
pBuf = (uint8_t*)pbuf->pValue;
countDown = valueSize = pbuf->valueSize;
}
bool Parse(uint8_t **pp, uint16_t *pcntdn);
};
class ByteSkipper {
uint8_t *pBuf;
uint8_t nStage;
uint16_t countDown;
public:
ByteSkipper() : pBuf(nullptr), nStage(0), countDown(0) {
}
void Initialize(MultiValueBuffer *pbuf) {
pBuf = (uint8_t*)pbuf->pValue;
countDown = 0;
}
bool Skip(uint8_t **pp, uint16_t *pcntdn, uint16_t bytes_to_skip) {
switch (nStage) {
case 0:
countDown = bytes_to_skip;
nStage++;
case 1:
for (; countDown && (*pcntdn); countDown--, (*pp)++, (*pcntdn)--);
if (!countDown)
nStage = 0;
}
return (!countDown);
}
};
// Pointer to a callback function triggered for each element of PTP array when used with PTPArrayParser
typedef void (*PTP_ARRAY_EL_FUNC)(const MultiValueBuffer * const p, uint32_t count, const void *me);
class PTPListParser {
public:
enum ParseMode {
modeArray, modeRange/*, modeEnum*/
};
private:
uint8_t nStage;
uint8_t enStage;
uint32_t arLen;
uint32_t arLenCntdn;
uint8_t lenSize; // size of the array length field in bytes
uint8_t valSize; // size of the array element in bytes
MultiValueBuffer *pBuf;
// The only parser for both size and array element parsing
MultiByteValueParser theParser;
uint8_t /*ParseMode*/ prsMode;
public:
PTPListParser() :
nStage(0),
enStage(0),
arLen(0),
arLenCntdn(0),
lenSize(0),
valSize(0),
pBuf(nullptr),
prsMode(modeArray) {}
;
void Initialize(const uint8_t len_size, const uint8_t val_size, MultiValueBuffer * const p, const uint8_t mode = modeArray) {
pBuf = p;
lenSize = len_size;
valSize = val_size;
prsMode = mode;
if (prsMode == modeRange) {
arLenCntdn = arLen = 3;
nStage = 2;
}
else {
arLenCntdn = arLen = 0;
nStage = 0;
}
enStage = 0;
theParser.Initialize(p);
}
bool Parse(uint8_t **pp, uint16_t *pcntdn, PTP_ARRAY_EL_FUNC pf, const void *me = nullptr);
};

View File

@@ -0,0 +1,80 @@
/**
* Copyright (C) 2011 Circuits At Home, LTD. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* Contact information
* -------------------
*
* Circuits At Home, LTD
* Web : http://www.circuitsathome.com
* e-mail : support@circuitsathome.com
*/
#pragma once
#ifndef _usb_h_
#error "Never include printhex.h directly; include Usb.h instead"
#endif
void E_Notifyc(char c, int lvl);
template <class T>
void PrintHex(T val, int lvl) {
int num_nibbles = sizeof (T) * 2;
do {
char v = 48 + (((val >> (num_nibbles - 1) * 4)) & 0x0f);
if (v > 57) v += 7;
E_Notifyc(v, lvl);
} while (--num_nibbles);
}
template <class T>
void PrintBin(T val, int lvl) {
for (T mask = (((T)1) << ((sizeof (T) << 3) - 1)); mask; mask >>= 1)
E_Notifyc(val & mask ? '1' : '0', lvl);
}
template <class T>
void SerialPrintHex(T val) {
int num_nibbles = sizeof (T) * 2;
do {
char v = 48 + (((val >> (num_nibbles - 1) * 4)) & 0x0f);
if (v > 57) v += 7;
USB_HOST_SERIAL.print(v);
} while (--num_nibbles);
}
template <class T>
void PrintHex2(Print *prn, T val) {
T mask = (((T)1) << (((sizeof (T) << 1) - 1) << 2));
while (mask > 1) {
if (val < mask) prn->print("0");
mask >>= 4;
}
prn->print((T)val, HEX);
}
template <class T> void D_PrintHex(T val __attribute__((unused)), int lvl __attribute__((unused))) {
#ifdef DEBUG_USB_HOST
PrintHex<T > (val, lvl);
#endif
}
template <class T>
void D_PrintBin(T val, int lvl) {
#ifdef DEBUG_USB_HOST
PrintBin<T > (val, lvl);
#endif
}

View 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
*/
#pragma once
#include "../../../inc/MarlinConfig.h"
#include "macros.h"
#if ENABLED(USB_FLASH_DRIVE_SUPPORT)
////////////////////////////////////////////////////////////////////////////////
/* Added by Bill Greiman to speed up mass storage initialization with USB
* flash drives and simple USB hard drives.
* Disable this by defining DELAY(x) to be delay(x).
*/
#define delay(x) if ((x) < 200) safe_delay(x)
/* Almost all USB flash drives and simple USB hard drives fail the write
* protect test and add 20 - 30 seconds to USB init. Set SKIP_WRITE_PROTECT
* to nonzero to skip the test and assume the drive is writable.
*/
#define SKIP_WRITE_PROTECT 1
/* Since Marlin only cares about USB flash drives, we only need one LUN. */
#define MASS_MAX_SUPPORTED_LUN 1
#endif
////////////////////////////////////////////////////////////////////////////////
// SPI Configuration
////////////////////////////////////////////////////////////////////////////////
#ifndef USB_SPI
#define USB_SPI SPI
//#define USB_SPI SPI1
#endif
////////////////////////////////////////////////////////////////////////////////
// DEBUGGING
////////////////////////////////////////////////////////////////////////////////
/* Set this to 1 to activate serial debugging */
#define ENABLE_UHS_DEBUGGING 0
/* This can be used to select which serial port to use for debugging if
* multiple serial ports are available.
* For example Serial3.
*/
#if ENABLED(USB_FLASH_DRIVE_SUPPORT)
#define USB_HOST_SERIAL MYSERIAL0
#endif
#ifndef USB_HOST_SERIAL
#define USB_HOST_SERIAL Serial
#endif
////////////////////////////////////////////////////////////////////////////////
// Manual board activation
////////////////////////////////////////////////////////////////////////////////
/* Set this to 1 if you are using an Arduino Mega ADK board with MAX3421e built-in */
#define USE_UHS_MEGA_ADK 0 // If you are using Arduino 1.5.5 or newer there is no need to do this manually
/* Set this to 1 if you are using a Black Widdow */
#define USE_UHS_BLACK_WIDDOW 0
/* Set this to a one to use the xmem2 lock. This is needed for multitasking and threading */
#define USE_XMEM_SPI_LOCK 0
////////////////////////////////////////////////////////////////////////////////
// Wii IR camera
////////////////////////////////////////////////////////////////////////////////
/* Set this to 1 to activate code for the Wii IR camera */
#define ENABLE_WII_IR_CAMERA 0
////////////////////////////////////////////////////////////////////////////////
// MASS STORAGE
////////////////////////////////////////////////////////////////////////////////
// ******* IMPORTANT *******
// Set this to 1 to support single LUN devices, and save RAM. -- I.E. thumb drives.
// Each LUN needs ~13 bytes to be able to track the state of each unit.
#ifndef MASS_MAX_SUPPORTED_LUN
#define MASS_MAX_SUPPORTED_LUN 8
#endif
////////////////////////////////////////////////////////////////////////////////
// Set to 1 to use the faster spi4teensy3 driver.
////////////////////////////////////////////////////////////////////////////////
#ifndef USE_SPI4TEENSY3
#define USE_SPI4TEENSY3 1
#endif
// Disabled on the Teensy LC, as it is incompatible for now
#ifdef __MKL26Z64__
#undef USE_SPI4TEENSY3
#define USE_SPI4TEENSY3 0
#endif
////////////////////////////////////////////////////////////////////////////////
// AUTOMATIC Settings
////////////////////////////////////////////////////////////////////////////////
// No user serviceable parts below this line.
// DO NOT change anything below here unless you are a developer!
//#include "version_helper.h"
#if defined(__GNUC__) && defined(__AVR__)
#ifndef GCC_VERSION
#define GCC_VERSION (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__)
#endif
#if GCC_VERSION < 40602 // Test for GCC < 4.6.2
#ifdef PROGMEM
#undef PROGMEM
#define PROGMEM __attribute__((section(".progmem.data"))) // Workaround for 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.
#ifndef XMEM_ACQUIRE_SPI
#if USE_XMEM_SPI_LOCK || defined(USE_MULTIPLE_APP_API)
#include <xmem.h>
#else
#define XMEM_ACQUIRE_SPI() (void(0))
#define XMEM_RELEASE_SPI() (void(0))
#endif
#endif
#if !defined(EXT_RAM) && defined(EXT_RAM_STACK) || defined(EXT_RAM_HEAP)
#include <xmem.h>
#else
#define EXT_RAM 0
#endif
#if defined(CORE_TEENSY) && defined(KINETISK)
#define USING_SPI4TEENSY3 USE_SPI4TEENSY3
#else
#define USING_SPI4TEENSY3 0
#endif
#if ((defined(ARDUINO_SAM_DUE) && defined(__SAM3X8E__)) || defined(__ARDUINO_X86__) || ARDUINO >= 10600) && !USING_SPI4TEENSY3
#include <SPI.h> // Use the Arduino SPI library for the Arduino Due, Intel Galileo 1 & 2, Intel Edison or if the SPI library with transaction is available
#endif
#ifdef RBL_NRF51822
#include <nrf_gpio.h>
#include <SPI_Master.h>
#define SPI SPI_Master
#define MFK_CASTUINT8T (uint8_t) // RBLs return type for sizeof needs casting to uint8_t
#endif
#if defined(__PIC32MX__) || defined(__PIC32MZ__)
#include <../../../../hardware/pic32/libraries/SPI/SPI.h> // Hack to use the SPI library
#endif
#if defined(ESP8266) || defined(ESP32)
#define MFK_CASTUINT8T (uint8_t) // ESP return type for sizeof needs casting to uint8_t
#endif
#ifdef STM32F4
#include "stm32f4xx_hal.h"
extern SPI_HandleTypeDef SPI_Handle; // Needed to be declared in your main.cpp
#endif
// Fix defines on Arduino Due
#ifdef ARDUINO_SAM_DUE
#ifdef tokSETUP
#undef tokSETUP
#endif
#ifdef tokIN
#undef tokIN
#endif
#ifdef tokOUT
#undef tokOUT
#endif
#ifdef tokINHS
#undef tokINHS
#endif
#ifdef tokOUTHS
#undef tokOUTHS
#endif
#endif
// Set defaults
#ifndef MFK_CASTUINT8T
#define MFK_CASTUINT8T
#endif
// Workaround issue: https://github.com/esp8266/Arduino/issues/2078
#ifdef ESP8266
#undef PROGMEM
#define PROGMEM
#undef PSTR
#define PSTR(s) (s)
#undef pgm_read_byte
#define pgm_read_byte(addr) (*reinterpret_cast<const uint8_t*>(addr))
#undef pgm_read_word
#define pgm_read_word(addr) (*reinterpret_cast<const uint16_t*>(addr))
#endif
#ifdef ARDUINO_ESP8266_WIFIO
#error "This board is currently not supported"
#endif

View File

@@ -0,0 +1,170 @@
/**
* Copyright (C) 2011 Circuits At Home, LTD. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* Contact information
* -------------------
*
* Circuits At Home, LTD
* Web : http://www.circuitsathome.com
* e-mail : support@circuitsathome.com
*/
#ifndef _usb_h_
#error "Never include usb_ch9.h directly; include Usb.h instead"
#endif
/* USB chapter 9 structures */
/* Misc.USB constants */
#define DEV_DESCR_LEN 18 //device descriptor length
#define CONF_DESCR_LEN 9 //configuration descriptor length
#define INTR_DESCR_LEN 9 //interface descriptor length
#define EP_DESCR_LEN 7 //endpoint descriptor length
/* Standard Device Requests */
#define USB_REQUEST_GET_STATUS 0 // Standard Device Request - GET STATUS
#define USB_REQUEST_CLEAR_FEATURE 1 // Standard Device Request - CLEAR FEATURE
#define USB_REQUEST_SET_FEATURE 3 // Standard Device Request - SET FEATURE
#define USB_REQUEST_SET_ADDRESS 5 // Standard Device Request - SET ADDRESS
#define USB_REQUEST_GET_DESCRIPTOR 6 // Standard Device Request - GET DESCRIPTOR
#define USB_REQUEST_SET_DESCRIPTOR 7 // Standard Device Request - SET DESCRIPTOR
#define USB_REQUEST_GET_CONFIGURATION 8 // Standard Device Request - GET CONFIGURATION
#define USB_REQUEST_SET_CONFIGURATION 9 // Standard Device Request - SET CONFIGURATION
#define USB_REQUEST_GET_INTERFACE 10 // Standard Device Request - GET INTERFACE
#define USB_REQUEST_SET_INTERFACE 11 // Standard Device Request - SET INTERFACE
#define USB_REQUEST_SYNCH_FRAME 12 // Standard Device Request - SYNCH FRAME
#define USB_FEATURE_ENDPOINT_HALT 0 // CLEAR/SET FEATURE - Endpoint Halt
#define USB_FEATURE_DEVICE_REMOTE_WAKEUP 1 // CLEAR/SET FEATURE - Device remote wake-up
#define USB_FEATURE_TEST_MODE 2 // CLEAR/SET FEATURE - Test mode
/* Setup Data Constants */
#define USB_SETUP_HOST_TO_DEVICE 0x00 // Device Request bmRequestType transfer direction - host to device transfer
#define USB_SETUP_DEVICE_TO_HOST 0x80 // Device Request bmRequestType transfer direction - device to host transfer
#define USB_SETUP_TYPE_STANDARD 0x00 // Device Request bmRequestType type - standard
#define USB_SETUP_TYPE_CLASS 0x20 // Device Request bmRequestType type - class
#define USB_SETUP_TYPE_VENDOR 0x40 // Device Request bmRequestType type - vendor
#define USB_SETUP_RECIPIENT_DEVICE 0x00 // Device Request bmRequestType recipient - device
#define USB_SETUP_RECIPIENT_INTERFACE 0x01 // Device Request bmRequestType recipient - interface
#define USB_SETUP_RECIPIENT_ENDPOINT 0x02 // Device Request bmRequestType recipient - endpoint
#define USB_SETUP_RECIPIENT_OTHER 0x03 // Device Request bmRequestType recipient - other
/* USB descriptors */
#define USB_DESCRIPTOR_DEVICE 0x01 // bDescriptorType for a Device Descriptor.
#define USB_DESCRIPTOR_CONFIGURATION 0x02 // bDescriptorType for a Configuration Descriptor.
#define USB_DESCRIPTOR_STRING 0x03 // bDescriptorType for a String Descriptor.
#define USB_DESCRIPTOR_INTERFACE 0x04 // bDescriptorType for an Interface Descriptor.
#define USB_DESCRIPTOR_ENDPOINT 0x05 // bDescriptorType for an Endpoint Descriptor.
#define USB_DESCRIPTOR_DEVICE_QUALIFIER 0x06 // bDescriptorType for a Device Qualifier.
#define USB_DESCRIPTOR_OTHER_SPEED 0x07 // bDescriptorType for a Other Speed Configuration.
#define USB_DESCRIPTOR_INTERFACE_POWER 0x08 // bDescriptorType for Interface Power.
#define USB_DESCRIPTOR_OTG 0x09 // bDescriptorType for an OTG Descriptor.
#define HID_DESCRIPTOR_HID 0x21
/* OTG SET FEATURE Constants */
#define OTG_FEATURE_B_HNP_ENABLE 3 // SET FEATURE OTG - Enable B device to perform HNP
#define OTG_FEATURE_A_HNP_SUPPORT 4 // SET FEATURE OTG - A device supports HNP
#define OTG_FEATURE_A_ALT_HNP_SUPPORT 5 // SET FEATURE OTG - Another port on the A device supports HNP
/* USB Endpoint Transfer Types */
#define USB_TRANSFER_TYPE_CONTROL 0x00 // Endpoint is a control endpoint.
#define USB_TRANSFER_TYPE_ISOCHRONOUS 0x01 // Endpoint is an isochronous endpoint.
#define USB_TRANSFER_TYPE_BULK 0x02 // Endpoint is a bulk endpoint.
#define USB_TRANSFER_TYPE_INTERRUPT 0x03 // Endpoint is an interrupt endpoint.
#define bmUSB_TRANSFER_TYPE 0x03 // bit mask to separate transfer type from ISO attributes
/* Standard Feature Selectors for CLEAR_FEATURE Requests */
#define USB_FEATURE_ENDPOINT_STALL 0 // Endpoint recipient
#define USB_FEATURE_DEVICE_REMOTE_WAKEUP 1 // Device recipient
#define USB_FEATURE_TEST_MODE 2 // Device recipient
/* descriptor data structures */
/* Device descriptor structure */
typedef struct {
uint8_t bLength; // Length of this descriptor.
uint8_t bDescriptorType; // DEVICE descriptor type (USB_DESCRIPTOR_DEVICE).
uint16_t bcdUSB; // USB Spec Release Number (BCD).
uint8_t bDeviceClass; // Class code (assigned by the USB-IF). 0xFF-Vendor specific.
uint8_t bDeviceSubClass; // Subclass code (assigned by the USB-IF).
uint8_t bDeviceProtocol; // Protocol code (assigned by the USB-IF). 0xFF-Vendor specific.
uint8_t bMaxPacketSize0; // Maximum packet size for endpoint 0.
uint16_t idVendor; // Vendor ID (assigned by the USB-IF).
uint16_t idProduct; // Product ID (assigned by the manufacturer).
uint16_t bcdDevice; // Device release number (BCD).
uint8_t iManufacturer; // Index of String Descriptor describing the manufacturer.
uint8_t iProduct; // Index of String Descriptor describing the product.
uint8_t iSerialNumber; // Index of String Descriptor with the device's serial number.
uint8_t bNumConfigurations; // Number of possible configurations.
} __attribute__((packed)) USB_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;

View 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) && DISABLED(USE_UHS3_USB)
#include "Usb.h"
#include "usbhost.h"
uint8_t MAX3421e::vbusState = 0;
// constructor
void MAX3421e::cs() {
WRITE(USB_CS_PIN,0);
}
void MAX3421e::ncs() {
WRITE(USB_CS_PIN,1);
}
// write single byte into MAX3421 register
void MAX3421e::regWr(uint8_t reg, uint8_t data) {
cs();
spiSend(reg | 0x02);
spiSend(data);
ncs();
};
// multiple-byte write
// return a pointer to memory position after last written
uint8_t* MAX3421e::bytesWr(uint8_t reg, uint8_t nbytes, uint8_t* data_p) {
cs();
spiSend(reg | 0x02);
while (nbytes--) spiSend(*data_p++);
ncs();
return data_p;
}
// GPIO write
// GPIO byte is split between 2 registers, so two writes are needed to write one byte
// GPOUT bits are in the low nybble. 0-3 in IOPINS1, 4-7 in IOPINS2
void MAX3421e::gpioWr(uint8_t data) {
regWr(rIOPINS1, data);
regWr(rIOPINS2, data >> 4);
}
// single host register read
uint8_t MAX3421e::regRd(uint8_t reg) {
cs();
spiSend(reg);
uint8_t rv = spiRec();
ncs();
return rv;
}
// multiple-byte register read
// return a pointer to a memory position after last read
uint8_t* MAX3421e::bytesRd(uint8_t reg, uint8_t nbytes, uint8_t* data_p) {
cs();
spiSend(reg);
while (nbytes--) *data_p++ = spiRec();
ncs();
return data_p;
}
// GPIO read. See gpioWr for explanation
// GPIN pins are in high nybbles of IOPINS1, IOPINS2
uint8_t MAX3421e::gpioRd() {
return (regRd(rIOPINS2) & 0xf0) | // pins 4-7, clean lower nybble
(regRd(rIOPINS1) >> 4); // shift low bits and OR with upper from previous operation.
}
// reset MAX3421e. Returns false if PLL failed to stabilize 1 second after reset
bool MAX3421e::reset() {
regWr(rUSBCTL, bmCHIPRES);
regWr(rUSBCTL, 0x00);
for (uint8_t i = 100; i--;) {
if (regRd(rUSBIRQ) & bmOSCOKIRQ) return true;
delay(10);
}
return false;
}
// initialize MAX3421e. Set Host mode, pullups, and stuff. Returns 0 if success, -1 if not
bool MAX3421e::start() {
// Initialize pins and SPI bus
SET_OUTPUT(USB_CS_PIN);
SET_INPUT_PULLUP(USB_INTR_PIN);
ncs();
spiBegin();
spiInit(
#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() {
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

View File

@@ -0,0 +1,58 @@
/**************
* usb_host.h *
**************/
/****************************************************************************
* Written By Marcio Teixeira 2018 - Aleph Objects, Inc. *
* *
* This program is free software: you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation, either version 3 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* To view a copy of the GNU General Public License, go to the following *
* location: <http://www.gnu.org/licenses/>. *
****************************************************************************/
#pragma once
/* This the following comes from "lib/usbhost.h", but has been rewritten
* to use the SPI functions from Marlin's HAL */
class MAX3421e {
private:
static uint8_t vbusState;
void cs();
void ncs();
uint8_t GpxHandler();
uint8_t IntHandler();
public:
bool start();
void regWr(uint8_t reg, uint8_t data);
uint8_t* bytesWr(uint8_t reg, uint8_t nbytes, uint8_t* data_p);
void gpioWr(uint8_t data);
uint8_t regRd(uint8_t reg);
uint8_t* bytesRd(uint8_t reg, uint8_t nbytes, uint8_t* data_p);
uint8_t gpioRd();
bool reset();
uint8_t getVbusState() {return vbusState;};
void busprobe();
uint8_t Task();
};
#define USE_MARLIN_MAX3421E
#if defined(__SAM3X8E__) && !defined(ARDUINO_SAM_DUE)
#define ARDUINO_SAM_DUE // Spoof the USB library that this is a DUE
#endif

View File

@@ -0,0 +1,31 @@
==== USB HOST SHIELD 3.0 LIBRARY ====
The lib-uhs3/ folder contains a subset of the files from the USB Host Shield
3.0 library:
https://github.com/felis/UHS30
==== LICENSE SUMMARY ====
Source Path: Repository: License:
------------ ----------- --------
usb_flashdrive/lib github.com/felis/UHS30 GPLv2 or later
==== MARLIN INTEGRATION WORK ====
All additional work done to integrate USB into Marlin was performed by
AlephObjects, Inc. and is licensed under the GPLv3.
This version of UHS3 has been modified for better compatibility with Marlin.
The upstream version of UHS 3.0 runs a frame timer interrupt every 1 ms to
handle device polling. This timer interrupt interferes with Marlin's stepper
IRQ, so the flag USB_HOST_MANUAL_POLL has been added to move the polling to
the idle task. Additional logic was added to disable and enable the frame
IRQ.
SKIP_PAGE3F and USB_NO_TEST_UNIT_READY were added to work around bugs with
certain devices.
-- marcio@alephobjects.com

View File

@@ -0,0 +1,249 @@
/* Copyright (C) 2015-2016 Andrew J. Kroll
and
Copyright (C) 2011 Circuits At Home, LTD. All rights reserved.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Contact information
-------------------
Circuits At Home, LTD
Web : http://www.circuitsathome.com
e-mail : support@circuitsathome.com
*/
#ifndef __UHS_BULK_STORAGE_H__
#define __UHS_BULK_STORAGE_H__
////////////////////////////////////////////////////////////////////////////////
// Define any of these options at the top of your sketch to override
// the defaults contained herewith. Do NOT do modifications here.
// Macro | Settings and notes | Default
// -----------------------------------------+-----------------------+-----------
// | 1 to 8 |
// | Each LUN needs |
// MASS_MAX_SUPPORTED_LUN | ~13 bytes to be able | 8
// | to track the state of |
// | each unit. |
// -----------------------------------------+-----------------------+-----------
// | Just define to use. |
// DEBUG_PRINTF_EXTRA_HUGE_UHS_BULK_STORAGE | works only if extra |
// | huge debug is on too. |
// -----------------------------------------^-----------------------^-----------
#ifndef MASS_MAX_SUPPORTED_LUN
#define MASS_MAX_SUPPORTED_LUN 8
#endif
#include "UHS_SCSI.h"
#define UHS_BULK_bmREQ_OUT USB_SETUP_HOST_TO_DEVICE|USB_SETUP_TYPE_CLASS|USB_SETUP_RECIPIENT_INTERFACE
#define UHS_BULK_bmREQ_IN USB_SETUP_DEVICE_TO_HOST|USB_SETUP_TYPE_CLASS|USB_SETUP_RECIPIENT_INTERFACE
// Request Codes
#define UHS_BULK_REQ_ADSC 0x00U
#define UHS_BULK_REQ_GET 0xFCU
#define UHS_BULK_REQ_PUT 0xFDU
#define UHS_BULK_REQ_GET_MAX_LUN 0xFEU
#define UHS_BULK_REQ_BOMSR 0xFFU // Mass Storage Reset
#define UHS_BULK_CBW_SIGNATURE 0x43425355LU
#define UHS_BULK_CSW_SIGNATURE 0x53425355LU
#define UHS_BULK_CMD_DIR_OUT 0x00U
#define UHS_BULK_CMD_DIR_IN 0x80U
/* Bulk error codes */
#define UHS_BULK_ERR_SUCCESS UHS_HOST_ERROR_NONE
#define UHS_BULK_ERR_PHASE_ERROR 0x22U
#define UHS_BULK_ERR_UNIT_NOT_READY 0x23U
#define UHS_BULK_ERR_UNIT_BUSY 0x24U
#define UHS_BULK_ERR_STALL 0x25U
#define UHS_BULK_ERR_CMD_NOT_SUPPORTED 0x26U
#define UHS_BULK_ERR_INVALID_CSW 0x27U
#define UHS_BULK_ERR_NO_MEDIA 0x28U
#define UHS_BULK_ERR_BAD_LBA 0x29U
#define UHS_BULK_ERR_MEDIA_CHANGED 0x2AU
#define UHS_BULK_ERR_DEVICE_DISCONNECTED UHS_HOST_ERROR_UNPLUGGED
#define UHS_BULK_ERR_UNABLE_TO_RECOVER 0x32U // Reset recovery error
#define UHS_BULK_ERR_INVALID_LUN 0x33U
#define UHS_BULK_ERR_WRITE_STALL 0x34U
#define UHS_BULK_ERR_READ_NAKS 0x35U
#define UHS_BULK_ERR_WRITE_NAKS 0x36U
#define UHS_BULK_ERR_WRITE_PROTECTED 0x37U
#define UHS_BULK_ERR_NOT_IMPLEMENTED 0xFDU
#define UHS_BULK_ERR_GENERAL_SCSI_ERROR 0xF0U
#define UHS_BULK_ERR_GENERAL_USB_ERROR 0xFFU
#define UHS_BULK_ERR_USER 0xA0U // For subclasses to define their own error codes
#define MASS_MAX_ENDPOINTS 3
struct UHS_BULK_CommandBlockWrapperBase {
volatile uint32_t dCBWSignature;
volatile uint32_t dCBWTag;
volatile uint32_t dCBWDataTransferLength;
volatile uint8_t bmCBWFlags;
public:
UHS_BULK_CommandBlockWrapperBase() {
}
UHS_BULK_CommandBlockWrapperBase(uint32_t tag, uint32_t xflen, uint8_t flgs) :
dCBWSignature(UHS_BULK_CBW_SIGNATURE), dCBWTag(tag), dCBWDataTransferLength(xflen), bmCBWFlags(flgs) {
}
} __attribute__((packed));
struct UHS_BULK_CommandBlockWrapper : public UHS_BULK_CommandBlockWrapperBase {
struct {
uint8_t bmCBWLUN : 4;
uint8_t bmReserved1 : 4;
};
struct {
uint8_t bmCBWCBLength : 4;
uint8_t bmReserved2 : 4;
};
uint8_t CBWCB[16];
public:
// All zeroed.
UHS_BULK_CommandBlockWrapper() :
UHS_BULK_CommandBlockWrapperBase(0, 0, 0), bmReserved1(0), bmReserved2(0) {
for(int i = 0; i < 16; i++) CBWCB[i] = 0;
}
// Generic Wrap, CDB zeroed.
UHS_BULK_CommandBlockWrapper(uint32_t tag, uint32_t xflen, uint8_t flgs, uint8_t lu, uint8_t cmdlen, uint8_t cmd) :
UHS_BULK_CommandBlockWrapperBase(tag, xflen, flgs),
bmCBWLUN(lu), bmReserved1(0), bmCBWCBLength(cmdlen), bmReserved2(0) {
for(int i = 0; i < 16; i++) CBWCB[i] = 0;
SCSI_CDB_BASE_t *x = reinterpret_cast<SCSI_CDB_BASE_t *>(CBWCB);
x->LUN = cmd;
}
// Wrap for CDB of 6
UHS_BULK_CommandBlockWrapper(uint32_t tag, uint32_t xflen, SCSI_CDB6_t *cdb, uint8_t dir) :
UHS_BULK_CommandBlockWrapperBase(tag, xflen, dir),
bmCBWLUN(cdb->LUN), bmReserved1(0), bmCBWCBLength(6), bmReserved2(0) {
memcpy(&CBWCB, cdb, 6);
}
// Wrap for CDB of 10
UHS_BULK_CommandBlockWrapper(uint32_t tag, uint32_t xflen, SCSI_CDB10_t *cdb, uint8_t dir) :
UHS_BULK_CommandBlockWrapperBase(tag, xflen, dir),
bmCBWLUN(cdb->LUN), bmReserved1(0), bmCBWCBLength(10), bmReserved2(0) {
memcpy(&CBWCB, cdb, 10);
}
} __attribute__((packed));
struct UHS_BULK_CommandStatusWrapper {
uint32_t dCSWSignature;
uint32_t dCSWTag;
uint32_t dCSWDataResidue;
uint8_t bCSWStatus;
} __attribute__((packed));
class UHS_Bulk_Storage : public UHS_USBInterface {
protected:
static const uint8_t epDataInIndex = 1; // DataIn endpoint index
static const uint8_t epDataOutIndex = 2; // DataOUT endpoint index
static const uint8_t epInterruptInIndex = 3; // InterruptIN endpoint index
uint8_t bMaxLUN; // Max LUN
volatile uint32_t dCBWTag; // Tag
volatile uint8_t bTheLUN; // Active LUN
volatile uint32_t CurrentCapacity[MASS_MAX_SUPPORTED_LUN]; // Total sectors
volatile uint16_t CurrentSectorSize[MASS_MAX_SUPPORTED_LUN]; // Sector size, clipped to 16 bits
volatile bool LUNOk[MASS_MAX_SUPPORTED_LUN]; // use this to check for media changes.
volatile bool WriteOk[MASS_MAX_SUPPORTED_LUN];
void PrintEndpointDescriptor(const USB_ENDPOINT_DESCRIPTOR* ep_ptr);
public:
UHS_Bulk_Storage(UHS_USB_HOST_BASE *p);
volatile UHS_EpInfo epInfo[MASS_MAX_ENDPOINTS];
uint8_t GetbMaxLUN() {
return bMaxLUN; // Max LUN
}
uint8_t GetbTheLUN() {
return bTheLUN; // Active LUN
}
bool WriteProtected(uint8_t lun);
uint8_t MediaCTL(uint8_t lun, uint8_t ctl);
uint8_t Read(uint8_t lun, uint32_t addr, uint16_t bsize, uint8_t blocks, uint8_t *buf);
uint8_t Write(uint8_t lun, uint32_t addr, uint16_t bsize, uint8_t blocks, const uint8_t *buf);
uint8_t LockMedia(uint8_t lun, uint8_t lock);
bool LUNIsGood(uint8_t lun);
uint32_t GetCapacity(uint8_t lun);
uint16_t GetSectorSize(uint8_t lun);
uint8_t SCSITransaction6(SCSI_CDB6_t *cdb, uint16_t buf_size, void *buf, uint8_t dir);
uint8_t SCSITransaction10(SCSI_CDB10_t *cdb, uint16_t buf_size, void *buf, uint8_t dir);
// Configure and internal methods, these should never be called by a user's sketch.
uint8_t Start();
bool OKtoEnumerate(ENUMERATION_INFO *ei);
uint8_t SetInterface(ENUMERATION_INFO *ei);
uint8_t GetAddress() {
return bAddress;
};
void Poll();
void DriverDefaults();
private:
void Reset();
void CheckMedia();
bool IsValidCBW(uint8_t size, uint8_t *pcbw);
bool IsMeaningfulCBW(uint8_t size, uint8_t *pcbw);
bool IsValidCSW(UHS_BULK_CommandStatusWrapper *pcsw, UHS_BULK_CommandBlockWrapperBase *pcbw);
bool CheckLUN(uint8_t lun);
uint8_t Inquiry(uint8_t lun, uint16_t size, uint8_t *buf);
uint8_t TestUnitReady(uint8_t lun);
uint8_t RequestSense(uint8_t lun, uint16_t size, uint8_t *buf);
uint8_t ModeSense6(uint8_t lun, uint8_t pc, uint8_t page, uint8_t subpage, uint8_t len, uint8_t *buf);
uint8_t GetMaxLUN(uint8_t *max_lun);
uint8_t SetCurLUN(uint8_t lun);
uint8_t ResetRecovery();
uint8_t ReadCapacity10(uint8_t lun, uint8_t *buf);
uint8_t Page3F(uint8_t lun);
uint8_t ClearEpHalt(uint8_t index);
uint8_t Transaction(UHS_BULK_CommandBlockWrapper *cbw, uint16_t bsize, void *buf);
uint8_t HandleUsbError(uint8_t error, uint8_t index);
uint8_t HandleSCSIError(uint8_t status);
};
#if defined(LOAD_UHS_BULK_STORAGE) && !defined(UHS_BULK_STORAGE_LOADED)
#include "UHS_BULK_STORAGE_INLINE.h"
#endif
#endif // __MASSTORAGE_H__

View File

@@ -0,0 +1,327 @@
/* Copyright (C) 2015-2016 Andrew J. Kroll
and
Copyright (C) 2011 Circuits At Home, LTD. All rights reserved.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Contact information
-------------------
Circuits At Home, LTD
Web : http://www.circuitsathome.com
e-mail : support@circuitsathome.com
*/
#ifndef UHS_SCSI_H
#define UHS_SCSI_H
/*
* 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 0x00U
#define SCSI_CMD_REQUEST_SENSE 0x03U
#define SCSI_CMD_FORMAT_UNIT 0x04U
#define SCSI_CMD_READ_6 0x08U
#define SCSI_CMD_WRITE_6 0x0AU
#define SCSI_CMD_INQUIRY 0x12U
#define SCSI_CMD_MODE_SELECT_6 0x15U
#define SCSI_CMD_MODE_SENSE_6 0x1AU
#define SCSI_CMD_START_STOP_UNIT 0x1BU
#define SCSI_CMD_PREVENT_REMOVAL 0x1EU
/* Group 2 Commands (CDB's here are 10-bytes) */
#define SCSI_CMD_READ_FORMAT_CAPACITIES 0x23U
#define SCSI_CMD_READ_CAPACITY_10 0x25U
#define SCSI_CMD_READ_10 0x28U
#define SCSI_CMD_WRITE_10 0x2AU
#define SCSI_CMD_SEEK_10 0x2BU
#define SCSI_CMD_ERASE_10 0x2CU
#define SCSI_CMD_WRITE_AND_VERIFY_10 0x2EU
#define SCSI_CMD_VERIFY_10 0x2FU
#define SCSI_CMD_SYNCHRONIZE_CACHE 0x35U
#define SCSI_CMD_WRITE_BUFFER 0x3BU
#define SCSI_CMD_READ_BUFFER 0x3CU
#define SCSI_CMD_READ_SUBCHANNEL 0x42U
#define SCSI_CMD_READ_TOC 0x43U
#define SCSI_CMD_READ_HEADER 0x44U
#define SCSI_CMD_PLAY_AUDIO_10 0x45U
#define SCSI_CMD_GET_CONFIGURATION 0x46U
#define SCSI_CMD_PLAY_AUDIO_MSF 0x47U
#define SCSI_CMD_PLAY_AUDIO_TI 0x48U
#define SCSI_CMD_PLAY_TRACK_REL_10 0x49U
#define SCSI_CMD_GET_EVENT_STATUS 0x4AU
#define SCSI_CMD_PAUSE_RESUME 0x4BU
#define SCSI_CMD_READ_DISC_INFORMATION 0x51U
#define SCSI_CMD_READ_TRACK_INFORMATION 0x52U
#define SCSI_CMD_RESERVE_TRACK 0x53U
#define SCSI_CMD_SEND_OPC_INFORMATION 0x54U
#define SCSI_CMD_MODE_SELECT_10 0x55U
#define SCSI_CMD_REPAIR_TRACK 0x58U
#define SCSI_CMD_MODE_SENSE_10 0x5AU
#define SCSI_CMD_CLOSE_TRACK_SESSION 0x5BU
#define SCSI_CMD_READ_BUFFER_CAPACITY 0x5CU
#define SCSI_CMD_SEND_CUE_SHEET 0x5DU
/* Group 5 Commands (CDB's here are 12-bytes) */
#define SCSI_CMD_REPORT_LUNS 0xA0U
#define SCSI_CMD_BLANK 0xA1U
#define SCSI_CMD_SECURITY_PROTOCOL_IN 0xA2U
#define SCSI_CMD_SEND_KEY 0xA3U
#define SCSI_CMD_REPORT_KEY 0xA4U
#define SCSI_CMD_PLAY_AUDIO_12 0xA5U
#define SCSI_CMD_LOAD_UNLOAD 0xA6U
#define SCSI_CMD_SET_READ_AHEAD 0xA7U
#define SCSI_CMD_READ_12 0xA8U
#define SCSI_CMD_PLAY_TRACK_REL_12 0xA9U
#define SCSI_CMD_WRITE_12 0xAAU
#define SCSI_CMD_READ_MEDIA_SERIAL_12 0xABU
#define SCSI_CMD_GET_PERFORMANCE 0xACU
#define SCSI_CMD_READ_DVD_STRUCTURE 0xADU
#define SCSI_CMD_SECURITY_PROTOCOL_OUT 0xB5U
#define SCSI_CMD_SET_STREAMING 0xB6U
#define SCSI_CMD_READ_MSF 0xB9U
#define SCSI_CMD_SET_SPEED 0xBBU
#define SCSI_CMD_MECHANISM_STATUS 0xBDU
#define SCSI_CMD_READ_CD 0xBEU
#define SCSI_CMD_SEND_DISC_STRUCTURE 0xBFU
/* Vendor-unique Commands, included for completeness */
#define SCSI_CMD_CD_PLAYBACK_STATUS 0xC4U /* SONY unique */
#define SCSI_CMD_PLAYBACK_CONTROL 0xC9U /* SONY unique */
#define SCSI_CMD_READ_CDDA 0xD8U /* Vendor unique */
#define SCSI_CMD_READ_CDXA 0xDBU /* Vendor unique */
#define SCSI_CMD_READ_ALL_SUBCODES 0xDFU /* Vendor unique */
/* SCSI error codes */
#define SCSI_S_NOT_READY 0x02U
#define SCSI_S_MEDIUM_ERROR 0x03U
#define SCSI_S_ILLEGAL_REQUEST 0x05U
#define SCSI_S_UNIT_ATTENTION 0x06U
#define SCSI_ASC_LBA_OUT_OF_RANGE 0x21U
#define SCSI_ASC_MEDIA_CHANGED 0x28U
#define SCSI_ASC_MEDIUM_NOT_PRESENT 0x3AU
struct SCSI_Capacity {
uint8_t data[8];
//uint32_t dwBlockAddress;
//uint32_t dwBlockLength;
} __attribute__((packed));
struct SCSI_CDB_BASE {
uint8_t Opcode;
unsigned unused : 5;
unsigned LUN : 3;
uint8_t info[12];
} __attribute__((packed));
typedef SCSI_CDB_BASE SCSI_CDB_BASE_t;
struct SCSI_CDB6 {
uint8_t Opcode;
unsigned LBAMSB : 5;
unsigned LUN : 3;
uint8_t LBAHB;
uint8_t LBALB;
uint8_t AllocationLength;
uint8_t Control;
public:
SCSI_CDB6(uint8_t _Opcode, uint8_t _LUN, uint32_t LBA, uint8_t _AllocationLength, uint8_t _Control) :
Opcode(_Opcode), LBAMSB(UHS_UINT8_BYTE2(LBA) & 0x1f), LUN(_LUN), LBAHB(UHS_UINT8_BYTE1(LBA)), LBALB(UHS_UINT8_BYTE0(LBA)),
AllocationLength(_AllocationLength), Control(_Control) {
}
SCSI_CDB6(uint8_t _Opcode, uint8_t _LUN, uint8_t _AllocationLength, uint8_t _Control) :
Opcode(_Opcode), LBAMSB(0), LUN(_LUN), LBAHB(0), LBALB(0),
AllocationLength(_AllocationLength), Control(_Control) {
}
} __attribute__((packed));
typedef SCSI_CDB6 SCSI_CDB6_t;
struct SCSI_CDB10 {
uint8_t Opcode;
unsigned Service_Action : 5;
unsigned LUN : 3;
uint8_t LBA_L_M_MB;
uint8_t LBA_L_M_LB;
uint8_t LBA_L_L_MB;
uint8_t LBA_L_L_LB;
uint8_t Misc2;
uint8_t ALC_MB;
uint8_t ALC_LB;
uint8_t Control;
public:
SCSI_CDB10(uint8_t _Opcode, uint8_t _LUN) :
Opcode(_Opcode), Service_Action(0), LUN(_LUN),
LBA_L_M_MB(0), LBA_L_M_LB(0), LBA_L_L_MB(0), LBA_L_L_LB(0),
Misc2(0), ALC_MB(0), ALC_LB(0), Control(0) {
}
SCSI_CDB10(uint8_t _Opcode, uint8_t _LUN, uint16_t xflen, uint32_t _LBA) :
Opcode(_Opcode), Service_Action(0), LUN(_LUN),
LBA_L_M_MB(UHS_UINT8_BYTE3(_LBA)), LBA_L_M_LB(UHS_UINT8_BYTE2(_LBA)), LBA_L_L_MB(UHS_UINT8_BYTE1(_LBA)), LBA_L_L_LB(UHS_UINT8_BYTE0(_LBA)),
Misc2(0), ALC_MB(UHS_UINT8_BYTE1(xflen)), ALC_LB(UHS_UINT8_BYTE0(xflen)), Control(0) {
}
} __attribute__((packed));
typedef SCSI_CDB10 SCSI_CDB10_t;
struct SCSI_CDB12 {
uint8_t Opcode;
unsigned Service_Action : 5;
unsigned Misc : 3;
uint8_t LBA_L_M_LB;
uint8_t LBA_L_L_MB;
uint8_t LBA_L_L_LB;
uint8_t ALC_M_LB;
uint8_t ALC_L_MB;
uint8_t ALC_L_LB;
uint8_t Control;
} __attribute__((packed));
typedef SCSI_CDB12 SCSI_CDB12_t;
struct SCSI_CDB_LBA32_16 {
uint8_t Opcode;
unsigned Service_Action : 5;
unsigned Misc : 3;
uint8_t LBA_L_M_MB;
uint8_t LBA_L_M_LB;
uint8_t LBA_L_L_MB;
uint8_t LBA_L_L_LB;
uint8_t A_M_M_MB;
uint8_t A_M_M_LB;
uint8_t A_M_L_MB;
uint8_t A_M_L_LB;
uint8_t ALC_M_MB;
uint8_t ALC_M_LB;
uint8_t ALC_L_MB;
uint8_t ALC_L_LB;
uint8_t Misc2;
uint8_t Control;
} __attribute__((packed));
struct SCSI_CDB_LBA64_16 {
uint8_t Opcode;
uint8_t Misc;
uint8_t LBA_M_M_MB;
uint8_t LBA_M_M_LB;
uint8_t LBA_M_L_MB;
uint8_t LBA_M_L_LB;
uint8_t LBA_L_M_MB;
uint8_t LBA_L_M_LB;
uint8_t LBA_L_L_MB;
uint8_t LBA_L_L_LB;
uint8_t ALC_M_MB;
uint8_t ALC_M_LB;
uint8_t ALC_L_MB;
uint8_t ALC_L_LB;
uint8_t Misc2;
uint8_t Control;
} __attribute__((packed));
struct SCSI_Inquiry_Response {
uint8_t DeviceType : 5;
uint8_t PeripheralQualifier : 3;
unsigned Reserved : 7;
unsigned Removable : 1;
uint8_t Version;
unsigned ResponseDataFormat : 4;
unsigned HISUP : 1;
unsigned NormACA : 1;
unsigned TrmTsk : 1;
unsigned AERC : 1;
uint8_t AdditionalLength;
unsigned PROTECT : 1;
unsigned Res : 2;
unsigned ThreePC : 1;
unsigned TPGS : 2;
unsigned ACC : 1;
unsigned SCCS : 1;
unsigned ADDR16 : 1;
unsigned R1 : 1;
unsigned R2 : 1;
unsigned MCHNGR : 1;
unsigned MULTIP : 1;
unsigned VS : 1;
unsigned ENCSERV : 1;
unsigned BQUE : 1;
unsigned SoftReset : 1;
unsigned CmdQue : 1;
unsigned Reserved4 : 1;
unsigned Linked : 1;
unsigned Sync : 1;
unsigned WideBus16Bit : 1;
unsigned WideBus32Bit : 1;
unsigned RelAddr : 1;
uint8_t VendorID[8];
uint8_t ProductID[16];
uint8_t RevisionID[4];
} __attribute__((packed));
struct SCSI_Request_Sense_Response {
uint8_t bResponseCode;
uint8_t bSegmentNumber;
uint8_t bmSenseKey : 4;
uint8_t bmReserved : 1;
uint8_t bmILI : 1;
uint8_t bmEOM : 1;
uint8_t bmFileMark : 1;
uint8_t Information[4];
uint8_t bAdditionalLength;
uint8_t CmdSpecificInformation[4];
uint8_t bAdditionalSenseCode;
uint8_t bAdditionalSenseQualifier;
uint8_t bFieldReplaceableUnitCode;
uint8_t SenseKeySpecific[3];
} __attribute__((packed));
#endif /* UHS_SCSI_H */

View File

@@ -0,0 +1,33 @@
/* Copyright (C) 2015-2016 Andrew J. Kroll
and
Copyright (C) 2011 Circuits At Home, LTD. All rights reserved.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Contact information
-------------------
Circuits At Home, LTD
Web : http://www.circuitsathome.com
e-mail : support@circuitsathome.com
*/
#ifndef _UHS_UNOFFICIAL_IDs_h
#define _UHS_UNOFFICIAL_IDs_h
// Bogus unofficial and unregistered VIDs from cloners to be listed here.
#define UHS_VID_UNOFFICIAL_JOYTECH 0x162EU // For unofficial Joytech controllers
#endif

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,336 @@
/* Copyright (C) 2015-2016 Andrew J. Kroll
and
Copyright (C) 2011 Circuits At Home, LTD. All rights reserved.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Contact information
-------------------
Circuits At Home, LTD
Web : http://www.circuitsathome.com
e-mail : support@circuitsathome.com
*/
#if !defined(_UHS_host_h_) || defined(USBCORE_H)
#error "Never include UHS_UsbCore.h directly; include UHS_Host.h instead"
#else
#define USBCORE_H
#ifndef UHS_HOST_MAX_INTERFACE_DRIVERS
#define UHS_HOST_MAX_INTERFACE_DRIVERS 0x10U // Default maximum number of USB interface drivers
#endif
#ifndef SYSTEM_OR_SPECIAL_YIELD
#define SYSTEM_OR_SPECIAL_YIELD(...) VOID0
#endif
#ifndef SYSTEM_OR_SPECIAL_YIELD_FROM_ISR
#define SYSTEM_OR_SPECIAL_YIELD_FROM_ISR(...) SYSTEM_OR_SPECIAL_YIELD
#endif
// As we make extensions to a target interface add to UHS_HOST_MAX_INTERFACE_DRIVERS
// This offset gets calculated for supporting wide subclasses, such as HID, BT, etc.
#define UHS_HID_INDEX (UHS_HOST_MAX_INTERFACE_DRIVERS + 1)
/* Common setup data constant combinations */
//get descriptor request type
#define UHS_bmREQ_GET_DESCR (USB_SETUP_DEVICE_TO_HOST|USB_SETUP_TYPE_STANDARD|USB_SETUP_RECIPIENT_DEVICE)
//set request type for all but 'set feature' and 'set interface'
#define UHS_bmREQ_SET (USB_SETUP_HOST_TO_DEVICE|USB_SETUP_TYPE_STANDARD|USB_SETUP_RECIPIENT_DEVICE)
//get interface request type
#define UHS_bmREQ_CL_GET_INTF (USB_SETUP_DEVICE_TO_HOST|USB_SETUP_TYPE_CLASS|USB_SETUP_RECIPIENT_INTERFACE)
// D7 data transfer direction (0 - host-to-device, 1 - device-to-host)
// D6-5 Type (0- standard, 1 - class, 2 - vendor, 3 - reserved)
// D4-0 Recipient (0 - device, 1 - interface, 2 - endpoint, 3 - other, 4..31 - reserved)
// TO-DO: Use the python script to generate these.
// TO-DO: Add _all_ subclasses here.
// USB Device Classes, Subclasses and Protocols
////////////////////////////////////////////////////////////////////////////////
// Use Class Info in the Interface Descriptors
#define UHS_USB_CLASS_USE_CLASS_INFO 0x00U
////////////////////////////////////////////////////////////////////////////////
// Audio
#define UHS_USB_CLASS_AUDIO 0x01U
// Subclasses
#define UHS_USB_SUBCLASS_AUDIOCONTROL 0x01U
#define UHS_USB_SUBCLASS_AUDIOSTREAMING 0x02U
#define UHS_USB_SUBCLASS_MIDISTREAMING 0x03U
////////////////////////////////////////////////////////////////////////////////
// Communications and CDC Control
#define UHS_USB_CLASS_COM_AND_CDC_CTRL 0x02U
////////////////////////////////////////////////////////////////////////////////
// HID
#define UHS_USB_CLASS_HID 0x03U
// Subclasses
#define UHS_HID_BOOT_SUBCLASS 0x01U
// Protocols
#define UHS_HID_PROTOCOL_HIDBOOT_KEYBOARD 0x01U
#define UHS_HID_PROTOCOL_HIDBOOT_MOUSE 0x02U
////////////////////////////////////////////////////////////////////////////////
// Physical
#define UHS_USB_CLASS_PHYSICAL 0x05U
////////////////////////////////////////////////////////////////////////////////
// Image
#define UHS_USB_CLASS_IMAGE 0x06U
////////////////////////////////////////////////////////////////////////////////
// Printer
#define UHS_USB_CLASS_PRINTER 0x07U
////////////////////////////////////////////////////////////////////////////////
// Mass Storage
#define UHS_USB_CLASS_MASS_STORAGE 0x08
// Subclasses
#define UHS_BULK_SUBCLASS_SCSI_NOT_REPORTED 0x00U // De facto use
#define UHS_BULK_SUBCLASS_RBC 0x01U
#define UHS_BULK_SUBCLASS_ATAPI 0x02U // MMC-5 (ATAPI)
#define UHS_BULK_SUBCLASS_OBSOLETE1 0x03U // Was QIC-157
#define UHS_BULK_SUBCLASS_UFI 0x04U // Specifies how to interface Floppy Disk Drives to USB
#define UHS_BULK_SUBCLASS_OBSOLETE2 0x05U // Was SFF-8070i
#define UHS_BULK_SUBCLASS_SCSI 0x06U // SCSI Transparent Command Set
#define UHS_BULK_SUBCLASS_LSDFS 0x07U // Specifies how host has to negotiate access before trying SCSI
#define UHS_BULK_SUBCLASS_IEEE1667 0x08U
// Protocols
#define UHS_STOR_PROTO_CBI 0x00U // CBI (with command completion interrupt)
#define UHS_STOR_PROTO_CBI_NO_INT 0x01U // CBI (without command completion interrupt)
#define UHS_STOR_PROTO_OBSOLETE 0x02U
#define UHS_STOR_PROTO_BBB 0x50U // Bulk Only Transport
#define UHS_STOR_PROTO_UAS 0x62U
////////////////////////////////////////////////////////////////////////////////
// Hub
#define UHS_USB_CLASS_HUB 0x09U
////////////////////////////////////////////////////////////////////////////////
// CDC-Data
#define UHS_USB_CLASS_CDC_DATA 0x0AU
////////////////////////////////////////////////////////////////////////////////
// Smart-Card
#define UHS_USB_CLASS_SMART_CARD 0x0BU
////////////////////////////////////////////////////////////////////////////////
// Content Security
#define UHS_USB_CLASS_CONTENT_SECURITY 0x0DU
////////////////////////////////////////////////////////////////////////////////
// Video
#define UHS_USB_CLASS_VIDEO 0x0EU
////////////////////////////////////////////////////////////////////////////////
// Personal Healthcare
#define UHS_USB_CLASS_PERSONAL_HEALTH 0x0FU
////////////////////////////////////////////////////////////////////////////////
// Diagnostic Device
#define UHS_USB_CLASS_DIAGNOSTIC_DEVICE 0xDCU
////////////////////////////////////////////////////////////////////////////////
// Wireless Controller
#define UHS_USB_CLASS_WIRELESS_CTRL 0xE0U
////////////////////////////////////////////////////////////////////////////////
// Miscellaneous
#define UHS_USB_CLASS_MISC 0xEFU
////////////////////////////////////////////////////////////////////////////////
// Application Specific
#define UHS_USB_CLASS_APP_SPECIFIC 0xFEU
////////////////////////////////////////////////////////////////////////////////
// Vendor Specific
#define UHS_USB_CLASS_VENDOR_SPECIFIC 0xFFU
////////////////////////////////////////////////////////////////////////////////
/* USB state machine states */
#define UHS_USB_HOST_STATE_MASK 0xF0U
// Configure states, MSN == 0 --------------------------V
#define UHS_USB_HOST_STATE_DETACHED 0x00U
#define UHS_USB_HOST_STATE_DEBOUNCE 0x01U
#define UHS_USB_HOST_STATE_DEBOUNCE_NOT_COMPLETE 0x02U
#define UHS_USB_HOST_STATE_RESET_NOT_COMPLETE 0x03U
#define UHS_USB_HOST_STATE_WAIT_SOF 0x04U
#define UHS_USB_HOST_STATE_WAIT_BUS_READY 0x05U
#define UHS_USB_HOST_STATE_RESET_DEVICE 0x0AU
#define UHS_USB_HOST_STATE_CONFIGURING 0x0CU // Looks like "CO"nfig (backwards)
#define UHS_USB_HOST_STATE_CONFIGURING_DONE 0x0DU // Looks like "DO"one (backwards)
#define UHS_USB_HOST_STATE_CHECK 0x0EU
#define UHS_USB_HOST_STATE_ILLEGAL 0x0FU // Foo
// Run states, MSN != 0 --------------------------------V
#define UHS_USB_HOST_STATE_RUNNING 0x60U // Looks like "GO"
#define UHS_USB_HOST_STATE_IDLE 0x1DU // Looks like "ID"le
#define UHS_USB_HOST_STATE_ERROR 0xF0U // Looks like "FO"o
#define UHS_USB_HOST_STATE_INITIALIZE 0x10U // Looks like "I"nit
// Host SE result codes.
// Common SE results are stored in the low nybble, all interface drivers understand these plus 0x1f.
// Extended SE results are 0x10-0x1e. SE code only understands these internal to the hardware.
// Values > 0x1F are driver or other internal error conditions.
// Return these result codes from your host controller driver to match the error condition
// ALL Non-zero values are errors.
// Values not listed in this table are not handled in the base class, or any host driver.
#define UHS_HOST_ERROR_NONE 0x00U // No error
#define UHS_HOST_ERROR_BUSY 0x01U // transfer pending
#define UHS_HOST_ERROR_BADREQ 0x02U // Transfer Launch Request was bad
#define UHS_HOST_ERROR_DMA 0x03U // DMA was too short, or too long
#define UHS_HOST_ERROR_NAK 0x04U // Peripheral returned NAK
#define UHS_HOST_ERROR_STALL 0x05U // Peripheral returned STALL
#define UHS_HOST_ERROR_TOGERR 0x06U // Toggle error/ISO over-underrun
#define UHS_HOST_ERROR_WRONGPID 0x07U // Received wrong Packet ID
#define UHS_HOST_ERROR_BADBC 0x08U // Byte count is bad
#define UHS_HOST_ERROR_PIDERR 0x09U // Received Packet ID is corrupted
#define UHS_HOST_ERROR_BADRQ 0x0AU // Packet error. Increase max packet.
#define UHS_HOST_ERROR_CRC 0x0BU // USB CRC was incorrect
#define UHS_HOST_ERROR_KERR 0x0CU // K-state instead of response, usually indicates wrong speed
#define UHS_HOST_ERROR_JERR 0x0DU // J-state instead of response, usually indicates wrong speed
#define UHS_HOST_ERROR_TIMEOUT 0x0EU // Device did not respond in time
#define UHS_HOST_ERROR_BABBLE 0x0FU // Line noise/unexpected data
#define UHS_HOST_ERROR_MEM_LAT 0x10U // Error caused by memory latency.
#define UHS_HOST_ERROR_NYET 0x11U // OUT transfer accepted with NYET
// Addressing error codes
#define ADDR_ERROR_INVALID_INDEX 0xA0U
#define ADDR_ERROR_INVALID_ADDRESS 0xA1U
// Common Interface Driver error codes
#define UHS_HOST_ERROR_DEVICE_NOT_SUPPORTED 0xD1U // Driver doesn't support the device or interfaces
#define UHS_HOST_ERROR_DEVICE_INIT_INCOMPLETE 0xD2U // Init partially finished, but died.
#define UHS_HOST_ERROR_CANT_REGISTER_DEVICE_CLASS 0xD3U // There was no driver for the interface requested.
#define UHS_HOST_ERROR_ADDRESS_POOL_FULL 0xD4U // No addresses left in the address pool.
#define UHS_HOST_ERROR_HUB_ADDRESS_OVERFLOW 0xD5U // No hub addresses left. The maximum is 7.
#define UHS_HOST_ERROR_NO_ADDRESS_IN_POOL 0xD6U // Address was not allocated in the pool, thus not found.
#define UHS_HOST_ERROR_NULL_EPINFO 0xD7U // The supplied endpoint was NULL, indicates a bug or other problem.
#define UHS_HOST_ERROR_BAD_ARGUMENT 0xD8U // Indicates a range violation bug.
#define UHS_HOST_ERROR_DEVICE_DRIVER_BUSY 0xD9U // The interface driver is busy or out buffer is full, try again later.
#define UHS_HOST_ERROR_BAD_MAX_PACKET_SIZE 0xDAU // The maximum packet size was exceeded. Try again with smaller size.
#define UHS_HOST_ERROR_NO_ENDPOINT_IN_TABLE 0xDBU // The endpoint could not be found in the endpoint table.
#define UHS_HOST_ERROR_UNPLUGGED 0xDEU // Someone removed the USB device, or Vbus was turned off.
#define UHS_HOST_ERROR_NOMEM 0xDFU // Out Of Memory.
// Control request stream errors
#define UHS_HOST_ERROR_FailGetDevDescr 0xE1U
#define UHS_HOST_ERROR_FailSetDevTblEntry 0xE2U
#define UHS_HOST_ERROR_FailGetConfDescr 0xE3U
#define UHS_HOST_ERROR_END_OF_STREAM 0xEFU
// Host base class specific Error codes
#define UHS_HOST_ERROR_NOT_IMPLEMENTED 0xFEU
#define UHS_HOST_ERROR_TRANSFER_TIMEOUT 0xFFU
// SEI interaction defaults
#define UHS_HOST_TRANSFER_MAX_MS 10000 // USB transfer timeout in ms, per section 9.2.6.1 of USB 2.0 spec
#define UHS_HOST_TRANSFER_RETRY_MAXIMUM 3 // 3 retry limit for a transfer
#define UHS_HOST_DEBOUNCE_DELAY_MS 500 // settle delay in milliseconds
#define UHS_HUB_RESET_DELAY_MS 20 // hub port reset delay, 10ms recomended, but can be up to 20ms
//
// We only provide the minimum needed information for enumeration.
// Interface drivers should be able to set up what is needed with nothing more.
// A driver needs to know the following information:
// 1: address on the USB network, parent and port (aka UsbDeviceAddress)
// 2: endpoints
// 3: vid:pid, class, subclass, protocol
//
struct ENDPOINT_INFO {
uint8_t bEndpointAddress; // Endpoint address. Bit 7 indicates direction (0=OUT, 1=IN).
uint8_t bmAttributes; // Endpoint transfer type.
uint16_t wMaxPacketSize; // Maximum packet size.
uint8_t bInterval; // Polling interval in frames.
} __attribute__((packed));
struct INTERFACE_INFO {
uint8_t bInterfaceNumber;
uint8_t bAlternateSetting;
uint8_t numep;
uint8_t klass;
uint8_t subklass;
uint8_t protocol;
ENDPOINT_INFO epInfo[16];
} __attribute__((packed));
struct ENUMERATION_INFO {
uint16_t vid;
uint16_t pid;
uint16_t bcdDevice;
uint8_t klass;
uint8_t subklass;
uint8_t protocol;
uint8_t bMaxPacketSize0;
uint8_t currentconfig;
uint8_t parent;
uint8_t port;
uint8_t address;
INTERFACE_INFO interface;
} __attribute__((packed));
/* USB Setup Packet Structure */
typedef struct {
// offset description
// 0 Bit-map of request type
union {
uint8_t bmRequestType;
struct {
uint8_t recipient : 5; // Recipient of the request
uint8_t type : 2; // Type of request
uint8_t direction : 1; // Direction of data transfer
} __attribute__((packed));
} ReqType_u;
// 1 Request
uint8_t bRequest;
// 2 Depends on bRequest
union {
uint16_t wValue;
struct {
uint8_t wValueLo;
uint8_t wValueHi;
} __attribute__((packed));
} wVal_u;
// 4 Depends on bRequest
uint16_t wIndex;
// 6 Depends on bRequest
uint16_t wLength;
// 8 bytes total
} __attribute__((packed)) SETUP_PKT, *PSETUP_PKT;
// little endian :-) 8 8 8 8 16 16
#define mkSETUP_PKT8(bmReqType, bRequest, wValLo, wValHi, wInd, total) ((uint64_t)(((uint64_t)(bmReqType)))|(((uint64_t)(bRequest))<<8)|(((uint64_t)(wValLo))<<16)|(((uint64_t)(wValHi))<<24)|(((uint64_t)(wInd))<<32)|(((uint64_t)(total)<<48)))
#define mkSETUP_PKT16(bmReqType, bRequest, wVal, wInd, total) ((uint64_t)(((uint64_t)(bmReqType)))|(((uint64_t)(bRequest))<<8)|(((uint64_t)(wVal ))<<16) |(((uint64_t)(wInd))<<32)|(((uint64_t)(total)<<48)))
// Big endian -- but we aren't able to use this :-/
//#define mkSETUP_PKT8(bmReqType, bRequest, wValLo, wValHi, wInd, total) ((uint64_t)(((uint64_t)(bmReqType))<<56)|(((uint64_t)(bRequest))<<48)|(((uint64_t)(wValLo))<<40)|(((uint64_t)(wValHi))<<32)|(((uint64_t)(wInd))<<16)|((uint64_t)(total)))
//#define mkSETUP_PKT16(bmReqType, bRequest, wVal, wInd, total) ((uint64_t)(((uint64_t)(bmReqType))<<56)|(((uint64_t)(bRequest))<<48) |(((uint64_t)(wVal))<<32) |(((uint64_t)(wInd))<<16)|((uint64_t)(total)))
#endif /* USBCORE_H */

View File

@@ -0,0 +1,248 @@
/* Copyright (C) 2015-2016 Andrew J. Kroll
and
Copyright (C) 2011 Circuits At Home, LTD. All rights reserved.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Contact information
-------------------
Circuits At Home, LTD
Web : http://www.circuitsathome.com
e-mail : support@circuitsathome.com
*/
#if !defined(_UHS_host_h_) || defined(__ADDRESS_H__)
#error "Never include UHS_address.h directly; include UHS_Usb.h instead"
#else
#define __ADDRESS_H__
/* NAK powers. To save space in endpoint data structure, amount of retries before giving up and returning 0x4 is stored in */
/* bmNakPower as a power of 2. The actual nak_limit is then calculated as nak_limit = ( 2^bmNakPower - 1) */
#define UHS_USB_NAK_MAX_POWER 14 // NAK binary order maximum value
#define UHS_USB_NAK_DEFAULT 13 // default 16K-1 NAKs before giving up
#define UHS_USB_NAK_NOWAIT 1 // Single NAK stops transfer
#define UHS_USB_NAK_NONAK 0 // Do not count NAKs, stop retrying after USB Timeout. Try not to use this.
#define bmUSB_DEV_ADDR_PORT 0x07
#define bmUSB_DEV_ADDR_PARENT 0x78
#define bmUSB_DEV_ADDR_HUB 0x40
// TODO: embed parent?
struct UHS_EpInfo {
uint8_t epAddr; // Endpoint address
uint8_t bIface;
uint16_t maxPktSize; // Maximum packet size
union {
uint8_t epAttribs;
struct {
uint8_t bmSndToggle : 1; // Send toggle, when zero bmSNDTOG0, bmSNDTOG1 otherwise
uint8_t bmRcvToggle : 1; // Send toggle, when zero bmRCVTOG0, bmRCVTOG1 otherwise
uint8_t bmNeedPing : 1; // 1 == ping protocol needed for next out packet
uint8_t bmNakPower : 5; // Binary order for NAK_LIMIT value
} __attribute__((packed));
};
} __attribute__((packed));
// TODO: embed parent address and port into epinfo struct,
// and nuke this address stupidity.
// This is a compact scheme. Should also support full spec.
// This produces a 7 hub limit, 49 devices + 7 hubs, 56 total.
//
// 7 6 5 4 3 2 1 0
// ---------------------------------
// | | H | P | P | P | A | A | A |
// ---------------------------------
//
// H - if 1 the address is a hub address
// P - parent hub number
// A - port number of parent
//
struct UHS_DeviceAddress {
union {
struct {
uint8_t bmAddress : 3; // port number
uint8_t bmParent : 3; // parent hub address
uint8_t bmHub : 1; // hub flag
uint8_t bmReserved : 1; // reserved, must be zero
} __attribute__((packed));
uint8_t devAddress;
};
} __attribute__((packed));
struct UHS_Device {
volatile UHS_EpInfo *epinfo[UHS_HOST_MAX_INTERFACE_DRIVERS]; // endpoint info pointer
UHS_DeviceAddress address;
uint8_t epcount; // number of endpoints
uint8_t speed; // indicates device speed
} __attribute__((packed));
typedef void (*UsbDeviceHandleFunc)(UHS_Device *pdev);
class AddressPool {
UHS_EpInfo dev0ep; //Endpoint data structure used during enumeration for uninitialized device
// In order to avoid hub address duplication, this should use bits
uint8_t hubCounter; // hub counter
UHS_Device thePool[UHS_HOST_MAX_INTERFACE_DRIVERS];
// Initializes address pool entry
void UHS_NI InitEntry(uint8_t index) {
thePool[index].address.devAddress = 0;
thePool[index].epcount = 1;
thePool[index].speed = 0;
for(uint8_t i = 0; i < UHS_HOST_MAX_INTERFACE_DRIVERS; i++) {
thePool[index].epinfo[i] = &dev0ep;
}
};
// Returns thePool index for a given address
uint8_t UHS_NI FindAddressIndex(uint8_t address = 0) {
for(uint8_t i = 1; i < UHS_HOST_MAX_INTERFACE_DRIVERS; i++) {
if(thePool[i].address.devAddress == address)
return i;
}
return 0;
};
// Returns thePool child index for a given parent
uint8_t UHS_NI FindChildIndex(UHS_DeviceAddress addr, uint8_t start = 1) {
for(uint8_t i = (start < 1 || start >= UHS_HOST_MAX_INTERFACE_DRIVERS) ? 1 : start; i < UHS_HOST_MAX_INTERFACE_DRIVERS; i++) {
if(thePool[i].address.bmParent == addr.bmAddress)
return i;
}
return 0;
};
// Frees address entry specified by index parameter
void UHS_NI FreeAddressByIndex(uint8_t index) {
// Zero field is reserved and should not be affected
if(index == 0)
return;
UHS_DeviceAddress uda = thePool[index].address;
// If a hub was switched off all port addresses should be freed
if(uda.bmHub == 1) {
for(uint8_t i = 1; (i = FindChildIndex(uda, i));)
FreeAddressByIndex(i);
// FIXME: use BIT MASKS
// If the hub had the last allocated address, hubCounter should be decremented
if(hubCounter == uda.bmAddress)
hubCounter--;
}
InitEntry(index);
}
void InitAllAddresses() {
for(uint8_t i = 1; i < UHS_HOST_MAX_INTERFACE_DRIVERS; i++) InitEntry(i);
hubCounter = 0;
};
public:
AddressPool() {
hubCounter = 0;
// Zero address is reserved
InitEntry(0);
thePool[0].epinfo[0] = &dev0ep;
dev0ep.epAddr = 0;
#if UHS_DEVICE_WINDOWS_USB_SPEC_VIOLATION_DESCRIPTOR_DEVICE
dev0ep.maxPktSize = 0x40; //starting at 0x40 and work down
#else
dev0ep.maxPktSize = 0x08;
#endif
dev0ep.epAttribs = 0; //set DATA0/1 toggles to 0
dev0ep.bmNakPower = UHS_USB_NAK_MAX_POWER;
InitAllAddresses();
};
// Returns a pointer to a specified address entry
UHS_Device* UHS_NI GetUsbDevicePtr(uint8_t addr) {
if(!addr)
return thePool;
uint8_t index = FindAddressIndex(addr);
return (!index) ? NULL : &thePool[index];
};
// Allocates new address
uint8_t UHS_NI AllocAddress(uint8_t parent, bool is_hub = false, uint8_t port = 1) {
/* if (parent != 0 && port == 0)
USB_HOST_SERIAL.println("PRT:0"); */
UHS_DeviceAddress _parent;
_parent.devAddress = parent;
if(_parent.bmReserved || port > 7)
//if(parent > 127 || port > 7)
return 0;
// FIXME: use BIT MASKS
if(is_hub && hubCounter == 7)
return 0;
// finds first empty address entry starting from one
uint8_t index = FindAddressIndex(0);
if(!index) // if empty entry is not found
return 0;
UHS_DeviceAddress addr;
addr.devAddress = port;
addr.bmParent = _parent.bmAddress;
// FIXME: use BIT MASKS
if(is_hub) {
hubCounter++;
addr.bmHub = 1;
addr.bmAddress = hubCounter;
}
thePool[index].address = addr;
#if DEBUG_PRINTF_EXTRA_HUGE
#ifdef UHS_DEBUG_USB_ADDRESS
printf("Address: %x (%x.%x.%x)\r\n", addr.devAddress, addr.bmHub, addr.bmParent, addr.bmAddress);
#endif
#endif
return thePool[index].address.devAddress;
};
void UHS_NI FreeAddress(uint8_t addr) {
// if the root hub is disconnected all the addresses should be initialized
if(addr == 0x41) {
InitAllAddresses();
return;
}
uint8_t index = FindAddressIndex(addr);
FreeAddressByIndex(index);
};
};
#endif // __ADDRESS_H__

View File

@@ -0,0 +1,70 @@
/* Copyright (C) 2015-2016 Andrew J. Kroll
and
Copyright (C) 2011 Circuits At Home, LTD. All rights reserved.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Contact information
-------------------
Circuits At Home, LTD
Web : http://www.circuitsathome.com
e-mail : support@circuitsathome.com
*/
#if !defined(_usb_h_) || defined(__HEXDUMP_H__)
#error "Never include UHS_hexdump.h directly; include UHS_Usb.h instead"
#else
#define __HEXDUMP_H__
extern int UsbDEBUGlvl;
template <class BASE_CLASS, class LEN_TYPE, class OFFSET_TYPE>
class HexDumper : public BASE_CLASS {
uint8_t byteCount;
OFFSET_TYPE byteTotal;
public:
HexDumper() : byteCount(0), byteTotal(0) {
};
void Initialize() {
byteCount = 0;
byteTotal = 0;
};
virtual void Parse(const LEN_TYPE len, const uint8_t *pbuf, const OFFSET_TYPE &offset);
};
template <class BASE_CLASS, class LEN_TYPE, class OFFSET_TYPE>
void HexDumper<BASE_CLASS, LEN_TYPE, OFFSET_TYPE>::Parse(const LEN_TYPE len, const uint8_t *pbuf, const OFFSET_TYPE &offset) {
if(UsbDEBUGlvl >= 0x80) { // Fully bypass this block of code if we do not debug.
for(LEN_TYPE j = 0; j < len; j++, byteCount++, byteTotal++) {
if(!byteCount) {
PrintHex<OFFSET_TYPE > (byteTotal, 0x80);
E_Notify(PSTR(": "), 0x80);
}
PrintHex<uint8_t > (pbuf[j], 0x80);
E_Notify(PSTR(" "), 0x80);
if(byteCount == 15) {
E_Notify(PSTR("\r\n"), 0x80);
byteCount = 0xFF;
}
}
}
}
#endif // __HEXDUMP_H__

View File

@@ -0,0 +1,111 @@
/* Copyright (C) 2015-2016 Andrew J. Kroll
and
Copyright (C) 2011 Circuits At Home, LTD. All rights reserved.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Contact information
-------------------
Circuits At Home, LTD
Web : http://www.circuitsathome.com
e-mail : support@circuitsathome.com
*/
/* USB functions */
#ifndef _UHS_host_h_
#define _UHS_host_h_
// WARNING: Do not change the order of includes, or stuff will break!
#include <inttypes.h>
#include <stddef.h>
#include <stdio.h>
#include <stdint.h>
#if DISABLED(USE_UHS3_USB)
#include <ISR_safe_memory.h>
#include <Wire.h>
#include <SPI.h>
#include <UHS_ByteBuffer.h>
#endif
#include "UHS_macros.h"
// None of these should ever be directly included by a driver, or a user's sketch.
#include "../dyn_SWI/dyn_SWI.h"
#include "UHS_USB_IDs.h"
#include "UHS_settings.h"
#include "UHS_usb_ch9.h"
#include "UHS_UsbCore.h"
#include "UHS_address.h"
#include "UHS_usbhost.h"
#include "UHS_printhex.h"
#include "UHS_message.h"
// Load system components as required
#if defined(LOAD_USB_HOST_SYSTEM) && !defined(USB_HOST_SYSTEM_LOADED)
#include "UHS_util_INLINE.h"
#include "UHS_host_INLINE.h"
#include "UHS_printf_HELPER.h"
#ifdef LOAD_USB_HOST_SHIELD
#include "USB_HOST_SHIELD/USB_HOST_SHIELD.h"
#endif
#if defined(LOAD_UHS_KINETIS_FS_HOST) && !defined(UHS_KINETIS_FS_HOST_LOADED)
#include "UHS_KINETIS_FS_HOST/UHS_KINETIS_FS_HOST.h"
#endif
#if defined(LOAD_UHS_KINETIS_EHCI) && !defined(UHS_KINETIS_EHCI_LOADED)
#include "UHS_KINETIS_EHCI/UHS_KINETIS_EHCI.h"
#endif
// Load USB drivers and multiplexers
#ifdef LOAD_UHS_HUB
#include "UHS_HUB/UHS_HUB.h"
#endif // HUB loaded
#ifdef LOAD_UHS_BULK_STORAGE
#include "UHS_BULK_STORAGE/UHS_BULK_STORAGE.h"
#endif
#ifdef LOAD_GENERIC_STORAGE
#include "../UHS_FS/UHS_FS.h"
#endif
// Add BT and optionally HID if directed to do so
#ifdef LOAD_UHS_BT
#include "UHS_BT/UHS_BT.h"
#endif // BT and optionally HID loaded
// Add HID
#ifdef LOAD_UHS_HID
#include "UHS_HID/UHS_HID.h"
#endif // HID loaded
// Add CDC multiplexers (currently only ACM)
#if defined(LOAD_UHS_CDC_ACM) || defined(LOAD_UHS_CDC_ACM_FTDI) || defined(LOAD_UHS_CDC_ACM_PROLIFIC) || defined(LOAD_UHS_CDC_ACM_XR21B1411)
#include "UHS_CDC/UHS_CDC.h"
#endif // CDC loaded
#ifdef LOAD_UHS_ADK
#include "UHS_ADK/UHS_ADK.h"
#endif
#ifdef LOAD_UHS_MIDI
#include "UHS_MIDI/UHS_MIDI.h"
#endif
#endif // System code loaded
#endif // _UHS_host_h_

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,392 @@
/* Copyright (C) 2015-2016 Andrew J. Kroll
and
Copyright (C) 2011 Circuits At Home, LTD. All rights reserved.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Contact information
-------------------
Circuits At Home, LTD
Web : http://www.circuitsathome.com
e-mail : support@circuitsathome.com
*/
#ifndef MACROS_H
#define MACROS_H
#include "macro_logic.h"
/*
* Universal Arduino(tm) "IDE" fixups.
*/
// Just in case...
#ifndef SERIAL_PORT_MONITOR
#define SERIAL_PORT_MONITOR Serial
#endif
#ifndef INT16_MIN
#define INT16_MIN -32768
#endif
// require 10607+
#if defined(ARDUINO) && ARDUINO >=10607
// nop :-)
#else
#error "Arduino version too old, and must be at least 1.6.7"
#endif
// Nuke screwed up macro junk from the IDE.
#ifdef __cplusplus
#ifdef true
#undef true
#endif
#ifdef false
#undef false
#endif
#endif
#ifndef UHS_DEVICE_WINDOWS_USB_SPEC_VIOLATION_DESCRIPTOR_DEVICE
#ifndef UHS_BIG_FLASH
#if defined(FLASHEND) && defined(FLASHSTART)
#if (FLASHEND - FLASHSTART) > 0x0FFFFU
#define UHS_BIG_FLASH 1
#else
#define UHS_BIG_FLASH 0
#endif
#elif defined(__PIC32_FLASH_SIZE)
#if __PIC32_FLASH_SIZE > 511
#define UHS_BIG_FLASH 1
#else
#define UHS_BIG_FLASH 0
#endif
#elif defined(FLASHEND) && !defined(FLASHSTART)
// Assumes flash starts at 0x00000, is this a safe assumption?
// 192K + should be OK
#if FLASHEND > 0x02FFFFU
#define UHS_BIG_FLASH 1
#else
#define UHS_BIG_FLASH 0
#endif
#elif defined(IFLASH_SIZE)
#if IFLASH_SIZE > 0x0FFFFU
#define UHS_BIG_FLASH 1
#else
#define UHS_BIG_FLASH 0
#endif
#elif defined(ESP8266)
#define UHS_BIG_FLASH 1
#define SYSTEM_OR_SPECIAL_YIELD(...) yield()
#elif defined(__arm__) && defined(CORE_TEENSY)
#define UHS_BIG_FLASH 1
#elif defined(ARDUINO_spresense_ast)
#define UHS_BIG_FLASH 1
#else
// safe default
#warning Small flash?
#define UHS_BIG_FLASH 0
#endif
#endif
#if UHS_BIG_FLASH
#define UHS_DEVICE_WINDOWS_USB_SPEC_VIOLATION_DESCRIPTOR_DEVICE 1
#else
#define UHS_DEVICE_WINDOWS_USB_SPEC_VIOLATION_DESCRIPTOR_DEVICE 0
#endif
#endif
#if defined(__arm__) && defined(CORE_TEENSY)
#define UHS_PIN_WRITE(p, v) digitalWriteFast(p, v)
#define UHS_PIN_READ(p) digitalReadFast(p)
#endif
// TODO: Fast inline code for AVR and SAM based microcontrollers
// This can be done pretty easily.
// For now, this will just work out-of-the-box.
#ifndef UHS_PIN_WRITE
#define UHS_PIN_WRITE(p, v) digitalWrite(p, v)
#endif
#ifndef UHS_PIN_READ
#define UHS_PIN_READ(p) digitalRead(p)
#endif
#if defined( __PIC32MX__ ) && !defined(interrupts) // compiling with Microchip XC32 compiler
#define interrupts() __builtin_enable_interrupts()
#edfine noInterrupts() __builtin_disable_interrupts()
#endif
#ifndef ARDUINO_SAMD_ZERO
#ifdef ARDUINO_AVR_ADK
#define UHS_GET_DPI(x) (x == 54 ? 6 : digitalPinToInterrupt(x))
#else
#define UHS_GET_DPI(x) digitalPinToInterrupt(x)
#endif
#else
#define UHS_GET_DPI(x) (x)
#endif
#ifndef __AVR__
#ifndef __PGMSPACE_H_
// This define should prevent reading the system pgmspace.h if included elsewhere
// This is not normally needed.
#define __PGMSPACE_H_ 1
#endif
#ifndef PROGMEM
#define PROGMEM
#endif
#ifndef PGM_P
#define PGM_P const char *
#endif
#ifndef PSTR
#define PSTR(str) (str)
#endif
#ifndef F
#define F(str) (str)
#endif
#ifndef _SFR_BYTE
#define _SFR_BYTE(n) (n)
#endif
#ifndef memchr_P
#define memchr_P(str, c, len) memchr((str), (c), (len))
#endif
#ifndef memcmp_P
#define memcmp_P(a, b, n) memcmp((a), (b), (n))
#endif
#ifndef memcpy_P
#define memcpy_P(dest, src, num) memcpy((dest), (src), (num))
#endif
#ifndef memmem_P
#define memmem_P(a, alen, b, blen) memmem((a), (alen), (b), (blen))
#endif
#ifndef memrchr_P
#define memrchr_P(str, val, len) memrchr((str), (val), (len))
#endif
#ifndef strcat_P
#define strcat_P(dest, src) strcat((dest), (src))
#endif
#ifndef strchr_P
#define strchr_P(str, c) strchr((str), (c))
#endif
#ifndef strchrnul_P
#define strchrnul_P(str, c) strchrnul((str), (c))
#endif
#ifndef strcmp_P
#define strcmp_P(a, b) strcmp((a), (b))
#endif
#ifndef strcpy_P
#define strcpy_P(dest, src) strcpy((dest), (src))
#endif
#ifndef strcasecmp_P
#define strcasecmp_P(a, b) strcasecmp((a), (b))
#endif
#ifndef strcasestr_P
#define strcasestr_P(a, b) strcasestr((a), (b))
#endif
#ifndef strlcat_P
#define strlcat_P(dest, src, len) strlcat((dest), (src), (len))
#endif
#ifndef strlcpy_P
#define strlcpy_P(dest, src, len) strlcpy((dest), (src), (len))
#endif
#ifndef strlen_P
#define strlen_P(s) strlen((const char *)(s))
#endif
#ifndef strnlen_P
#define strnlen_P(str, len) strnlen((str), (len))
#endif
#ifndef strncmp_P
#define strncmp_P(a, b, n) strncmp((a), (b), (n))
#endif
#ifndef strncasecmp_P
#define strncasecmp_P(a, b, n) strncasecmp((a), (b), (n))
#endif
#ifndef strncat_P
#define strncat_P(a, b, n) strncat((a), (b), (n))
#endif
#ifndef strncpy_P
#define strncpy_P(a, b, n) strncmp((a), (b), (n))
#endif
#ifndef strpbrk_P
#define strpbrk_P(str, chrs) strpbrk((str), (chrs))
#endif
#ifndef strrchr_P
#define strrchr_P(str, c) strrchr((str), (c))
#endif
#ifndef strsep_P
#define strsep_P(strp, delim) strsep((strp), (delim))
#endif
#ifndef strspn_P
#define strspn_P(str, chrs) strspn((str), (chrs))
#endif
#ifndef strstr_P
#define strstr_P(a, b) strstr((a), (b))
#endif
#ifndef sprintf_P
#define sprintf_P(s, ...) sprintf((s), __VA_ARGS__)
#endif
#ifndef vfprintf_P
#define vfprintf_P(s, ...) vfprintf((s), __VA_ARGS__)
#endif
#ifndef printf_P
#define printf_P(...) printf(__VA_ARGS__)
#endif
#ifndef snprintf_P
#define snprintf_P(s, n, ...) ((s), (n), __VA_ARGS__)
#endif
#ifndef vsprintf_P
#define vsprintf_P(s, ...) ((s),__VA_ARGS__)
#endif
#ifndef vsnprintf_P
#define vsnprintf_P(s, n, ...) ((s), (n),__VA_ARGS__)
#endif
#ifndef fprintf_P
#define fprintf_P(s, ...) ((s), __VA_ARGS__)
#endif
#ifndef pgm_read_byte
#define pgm_read_byte(addr) (*(const unsigned char *)(addr))
#endif
#ifndef pgm_read_word
#define pgm_read_word(addr) (*(const unsigned short *)(addr))
#endif
#ifndef pgm_read_dword
#define pgm_read_dword(addr) (*(const unsigned long *)(addr))
#endif
#ifndef pgm_read_float
#define pgm_read_float(addr) (*(const float *)(addr))
#endif
#ifndef pgm_read_byte_near
#define pgm_read_byte_near(addr) pgm_read_byte(addr)
#endif
#ifndef pgm_read_word_near
#define pgm_read_word_near(addr) pgm_read_word(addr)
#endif
#ifndef pgm_read_dword_near
#define pgm_read_dword_near(addr) pgm_read_dword(addr)
#endif
#ifndef pgm_read_float_near
#define pgm_read_float_near(addr) pgm_read_float(addr)
#endif
#ifndef pgm_read_byte_far
#define pgm_read_byte_far(addr) pgm_read_byte(addr)
#endif
#ifndef pgm_read_word_far
#define pgm_read_word_far(addr) pgm_read_word(addr)
#endif
#ifndef pgm_read_dword_far
#define pgm_read_dword_far(addr) pgm_read_dword(addr)
#endif
#ifndef pgm_read_float_far
#define pgm_read_float_far(addr) pgm_read_float(addr)
#endif
#ifndef pgm_read_pointer
#define pgm_read_pointer
#endif
#endif
////////////////////////////////////////////////////////////////////////////////
// HANDY MACROS
////////////////////////////////////////////////////////////////////////////////
// Atmoically set/clear single bits using bitbands.
// Believe it or not, this boils down to a constant,
// and is less code than using |= &= operators.
// Bonus, it makes code easier to read too.
// Bitbanding is a wonderful thing.
#define BITNR(i) (i&0x1?0:i&0x2?1:i&0x4?2:i&0x8?3:i&0x10?4:i&0x20?5:i&0x40?6:i&0x80?7:i&0x100?8:i&0x200?9:i&0x400?10:i&0x800?11:i&0x1000?12:i&0x2000?13:i&0x4000?14:i&0x8000?15:i&0x10000?16:i&0x20000?17:i&0x40000?18:i&0x80000?19:i&0x100000?20:i&0x200000?21:i&0x400000?22:i&0x800000?23:i&0x1000000?24:i&0x2000000?25:i&0x4000000?26:i&0x8000000?27:i&0x10000000?28:i&0x20000000?29:i&0x40000000?30:i&0x80000000?31:32)
#define UHS_KIO_BITBAND_ADDR(r, i) (((uint32_t)&(r) - 0x40000000) * 32 + (i) * 4 + 0x42000000)
#define UHS_KIO_SETBIT_ATOMIC(r, m) (*(uint32_t *)UHS_KIO_BITBAND_ADDR((r), BITNR((m)))) = 1
#define UHS_KIO_CLRBIT_ATOMIC(r, m) (*(uint32_t *)UHS_KIO_BITBAND_ADDR((r), BITNR((m)))) = 0
#define VALUE_BETWEEN(v,l,h) (((v)>(l)) && ((v)<(h)))
#define VALUE_WITHIN(v,l,h) (((v)>=(l)) && ((v)<=(h)))
#define output_pgm_message(wa,fp,mp,el) wa = &mp, fp((char *)pgm_read_pointer(wa), el)
#define output_if_between(v,l,h,wa,fp,mp,el) if(VALUE_BETWEEN(v,l,h)) output_pgm_message(wa,fp,mp[v-(l+1)],el);
#define UHS_SWAP_VALUES(a, b) (((a) ^= (b)), ((b) ^= (a)), ((a) ^= (b)))
#ifndef __BYTE_GRABBING_DEFINED__
#define __BYTE_GRABBING_DEFINED__ 1
#ifdef BROKEN_OPTIMIZER_LITTLE_ENDIAN
// Note: Use this if your compiler generates horrible assembler!
#define UHS_UINT8_BYTE0(__usi__) (((uint8_t *)&(__usi__))[0])
#define UHS_UINT8_BYTE1(__usi__) (((uint8_t *)&(__usi__))[1])
#define UHS_UINT8_BYTE2(__usi__) (((uint8_t *)&(__usi__))[2])
#define UHS_UINT8_BYTE3(__usi__) (((uint8_t *)&(__usi__))[3])
#define UHS_UINT8_BYTE4(__usi__) (((uint8_t *)&(__usi__))[4])
#define UHS_UINT8_BYTE5(__usi__) (((uint8_t *)&(__usi__))[5])
#define UHS_UINT8_BYTE6(__usi__) (((uint8_t *)&(__usi__))[6])
#define UHS_UINT8_BYTE7(__usi__) (((uint8_t *)&(__usi__))[7])
#else
// Note: The cast alone to uint8_t is actually enough.
// GCC throws out the "& 0xff", and the size is no different.
// Some compilers need it.
#define UHS_UINT8_BYTE0(__usi__) ((uint8_t)((__usi__) & 0xff ))
#define UHS_UINT8_BYTE1(__usi__) ((uint8_t)(((__usi__) >> 8) & 0xff))
#define UHS_UINT8_BYTE2(__usi__) ((uint8_t)(((__usi__) >> 16) & 0xff))
#define UHS_UINT8_BYTE3(__usi__) ((uint8_t)(((__usi__) >> 24) & 0xff))
#define UHS_UINT8_BYTE4(__usi__) ((uint8_t)(((__usi__) >> 32) & 0xff))
#define UHS_UINT8_BYTE5(__usi__) ((uint8_t)(((__usi__) >> 40) & 0xff))
#define UHS_UINT8_BYTE6(__usi__) ((uint8_t)(((__usi__) >> 48) & 0xff))
#define UHS_UINT8_BYTE7(__usi__) ((uint8_t)(((__usi__) >> 56) & 0xff))
#endif
#define UHS_UINT16_SET_BYTE1(__usi__) ((uint16_t)(__usi__) << 8)
#define UHS_UINT32_SET_BYTE1(__usi__) ((uint32_t)(__usi__) << 8)
#define UHS_UINT64_SET_BYTE1(__usi__) ((uint64_t)(__usi__) << 8)
#define UHS_UINT32_SET_BYTE2(__usi__) ((uint32_t)(__usi__) << 16)
#define UHS_UINT64_SET_BYTE2(__usi__) ((uint64_t)(__usi__) << 16)
#define UHS_UINT32_SET_BYTE3(__usi__) ((uint32_t)(__usi__) << 24)
#define UHS_UINT64_SET_BYTE3(__usi__) ((uint64_t)(__usi__) << 24)
#define UHS_UINT64_SET_BYTE4(__usi__) ((uint64_t)(__usi__) << 32)
#define UHS_UINT64_SET_BYTE5(__usi__) ((uint64_t)(__usi__) << 40)
#define UHS_UINT64_SET_BYTE6(__usi__) ((uint64_t)(__usi__) << 48)
#define UHS_UINT64_SET_BYTE7(__usi__) ((uint64_t)(__usi__) << 56)
// These are the smallest and fastest ways I have found so far in pure C/C++.
#define UHS_BYTES_TO_UINT16(__usc1__,__usc0__) ((uint16_t)((uint16_t)(__usc0__) | (uint16_t)UHS_UINT16_SET_BYTE1(__usc1__)))
#define UHS_BYTES_TO_UINT32(__usc3__,__usc2__,__usc1__,__usc0__) ((uint32_t)((uint32_t)(__usc0__) | UHS_UINT32_SET_BYTE1(__usc1__) | UHS_UINT32_SET_BYTE2(__usc2__) | UHS_UINT32_SET_BYTE3(__usc3__)))
#define UHS_BYTES_TO_UINT64(__usc7__,__usc6__,__usc5__,__usc4__,__usc3__,__usc2__,__usc1__,__usc0__) ((uint64_t)((uint64_t)__usc0__ | UHS_UINT64_SET_BYTE1(__usc1__) | UHS_UINT64_SET_BYTE2(__usc2__) | UHS_UINT64_SET_BYTE3(__usc3__) | UHS_UINT64_SET_BYTE4(__usc4__) | UHS_UINT64_SET_BYTE5(__usc5__) | UHS_UINT64_SET_BYTE6(__usc6__) | UHS_UINT64_SET_BYTE7(__usc7__)))
#endif
/*
* Debug macros.
* Useful when porting from UHS2.
* Do not use these for any new code.
* Change to better debugging after port is completed.
* Strings are stored in progmem (flash) instead of RAM.
*/
#define USBTRACE1(s,l) (Notify(PSTR(s), l))
#define USBTRACE(s) (USBTRACE1((s), 0x80)); USB_HOST_SERIAL.flush()
#define USBTRACE3(s,r,l) (Notify(PSTR(s), l), D_PrintHex((r), l), Notify(PSTR("\r\n"), l))
#define USBTRACE3X(s,r,l) (Notify(PSTR(s), l), D_PrintHex((r), l))
#define USBTRACE2(s,r) (USBTRACE3((s),(r),0x80)); USB_HOST_SERIAL.flush()
#define USBTRACE2X(s,r) (USBTRACE3X((s),(r),0x80)); USB_HOST_SERIAL.flush()
#define VOID0 ((void)0)
#ifndef NOTUSED
#define NOTUSED(...) __VA_ARGS__ __attribute__((unused))
#endif
#endif /* MACROS_H */

View File

@@ -0,0 +1,91 @@
/* Copyright (C) 2015-2016 Andrew J. Kroll
and
Copyright (C) 2011 Circuits At Home, LTD. All rights reserved.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Contact information
-------------------
Circuits At Home, LTD
Web : http://www.circuitsathome.com
e-mail : support@circuitsathome.com
*/
#if !defined(_UHS_host_h_) || defined(__MESSAGE_H__)
#error "Never include UHS_message.h directly; include UHS_Usb.h instead"
#else
#define __MESSAGE_H__
extern int UsbDEBUGlvl;
void E_Notify(char const * msg, int lvl);
void E_Notify(uint8_t b, int lvl);
void E_NotifyStr(char const * msg, int lvl);
void E_Notifyc(char c, int lvl);
#ifdef DEBUG_USB_HOST
#define Notify E_Notify
#define NotifyStr E_NotifyStr
#define Notifyc E_Notifyc
void NotifyFailGetDevDescr(uint8_t reason);
void NotifyFailSetDevTblEntry(uint8_t reason);
void NotifyFailGetConfDescr(uint8_t reason);
void NotifyFailSetConfDescr(uint8_t reason);
void NotifyFailGetDevDescr();
void NotifyFailSetDevTblEntry();
void NotifyFailGetConfDescr();
void NotifyFailSetConfDescr();
void NotifyFailUnknownDevice(uint16_t VID, uint16_t PID);
void NotifyFail(uint8_t rcode);
#else
#define Notify(...) VOID0
#define NotifyStr(...) VOID0
#define Notifyc(...) VOID0
#define NotifyFailGetDevDescr(...) VOID0
#define NotifyFailSetDevTblEntry(...) VOID0
#define NotifyFailGetConfDescr(...) VOID0
#define NotifyFailGetDevDescr(...) VOID0
#define NotifyFailSetDevTblEntry(...) VOID0
#define NotifyFailGetConfDescr(...) VOID0
#define NotifyFailSetConfDescr(...) VOID0
#define NotifyFailUnknownDevice(...) VOID0
#define NotifyFail(...) VOID0
#endif
#ifdef DEBUG_USB_HOST
template <class ERROR_TYPE> void ErrorMessage(uint8_t level, char const * msg, ERROR_TYPE rcode = 0) {
Notify(msg, level);
Notify(PSTR(": "), level);
D_PrintHex<ERROR_TYPE > (rcode, level);
Notify(PSTR("\r\n"), level);
#else
template <class ERROR_TYPE> void ErrorMessage(NOTUSED(uint8_t level), NOTUSED(char const * msg), ERROR_TYPE rcode = 0) {
(void)rcode;
#endif
}
#ifdef DEBUG_USB_HOST
template <class ERROR_TYPE> void ErrorMessage(char const * msg, ERROR_TYPE rcode = 0) {
Notify(msg, 0x80);
Notify(PSTR(": "), 0x80);
D_PrintHex<ERROR_TYPE > (rcode, 0x80);
Notify(PSTR("\r\n"), 0x80);
#else
template <class ERROR_TYPE> void ErrorMessage(NOTUSED(char const * msg), ERROR_TYPE rcode = 0) {
(void)rcode;
#endif
}
#endif // __MESSAGE_H__

View File

@@ -0,0 +1,200 @@
/* Copyright (C) 2015-2016 Andrew J. Kroll
and
Copyright (C) 2011 Circuits At Home, LTD. All rights reserved.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Contact information
-------------------
Circuits At Home, LTD
Web : http://www.circuitsathome.com
e-mail : support@circuitsathome.com
*/
#ifndef UHS_PRINTF_HELPER_H
#define UHS_PRINTF_HELPER_H
#ifdef LOAD_UHS_PRINTF_HELPER
#include <Arduino.h>
#ifdef true
#undef true
#endif
#ifdef false
#undef false
#endif
#ifndef STDIO_IS_OK_TO_USE_AS_IS
#if defined(ARDUINO_SAMD_ZERO) || defined(ARDUINO_SAM_DUE) || defined(ARDUINO_spresense_ast)
// STDIO patching not required.
#define STDIO_IS_OK_TO_USE_AS_IS
#endif
#endif
#ifndef STDIO_IS_OK_TO_USE_AS_IS
// We need to patch STDIO so it can be used.
#ifndef SERIAL_PORT_MONITOR
// Some don't define this.
#define SERIAL_PORT_MONITOR Serial
#endif
#ifndef SERIAL_PORT_HARDWARE
// Some don't define this.
#define SERIAL_PORT_HARDWARE SERIAL_PORT_MONITOR
#endif
#ifndef USB_HOST_SERIAL
#if defined(SERIAL_PORT_USBVIRTUAL) && defined(LOAD_UHS_KINETIS_FS_HOST)
#define USB_HOST_SERIAL SERIAL_PORT_HARDWARE
#else
#define USB_HOST_SERIAL SERIAL_PORT_MONITOR
#endif
#endif
#ifndef NOTUSED
#define NOTUSED(...) __VA_ARGS__ __attribute__((unused))
#endif
#ifndef __AVR__
#ifndef printf_P
#define printf_P(...) printf(__VA_ARGS__)
#endif
#endif
#ifdef ARDUINO_ARCH_PIC32
/*
* For printf() output with pic32 Arduino
*/
extern "C" {
void _mon_putc(char s) {
USB_HOST_SERIAL.write(s);
}
int _mon_getc() {
while(!USB_HOST_SERIAL.available());
return USB_HOST_SERIAL.read();
}
}
#elif defined(__AVR__)
extern "C" {
static FILE tty_stdio;
static FILE tty_stderr;
static int NOTUSED(tty_stderr_putc(char c, NOTUSED(FILE *t)));
static int NOTUSED(tty_stderr_flush(NOTUSED(FILE *t)));
static int NOTUSED(tty_std_putc(char c, NOTUSED(FILE *t)));
static int NOTUSED(tty_std_getc(NOTUSED(FILE *t)));
static int NOTUSED(tty_std_flush(NOTUSED(FILE *t)));
static int tty_stderr_putc(char c, NOTUSED(FILE *t)) {
USB_HOST_SERIAL.write(c);
return 0;
}
static int tty_stderr_flush(NOTUSED(FILE *t)) {
USB_HOST_SERIAL.flush();
return 0;
}
static int tty_std_putc(char c, NOTUSED(FILE *t)) {
USB_HOST_SERIAL.write(c);
return 0;
}
static int tty_std_getc(NOTUSED(FILE *t)) {
while(!USB_HOST_SERIAL.available());
return USB_HOST_SERIAL.read();
}
static int tty_std_flush(NOTUSED(FILE *t)) {
USB_HOST_SERIAL.flush();
return 0;
}
}
#elif defined(CORE_TEENSY)
extern "C" {
int _write(int fd, const char *ptr, int len) {
int j;
for(j = 0; j < len; j++) {
if(fd == 1)
USB_HOST_SERIAL.write(*ptr++);
else if(fd == 2)
USB_HOST_SERIAL.write(*ptr++);
}
return len;
}
int _read(int fd, char *ptr, int len) {
if(len > 0 && fd == 0) {
while(!USB_HOST_SERIAL.available());
*ptr = USB_HOST_SERIAL.read();
return 1;
}
return 0;
}
#include <sys/stat.h>
int _fstat(int fd, struct stat *st) {
memset(st, 0, sizeof (*st));
st->st_mode = S_IFCHR;
st->st_blksize = 1024;
return 0;
}
int _isatty(int fd) {
return (fd < 3) ? 1 : 0;
}
}
#else
#error no STDIO
#endif // defined(ARDUINO_ARCH_PIC32)
#ifdef __AVR__
// The only wierdo in the bunch...
void UHS_AVR_printf_HELPER_init() {
// Set up stdio/stderr
tty_stdio.put = tty_std_putc;
tty_stdio.get = tty_std_getc;
tty_stdio.flags = _FDEV_SETUP_RW;
tty_stdio.udata = 0;
tty_stderr.put = tty_stderr_putc;
tty_stderr.get = NULL;
tty_stderr.flags = _FDEV_SETUP_WRITE;
tty_stderr.udata = 0;
stdout = &tty_stdio;
stdin = &tty_stdio;
stderr = &tty_stderr;
}
#define UHS_printf_HELPER_init() UHS_AVR_printf_HELPER_init()
#endif
#endif /* STDIO_IS_OK_TO_USE_AS_IS */
#endif /* load.... */
#ifndef UHS_printf_HELPER_init
#define UHS_printf_HELPER_init() (void(0))
#endif
#endif /* UHS_PRINTF_HELPER_H */

View File

@@ -0,0 +1,96 @@
/* Copyright (C) 2015-2016 Andrew J. Kroll
and
Copyright (C) 2011 Circuits At Home, LTD. All rights reserved.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Contact information
-------------------
Circuits At Home, LTD
Web : http://www.circuitsathome.com
e-mail : support@circuitsathome.com
*/
#if !defined(_UHS_host_h_) || defined(__PRINTHEX_H__)
#error "Never include UHS_printhex.h directly; include UHS_Usb.h instead"
#else
#define __PRINTHEX_H__
void E_Notifyc(char c, int lvl);
template <class T>
void PrintHex(T val, int lvl) {
int num_nibbles = sizeof (T) * 2;
do {
char v = 48 + (((val >> (num_nibbles - 1) * 4)) & 0x0f);
if(v > 57) v += 7;
E_Notifyc(v, lvl);
} while(--num_nibbles);
}
template <class T>
void PrintBin(T val, int lvl) {
for(T mask = (((T)1) << ((sizeof (T) << 3) - 1)); mask; mask >>= 1)
if(val & mask)
E_Notifyc('1', lvl);
else
E_Notifyc('0', lvl);
}
template <class T>
void SerialPrintHex(T val) {
int num_nibbles = sizeof (T) * 2;
do {
char v = 48 + (((val >> (num_nibbles - 1) * 4)) & 0x0f);
if(v > 57) v += 7;
USB_HOST_SERIAL.print(v);
} while(--num_nibbles);
}
template <class T>
void PrintHex2(Print *prn, T val) {
T mask = (((T)1) << (((sizeof (T) << 1) - 1) << 2));
while(mask > 1) {
if(val < mask)
prn->print("0");
mask >>= 4;
}
prn->print((T)val, HEX);
}
#ifdef DEBUG_USB_HOST
template <class T> void D_PrintHex(T val, int lvl) {
PrintHex<T > (val, lvl);
#else
template <class T> void D_PrintHex(NOTUSED(T val), NOTUSED(int lvl)) {
#endif
}
#ifdef DEBUG_USB_HOST
template <class T> void D_PrintBin(T val, int lvl) {
PrintBin<T > (val, lvl);
#else
template <class T> void D_PrintBin(NOTUSED(T val), NOTUSED(int lvl)) {
#endif
}
#endif // __PRINTHEX_H__

View File

@@ -0,0 +1,141 @@
/* Copyright (C) 2015-2016 Andrew J. Kroll
and
Copyright (C) 2011 Circuits At Home, LTD. All rights reserved.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Contact information
-------------------
Circuits At Home, LTD
Web : http://www.circuitsathome.com
e-mail : support@circuitsathome.com
*/
#ifndef UHS_SETTINGS_H
#define UHS_SETTINGS_H
// TO-DO: Move specific settings to modules which use them.
////////////////////////////////////////////////////////////////////////////////
// Define any of these options at the top of your sketch to override
// the defaults contained herewith. Do NOT do modifications here.
// Individual Components have their own settings.
//
// Macro | Settings and notes | Default
// -----------------------------+-----------------------+-----------------------
// | Any class that does |
// USB_HOST_SERIAL | text streaming | SERIAL_PORT_MONITOR
// | e.g. Serial2 |
// -----------------------------+-----------------------+-----------------------
// ENABLE_UHS_DEBUGGING | 0 = off, 1 = on | 0
// -----------------------------+-----------------------+-----------------------
// | 0 = off, 1 = on |
// | Caution! Can make |
// DEBUG_PRINTF_EXTRA_HUGE | program too large! | 0
// | Other modules depend |
// | on this setting. |
// -----------------------------+-----------------------+-----------------------
// USE_UHS_BLACK_WIDDOW | 0 = no, 1 = yes | 0
// -----------------------------+-----------------------+-----------------------
// ENABLE_WII_IR_CAMERA | 0 = no, 1 = yes | 0
// -----------------------------^-----------------------^-----------------------
//
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
// DEBUGGING
////////////////////////////////////////////////////////////////////////////////
#ifndef USB_HOST_SERIAL
#if defined(SERIAL_PORT_USBVIRTUAL) && defined(LOAD_UHS_KINETIS_FS_HOST)
#define USB_HOST_SERIAL SERIAL_PORT_HARDWARE
#else
#define USB_HOST_SERIAL SERIAL_PORT_MONITOR
#endif
#endif
#ifndef ENABLE_UHS_DEBUGGING
#define ENABLE_UHS_DEBUGGING 0
#endif
#ifndef DEBUG_PRINTF_EXTRA_HUGE
#define DEBUG_PRINTF_EXTRA_HUGE 0
#endif
////////////////////////////////////////////////////////////////////////////////
// Manual board activation
////////////////////////////////////////////////////////////////////////////////
/* Set this to 1 if you are using a Black Widdow */
#ifndef USE_UHS_BLACK_WIDDOW
#define USE_UHS_BLACK_WIDDOW 0
#endif
////////////////////////////////////////////////////////////////////////////////
// Wii IR camera
////////////////////////////////////////////////////////////////////////////////
/* Set this to 1 to activate code for the Wii IR camera */
#ifndef ENABLE_WII_IR_CAMERA
#define ENABLE_WII_IR_CAMERA 0
#endif
////////////////////////////////////////////////////////////////////////////////
// Set to 1 to use the faster spi4teensy3 driver. (not used yet))
////////////////////////////////////////////////////////////////////////////////
#ifndef USE_SPI4TEENSY3
#define USE_SPI4TEENSY3 0
#endif
////////////////////////////////////////////////////////////////////////////////
// AUTOMATIC Settings
////////////////////////////////////////////////////////////////////////////////
// No user serviceable parts below this line.
// DO NOT change anything below here unless you are a developer!
#if defined(__GNUC__) && defined(__AVR__)
#ifndef GCC_VERSION
#define GCC_VERSION (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__)
#endif
#if GCC_VERSION < 40602 // Test for GCC < 4.6.2
#ifdef PROGMEM
#undef PROGMEM
#define PROGMEM __attribute__((section(".progmem.data"))) // Workaround for 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
#define UHS_SLEEP_MS(v) pUsb->sof_delay(v)
#ifndef UHS_NI
#define UHS_NI __attribute__((noinline))
#endif
#endif /* SETTINGS_H */

View File

@@ -0,0 +1,222 @@
/* Copyright (C) 2015-2016 Andrew J. Kroll
and
Copyright (C) 2011 Circuits At Home, LTD. All rights reserved.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Contact information
-------------------
Circuits At Home, LTD
Web : http://www.circuitsathome.com
e-mail : support@circuitsathome.com
*/
#if !defined(_UHS_host_h_) || defined(_UHS_ch9_h_)
#error "Never include UHS_usb_ch9.h directly; include UHS_Usb.h instead"
#else
/* USB chapter 9 structures */
#define _UHS_ch9_h_
/* Misc.USB constants */
#define DEV_DESCR_LEN 18 //device descriptor length
#define CONF_DESCR_LEN 9 //configuration descriptor length
#define INTR_DESCR_LEN 9 //interface descriptor length
#define EP_DESCR_LEN 7 //endpoint descriptor length
/* Standard Device Requests */
#define USB_REQUEST_GET_STATUS 0 // Standard Device Request - GET STATUS
#define USB_REQUEST_CLEAR_FEATURE 1 // Standard Device Request - CLEAR FEATURE
#define USB_REQUEST_SET_FEATURE 3 // Standard Device Request - SET FEATURE
#define USB_REQUEST_SET_ADDRESS 5 // Standard Device Request - SET ADDRESS
#define USB_REQUEST_GET_DESCRIPTOR 6 // Standard Device Request - GET DESCRIPTOR
#define USB_REQUEST_SET_DESCRIPTOR 7 // Standard Device Request - SET DESCRIPTOR
#define USB_REQUEST_GET_CONFIGURATION 8 // Standard Device Request - GET CONFIGURATION
#define USB_REQUEST_SET_CONFIGURATION 9 // Standard Device Request - SET CONFIGURATION
#define USB_REQUEST_GET_INTERFACE 10 // Standard Device Request - GET INTERFACE
#define USB_REQUEST_SET_INTERFACE 11 // Standard Device Request - SET INTERFACE
#define USB_REQUEST_SYNCH_FRAME 12 // Standard Device Request - SYNCH FRAME
/* Wireless USB Device Requests */
#define USB_REQ_SET_ENCRYPTION 0x0D
#define USB_REQ_GET_ENCRYPTION 0x0E
#define USB_REQ_RPIPE_ABORT 0x0E
#define USB_REQ_SET_HANDSHAKE 0x0F
#define USB_REQ_RPIPE_RESET 0x0F
#define USB_REQ_GET_HANDSHAKE 0x10
#define USB_REQ_SET_CONNECTION 0x11
#define USB_REQ_SET_SECURITY_DATA 0x12
#define USB_REQ_GET_SECURITY_DATA 0x13
#define USB_REQ_SET_WUSB_DATA 0x14
#define USB_REQ_LOOPBACK_DATA_WRITE 0x15
#define USB_REQ_LOOPBACK_DATA_READ 0x16
#define USB_REQ_SET_INTERFACE_DS 0x17
/* USB feature flags */
#define USB_DEVICE_SELF_POWERED 0 /* (read only) */
#define USB_DEVICE_REMOTE_WAKEUP 1 /* dev may initiate wakeup */
#define USB_DEVICE_TEST_MODE 2 /* (wired high speed only) */
#define USB_DEVICE_BATTERY 2 /* (wireless) */
#define USB_DEVICE_B_HNP_ENABLE 3 /* (otg) dev may initiate HNP */
#define USB_DEVICE_WUSB_DEVICE 3 /* (wireless)*/
#define USB_DEVICE_A_HNP_SUPPORT 4 /* (otg) RH port supports HNP */
#define USB_DEVICE_A_ALT_HNP_SUPPORT 5 /* (otg) other RH port does */
#define USB_DEVICE_DEBUG_MODE 6 /* (special devices only) */
#define USB_FEATURE_ENDPOINT_HALT 0 // CLEAR/SET FEATURE - Endpoint Halt
#define USB_FEATURE_DEVICE_REMOTE_WAKEUP 1 // CLEAR/SET FEATURE - Device remote wake-up
#define USB_FEATURE_TEST_MODE 2 // CLEAR/SET FEATURE - Test mode
/* OTG SET FEATURE Constants */
#define OTG_FEATURE_B_HNP_ENABLE 3 // SET FEATURE OTG - Enable B device to perform HNP
#define OTG_FEATURE_A_HNP_SUPPORT 4 // SET FEATURE OTG - A device supports HNP
#define OTG_FEATURE_A_ALT_HNP_SUPPORT 5 // SET FEATURE OTG - Another port on the A device supports HNP
/* Setup Data Constants */
#define USB_SETUP_HOST_TO_DEVICE 0x00 // Device Request bmRequestType transfer direction - host to device transfer
#define USB_SETUP_DEVICE_TO_HOST 0x80 // Device Request bmRequestType transfer direction - device to host transfer
#define USB_SETUP_TYPE_STANDARD 0x00 // Device Request bmRequestType type - standard
#define USB_SETUP_TYPE_CLASS 0x20 // Device Request bmRequestType type - class
#define USB_SETUP_TYPE_VENDOR 0x40 // Device Request bmRequestType type - vendor
#define USB_SETUP_RECIPIENT_DEVICE 0x00 // Device Request bmRequestType recipient - device
#define USB_SETUP_RECIPIENT_INTERFACE 0x01 // Device Request bmRequestType recipient - interface
#define USB_SETUP_RECIPIENT_ENDPOINT 0x02 // Device Request bmRequestType recipient - endpoint
#define USB_SETUP_RECIPIENT_OTHER 0x03 // Device Request bmRequestType recipient - other
#define USB_SETUP_RECIPIENT_PORT 0x04 // Wireless USB 1.0
#define USB_SETUP_RECIPIENT_RPIPE 0x05 // Wireless USB 1.0
/* USB descriptors */
#define USB_DESCRIPTOR_DEVICE 0x01 // bDescriptorType for a Device Descriptor.
#define USB_DESCRIPTOR_CONFIGURATION 0x02 // bDescriptorType for a Configuration Descriptor.
#define USB_DESCRIPTOR_STRING 0x03 // bDescriptorType for a String Descriptor.
#define USB_DESCRIPTOR_INTERFACE 0x04 // bDescriptorType for an Interface Descriptor.
#define USB_DESCRIPTOR_ENDPOINT 0x05 // bDescriptorType for an Endpoint Descriptor.
#define USB_DESCRIPTOR_DEVICE_QUALIFIER 0x06 // bDescriptorType for a Device Qualifier.
#define USB_DESCRIPTOR_OTHER_SPEED 0x07 // bDescriptorType for a Other Speed Configuration.
#define USB_DESCRIPTOR_INTERFACE_POWER 0x08 // bDescriptorType for Interface Power.
#define USB_DESCRIPTOR_OTG 0x09 // bDescriptorType for an OTG Descriptor.
#define USB_DESCRIPTOR_DEBUG 0x0a
#define USB_DESCRIPTOR_INTERFACE_ASSOCIATION 0x0b
#define USB_DESCRIPTOR_SECURITY 0x0c
#define USB_DESCRIPTOR_KEY 0x0d
#define USB_DESCRIPTOR_ENCRYPTION_TYPE 0x0e
#define USB_DESCRIPTOR_BOS 0x0f
#define USB_DESCRIPTOR_DEVICE_CAPABILITY 0x10
#define USB_DESCRIPTOR_WIRELESS_ENDPOINT_COMP 0x11
#define USB_DESCRIPTOR_WIRE_ADAPTER 0x21
#define USB_DESCRIPTOR_RPIPE 0x22
#define USB_DESCRIPTOR_CS_RADIO_CONTROL 0x23
#define USB_DESCRIPTOR_SS_ENDPOINT_COMP 0x30
#define USB_HID_DESCRIPTOR 0x21
// Conventional codes for class-specific descriptors. "Common Class" Spec (3.11)
#define USB_DESCRIPTOR_CS_DEVICE 0x21
#define USB_DESCRIPTOR_CS_CONFIG 0x22
#define USB_DESCRIPTOR_CS_STRING 0x23
#define USB_DESCRIPTOR_CS_INTERFACE 0x24
#define USB_DESCRIPTOR_CS_ENDPOINT 0x25
/* USB Endpoint Transfer Types */
#define USB_TRANSFER_TYPE_CONTROL 0x00 // Endpoint is a control endpoint.
#define USB_TRANSFER_TYPE_ISOCHRONOUS 0x01 // Endpoint is an isochronous endpoint.
#define USB_TRANSFER_TYPE_BULK 0x02 // Endpoint is a bulk endpoint.
#define USB_TRANSFER_TYPE_INTERRUPT 0x03 // Endpoint is an interrupt endpoint.
#define bmUSB_TRANSFER_TYPE 0x03 // bit mask to separate transfer type from ISO attributes
#define USB_TRANSFER_DIRECTION_IN 0x80 // Indicate direction is IN
/* Standard Feature Selectors for CLEAR_FEATURE Requests */
#define USB_FEATURE_ENDPOINT_STALL 0 // Endpoint recipient
#define USB_FEATURE_DEVICE_REMOTE_WAKEUP 1 // Device recipient
#define USB_FEATURE_TEST_MODE 2 // Device recipient
/* descriptor data structures */
/* Device descriptor structure */
typedef struct {
uint8_t bLength; // Length of this descriptor.
uint8_t bDescriptorType; // DEVICE descriptor type (USB_DESCRIPTOR_DEVICE).
uint16_t bcdUSB; // USB Spec Release Number (BCD).
uint8_t bDeviceClass; // Class code (assigned by the USB-IF). 0xFF-Vendor specific.
uint8_t bDeviceSubClass; // Subclass code (assigned by the USB-IF).
uint8_t bDeviceProtocol; // Protocol code (assigned by the USB-IF). 0xFF-Vendor specific.
uint8_t bMaxPacketSize0; // Maximum packet size for endpoint 0.
uint16_t idVendor; // Vendor ID (assigned by the USB-IF).
uint16_t idProduct; // Product ID (assigned by the manufacturer).
uint16_t bcdDevice; // Device release number (BCD).
uint8_t iManufacturer; // Index of String Descriptor describing the manufacturer.
uint8_t iProduct; // Index of String Descriptor describing the product.
uint8_t iSerialNumber; // Index of String Descriptor with the device's serial number.
uint8_t bNumConfigurations; // Number of possible configurations.
} __attribute__((packed)) USB_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_

View File

@@ -0,0 +1,452 @@
/* Copyright (C) 2015-2016 Andrew J. Kroll
and
Copyright (C) 2011 Circuits At Home, LTD. All rights reserved.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Contact information
-------------------
Circuits At Home, LTD
Web : http://www.circuitsathome.com
e-mail : support@circuitsathome.com
*/
#ifndef _UHS_host_h_
#error "Never include UHS_usbhost.h directly; include UHS_host.h instead"
#else
#ifndef _USBHOST_H_
#define _USBHOST_H_
// Very early prototypes
#ifdef UHS_LOAD_BT
void UHS_BT_SetUSBInterface(UHS_USB_HOST_BASE *host, ENUMERATION_INFO *ei);
void UHS_BT_ScanUninitialized(UHS_USB_HOST_BASE *host);
void UHS_BT_Poll(UHS_USB_HOST_BASE *host);
#endif
#ifdef UHS_LOAD_HID
void UHS_HID_SetUSBInterface(UHS_USB_HOST_BASE *host, ENUMERATION_INFO *ei);
void UHS_HID_ScanUninitialized(UHS_USB_HOST_BASE *host);
void UHS_HID_Poll(UHS_USB_HOST_BASE *host);
#endif
//#if defined(LOAD_UHS_CDC_ACM) || defined(LOAD_UHS_CDC_ACM_FTDI) || defined(LOAD_UHS_CDC_ACM_PROLIFIC) || defined(LOAD_UHS_CDC_ACM_XR21B1411)
//void UHS_CDC_ACM_SetUSBInterface(UHS_USB_HOST_BASE *host, ENUMERATION_INFO *ei);
//void UHS_CDC_ACM_ScanUninitialized(UHS_USB_HOST_BASE *host);
//void UHS_CDC_ACM_Poll(UHS_USB_HOST_BASE *host);
//#endif
class UHS_USBInterface; // forward class declaration
// enumerator to turn the VBUS on/off
typedef enum {
vbus_on = 0,
vbus_off = 1
} VBUS_t;
// All host SEI use this base class
class UHS_USB_HOST_BASE {
public:
AddressPool addrPool;
UHS_USBInterface* devConfig[UHS_HOST_MAX_INTERFACE_DRIVERS];
volatile uint8_t usb_error;
volatile uint8_t usb_task_state;
volatile uint8_t usb_task_polling_disabled;
volatile uint8_t usb_host_speed;
volatile uint8_t hub_present;
UHS_USB_HOST_BASE() {
for(uint16_t i = 0; i < UHS_HOST_MAX_INTERFACE_DRIVERS; i++) {
devConfig[i] = NULL;
}
usb_task_polling_disabled = 0;
usb_task_state = UHS_USB_HOST_STATE_INITIALIZE; //set up state machine
usb_host_speed = 0;
usb_error = 0;
};
/////////////////////////////////////////////
//
// Virtual methods that interface to the SIE
// Overriding each is mandatory.
//
/////////////////////////////////////////////
/**
* Delay for x milliseconds
* Override if your controller provides an SOF IRQ, which may involve
* some sort of reentrant ISR or workaround with interrupts enabled.
*
* @param x how many milliseconds to delay
* @return true if delay completed without a state change, false if delay aborted
*/
virtual bool UHS_NI sof_delay(uint16_t x) {
if(!(usb_task_state & UHS_USB_HOST_STATE_MASK)) return false;
uint8_t current_state = usb_task_state;
while(current_state == usb_task_state && x--) {
delay(1);
}
return (current_state == usb_task_state);
};
virtual UHS_EpInfo * UHS_NI ctrlReqOpen(NOTUSED(uint8_t addr), NOTUSED(uint64_t Request), NOTUSED(uint8_t* dataptr)) {
return NULL;
};
virtual void UHS_NI vbusPower(NOTUSED(VBUS_t state)) {
};
virtual void UHS_NI Task() {
};
virtual uint8_t UHS_NI SetAddress(NOTUSED(uint8_t addr), NOTUSED(uint8_t ep), NOTUSED(UHS_EpInfo **ppep), NOTUSED(uint16_t &nak_limit)) {
return UHS_HOST_ERROR_NOT_IMPLEMENTED;
};
virtual uint8_t UHS_NI OutTransfer(NOTUSED(UHS_EpInfo *pep), NOTUSED(uint16_t nak_limit), NOTUSED(uint16_t nbytes), NOTUSED(uint8_t *data)) {
return UHS_HOST_ERROR_NOT_IMPLEMENTED;
};
virtual uint8_t UHS_NI InTransfer(NOTUSED(UHS_EpInfo *pep), NOTUSED(uint16_t nak_limit), NOTUSED(uint16_t *nbytesptr), NOTUSED(uint8_t *data)) {
return UHS_HOST_ERROR_NOT_IMPLEMENTED;
};
virtual uint8_t UHS_NI ctrlReqClose(NOTUSED(UHS_EpInfo *pep), NOTUSED(uint8_t bmReqType), NOTUSED(uint16_t left), NOTUSED(uint16_t nbytes), NOTUSED(uint8_t *dataptr)) {
return UHS_HOST_ERROR_NOT_IMPLEMENTED;
};
virtual uint8_t UHS_NI ctrlReqRead(NOTUSED(UHS_EpInfo *pep), NOTUSED(uint16_t *left), NOTUSED(uint16_t *read), NOTUSED(uint16_t nbytes), NOTUSED(uint8_t *dataptr)) {
return UHS_HOST_ERROR_NOT_IMPLEMENTED;
};
virtual uint8_t UHS_NI dispatchPkt(NOTUSED(uint8_t token), NOTUSED(uint8_t ep), NOTUSED(uint16_t nak_limit)) {
return UHS_HOST_ERROR_NOT_IMPLEMENTED;
};
virtual uint8_t UHS_NI init() {
return 0;
};
virtual void UHS_NI doHostReset() {
};
virtual int16_t UHS_NI Init(NOTUSED(int16_t mseconds)) {
return -1;
};
virtual int16_t UHS_NI Init() {
return Init(INT16_MIN);
};
virtual uint8_t hwlPowerUp() {
/* This is for machine specific support to enable/power up the USB HW to operate*/
return UHS_HOST_ERROR_NOT_IMPLEMENTED;
};
virtual uint8_t hwPowerDown() {
/* This is for machine specific support to disable/powerdown the USB Hw */
return UHS_HOST_ERROR_NOT_IMPLEMENTED;
};
virtual bool IsHub(uint8_t klass) {
return (klass == UHS_USB_CLASS_HUB);
};
virtual void UHS_NI suspend_host() {
// Used on MCU that lack control of IRQ priority (AVR).
// Suspends ISRs, for critical code. IRQ will be serviced after it is resumed.
// NOTE: you must track the state yourself!
};
virtual void UHS_NI resume_host() {
// Used on MCU that lack control of IRQ priority (AVR).
// Resumes ISRs.
// NOTE: you must track the state yourself!
};
/////////////////////////////////////////////
//
// Built-ins, No need to override
//
/////////////////////////////////////////////
// these two probably will go away, and won't be used, TBD
inline void Poll_Others() {
#ifdef UHS_LOAD_BT
UHS_BT_Poll(this);
#endif
#ifdef UHS_LOAD_HID
UHS_HID_Poll(this);
#endif
}
inline void DisablePoll() {
noInterrupts();
usb_task_polling_disabled++;
DDSB();
interrupts();
}
inline void EnablePoll() {
noInterrupts();
usb_task_polling_disabled--;
DDSB();
interrupts();
}
uint8_t UHS_NI seekInterface(ENUMERATION_INFO *ei, uint16_t inf, USB_CONFIGURATION_DESCRIPTOR *ucd);
uint8_t UHS_NI setEpInfoEntry(uint8_t addr, uint8_t iface, uint8_t epcount, volatile UHS_EpInfo* eprecord_ptr);
uint8_t UHS_NI EPClearHalt(uint8_t addr, uint8_t ep);
uint8_t UHS_NI ctrlReq(uint8_t addr, uint64_t Request, uint16_t nbytes, uint8_t* dataptr);
uint8_t UHS_NI getDevDescr(uint8_t addr, uint16_t nbytes, uint8_t* dataptr);
uint8_t UHS_NI getConfDescr(uint8_t addr, uint16_t nbytes, uint8_t conf, uint8_t* dataptr);
uint8_t UHS_NI setAddr(uint8_t oldaddr, uint8_t newaddr);
uint8_t UHS_NI setConf(uint8_t addr, uint8_t conf_value);
uint8_t UHS_NI getStrDescr(uint8_t addr, uint16_t nbytes, uint8_t index, uint16_t langid, uint8_t* dataptr);
void UHS_NI ReleaseDevice(uint8_t addr);
uint8_t UHS_NI Configuring(uint8_t parent, uint8_t port, uint8_t speed);
void UHS_NI DeviceDefaults(uint8_t maxep, UHS_USBInterface *device);
UHS_EpInfo* UHS_NI getEpInfoEntry(uint8_t addr, uint8_t ep);
inline uint8_t getUsbTaskState() {
return ( usb_task_state);
};
inline AddressPool* GetAddressPool() {
return &addrPool;
};
int UHS_NI RegisterDeviceClass(UHS_USBInterface *pdev) {
for(uint8_t i = 0; i < UHS_HOST_MAX_INTERFACE_DRIVERS; i++) {
if(!devConfig[i]) {
devConfig[i] = pdev;
return i;
}
}
//return UHS_HOST_ERROR_CANT_REGISTER_DEVICE_CLASS;
return -1;
};
#if 0
inline void ForEachUsbDevice(UsbDeviceHandleFunc pfunc) {
addrPool.ForEachUsbDevice(pfunc);
};
#endif
uint8_t TestInterface(ENUMERATION_INFO *ei);
uint8_t enumerateInterface(ENUMERATION_INFO *ei);
uint8_t getNextInterface(ENUMERATION_INFO *ei, UHS_EpInfo *pep, uint8_t data[], uint16_t *left, uint16_t *read, uint8_t *offset);
uint8_t initDescrStream(ENUMERATION_INFO *ei, USB_CONFIGURATION_DESCRIPTOR *ucd, UHS_EpInfo *pep, uint8_t *data, uint16_t *left, uint16_t *read, uint8_t *offset);
uint8_t outTransfer(uint8_t addr, uint8_t ep, uint16_t nbytes, uint8_t* data);
uint8_t inTransfer(uint8_t addr, uint8_t ep, uint16_t *nbytesptr, uint8_t* data);
uint8_t doSoftReset(uint8_t parent, uint8_t port, uint8_t address);
uint8_t getone(UHS_EpInfo *pep, uint16_t *left, uint16_t *read, uint8_t *dataptr, uint8_t *offset);
uint8_t eat(UHS_EpInfo *pep, uint16_t *left, uint16_t *read, uint8_t *dataptr, uint8_t *offset, uint16_t *yum);
};
// All device interface drivers use this subclass
class UHS_USBInterface {
public:
UHS_USB_HOST_BASE *pUsb; // Parent USB host
volatile uint8_t bNumEP; // total number of EP in this interface
volatile UHS_EpInfo epInfo[16]; // This is a stub, override in the driver.
volatile uint8_t bAddress; // address of the device
volatile uint8_t bConfNum; // configuration number
volatile uint8_t bIface; // interface value
volatile bool bPollEnable; // poll enable flag, operating status
volatile uint32_t qNextPollTime; // next poll time
/**
* Resets interface driver to unused state. You should override this in
* your driver if it requires extra class variable cleanup.
*/
virtual void DriverDefaults() {
printf("Default driver defaults.\r\n");
pUsb->DeviceDefaults(bNumEP, this);
};
/**
* Checks if this interface is supported.
* Executed called when new devices are connected.
*
* @param ei
* @return true if the interface is supported
*/
virtual bool OKtoEnumerate(NOTUSED(ENUMERATION_INFO *ei)) {
return false;
};
/**
* Configures any needed endpoint information for an interface.
* You must provide this in your driver.
* Executed when new devices are connected and OKtoEnumerate()
* returned true.
*
* @param ei
* @return zero on success
*/
virtual uint8_t SetInterface(NOTUSED(ENUMERATION_INFO *ei)) {
return UHS_HOST_ERROR_NOT_IMPLEMENTED;
};
/**
* Interface specific additional setup and enumeration that
* can't occur when the descriptor stream is open.
* Also used for collection of unclaimed interfaces, to link to the master.
*
* @return zero on success
*/
virtual uint8_t Finalize() {
return 0;
};
/**
* Executed after interface is finalized but, before polling has started.
*
* @return 0 on success
*/
virtual uint8_t OnStart() {
return 0;
};
/**
* Start interface polling
* @return
*/
virtual uint8_t Start() {
uint8_t rcode = OnStart();
if(!rcode) bPollEnable = true;
return rcode;
};
/**
* Executed before anything else in Release().
*
*/
virtual void OnRelease() {
return;
};
/**
* Release resources when device is disconnected.
* Normally this does not need to be overridden.
*/
virtual void Release() {
OnRelease();
DriverDefaults();
return;
};
/**
* Executed After driver polls.
* Can be used when there is an important change detected during polling
* and you want to handle it elsewhere.
* Examples:
* Media status change for bulk, e.g. ready, not-ready, media changed, door opened.
* Button state/joystick position/etc changes on a HID device.
* Flow control status change on a communication device, e.g. CTS on serial
*/
virtual void OnPoll() {
return;
};
/**
* Poll interface driver. You should override this in your driver if you
* require polling faster or slower than every 100 milliseconds, or your
* driver requires special housekeeping.
*/
virtual void Poll() {
OnPoll();
qNextPollTime = millis() + 100;
};
virtual bool UHS_NI Polling() {
return bPollEnable;
}
/**
* This is only for a hub.
* @param port
*/
virtual void ResetHubPort(NOTUSED(uint8_t port)) {
return;
};
#if 0
/**
*
* @return true if this interface is Vendor Specific.
*/
virtual bool IsVSI() {
return false;
}
#endif
};
#if 0
/**
*
* Vendor Specific interface class.
* This is used by a partner interface.
* It can also be used to force-enumerate an interface that
* can use this interface directly.
* You can also add an instance of this class within the interface constructor
* if you expect the interface.
*
* If this is not needed, it may be removed. Nothing I have written needs this.
* Let me know if it is not required, then IsVSI method can also be shit-canned.
* -- AJK
*/
class UHS_VSI : public UHS_USBInterface {
public:
volatile UHS_EpInfo epInfo[1];
volatile ENUMERATION_INFO eInfo;
UHS_VSI(UHS_USB_HOST_BASE *p);
bool OKtoEnumerate(ENUMERATION_INFO *ei);
uint8_t SetInterface(ENUMERATION_INFO *ei);
virtual void DriverDefaults();
virtual void Release();
uint8_t GetAddress() {
return bAddress;
};
virtual bool IsVSI() {
return true;
}
};
#endif
#endif //_USBHOST_H_
#endif

View File

@@ -0,0 +1,129 @@
/* Copyright (C) 2015-2016 Andrew J. Kroll
and
Copyright (C) 2011 Circuits At Home, LTD. All rights reserved.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Contact information
-------------------
Circuits At Home, LTD
Web : http://www.circuitsathome.com
e-mail : support@circuitsathome.com
*/
#if defined(LOAD_USB_HOST_SYSTEM) && !defined(USB_HOST_SYSTEM_UTIL_LOADED)
#define USB_HOST_SYSTEM_UTIL_LOADED
// 0x80 is the default (i.e. trace) to turn off set this global to something lower.
// this allows for 126 other debugging levels.
// TO-DO: Allow assignment to a different serial port by software
int UsbDEBUGlvl = 0x80;
void E_Notifyc(char c, int lvl) {
if(UsbDEBUGlvl < lvl) return;
#if defined(ARDUINO) && ARDUINO >=100
USB_HOST_SERIAL.print(c);
#else
USB_HOST_SERIAL.print(c, BYTE);
#endif
//USB_HOST_SERIAL.flush();
}
void E_Notify(char const * msg, int lvl) {
if(UsbDEBUGlvl < lvl) return;
if(!msg) return;
char c;
while((c = pgm_read_byte(msg++))) E_Notifyc(c, lvl);
}
void E_NotifyStr(char const * msg, int lvl) {
if(UsbDEBUGlvl < lvl) return;
if(!msg) return;
char c;
while((c = *msg++)) E_Notifyc(c, lvl);
}
void E_Notify(uint8_t b, int lvl) {
if(UsbDEBUGlvl < lvl) return;
#if defined(ARDUINO) && ARDUINO >=100
USB_HOST_SERIAL.print(b);
#else
USB_HOST_SERIAL.print(b, DEC);
#endif
}
void E_Notify(double d, int lvl) {
if(UsbDEBUGlvl < lvl) return;
USB_HOST_SERIAL.print(d);
}
#ifdef DEBUG_USB_HOST
void NotifyFailGetDevDescr() {
Notify(PSTR("\r\ngetDevDescr "), 0x80);
}
void NotifyFailSetDevTblEntry() {
Notify(PSTR("\r\nsetDevTblEn "), 0x80);
}
void NotifyFailGetConfDescr() {
Notify(PSTR("\r\ngetConf "), 0x80);
}
void NotifyFailSetConfDescr() {
Notify(PSTR("\r\nsetConf "), 0x80);
}
void NotifyFailGetDevDescr(uint8_t reason) {
NotifyFailGetDevDescr();
NotifyFail(reason);
}
void NotifyFailSetDevTblEntry(uint8_t reason) {
NotifyFailSetDevTblEntry();
NotifyFail(reason);
}
void NotifyFailGetConfDescr(uint8_t reason) {
NotifyFailGetConfDescr();
NotifyFail(reason);
}
void NotifyFailSetConfDescr(uint8_t reason) {
NotifyFailSetConfDescr();
NotifyFail(reason);
}
void NotifyFailUnknownDevice(uint16_t VID, uint16_t PID) {
Notify(PSTR("\r\nUnknown Device Connected - VID: "), 0x80);
D_PrintHex<uint16_t > (VID, 0x80);
Notify(PSTR(" PID: "), 0x80);
D_PrintHex<uint16_t > (PID, 0x80);
}
void NotifyFail(uint8_t rcode) {
D_PrintHex<uint8_t > (rcode, 0x80);
Notify(PSTR("\r\n"), 0x80);
}
#endif
#else
#error "Never include UHS_util_INLINE.h, include UHS_host.h instead"
#endif

View File

@@ -0,0 +1,226 @@
/* Copyright (C) 2015-2016 Andrew J. Kroll
and
Copyright (C) 2011 Circuits At Home, LTD. All rights reserved.
This software may be distributed and modified under the terms of the GNU
General Public License version 2 (GPL2) as published by the Free Software
Foundation and appearing in the file GPL2.TXT included in the packaging of
this file. Please note that GPL2 Section 2[b] requires that all works based
on this software must also be made publicly available under the terms of
the GPL2 ("Copyleft").
Contact information
-------------------
Circuits At Home, LTD
Web : http://www.circuitsathome.com
e-mail : support@circuitsathome.com
*/
#if !defined(USB_HOST_SHIELD_H) || defined(_max3421e_h_)
#error "Never include UHS_max3421e.h directly; include USB_HOST_SHIELD.h instead"
#else
#define _max3421e_h_
/* MAX3421E register/bit names and bitmasks */
#define SE0 0
#define SE1 1
#define FSHOST 2
#define LSHOST 3
/* MAX3421E command byte format: rrrrr0wa where 'r' is register number */
//
// MAX3421E Registers in HOST mode.
//
#define rRCVFIFO 0x08 // Receive FIFO Register
#define rSNDFIFO 0x10 // Send FIFO Register
#define rSUDFIFO 0x20 // Set Up Data FIFO Register
#define rRCVBC 0x30 // Receive FIFO Byte Count Register
#define rSNDBC 0x38 // Send FIFO Byte Count Register
// USB Interrupt Request Status (USBIRQ)
#define rUSBIRQ 0x68 // USB Interrupt Request Register
#define bmVBUSIRQ 0x40 // Vbus Present Interrupt Request
#define bmNOVBUSIRQ 0x20 // Vbus Absent Interrupt Request
#define bmOSCOKIRQ 0x01 // Oscillator OK Interrupt Request
// USB Interrupt Request Control (USBIEN)
#define rUSBIEN 0x70 // USB Interrupt Request Enable Register
#define bmVBUSIE bmVBUSIRQ // Vbus Present Interrupt Request Enable
#define bmNOVBUSIE bmNOVBUSIRQ // Vbus Absent Interrupt Request Enable
#define bmOSCOKIE bmOSCOKIRQ // Oscillator OK Interrupt Request Enable
// (USBCTL)
#define rUSBCTL 0x78 //15<<3
#define bmCHIPRES 0x20 //b5
#define bmPWRDOWN 0x10 //b4
// (CPUCTL)
#define rCPUCTL 0x80 //16<<3
#define bmPUSLEWID1 0x80 //b7
#define bmPULSEWID0 0x40 //b6
#define bmIE 0x01 //b0
// bmPUSLEWID1 bmPULSEWID0 Pulse width
// 0 0 10.6uS
// 0 1 5.3uS
// 1 0 2.6uS
// 1 1 1.3uS
#define PUSLEWIDTH10_6 (0)
#define PUSLEWIDTH5_3 (bmPULSEWID0)
#define PUSLEWIDTH2_6 (bmPUSLEWID1)
#define PUSLEWIDTH1_3 (bmPULSEWID0 | bmPUSLEWID1)
// (PINCTL)
#define rPINCTL 0x88 //17<<3
#define bmFDUPSPI 0x10 //b4
#define bmINTLEVEL 0x08 //b3
#define bmPOSINT 0x04 //b2
#define bmGPXB 0x02 //b1
#define bmGPXA 0x01 //b0
// GPX pin selections
#define GPX_OPERATE 0x00 //
#define GPX_VBDET 0x01 //
#define GPX_BUSACT 0x02 //
#define GPX_SOF 0x03 //
#define rREVISION 0x90 //18<<3
// (IOPINS1)
#define rIOPINS1 0xa0 //20<<3
#define bmGPOUT0 0x01 //
#define bmGPOUT1 0x02 //
#define bmGPOUT2 0x04 //
#define bmGPOUT3 0x08 //
#define bmGPIN0 0x10 //
#define bmGPIN1 0x20 //
#define bmGPIN2 0x40 //
#define bmGPIN3 0x80 //
// (IOPINS2)
#define rIOPINS2 0xa8 //21<<3
#define bmGPOUT4 0x01 //
#define bmGPOUT5 0x02 //
#define bmGPOUT6 0x04 //
#define bmGPOUT7 0x08 //
#define bmGPIN4 0x10 //
#define bmGPIN5 0x20 //
#define bmGPIN6 0x40 //
#define bmGPIN7 0x80 //
// (GPINIRQ)
#define rGPINIRQ 0xb0 //22<<3
#define bmGPINIRQ0 0x01 //
#define bmGPINIRQ1 0x02 //
#define bmGPINIRQ2 0x04 //
#define bmGPINIRQ3 0x08 //
#define bmGPINIRQ4 0x10 //
#define bmGPINIRQ5 0x20 //
#define bmGPINIRQ6 0x40 //
#define bmGPINIRQ7 0x80 //
// (GPINIEN)
#define rGPINIEN 0xb8 //23<<3
#define bmGPINIEN0 0x01 //
#define bmGPINIEN1 0x02 //
#define bmGPINIEN2 0x04 //
#define bmGPINIEN3 0x08 //
#define bmGPINIEN4 0x10 //
#define bmGPINIEN5 0x20 //
#define bmGPINIEN6 0x40 //
#define bmGPINIEN7 0x80 //
// (GPINPOL)
#define rGPINPOL 0xc0 //24<<3
#define bmGPINPOL0 0x01 //
#define bmGPINPOL1 0x02 //
#define bmGPINPOL2 0x04 //
#define bmGPINPOL3 0x08 //
#define bmGPINPOL4 0x10 //
#define bmGPINPOL5 0x20 //
#define bmGPINPOL6 0x40 //
#define bmGPINPOL7 0x80 //
//
// If any data transfer errors occur, the HXFRDNIRQ asserts, while the RCVDAVIRQ does not.
//
// The CPU clears the SNDBAVIRQ by writing the SNDBC register.
// The CPU should never directly clear the SNDBAVIRQ bit.
// Host Interrupt Request Status (HIRQ)
#define rHIRQ 0xc8 // Host Interrupt Request Register
#define bmBUSEVENTIRQ 0x01 // BUS Reset Done or BUS Resume Interrupt Request
#define bmRWUIRQ 0x02 // Remote Wakeup Interrupt Request
#define bmRCVDAVIRQ 0x04 // Receive FIFO Data Available Interrupt Request
#define bmSNDBAVIRQ 0x08 // Send Buffer Available Interrupt Request
#define bmSUSDNIRQ 0x10 // Suspend operation Done Interrupt Request
#define bmCONDETIRQ 0x20 // Peripheral Connect/Disconnect Interrupt Request
#define bmFRAMEIRQ 0x40 // Frame Generator Interrupt Request
#define bmHXFRDNIRQ 0x80 // Host Transfer Done Interrupt Request
// IRQs that are OK for the CPU to clear
#define ICLRALLBITS (bmBUSEVENTIRQ | bmRWUIRQ | bmRCVDAVIRQ | bmSUSDNIRQ | bmCONDETIRQ | bmFRAMEIRQ | bmHXFRDNIRQ)
// Host Interrupt Request Control (HIEN)
#define rHIEN 0xd0 //
#define bmBUSEVENTIE bmBUSEVENTIRQ // BUS Reset Done or BUS Resume Interrupt Request Enable
#define bmRWUIE bmRWUIRQ // Remote Wakeup Interrupt Request Enable
#define bmRCVDAVIE bmRCVDAVIRQ // Receive FIFO Data Available Interrupt Request Enable
#define bmSNDBAVIE bmSNDBAVIRQ // Send Buffer Available Interrupt Request Enable
#define bmSUSDNIE bmSUSDNIRQ // Suspend operation Done Interrupt Request Enable
#define bmCONDETIE bmCONDETIRQ // Peripheral Connect/Disconnect Interrupt Request Enable
#define bmFRAMEIE bmFRAMEIRQ // Frame Generator Interrupt Request Enable
#define bmHXFRDNIE bmHXFRDNIRQ // Host Transfer Done Interrupt Request Enable
// (MODE))
#define rMODE 0xd8 //27<<3
#define bmHOST 0x01 //
#define bmLOWSPEED 0x02 //
#define bmHUBPRE 0x04 //
#define bmSOFKAENAB 0x08 //
#define bmSEPIRQ 0x10 //
#define bmDELAYISO 0x20 //
#define bmDMPULLDN 0x40 //
#define bmDPPULLDN 0x80 //
#define rPERADDR 0xe0 //28<<3
// (HCTL)
#define rHCTL 0xe8 //29<<3
#define bmBUSRST 0x01 //
#define bmFRMRST 0x02 //
#define bmSAMPLEBUS 0x04 //
#define bmSIGRSM 0x08 //
#define bmRCVTOG0 0x10 //
#define bmRCVTOG1 0x20 //
#define bmSNDTOG0 0x40 //
#define bmSNDTOG1 0x80 //
// Host transfer (HXFR)
#define rHXFR 0xf0 //30<<3
/* Host transfer token values for writing the HXFR register (R30) */
/* OR this bit field with the endpoint number in bits 3:0 */
#define MAX3421E_tokSETUP 0x10 // HS=0, ISO=0, OUTNIN=0, SETUP=1
#define MAX3421E_tokIN 0x00 // HS=0, ISO=0, OUTNIN=0, SETUP=0
#define MAX3421E_tokOUT 0x20 // HS=0, ISO=0, OUTNIN=1, SETUP=0
#define MAX3421E_tokINHS 0x80 // HS=1, ISO=0, OUTNIN=0, SETUP=0
#define MAX3421E_tokOUTHS 0xA0 // HS=1, ISO=0, OUTNIN=1, SETUP=0
#define MAX3421E_tokISOIN 0x40 // HS=0, ISO=1, OUTNIN=0, SETUP=0
#define MAX3421E_tokISOOUT 0x60 // HS=0, ISO=1, OUTNIN=1, SETUP=0
// (HRSL)
#define rHRSL 0xf8 //31<<3
#define bmRCVTOGRD 0x10 //
#define bmSNDTOGRD 0x20 //
#define bmKSTATUS 0x40 //
#define bmJSTATUS 0x80 //
#define bmSE0 0x00 //SE0 - disconnect state
#define bmSE1 0xc0 //SE1 - illegal state
#define MODE_FS_HOST (bmDPPULLDN|bmDMPULLDN|bmHOST|bmSOFKAENAB)
#define MODE_LS_HOST (bmDPPULLDN|bmDMPULLDN|bmHOST|bmLOWSPEED|bmSOFKAENAB)
#endif //_max3421e_h_

View File

@@ -0,0 +1,519 @@
/* Copyright (C) 2015-2016 Andrew J. Kroll
and
Copyright (C) 2011 Circuits At Home, LTD. All rights reserved.
This software may be distributed and modified under the terms of the GNU
General Public License version 2 (GPL2) as published by the Free Software
Foundation and appearing in the file GPL2.TXT included in the packaging of
this file. Please note that GPL2 Section 2[b] requires that all works based
on this software must also be made publicly available under the terms of
the GPL2 ("Copyleft").
Contact information
-------------------
Circuits At Home, LTD
Web : http://www.circuitsathome.com
e-mail : support@circuitsathome.com
*/
#ifndef USB_HOST_SHIELD_H
#define USB_HOST_SHIELD_H
// uncomment to get 'printf' console debugging. NOT FOR UNO!
//#define DEBUG_PRINTF_EXTRA_HUGE_USB_HOST_SHIELD
#ifdef LOAD_USB_HOST_SHIELD
#include "UHS_max3421e.h"
#include <SPI.h>
#ifndef SPI_HAS_TRANSACTION
#error "Your SPI library installation is too old."
#else
#ifndef SPI_ATOMIC_VERSION
#warning "Your SPI library installation lacks 'SPI_ATOMIC_VERSION'. Please complain to the maintainer."
#elif SPI_ATOMIC_VERSION < 1
#error "Your SPI library installation is too old."
#endif
#endif
#if DEBUG_PRINTF_EXTRA_HUGE
#ifdef DEBUG_PRINTF_EXTRA_HUGE_USB_HOST_SHIELD
#define MAX_HOST_DEBUG(...) printf_P(__VA_ARGS__)
#else
#define MAX_HOST_DEBUG(...) VOID0
#endif
#else
#define MAX_HOST_DEBUG(...) VOID0
#endif
#ifndef USB_HOST_SHIELD_USE_ISR
#ifdef USE_MULTIPLE_APP_API
#define USB_HOST_SHIELD_USE_ISR 0
#else
#define USB_HOST_SHIELD_USE_ISR 1
#endif
#else
#define USB_HOST_SHIELD_USE_ISR 1
#endif
#if !USB_HOST_SHIELD_USE_ISR
#error NOISR Polled mode _NOT SUPPORTED YET_
//
// Polled defaults
//
#ifdef BOARD_BLACK_WIDDOW
#define UHS_MAX3421E_SS_ 6
#define UHS_MAX3421E_INT_ 3
#elif defined(CORE_TEENSY) && (defined(__AVR_AT90USB646__) || defined(__AVR_AT90USB1286__))
#if EXT_RAM
// Teensy++ 2.0 with XMEM2
#define UHS_MAX3421E_SS_ 20
#define UHS_MAX3421E_INT_ 7
#else
#define UHS_MAX3421E_SS_ 9
#define UHS_MAX3421E_INT_ 8
#endif
#define UHS_MAX3421E_SPD
#elif defined(ARDUINO_AVR_ADK)
#define UHS_MAX3421E_SS_ 53
#define UHS_MAX3421E_INT_ 54
#elif defined(ARDUINO_AVR_BALANDUINO)
#define UHS_MAX3421E_SS_ 20
#define UHS_MAX3421E_INT_ 19
#else
#define UHS_MAX3421E_SS_ 10
#define UHS_MAX3421E_INT_ 9
#endif
#else
#ifdef ARDUINO_ARCH_PIC32
// PIC32 only allows edge interrupts, isn't that lovely? We'll emulate it...
#if CHANGE < 2
#error core too old.
#endif
#define IRQ_IS_EDGE 0
#ifndef digitalPinToInterrupt
// great, this isn't implemented.
#warning digitalPinToInterrupt is not defined, complain here https://github.com/chipKIT32/chipKIT-core/issues/114
#if defined(_BOARD_UNO_) || defined(_BOARD_UC32_)
#define digitalPinToInterrupt(p) ((p) == 2 ? 1 : ((p) == 7 ? 2 : ((p) == 8 ? 3 : ((p) == 35 ? 4 : ((p) == 38 ? 0 : NOT_AN_INTERRUPT)))))
#warning digitalPinToInterrupt is now defined until this is taken care of.
#else
#error digitalPinToInterrupt not defined for your board, complain here https://github.com/chipKIT32/chipKIT-core/issues/114
#endif
#endif
#else
#define IRQ_IS_EDGE 0
#endif
// More stupidity from our friends @ Sony...
#ifdef ARDUINO_spresense_ast
#ifndef NOT_AN_INTERRUPT
#define NOT_AN_INTERRUPT -1
#endif
#endif
// SAMD uses an enum for this instead of a define. Isn't that just dandy?
#if !defined(NOT_AN_INTERRUPT) && !defined(ARDUINO_ARCH_SAMD)
#warning NOT_AN_INTERRUPT not defined, possible problems ahead.
#warning If NOT_AN_INTERRUPT is an enum or something else, complain to UHS30 developers on github.
#warning Otherwise complain to your board core developer/maintainer.
#define NOT_AN_INTERRUPT -1
#endif
//
// Interrupt defaults. Int0 or Int1
//
#ifdef BOARD_BLACK_WIDDOW
#error "HELP! Please send us an email, I don't know the values for Int0 and Int1 on the Black Widow board!"
#elif defined(ARDUINO_AVR_ADK)
#define UHS_MAX3421E_SS_ 53
#define UHS_MAX3421E_INT_ 54
#elif defined(ARDUINO_spresense_ast)
#define UHS_MAX3421E_SS_ 21
#define UHS_MAX3421E_INT_ 20
#define SPIclass SPI5
//#define UHS_MAX3421E_SPD 100000
#elif defined(CORE_TEENSY) && (defined(__AVR_AT90USB646__) || defined(__AVR_AT90USB1286__))
// TO-DO!
#if EXT_RAM
// Teensy++ 2.0 with XMEM2
#define UHS_MAX3421E_SS_ 20
#define UHS_MAX3421E_INT_ 7
#else
#define UHS_MAX3421E_SS_ 9
#define UHS_MAX3421E_INT_ 8
#endif
#elif defined(ARDUINO_AVR_BALANDUINO)
#error "ISR mode is currently not supported on the Balanduino. Please set USB_HOST_SHIELD_USE_ISR to 0."
#else
#define UHS_MAX3421E_SS_ 10
#ifdef __AVR__
#ifdef __AVR_ATmega32U4__
#define INT_FOR_PIN2 1
#define INT_FOR_PIN3 0
#else
// Everybody else???
#define INT_FOR_PIN2 0
#define INT_FOR_PIN3 1
#endif
#define UHS_MAX3421E_INT_ 3
#else
// Non-avr
#ifdef ARDUINO_ARCH_PIC32
// UNO32 External Interrupts:
// Pin 38 (INT0), Pin 2 (INT1), Pin 7 (INT2), Pin 8 (INT3), Pin 35 (INT4)
#define UHS_MAX3421E_INT_ 7
#else
#define UHS_MAX3421E_INT_ 9
#endif
#endif
#endif
#endif
#ifdef NO_AUTO_SPEED
// Ugly details section...
// MAX3421E characteristics
// SPI Serial - Clock Input. An external SPI master supplies SCLK with frequencies up to 26MHz. The
// logic level is referenced to the voltage on VL. Data is clocked into the SPI slave inter face on the
// rising edge of SCLK. Data is clocked out of the SPI slave interface on the falling edge of SCLK.
// Serial Clock (SCLK) Period 38.4ns minimum. 17ns minimum pulse width. VL >2.5V
// SCLK Fall to MISO Propagation Delay 14.2ns
// SCLK Fall to MOSI Propagation Delay 14.2ns
// SCLK Fall to MOSI Drive 3.5ns
// Theoretical deadline for reply 17.7ns
// 26MHz 38.4615ns period <-- MAX3421E theoretical maximum
#ifndef UHS_MAX3421E_SPD
#ifdef ARDUINO_SAMD_ZERO
// Zero violates spec early, needs a long setup time, or doesn't like high latency.
#define UHS_MAX3421E_SPD 10000000
#elif defined(ARDUINO_ARCH_PIC32)
// PIC MX 5/6/7 characteristics
// 25MHZ 40ns period <-- PIC MX 5/6/7 theoretical maximum
// pulse width minimum Tsclk/2ns
// Trise/fall 10ns maximum. 5ns is typical but not guaranteed.
// Tsetup minimum for MISO 10ns.
// We are in violation by 7.7ns @ 25MHz due to latency alone.
// Even reading at end of data cycle, we only have a 2.3ns window.
// This is too narrow to to compensate for capacitance, trace lengths, and noise.
// 17.7ns + 10ns = 27.7ns
// 18MHz fits and has enough slack time to compensate for capacitance, trace lengths, and noise.
// For high speeds the SMP bit is recommended too, which samples at the end instead of the middle.
// 20Mhz seems to work.
#define UHS_MAX3421E_SPD 20000000
#else
#define UHS_MAX3421E_SPD 25000000
#endif
#endif
#else
// We start at 25MHz, and back down until hardware can take it.
// Of course, SPI library can adjust this for us too.
// Why not 26MHz? Because I have not found any MCU board that
// can actually go that fast without problems.
// Could be a shield limitation too.
#ifndef UHS_MAX3421E_SPD
#define UHS_MAX3421E_SPD 25000000
#endif
#endif
#ifndef UHS_MAX3421E_INT
#define UHS_MAX3421E_INT UHS_MAX3421E_INT_
#endif
#ifndef UHS_MAX3421E_SS
#define UHS_MAX3421E_SS UHS_MAX3421E_SS_
#endif
// NOTE: On the max3421e the irq enable and irq bits are in the same position.
// IRQs used if CPU polls
#define ENIBITSPOLLED (bmCONDETIE | bmBUSEVENTIE | bmFRAMEIE)
// IRQs used if CPU is interrupted
#define ENIBITSISR (bmCONDETIE | bmBUSEVENTIE | bmFRAMEIE /* | bmRCVDAVIRQ | bmSNDBAVIRQ | bmHXFRDNIRQ */ )
#if !USB_HOST_SHIELD_USE_ISR
#define IRQ_CHECK_MASK (ENIBITSPOLLED & ICLRALLBITS)
#define IRQ_IS_EDGE 0
#else
#define IRQ_CHECK_MASK (ENIBITSISR & ICLRALLBITS)
#endif
#if IRQ_IS_EDGE
// Note: UNO32 Interrupts can only be RISING, or FALLING.
// This poses an interesting problem, since we want to use a LOW level.
// The MAX3421E provides for pulse width control for an IRQ.
// We do need to watch the timing on this, as a second IRQ could cause
// a missed IRQ, since we read the level of the line to check if the IRQ
// is actually for this chip. The only other alternative is to add a capacitor
// and an NPN transistor, and use two lines. We can try this first, though.
// Worse case, we can ignore reading the pin for verification on UNO32.
// Too bad there is no minimum low width setting.
//
// Single Clear First Second Clear first Clear last
// IRQ Single IRQ IRQ Second active pending IRQ
// | | | | | |
// V V V V V V
// _____ _________ _ _ _______
// |______| |______| |______| |______________|
//
#define IRQ_SENSE FALLING
#ifdef ARDUINO_ARCH_PIC32
//#define bmPULSEWIDTH PUSLEWIDTH10_6
#define bmPULSEWIDTH 0
#define bmIRQ_SENSE 0
#else
#define bmPULSEWIDTH PUSLEWIDTH1_3
#define bmIRQ_SENSE 0
#endif
#else
#ifndef IRQ_SENSE
#define IRQ_SENSE LOW
#endif
#ifndef bmPULSEWIDTH
#define bmPULSEWIDTH 0
#endif
#ifndef bmIRQ_SENSE
#define bmIRQ_SENSE bmINTLEVEL
#endif
#endif
class MAX3421E_HOST :
public UHS_USB_HOST_BASE
#ifdef SWI_IRQ_NUM
, public dyn_SWI
#endif
{
// TO-DO: move these into the parent class.
volatile uint8_t vbusState;
volatile uint16_t sof_countdown;
// TO-DO: pack into a struct/union and use one byte
volatile bool busevent;
volatile bool sofevent;
volatile bool counted;
volatile bool condet;
volatile bool doingreset;
#ifdef USB_HOST_MANUAL_POLL
volatile bool frame_irq_enabled = false;
bool enable_frame_irq(bool enable) {
const bool prev_state = frame_irq_enabled;
if(prev_state != enable) {
if(enable)
regWr(rHIEN, regRd(rHIEN) | bmFRAMEIE);
else
regWr(rHIEN, regRd(rHIEN) & ~bmFRAMEIE);
frame_irq_enabled = enable;
}
return prev_state;
}
#endif
public:
SPISettings MAX3421E_SPI_Settings;
uint8_t ss_pin;
uint8_t irq_pin;
// Will use the defaults UHS_MAX3421E_SS, UHS_MAX3421E_INT and speed
UHS_NI MAX3421E_HOST() {
sof_countdown = 0;
busevent = false;
doingreset = false;
sofevent = false;
condet = false;
ss_pin = UHS_MAX3421E_SS;
irq_pin = UHS_MAX3421E_INT;
MAX3421E_SPI_Settings = SPISettings(UHS_MAX3421E_SPD, MSBFIRST, SPI_MODE0);
hub_present = 0;
};
// Will use user supplied pins, and UHS_MAX3421E_SPD
UHS_NI MAX3421E_HOST(uint8_t pss, uint8_t pirq) {
sof_countdown = 0;
busevent = false;
doingreset = false;
sofevent = false;
condet = false;
ss_pin = pss;
irq_pin = pirq;
MAX3421E_SPI_Settings = SPISettings(UHS_MAX3421E_SPD, MSBFIRST, SPI_MODE0);
hub_present = 0;
};
// Will use user supplied pins, and speed
UHS_NI MAX3421E_HOST(uint8_t pss, uint8_t pirq, uint32_t pspd) {
sof_countdown = 0;
doingreset = false;
busevent = false;
sofevent = false;
condet = false;
ss_pin = pss;
irq_pin = pirq;
MAX3421E_SPI_Settings = SPISettings(pspd, MSBFIRST, SPI_MODE0);
hub_present = 0;
};
virtual bool UHS_NI sof_delay(uint16_t x) {
#ifdef USB_HOST_MANUAL_POLL
const bool saved_irq_state = enable_frame_irq(true);
#endif
sof_countdown = x;
while((sof_countdown != 0) && !condet) {
SYSTEM_OR_SPECIAL_YIELD();
#if !USB_HOST_SHIELD_USE_ISR
Task();
#endif
}
#ifdef USB_HOST_MANUAL_POLL
enable_frame_irq(saved_irq_state);
#endif
// Serial.println("...Wake");
return (!condet);
};
virtual UHS_EpInfo *ctrlReqOpen(uint8_t addr, uint64_t Request, uint8_t* dataptr);
virtual void UHS_NI vbusPower(VBUS_t state) {
regWr(rPINCTL, (bmFDUPSPI | bmIRQ_SENSE) | (uint8_t)(state));
};
void UHS_NI Task();
virtual uint8_t SetAddress(uint8_t addr, uint8_t ep, UHS_EpInfo **ppep, uint16_t &nak_limit);
virtual uint8_t OutTransfer(UHS_EpInfo *pep, uint16_t nak_limit, uint16_t nbytes, uint8_t *data);
virtual uint8_t InTransfer(UHS_EpInfo *pep, uint16_t nak_limit, uint16_t *nbytesptr, uint8_t *data);
virtual uint8_t ctrlReqClose(UHS_EpInfo *pep, uint8_t bmReqType, uint16_t left, uint16_t nbytes, uint8_t *dataptr);
virtual uint8_t ctrlReqRead(UHS_EpInfo *pep, uint16_t *left, uint16_t *read, uint16_t nbytes, uint8_t *dataptr);
virtual uint8_t dispatchPkt(uint8_t token, uint8_t ep, uint16_t nak_limit);
void UHS_NI ReleaseChildren() {
for(uint8_t i = 0; i < UHS_HOST_MAX_INTERFACE_DRIVERS; i++)
if(devConfig[i])
devConfig[i]->Release();
hub_present = 0;
};
virtual bool IsHub(uint8_t klass) {
if(klass == UHS_USB_CLASS_HUB) {
hub_present = bmHUBPRE;
return true;
}
return false;
};
virtual void VBUS_changed();
virtual void UHS_NI doHostReset() {
#if USB_HOST_SHIELD_USE_ISR
// Enable interrupts
noInterrupts();
#endif
doingreset = true;
busevent = true;
regWr(rHIRQ, bmBUSEVENTIRQ); // see data sheet.
regWr(rHCTL, bmBUSRST); //issue bus reset
#if USB_HOST_SHIELD_USE_ISR
DDSB();
// Enable interrupts
interrupts();
#endif
while(busevent) {
DDSB();
SYSTEM_OR_SPECIAL_YIELD();
}
#endif
#if USB_HOST_SHIELD_USE_ISR
// Enable interrupts
noInterrupts();
#endif
#ifdef USB_HOST_MANUAL_POLL
enable_frame_irq(true);
#endif
sofevent = true;
#if USB_HOST_SHIELD_USE_ISR
DDSB();
// Enable interrupts
interrupts();
#endif
// Wait for SOF
while(sofevent) {
}
#if USB_HOST_SHIELD_USE_ISR
// Enable interrupts
noInterrupts();
#endif
doingreset = false;
#if USB_HOST_SHIELD_USE_ISR
DDSB();
// Enable interrupts
interrupts();
};
int16_t UHS_NI Init(int16_t mseconds);
int16_t UHS_NI Init() {
return Init(INT16_MIN);
};
void ISRTask();
void ISRbottom();
void busprobe();
uint16_t reset();
// MAX3421e specific
void regWr(uint8_t reg, uint8_t data);
void gpioWr(uint8_t data);
uint8_t regRd(uint8_t reg);
uint8_t gpioRd();
uint8_t* bytesWr(uint8_t reg, uint8_t nbytes, uint8_t* data_p);
uint8_t* bytesRd(uint8_t reg, uint8_t nbytes, uint8_t* data_p);
// ARM/NVIC specific, used to emulate reentrant ISR.
#ifdef SWI_IRQ_NUM
void dyn_SWISR() {
ISRbottom();
};
#endif
virtual void UHS_NI suspend_host() {
// Used on MCU that lack control of IRQ priority (AVR).
// Suspends ISRs, for critical code. IRQ will be serviced after it is resumed.
// NOTE: you must track the state yourself!
#ifdef __AVR__
noInterrupts();
detachInterrupt(UHS_GET_DPI(irq_pin));
interrupts();
#endif
};
virtual void UHS_NI resume_host();
};
#ifndef SPIclass
#define SPIclass SPI
#endif
#ifndef USB_HOST_SHIELD_LOADED
#include "USB_HOST_SHIELD_INLINE.h"
#endif
#else
#error "define LOAD_USB_HOST_SHIELD in your sketch, never include USB_HOST_SHIELD.h in a driver."
#endif
#endif /* USB_HOST_SHIELD_H */

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,153 @@
/*
* File: macro_logic.h
* Author: root
*
* Created on December 22, 2018, 4:49 AM
*
* To test:
* gcc -DAJK_TEST_MACRO_LOGIC -E macro_logic.h
*
*/
#ifndef MACRO_LOGIC_H
#define MACRO_LOGIC_H
#define AJK_CAT(a, ...) AJK_PRIMITIVE_CAT(a, __VA_ARGS__)
#define AJK_PRIMITIVE_CAT(a, ...) a ## __VA_ARGS__
#define AJK_COMPL(b) AJK_PRIMITIVE_CAT(AJK_COMPL_, b)
#define AJK_COMPL_0 1
#define AJK_COMPL_1 0
#define AJK_BITAND(x) AJK_PRIMITIVE_CAT(AJK_BITAND_, x)
#define AJK_BITAND_0(y) 0
#define AJK_BITAND_1(y) y
#define AJK_INC(x) AJK_PRIMITIVE_CAT(AJK_INC_, x)
#define AJK_INC_0 1
#define AJK_INC_1 2
#define AJK_INC_2 3
#define AJK_INC_3 4
#define AJK_INC_4 5
#define AJK_INC_5 6
#define AJK_INC_6 7
#define AJK_INC_7 8
#define AJK_INC_8 9
#define AJK_INC_9 10
#define AJK_INC_10 10
#define AJK_DEC(x) AJK_PRIMITIVE_CAT(AJK_DEC_, x)
#define AJK_DEC_0 0
#define AJK_DEC_1 0
#define AJK_DEC_2 1
#define AJK_DEC_3 2
#define AJK_DEC_4 3
#define AJK_DEC_5 4
#define AJK_DEC_6 5
#define AJK_DEC_7 6
#define AJK_DEC_8 7
#define AJK_DEC_9 8
#define AJK_DEC_10 9
#define AJK_CHECK_N(x, n, ...) n
#define AJK_CHECK(...) AJK_CHECK_N(__VA_ARGS__, 0,)
#define AJK_PROBE(x) x, 1,
#define AJK_IS_PAREN(x) AJK_CHECK(AJK_IS_PAREN_PROBE x)
#define AJK_IS_PAREN_PROBE(...) AJK_PROBE(~)
#define AJK_NOT(x) AJK_CHECK(AJK_PRIMITIVE_CAT(AJK_NOT_, x))
#define AJK_NOT_0 AJK_PROBE(~)
#define AJK_COMPL(b) AJK_PRIMITIVE_CAT(AJK_COMPL_, b)
#define AJK_COMPL_0 1
#define AJK_COMPL_1 0
#define AJK_BOOL(x) AJK_COMPL(AJK_NOT(x))
#define AJK_IIF(c) AJK_PRIMITIVE_CAT(AJK_IIF_, c)
#define AJK_IIF_0(t, ...) __VA_ARGS__
#define AJK_IIF_1(t, ...) t
#define AJK_IF(c) AJK_IIF(AJK_BOOL(c))
#define AJK_EAT(...)
#define AJK_EXPAND(...) __VA_ARGS__
#define AJK_WHEN(c) AJK_IF(c)(AJK_EXPAND, AJK_EAT)
#define AJK_EMPTY()
#define AJK_DEFER(id) id AJK_EMPTY()
#define AJK_OBSTRUCT(id) id AJK_DEFER(AJK_EMPTY)()
#define AJK_EVAL(...) AJK_EVAL1(AJK_EVAL1(AJK_EVAL1(__VA_ARGS__)))
#define AJK_EVAL1(...) AJK_EVAL2(AJK_EVAL2(AJK_EVAL2(__VA_ARGS__)))
#define AJK_EVAL2(...) AJK_EVAL3(AJK_EVAL3(AJK_EVAL3(__VA_ARGS__)))
#define AJK_EVAL3(...) AJK_EVAL4(AJK_EVAL4(AJK_EVAL4(__VA_ARGS__)))
#define AJK_EVAL4(...) AJK_EVAL5(AJK_EVAL5(AJK_EVAL5(__VA_ARGS__)))
#define AJK_EVAL5(...) __VA_ARGS__
#define AJK_REPEAT(AJK_count, AJK_macro, ...) \
AJK_WHEN(AJK_count) \
( \
AJK_OBSTRUCT(AJK_REPEAT_INDIRECT) () \
( \
AJK_DEC(AJK_count), AJK_macro, __VA_ARGS__ \
) \
AJK_OBSTRUCT(AJK_macro) \
( \
AJK_DEC(AJK_count), __VA_ARGS__ \
) \
)
#define AJK_REPEAT_INDIRECT() AJK_REPEAT
#define AJK_WHILE(AJK_pred, AJK_op, ...) \
IF(AJK_pred(__VA_ARGS__)) \
( \
AJK_OBSTRUCT(AJK_WHILE_INDIRECT) () \
( \
AJK_pred, AJK_op, AJK_op(__VA_ARGS__) \
), \
__VA_ARGS__ \
)
#define AJK_WHILE_INDIRECT() AJK_WHILE
#define AJK_PRIMITIVE_COMPARE(x, y) AJK_IS_PAREN \
( \
AJK_COMPARE_ ## x ( AJK_COMPARE_ ## y) (()) \
)
#define AJK_IS_COMPARABLE(x) AJK_IS_PAREN( AJK_CAT(AJK_COMPARE_, x) (()) )
#define AJK_NOT_EQUAL(x, y) \
AJK_IIF(AJK_BITAND(AJK_IS_COMPARABLE(x))(AJK_IS_COMPARABLE(y)) ) \
( \
AJK_PRIMITIVE_COMPARE, \
1 AJK_EAT \
)(x, y)
#define AJK_EQUAL(x, y) AJK_COMPL(AJK_NOT_EQUAL(x, y))
#define AJK_COMMA() ,
#define AJK_COMMA_IF(n) AJK_IF(n)(AJK_COMMA, AJK_EAT)()
#define AJK_COMMA_VAR(AJK_count, AJK_v) AJK_COMMA_IF(AJK_count) AJK_v ## AJK_count
#define AJK_MAKE_LIST(AJK_v, AJK_count) AJK_EVAL(AJK_REPEAT(AJK_count, AJK_COMMA_VAR, AJK_v))
#define AJK_FUN(AJK_count, AJK_v, AJK_args, AJK_body) AJK_v ## AJK_count (AJK_args) { AJK_body(AJK_count) }
#define AJK_MAKE_FUNS(AJK_v, AJK_args, AJK_count, AJK_body) AJK_EVAL(AJK_REPEAT(AJK_count, AJK_FUN, AJK_v, AJK_args, AJK_body))
#ifdef AJK_TEST_MACRO_LOGIC
#define BODY(AJKindex) some(C, statement); contaning(a, test[AJKindex]);
#define ZERO_TIMES_TEST 0
#define THREE_TIMES_TEST 3
blank > AJK_MAKE_LIST(VARIABLE_, ZERO_TIMES_TEST) < because zero repeats
Make 3 comma separated indexed variables : AJK_MAKE_LIST(VARIABLE_, THREE_TIMES_TEST)
Make 3 bogus function bodies
AJK_MAKE_FUNS(unsigned Cfunc,(arg1, arg2),3,BODY)
#endif
#endif /* MACRO_LOGIC_H */

View File

@@ -0,0 +1,246 @@
/*
* File: SWI_INLINE.h
* Author: xxxajk@gmail.com
*
* Created on December 5, 2014, 9:40 AM
*
* This is the actual library.
* There are no 'c' or 'cpp' files.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifdef DYN_SWI_H
#ifndef SWI_INLINE_H
#define SWI_INLINE_H
#ifndef SWI_MAXIMUM_ALLOWED
#define SWI_MAXIMUM_ALLOWED 4
#endif
#if defined(__arm__) || defined(ARDUINO_ARCH_PIC32)
static char dyn_SWI_initied = 0;
static dyn_SWI* dyn_SWI_LIST[SWI_MAXIMUM_ALLOWED];
static dyn_SWI* dyn_SWI_EXEC[SWI_MAXIMUM_ALLOWED];
#ifdef __arm__
#ifdef __USE_CMSIS_VECTORS__
extern "C" {
void (*_VectorsRam[VECTORTABLE_SIZE])(void)__attribute__((aligned(VECTORTABLE_ALIGNMENT)));
}
#else
__attribute__((always_inline)) static inline void __DSB() {
__asm__ volatile ("dsb");
}
#endif // defined(__USE_CMSIS_VECTORS__)
#else // defined(__arm__)
__attribute__((always_inline)) static inline void __DSB() {
__asm__ volatile ("sync" : : : "memory");
}
#endif // defined(__arm__)
/**
* Execute queued class ISR routines.
*/
#ifdef ARDUINO_ARCH_PIC32
static p32_regset *ifs = ((p32_regset *) & IFS0) + (SWI_IRQ_NUM / 32); //interrupt flag register set
static p32_regset *iec = ((p32_regset *) & IEC0) + (SWI_IRQ_NUM / 32); //interrupt enable control reg set
static uint32_t swibit = 1 << (SWI_IRQ_NUM % 32);
void
#ifdef __PIC32MZXX__
__attribute__((nomips16,at_vector(SWI_VECTOR),interrupt(SWI_IPL)))
#else
__attribute__((interrupt(),nomips16))
#endif
softISR() {
#else
#ifdef ARDUINO_spresense_ast
unsigned int softISR() {
#else
void softISR() {
#endif
#endif
//
// TO-DO: Perhaps limit to 8, and inline this?
//
// Make a working copy, while clearing the queue.
noInterrupts();
#ifdef ARDUINO_ARCH_PIC32
//ifs->clr = swibit;
#endif
for(int i = 0; i < SWI_MAXIMUM_ALLOWED; i++) {
dyn_SWI_EXEC[i] = dyn_SWI_LIST[i];
dyn_SWI_LIST[i] = NULL;
}
__DSB();
interrupts();
// Execute each class SWI
for(int i = 0; i < SWI_MAXIMUM_ALLOWED; i++) {
if(dyn_SWI_EXEC[i]) {
#ifdef __DYN_SWI_DEBUG_LED__
digitalWrite(__DYN_SWI_DEBUG_LED__, HIGH);
#endif
dyn_SWI_EXEC[i]->dyn_SWISR();
#ifdef __DYN_SWI_DEBUG_LED__
digitalWrite(__DYN_SWI_DEBUG_LED__, LOW);
#endif
}
}
#ifdef ARDUINO_ARCH_PIC32
noInterrupts();
if(!dyn_SWI_EXEC[0]) ifs->clr = swibit;
interrupts();
#endif
#ifdef ARDUINO_spresense_ast
return 0;
#endif
}
#define DDSB() __DSB()
#endif
#ifdef __arm__
#ifndef interruptsStatus
#define interruptsStatus() __interruptsStatus()
static inline unsigned char __interruptsStatus() __attribute__((always_inline, unused));
static inline unsigned char __interruptsStatus() {
unsigned int primask;
asm volatile ("mrs %0, primask" : "=r" (primask));
if(primask) return 0;
return 1;
}
#endif
/**
* Initialize the Dynamic (class) Software Interrupt
*/
static void Init_dyn_SWI() {
if(!dyn_SWI_initied) {
#ifdef __USE_CMSIS_VECTORS__
uint32_t *X_Vectors = (uint32_t*)SCB->VTOR;
for(int i = 0; i < VECTORTABLE_SIZE; i++) {
_VectorsRam[i] = reinterpret_cast<void (*)()>(X_Vectors[i]); /* copy vector table to RAM */
}
/* relocate vector table */
noInterrupts();
SCB->VTOR = reinterpret_cast<uint32_t>(&_VectorsRam);
DDSB();
interrupts();
#endif
#ifndef ARDUINO_spresense_ast
for(int i = 0; i < SWI_MAXIMUM_ALLOWED; i++) dyn_SWI_LIST[i] = NULL;
noInterrupts();
_VectorsRam[SWI_IRQ_NUM + 16] = reinterpret_cast<void (*)()>(softISR);
DDSB();
interrupts();
NVIC_SET_PRIORITY(SWI_IRQ_NUM, 255);
NVIC_ENABLE_IRQ(SWI_IRQ_NUM);
#endif
#ifdef __DYN_SWI_DEBUG_LED__
pinMode(__DYN_SWI_DEBUG_LED__, OUTPUT);
digitalWrite(__DYN_SWI_DEBUG_LED__, LOW);
#endif
dyn_SWI_initied = 1;
}
}
/**
*
* @param klass class that extends dyn_SWI
* @return 0 on queue full, else returns queue position (ones based)
*/
int exec_SWI(const dyn_SWI* klass) {
int rc = 0;
uint8_t irestore = interruptsStatus();
// Allow use from inside a critical section...
// ... and prevent races if also used inside an ISR
noInterrupts();
for(int i = 0; i < SWI_MAXIMUM_ALLOWED; i++) {
if(!dyn_SWI_LIST[i]) {
rc = 1 + i; // Success!
dyn_SWI_LIST[i] = (dyn_SWI*)klass;
#ifndef ARDUINO_spresense_ast
if(!NVIC_GET_PENDING(SWI_IRQ_NUM)) NVIC_SET_PENDING(SWI_IRQ_NUM);
#else
// Launch 1-shot timer as an emulated SWI
// Hopefully the value of Zero is legal.
// 1 microsecond latency would suck!
attachTimerInterrupt(softISR, 100);
#endif
DDSB();
break;
}
}
// Restore interrupts, if they were on.
if(irestore) interrupts();
return rc;
}
#elif defined(ARDUINO_ARCH_PIC32)
/**
* Initialize the Dynamic (class) Software Interrupt
*/
static void Init_dyn_SWI() {
if(!dyn_SWI_initied) {
uint32_t sreg = disableInterrupts();
setIntVector(SWI_VECTOR, softISR);
setIntPriority(SWI_VECTOR, 1, 1); // Lowest priority, ever.
ifs->clr = swibit;
iec->clr = swibit;
iec->set = swibit;
restoreInterrupts(sreg);
#ifdef __DYN_SWI_DEBUG_LED__
pinMode(__DYN_SWI_DEBUG_LED__, OUTPUT);
UHS_PIN_WRITE(__DYN_SWI_DEBUG_LED__, LOW);
#endif
}
}
/**
*
* @param klass class that extends dyn_SWI
* @return 0 on queue full, else returns queue position (ones based)
*/
int exec_SWI(const dyn_SWI* klass) {
int rc = 0;
uint32_t sreg = disableInterrupts();
for(int i = 0; i < SWI_MAXIMUM_ALLOWED; i++) {
if(!dyn_SWI_LIST[i]) {
rc = 1 + i; // Success!
dyn_SWI_LIST[i] = (dyn_SWI*)klass;
if(!(ifs->reg & swibit)) ifs->set = swibit;
;
break;
}
}
restoreInterrupts(sreg);
return rc;
}
#endif /* defined(__arm__) */
#endif /* SWI_INLINE_H */
#else
#error "Never include SWI_INLINE.h directly, include dyn_SWI.h instead"
#endif

View File

@@ -0,0 +1,172 @@
/*
* File: dyn_SWI.h
* Author: xxxajk@gmail.com
*
* Created on December 5, 2014, 9:12 AM
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef DYN_SWI_H
#define DYN_SWI_H
#if defined(__arm__) || defined(ARDUINO_ARCH_PIC32)
#ifdef ARDUINO_ARCH_PIC32
#include <p32xxxx.h>
#endif
#ifdef __cplusplus
#ifdef true
#undef true
#endif
#ifdef false
#undef false
#endif
#endif
#ifdef ARDUINO_spresense_ast
#define SWI_IRQ_NUM 666 // because this board is totally evil.
#elif defined(ARDUINO_ARCH_PIC32)
#ifndef SWI_IRQ_NUM
#ifdef _DSPI0_IPL_ISR
#define SWI_IPL _DSPI0_IPL_ISR
#define SWI_VECTOR _DSPI0_ERR_IRQ
#define SWI_IRQ_NUM _DSPI0_ERR_IRQ
#elif defined(_PMP_ERROR_IRQ)
#define SWI_IRQ_NUM _PMP_ERROR_IRQ
#define SWI_VECTOR _PMP_VECTOR
#else
#error SWI_IRQ_NUM and SWI_VECTOR need a definition
#endif
#ifdef __cplusplus
extern "C"
{
void
#ifdef __PIC32MZXX__
__attribute__((nomips16,at_vector(SWI_VECTOR),interrupt(SWI_IPL)))
#else
__attribute__((interrupt(),nomips16))
#endif
softISR();
}
#endif
#endif
#elif !defined(NVIC_NUM_INTERRUPTS)
// Assume CMSIS
#define __USE_CMSIS_VECTORS__
#ifdef NUMBER_OF_INT_VECTORS
#define NVIC_NUM_INTERRUPTS (NUMBER_OF_INT_VECTORS-16)
#else
#define NVIC_NUM_INTERRUPTS ((int)PERIPH_COUNT_IRQn)
#endif
#define VECTORTABLE_SIZE (NVIC_NUM_INTERRUPTS+16)
#define VECTORTABLE_ALIGNMENT (0x100ul)
#define NVIC_GET_ACTIVE(n) NVIC_GetActive((IRQn_Type)n)
#define NVIC_GET_PENDING(n) NVIC_GetPendingIRQ((IRQn_Type)n)
#define NVIC_SET_PENDING(n) NVIC_SetPendingIRQ((IRQn_Type)n)
#define NVIC_ENABLE_IRQ(n) NVIC_EnableIRQ((IRQn_Type)n)
#define NVIC_SET_PRIORITY(n ,p) NVIC_SetPriority((IRQn_Type)n, (uint32_t) p)
//extern "C" {
// extern uint32_t _VectorsRam[VECTORTABLE_SIZE] __attribute__((aligned(VECTORTABLE_ALIGNMENT)));
//}
#ifndef SWI_IRQ_NUM
#if defined(__SAM3X8E__) && defined(_VARIANT_ARDUINO_DUE_X_)
// DUE
// Choices available:
// HSMCI_IRQn Multimedia Card Interface (HSMCI)
// EMAC_IRQn Ethernet MAC (EMAC)
// EMAC is not broken out on the official DUE, but is on clones.
// SPI0_IRQn Serial Peripheral Interface (SPI0)
// SPI0_IRQn seems to be the best choice, as long as nobody uses an ISR based master
#define SWI_IRQ_NUM SPI0_IRQn
#elif defined(ARDUINO_SAMD_ZERO)
// Just use sercom4's unused IRQ vector.
#define SWI_IRQ_NUM I2S_IRQn
//#define SWI_IRQ_NUM SERCOM4_IRQn
#endif
#endif
#ifndef SWI_IRQ_NUM
#error SWI_IRQ_NUM not defined (CMSIS)
#endif
#elif defined(CORE_TEENSY)
#ifndef NVIC_GET_ACTIVE
#define NVIC_GET_ACTIVE(n) (*((volatile uint32_t *)0xE000E300 + ((n) >> 5)) & (1 << ((n) & 31)))
#endif
#ifndef NVIC_GET_PENDING
#define NVIC_GET_PENDING(n) (*((volatile uint32_t *)0xE000E200 + ((n) >> 5)) & (1 << ((n) & 31)))
#ifndef SWI_IRQ_NUM
#ifdef __MK20DX256__
#define SWI_IRQ_NUM 17
#elif defined(__MK20DX128__)
#define SWI_IRQ_NUM 5
#elif defined(__MKL26Z64__)
#define SWI_IRQ_NUM 4
#elif defined(__MK66FX1M0__)
#define SWI_IRQ_NUM 30
#elif defined(__MK64FX512__)
#define SWI_IRQ_NUM 30
#elif defined(__IMXRT1052__) || defined(__IMXRT1062__)
#define SWI_IRQ_NUM 71
#else
#error Do not know how to relocate IRQ vectors for this pjrc product
#endif
#endif
#endif
#else // Not CMSIS or PJRC CORE_TEENSY or PIC32 or SPRESENSE
#error Do not know how to relocate IRQ vectors or perform SWI
#endif // SWI_IRQ_NUM
#ifndef SWI_IRQ_NUM
#error SWI_IRQ_NUM not defined
#else
/**
* Use this class to extend your class, in order to provide
* a C++ context callable SWI.
*/
class dyn_SWI {
public:
/**
* Override this method with your code.
*/
virtual void dyn_SWISR() {
};
};
extern int exec_SWI(const dyn_SWI* klass);
#include "SWI_INLINE.h"
// IMPORTANT! Define this so that you do NOT end up with a NULL stub!
#define SWI_NO_STUB
#endif /* SWI_IRQ_NUM */
#endif /* __arm__ */
// if no SWI for CPU (e.g. AVR) make a void stub.
#ifndef SWI_NO_STUB
#define Init_dyn_SWI() (void(0))
#ifndef DDSB
#define DDSB() (void(0))
#endif
#endif
#endif /* DYN_SWI_H */