USB Host Shield 2.0
 All Classes Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
usbhub.cpp
Go to the documentation of this file.
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 
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  uint8_t rcode;
45  UsbDevice *p = NULL;
46  EpInfo *oldep_ptr = NULL;
47  uint8_t len = 0;
48  uint16_t cd_len = 0;
49 
50  //USBTRACE("\r\nHub Init Start");
51 
52  AddressPool &addrPool = pUsb->GetAddressPool();
53 
54  switch (bInitState) {
55  case 0:
56  if (bAddress)
58 
59  // Get pointer to pseudo device with address 0 assigned
60  p = addrPool.GetUsbDevicePtr(0);
61 
62  if (!p)
64 
65  if (!p->epinfo)
67 
68  // Save old pointer to EP_RECORD of address 0
69  oldep_ptr = p->epinfo;
70 
71  // Temporary assign new pointer to epInfo to p->epinfo in order to avoid toggle inconsistence
72  p->epinfo = epInfo;
73 
74  p->lowspeed = lowspeed;
75 
76  // Get device descriptor
77  rcode = pUsb->getDevDescr(0, 0, 8, (uint8_t*)buf);
78 
79  p->lowspeed = false;
80 
81  if (!rcode)
82  len = (buf[0] > 32) ? 32 : buf[0];
83 
84  if (rcode) {
85  // Restore p->epinfo
86  p->epinfo = oldep_ptr;
87  return rcode;
88  }
89 
90  // Extract device class from device descriptor
91  // If device class is not a hub return
92  if (((USB_DEVICE_DESCRIPTOR*)buf)->bDeviceClass != 0x09)
94 
95  // Allocate new address according to device class
96  bAddress = addrPool.AllocAddress(parent, (((USB_DEVICE_DESCRIPTOR*)buf)->bDeviceClass == 0x09) ? true : false, port);
97 
98  if (!bAddress)
100 
101  // Extract Max Packet Size from the device descriptor
102  epInfo[0].maxPktSize = ((USB_DEVICE_DESCRIPTOR*)buf)->bMaxPacketSize0;
103 
104  // Assign new address to the device
105  rcode = pUsb->setAddr(0, 0, bAddress);
106 
107  if (rcode) {
108  // Restore p->epinfo
109  p->epinfo = oldep_ptr;
110  addrPool.FreeAddress(bAddress);
111  bAddress = 0;
112  return rcode;
113  }
114 
115  //USBTRACE2("\r\nHub address: ", bAddress );
116 
117  // Restore p->epinfo
118  p->epinfo = oldep_ptr;
119 
120  if (len)
121  rcode = pUsb->getDevDescr(bAddress, 0, len, (uint8_t*)buf);
122 
123  if (rcode)
124  goto FailGetDevDescr;
125 
126  // Assign epInfo to epinfo pointer
127  rcode = pUsb->setEpInfoEntry(bAddress, 2, epInfo);
128 
129  if (rcode)
130  goto FailSetDevTblEntry;
131 
132  bInitState = 1;
133 
134  case 1:
135  // Get hub descriptor
136  rcode = GetHubDescriptor(0, 8, buf);
137 
138  if (rcode)
139  goto FailGetHubDescr;
140 
141  // Save number of ports for future use
142  bNbrPorts = ((HubDescriptor*)buf)->bNbrPorts;
143 
144  bInitState = 2;
145 
146  case 2:
147  // Read configuration Descriptor in Order To Obtain Proper Configuration Value
148  rcode = pUsb->getConfDescr(bAddress, 0, 8, 0, buf);
149 
150  if (!rcode) {
151  cd_len = ((USB_CONFIGURATION_DESCRIPTOR*)buf)->wTotalLength;
152  rcode = pUsb->getConfDescr(bAddress, 0, cd_len, 0, buf);
153  }
154  if (rcode)
155  goto FailGetConfDescr;
156 
157  // The following code is of no practical use in real life applications.
158  // It only intended for the usb protocol sniffer to properly parse hub-class requests.
159  {
160  uint8_t buf2[24];
161 
162  rcode = pUsb->getConfDescr(bAddress, 0, buf[0], 0, buf2);
163 
164  if (rcode)
165  goto FailGetConfDescr;
166  }
167 
168  // Set Configuration Value
169  rcode = pUsb->setConf(bAddress, 0, buf[5]);
170 
171  if (rcode)
172  goto FailSetConfDescr;
173 
174  bInitState = 3;
175 
176  case 3:
177  // Power on all ports
178  for (uint8_t j = 1; j <= bNbrPorts; j++)
179  SetPortFeature(HUB_FEATURE_PORT_POWER, j, 0); //HubPortPowerOn(j);
180 
181  pUsb->SetHubPreMask();
182  bPollEnable = true;
183  bInitState = 0;
184  }
185  bInitState = 0;
186  return 0;
187 
188 // Oleg, No debugging?? -- xxxajk
189 FailGetDevDescr:
190  goto Fail;
191 
192 FailSetDevTblEntry:
193  goto Fail;
194 
195 FailGetHubDescr:
196  goto Fail;
197 
198 FailGetConfDescr:
199  goto Fail;
200 
201 FailSetConfDescr:
202  goto Fail;
203 
204 Fail:
205  return rcode;
206 }
207 
208 uint8_t USBHub::Release() {
209  pUsb->GetAddressPool().FreeAddress(bAddress);
210 
211  if (bAddress == 0x41)
212  pUsb->SetHubPreMask();
213 
214  bAddress = 0;
215  bNbrPorts = 0;
216  qNextPollTime = 0;
217  bPollEnable = false;
218  return 0;
219 }
220 
221 uint8_t USBHub::Poll() {
222  uint8_t rcode = 0;
223 
224  if (!bPollEnable)
225  return 0;
226 
227  if (qNextPollTime <= millis()) {
228  rcode = CheckHubStatus();
229  qNextPollTime = millis() + 100;
230  }
231  return rcode;
232 }
233 
234 uint8_t USBHub::CheckHubStatus() {
235  uint8_t rcode;
236  uint8_t buf[8];
237  uint16_t read = 1;
238 
239  rcode = pUsb->inTransfer(bAddress, 1, &read, buf);
240 
241  if (rcode)
242  return rcode;
243 
244  if (buf[0] & 0x01) // Hub Status Change
245  {
246  //pUsb->PrintHubStatus(addr);
247  //rcode = GetHubStatus(1, 0, 1, 4, buf);
248  //if (rcode)
249  //{
250  // Serial.print("GetHubStatus Error");
251  // Serial.println(rcode, HEX);
252  // return rcode;
253  //}
254  }
255  for (uint8_t port = 1, mask = 0x02; port < 8; mask <<= 1, port++) {
256  if (buf[0] & mask) {
257  HubEvent evt;
258  evt.bmEvent = 0;
259 
260  rcode = GetPortStatus(port, 4, evt.evtBuff);
261 
262  if (rcode)
263  continue;
264 
265  rcode = PortStatusChange(port, evt);
266 
267  if (rcode == HUB_ERROR_PORT_HAS_BEEN_RESET)
268  return 0;
269 
270  if (rcode)
271  return rcode;
272  }
273  } // for
274 
275  for (uint8_t port = 1; port <= bNbrPorts; port++) {
276  HubEvent evt;
277  evt.bmEvent = 0;
278 
279  rcode = GetPortStatus(port, 4, evt.evtBuff);
280 
281  if (rcode)
282  continue;
283 
285  continue;
286 
287  // Emulate connection event for the port
289 
290  rcode = PortStatusChange(port, evt);
291 
292  if (rcode == HUB_ERROR_PORT_HAS_BEEN_RESET)
293  return 0;
294 
295  if (rcode)
296  return rcode;
297  } // for
298  return 0;
299 }
300 
301 uint8_t USBHub::PortStatusChange(uint8_t port, HubEvent &evt) {
302  switch (evt.bmEvent) {
303  // Device connected event
306  if (bResetInitiated)
307  return 0;
308 
312  bResetInitiated = true;
314 
315  // Device disconnected event
319  bResetInitiated = false;
320 
322  a.bmHub = 0;
323  a.bmParent = bAddress;
324  a.bmAddress = port;
325  pUsb->ReleaseDevice(a.devAddress);
326  return 0;
327 
328  // Reset complete event
333 
334  delay(20);
335 
336  a.devAddress = bAddress;
337 
339  bResetInitiated = false;
340  break;
341 
342  } // switch (evt.bmEvent)
343  return 0;
344 }
345 
346 void PrintHubPortStatus(USBHub *hubptr, uint8_t addr, uint8_t port, bool print_changes) {
347  uint8_t rcode = 0;
348  HubEvent evt;
349 
350  rcode = hubptr->GetPortStatus(port, 4, evt.evtBuff);
351 
352  if (rcode) {
353  Serial.println("ERROR!");
354  return;
355  }
356  Serial.print("\r\nPort ");
357  Serial.println(port, DEC);
358 
359  Serial.println("Status");
360  Serial.print("CONNECTION:\t");
361  Serial.println((evt.bmStatus & bmHUB_PORT_STATUS_PORT_CONNECTION) > 0, DEC);
362  Serial.print("ENABLE:\t\t");
363  Serial.println((evt.bmStatus & bmHUB_PORT_STATUS_PORT_ENABLE) > 0, DEC);
364  Serial.print("SUSPEND:\t");
365  Serial.println((evt.bmStatus & bmHUB_PORT_STATUS_PORT_SUSPEND) > 0, DEC);
366  Serial.print("OVER_CURRENT:\t");
367  Serial.println((evt.bmStatus & bmHUB_PORT_STATUS_PORT_OVER_CURRENT) > 0, DEC);
368  Serial.print("RESET:\t\t");
369  Serial.println((evt.bmStatus & bmHUB_PORT_STATUS_PORT_RESET) > 0, DEC);
370  Serial.print("POWER:\t\t");
371  Serial.println((evt.bmStatus & bmHUB_PORT_STATUS_PORT_POWER) > 0, DEC);
372  Serial.print("LOW_SPEED:\t");
373  Serial.println((evt.bmStatus & bmHUB_PORT_STATUS_PORT_LOW_SPEED) > 0, DEC);
374  Serial.print("HIGH_SPEED:\t");
375  Serial.println((evt.bmStatus & bmHUB_PORT_STATUS_PORT_HIGH_SPEED) > 0, DEC);
376  Serial.print("TEST:\t\t");
377  Serial.println((evt.bmStatus & bmHUB_PORT_STATUS_PORT_TEST) > 0, DEC);
378  Serial.print("INDICATOR:\t");
379  Serial.println((evt.bmStatus & bmHUB_PORT_STATUS_PORT_INDICATOR) > 0, DEC);
380 
381  if (!print_changes)
382  return;
383 
384  Serial.println("\r\nChange");
385  Serial.print("CONNECTION:\t");
386  Serial.println((evt.bmChange & bmHUB_PORT_STATUS_C_PORT_CONNECTION) > 0, DEC);
387  Serial.print("ENABLE:\t\t");
388  Serial.println((evt.bmChange & bmHUB_PORT_STATUS_C_PORT_ENABLE) > 0, DEC);
389  Serial.print("SUSPEND:\t");
390  Serial.println((evt.bmChange & bmHUB_PORT_STATUS_C_PORT_SUSPEND) > 0, DEC);
391  Serial.print("OVER_CURRENT:\t");
392  Serial.println((evt.bmChange & bmHUB_PORT_STATUS_C_PORT_OVER_CURRENT) > 0, DEC);
393  Serial.print("RESET:\t\t");
394  Serial.println((evt.bmChange & bmHUB_PORT_STATUS_C_PORT_RESET) > 0, DEC);
395 }