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