diff options
Diffstat (limited to 'lib/usbhost/USB_Host_Shield_2.0/usbhub.cpp')
-rw-r--r-- | lib/usbhost/USB_Host_Shield_2.0/usbhub.cpp | 425 |
1 files changed, 425 insertions, 0 deletions
diff --git a/lib/usbhost/USB_Host_Shield_2.0/usbhub.cpp b/lib/usbhost/USB_Host_Shield_2.0/usbhub.cpp new file mode 100644 index 000000000..7fed48e78 --- /dev/null +++ b/lib/usbhost/USB_Host_Shield_2.0/usbhub.cpp | |||
@@ -0,0 +1,425 @@ | |||
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 | #include "usbhub.h" | ||
18 | |||
19 | bool USBHub::bResetInitiated = false; | ||
20 | |||
21 | USBHub::USBHub(USB *p) : | ||
22 | pUsb(p), | ||
23 | bAddress(0), | ||
24 | bNbrPorts(0), | ||
25 | //bInitState(0), | ||
26 | qNextPollTime(0), | ||
27 | bPollEnable(false) { | ||
28 | epInfo[0].epAddr = 0; | ||
29 | epInfo[0].maxPktSize = 8; | ||
30 | epInfo[0].epAttribs = 0; | ||
31 | epInfo[0].bmNakPower = USB_NAK_MAX_POWER; | ||
32 | |||
33 | epInfo[1].epAddr = 1; | ||
34 | epInfo[1].maxPktSize = 8; //kludge | ||
35 | epInfo[1].epAttribs = 0; | ||
36 | epInfo[1].bmNakPower = USB_NAK_NOWAIT; | ||
37 | |||
38 | if(pUsb) | ||
39 | pUsb->RegisterDeviceClass(this); | ||
40 | } | ||
41 | |||
42 | uint8_t USBHub::Init(uint8_t parent, uint8_t port, bool lowspeed) { | ||
43 | uint8_t buf[32]; | ||
44 | USB_DEVICE_DESCRIPTOR * udd = reinterpret_cast<USB_DEVICE_DESCRIPTOR*>(buf); | ||
45 | HubDescriptor* hd = reinterpret_cast<HubDescriptor*>(buf); | ||
46 | USB_CONFIGURATION_DESCRIPTOR * ucd = reinterpret_cast<USB_CONFIGURATION_DESCRIPTOR*>(buf); | ||
47 | uint8_t rcode; | ||
48 | UsbDevice *p = NULL; | ||
49 | EpInfo *oldep_ptr = NULL; | ||
50 | uint8_t len = 0; | ||
51 | uint16_t cd_len = 0; | ||
52 | |||
53 | //USBTRACE("\r\nHub Init Start "); | ||
54 | //D_PrintHex<uint8_t > (bInitState, 0x80); | ||
55 | |||
56 | AddressPool &addrPool = pUsb->GetAddressPool(); | ||
57 | |||
58 | //switch (bInitState) { | ||
59 | // case 0: | ||
60 | if(bAddress) | ||
61 | return USB_ERROR_CLASS_INSTANCE_ALREADY_IN_USE; | ||
62 | |||
63 | // Get pointer to pseudo device with address 0 assigned | ||
64 | p = addrPool.GetUsbDevicePtr(0); | ||
65 | |||
66 | if(!p) | ||
67 | return USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL; | ||
68 | |||
69 | if(!p->epinfo) | ||
70 | return USB_ERROR_EPINFO_IS_NULL; | ||
71 | |||
72 | // Save old pointer to EP_RECORD of address 0 | ||
73 | oldep_ptr = p->epinfo; | ||
74 | |||
75 | // Temporary assign new pointer to epInfo to p->epinfo in order to avoid toggle inconsistence | ||
76 | p->epinfo = epInfo; | ||
77 | |||
78 | p->lowspeed = lowspeed; | ||
79 | |||
80 | // Get device descriptor | ||
81 | rcode = pUsb->getDevDescr(0, 0, 8, (uint8_t*)buf); | ||
82 | |||
83 | p->lowspeed = false; | ||
84 | |||
85 | if(!rcode) | ||
86 | len = (buf[0] > 32) ? 32 : buf[0]; | ||
87 | |||
88 | if(rcode) { | ||
89 | // Restore p->epinfo | ||
90 | p->epinfo = oldep_ptr; | ||
91 | return rcode; | ||
92 | } | ||
93 | |||
94 | // Extract device class from device descriptor | ||
95 | // If device class is not a hub return | ||
96 | if(udd->bDeviceClass != 0x09) | ||
97 | return USB_DEV_CONFIG_ERROR_DEVICE_NOT_SUPPORTED; | ||
98 | |||
99 | // Allocate new address according to device class | ||
100 | bAddress = addrPool.AllocAddress(parent, (udd->bDeviceClass == 0x09) ? true : false, port); | ||
101 | |||
102 | if(!bAddress) | ||
103 | return USB_ERROR_OUT_OF_ADDRESS_SPACE_IN_POOL; | ||
104 | |||
105 | // Extract Max Packet Size from the device descriptor | ||
106 | epInfo[0].maxPktSize = udd->bMaxPacketSize0; | ||
107 | |||
108 | // Assign new address to the device | ||
109 | rcode = pUsb->setAddr(0, 0, bAddress); | ||
110 | |||
111 | if(rcode) { | ||
112 | // Restore p->epinfo | ||
113 | p->epinfo = oldep_ptr; | ||
114 | addrPool.FreeAddress(bAddress); | ||
115 | bAddress = 0; | ||
116 | return rcode; | ||
117 | } | ||
118 | |||
119 | //USBTRACE2("\r\nHub address: ", bAddress ); | ||
120 | |||
121 | // Restore p->epinfo | ||
122 | p->epinfo = oldep_ptr; | ||
123 | |||
124 | if(len) | ||
125 | rcode = pUsb->getDevDescr(bAddress, 0, len, (uint8_t*)buf); | ||
126 | |||
127 | if(rcode) | ||
128 | goto FailGetDevDescr; | ||
129 | |||
130 | // Assign epInfo to epinfo pointer | ||
131 | rcode = pUsb->setEpInfoEntry(bAddress, 2, epInfo); | ||
132 | |||
133 | if(rcode) | ||
134 | goto FailSetDevTblEntry; | ||
135 | |||
136 | // bInitState = 1; | ||
137 | |||
138 | // case 1: | ||
139 | // Get hub descriptor | ||
140 | rcode = GetHubDescriptor(0, 8, buf); | ||
141 | |||
142 | if(rcode) | ||
143 | goto FailGetHubDescr; | ||
144 | |||
145 | // Save number of ports for future use | ||
146 | bNbrPorts = hd->bNbrPorts; | ||
147 | |||
148 | // bInitState = 2; | ||
149 | |||
150 | // case 2: | ||
151 | // Read configuration Descriptor in Order To Obtain Proper Configuration Value | ||
152 | rcode = pUsb->getConfDescr(bAddress, 0, 8, 0, buf); | ||
153 | |||
154 | if(!rcode) { | ||
155 | cd_len = ucd->wTotalLength; | ||
156 | rcode = pUsb->getConfDescr(bAddress, 0, cd_len, 0, buf); | ||
157 | } | ||
158 | if(rcode) | ||
159 | goto FailGetConfDescr; | ||
160 | |||
161 | // The following code is of no practical use in real life applications. | ||
162 | // It only intended for the usb protocol sniffer to properly parse hub-class requests. | ||
163 | { | ||
164 | uint8_t buf2[24]; | ||
165 | |||
166 | rcode = pUsb->getConfDescr(bAddress, 0, buf[0], 0, buf2); | ||
167 | |||
168 | if(rcode) | ||
169 | goto FailGetConfDescr; | ||
170 | } | ||
171 | |||
172 | // Set Configuration Value | ||
173 | rcode = pUsb->setConf(bAddress, 0, buf[5]); | ||
174 | |||
175 | if(rcode) | ||
176 | goto FailSetConfDescr; | ||
177 | |||
178 | // bInitState = 3; | ||
179 | |||
180 | // case 3: | ||
181 | // Power on all ports | ||
182 | for(uint8_t j = 1; j <= bNbrPorts; j++) | ||
183 | SetPortFeature(HUB_FEATURE_PORT_POWER, j, 0); //HubPortPowerOn(j); | ||
184 | |||
185 | pUsb->SetHubPreMask(); | ||
186 | bPollEnable = true; | ||
187 | // bInitState = 0; | ||
188 | //} | ||
189 | //bInitState = 0; | ||
190 | //USBTRACE("...OK\r\n"); | ||
191 | return 0; | ||
192 | |||
193 | // Oleg, No debugging?? -- xxxajk | ||
194 | FailGetDevDescr: | ||
195 | goto Fail; | ||
196 | |||
197 | FailSetDevTblEntry: | ||
198 | goto Fail; | ||
199 | |||
200 | FailGetHubDescr: | ||
201 | goto Fail; | ||
202 | |||
203 | FailGetConfDescr: | ||
204 | goto Fail; | ||
205 | |||
206 | FailSetConfDescr: | ||
207 | goto Fail; | ||
208 | |||
209 | Fail: | ||
210 | USBTRACE("...FAIL\r\n"); | ||
211 | return rcode; | ||
212 | } | ||
213 | |||
214 | uint8_t USBHub::Release() { | ||
215 | pUsb->GetAddressPool().FreeAddress(bAddress); | ||
216 | |||
217 | if(bAddress == 0x41) | ||
218 | pUsb->SetHubPreMask(); | ||
219 | |||
220 | bAddress = 0; | ||
221 | bNbrPorts = 0; | ||
222 | qNextPollTime = 0; | ||
223 | bPollEnable = false; | ||
224 | return 0; | ||
225 | } | ||
226 | |||
227 | uint8_t USBHub::Poll() { | ||
228 | uint8_t rcode = 0; | ||
229 | |||
230 | if(!bPollEnable) | ||
231 | return 0; | ||
232 | |||
233 | if(((long)(millis() - qNextPollTime) >= 0L)) { | ||
234 | rcode = CheckHubStatus(); | ||
235 | qNextPollTime = millis() + 100; | ||
236 | } | ||
237 | return rcode; | ||
238 | } | ||
239 | |||
240 | uint8_t USBHub::CheckHubStatus() { | ||
241 | uint8_t rcode; | ||
242 | uint8_t buf[8]; | ||
243 | uint16_t read = 1; | ||
244 | |||
245 | rcode = pUsb->inTransfer(bAddress, 1, &read, buf); | ||
246 | |||
247 | if(rcode) | ||
248 | return rcode; | ||
249 | |||
250 | //if (buf[0] & 0x01) // Hub Status Change | ||
251 | //{ | ||
252 | // pUsb->PrintHubStatus(addr); | ||
253 | // rcode = GetHubStatus(1, 0, 1, 4, buf); | ||
254 | // if (rcode) | ||
255 | // { | ||
256 | // USB_HOST_SERIAL.print("GetHubStatus Error"); | ||
257 | // USB_HOST_SERIAL.println(rcode, HEX); | ||
258 | // return rcode; | ||
259 | // } | ||
260 | //} | ||
261 | for(uint8_t port = 1, mask = 0x02; port < 8; mask <<= 1, port++) { | ||
262 | if(buf[0] & mask) { | ||
263 | HubEvent evt; | ||
264 | evt.bmEvent = 0; | ||
265 | |||
266 | rcode = GetPortStatus(port, 4, evt.evtBuff); | ||
267 | |||
268 | if(rcode) | ||
269 | continue; | ||
270 | |||
271 | rcode = PortStatusChange(port, evt); | ||
272 | |||
273 | if(rcode == HUB_ERROR_PORT_HAS_BEEN_RESET) | ||
274 | return 0; | ||
275 | |||
276 | if(rcode) | ||
277 | return rcode; | ||
278 | } | ||
279 | } // for | ||
280 | |||
281 | for(uint8_t port = 1; port <= bNbrPorts; port++) { | ||
282 | HubEvent evt; | ||
283 | evt.bmEvent = 0; | ||
284 | |||
285 | rcode = GetPortStatus(port, 4, evt.evtBuff); | ||
286 | |||
287 | if(rcode) | ||
288 | continue; | ||
289 | |||
290 | if((evt.bmStatus & bmHUB_PORT_STATE_CHECK_DISABLED) != bmHUB_PORT_STATE_DISABLED) | ||
291 | continue; | ||
292 | |||
293 | // Emulate connection event for the port | ||
294 | evt.bmChange |= bmHUB_PORT_STATUS_C_PORT_CONNECTION; | ||
295 | |||
296 | rcode = PortStatusChange(port, evt); | ||
297 | |||
298 | if(rcode == HUB_ERROR_PORT_HAS_BEEN_RESET) | ||
299 | return 0; | ||
300 | |||
301 | if(rcode) | ||
302 | return rcode; | ||
303 | } // for | ||
304 | return 0; | ||
305 | } | ||
306 | |||
307 | void USBHub::ResetHubPort(uint8_t port) { | ||
308 | HubEvent evt; | ||
309 | evt.bmEvent = 0; | ||
310 | uint8_t rcode; | ||
311 | |||
312 | ClearPortFeature(HUB_FEATURE_C_PORT_ENABLE, port, 0); | ||
313 | ClearPortFeature(HUB_FEATURE_C_PORT_CONNECTION, port, 0); | ||
314 | SetPortFeature(HUB_FEATURE_PORT_RESET, port, 0); | ||
315 | |||
316 | |||
317 | for(int i = 0; i < 3; i++) { | ||
318 | rcode = GetPortStatus(port, 4, evt.evtBuff); | ||
319 | if(rcode) break; // Some kind of error, bail. | ||
320 | if(evt.bmEvent == bmHUB_PORT_EVENT_RESET_COMPLETE || evt.bmEvent == bmHUB_PORT_EVENT_LS_RESET_COMPLETE) { | ||
321 | break; | ||
322 | } | ||
323 | delay(100); // simulate polling. | ||
324 | } | ||
325 | ClearPortFeature(HUB_FEATURE_C_PORT_RESET, port, 0); | ||
326 | ClearPortFeature(HUB_FEATURE_C_PORT_CONNECTION, port, 0); | ||
327 | delay(20); | ||
328 | } | ||
329 | |||
330 | uint8_t USBHub::PortStatusChange(uint8_t port, HubEvent &evt) { | ||
331 | switch(evt.bmEvent) { | ||
332 | // Device connected event | ||
333 | case bmHUB_PORT_EVENT_CONNECT: | ||
334 | case bmHUB_PORT_EVENT_LS_CONNECT: | ||
335 | if(bResetInitiated) | ||
336 | return 0; | ||
337 | |||
338 | ClearPortFeature(HUB_FEATURE_C_PORT_ENABLE, port, 0); | ||
339 | ClearPortFeature(HUB_FEATURE_C_PORT_CONNECTION, port, 0); | ||
340 | SetPortFeature(HUB_FEATURE_PORT_RESET, port, 0); | ||
341 | bResetInitiated = true; | ||
342 | return HUB_ERROR_PORT_HAS_BEEN_RESET; | ||
343 | |||
344 | // Device disconnected event | ||
345 | case bmHUB_PORT_EVENT_DISCONNECT: | ||
346 | ClearPortFeature(HUB_FEATURE_C_PORT_ENABLE, port, 0); | ||
347 | ClearPortFeature(HUB_FEATURE_C_PORT_CONNECTION, port, 0); | ||
348 | bResetInitiated = false; | ||
349 | |||
350 | UsbDeviceAddress a; | ||
351 | a.devAddress = 0; | ||
352 | a.bmHub = 0; | ||
353 | a.bmParent = bAddress; | ||
354 | a.bmAddress = port; | ||
355 | pUsb->ReleaseDevice(a.devAddress); | ||
356 | return 0; | ||
357 | |||
358 | // Reset complete event | ||
359 | case bmHUB_PORT_EVENT_RESET_COMPLETE: | ||
360 | case bmHUB_PORT_EVENT_LS_RESET_COMPLETE: | ||
361 | ClearPortFeature(HUB_FEATURE_C_PORT_RESET, port, 0); | ||
362 | ClearPortFeature(HUB_FEATURE_C_PORT_CONNECTION, port, 0); | ||
363 | |||
364 | delay(20); | ||
365 | |||
366 | a.devAddress = bAddress; | ||
367 | |||
368 | pUsb->Configuring(a.bmAddress, port, (evt.bmStatus & bmHUB_PORT_STATUS_PORT_LOW_SPEED)); | ||
369 | bResetInitiated = false; | ||
370 | break; | ||
371 | |||
372 | } // switch (evt.bmEvent) | ||
373 | return 0; | ||
374 | } | ||
375 | |||
376 | void PrintHubPortStatus(USBHub *hubptr, uint8_t addr, uint8_t port, bool print_changes) { | ||
377 | uint8_t rcode = 0; | ||
378 | HubEvent evt; | ||
379 | |||
380 | rcode = hubptr->GetPortStatus(port, 4, evt.evtBuff); | ||
381 | |||
382 | if(rcode) { | ||
383 | USB_HOST_SERIAL.println("ERROR!"); | ||
384 | return; | ||
385 | } | ||
386 | USB_HOST_SERIAL.print("\r\nPort "); | ||
387 | USB_HOST_SERIAL.println(port, DEC); | ||
388 | |||
389 | USB_HOST_SERIAL.println("Status"); | ||
390 | USB_HOST_SERIAL.print("CONNECTION:\t"); | ||
391 | USB_HOST_SERIAL.println((evt.bmStatus & bmHUB_PORT_STATUS_PORT_CONNECTION) > 0, DEC); | ||
392 | USB_HOST_SERIAL.print("ENABLE:\t\t"); | ||
393 | USB_HOST_SERIAL.println((evt.bmStatus & bmHUB_PORT_STATUS_PORT_ENABLE) > 0, DEC); | ||
394 | USB_HOST_SERIAL.print("SUSPEND:\t"); | ||
395 | USB_HOST_SERIAL.println((evt.bmStatus & bmHUB_PORT_STATUS_PORT_SUSPEND) > 0, DEC); | ||
396 | USB_HOST_SERIAL.print("OVER_CURRENT:\t"); | ||
397 | USB_HOST_SERIAL.println((evt.bmStatus & bmHUB_PORT_STATUS_PORT_OVER_CURRENT) > 0, DEC); | ||
398 | USB_HOST_SERIAL.print("RESET:\t\t"); | ||
399 | USB_HOST_SERIAL.println((evt.bmStatus & bmHUB_PORT_STATUS_PORT_RESET) > 0, DEC); | ||
400 | USB_HOST_SERIAL.print("POWER:\t\t"); | ||
401 | USB_HOST_SERIAL.println((evt.bmStatus & bmHUB_PORT_STATUS_PORT_POWER) > 0, DEC); | ||
402 | USB_HOST_SERIAL.print("LOW_SPEED:\t"); | ||
403 | USB_HOST_SERIAL.println((evt.bmStatus & bmHUB_PORT_STATUS_PORT_LOW_SPEED) > 0, DEC); | ||
404 | USB_HOST_SERIAL.print("HIGH_SPEED:\t"); | ||
405 | USB_HOST_SERIAL.println((evt.bmStatus & bmHUB_PORT_STATUS_PORT_HIGH_SPEED) > 0, DEC); | ||
406 | USB_HOST_SERIAL.print("TEST:\t\t"); | ||
407 | USB_HOST_SERIAL.println((evt.bmStatus & bmHUB_PORT_STATUS_PORT_TEST) > 0, DEC); | ||
408 | USB_HOST_SERIAL.print("INDICATOR:\t"); | ||
409 | USB_HOST_SERIAL.println((evt.bmStatus & bmHUB_PORT_STATUS_PORT_INDICATOR) > 0, DEC); | ||
410 | |||
411 | if(!print_changes) | ||
412 | return; | ||
413 | |||
414 | USB_HOST_SERIAL.println("\r\nChange"); | ||
415 | USB_HOST_SERIAL.print("CONNECTION:\t"); | ||
416 | USB_HOST_SERIAL.println((evt.bmChange & bmHUB_PORT_STATUS_C_PORT_CONNECTION) > 0, DEC); | ||
417 | USB_HOST_SERIAL.print("ENABLE:\t\t"); | ||
418 | USB_HOST_SERIAL.println((evt.bmChange & bmHUB_PORT_STATUS_C_PORT_ENABLE) > 0, DEC); | ||
419 | USB_HOST_SERIAL.print("SUSPEND:\t"); | ||
420 | USB_HOST_SERIAL.println((evt.bmChange & bmHUB_PORT_STATUS_C_PORT_SUSPEND) > 0, DEC); | ||
421 | USB_HOST_SERIAL.print("OVER_CURRENT:\t"); | ||
422 | USB_HOST_SERIAL.println((evt.bmChange & bmHUB_PORT_STATUS_C_PORT_OVER_CURRENT) > 0, DEC); | ||
423 | USB_HOST_SERIAL.print("RESET:\t\t"); | ||
424 | USB_HOST_SERIAL.println((evt.bmChange & bmHUB_PORT_STATUS_C_PORT_RESET) > 0, DEC); | ||
425 | } | ||