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