[136] | 1 | /* Copyright (C) 2011 Circuits At Home, LTD. All rights reserved.
|
---|
| 2 |
|
---|
| 3 | This software may be distributed and modified under the terms of the GNU
|
---|
| 4 | General Public License version 2 (GPL2) as published by the Free Software
|
---|
| 5 | Foundation and appearing in the file GPL2.TXT included in the packaging of
|
---|
| 6 | this file. Please note that GPL2 Section 2[b] requires that all works based
|
---|
| 7 | on this software must also be made publicly available under the terms of
|
---|
| 8 | the GPL2 ("Copyleft").
|
---|
| 9 |
|
---|
| 10 | Contact information
|
---|
| 11 | -------------------
|
---|
| 12 |
|
---|
| 13 | Circuits At Home, LTD
|
---|
| 14 | Web : http://www.circuitsathome.com
|
---|
| 15 | e-mail : support@circuitsathome.com
|
---|
| 16 | */
|
---|
| 17 |
|
---|
| 18 | #ifndef ADDRESS_H_INCLUDED
|
---|
| 19 | #define ADDRESS_H_INCLUDED
|
---|
| 20 |
|
---|
| 21 | #include <stdint.h>
|
---|
| 22 |
|
---|
| 23 | /* NAK powers. To save space in endpoint data structure, amount of retries before giving up and returning 0x4 is stored in */
|
---|
| 24 | /* bmNakPower as a power of 2. The actual nak_limit is then calculated as nak_limit = ( 2^bmNakPower - 1) */
|
---|
| 25 | #define USB_NAK_MAX_POWER 16 //NAK binary order maximum value
|
---|
| 26 | #define USB_NAK_DEFAULT 14 //default 16K-1 NAKs before giving up
|
---|
| 27 | #define USB_NAK_NOWAIT 1 //Single NAK stops transfer
|
---|
| 28 | #define USB_NAK_NONAK 0 //Do not count NAKs, stop retrying after USB Timeout
|
---|
| 29 |
|
---|
| 30 | /**
|
---|
| 31 | * \brief Device endpoint definition.
|
---|
| 32 | *
|
---|
| 33 | * \note hostPipeNum is the allocated pipe used for the communication with
|
---|
| 34 | * deviceEpNum remote device endpoint.
|
---|
| 35 | * There is exactly one hostPipeNum corresponding to a deviceEpNum.
|
---|
| 36 | *
|
---|
| 37 | * \note The number of host pipe is limited by the hardware (10 on SAM3X).
|
---|
| 38 | * Moreover hostPipeNum allocation is static, meaning that only a limited
|
---|
| 39 | * amount of device endpoints can be opened at the same time, thus limitating
|
---|
| 40 | * the maximum number of connected devices at the same time.
|
---|
| 41 | */
|
---|
| 42 | struct EpInfo
|
---|
| 43 | {
|
---|
| 44 | uint32_t deviceEpNum; // Device endpoint number
|
---|
| 45 | uint32_t hostPipeNum; // Host corresponding pipe number
|
---|
| 46 | uint32_t maxPktSize; // Maximum packet size
|
---|
| 47 |
|
---|
| 48 | union
|
---|
| 49 | {
|
---|
| 50 | uint8_t epAttribs;
|
---|
| 51 |
|
---|
| 52 | struct
|
---|
| 53 | {
|
---|
| 54 | uint8_t bmSndToggle : 1; // Send toggle, when zero bmSNDTOG0, bmSNDTOG1 otherwise
|
---|
| 55 | uint8_t bmRcvToggle : 1; // Send toggle, when zero bmRCVTOG0, bmRCVTOG1 otherwise
|
---|
| 56 | uint8_t bmNakPower : 6; // Binary order for NAK_LIMIT value
|
---|
| 57 | };
|
---|
| 58 | };
|
---|
| 59 | };
|
---|
| 60 |
|
---|
| 61 | /**
|
---|
| 62 | * \brief USB device address definition.
|
---|
| 63 | *
|
---|
| 64 | * \note The 8 bits USB address is defined like this:
|
---|
| 65 | *
|
---|
| 66 | * 7 6 5 4 3 2 1 0
|
---|
| 67 | * ---------------------------------
|
---|
| 68 | * | | H | P | P | P | A | A | A |
|
---|
| 69 | * ---------------------------------
|
---|
| 70 | *
|
---|
| 71 | * H - if 1 the address is a hub address
|
---|
| 72 | * P - parent hub address
|
---|
| 73 | * A - device address / port number in case of hub
|
---|
| 74 | */
|
---|
| 75 | struct UsbDeviceAddress
|
---|
| 76 | {
|
---|
| 77 | union
|
---|
| 78 | {
|
---|
| 79 | struct
|
---|
| 80 | {
|
---|
| 81 | uint32_t bmAddress : 3; // device address/port number
|
---|
| 82 | uint32_t bmParent : 3; // parent hub address
|
---|
| 83 | uint32_t bmHub : 1; // hub flag
|
---|
| 84 | uint32_t bmReserved : 25; // reserved, must be zerro
|
---|
| 85 | };
|
---|
| 86 | uint32_t devAddress;
|
---|
| 87 | };
|
---|
| 88 | };
|
---|
| 89 |
|
---|
| 90 | #define bmUSB_DEV_ADDR_ADDRESS 0x07
|
---|
| 91 | #define bmUSB_DEV_ADDR_PARENT 0x38
|
---|
| 92 | #define bmUSB_DEV_ADDR_HUB 0x40
|
---|
| 93 |
|
---|
| 94 | /**
|
---|
| 95 | * \brief USB device definition.
|
---|
| 96 | *
|
---|
| 97 | * \note epinfo is used to store the list of device endpoints currently used
|
---|
| 98 | * by the USBHost stack. This field is set during enumeration process when
|
---|
| 99 | * a supported USB class is found. See any USB classes implementing
|
---|
| 100 | * USBDeviceConfig and init() method for reference.
|
---|
| 101 | */
|
---|
| 102 | struct UsbDevice
|
---|
| 103 | {
|
---|
| 104 | EpInfo *epinfo; // endpoint info pointer
|
---|
| 105 | uint32_t address; // address
|
---|
| 106 | uint32_t epcount; // number of endpoints
|
---|
| 107 | uint32_t lowspeed; // indicates if a device is the low speed one
|
---|
| 108 | };
|
---|
| 109 |
|
---|
| 110 | /**
|
---|
| 111 | * \class Abstract AddressPool definition.
|
---|
| 112 | */
|
---|
| 113 | class AddressPool
|
---|
| 114 | {
|
---|
| 115 | public:
|
---|
| 116 | virtual UsbDevice* GetUsbDevicePtr(uint32_t addr) = 0;
|
---|
| 117 | virtual uint32_t AllocAddress(uint32_t parent, uint32_t is_hub = 0, uint32_t port = 0) = 0;
|
---|
| 118 | virtual void FreeAddress(uint32_t addr) = 0;
|
---|
| 119 | };
|
---|
| 120 |
|
---|
| 121 | typedef void (*UsbDeviceHandleFunc)(UsbDevice *pdev);
|
---|
| 122 |
|
---|
| 123 | #define ADDR_ERROR_INVALID_INDEX 0xFF
|
---|
| 124 | #define ADDR_ERROR_INVALID_ADDRESS 0xFF
|
---|
| 125 |
|
---|
| 126 | /**
|
---|
| 127 | * \class AddressPoolImpl definition.
|
---|
| 128 | * Used to store the list of connected devices and to keep track of free USB
|
---|
| 129 | * addresses.
|
---|
| 130 | */
|
---|
| 131 | template <const uint32_t MAX_DEVICES_ALLOWED>
|
---|
| 132 | class AddressPoolImpl : public AddressPool
|
---|
| 133 | {
|
---|
| 134 | private:
|
---|
| 135 |
|
---|
| 136 | EpInfo dev0ep; // Endpoint data structure used during enumeration for uninitialized device
|
---|
| 137 |
|
---|
| 138 | uint32_t hubCounter; // hub counter is kept
|
---|
| 139 | // in order to avoid hub address duplication
|
---|
| 140 |
|
---|
| 141 | UsbDevice thePool[MAX_DEVICES_ALLOWED];
|
---|
| 142 |
|
---|
| 143 | /**
|
---|
| 144 | * \brief Initialize the specified address pool entry.
|
---|
| 145 | *
|
---|
| 146 | * \param index Index pointing to a UsbDevice instance in the address pool.
|
---|
| 147 | */
|
---|
| 148 | void InitEntry(uint32_t index)
|
---|
| 149 | {
|
---|
| 150 | thePool[index].address = 0;
|
---|
| 151 | thePool[index].epcount = 1;
|
---|
| 152 | thePool[index].lowspeed = 0;
|
---|
| 153 | thePool[index].epinfo = &dev0ep;
|
---|
| 154 | };
|
---|
| 155 |
|
---|
| 156 | /**
|
---|
| 157 | * \brief Return an address pool index for a given address. This index can
|
---|
| 158 | * further be used to retrieve the corresponding USB device instance
|
---|
| 159 | * UsbDevice.
|
---|
| 160 | *
|
---|
| 161 | * \param index Index pointing to a UsbDevice instance in the address pool.
|
---|
| 162 | *
|
---|
| 163 | * \return Index number if found, 0 otherwise.
|
---|
| 164 | * \note Index 0 is reserved for address 0 and shall never be used.
|
---|
| 165 | */
|
---|
| 166 | uint32_t FindAddressIndex(uint32_t address = 0)
|
---|
| 167 | {
|
---|
| 168 | for (uint8_t i = 1; i < MAX_DEVICES_ALLOWED; i++)
|
---|
| 169 | {
|
---|
| 170 | if (thePool[i].address == address)
|
---|
| 171 | return i;
|
---|
| 172 | }
|
---|
| 173 | return 0;
|
---|
| 174 | };
|
---|
| 175 |
|
---|
| 176 | /**
|
---|
| 177 | * \brief Return address pool child index for a given parent. This index can
|
---|
| 178 | * further be used to retrieve the corresponding USB device instance
|
---|
| 179 | * UsbDevice.
|
---|
| 180 | *
|
---|
| 181 | * \param addr Parent USB address.
|
---|
| 182 | * \param start Search in the pool from this index. Calling multiple time
|
---|
| 183 | * this function with the returned index + 1 can be used to walk through
|
---|
| 184 | * all children.
|
---|
| 185 | *
|
---|
| 186 | * \return Child index number if found, 0 otherwise.
|
---|
| 187 | * \note Index 0 is reserved for address 0 and shall never be used.
|
---|
| 188 | */
|
---|
| 189 | uint32_t FindChildIndex(UsbDeviceAddress addr, uint32_t start = 1)
|
---|
| 190 | {
|
---|
| 191 | for (uint32_t i = (start < 1 || start >= MAX_DEVICES_ALLOWED) ? 1 : start; i < MAX_DEVICES_ALLOWED; ++i)
|
---|
| 192 | {
|
---|
| 193 | if (((UsbDeviceAddress*)&thePool[i].address)->bmParent == addr.bmAddress)
|
---|
| 194 | return i;
|
---|
| 195 | }
|
---|
| 196 |
|
---|
| 197 | return 0;
|
---|
| 198 | };
|
---|
| 199 |
|
---|
| 200 | /**
|
---|
| 201 | * \brief Free address entry specified by index parameter.
|
---|
| 202 | *
|
---|
| 203 | * \note Calling FreeAddressByIndex only frees the USB address for possible
|
---|
| 204 | * further assignement. However, it does not free the actual USB resources
|
---|
| 205 | * used by the device. This can be made by calling the release() method
|
---|
| 206 | * from any UsbDevice class implementing USBDeviceConfig.
|
---|
| 207 | *
|
---|
| 208 | * \param index Index pointing to a UsbDevice instance in the address pool.
|
---|
| 209 | *
|
---|
| 210 | * \note Calling FreeAddressByIndex with a 0 index param has no effect.
|
---|
| 211 | */
|
---|
| 212 | void FreeAddressByIndex(uint32_t index)
|
---|
| 213 | {
|
---|
| 214 | // Zero field is reserved and should not be affected
|
---|
| 215 | if (index == 0)
|
---|
| 216 | return;
|
---|
| 217 |
|
---|
| 218 | // If a hub was switched off all port addresses should be freed
|
---|
| 219 | if (((UsbDeviceAddress*)&thePool[index].address)->bmHub == 1)
|
---|
| 220 | {
|
---|
| 221 | for (uint32_t i = 1; (i = FindChildIndex(*((UsbDeviceAddress*)&thePool[index].address), i) > 0); )
|
---|
| 222 | FreeAddressByIndex(i);
|
---|
| 223 |
|
---|
| 224 | // If the hub had the last allocated address, hubCounter should be decremented
|
---|
| 225 | if (hubCounter == ((UsbDeviceAddress*)&thePool[index].address)->bmAddress)
|
---|
| 226 | hubCounter --;
|
---|
| 227 | }
|
---|
| 228 |
|
---|
| 229 | InitEntry(index);
|
---|
| 230 | }
|
---|
| 231 |
|
---|
| 232 | /**
|
---|
| 233 | * \brief Initialize all address poll entries at once.
|
---|
| 234 | */
|
---|
| 235 | void InitAllAddresses()
|
---|
| 236 | {
|
---|
| 237 | for (uint32_t i = 1; i < MAX_DEVICES_ALLOWED; i++)
|
---|
| 238 | InitEntry(i);
|
---|
| 239 |
|
---|
| 240 | hubCounter = 0;
|
---|
| 241 | };
|
---|
| 242 |
|
---|
| 243 | public:
|
---|
| 244 | /**
|
---|
| 245 | * \brief AddressPoolImpl class constructor.
|
---|
| 246 | */
|
---|
| 247 | AddressPoolImpl() : hubCounter(0)
|
---|
| 248 | {
|
---|
| 249 | // Init address zero (reserved)
|
---|
| 250 | InitEntry(0);
|
---|
| 251 |
|
---|
| 252 | // Init all remaing addresses
|
---|
| 253 | InitAllAddresses();
|
---|
| 254 |
|
---|
| 255 | // Configure ep0 used for enumeration
|
---|
| 256 | dev0ep.deviceEpNum = 0;
|
---|
| 257 | dev0ep.hostPipeNum = 0;
|
---|
| 258 | dev0ep.maxPktSize = 8;
|
---|
| 259 | };
|
---|
| 260 |
|
---|
| 261 | /**
|
---|
| 262 | * \brief Get a UsbDevice pointer from a USB device address.
|
---|
| 263 | *
|
---|
| 264 | * \param addr USB device address.
|
---|
| 265 | *
|
---|
| 266 | * \return UsbDevice pointer on success, 0 otherwise.
|
---|
| 267 | */
|
---|
| 268 | virtual UsbDevice* GetUsbDevicePtr(uint32_t addr)
|
---|
| 269 | {
|
---|
| 270 | if (!addr)
|
---|
| 271 | return thePool;
|
---|
| 272 |
|
---|
| 273 | uint32_t index = FindAddressIndex(addr);
|
---|
| 274 |
|
---|
| 275 | return (!index) ? 0 : (thePool + index);
|
---|
| 276 | };
|
---|
| 277 |
|
---|
| 278 | /**
|
---|
| 279 | * \brief Perform an operation specified by pfunc for each addressed
|
---|
| 280 | * USB device.
|
---|
| 281 | *
|
---|
| 282 | * \param pfunc Any function pointer with type UsbDeviceHandleFunc.
|
---|
| 283 | */
|
---|
| 284 | void ForEachUsbDevice(UsbDeviceHandleFunc pfunc)
|
---|
| 285 | {
|
---|
| 286 | if (!pfunc)
|
---|
| 287 | return;
|
---|
| 288 |
|
---|
| 289 | for (uint32_t i = 1; i < MAX_DEVICES_ALLOWED; i++)
|
---|
| 290 | if (thePool[i].address)
|
---|
| 291 | pfunc(thePool + i);
|
---|
| 292 | };
|
---|
| 293 |
|
---|
| 294 | /**
|
---|
| 295 | * \brief Allocate a new USB device address.
|
---|
| 296 | *
|
---|
| 297 | * \note See UsbDeviceAddress definition for better understanding.
|
---|
| 298 | *
|
---|
| 299 | * \param parent USB device address of the Parent device.
|
---|
| 300 | * \param is_hub Set to true if the corresponding device is a Hub, false
|
---|
| 301 | * otherwise.
|
---|
| 302 | * \param port USB device base address.
|
---|
| 303 | *
|
---|
| 304 | * \return UsbDevice pointer on success, 0 otherwise.
|
---|
| 305 | */
|
---|
| 306 | virtual uint32_t AllocAddress(uint32_t parent, uint32_t is_hub = 0, uint32_t port = 0)
|
---|
| 307 | {
|
---|
| 308 | if (parent > 127 || port > 7)
|
---|
| 309 | return 0;
|
---|
| 310 |
|
---|
| 311 | if (is_hub && hubCounter == 7)
|
---|
| 312 | return 0;
|
---|
| 313 |
|
---|
| 314 | // Finds first empty address entry starting from one
|
---|
| 315 | uint32_t index = FindAddressIndex(0);
|
---|
| 316 |
|
---|
| 317 | // If empty entry is not found
|
---|
| 318 | if (!index)
|
---|
| 319 | return 0;
|
---|
| 320 |
|
---|
| 321 | if (parent == 0)
|
---|
| 322 | {
|
---|
| 323 | if (is_hub)
|
---|
| 324 | {
|
---|
| 325 | thePool[index].address = 0x41;
|
---|
| 326 | hubCounter++;
|
---|
| 327 | }
|
---|
| 328 | else
|
---|
| 329 | thePool[index].address = 1;
|
---|
| 330 |
|
---|
| 331 | return thePool[index].address;
|
---|
| 332 | }
|
---|
| 333 |
|
---|
| 334 | UsbDeviceAddress addr;
|
---|
| 335 |
|
---|
| 336 | addr.bmParent = ((UsbDeviceAddress*)&parent)->bmAddress;
|
---|
| 337 |
|
---|
| 338 | if (is_hub)
|
---|
| 339 | {
|
---|
| 340 | addr.bmHub = 1;
|
---|
| 341 | addr.bmAddress = hubCounter++;
|
---|
| 342 | }
|
---|
| 343 | else
|
---|
| 344 | {
|
---|
| 345 | addr.bmHub = 0;
|
---|
| 346 | addr.bmAddress = port;
|
---|
| 347 | }
|
---|
| 348 |
|
---|
| 349 | thePool[index].address = *((uint8_t*)&addr);
|
---|
| 350 |
|
---|
| 351 | return thePool[index].address;
|
---|
| 352 | };
|
---|
| 353 |
|
---|
| 354 | /**
|
---|
| 355 | * \brief Free the specified USB device address.
|
---|
| 356 | *
|
---|
| 357 | * \param addr USB device address to free.
|
---|
| 358 | */
|
---|
| 359 | virtual void FreeAddress(uint32_t addr)
|
---|
| 360 | {
|
---|
| 361 | // If the root hub is disconnected all the addresses should be initialized
|
---|
| 362 | if (addr == 0x41)
|
---|
| 363 | {
|
---|
| 364 | InitAllAddresses();
|
---|
| 365 | return;
|
---|
| 366 | }
|
---|
| 367 |
|
---|
| 368 | uint32_t index = FindAddressIndex(addr);
|
---|
| 369 | FreeAddressByIndex(index);
|
---|
| 370 | };
|
---|
| 371 |
|
---|
| 372 | // Returns number of hubs attached
|
---|
| 373 | // It can be rather helpfull to find out if there are hubs attached than getting the exact number of hubs.
|
---|
| 374 | /*uint32_t GetNumHubs()
|
---|
| 375 | {
|
---|
| 376 | return hubCounter;
|
---|
| 377 | };
|
---|
| 378 |
|
---|
| 379 | uint32_t GetNumDevices()
|
---|
| 380 | {
|
---|
| 381 | uint32_t counter = 0;
|
---|
| 382 |
|
---|
| 383 | for (uint32_t i = 1; i < MAX_DEVICES_ALLOWED; ++i)
|
---|
| 384 | if (thePool[i].address != 0);
|
---|
| 385 | counter++;
|
---|
| 386 |
|
---|
| 387 | return counter;
|
---|
| 388 | };*/
|
---|
| 389 |
|
---|
| 390 | };
|
---|
| 391 |
|
---|
| 392 | #endif /* ADDRESS_H_INCLUDED */
|
---|