You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
This repo is archived. You can view files and clone it, but cannot push or open issues/pull-requests.

usbhub.cpp 14KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425
  1. /* Copyright (C) 2011 Circuits At Home, LTD. All rights reserved.
  2. This software may be distributed and modified under the terms of the GNU
  3. General Public License version 2 (GPL2) as published by the Free Software
  4. Foundation and appearing in the file GPL2.TXT included in the packaging of
  5. this file. Please note that GPL2 Section 2[b] requires that all works based
  6. on this software must also be made publicly available under the terms of
  7. the GPL2 ("Copyleft").
  8. Contact information
  9. -------------------
  10. Circuits At Home, LTD
  11. Web : http://www.circuitsathome.com
  12. e-mail : [email protected]
  13. */
  14. #include "usbhub.h"
  15. bool USBHub::bResetInitiated = false;
  16. USBHub::USBHub(USB *p) :
  17. pUsb(p),
  18. bAddress(0),
  19. bNbrPorts(0),
  20. //bInitState(0),
  21. qNextPollTime(0),
  22. bPollEnable(false) {
  23. epInfo[0].epAddr = 0;
  24. epInfo[0].maxPktSize = 8;
  25. epInfo[0].epAttribs = 0;
  26. epInfo[0].bmNakPower = USB_NAK_MAX_POWER;
  27. epInfo[1].epAddr = 1;
  28. epInfo[1].maxPktSize = 8; //kludge
  29. epInfo[1].epAttribs = 0;
  30. epInfo[1].bmNakPower = USB_NAK_NOWAIT;
  31. if(pUsb)
  32. pUsb->RegisterDeviceClass(this);
  33. }
  34. uint8_t USBHub::Init(uint8_t parent, uint8_t port, bool lowspeed) {
  35. uint8_t buf[32];
  36. USB_DEVICE_DESCRIPTOR * udd = reinterpret_cast<USB_DEVICE_DESCRIPTOR*>(buf);
  37. HubDescriptor* hd = reinterpret_cast<HubDescriptor*>(buf);
  38. USB_CONFIGURATION_DESCRIPTOR * ucd = reinterpret_cast<USB_CONFIGURATION_DESCRIPTOR*>(buf);
  39. uint8_t rcode;
  40. UsbDevice *p = NULL;
  41. EpInfo *oldep_ptr = NULL;
  42. uint8_t len = 0;
  43. uint16_t cd_len = 0;
  44. //USBTRACE("\r\nHub Init Start ");
  45. //D_PrintHex<uint8_t > (bInitState, 0x80);
  46. AddressPool &addrPool = pUsb->GetAddressPool();
  47. //switch (bInitState) {
  48. // case 0:
  49. if(bAddress)
  50. return USB_ERROR_CLASS_INSTANCE_ALREADY_IN_USE;
  51. // Get pointer to pseudo device with address 0 assigned
  52. p = addrPool.GetUsbDevicePtr(0);
  53. if(!p)
  54. return USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL;
  55. if(!p->epinfo)
  56. return USB_ERROR_EPINFO_IS_NULL;
  57. // Save old pointer to EP_RECORD of address 0
  58. oldep_ptr = p->epinfo;
  59. // Temporary assign new pointer to epInfo to p->epinfo in order to avoid toggle inconsistence
  60. p->epinfo = epInfo;
  61. p->lowspeed = lowspeed;
  62. // Get device descriptor
  63. rcode = pUsb->getDevDescr(0, 0, 8, (uint8_t*)buf);
  64. p->lowspeed = false;
  65. if(!rcode)
  66. len = (buf[0] > 32) ? 32 : buf[0];
  67. if(rcode) {
  68. // Restore p->epinfo
  69. p->epinfo = oldep_ptr;
  70. return rcode;
  71. }
  72. // Extract device class from device descriptor
  73. // If device class is not a hub return
  74. if(udd->bDeviceClass != 0x09)
  75. return USB_DEV_CONFIG_ERROR_DEVICE_NOT_SUPPORTED;
  76. // Allocate new address according to device class
  77. bAddress = addrPool.AllocAddress(parent, (udd->bDeviceClass == 0x09) ? true : false, port);
  78. if(!bAddress)
  79. return USB_ERROR_OUT_OF_ADDRESS_SPACE_IN_POOL;
  80. // Extract Max Packet Size from the device descriptor
  81. epInfo[0].maxPktSize = udd->bMaxPacketSize0;
  82. // Assign new address to the device
  83. rcode = pUsb->setAddr(0, 0, bAddress);
  84. if(rcode) {
  85. // Restore p->epinfo
  86. p->epinfo = oldep_ptr;
  87. addrPool.FreeAddress(bAddress);
  88. bAddress = 0;
  89. return rcode;
  90. }
  91. //USBTRACE2("\r\nHub address: ", bAddress );
  92. // Restore p->epinfo
  93. p->epinfo = oldep_ptr;
  94. if(len)
  95. rcode = pUsb->getDevDescr(bAddress, 0, len, (uint8_t*)buf);
  96. if(rcode)
  97. goto FailGetDevDescr;
  98. // Assign epInfo to epinfo pointer
  99. rcode = pUsb->setEpInfoEntry(bAddress, 2, epInfo);
  100. if(rcode)
  101. goto FailSetDevTblEntry;
  102. // bInitState = 1;
  103. // case 1:
  104. // Get hub descriptor
  105. rcode = GetHubDescriptor(0, 8, buf);
  106. if(rcode)
  107. goto FailGetHubDescr;
  108. // Save number of ports for future use
  109. bNbrPorts = hd->bNbrPorts;
  110. // bInitState = 2;
  111. // case 2:
  112. // Read configuration Descriptor in Order To Obtain Proper Configuration Value
  113. rcode = pUsb->getConfDescr(bAddress, 0, 8, 0, buf);
  114. if(!rcode) {
  115. cd_len = ucd->wTotalLength;
  116. rcode = pUsb->getConfDescr(bAddress, 0, cd_len, 0, buf);
  117. }
  118. if(rcode)
  119. goto FailGetConfDescr;
  120. // The following code is of no practical use in real life applications.
  121. // It only intended for the usb protocol sniffer to properly parse hub-class requests.
  122. {
  123. uint8_t buf2[24];
  124. rcode = pUsb->getConfDescr(bAddress, 0, buf[0], 0, buf2);
  125. if(rcode)
  126. goto FailGetConfDescr;
  127. }
  128. // Set Configuration Value
  129. rcode = pUsb->setConf(bAddress, 0, buf[5]);
  130. if(rcode)
  131. goto FailSetConfDescr;
  132. // bInitState = 3;
  133. // case 3:
  134. // Power on all ports
  135. for(uint8_t j = 1; j <= bNbrPorts; j++)
  136. SetPortFeature(HUB_FEATURE_PORT_POWER, j, 0); //HubPortPowerOn(j);
  137. pUsb->SetHubPreMask();
  138. bPollEnable = true;
  139. // bInitState = 0;
  140. //}
  141. //bInitState = 0;
  142. //USBTRACE("...OK\r\n");
  143. return 0;
  144. // Oleg, No debugging?? -- xxxajk
  145. FailGetDevDescr:
  146. goto Fail;
  147. FailSetDevTblEntry:
  148. goto Fail;
  149. FailGetHubDescr:
  150. goto Fail;
  151. FailGetConfDescr:
  152. goto Fail;
  153. FailSetConfDescr:
  154. goto Fail;
  155. Fail:
  156. USBTRACE("...FAIL\r\n");
  157. return rcode;
  158. }
  159. uint8_t USBHub::Release() {
  160. pUsb->GetAddressPool().FreeAddress(bAddress);
  161. if(bAddress == 0x41)
  162. pUsb->SetHubPreMask();
  163. bAddress = 0;
  164. bNbrPorts = 0;
  165. qNextPollTime = 0;
  166. bPollEnable = false;
  167. return 0;
  168. }
  169. uint8_t USBHub::Poll() {
  170. uint8_t rcode = 0;
  171. if(!bPollEnable)
  172. return 0;
  173. if(((long)(millis() - qNextPollTime) >= 0L)) {
  174. rcode = CheckHubStatus();
  175. qNextPollTime = millis() + 100;
  176. }
  177. return rcode;
  178. }
  179. uint8_t USBHub::CheckHubStatus() {
  180. uint8_t rcode;
  181. uint8_t buf[8];
  182. uint16_t read = 1;
  183. rcode = pUsb->inTransfer(bAddress, 1, &read, buf);
  184. if(rcode)
  185. return rcode;
  186. //if (buf[0] & 0x01) // Hub Status Change
  187. //{
  188. // pUsb->PrintHubStatus(addr);
  189. // rcode = GetHubStatus(1, 0, 1, 4, buf);
  190. // if (rcode)
  191. // {
  192. // USB_HOST_SERIAL.print("GetHubStatus Error");
  193. // USB_HOST_SERIAL.println(rcode, HEX);
  194. // return rcode;
  195. // }
  196. //}
  197. for(uint8_t port = 1, mask = 0x02; port < 8; mask <<= 1, port++) {
  198. if(buf[0] & mask) {
  199. HubEvent evt;
  200. evt.bmEvent = 0;
  201. rcode = GetPortStatus(port, 4, evt.evtBuff);
  202. if(rcode)
  203. continue;
  204. rcode = PortStatusChange(port, evt);
  205. if(rcode == HUB_ERROR_PORT_HAS_BEEN_RESET)
  206. return 0;
  207. if(rcode)
  208. return rcode;
  209. }
  210. } // for
  211. for(uint8_t port = 1; port <= bNbrPorts; port++) {
  212. HubEvent evt;
  213. evt.bmEvent = 0;
  214. rcode = GetPortStatus(port, 4, evt.evtBuff);
  215. if(rcode)
  216. continue;
  217. if((evt.bmStatus & bmHUB_PORT_STATE_CHECK_DISABLED) != bmHUB_PORT_STATE_DISABLED)
  218. continue;
  219. // Emulate connection event for the port
  220. evt.bmChange |= bmHUB_PORT_STATUS_C_PORT_CONNECTION;
  221. rcode = PortStatusChange(port, evt);
  222. if(rcode == HUB_ERROR_PORT_HAS_BEEN_RESET)
  223. return 0;
  224. if(rcode)
  225. return rcode;
  226. } // for
  227. return 0;
  228. }
  229. void USBHub::ResetHubPort(uint8_t port) {
  230. HubEvent evt;
  231. evt.bmEvent = 0;
  232. uint8_t rcode;
  233. ClearPortFeature(HUB_FEATURE_C_PORT_ENABLE, port, 0);
  234. ClearPortFeature(HUB_FEATURE_C_PORT_CONNECTION, port, 0);
  235. SetPortFeature(HUB_FEATURE_PORT_RESET, port, 0);
  236. for(int i = 0; i < 3; i++) {
  237. rcode = GetPortStatus(port, 4, evt.evtBuff);
  238. if(rcode) break; // Some kind of error, bail.
  239. if(evt.bmEvent == bmHUB_PORT_EVENT_RESET_COMPLETE || evt.bmEvent == bmHUB_PORT_EVENT_LS_RESET_COMPLETE) {
  240. break;
  241. }
  242. delay(100); // simulate polling.
  243. }
  244. ClearPortFeature(HUB_FEATURE_C_PORT_RESET, port, 0);
  245. ClearPortFeature(HUB_FEATURE_C_PORT_CONNECTION, port, 0);
  246. delay(20);
  247. }
  248. uint8_t USBHub::PortStatusChange(uint8_t port, HubEvent &evt) {
  249. switch(evt.bmEvent) {
  250. // Device connected event
  251. case bmHUB_PORT_EVENT_CONNECT:
  252. case bmHUB_PORT_EVENT_LS_CONNECT:
  253. if(bResetInitiated)
  254. return 0;
  255. ClearPortFeature(HUB_FEATURE_C_PORT_ENABLE, port, 0);
  256. ClearPortFeature(HUB_FEATURE_C_PORT_CONNECTION, port, 0);
  257. SetPortFeature(HUB_FEATURE_PORT_RESET, port, 0);
  258. bResetInitiated = true;
  259. return HUB_ERROR_PORT_HAS_BEEN_RESET;
  260. // Device disconnected event
  261. case bmHUB_PORT_EVENT_DISCONNECT:
  262. ClearPortFeature(HUB_FEATURE_C_PORT_ENABLE, port, 0);
  263. ClearPortFeature(HUB_FEATURE_C_PORT_CONNECTION, port, 0);
  264. bResetInitiated = false;
  265. UsbDeviceAddress a;
  266. a.devAddress = 0;
  267. a.bmHub = 0;
  268. a.bmParent = bAddress;
  269. a.bmAddress = port;
  270. pUsb->ReleaseDevice(a.devAddress);
  271. return 0;
  272. // Reset complete event
  273. case bmHUB_PORT_EVENT_RESET_COMPLETE:
  274. case bmHUB_PORT_EVENT_LS_RESET_COMPLETE:
  275. ClearPortFeature(HUB_FEATURE_C_PORT_RESET, port, 0);
  276. ClearPortFeature(HUB_FEATURE_C_PORT_CONNECTION, port, 0);
  277. delay(20);
  278. a.devAddress = bAddress;
  279. pUsb->Configuring(a.bmAddress, port, (evt.bmStatus & bmHUB_PORT_STATUS_PORT_LOW_SPEED));
  280. bResetInitiated = false;
  281. break;
  282. } // switch (evt.bmEvent)
  283. return 0;
  284. }
  285. void PrintHubPortStatus(USBHub *hubptr, uint8_t addr, uint8_t port, bool print_changes) {
  286. uint8_t rcode = 0;
  287. HubEvent evt;
  288. rcode = hubptr->GetPortStatus(port, 4, evt.evtBuff);
  289. if(rcode) {
  290. USB_HOST_SERIAL.println("ERROR!");
  291. return;
  292. }
  293. USB_HOST_SERIAL.print("\r\nPort ");
  294. USB_HOST_SERIAL.println(port, DEC);
  295. USB_HOST_SERIAL.println("Status");
  296. USB_HOST_SERIAL.print("CONNECTION:\t");
  297. USB_HOST_SERIAL.println((evt.bmStatus & bmHUB_PORT_STATUS_PORT_CONNECTION) > 0, DEC);
  298. USB_HOST_SERIAL.print("ENABLE:\t\t");
  299. USB_HOST_SERIAL.println((evt.bmStatus & bmHUB_PORT_STATUS_PORT_ENABLE) > 0, DEC);
  300. USB_HOST_SERIAL.print("SUSPEND:\t");
  301. USB_HOST_SERIAL.println((evt.bmStatus & bmHUB_PORT_STATUS_PORT_SUSPEND) > 0, DEC);
  302. USB_HOST_SERIAL.print("OVER_CURRENT:\t");
  303. USB_HOST_SERIAL.println((evt.bmStatus & bmHUB_PORT_STATUS_PORT_OVER_CURRENT) > 0, DEC);
  304. USB_HOST_SERIAL.print("RESET:\t\t");
  305. USB_HOST_SERIAL.println((evt.bmStatus & bmHUB_PORT_STATUS_PORT_RESET) > 0, DEC);
  306. USB_HOST_SERIAL.print("POWER:\t\t");
  307. USB_HOST_SERIAL.println((evt.bmStatus & bmHUB_PORT_STATUS_PORT_POWER) > 0, DEC);
  308. USB_HOST_SERIAL.print("LOW_SPEED:\t");
  309. USB_HOST_SERIAL.println((evt.bmStatus & bmHUB_PORT_STATUS_PORT_LOW_SPEED) > 0, DEC);
  310. USB_HOST_SERIAL.print("HIGH_SPEED:\t");
  311. USB_HOST_SERIAL.println((evt.bmStatus & bmHUB_PORT_STATUS_PORT_HIGH_SPEED) > 0, DEC);
  312. USB_HOST_SERIAL.print("TEST:\t\t");
  313. USB_HOST_SERIAL.println((evt.bmStatus & bmHUB_PORT_STATUS_PORT_TEST) > 0, DEC);
  314. USB_HOST_SERIAL.print("INDICATOR:\t");
  315. USB_HOST_SERIAL.println((evt.bmStatus & bmHUB_PORT_STATUS_PORT_INDICATOR) > 0, DEC);
  316. if(!print_changes)
  317. return;
  318. USB_HOST_SERIAL.println("\r\nChange");
  319. USB_HOST_SERIAL.print("CONNECTION:\t");
  320. USB_HOST_SERIAL.println((evt.bmChange & bmHUB_PORT_STATUS_C_PORT_CONNECTION) > 0, DEC);
  321. USB_HOST_SERIAL.print("ENABLE:\t\t");
  322. USB_HOST_SERIAL.println((evt.bmChange & bmHUB_PORT_STATUS_C_PORT_ENABLE) > 0, DEC);
  323. USB_HOST_SERIAL.print("SUSPEND:\t");
  324. USB_HOST_SERIAL.println((evt.bmChange & bmHUB_PORT_STATUS_C_PORT_SUSPEND) > 0, DEC);
  325. USB_HOST_SERIAL.print("OVER_CURRENT:\t");
  326. USB_HOST_SERIAL.println((evt.bmChange & bmHUB_PORT_STATUS_C_PORT_OVER_CURRENT) > 0, DEC);
  327. USB_HOST_SERIAL.print("RESET:\t\t");
  328. USB_HOST_SERIAL.println((evt.bmChange & bmHUB_PORT_STATUS_C_PORT_RESET) > 0, DEC);
  329. }