aboutsummaryrefslogtreecommitdiff
path: root/Marlin/src/sd/usb_flashdrive/lib-uhs2/address.h
diff options
context:
space:
mode:
authorGeorgiy Bondarenko <69736697+nehilo@users.noreply.github.com>2021-03-04 20:54:23 +0300
committerGeorgiy Bondarenko <69736697+nehilo@users.noreply.github.com>2021-03-04 20:54:23 +0300
commite8701195e66f2d27ffe17fb514eae8173795aaf7 (patch)
tree9f519c4abf6556b9ae7190a6210d87ead1dfadde /Marlin/src/sd/usb_flashdrive/lib-uhs2/address.h
downloadkp3s-lgvl-e8701195e66f2d27ffe17fb514eae8173795aaf7.tar.xz
kp3s-lgvl-e8701195e66f2d27ffe17fb514eae8173795aaf7.zip
Initial commit
Diffstat (limited to 'Marlin/src/sd/usb_flashdrive/lib-uhs2/address.h')
-rw-r--r--Marlin/src/sd/usb_flashdrive/lib-uhs2/address.h271
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;
+ //}
+};