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