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 | #ifndef CONFDESCPARSER_H_INCLUDED
|
---|
19 | #define CONFDESCPARSER_H_INCLUDED
|
---|
20 |
|
---|
21 | #include <stdint.h>
|
---|
22 | #include "parsetools.h"
|
---|
23 |
|
---|
24 | /**
|
---|
25 | * \class Abstract UsbConfigXtracter definition.
|
---|
26 | *
|
---|
27 | * \note This class is used for extracting USB endpoint descriptors.
|
---|
28 | */
|
---|
29 | class UsbConfigXtracter
|
---|
30 | {
|
---|
31 | public:
|
---|
32 | virtual void EndpointXtract(uint32_t conf, uint32_t iface, uint32_t alt, uint32_t proto, const USB_ENDPOINT_DESCRIPTOR *ep) = 0;
|
---|
33 | };
|
---|
34 |
|
---|
35 | #define CP_MASK_COMPARE_CLASS 1
|
---|
36 | #define CP_MASK_COMPARE_SUBCLASS 2
|
---|
37 | #define CP_MASK_COMPARE_PROTOCOL 4
|
---|
38 | #define CP_MASK_COMPARE_ALL 7
|
---|
39 |
|
---|
40 | /**
|
---|
41 | * \class ConfigDescParser definition.
|
---|
42 | *
|
---|
43 | * \note This class is used for parsing configuration descriptors.
|
---|
44 | */
|
---|
45 | template <const uint8_t CLASS_ID, const uint8_t SUBCLASS_ID, const uint8_t PROTOCOL_ID, const uint8_t MASK>
|
---|
46 | class ConfigDescParser : public USBReadParser
|
---|
47 | {
|
---|
48 | UsbConfigXtracter *theXtractor;
|
---|
49 | MultiValueBuffer theBuffer;
|
---|
50 | MultiByteValueParser valParser;
|
---|
51 | ByteSkipper theSkipper;
|
---|
52 | uint8_t varBuffer[16 /*sizeof(USB_CONFIGURATION_DESCRIPTOR)*/];
|
---|
53 |
|
---|
54 | uint32_t stateParseDescr; // ParseDescriptor state
|
---|
55 |
|
---|
56 | uint32_t dscrLen; // Descriptor length
|
---|
57 | uint32_t dscrType; // Descriptor type
|
---|
58 |
|
---|
59 | bool isGoodInterface; // Apropriate interface flag
|
---|
60 | uint32_t confValue; // Configuration value
|
---|
61 | uint32_t protoValue; // Protocol value
|
---|
62 | uint32_t ifaceNumber; // Interface number
|
---|
63 | uint32_t ifaceAltSet; // Interface alternate settings
|
---|
64 |
|
---|
65 | bool ParseDescriptor(uint8_t **pp, uint32_t *pcntdn);
|
---|
66 |
|
---|
67 | void PrintHidDescriptor(const USB_HID_DESCRIPTOR *pDesc);
|
---|
68 |
|
---|
69 | public:
|
---|
70 | ConfigDescParser(UsbConfigXtracter *xtractor);
|
---|
71 | virtual void Parse(const uint32_t len, const uint8_t *pbuf, const uint32_t &offset);
|
---|
72 | };
|
---|
73 |
|
---|
74 | /**
|
---|
75 | * \brief ConfigDescParser class constructor.
|
---|
76 | *
|
---|
77 | * \param xtractor Is saved as ConfigDescParser attribute and later used as a
|
---|
78 | * callback for parsing the endpoint descriptors.
|
---|
79 | *
|
---|
80 | * \note During enumeration stage, all supported USB classes invoke
|
---|
81 | * ConfigDescParser with "this" as parameter, meaning that one class is also
|
---|
82 | * responsible for parsing its endpoint descriptors. This makes sense since
|
---|
83 | * each USB class handles different number of endpoints and configurations.
|
---|
84 | * For instance see ADK::Init from ADK class.
|
---|
85 | */
|
---|
86 | template <const uint8_t CLASS_ID, const uint8_t SUBCLASS_ID, const uint8_t PROTOCOL_ID, const uint8_t MASK>
|
---|
87 | ConfigDescParser<CLASS_ID, SUBCLASS_ID, PROTOCOL_ID, MASK>::ConfigDescParser(UsbConfigXtracter *xtractor) :
|
---|
88 | theXtractor(xtractor),
|
---|
89 | stateParseDescr(0),
|
---|
90 | dscrLen(0),
|
---|
91 | dscrType(0)
|
---|
92 | {
|
---|
93 | theBuffer.pValue = varBuffer;
|
---|
94 | valParser.Initialize(&theBuffer);
|
---|
95 | theSkipper.Initialize(&theBuffer);
|
---|
96 | };
|
---|
97 |
|
---|
98 | /**
|
---|
99 | * \brief Parse a complete USB configuration descriptor.
|
---|
100 | *
|
---|
101 | * \param len Buffer length.
|
---|
102 | * \param pbuf Buffer containing the configuration descriptor.
|
---|
103 | * \param offset Current offset position.
|
---|
104 | */
|
---|
105 | template <const uint8_t CLASS_ID, const uint8_t SUBCLASS_ID, const uint8_t PROTOCOL_ID, const uint8_t MASK>
|
---|
106 | void ConfigDescParser<CLASS_ID, SUBCLASS_ID, PROTOCOL_ID, MASK>::Parse(const uint32_t len, const uint8_t *pbuf, const uint32_t &offset)
|
---|
107 | {
|
---|
108 | uint32_t cntdn = len;
|
---|
109 | uint8_t *p = (uint8_t*)pbuf;
|
---|
110 |
|
---|
111 | while (cntdn)
|
---|
112 | if (!ParseDescriptor(&p, &cntdn))
|
---|
113 | return;
|
---|
114 | }
|
---|
115 |
|
---|
116 | /**
|
---|
117 | * \brief Parse a USB configuration descriptor.
|
---|
118 | * Takes values for class, subclass, protocol fields in interface descriptor
|
---|
119 | * and compare masks for them. When the match is found, calls EndpointXtract
|
---|
120 | * passing buffer containing endpoint descriptor.
|
---|
121 | *
|
---|
122 | * \note This method should not be called directly, use Parse() instead.
|
---|
123 | *
|
---|
124 | * \param pcntdn Buffer length.
|
---|
125 | * \param pp Buffer containing the configuration descriptor.
|
---|
126 | *
|
---|
127 | * \return true if data remains in the buffer for parsing, false otherwise.
|
---|
128 | */
|
---|
129 | template <const uint8_t CLASS_ID, const uint8_t SUBCLASS_ID, const uint8_t PROTOCOL_ID, const uint8_t MASK>
|
---|
130 | bool ConfigDescParser<CLASS_ID, SUBCLASS_ID, PROTOCOL_ID, MASK>::ParseDescriptor(uint8_t **pp, uint32_t *pcntdn)
|
---|
131 | {
|
---|
132 | switch (stateParseDescr)
|
---|
133 | {
|
---|
134 | case 0:
|
---|
135 | theBuffer.valueSize = 2;
|
---|
136 | valParser.Initialize(&theBuffer);
|
---|
137 | stateParseDescr = 1;
|
---|
138 | case 1:
|
---|
139 | if (!valParser.Parse(pp, pcntdn))
|
---|
140 | return false;
|
---|
141 | dscrLen = *((uint8_t*)theBuffer.pValue);
|
---|
142 | dscrType = *((uint8_t*)theBuffer.pValue + 1);
|
---|
143 | stateParseDescr = 2;
|
---|
144 | case 2:
|
---|
145 | // This is a sort of hack. Assuming that two bytes are already in the buffer
|
---|
146 | // the pointer is positioned two bytes ahead in order for the rest of descriptor
|
---|
147 | // to be read right after the size and the type fields.
|
---|
148 | // This should be used carefuly. varBuffer should be used directly to handle data
|
---|
149 | // in the buffer.
|
---|
150 | theBuffer.pValue = varBuffer + 2;
|
---|
151 | stateParseDescr = 3;
|
---|
152 | case 3:
|
---|
153 | switch (dscrType)
|
---|
154 | {
|
---|
155 | case USB_DESCRIPTOR_INTERFACE:
|
---|
156 | isGoodInterface = false;
|
---|
157 | case USB_DESCRIPTOR_CONFIGURATION:
|
---|
158 | theBuffer.valueSize = sizeof(USB_CONFIGURATION_DESCRIPTOR) - 2;
|
---|
159 | break;
|
---|
160 | case USB_DESCRIPTOR_ENDPOINT:
|
---|
161 | theBuffer.valueSize = sizeof(USB_ENDPOINT_DESCRIPTOR) - 2;
|
---|
162 | break;
|
---|
163 | case HID_DESCRIPTOR_HID:
|
---|
164 | theBuffer.valueSize = dscrLen - 2;
|
---|
165 | break;
|
---|
166 | }
|
---|
167 | valParser.Initialize(&theBuffer);
|
---|
168 | stateParseDescr = 4;
|
---|
169 | case 4:
|
---|
170 | switch (dscrType)
|
---|
171 | {
|
---|
172 | case USB_DESCRIPTOR_CONFIGURATION:
|
---|
173 | if (!valParser.Parse(pp, pcntdn))
|
---|
174 | return false;
|
---|
175 | confValue = ((USB_CONFIGURATION_DESCRIPTOR*)varBuffer)->bConfigurationValue;
|
---|
176 | break;
|
---|
177 | case USB_DESCRIPTOR_INTERFACE:
|
---|
178 | if (!valParser.Parse(pp, pcntdn))
|
---|
179 | return false;
|
---|
180 | if ((MASK & CP_MASK_COMPARE_CLASS) && ((USB_INTERFACE_DESCRIPTOR*)varBuffer)->bInterfaceClass != CLASS_ID)
|
---|
181 | break;
|
---|
182 | if ((MASK & CP_MASK_COMPARE_SUBCLASS) && ((USB_INTERFACE_DESCRIPTOR*)varBuffer)->bInterfaceSubClass != SUBCLASS_ID)
|
---|
183 | break;
|
---|
184 | if ((MASK & CP_MASK_COMPARE_PROTOCOL) && ((USB_INTERFACE_DESCRIPTOR*)varBuffer)->bInterfaceProtocol != PROTOCOL_ID)
|
---|
185 | break;
|
---|
186 |
|
---|
187 | isGoodInterface = true;
|
---|
188 | ifaceNumber = ((USB_INTERFACE_DESCRIPTOR*)varBuffer)->bInterfaceNumber;
|
---|
189 | ifaceAltSet = ((USB_INTERFACE_DESCRIPTOR*)varBuffer)->bAlternateSetting;
|
---|
190 | protoValue = ((USB_INTERFACE_DESCRIPTOR*)varBuffer)->bInterfaceProtocol;
|
---|
191 | break;
|
---|
192 | case USB_DESCRIPTOR_ENDPOINT:
|
---|
193 | if (!valParser.Parse(pp, pcntdn))
|
---|
194 | return false;
|
---|
195 | if (isGoodInterface)
|
---|
196 | if (theXtractor)
|
---|
197 | theXtractor->EndpointXtract(confValue, ifaceNumber, ifaceAltSet, protoValue, (USB_ENDPOINT_DESCRIPTOR*)varBuffer);
|
---|
198 | break;
|
---|
199 | //case HID_DESCRIPTOR_HID:
|
---|
200 | // if (!valParser.Parse(pp, pcntdn))
|
---|
201 | // return false;
|
---|
202 | // PrintHidDescriptor((const USB_HID_DESCRIPTOR*)varBuffer);
|
---|
203 | // break;
|
---|
204 | default:
|
---|
205 | if (!theSkipper.Skip(pp, pcntdn, dscrLen - 2))
|
---|
206 | return false;
|
---|
207 | }
|
---|
208 | theBuffer.pValue = varBuffer;
|
---|
209 | stateParseDescr = 0;
|
---|
210 | }
|
---|
211 | return true;
|
---|
212 | }
|
---|
213 |
|
---|
214 | /**
|
---|
215 | * \brief Print HID descriptor.
|
---|
216 | *
|
---|
217 | * \note TRACE_USBHOST macro must be enabled. See Usb.h for reference.
|
---|
218 | *
|
---|
219 | * \param pDesc Pointer to HID descriptor.
|
---|
220 | */
|
---|
221 | template <const uint8_t CLASS_ID, const uint8_t SUBCLASS_ID, const uint8_t PROTOCOL_ID, const uint8_t MASK>
|
---|
222 | void ConfigDescParser<CLASS_ID, SUBCLASS_ID, PROTOCOL_ID, MASK>::PrintHidDescriptor(const USB_HID_DESCRIPTOR *pDesc)
|
---|
223 | {
|
---|
224 | TRACE_USBHOST(printf("ConfigDescParser::PrintHidDescriptor : bDescLength: %d\r\n", pDesc->bLength);)
|
---|
225 | TRACE_USBHOST(printf("ConfigDescParser::PrintHidDescriptor : bDescriptorType: %d\r\n", pDesc->bDescriptorType);)
|
---|
226 | TRACE_USBHOST(printf("ConfigDescParser::PrintHidDescriptor : bcdHID: %d\r\n", pDesc->bcdHID);)
|
---|
227 | TRACE_USBHOST(printf("ConfigDescParser::PrintHidDescriptor : bCountryCode: %d\r\n", pDesc->bCountryCode);)
|
---|
228 | TRACE_USBHOST(printf("ConfigDescParser::PrintHidDescriptor : bNumDescriptors: %d\r\n", pDesc->bNumDescriptors);)
|
---|
229 | TRACE_USBHOST(printf("ConfigDescParser::PrintHidDescriptor : bDescrType: %d\r\n", pDesc->bDescrType);)
|
---|
230 | TRACE_USBHOST(printf("ConfigDescParser::PrintHidDescriptor : wDescriptorLength: %d\r\n", pDesc->wDescriptorLength);)
|
---|
231 |
|
---|
232 | for (uint32_t i = 0; i < pDesc->bNumDescriptors; ++i)
|
---|
233 | {
|
---|
234 | HID_CLASS_DESCRIPTOR_LEN_AND_TYPE *pLT = (HID_CLASS_DESCRIPTOR_LEN_AND_TYPE*)&(pDesc->bDescrType);
|
---|
235 |
|
---|
236 | TRACE_USBHOST(printf("ConfigDescParser::PrintHidDescriptor : bDescrType: %d\r\n", pLT[i].bDescrType);)
|
---|
237 | TRACE_USBHOST(printf("ConfigDescParser::PrintHidDescriptor : wDescriptorLength: %d\r\n", pLT[i].wDescriptorLength);)
|
---|
238 | }
|
---|
239 | }
|
---|
240 |
|
---|
241 | #endif /* CONFDESCPARSER_H_INCLUDED */
|
---|