1 /* Copyright (C) 2011 Circuits At Home, LTD. All rights reserved.
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
14 Web : http://www.circuitsathome.com
15 e-mail : support@circuitsathome.com
18 #if !defined(_usb_h_) || defined(__ADDRESS_H__)
19 #error "Never include address.h directly; include Usb.h instead"
25 /* NAK powers. To save space in endpoint data structure, amount of retries before giving up and returning 0x4 is stored in */
26 /* bmNakPower as a power of 2. The actual nak_limit is then calculated as nak_limit = ( 2^bmNakPower - 1) */
27 #define USB_NAK_MAX_POWER 15 //NAK binary order maximum value
28 #define USB_NAK_DEFAULT 14 //default 32K-1 NAKs before giving up
29 #define USB_NAK_NOWAIT 1 //Single NAK stops transfer
30 #define USB_NAK_NONAK 0 //Do not count NAKs, stop retrying after USB Timeout
33 uint8_t epAddr
; // Endpoint address
34 uint8_t maxPktSize
; // Maximum packet size
40 uint8_t bmSndToggle
: 1; // Send toggle, when zero bmSNDTOG0, bmSNDTOG1 otherwise
41 uint8_t bmRcvToggle
: 1; // Send toggle, when zero bmRCVTOG0, bmRCVTOG1 otherwise
42 uint8_t bmNakPower
: 6; // Binary order for NAK_LIMIT value
43 } __attribute__((packed
));
45 } __attribute__((packed
));
48 // ---------------------------------
49 // | | H | P | P | P | A | A | A |
50 // ---------------------------------
52 // H - if 1 the address is a hub address
53 // P - parent hub address
54 // A - device address / port number in case of hub
57 struct UsbDeviceAddress
{
62 uint8_t bmAddress
: 3; // device address/port number
63 uint8_t bmParent
: 3; // parent hub address
64 uint8_t bmHub
: 1; // hub flag
65 uint8_t bmReserved
: 1; // reserved, must be zero
66 } __attribute__((packed
));
69 } __attribute__((packed
));
71 #define bmUSB_DEV_ADDR_ADDRESS 0x07
72 #define bmUSB_DEV_ADDR_PARENT 0x38
73 #define bmUSB_DEV_ADDR_HUB 0x40
76 EpInfo
*epinfo
; // endpoint info pointer
77 UsbDeviceAddress address
;
78 uint8_t epcount
; // number of endpoints
79 bool lowspeed
; // indicates if a device is the low speed one
80 // uint8_t devclass; // device class
81 } __attribute__((packed
));
85 virtual UsbDevice
* GetUsbDevicePtr(uint8_t addr
) = 0;
86 virtual uint8_t AllocAddress(uint8_t parent
, bool is_hub
= false, uint8_t port
= 0) = 0;
87 virtual void FreeAddress(uint8_t addr
) = 0;
90 typedef void (*UsbDeviceHandleFunc
)(UsbDevice
*pdev
);
92 #define ADDR_ERROR_INVALID_INDEX 0xFF
93 #define ADDR_ERROR_INVALID_ADDRESS 0xFF
95 template <const uint8_t MAX_DEVICES_ALLOWED
>
96 class AddressPoolImpl
: public AddressPool
{
97 EpInfo dev0ep
; //Endpoint data structure used during enumeration for uninitialized device
99 uint8_t hubCounter
; // hub counter is kept
100 // in order to avoid hub address duplication
102 UsbDevice thePool
[MAX_DEVICES_ALLOWED
];
104 // Initializes address pool entry
106 void InitEntry(uint8_t index
) {
107 thePool
[index
].address
.devAddress
= 0;
108 thePool
[index
].epcount
= 1;
109 thePool
[index
].lowspeed
= 0;
110 thePool
[index
].epinfo
= &dev0ep
;
113 // Returns thePool index for a given address
115 uint8_t FindAddressIndex(uint8_t address
= 0) {
116 for(uint8_t i
= 1; i
< MAX_DEVICES_ALLOWED
; i
++) {
117 if(thePool
[i
].address
.devAddress
== address
)
123 // Returns thePool child index for a given parent
125 uint8_t FindChildIndex(UsbDeviceAddress addr
, uint8_t start
= 1) {
126 for(uint8_t i
= (start
< 1 || start
>= MAX_DEVICES_ALLOWED
) ? 1 : start
; i
< MAX_DEVICES_ALLOWED
; i
++) {
127 if(thePool
[i
].address
.bmParent
== addr
.bmAddress
)
133 // Frees address entry specified by index parameter
135 void FreeAddressByIndex(uint8_t index
) {
136 // Zero field is reserved and should not be affected
140 UsbDeviceAddress uda
= thePool
[index
].address
;
141 // If a hub was switched off all port addresses should be freed
143 for(uint8_t i
= 1; (i
= FindChildIndex(uda
, i
));)
144 FreeAddressByIndex(i
);
146 // If the hub had the last allocated address, hubCounter should be decremented
147 if(hubCounter
== uda
.bmAddress
)
153 // Initializes the whole address pool at once
155 void InitAllAddresses() {
156 for(uint8_t i
= 1; i
< MAX_DEVICES_ALLOWED
; i
++)
164 AddressPoolImpl() : hubCounter(0) {
165 // Zero address is reserved
168 thePool
[0].address
.devAddress
= 0;
169 thePool
[0].epinfo
= &dev0ep
;
171 dev0ep
.maxPktSize
= 8;
172 dev0ep
.epAttribs
= 0; //set DATA0/1 toggles to 0
173 dev0ep
.bmNakPower
= USB_NAK_MAX_POWER
;
178 // Returns a pointer to a specified address entry
180 virtual UsbDevice
* GetUsbDevicePtr(uint8_t addr
) {
184 uint8_t index
= FindAddressIndex(addr
);
186 return (!index
) ? NULL
: thePool
+ index
;
189 // Performs an operation specified by pfunc for each addressed device
191 void ForEachUsbDevice(UsbDeviceHandleFunc pfunc
) {
195 for(uint8_t i
= 1; i
< MAX_DEVICES_ALLOWED
; i
++)
196 if(thePool
[i
].address
.devAddress
)
200 // Allocates new address
202 virtual uint8_t AllocAddress(uint8_t parent
, bool is_hub
= false, uint8_t port
= 0) {
203 /* if (parent != 0 && port == 0)
204 USB_HOST_SERIAL.println("PRT:0"); */
205 UsbDeviceAddress _parent
;
206 _parent
.devAddress
= parent
;
207 if(_parent
.bmReserved
|| port
> 7)
208 //if(parent > 127 || port > 7)
211 if(is_hub
&& hubCounter
== 7)
214 // finds first empty address entry starting from one
215 uint8_t index
= FindAddressIndex(0);
217 if(!index
) // if empty entry is not found
220 if(_parent
.devAddress
== 0) {
222 thePool
[index
].address
.devAddress
= 0x41;
225 thePool
[index
].address
.devAddress
= 1;
227 return thePool
[index
].address
.devAddress
;
230 UsbDeviceAddress addr
;
231 addr
.devAddress
= 0; // Ensure all bits are zero
232 addr
.bmParent
= _parent
.bmAddress
;
235 addr
.bmAddress
= ++hubCounter
;
238 addr
.bmAddress
= port
;
240 thePool
[index
].address
= addr
;
242 USB_HOST_SERIAL.print("Addr:");
243 USB_HOST_SERIAL.print(addr.bmHub, HEX);
244 USB_HOST_SERIAL.print(".");
245 USB_HOST_SERIAL.print(addr.bmParent, HEX);
246 USB_HOST_SERIAL.print(".");
247 USB_HOST_SERIAL.println(addr.bmAddress, HEX);
249 return thePool
[index
].address
.devAddress
;
252 // Empties pool entry
254 virtual void FreeAddress(uint8_t addr
) {
255 // if the root hub is disconnected all the addresses should be initialized
260 uint8_t index
= FindAddressIndex(addr
);
261 FreeAddressByIndex(index
);
264 // Returns number of hubs attached
265 // It can be rather helpfull to find out if there are hubs attached than getting the exact number of hubs.
266 //uint8_t GetNumHubs()
268 // return hubCounter;
270 //uint8_t GetNumDevices()
272 // uint8_t counter = 0;
274 // for (uint8_t i=1; i<MAX_DEVICES_ALLOWED; i++)
275 // if (thePool[i].address != 0);
282 #endif // __ADDRESS_H__