Takumi Odashima / ArduinoUsbHostShield

Dependents:   USBHOST_PS5

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 
00025 #if !defined(_usb_h_) || defined(__ADDRESS_H__)
00026 #error "Never include address.h directly; include Usb.h instead"
00027 #else
00028 #define __ADDRESS_H__
00029 
00030 
00031 
00032 /* NAK powers. To save space in endpoint data structure, amount of retries before giving up and returning 0x4 is stored in */
00033 /* bmNakPower as a power of 2. The actual nak_limit is then calculated as nak_limit = ( 2^bmNakPower - 1) */
00034 #define USB_NAK_MAX_POWER               15              //NAK binary order maximum value
00035 #define USB_NAK_DEFAULT                 14              //default 32K-1 NAKs before giving up
00036 #define USB_NAK_NOWAIT                  1               //Single NAK stops transfer
00037 #define USB_NAK_NONAK                   0               //Do not count NAKs, stop retrying after USB Timeout
00038 
00039 struct EpInfo {
00040         uint8_t epAddr; // Endpoint address
00041         uint8_t maxPktSize; // Maximum packet size
00042 
00043         union {
00044                 uint8_t epAttribs;
00045 
00046                 struct {
00047                         uint8_t bmSndToggle : 1; // Send toggle, when zero bmSNDTOG0, bmSNDTOG1 otherwise
00048                         uint8_t bmRcvToggle : 1; // Send toggle, when zero bmRCVTOG0, bmRCVTOG1 otherwise
00049                         uint8_t bmNakPower : 6; // Binary order for NAK_LIMIT value
00050                 } __attribute__((packed));
00051         };
00052 } __attribute__((packed));
00053 
00054 //        7   6   5   4   3   2   1   0
00055 //  ---------------------------------
00056 //  |   | H | P | P | P | A | A | A |
00057 //  ---------------------------------
00058 //
00059 // H - if 1 the address is a hub address
00060 // P - parent hub address
00061 // A - device address / port number in case of hub
00062 //
00063 
00064 struct UsbDeviceAddress {
00065 
00066         union {
00067 
00068                 struct {
00069                         uint8_t bmAddress : 3; // device address/port number
00070                         uint8_t bmParent : 3; // parent hub address
00071                         uint8_t bmHub : 1; // hub flag
00072                         uint8_t bmReserved : 1; // reserved, must be zero
00073                 } __attribute__((packed));
00074                 uint8_t devAddress;
00075         };
00076 } __attribute__((packed));
00077 
00078 #define bmUSB_DEV_ADDR_ADDRESS          0x07
00079 #define bmUSB_DEV_ADDR_PARENT           0x38
00080 #define bmUSB_DEV_ADDR_HUB              0x40
00081 
00082 struct UsbDevice {
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         //      uint8_t devclass; // device class
00088 } __attribute__((packed));
00089 
00090 class AddressPool {
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         EpInfo dev0ep; //Endpoint data structure used during enumeration for uninitialized device
00105 
00106         uint8_t hubCounter; // hub counter is kept
00107         // in order to avoid hub address duplication
00108 
00109         UsbDevice thePool[MAX_DEVICES_ALLOWED];
00110 
00111         // Initializes address pool entry
00112 
00113         void InitEntry(uint8_t index) {
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 
00122         uint8_t FindAddressIndex(uint8_t address = 0) {
00123                 for(uint8_t i = 1; i < MAX_DEVICES_ALLOWED; i++) {
00124                         if(thePool[i].address.devAddress == address)
00125                                 return i;
00126                 }
00127                 return 0;
00128         };
00129 
00130         // Returns thePool child index for a given parent
00131 
00132         uint8_t FindChildIndex(UsbDeviceAddress addr, uint8_t start = 1) {
00133                 for(uint8_t i = (start < 1 || start >= MAX_DEVICES_ALLOWED) ? 1 : start; i < MAX_DEVICES_ALLOWED; i++) {
00134                         if(thePool[i].address.bmParent == addr.bmAddress)
00135                                 return i;
00136                 }
00137                 return 0;
00138         };
00139 
00140         // Frees address entry specified by index parameter
00141 
00142         void FreeAddressByIndex(uint8_t index) {
00143                 // Zero field is reserved and should not be affected
00144                 if(index == 0)
00145                         return;
00146 
00147                 UsbDeviceAddress uda = thePool[index].address;
00148                 // If a hub was switched off all port addresses should be freed
00149                 if(uda.bmHub == 1) {
00150                         for(uint8_t i = 1; (i = FindChildIndex(uda, i));)
00151                                 FreeAddressByIndex(i);
00152 
00153                         // If the hub had the last allocated address, hubCounter should be decremented
00154                         if(hubCounter == uda.bmAddress)
00155                                 hubCounter--;
00156                 }
00157                 InitEntry(index);
00158         }
00159 
00160         // Initializes the whole address pool at once
00161 
00162         void InitAllAddresses() {
00163                 for(uint8_t i = 1; i < MAX_DEVICES_ALLOWED; i++)
00164                         InitEntry(i);
00165 
00166                 hubCounter = 0;
00167         };
00168 
00169 public:
00170 
00171         AddressPoolImpl() : hubCounter(0) {
00172                 // Zero address is reserved
00173                 InitEntry(0);
00174 
00175                 thePool[0].address.devAddress = 0;
00176                 thePool[0].epinfo = &dev0ep;
00177                 dev0ep.epAddr = 0;
00178                 dev0ep.maxPktSize = 8;
00179                 dev0ep.bmSndToggle = 0; // Set DATA0/1 toggles to 0
00180                 dev0ep.bmRcvToggle = 0;
00181                 dev0ep.bmNakPower = USB_NAK_MAX_POWER;
00182 
00183                 InitAllAddresses();
00184         };
00185 
00186         // Returns a pointer to a specified address entry
00187 
00188         virtual UsbDevice* GetUsbDevicePtr(uint8_t addr) {
00189                 if(!addr)
00190                         return thePool;
00191 
00192                 uint8_t index = FindAddressIndex(addr);
00193 
00194                 return (!index) ? NULL : thePool + index;
00195         };
00196 
00197         // Performs an operation specified by pfunc for each addressed device
00198 
00199         void ForEachUsbDevice(UsbDeviceHandleFunc pfunc) {
00200                 if(!pfunc)
00201                         return;
00202 
00203                 for(uint8_t i = 1; i < MAX_DEVICES_ALLOWED; i++)
00204                         if(thePool[i].address.devAddress)
00205                                 pfunc(thePool + i);
00206         };
00207 
00208         // Allocates new address
00209 
00210         virtual uint8_t AllocAddress(uint8_t parent, bool is_hub = false, uint8_t port = 0) {
00211                 /* if (parent != 0 && port == 0)
00212                         USB_HOST_SERIAL.println("PRT:0"); */
00213                 UsbDeviceAddress _parent;
00214                 _parent.devAddress = parent;
00215                 if(_parent.bmReserved || port > 7)
00216                         //if(parent > 127 || port > 7)
00217                         return 0;
00218 
00219                 if(is_hub && hubCounter == 7)
00220                         return 0;
00221 
00222                 // finds first empty address entry starting from one
00223                 uint8_t index = FindAddressIndex(0);
00224 
00225                 if(!index) // if empty entry is not found
00226                         return 0;
00227 
00228                 if(_parent.devAddress == 0) {
00229                         if(is_hub) {
00230                                 thePool[index].address.devAddress = 0x41;
00231                                 hubCounter++;
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                 } else {
00245                         addr.bmHub = 0;
00246                         addr.bmAddress = port;
00247                 }
00248                 thePool[index].address = addr;
00249                 /*
00250                                 USB_HOST_SERIAL.print("Addr:");
00251                                 USB_HOST_SERIAL.print(addr.bmHub, HEX);
00252                                 USB_HOST_SERIAL.print(".");
00253                                 USB_HOST_SERIAL.print(addr.bmParent, HEX);
00254                                 USB_HOST_SERIAL.print(".");
00255                                 USB_HOST_SERIAL.println(addr.bmAddress, HEX);
00256                  */
00257                 return thePool[index].address.devAddress;
00258         };
00259 
00260         // Empties pool entry
00261 
00262         virtual void FreeAddress(uint8_t addr) {
00263                 // if the root hub is disconnected all the addresses should be initialized
00264                 if(addr == 0x41) {
00265                         InitAllAddresses();
00266                         return;
00267                 }
00268                 uint8_t index = FindAddressIndex(addr);
00269                 FreeAddressByIndex(index);
00270         };
00271 
00272         // Returns number of hubs attached
00273         // It can be rather helpfull to find out if there are hubs attached than getting the exact number of hubs.
00274         //uint8_t GetNumHubs()
00275         //{
00276         //        return hubCounter;
00277         //};
00278         //uint8_t GetNumDevices()
00279         //{
00280         //        uint8_t counter = 0;
00281 
00282         //        for (uint8_t i=1; i<MAX_DEVICES_ALLOWED; i++)
00283         //                if (thePool[i].address != 0);
00284         //                        counter ++;
00285 
00286         //        return counter;
00287         //};
00288 };
00289 
00290 #endif // __ADDRESS_H__
00291