Zoltan Hudak / UsbHostMAX3421E

Dependents:   UsbHostMAX3421E_Hello

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers address.h Source File

address.h

00001 /* Copyright (C) 2011 Circuits At Home, LTD. All rights reserved.
00002 
00003 This program is free software; you can redistribute it and/or modify
00004 it under the terms of the GNU General Public License as published by
00005 the Free Software Foundation; either version 2 of the License, or
00006 (at your option) any later version.
00007 
00008 This program is distributed in the hope that it will be useful,
00009 but WITHOUT ANY WARRANTY; without even the implied warranty of
00010 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00011 GNU General Public License for more details.
00012 
00013 You should have received a copy of the GNU General Public License
00014 along with this program; if not, write to the Free Software
00015 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00016 
00017 Contact information
00018 -------------------
00019 
00020 Circuits At Home, LTD
00021 Web      :  http://www.circuitsathome.com
00022 e-mail   :  support@circuitsathome.com
00023  */
00024 #ifndef __ADDRESS_H__
00025 #define __ADDRESS_H__
00026 
00027 /* NAK powers. To save space in endpoint data structure, amount of retries before giving up and returning 0x4 is stored in */
00028 
00029 /* bmNakPower as a power of 2. The actual nak_limit is then calculated as nak_limit = ( 2^bmNakPower - 1) */
00030 #define USB_NAK_MAX_POWER   15          //NAK binary order maximum value
00031 #define USB_NAK_DEFAULT     14          //default 32K-1 NAKs before giving up
00032 #define USB_NAK_NOWAIT      1           //Single NAK stops transfer
00033 #define USB_NAK_NONAK       0           //Do not count NAKs, stop retrying after USB Timeout
00034 struct EpInfo
00035 {
00036     uint8_t epAddr;                     // Endpoint address
00037     uint8_t maxPktSize;                 // Maximum packet size
00038 
00039     union
00040     {
00041         uint8_t epAttribs;
00042 
00043         struct
00044         {
00045             uint8_t bmSndToggle : 1;    // Send toggle, when zero bmSNDTOG0, bmSNDTOG1 otherwise
00046             uint8_t bmRcvToggle : 1;    // Send toggle, when zero bmRCVTOG0, bmRCVTOG1 otherwise
00047             uint8_t bmNakPower : 6;     // Binary order for NAK_LIMIT value
00048         } __attribute__((packed));
00049     };
00050 }
00051 __attribute__((packed));
00052 
00053 //        7   6   5   4   3   2   1   0
00054 //  ---------------------------------
00055 //  |   | H | P | P | P | A | A | A |
00056 //  ---------------------------------
00057 //
00058 // H - if 1 the address is a hub address
00059 // P - parent hub address
00060 // A - device address / port number in case of hub
00061 //
00062 struct UsbDeviceAddress
00063 {
00064     union
00065     {
00066         struct
00067         {
00068             uint8_t bmAddress : 3;  // device address/port number
00069             uint8_t bmParent : 3;   // parent hub address
00070             uint8_t bmHub : 1;      // hub flag
00071             uint8_t bmReserved : 1; // reserved, must be zero
00072         } __attribute__((packed));
00073         uint8_t devAddress;
00074     };
00075 }   __attribute__((packed));
00076 
00077 #define bmUSB_DEV_ADDR_ADDRESS  0x07
00078 #define bmUSB_DEV_ADDR_PARENT   0x38
00079 #define bmUSB_DEV_ADDR_HUB      0x40
00080 
00081 struct UsbDevice
00082 {
00083     EpInfo*             epinfo;     // endpoint info pointer
00084     UsbDeviceAddress    address;
00085     uint8_t             epcount;    // number of endpoints
00086     bool                lowspeed;   // indicates if a device is the low speed one
00087 }       __attribute__((packed));
00088 
00089 class   AddressPool
00090 {
00091 public:
00092     virtual UsbDevice*  GetUsbDevicePtr(uint8_t addr) = 0;
00093     virtual uint8_t     AllocAddress(uint8_t parent, bool is_hub = false, uint8_t port = 0) = 0;
00094     virtual void        FreeAddress(uint8_t addr) = 0;
00095 };
00096 
00097 typedef void (*UsbDeviceHandleFunc) (UsbDevice * pdev);
00098 
00099 #define ADDR_ERROR_INVALID_INDEX    0xFF
00100 #define ADDR_ERROR_INVALID_ADDRESS  0xFF
00101 
00102 template<const uint8_t MAX_DEVICES_ALLOWED>
00103 class AddressPoolImpl : public AddressPool
00104 {
00105     EpInfo      dev0ep;             //Endpoint data structure used during enumeration for uninitialized device
00106     uint8_t     hubCounter;         // hub counter is kept
00107 
00108     // in order to avoid hub address duplication
00109     UsbDevice   thePool[MAX_DEVICES_ALLOWED];
00110 
00111     // Initializes address pool entry
00112     void InitEntry(uint8_t index)
00113     {
00114         thePool[index].address.devAddress = 0;
00115         thePool[index].epcount = 1;
00116         thePool[index].lowspeed = 0;
00117         thePool[index].epinfo = &dev0ep;
00118     }
00119 
00120     // Returns thePool index for a given address
00121     uint8_t FindAddressIndex(uint8_t address = 0)
00122     {
00123         for (uint8_t i = 1; i < MAX_DEVICES_ALLOWED; i++) {
00124             if (thePool[i].address.devAddress == address)
00125                 return i;
00126         }
00127 
00128         return 0;
00129     }
00130 
00131     // Returns thePool child index for a given parent
00132     uint8_t FindChildIndex(UsbDeviceAddress addr, uint8_t start = 1)
00133     {
00134         for (uint8_t i = (start < 1 || start >= MAX_DEVICES_ALLOWED) ? 1 : start; i < MAX_DEVICES_ALLOWED; i++) {
00135             if (thePool[i].address.bmParent == addr.bmAddress)
00136                 return i;
00137         }
00138 
00139         return 0;
00140     }
00141 
00142     // Frees address entry specified by index parameter
00143     void FreeAddressByIndex(uint8_t index)
00144     {
00145         // Zero field is reserved and should not be affected
00146 
00147         if (index == 0)
00148             return;
00149 
00150         UsbDeviceAddress    uda = thePool[index].address;
00151         // If a hub was switched off all port addresses should be freed
00152 
00153         if (uda.bmHub == 1) {
00154             for (uint8_t i = 1; (i = FindChildIndex(uda, i));)
00155                 FreeAddressByIndex(i);
00156 
00157             // If the hub had the last allocated address, hubCounter should be decremented
00158             if (hubCounter == uda.bmAddress)
00159                 hubCounter--;
00160         }
00161 
00162         InitEntry(index);
00163     }
00164 
00165     // Initializes the whole address pool at once
00166     void    InitAllAddresses()  { for (uint8_t i = 1; i < MAX_DEVICES_ALLOWED; i++) InitEntry(i); hubCounter = 0; }
00167 public:
00168     AddressPoolImpl() : hubCounter(0)
00169     {
00170         // Zero address is reserved
00171 
00172         InitEntry(0);
00173 
00174         thePool[0].address.devAddress = 0;
00175         thePool[0].epinfo = &dev0ep;
00176         dev0ep.epAddr = 0;
00177         dev0ep.maxPktSize = 8;
00178         dev0ep.bmSndToggle = 0; // Set DATA0/1 toggles to 0
00179         dev0ep.bmRcvToggle = 0;
00180         dev0ep.bmNakPower = USB_NAK_MAX_POWER;
00181 
00182         InitAllAddresses();
00183     }
00184 
00185     // Returns a pointer to a specified address entry
00186     virtual UsbDevice* GetUsbDevicePtr(uint8_t addr)
00187     {
00188         if (!addr)
00189             return thePool;
00190 
00191         uint8_t index = FindAddressIndex(addr);
00192 
00193         return(!index) ? NULL : thePool + index;
00194     }
00195 
00196     // Performs an operation specified by pfunc for each addressed device
00197     void ForEachUsbDevice(UsbDeviceHandleFunc pfunc)
00198     {
00199         if (!pfunc)
00200             return;
00201 
00202         for (uint8_t i = 1; i < MAX_DEVICES_ALLOWED; i++)
00203             if (thePool[i].address.devAddress)
00204                 pfunc(thePool + i);
00205     }
00206 
00207     // Allocates new address
00208     virtual uint8_t AllocAddress(uint8_t parent, bool is_hub = false, uint8_t port = 0)
00209     {
00210         /* if (parent != 0 && port == 0)
00211                         USB_HOST_SERIAL.println("PRT:0"); */
00212         UsbDeviceAddress    _parent;
00213         _parent.devAddress = parent;
00214         if (_parent.bmReserved || port > 7)
00215             //if(parent > 127 || port > 7)
00216             return 0;
00217 
00218         if (is_hub && hubCounter == 7)
00219             return 0;
00220 
00221         // finds first empty address entry starting from one
00222         uint8_t index = FindAddressIndex(0);
00223 
00224         if (!index)             // if empty entry is not found
00225             return 0;
00226 
00227         if (_parent.devAddress == 0) {
00228             if (is_hub) {
00229                 thePool[index].address.devAddress = 0x41;
00230                 hubCounter++;
00231             }
00232             else
00233                 thePool[index].address.devAddress = 1;
00234 
00235             return thePool[index].address.devAddress;
00236         }
00237 
00238         UsbDeviceAddress    addr;
00239         addr.devAddress = 0;    // Ensure all bits are zero
00240         addr.bmParent = _parent.bmAddress;
00241         if (is_hub) {
00242             addr.bmHub = 1;
00243             addr.bmAddress = ++hubCounter;
00244         }
00245         else {
00246             addr.bmHub = 0;
00247             addr.bmAddress = port;
00248         }
00249 
00250         thePool[index].address = addr;
00251 
00252         /*
00253             USB_HOST_SERIAL.print("Addr:");
00254             USB_HOST_SERIAL.print(addr.bmHub, HEX);
00255             USB_HOST_SERIAL.print(".");
00256             USB_HOST_SERIAL.print(addr.bmParent, HEX);
00257             USB_HOST_SERIAL.print(".");
00258             USB_HOST_SERIAL.println(addr.bmAddress, HEX);
00259          */
00260         return thePool[index].address.devAddress;
00261     }
00262 
00263     // Empties pool entry
00264     virtual void FreeAddress(uint8_t addr)
00265     {
00266         // if the root hub is disconnected all the addresses should be initialized
00267 
00268         if (addr == 0x41) {
00269             InitAllAddresses();
00270             return;
00271         }
00272 
00273         uint8_t index = FindAddressIndex(addr);
00274         FreeAddressByIndex(index);
00275     }
00276 
00277     // Returns number of hubs attached
00278     // It can be rather helpfull to find out if there are hubs attached than getting the exact number of hubs.
00279     //uint8_t GetNumHubs()
00280     //{
00281     //        return hubCounter;
00282     //};
00283     //uint8_t GetNumDevices()
00284     //{
00285     //        uint8_t counter = 0;
00286     //        for (uint8_t i=1; i<MAX_DEVICES_ALLOWED; i++)
00287     //                if (thePool[i].address != 0);
00288     //                        counter ++;
00289     //        return counter;
00290     //};
00291 };
00292 #endif // __ADDRESS_H__