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.

hiduniversal.cpp 13KB

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 "hiduniversal.h"
  15. HIDUniversal::HIDUniversal(USB *p) :
  16. HID(p),
  17. qNextPollTime(0),
  18. pollInterval(0),
  19. bPollEnable(false),
  20. bHasReportId(false) {
  21. Initialize();
  22. if(pUsb)
  23. pUsb->RegisterDeviceClass(this);
  24. }
  25. uint16_t HIDUniversal::GetHidClassDescrLen(uint8_t type, uint8_t num) {
  26. for(uint8_t i = 0, n = 0; i < HID_MAX_HID_CLASS_DESCRIPTORS; i++) {
  27. if(descrInfo[i].bDescrType == type) {
  28. if(n == num)
  29. return descrInfo[i].wDescriptorLength;
  30. n++;
  31. }
  32. }
  33. return 0;
  34. }
  35. void HIDUniversal::Initialize() {
  36. for(uint8_t i = 0; i < MAX_REPORT_PARSERS; i++) {
  37. rptParsers[i].rptId = 0;
  38. rptParsers[i].rptParser = NULL;
  39. }
  40. for(uint8_t i = 0; i < HID_MAX_HID_CLASS_DESCRIPTORS; i++) {
  41. descrInfo[i].bDescrType = 0;
  42. descrInfo[i].wDescriptorLength = 0;
  43. }
  44. for(uint8_t i = 0; i < maxHidInterfaces; i++) {
  45. hidInterfaces[i].bmInterface = 0;
  46. hidInterfaces[i].bmProtocol = 0;
  47. for(uint8_t j = 0; j < maxEpPerInterface; j++)
  48. hidInterfaces[i].epIndex[j] = 0;
  49. }
  50. for(uint8_t i = 0; i < totalEndpoints; i++) {
  51. epInfo[i].epAddr = 0;
  52. epInfo[i].maxPktSize = (i) ? 0 : 8;
  53. epInfo[i].epAttribs = 0;
  54. epInfo[i].bmNakPower = (i) ? USB_NAK_NOWAIT : USB_NAK_MAX_POWER;
  55. }
  56. bNumEP = 1;
  57. bNumIface = 0;
  58. bConfNum = 0;
  59. pollInterval = 0;
  60. ZeroMemory(constBuffLen, prevBuf);
  61. }
  62. bool HIDUniversal::SetReportParser(uint8_t id, HIDReportParser *prs) {
  63. for(uint8_t i = 0; i < MAX_REPORT_PARSERS; i++) {
  64. if(rptParsers[i].rptId == 0 && rptParsers[i].rptParser == NULL) {
  65. rptParsers[i].rptId = id;
  66. rptParsers[i].rptParser = prs;
  67. return true;
  68. }
  69. }
  70. return false;
  71. }
  72. HIDReportParser* HIDUniversal::GetReportParser(uint8_t id) {
  73. if(!bHasReportId)
  74. return ((rptParsers[0].rptParser) ? rptParsers[0].rptParser : NULL);
  75. for(uint8_t i = 0; i < MAX_REPORT_PARSERS; i++) {
  76. if(rptParsers[i].rptId == id)
  77. return rptParsers[i].rptParser;
  78. }
  79. return NULL;
  80. }
  81. uint8_t HIDUniversal::Init(uint8_t parent, uint8_t port, bool lowspeed) {
  82. const uint8_t constBufSize = sizeof (USB_DEVICE_DESCRIPTOR);
  83. uint8_t buf[constBufSize];
  84. USB_DEVICE_DESCRIPTOR * udd = reinterpret_cast<USB_DEVICE_DESCRIPTOR*>(buf);
  85. uint8_t rcode;
  86. UsbDevice *p = NULL;
  87. EpInfo *oldep_ptr = NULL;
  88. uint8_t len = 0;
  89. uint8_t num_of_conf; // number of configurations
  90. //uint8_t num_of_intf; // number of interfaces
  91. AddressPool &addrPool = pUsb->GetAddressPool();
  92. USBTRACE("HU Init\r\n");
  93. if(bAddress)
  94. return USB_ERROR_CLASS_INSTANCE_ALREADY_IN_USE;
  95. // Get pointer to pseudo device with address 0 assigned
  96. p = addrPool.GetUsbDevicePtr(0);
  97. if(!p)
  98. return USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL;
  99. if(!p->epinfo) {
  100. USBTRACE("epinfo\r\n");
  101. return USB_ERROR_EPINFO_IS_NULL;
  102. }
  103. // Save old pointer to EP_RECORD of address 0
  104. oldep_ptr = p->epinfo;
  105. // Temporary assign new pointer to epInfo to p->epinfo in order to avoid toggle inconsistence
  106. p->epinfo = epInfo;
  107. p->lowspeed = lowspeed;
  108. // Get device descriptor
  109. rcode = pUsb->getDevDescr(0, 0, 8, (uint8_t*)buf);
  110. if(!rcode)
  111. len = (buf[0] > constBufSize) ? constBufSize : buf[0];
  112. if(rcode) {
  113. // Restore p->epinfo
  114. p->epinfo = oldep_ptr;
  115. goto FailGetDevDescr;
  116. }
  117. // Restore p->epinfo
  118. p->epinfo = oldep_ptr;
  119. // Allocate new address according to device class
  120. bAddress = addrPool.AllocAddress(parent, false, port);
  121. if(!bAddress)
  122. return USB_ERROR_OUT_OF_ADDRESS_SPACE_IN_POOL;
  123. // Extract Max Packet Size from the device descriptor
  124. epInfo[0].maxPktSize = udd->bMaxPacketSize0;
  125. // Assign new address to the device
  126. rcode = pUsb->setAddr(0, 0, bAddress);
  127. if(rcode) {
  128. p->lowspeed = false;
  129. addrPool.FreeAddress(bAddress);
  130. bAddress = 0;
  131. USBTRACE2("setAddr:", rcode);
  132. return rcode;
  133. }
  134. //delay(2); //per USB 2.0 sect.9.2.6.3
  135. USBTRACE2("Addr:", bAddress);
  136. p->lowspeed = false;
  137. p = addrPool.GetUsbDevicePtr(bAddress);
  138. if(!p)
  139. return USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL;
  140. p->lowspeed = lowspeed;
  141. if(len)
  142. rcode = pUsb->getDevDescr(bAddress, 0, len, (uint8_t*)buf);
  143. if(rcode)
  144. goto FailGetDevDescr;
  145. VID = udd->idVendor; // Can be used by classes that inherits this class to check the VID and PID of the connected device
  146. PID = udd->idProduct;
  147. num_of_conf = udd->bNumConfigurations;
  148. // Assign epInfo to epinfo pointer
  149. rcode = pUsb->setEpInfoEntry(bAddress, 1, epInfo);
  150. if(rcode)
  151. goto FailSetDevTblEntry;
  152. USBTRACE2("NC:", num_of_conf);
  153. for(uint8_t i = 0; i < num_of_conf; i++) {
  154. //HexDumper<USBReadParser, uint16_t, uint16_t> HexDump;
  155. ConfigDescParser<USB_CLASS_HID, 0, 0,
  156. CP_MASK_COMPARE_CLASS> confDescrParser(this);
  157. //rcode = pUsb->getConfDescr(bAddress, 0, i, &HexDump);
  158. rcode = pUsb->getConfDescr(bAddress, 0, i, &confDescrParser);
  159. if(rcode)
  160. goto FailGetConfDescr;
  161. if(bNumEP > 1)
  162. break;
  163. } // for
  164. if(bNumEP < 2)
  165. return USB_DEV_CONFIG_ERROR_DEVICE_NOT_SUPPORTED;
  166. // Assign epInfo to epinfo pointer
  167. rcode = pUsb->setEpInfoEntry(bAddress, bNumEP, epInfo);
  168. USBTRACE2("Cnf:", bConfNum);
  169. // Set Configuration Value
  170. rcode = pUsb->setConf(bAddress, 0, bConfNum);
  171. if(rcode)
  172. goto FailSetConfDescr;
  173. for(uint8_t i = 0; i < bNumIface; i++) {
  174. if(hidInterfaces[i].epIndex[epInterruptInIndex] == 0)
  175. continue;
  176. rcode = SetIdle(hidInterfaces[i].bmInterface, 0, 0);
  177. if(rcode && rcode != hrSTALL)
  178. goto FailSetIdle;
  179. }
  180. USBTRACE("HU configured\r\n");
  181. OnInitSuccessful();
  182. bPollEnable = true;
  183. return 0;
  184. FailGetDevDescr:
  185. #ifdef DEBUG_USB_HOST
  186. NotifyFailGetDevDescr();
  187. goto Fail;
  188. #endif
  189. FailSetDevTblEntry:
  190. #ifdef DEBUG_USB_HOST
  191. NotifyFailSetDevTblEntry();
  192. goto Fail;
  193. #endif
  194. FailGetConfDescr:
  195. #ifdef DEBUG_USB_HOST
  196. NotifyFailGetConfDescr();
  197. goto Fail;
  198. #endif
  199. FailSetConfDescr:
  200. #ifdef DEBUG_USB_HOST
  201. NotifyFailSetConfDescr();
  202. goto Fail;
  203. #endif
  204. FailSetIdle:
  205. #ifdef DEBUG_USB_HOST
  206. USBTRACE("SetIdle:");
  207. #endif
  208. #ifdef DEBUG_USB_HOST
  209. Fail:
  210. NotifyFail(rcode);
  211. #endif
  212. Release();
  213. return rcode;
  214. }
  215. HIDUniversal::HIDInterface* HIDUniversal::FindInterface(uint8_t iface, uint8_t alt, uint8_t proto) {
  216. for(uint8_t i = 0; i < bNumIface && i < maxHidInterfaces; i++)
  217. if(hidInterfaces[i].bmInterface == iface && hidInterfaces[i].bmAltSet == alt
  218. && hidInterfaces[i].bmProtocol == proto)
  219. return hidInterfaces + i;
  220. return NULL;
  221. }
  222. void HIDUniversal::EndpointXtract(uint8_t conf, uint8_t iface, uint8_t alt, uint8_t proto, const USB_ENDPOINT_DESCRIPTOR *pep) {
  223. // If the first configuration satisfies, the others are not concidered.
  224. if(bNumEP > 1 && conf != bConfNum)
  225. return;
  226. //ErrorMessage<uint8_t>(PSTR("\r\nConf.Val"), conf);
  227. //ErrorMessage<uint8_t>(PSTR("Iface Num"), iface);
  228. //ErrorMessage<uint8_t>(PSTR("Alt.Set"), alt);
  229. bConfNum = conf;
  230. uint8_t index = 0;
  231. HIDInterface *piface = FindInterface(iface, alt, proto);
  232. // Fill in interface structure in case of new interface
  233. if(!piface) {
  234. piface = hidInterfaces + bNumIface;
  235. piface->bmInterface = iface;
  236. piface->bmAltSet = alt;
  237. piface->bmProtocol = proto;
  238. bNumIface++;
  239. }
  240. if((pep->bmAttributes & 0x03) == 3 && (pep->bEndpointAddress & 0x80) == 0x80)
  241. index = epInterruptInIndex;
  242. else
  243. index = epInterruptOutIndex;
  244. if(index) {
  245. // Fill in the endpoint info structure
  246. epInfo[bNumEP].epAddr = (pep->bEndpointAddress & 0x0F);
  247. epInfo[bNumEP].maxPktSize = (uint8_t)pep->wMaxPacketSize;
  248. epInfo[bNumEP].epAttribs = 0;
  249. epInfo[bNumEP].bmNakPower = USB_NAK_NOWAIT;
  250. // Fill in the endpoint index list
  251. piface->epIndex[index] = bNumEP; //(pep->bEndpointAddress & 0x0F);
  252. if(pollInterval < pep->bInterval) // Set the polling interval as the largest polling interval obtained from endpoints
  253. pollInterval = pep->bInterval;
  254. bNumEP++;
  255. }
  256. //PrintEndpointDescriptor(pep);
  257. }
  258. uint8_t HIDUniversal::Release() {
  259. pUsb->GetAddressPool().FreeAddress(bAddress);
  260. bNumEP = 1;
  261. bAddress = 0;
  262. qNextPollTime = 0;
  263. bPollEnable = false;
  264. return 0;
  265. }
  266. bool HIDUniversal::BuffersIdentical(uint8_t len, uint8_t *buf1, uint8_t *buf2) {
  267. for(uint8_t i = 0; i < len; i++)
  268. if(buf1[i] != buf2[i])
  269. return false;
  270. return true;
  271. }
  272. void HIDUniversal::ZeroMemory(uint8_t len, uint8_t *buf) {
  273. for(uint8_t i = 0; i < len; i++)
  274. buf[i] = 0;
  275. }
  276. void HIDUniversal::SaveBuffer(uint8_t len, uint8_t *src, uint8_t *dest) {
  277. for(uint8_t i = 0; i < len; i++)
  278. dest[i] = src[i];
  279. }
  280. uint8_t HIDUniversal::Poll() {
  281. uint8_t rcode = 0;
  282. if(!bPollEnable)
  283. return 0;
  284. if((long)(millis() - qNextPollTime) >= 0L) {
  285. qNextPollTime = millis() + pollInterval;
  286. uint8_t buf[constBuffLen];
  287. for(uint8_t i = 0; i < bNumIface; i++) {
  288. uint8_t index = hidInterfaces[i].epIndex[epInterruptInIndex];
  289. uint16_t read = (uint16_t)epInfo[index].maxPktSize;
  290. ZeroMemory(constBuffLen, buf);
  291. uint8_t rcode = pUsb->inTransfer(bAddress, epInfo[index].epAddr, &read, buf);
  292. if(rcode) {
  293. if(rcode != hrNAK)
  294. USBTRACE3("(hiduniversal.h) Poll:", rcode, 0x81);
  295. return rcode;
  296. }
  297. if(read > constBuffLen)
  298. read = constBuffLen;
  299. bool identical = BuffersIdentical(read, buf, prevBuf);
  300. SaveBuffer(read, buf, prevBuf);
  301. if(identical)
  302. return 0;
  303. #if 0
  304. Notify(PSTR("\r\nBuf: "), 0x80);
  305. for(uint8_t i = 0; i < read; i++) {
  306. D_PrintHex<uint8_t > (buf[i], 0x80);
  307. Notify(PSTR(" "), 0x80);
  308. }
  309. Notify(PSTR("\r\n"), 0x80);
  310. #endif
  311. ParseHIDData(this, bHasReportId, (uint8_t)read, buf);
  312. HIDReportParser *prs = GetReportParser(((bHasReportId) ? *buf : 0));
  313. if(prs)
  314. prs->Parse(this, bHasReportId, (uint8_t)read, buf);
  315. }
  316. }
  317. return rcode;
  318. }
  319. // Send a report to interrupt out endpoint. This is NOT SetReport() request!
  320. uint8_t HIDUniversal::SndRpt(uint16_t nbytes, uint8_t *dataptr) {
  321. return pUsb->outTransfer(bAddress, epInfo[epInterruptOutIndex].epAddr, nbytes, dataptr);
  322. }