1 /* Copyright (C) 2011 Circuits At Home, LTD. All rights reserved.
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
14 Web : http://www.circuitsathome.com
15 e-mail : support@circuitsathome.com
18 #include "hiduniversal.h"
20 HIDUniversal::HIDUniversal(USB *p) :
29 pUsb->RegisterDeviceClass(this);
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) {
36 return descrInfo[i].wDescriptorLength;
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;
48 for(uint8_t i = 0; i < HID_MAX_HID_CLASS_DESCRIPTORS; i++) {
49 descrInfo[i].bDescrType = 0;
50 descrInfo[i].wDescriptorLength = 0;
52 for(uint8_t i = 0; i < maxHidInterfaces; i++) {
53 hidInterfaces[i].bmInterface = 0;
54 hidInterfaces[i].bmProtocol = 0;
56 for(uint8_t j = 0; j < maxEpPerInterface; j++)
57 hidInterfaces[i].epIndex[j] = 0;
59 for(uint8_t i = 0; i < totalEndpoints; i++) {
61 epInfo[i].maxPktSize = (i) ? 0 : 8;
62 epInfo[i].epAttribs = 0;
63 epInfo[i].bmNakPower = (i) ? USB_NAK_NOWAIT : USB_NAK_MAX_POWER;
70 ZeroMemory(constBuffLen, prevBuf);
73 bool HIDUniversal::SetReportParser(uint8_t id, HIDReportParser *prs) {
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;
84 HIDReportParser* HIDUniversal::GetReportParser(uint8_t id) {
86 return ((rptParsers[0].rptParser) ? rptParsers[0].rptParser : NULL);
88 for(uint8_t i = 0; i < MAX_REPORT_PARSERS; i++) {
89 if(rptParsers[i].rptId == id)
90 return rptParsers[i].rptParser;
95 uint8_t HIDUniversal::Init(uint8_t parent, uint8_t port, bool lowspeed) {
96 const uint8_t constBufSize = sizeof (USB_DEVICE_DESCRIPTOR);
98 uint8_t buf[constBufSize];
99 USB_DEVICE_DESCRIPTOR * udd = reinterpret_cast<USB_DEVICE_DESCRIPTOR*>(buf);
102 EpInfo *oldep_ptr = NULL;
105 uint8_t num_of_conf; // number of configurations
106 //uint8_t num_of_intf; // number of interfaces
108 AddressPool &addrPool = pUsb->GetAddressPool();
110 USBTRACE("HU Init\r\n");
113 return USB_ERROR_CLASS_INSTANCE_ALREADY_IN_USE;
115 // Get pointer to pseudo device with address 0 assigned
116 p = addrPool.GetUsbDevicePtr(0);
119 return USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL;
122 USBTRACE("epinfo\r\n");
123 return USB_ERROR_EPINFO_IS_NULL;
126 // Save old pointer to EP_RECORD of address 0
127 oldep_ptr = p->epinfo;
129 // Temporary assign new pointer to epInfo to p->epinfo in order to avoid toggle inconsistence
132 p->lowspeed = lowspeed;
134 // Get device descriptor
135 rcode = pUsb->getDevDescr(0, 0, 8, (uint8_t*)buf);
138 len = (buf[0] > constBufSize) ? constBufSize : buf[0];
142 p->epinfo = oldep_ptr;
144 goto FailGetDevDescr;
148 p->epinfo = oldep_ptr;
150 // Allocate new address according to device class
151 bAddress = addrPool.AllocAddress(parent, false, port);
154 return USB_ERROR_OUT_OF_ADDRESS_SPACE_IN_POOL;
156 // Extract Max Packet Size from the device descriptor
157 epInfo[0].maxPktSize = udd->bMaxPacketSize0;
159 // Assign new address to the device
160 rcode = pUsb->setAddr(0, 0, bAddress);
164 addrPool.FreeAddress(bAddress);
166 USBTRACE2("setAddr:", rcode);
170 //delay(2); //per USB 2.0 sect.9.2.6.3
172 USBTRACE2("Addr:", bAddress);
176 p = addrPool.GetUsbDevicePtr(bAddress);
179 return USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL;
181 p->lowspeed = lowspeed;
184 rcode = pUsb->getDevDescr(bAddress, 0, len, (uint8_t*)buf);
187 goto FailGetDevDescr;
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;
192 num_of_conf = udd->bNumConfigurations;
194 // Assign epInfo to epinfo pointer
195 rcode = pUsb->setEpInfoEntry(bAddress, 1, epInfo);
198 goto FailSetDevTblEntry;
200 USBTRACE2("NC:", num_of_conf);
202 for(uint8_t i = 0; i < num_of_conf; i++) {
203 //HexDumper<USBReadParser, uint16_t, uint16_t> HexDump;
204 ConfigDescParser<USB_CLASS_HID, 0, 0,
205 CP_MASK_COMPARE_CLASS> confDescrParser(this);
207 //rcode = pUsb->getConfDescr(bAddress, 0, i, &HexDump);
208 rcode = pUsb->getConfDescr(bAddress, 0, i, &confDescrParser);
211 goto FailGetConfDescr;
218 return USB_DEV_CONFIG_ERROR_DEVICE_NOT_SUPPORTED;
220 // Assign epInfo to epinfo pointer
221 rcode = pUsb->setEpInfoEntry(bAddress, bNumEP, epInfo);
223 USBTRACE2("Cnf:", bConfNum);
225 // Set Configuration Value
226 rcode = pUsb->setConf(bAddress, 0, bConfNum);
229 goto FailSetConfDescr;
231 for(uint8_t i = 0; i < bNumIface; i++) {
232 if(hidInterfaces[i].epIndex[epInterruptInIndex] == 0)
235 rcode = SetIdle(hidInterfaces[i].bmInterface, 0, 0);
237 if(rcode && rcode != hrSTALL)
241 USBTRACE("HU configured\r\n");
249 #ifdef DEBUG_USB_HOST
250 NotifyFailGetDevDescr();
255 #ifdef DEBUG_USB_HOST
256 NotifyFailSetDevTblEntry();
261 #ifdef DEBUG_USB_HOST
262 NotifyFailGetConfDescr();
267 #ifdef DEBUG_USB_HOST
268 NotifyFailSetConfDescr();
274 #ifdef DEBUG_USB_HOST
275 USBTRACE("SetIdle:");
278 #ifdef DEBUG_USB_HOST
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;
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)
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);
306 HIDInterface *piface = FindInterface(iface, alt, proto);
308 // Fill in interface structure in case of new interface
310 piface = hidInterfaces + bNumIface;
311 piface->bmInterface = iface;
312 piface->bmAltSet = alt;
313 piface->bmProtocol = proto;
317 if((pep->bmAttributes & 0x03) == 3 && (pep->bEndpointAddress & 0x80) == 0x80)
318 index = epInterruptInIndex;
320 index = epInterruptOutIndex;
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;
329 // Fill in the endpoint index list
330 piface->epIndex[index] = bNumEP; //(pep->bEndpointAddress & 0x0F);
332 if(pollInterval < pep->bInterval) // Set the polling interval as the largest polling interval obtained from endpoints
333 pollInterval = pep->bInterval;
337 //PrintEndpointDescriptor(pep);
340 uint8_t HIDUniversal::Release() {
341 pUsb->GetAddressPool().FreeAddress(bAddress);
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])
357 void HIDUniversal::ZeroMemory(uint8_t len, uint8_t *buf) {
358 for(uint8_t i = 0; i < len; i++)
362 void HIDUniversal::SaveBuffer(uint8_t len, uint8_t *src, uint8_t *dest) {
363 for(uint8_t i = 0; i < len; i++)
367 uint8_t HIDUniversal::Poll() {
373 if((long)(millis() - qNextPollTime) >= 0L) {
374 qNextPollTime = millis() + pollInterval;
376 uint8_t buf[constBuffLen];
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;
382 ZeroMemory(constBuffLen, buf);
384 uint8_t rcode = pUsb->inTransfer(bAddress, epInfo[index].epAddr, &read, buf);
388 USBTRACE3("(hiduniversal.h) Poll:", rcode, 0x81);
392 if(read > constBuffLen)
395 bool identical = BuffersIdentical(read, buf, prevBuf);
397 SaveBuffer(read, buf, prevBuf);
402 Notify(PSTR("\r\nBuf: "), 0x80);
404 for(uint8_t i = 0; i < read; i++) {
405 D_PrintHex<uint8_t > (buf[i], 0x80);
406 Notify(PSTR(" "), 0x80);
409 Notify(PSTR("\r\n"), 0x80);
411 ParseHIDData(this, bHasReportId, (uint8_t)read, buf);
413 HIDReportParser *prs = GetReportParser(((bHasReportId) ? *buf : 0));
416 prs->Parse(this, bHasReportId, (uint8_t)read, buf);
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);