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 */
|
---|