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
19 bool USBHub::bResetInitiated
= false;
21 USBHub::USBHub(USB
*p
) :
29 epInfo
[0].maxPktSize
= 8;
30 epInfo
[0].epAttribs
= 0;
31 epInfo
[0].bmNakPower
= USB_NAK_MAX_POWER
;
34 epInfo
[1].maxPktSize
= 8; //kludge
35 epInfo
[1].epAttribs
= 0;
36 epInfo
[1].bmNakPower
= USB_NAK_NOWAIT
;
39 pUsb
->RegisterDeviceClass(this);
42 uint8_t USBHub::Init(uint8_t parent
, uint8_t port
, bool lowspeed
) {
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
);
49 EpInfo
*oldep_ptr
= NULL
;
53 //USBTRACE("\r\nHub Init Start ");
54 //D_PrintHex<uint8_t > (bInitState, 0x80);
56 AddressPool
&addrPool
= pUsb
->GetAddressPool();
58 //switch (bInitState) {
61 return USB_ERROR_CLASS_INSTANCE_ALREADY_IN_USE
;
63 // Get pointer to pseudo device with address 0 assigned
64 p
= addrPool
.GetUsbDevicePtr(0);
67 return USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL
;
70 return USB_ERROR_EPINFO_IS_NULL
;
72 // Save old pointer to EP_RECORD of address 0
73 oldep_ptr
= p
->epinfo
;
75 // Temporary assign new pointer to epInfo to p->epinfo in order to avoid toggle inconsistence
78 p
->lowspeed
= lowspeed
;
80 // Get device descriptor
81 rcode
= pUsb
->getDevDescr(0, 0, 8, (uint8_t*)buf
);
86 len
= (buf
[0] > 32) ? 32 : buf
[0];
90 p
->epinfo
= oldep_ptr
;
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
;
99 // Allocate new address according to device class
100 bAddress
= addrPool
.AllocAddress(parent
, (udd
->bDeviceClass
== 0x09) ? true : false, port
);
103 return USB_ERROR_OUT_OF_ADDRESS_SPACE_IN_POOL
;
105 // Extract Max Packet Size from the device descriptor
106 epInfo
[0].maxPktSize
= udd
->bMaxPacketSize0
;
108 // Assign new address to the device
109 rcode
= pUsb
->setAddr(0, 0, bAddress
);
113 p
->epinfo
= oldep_ptr
;
114 addrPool
.FreeAddress(bAddress
);
119 //USBTRACE2("\r\nHub address: ", bAddress );
122 p
->epinfo
= oldep_ptr
;
125 rcode
= pUsb
->getDevDescr(bAddress
, 0, len
, (uint8_t*)buf
);
128 goto FailGetDevDescr
;
130 // Assign epInfo to epinfo pointer
131 rcode
= pUsb
->setEpInfoEntry(bAddress
, 2, epInfo
);
134 goto FailSetDevTblEntry
;
139 // Get hub descriptor
140 rcode
= GetHubDescriptor(0, 8, buf
);
143 goto FailGetHubDescr
;
145 // Save number of ports for future use
146 bNbrPorts
= hd
->bNbrPorts
;
151 // Read configuration Descriptor in Order To Obtain Proper Configuration Value
152 rcode
= pUsb
->getConfDescr(bAddress
, 0, 8, 0, buf
);
155 cd_len
= ucd
->wTotalLength
;
156 rcode
= pUsb
->getConfDescr(bAddress
, 0, cd_len
, 0, buf
);
159 goto FailGetConfDescr
;
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.
166 rcode
= pUsb
->getConfDescr(bAddress
, 0, buf
[0], 0, buf2
);
169 goto FailGetConfDescr
;
172 // Set Configuration Value
173 rcode
= pUsb
->setConf(bAddress
, 0, buf
[5]);
176 goto FailSetConfDescr
;
181 // Power on all ports
182 for(uint8_t j
= 1; j
<= bNbrPorts
; j
++)
183 SetPortFeature(HUB_FEATURE_PORT_POWER
, j
, 0); //HubPortPowerOn(j);
185 pUsb
->SetHubPreMask();
190 //USBTRACE("...OK\r\n");
193 // Oleg, No debugging?? -- xxxajk
210 USBTRACE("...FAIL\r\n");
214 uint8_t USBHub::Release() {
215 pUsb
->GetAddressPool().FreeAddress(bAddress
);
218 pUsb
->SetHubPreMask();
227 uint8_t USBHub::Poll() {
233 if(((long)(millis() - qNextPollTime
) >= 0L)) {
234 rcode
= CheckHubStatus();
235 qNextPollTime
= millis() + 100;
240 uint8_t USBHub::CheckHubStatus() {
245 rcode
= pUsb
->inTransfer(bAddress
, 1, &read
, buf
);
250 //if (buf[0] & 0x01) // Hub Status Change
252 // pUsb->PrintHubStatus(addr);
253 // rcode = GetHubStatus(1, 0, 1, 4, buf);
256 // USB_HOST_SERIAL.print("GetHubStatus Error");
257 // USB_HOST_SERIAL.println(rcode, HEX);
261 for(uint8_t port
= 1, mask
= 0x02; port
< 8; mask
<<= 1, port
++) {
266 rcode
= GetPortStatus(port
, 4, evt
.evtBuff
);
271 rcode
= PortStatusChange(port
, evt
);
273 if(rcode
== HUB_ERROR_PORT_HAS_BEEN_RESET
)
281 for(uint8_t port
= 1; port
<= bNbrPorts
; port
++) {
285 rcode
= GetPortStatus(port
, 4, evt
.evtBuff
);
290 if((evt
.bmStatus
& bmHUB_PORT_STATE_CHECK_DISABLED
) != bmHUB_PORT_STATE_DISABLED
)
293 // Emulate connection event for the port
294 evt
.bmChange
|= bmHUB_PORT_STATUS_C_PORT_CONNECTION
;
296 rcode
= PortStatusChange(port
, evt
);
298 if(rcode
== HUB_ERROR_PORT_HAS_BEEN_RESET
)
307 void USBHub::ResetHubPort(uint8_t port
) {
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);
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
) {
323 delay(100); // simulate polling.
325 ClearPortFeature(HUB_FEATURE_C_PORT_RESET
, port
, 0);
326 ClearPortFeature(HUB_FEATURE_C_PORT_CONNECTION
, port
, 0);
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
:
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
;
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;
353 a
.bmParent
= bAddress
;
355 pUsb
->ReleaseDevice(a
.devAddress
);
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);
366 a
.devAddress
= bAddress
;
368 pUsb
->Configuring(a
.bmAddress
, port
, (evt
.bmStatus
& bmHUB_PORT_STATUS_PORT_LOW_SPEED
));
369 bResetInitiated
= false;
372 } // switch (evt.bmEvent)
376 void PrintHubPortStatus(USBHub
*hubptr
, uint8_t addr
, uint8_t port
, bool print_changes
) {
380 rcode
= hubptr
->GetPortStatus(port
, 4, evt
.evtBuff
);
383 USB_HOST_SERIAL
.println("ERROR!");
386 USB_HOST_SERIAL
.print("\r\nPort ");
387 USB_HOST_SERIAL
.println(port
, DEC
);
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
);
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
);