USB Host Shield 2.0
hiduniversal.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 
18 #include "hiduniversal.h"
19 
21 HID(p),
22 qNextPollTime(0),
23 pollInterval(0),
24 bPollEnable(false),
25 bHasReportId(false) {
26  Initialize();
27 
28  if(pUsb)
30 }
31 
32 uint16_t HIDUniversal::GetHidClassDescrLen(uint8_t type, uint8_t num) {
33  for(uint8_t i = 0, n = 0; i < HID_MAX_HID_CLASS_DESCRIPTORS; i++) {
34  if(descrInfo[i].bDescrType == type) {
35  if(n == num)
36  return descrInfo[i].wDescriptorLength;
37  n++;
38  }
39  }
40  return 0;
41 }
42 
43 void HIDUniversal::Initialize() {
44  for(uint8_t i = 0; i < MAX_REPORT_PARSERS; i++) {
45  rptParsers[i].rptId = 0;
46  rptParsers[i].rptParser = NULL;
47  }
48  for(uint8_t i = 0; i < HID_MAX_HID_CLASS_DESCRIPTORS; i++) {
49  descrInfo[i].bDescrType = 0;
50  descrInfo[i].wDescriptorLength = 0;
51  }
52  for(uint8_t i = 0; i < maxHidInterfaces; i++) {
53  hidInterfaces[i].bmInterface = 0;
54  hidInterfaces[i].bmProtocol = 0;
55 
56  for(uint8_t j = 0; j < maxEpPerInterface; j++)
57  hidInterfaces[i].epIndex[j] = 0;
58  }
59  for(uint8_t i = 0; i < totalEndpoints; i++) {
60  epInfo[i].epAddr = 0;
61  epInfo[i].maxPktSize = (i) ? 0 : 8;
62  epInfo[i].epAttribs = 0;
64  }
65  bNumEP = 1;
66  bNumIface = 0;
67  bConfNum = 0;
68  pollInterval = 0;
69 
70  ZeroMemory(constBuffLen, prevBuf);
71 }
72 
74  for(uint8_t i = 0; i < MAX_REPORT_PARSERS; i++) {
75  if(rptParsers[i].rptId == 0 && rptParsers[i].rptParser == NULL) {
76  rptParsers[i].rptId = id;
77  rptParsers[i].rptParser = prs;
78  return true;
79  }
80  }
81  return false;
82 }
83 
85  if(!bHasReportId)
86  return ((rptParsers[0].rptParser) ? rptParsers[0].rptParser : NULL);
87 
88  for(uint8_t i = 0; i < MAX_REPORT_PARSERS; i++) {
89  if(rptParsers[i].rptId == id)
90  return rptParsers[i].rptParser;
91  }
92  return NULL;
93 }
94 
95 uint8_t HIDUniversal::Init(uint8_t parent, uint8_t port, bool lowspeed) {
96  const uint8_t constBufSize = sizeof (USB_DEVICE_DESCRIPTOR);
97 
98  uint8_t buf[constBufSize];
99  USB_DEVICE_DESCRIPTOR * udd = reinterpret_cast<USB_DEVICE_DESCRIPTOR*>(buf);
100  uint8_t rcode;
101  UsbDevice *p = NULL;
102  EpInfo *oldep_ptr = NULL;
103  uint8_t len = 0;
104 
105  uint8_t num_of_conf; // number of configurations
106  //uint8_t num_of_intf; // number of interfaces
107 
108  AddressPool &addrPool = pUsb->GetAddressPool();
109 
110  USBTRACE("HU Init\r\n");
111 
112  if(bAddress)
114 
115  // Get pointer to pseudo device with address 0 assigned
116  p = addrPool.GetUsbDevicePtr(0);
117 
118  if(!p)
120 
121  if(!p->epinfo) {
122  USBTRACE("epinfo\r\n");
124  }
125 
126  // Save old pointer to EP_RECORD of address 0
127  oldep_ptr = p->epinfo;
128 
129  // Temporary assign new pointer to epInfo to p->epinfo in order to avoid toggle inconsistence
130  p->epinfo = epInfo;
131 
132  p->lowspeed = lowspeed;
133 
134  // Get device descriptor
135  rcode = pUsb->getDevDescr(0, 0, 8, (uint8_t*)buf);
136 
137  if(!rcode)
138  len = (buf[0] > constBufSize) ? constBufSize : buf[0];
139 
140  if(rcode) {
141  // Restore p->epinfo
142  p->epinfo = oldep_ptr;
143 
144  goto FailGetDevDescr;
145  }
146 
147  // Restore p->epinfo
148  p->epinfo = oldep_ptr;
149 
150  // Allocate new address according to device class
151  bAddress = addrPool.AllocAddress(parent, false, port);
152 
153  if(!bAddress)
155 
156  // Extract Max Packet Size from the device descriptor
158 
159  // Assign new address to the device
160  rcode = pUsb->setAddr(0, 0, bAddress);
161 
162  if(rcode) {
163  p->lowspeed = false;
164  addrPool.FreeAddress(bAddress);
165  bAddress = 0;
166  USBTRACE2("setAddr:", rcode);
167  return rcode;
168  }
169 
170  //delay(2); //per USB 2.0 sect.9.2.6.3
171 
172  USBTRACE2("Addr:", bAddress);
173 
174  p->lowspeed = false;
175 
176  p = addrPool.GetUsbDevicePtr(bAddress);
177 
178  if(!p)
180 
181  p->lowspeed = lowspeed;
182 
183  if(len)
184  rcode = pUsb->getDevDescr(bAddress, 0, len, (uint8_t*)buf);
185 
186  if(rcode)
187  goto FailGetDevDescr;
188 
189  VID = udd->idVendor; // Can be used by classes that inherits this class to check the VID and PID of the connected device
190  PID = udd->idProduct;
191 
192  num_of_conf = udd->bNumConfigurations;
193 
194  // Assign epInfo to epinfo pointer
195  rcode = pUsb->setEpInfoEntry(bAddress, 1, epInfo);
196 
197  if(rcode)
198  goto FailSetDevTblEntry;
199 
200  USBTRACE2("NC:", num_of_conf);
201 
202  for(uint8_t i = 0; i < num_of_conf; i++) {
203  //HexDumper<USBReadParser, uint16_t, uint16_t> HexDump;
205  CP_MASK_COMPARE_CLASS> confDescrParser(this);
206 
207  //rcode = pUsb->getConfDescr(bAddress, 0, i, &HexDump);
208  rcode = pUsb->getConfDescr(bAddress, 0, i, &confDescrParser);
209 
210  if(rcode)
211  goto FailGetConfDescr;
212 
213  if(bNumEP > 1)
214  break;
215  } // for
216 
217  if(bNumEP < 2)
219 
220  // Assign epInfo to epinfo pointer
221  rcode = pUsb->setEpInfoEntry(bAddress, bNumEP, epInfo);
222 
223  USBTRACE2("Cnf:", bConfNum);
224 
225  // Set Configuration Value
226  rcode = pUsb->setConf(bAddress, 0, bConfNum);
227 
228  if(rcode)
229  goto FailSetConfDescr;
230 
231  for(uint8_t i = 0; i < bNumIface; i++) {
232  if(hidInterfaces[i].epIndex[epInterruptInIndex] == 0)
233  continue;
234 
235  rcode = SetIdle(hidInterfaces[i].bmInterface, 0, 0);
236 
237  if(rcode && rcode != hrSTALL)
238  goto FailSetIdle;
239  }
240 
241  USBTRACE("HU configured\r\n");
242 
244 
245  bPollEnable = true;
246  return 0;
247 
248 FailGetDevDescr:
249 #ifdef DEBUG_USB_HOST
251  goto Fail;
252 #endif
253 
254 FailSetDevTblEntry:
255 #ifdef DEBUG_USB_HOST
257  goto Fail;
258 #endif
259 
260 FailGetConfDescr:
261 #ifdef DEBUG_USB_HOST
263  goto Fail;
264 #endif
265 
266 FailSetConfDescr:
267 #ifdef DEBUG_USB_HOST
269  goto Fail;
270 #endif
271 
272 
273 FailSetIdle:
274 #ifdef DEBUG_USB_HOST
275  USBTRACE("SetIdle:");
276 #endif
277 
278 #ifdef DEBUG_USB_HOST
279 Fail:
280  NotifyFail(rcode);
281 #endif
282  Release();
283  return rcode;
284 }
285 
286 HIDUniversal::HIDInterface* HIDUniversal::FindInterface(uint8_t iface, uint8_t alt, uint8_t proto) {
287  for(uint8_t i = 0; i < bNumIface && i < maxHidInterfaces; i++)
288  if(hidInterfaces[i].bmInterface == iface && hidInterfaces[i].bmAltSet == alt
289  && hidInterfaces[i].bmProtocol == proto)
290  return hidInterfaces + i;
291  return NULL;
292 }
293 
294 void HIDUniversal::EndpointXtract(uint8_t conf, uint8_t iface, uint8_t alt, uint8_t proto, const USB_ENDPOINT_DESCRIPTOR *pep) {
295  // If the first configuration satisfies, the others are not concidered.
296  if(bNumEP > 1 && conf != bConfNum)
297  return;
298 
299  //ErrorMessage<uint8_t>(PSTR("\r\nConf.Val"), conf);
300  //ErrorMessage<uint8_t>(PSTR("Iface Num"), iface);
301  //ErrorMessage<uint8_t>(PSTR("Alt.Set"), alt);
302 
303  bConfNum = conf;
304 
305  uint8_t index = 0;
306  HIDInterface *piface = FindInterface(iface, alt, proto);
307 
308  // Fill in interface structure in case of new interface
309  if(!piface) {
310  piface = hidInterfaces + bNumIface;
311  piface->bmInterface = iface;
312  piface->bmAltSet = alt;
313  piface->bmProtocol = proto;
314  bNumIface++;
315  }
316 
317  if((pep->bmAttributes & 0x03) == 3 && (pep->bEndpointAddress & 0x80) == 0x80)
318  index = epInterruptInIndex;
319  else
320  index = epInterruptOutIndex;
321 
322  if(index) {
323  // Fill in the endpoint info structure
324  epInfo[bNumEP].epAddr = (pep->bEndpointAddress & 0x0F);
325  epInfo[bNumEP].maxPktSize = (uint8_t)pep->wMaxPacketSize;
326  epInfo[bNumEP].epAttribs = 0;
327  epInfo[bNumEP].bmNakPower = USB_NAK_NOWAIT;
328 
329  // Fill in the endpoint index list
330  piface->epIndex[index] = bNumEP; //(pep->bEndpointAddress & 0x0F);
331 
332  if(pollInterval < pep->bInterval) // Set the polling interval as the largest polling interval obtained from endpoints
333  pollInterval = pep->bInterval;
334 
335  bNumEP++;
336  }
337  //PrintEndpointDescriptor(pep);
338 }
339 
342 
343  bNumEP = 1;
344  bAddress = 0;
345  qNextPollTime = 0;
346  bPollEnable = false;
347  return 0;
348 }
349 
350 bool HIDUniversal::BuffersIdentical(uint8_t len, uint8_t *buf1, uint8_t *buf2) {
351  for(uint8_t i = 0; i < len; i++)
352  if(buf1[i] != buf2[i])
353  return false;
354  return true;
355 }
356 
357 void HIDUniversal::ZeroMemory(uint8_t len, uint8_t *buf) {
358  for(uint8_t i = 0; i < len; i++)
359  buf[i] = 0;
360 }
361 
362 void HIDUniversal::SaveBuffer(uint8_t len, uint8_t *src, uint8_t *dest) {
363  for(uint8_t i = 0; i < len; i++)
364  dest[i] = src[i];
365 }
366 
368  uint8_t rcode = 0;
369 
370  if(!bPollEnable)
371  return 0;
372 
373  if((long)(millis() - qNextPollTime) >= 0L) {
374  qNextPollTime = millis() + pollInterval;
375 
376  uint8_t buf[constBuffLen];
377 
378  for(uint8_t i = 0; i < bNumIface; i++) {
379  uint8_t index = hidInterfaces[i].epIndex[epInterruptInIndex];
380  uint16_t read = (uint16_t)epInfo[index].maxPktSize;
381 
382  ZeroMemory(constBuffLen, buf);
383 
384  uint8_t rcode = pUsb->inTransfer(bAddress, epInfo[index].epAddr, &read, buf);
385 
386  if(rcode) {
387  if(rcode != hrNAK)
388  USBTRACE3("(hiduniversal.h) Poll:", rcode, 0x81);
389  return rcode;
390  }
391 
392  if(read > constBuffLen)
393  read = constBuffLen;
394 
395  bool identical = BuffersIdentical(read, buf, prevBuf);
396 
397  SaveBuffer(read, buf, prevBuf);
398 
399  if(identical)
400  return 0;
401 #if 0
402  Notify(PSTR("\r\nBuf: "), 0x80);
403 
404  for(uint8_t i = 0; i < read; i++) {
405  D_PrintHex<uint8_t > (buf[i], 0x80);
406  Notify(PSTR(" "), 0x80);
407  }
408 
409  Notify(PSTR("\r\n"), 0x80);
410 #endif
411  ParseHIDData(this, bHasReportId, (uint8_t)read, buf);
412 
413  HIDReportParser *prs = GetReportParser(((bHasReportId) ? *buf : 0));
414 
415  if(prs)
416  prs->Parse(this, bHasReportId, (uint8_t)read, buf);
417  }
418  }
419  return rcode;
420 }
421 
422 // Send a report to interrupt out endpoint. This is NOT SetReport() request!
423 uint8_t HIDUniversal::SndRpt(uint16_t nbytes, uint8_t *dataptr) {
424  return pUsb->outTransfer(bAddress, epInfo[epInterruptOutIndex].epAddr, nbytes, dataptr);
425 }
uint16_t PID
Definition: hiduniversal.h:69
uint8_t getConfDescr(uint8_t addr, uint8_t ep, uint16_t nbytes, uint8_t conf, uint8_t *dataptr)
Definition: Usb.cpp:769
uint8_t Init(uint8_t parent, uint8_t port, bool lowspeed)
bool bHasReportId
Definition: hiduniversal.h:67
EpInfo * epinfo
Definition: address.h:76
bool lowspeed
Definition: address.h:79
#define USB_ERROR_EPINFO_IS_NULL
Definition: UsbCore.h:83
#define hrSTALL
Definition: max3421e.h:212
uint8_t bmNakPower
Definition: address.h:42
uint8_t bMaxPacketSize0
Definition: usb_ch9.h:105
#define NotifyFail(...)
Definition: message.h:55
static const uint8_t epInterruptOutIndex
Definition: hid.h:150
uint8_t setConf(uint8_t addr, uint8_t ep, uint8_t conf_value)
Definition: Usb.cpp:808
#define NotifyFailGetDevDescr(...)
Definition: message.h:50
uint8_t bAddress
Definition: hid.h:146
HIDInterface hidInterfaces[maxHidInterfaces]
Definition: hiduniversal.h:65
uint8_t setEpInfoEntry(uint8_t addr, uint8_t epcount, EpInfo *eprecord_ptr)
Definition: Usb.cpp:64
uint8_t Release()
#define CP_MASK_COMPARE_CLASS
uint16_t VID
Definition: hiduniversal.h:69
virtual uint8_t OnInitSuccessful()
Definition: hiduniversal.h:74
#define USB_CLASS_HID
Definition: UsbCore.h:59
virtual void FreeAddress(uint8_t addr)=0
uint8_t Poll()
uint8_t epAttribs
Definition: address.h:37
virtual UsbDevice * GetUsbDevicePtr(uint8_t addr)=0
#define Notify(...)
Definition: message.h:44
#define USBTRACE2(s, r)
Definition: macros.h:77
uint8_t setAddr(uint8_t oldaddr, uint8_t ep, uint8_t newaddr)
Definition: Usb.cpp:799
#define NotifyFailGetConfDescr(...)
Definition: message.h:52
virtual void ParseHIDData(HID *hid, bool is_rpt_id, uint8_t len, uint8_t *buf)
Definition: hiduniversal.h:78
uint8_t epAddr
Definition: address.h:33
#define USB_NAK_MAX_POWER
Definition: address.h:27
HIDReportParser * GetReportParser(uint8_t id)
Definition: address.h:32
uint8_t outTransfer(uint8_t addr, uint8_t ep, uint16_t nbytes, uint8_t *data)
Definition: Usb.cpp:292
void EndpointXtract(uint8_t conf, uint8_t iface, uint8_t alt, uint8_t proto, const USB_ENDPOINT_DESCRIPTOR *ep)
#define hrNAK
Definition: max3421e.h:211
HIDUniversal(USB *p)
uint16_t wMaxPacketSize
Definition: usb_ch9.h:146
Definition: hid.h:143
virtual uint8_t AllocAddress(uint8_t parent, bool is_hub=false, uint8_t port=0)=0
uint8_t bEndpointAddress
Definition: usb_ch9.h:144
#define USB_ERROR_CLASS_INSTANCE_ALREADY_IN_USE
Definition: UsbCore.h:85
#define PSTR(str)
#define USB_NAK_NOWAIT
Definition: address.h:29
#define USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL
Definition: UsbCore.h:82
virtual void Parse(HID *hid, bool is_rpt_id, uint8_t len, uint8_t *buf)=0
uint8_t inTransfer(uint8_t addr, uint8_t ep, uint16_t *nbytesptr, uint8_t *data)
Definition: Usb.cpp:206
#define MAX_REPORT_PARSERS
Definition: hid.h:23
#define USB_DEV_CONFIG_ERROR_DEVICE_NOT_SUPPORTED
Definition: UsbCore.h:77
USB * pUsb
Definition: hid.h:145
uint8_t SetIdle(uint8_t iface, uint8_t reportID, uint8_t duration)
Definition: hid.cpp:62
uint16_t idProduct
Definition: usb_ch9.h:107
static const uint8_t epInterruptInIndex
Definition: hid.h:149
uint8_t SndRpt(uint16_t nbytes, uint8_t *dataptr)
uint8_t bNumConfigurations
Definition: usb_ch9.h:112
#define USB_ERROR_OUT_OF_ADDRESS_SPACE_IN_POOL
Definition: UsbCore.h:80
uint8_t maxPktSize
Definition: address.h:34
AddressPool & GetAddressPool()
Definition: UsbCore.h:213
Definition: UsbCore.h:197
#define USBTRACE3(s, r, l)
Definition: macros.h:78
uint8_t RegisterDeviceClass(USBDeviceConfig *pdev)
Definition: UsbCore.h:217
static const uint8_t totalEndpoints
Definition: hid.h:154
#define NotifyFailSetConfDescr(...)
Definition: message.h:53
EpInfo epInfo[totalEndpoints]
Definition: hiduniversal.h:64
#define HID_MAX_HID_CLASS_DESCRIPTORS
Definition: hid.h:24
static const uint8_t maxEpPerInterface
Definition: hid.h:153
bool SetReportParser(uint8_t id, HIDReportParser *prs)
#define USBTRACE(s)
Definition: macros.h:75
uint8_t getDevDescr(uint8_t addr, uint8_t ep, uint16_t nbytes, uint8_t *dataptr)
defined(USB_METHODS_INLINE)
Definition: Usb.cpp:764
#define NotifyFailSetDevTblEntry(...)
Definition: message.h:51
static const uint8_t maxHidInterfaces
Definition: hid.h:152