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