diff options
Diffstat (limited to 'lib/usbhost/USB_Host_Shield_2.0/address.h')
-rw-r--r-- | lib/usbhost/USB_Host_Shield_2.0/address.h | 282 |
1 files changed, 282 insertions, 0 deletions
diff --git a/lib/usbhost/USB_Host_Shield_2.0/address.h b/lib/usbhost/USB_Host_Shield_2.0/address.h new file mode 100644 index 000000000..c3e1b3141 --- /dev/null +++ b/lib/usbhost/USB_Host_Shield_2.0/address.h | |||
@@ -0,0 +1,282 @@ | |||
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 | #if !defined(_usb_h_) || defined(__ADDRESS_H__) | ||
19 | #error "Never include address.h directly; include Usb.h instead" | ||
20 | #else | ||
21 | #define __ADDRESS_H__ | ||
22 | |||
23 | |||
24 | |||
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 | ||
31 | |||
32 | struct EpInfo { | ||
33 | uint8_t epAddr; // Endpoint address | ||
34 | uint8_t maxPktSize; // Maximum packet size | ||
35 | |||
36 | union { | ||
37 | uint8_t epAttribs; | ||
38 | |||
39 | struct { | ||
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)); | ||
44 | }; | ||
45 | } __attribute__((packed)); | ||
46 | |||
47 | // 7 6 5 4 3 2 1 0 | ||
48 | // --------------------------------- | ||
49 | // | | H | P | P | P | A | A | A | | ||
50 | // --------------------------------- | ||
51 | // | ||
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 | ||
55 | // | ||
56 | |||
57 | struct UsbDeviceAddress { | ||
58 | |||
59 | union { | ||
60 | |||
61 | struct { | ||
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)); | ||
67 | uint8_t devAddress; | ||
68 | }; | ||
69 | } __attribute__((packed)); | ||
70 | |||
71 | #define bmUSB_DEV_ADDR_ADDRESS 0x07 | ||
72 | #define bmUSB_DEV_ADDR_PARENT 0x38 | ||
73 | #define bmUSB_DEV_ADDR_HUB 0x40 | ||
74 | |||
75 | struct UsbDevice { | ||
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)); | ||
82 | |||
83 | class AddressPool { | ||
84 | public: | ||
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; | ||
88 | }; | ||
89 | |||
90 | typedef void (*UsbDeviceHandleFunc)(UsbDevice *pdev); | ||
91 | |||
92 | #define ADDR_ERROR_INVALID_INDEX 0xFF | ||
93 | #define ADDR_ERROR_INVALID_ADDRESS 0xFF | ||
94 | |||
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 | ||
98 | |||
99 | uint8_t hubCounter; // hub counter is kept | ||
100 | // in order to avoid hub address duplication | ||
101 | |||
102 | UsbDevice thePool[MAX_DEVICES_ALLOWED]; | ||
103 | |||
104 | // Initializes address pool entry | ||
105 | |||
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; | ||
111 | }; | ||
112 | |||
113 | // Returns thePool index for a given address | ||
114 | |||
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) | ||
118 | return i; | ||
119 | } | ||
120 | return 0; | ||
121 | }; | ||
122 | |||
123 | // Returns thePool child index for a given parent | ||
124 | |||
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) | ||
128 | return i; | ||
129 | } | ||
130 | return 0; | ||
131 | }; | ||
132 | |||
133 | // Frees address entry specified by index parameter | ||
134 | |||
135 | void FreeAddressByIndex(uint8_t index) { | ||
136 | // Zero field is reserved and should not be affected | ||
137 | if(index == 0) | ||
138 | return; | ||
139 | |||
140 | UsbDeviceAddress uda = thePool[index].address; | ||
141 | // If a hub was switched off all port addresses should be freed | ||
142 | if(uda.bmHub == 1) { | ||
143 | for(uint8_t i = 1; (i = FindChildIndex(uda, i));) | ||
144 | FreeAddressByIndex(i); | ||
145 | |||
146 | // If the hub had the last allocated address, hubCounter should be decremented | ||
147 | if(hubCounter == uda.bmAddress) | ||
148 | hubCounter--; | ||
149 | } | ||
150 | InitEntry(index); | ||
151 | } | ||
152 | |||
153 | // Initializes the whole address pool at once | ||
154 | |||
155 | void InitAllAddresses() { | ||
156 | for(uint8_t i = 1; i < MAX_DEVICES_ALLOWED; i++) | ||
157 | InitEntry(i); | ||
158 | |||
159 | hubCounter = 0; | ||
160 | }; | ||
161 | |||
162 | public: | ||
163 | |||
164 | AddressPoolImpl() : hubCounter(0) { | ||
165 | // Zero address is reserved | ||
166 | InitEntry(0); | ||
167 | |||
168 | thePool[0].address.devAddress = 0; | ||
169 | thePool[0].epinfo = &dev0ep; | ||
170 | dev0ep.epAddr = 0; | ||
171 | dev0ep.maxPktSize = 8; | ||
172 | dev0ep.epAttribs = 0; //set DATA0/1 toggles to 0 | ||
173 | dev0ep.bmNakPower = USB_NAK_MAX_POWER; | ||
174 | |||
175 | InitAllAddresses(); | ||
176 | }; | ||
177 | |||
178 | // Returns a pointer to a specified address entry | ||
179 | |||
180 | virtual UsbDevice* GetUsbDevicePtr(uint8_t addr) { | ||
181 | if(!addr) | ||
182 | return thePool; | ||
183 | |||
184 | uint8_t index = FindAddressIndex(addr); | ||
185 | |||
186 | return (!index) ? NULL : thePool + index; | ||
187 | }; | ||
188 | |||
189 | // Performs an operation specified by pfunc for each addressed device | ||
190 | |||
191 | void ForEachUsbDevice(UsbDeviceHandleFunc pfunc) { | ||
192 | if(!pfunc) | ||
193 | return; | ||
194 | |||
195 | for(uint8_t i = 1; i < MAX_DEVICES_ALLOWED; i++) | ||
196 | if(thePool[i].address.devAddress) | ||
197 | pfunc(thePool + i); | ||
198 | }; | ||
199 | |||
200 | // Allocates new address | ||
201 | |||
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) | ||
209 | return 0; | ||
210 | |||
211 | if(is_hub && hubCounter == 7) | ||
212 | return 0; | ||
213 | |||
214 | // finds first empty address entry starting from one | ||
215 | uint8_t index = FindAddressIndex(0); | ||
216 | |||
217 | if(!index) // if empty entry is not found | ||
218 | return 0; | ||
219 | |||
220 | if(_parent.devAddress == 0) { | ||
221 | if(is_hub) { | ||
222 | thePool[index].address.devAddress = 0x41; | ||
223 | hubCounter++; | ||
224 | } else | ||
225 | thePool[index].address.devAddress = 1; | ||
226 | |||
227 | return thePool[index].address.devAddress; | ||
228 | } | ||
229 | |||
230 | UsbDeviceAddress addr; | ||
231 | addr.devAddress = 0; // Ensure all bits are zero | ||
232 | addr.bmParent = _parent.bmAddress; | ||
233 | if(is_hub) { | ||
234 | addr.bmHub = 1; | ||
235 | addr.bmAddress = ++hubCounter; | ||
236 | } else { | ||
237 | addr.bmHub = 0; | ||
238 | addr.bmAddress = port; | ||
239 | } | ||
240 | thePool[index].address = addr; | ||
241 | /* | ||
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); | ||
248 | */ | ||
249 | return thePool[index].address.devAddress; | ||
250 | }; | ||
251 | |||
252 | // Empties pool entry | ||
253 | |||
254 | virtual void FreeAddress(uint8_t addr) { | ||
255 | // if the root hub is disconnected all the addresses should be initialized | ||
256 | if(addr == 0x41) { | ||
257 | InitAllAddresses(); | ||
258 | return; | ||
259 | } | ||
260 | uint8_t index = FindAddressIndex(addr); | ||
261 | FreeAddressByIndex(index); | ||
262 | }; | ||
263 | |||
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() | ||
267 | //{ | ||
268 | // return hubCounter; | ||
269 | //}; | ||
270 | //uint8_t GetNumDevices() | ||
271 | //{ | ||
272 | // uint8_t counter = 0; | ||
273 | |||
274 | // for (uint8_t i=1; i<MAX_DEVICES_ALLOWED; i++) | ||
275 | // if (thePool[i].address != 0); | ||
276 | // counter ++; | ||
277 | |||
278 | // return counter; | ||
279 | //}; | ||
280 | }; | ||
281 | |||
282 | #endif // __ADDRESS_H__ | ||