USB Host Shield 2.0
Loading...
Searching...
No Matches
address.h
Go to the documentation of this file.
1/* Copyright (C) 2011 Circuits At Home, LTD. All rights reserved.
2
3This program is free software; you can redistribute it and/or modify
4it under the terms of the GNU General Public License as published by
5the Free Software Foundation; either version 2 of the License, or
6(at your option) any later version.
7
8This program is distributed in the hope that it will be useful,
9but WITHOUT ANY WARRANTY; without even the implied warranty of
10MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11GNU General Public License for more details.
12
13You should have received a copy of the GNU General Public License
14along with this program; if not, write to the Free Software
15Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
16
17Contact information
18-------------------
19
20Circuits At Home, LTD
21Web : http://www.circuitsathome.com
22e-mail : support@circuitsathome.com
23 */
24
25#if !defined(_usb_h_) || defined(__ADDRESS_H__)
26#error "Never include address.h directly; include Usb.h instead"
27#else
28#define __ADDRESS_H__
29
30
31
32/* NAK powers. To save space in endpoint data structure, amount of retries before giving up and returning 0x4 is stored in */
33/* bmNakPower as a power of 2. The actual nak_limit is then calculated as nak_limit = ( 2^bmNakPower - 1) */
34#define USB_NAK_MAX_POWER 15 //NAK binary order maximum value
35#define USB_NAK_DEFAULT 14 //default 32K-1 NAKs before giving up
36#define USB_NAK_NOWAIT 1 //Single NAK stops transfer
37#define USB_NAK_NONAK 0 //Do not count NAKs, stop retrying after USB Timeout
38
39struct EpInfo {
40 uint8_t epAddr; // Endpoint address
41 uint8_t maxPktSize; // Maximum packet size
42
43 union {
44 uint8_t epAttribs;
45
46 struct {
47 uint8_t bmSndToggle : 1; // Send toggle, when zero bmSNDTOG0, bmSNDTOG1 otherwise
48 uint8_t bmRcvToggle : 1; // Send toggle, when zero bmRCVTOG0, bmRCVTOG1 otherwise
49 uint8_t bmNakPower : 6; // Binary order for NAK_LIMIT value
50 } __attribute__((packed));
51 };
52} __attribute__((packed));
53
54// 7 6 5 4 3 2 1 0
55// ---------------------------------
56// | | H | P | P | P | A | A | A |
57// ---------------------------------
58//
59// H - if 1 the address is a hub address
60// P - parent hub address
61// A - device address / port number in case of hub
62//
63
65
66 union {
67
68 struct {
69 uint8_t bmAddress : 3; // device address/port number
70 uint8_t bmParent : 3; // parent hub address
71 uint8_t bmHub : 1; // hub flag
72 uint8_t bmReserved : 1; // reserved, must be zero
73 } __attribute__((packed));
74 uint8_t devAddress;
75 };
76} __attribute__((packed));
77
78#define bmUSB_DEV_ADDR_ADDRESS 0x07
79#define bmUSB_DEV_ADDR_PARENT 0x38
80#define bmUSB_DEV_ADDR_HUB 0x40
81
82struct UsbDevice {
83 EpInfo *epinfo; // endpoint info pointer
85 uint8_t epcount; // number of endpoints
86 bool lowspeed; // indicates if a device is the low speed one
87 // uint8_t devclass; // device class
88} __attribute__((packed));
89
91public:
92 virtual UsbDevice* GetUsbDevicePtr(uint8_t addr) = 0;
93 virtual uint8_t AllocAddress(uint8_t parent, bool is_hub = false, uint8_t port = 0) = 0;
94 virtual void FreeAddress(uint8_t addr) = 0;
95};
96
97typedef void (*UsbDeviceHandleFunc)(UsbDevice *pdev);
98
99#define ADDR_ERROR_INVALID_INDEX 0xFF
100#define ADDR_ERROR_INVALID_ADDRESS 0xFF
101
102template <const uint8_t MAX_DEVICES_ALLOWED>
104 EpInfo dev0ep; //Endpoint data structure used during enumeration for uninitialized device
105
106 uint8_t hubCounter; // hub counter is kept
107 // in order to avoid hub address duplication
108
109 UsbDevice thePool[MAX_DEVICES_ALLOWED];
110
111 // Initializes address pool entry
112
113 void InitEntry(uint8_t index) {
114 thePool[index].address.devAddress = 0;
115 thePool[index].epcount = 1;
116 thePool[index].lowspeed = 0;
117 thePool[index].epinfo = &dev0ep;
118 };
119
120 // Returns thePool index for a given address
121
122 uint8_t FindAddressIndex(uint8_t address = 0) {
123 for(uint8_t i = 1; i < MAX_DEVICES_ALLOWED; i++) {
124 if(thePool[i].address.devAddress == address)
125 return i;
126 }
127 return 0;
128 };
129
130 // Returns thePool child index for a given parent
131
132 uint8_t FindChildIndex(UsbDeviceAddress addr, uint8_t start = 1) {
133 for(uint8_t i = (start < 1 || start >= MAX_DEVICES_ALLOWED) ? 1 : start; i < MAX_DEVICES_ALLOWED; i++) {
134 if(thePool[i].address.bmParent == addr.bmAddress)
135 return i;
136 }
137 return 0;
138 };
139
140 // Frees address entry specified by index parameter
141
142 void FreeAddressByIndex(uint8_t index) {
143 // Zero field is reserved and should not be affected
144 if(index == 0)
145 return;
146
147 UsbDeviceAddress uda = thePool[index].address;
148 // If a hub was switched off all port addresses should be freed
149 if(uda.bmHub == 1) {
150 for(uint8_t i = 1; (i = FindChildIndex(uda, i));)
151 FreeAddressByIndex(i);
152
153 // If the hub had the last allocated address, hubCounter should be decremented
154 if(hubCounter == uda.bmAddress)
155 hubCounter--;
156 }
157 InitEntry(index);
158 }
159
160 // Initializes the whole address pool at once
161
162 void InitAllAddresses() {
163 for(uint8_t i = 1; i < MAX_DEVICES_ALLOWED; i++)
164 InitEntry(i);
165
166 hubCounter = 0;
167 };
168
169public:
170
171 AddressPoolImpl() : hubCounter(0) {
172 // Zero address is reserved
173 InitEntry(0);
174
175 thePool[0].address.devAddress = 0;
176 thePool[0].epinfo = &dev0ep;
177 dev0ep.epAddr = 0;
178 dev0ep.maxPktSize = 8;
179 dev0ep.bmSndToggle = 0; // Set DATA0/1 toggles to 0
180 dev0ep.bmRcvToggle = 0;
182
183 InitAllAddresses();
184 };
185
186 // Returns a pointer to a specified address entry
187
188 virtual UsbDevice* GetUsbDevicePtr(uint8_t addr) {
189 if(!addr)
190 return thePool;
191
192 uint8_t index = FindAddressIndex(addr);
193
194 return (!index) ? NULL : thePool + index;
195 };
196
197 // Performs an operation specified by pfunc for each addressed device
198
200 if(!pfunc)
201 return;
202
203 for(uint8_t i = 1; i < MAX_DEVICES_ALLOWED; i++)
204 if(thePool[i].address.devAddress)
205 pfunc(thePool + i);
206 };
207
208 // Allocates new address
209
210 virtual uint8_t AllocAddress(uint8_t parent, bool is_hub = false, uint8_t port = 0) {
211 /* if (parent != 0 && port == 0)
212 USB_HOST_SERIAL.println("PRT:0"); */
213 UsbDeviceAddress _parent;
214 _parent.devAddress = parent;
215 if(_parent.bmReserved || port > 7)
216 //if(parent > 127 || port > 7)
217 return 0;
218
219 if(is_hub && hubCounter == 7)
220 return 0;
221
222 // finds first empty address entry starting from one
223 uint8_t index = FindAddressIndex(0);
224
225 if(!index) // if empty entry is not found
226 return 0;
227
228 if(_parent.devAddress == 0) {
229 if(is_hub) {
230 thePool[index].address.devAddress = 0x41;
231 hubCounter++;
232 } else
233 thePool[index].address.devAddress = 1;
234
235 return thePool[index].address.devAddress;
236 }
237
238 UsbDeviceAddress addr;
239 addr.devAddress = 0; // Ensure all bits are zero
240 addr.bmParent = _parent.bmAddress;
241 if(is_hub) {
242 addr.bmHub = 1;
243 addr.bmAddress = ++hubCounter;
244 } else {
245 addr.bmHub = 0;
246 addr.bmAddress = port;
247 }
248 thePool[index].address = addr;
249 /*
250 USB_HOST_SERIAL.print("Addr:");
251 USB_HOST_SERIAL.print(addr.bmHub, HEX);
252 USB_HOST_SERIAL.print(".");
253 USB_HOST_SERIAL.print(addr.bmParent, HEX);
254 USB_HOST_SERIAL.print(".");
255 USB_HOST_SERIAL.println(addr.bmAddress, HEX);
256 */
257 return thePool[index].address.devAddress;
258 };
259
260 // Empties pool entry
261
262 virtual void FreeAddress(uint8_t addr) {
263 // if the root hub is disconnected all the addresses should be initialized
264 if(addr == 0x41) {
265 InitAllAddresses();
266 return;
267 }
268 uint8_t index = FindAddressIndex(addr);
269 FreeAddressByIndex(index);
270 };
271
272 // Returns number of hubs attached
273 // It can be rather helpfull to find out if there are hubs attached than getting the exact number of hubs.
274 //uint8_t GetNumHubs()
275 //{
276 // return hubCounter;
277 //};
278 //uint8_t GetNumDevices()
279 //{
280 // uint8_t counter = 0;
281
282 // for (uint8_t i=1; i<MAX_DEVICES_ALLOWED; i++)
283 // if (thePool[i].address != 0);
284 // counter ++;
285
286 // return counter;
287 //};
288};
289
290#endif // __ADDRESS_H__
#define USB_NAK_MAX_POWER
Definition address.h:34
void(* UsbDeviceHandleFunc)(UsbDevice *pdev)
Definition address.h:97
virtual void FreeAddress(uint8_t addr)=0
virtual UsbDevice * GetUsbDevicePtr(uint8_t addr)=0
virtual uint8_t AllocAddress(uint8_t parent, bool is_hub=false, uint8_t port=0)=0
void ForEachUsbDevice(UsbDeviceHandleFunc pfunc)
Definition address.h:199
virtual uint8_t AllocAddress(uint8_t parent, bool is_hub=false, uint8_t port=0)
Definition address.h:210
virtual void FreeAddress(uint8_t addr)
Definition address.h:262
virtual UsbDevice * GetUsbDevicePtr(uint8_t addr)
Definition address.h:188
uint8_t epAttribs
Definition address.h:44
uint8_t bmNakPower
Definition address.h:49
uint8_t bmRcvToggle
Definition address.h:48
uint8_t epAddr
Definition address.h:40
uint8_t maxPktSize
Definition address.h:41
uint8_t bmSndToggle
Definition address.h:47
uint8_t bmHub
Definition address.h:71
uint8_t bmReserved
Definition address.h:72
uint8_t devAddress
Definition address.h:74
uint8_t bmParent
Definition address.h:70
uint8_t bmAddress
Definition address.h:69
UsbDeviceAddress address
Definition address.h:84
EpInfo * epinfo
Definition address.h:83
uint8_t epcount
Definition address.h:85
bool lowspeed
Definition address.h:86