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
);