/* Copyright (C) 2011 Circuits At Home, LTD. All rights reserved. This software may be distributed and modified under the terms of the GNU General Public License version 2 (GPL2) as published by the Free Software Foundation and appearing in the file GPL2.TXT included in the packaging of this file. Please note that GPL2 Section 2[b] requires that all works based on this software must also be made publicly available under the terms of the GPL2 ("Copyleft"). Contact information ------------------- Circuits At Home, LTD Web : http://www.circuitsathome.com e-mail : support@circuitsathome.com */ #if !defined(__ADDRESS_H__) #define __ADDRESS_H__ #include #include #include "max3421e.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 }; }; }; // 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 zerro }; uint8_t devAddress; }; }; #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 uint8_t address; // address uint8_t epcount; // number of endpoints bool lowspeed; // indicates if a device is the low speed one // uint8_t devclass; // device class }; 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 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 = 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) ? 1 : start; ibmParent == addr.bmAddress) return i; } return 0; }; // Frees address entry specified by index parameter void FreeAddressByIndex(uint8_t index) { // Zerro field is reserved and should not be affected if (index == 0) return; // If a hub was switched off all port addresses should be freed if (((UsbDeviceAddress*)&thePool[index].address)->bmHub == 1) { for (uint8_t i=1; i = FindChildIndex(*((UsbDeviceAddress*)&thePool[index].address), i); ) FreeAddressByIndex(i); // If the hub had the last allocated address, hubCounter should be decremented if (hubCounter == ((UsbDeviceAddress*)&thePool[index].address)->bmAddress) hubCounter --; } InitEntry(index); } // Initializes the whole address pool at once void InitAllAddresses() { for (uint8_t i=1; i 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 == 0) { if (is_hub) { thePool[index].address = 0x41; hubCounter ++; } else thePool[index].address = 1; return thePool[index].address; } UsbDeviceAddress addr; addr.bmParent = ((UsbDeviceAddress*)&parent)->bmAddress; if (is_hub) { addr.bmHub = 1; addr.bmAddress = ++hubCounter; } else { addr.bmHub = 0; addr.bmAddress = port; } thePool[index].address = *((uint8_t*)&addr); /* Serial.print("Addr:"); Serial.print(addr.bmHub, HEX); Serial.print("."); Serial.print(addr.bmParent, HEX); Serial.print("."); Serial.println(addr.bmAddress, HEX); */ return thePool[index].address; }; // 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