Statistics
| Branch: | Tag: | Revision:

root / LUFA / Drivers / USB / Class / Common / HIDParser.c @ 978b99e5

History | View | Annotate | Download (10.8 KB)

1
/*
2
             LUFA Library
3
     Copyright (C) Dean Camera, 2011.
4

5
  dean [at] fourwalledcubicle [dot] com
6
           www.lufa-lib.org
7
*/
8

    
9
/*
10
  Copyright 2011  Dean Camera (dean [at] fourwalledcubicle [dot] com)
11

12
  Permission to use, copy, modify, distribute, and sell this
13
  software and its documentation for any purpose is hereby granted
14
  without fee, provided that the above copyright notice appear in
15
  all copies and that both that the copyright notice and this
16
  permission notice and warranty disclaimer appear in supporting
17
  documentation, and that the name of the author not be used in
18
  advertising or publicity pertaining to distribution of the
19
  software without specific, written prior permission.
20

21
  The author disclaim all warranties with regard to this
22
  software, including all implied warranties of merchantability
23
  and fitness.  In no event shall the author be liable for any
24
  special, indirect or consequential damages or any damages
25
  whatsoever resulting from loss of use, data or profits, whether
26
  in an action of contract, negligence or other tortious action,
27
  arising out of or in connection with the use or performance of
28
  this software.
29
*/
30

    
31
#define  __INCLUDE_FROM_USB_DRIVER
32
#define  __INCLUDE_FROM_HID_DRIVER
33
#include "HIDParser.h"
34

    
35
uint8_t USB_ProcessHIDReport(const uint8_t* ReportData,
36
                             uint16_t ReportSize,
37
                             HID_ReportInfo_t* const ParserData)
38
{
39
        HID_StateTable_t      StateTable[HID_STATETABLE_STACK_DEPTH];
40
        HID_StateTable_t*     CurrStateTable          = &StateTable[0];
41
        HID_CollectionPath_t* CurrCollectionPath      = NULL;
42
        HID_ReportSizeInfo_t* CurrReportIDInfo        = &ParserData->ReportIDSizes[0];
43
        uint16_t              UsageList[HID_USAGE_STACK_DEPTH];
44
        uint8_t               UsageListSize           = 0;
45
        HID_MinMax_t          UsageMinMax             = {0, 0};
46

    
47
        memset(ParserData,       0x00, sizeof(HID_ReportInfo_t));
48
        memset(CurrStateTable,   0x00, sizeof(HID_StateTable_t));
49
        memset(CurrReportIDInfo, 0x00, sizeof(HID_ReportSizeInfo_t));
50

    
51
        ParserData->TotalDeviceReports = 1;
52

    
53
        while (ReportSize)
54
        {
55
                uint8_t  HIDReportItem  = *ReportData;
56
                uint32_t ReportItemData = 0;
57

    
58
                ReportData++;
59
                ReportSize--;
60

    
61
                switch (HIDReportItem & HID_RI_DATA_SIZE_MASK)
62
                {
63
                        case HID_RI_DATA_BITS_32:
64
                                ReportItemData  = le32_to_cpu(*((uint32_t*)ReportData));
65
                                ReportSize     -= 4;
66
                                ReportData     += 4;
67
                                break;
68
                        case HID_RI_DATA_BITS_16:
69
                                ReportItemData  = le16_to_cpu(*((uint16_t*)ReportData));
70
                                ReportSize     -= 2;
71
                                ReportData     += 2;
72
                                break;
73
                        case HID_RI_DATA_BITS_8:
74
                                ReportItemData  = *((uint8_t*)ReportData);
75
                                ReportSize     -= 1;
76
                                ReportData     += 1;
77
                                break;
78
                }
79

    
80
                switch (HIDReportItem & (HID_RI_TYPE_MASK | HID_RI_TAG_MASK))
81
                {
82
                        case HID_RI_PUSH(0):
83
                                if (CurrStateTable == &StateTable[HID_STATETABLE_STACK_DEPTH - 1])
84
                                  return HID_PARSE_HIDStackOverflow;
85

    
86
                                memcpy((CurrStateTable + 1),
87
                                       CurrStateTable,
88
                                       sizeof(HID_ReportItem_t));
89

    
90
                                CurrStateTable++;
91
                                break;
92
                        case HID_RI_POP(0):
93
                                if (CurrStateTable == &StateTable[0])
94
                                  return HID_PARSE_HIDStackUnderflow;
95

    
96
                                CurrStateTable--;
97
                                break;
98
                        case HID_RI_USAGE_PAGE(0):
99
                                if ((HIDReportItem & HID_RI_DATA_SIZE_MASK) == HID_RI_DATA_BITS_32)
100
                                  CurrStateTable->Attributes.Usage.Page = (ReportItemData >> 16);
101
                                
102
                                CurrStateTable->Attributes.Usage.Page       = ReportItemData;
103
                                break;
104
                        case HID_RI_LOGICAL_MINIMUM(0):
105
                                CurrStateTable->Attributes.Logical.Minimum  = ReportItemData;
106
                                break;
107
                        case HID_RI_LOGICAL_MAXIMUM(0):
108
                                CurrStateTable->Attributes.Logical.Maximum  = ReportItemData;
109
                                break;
110
                        case HID_RI_PHYSICAL_MINIMUM(0):
111
                                CurrStateTable->Attributes.Physical.Minimum = ReportItemData;
112
                                break;
113
                        case HID_RI_PHYSICAL_MAXIMUM(0):
114
                                CurrStateTable->Attributes.Physical.Maximum = ReportItemData;
115
                                break;
116
                        case HID_RI_UNIT_EXPONENT(0):
117
                                CurrStateTable->Attributes.Unit.Exponent    = ReportItemData;
118
                                break;
119
                        case HID_RI_UNIT(0):
120
                                CurrStateTable->Attributes.Unit.Type        = ReportItemData;
121
                                break;
122
                        case HID_RI_REPORT_SIZE(0):
123
                                CurrStateTable->Attributes.BitSize          = ReportItemData;
124
                                break;
125
                        case HID_RI_REPORT_COUNT(0):
126
                                CurrStateTable->ReportCount                 = ReportItemData;
127
                                break;
128
                        case HID_RI_REPORT_ID(0):
129
                                CurrStateTable->ReportID                    = ReportItemData;
130

    
131
                                if (ParserData->UsingReportIDs)
132
                                {
133
                                        CurrReportIDInfo = NULL;
134

    
135
                                        for (uint8_t i = 0; i < ParserData->TotalDeviceReports; i++)
136
                                        {
137
                                                if (ParserData->ReportIDSizes[i].ReportID == CurrStateTable->ReportID)
138
                                                {
139
                                                        CurrReportIDInfo = &ParserData->ReportIDSizes[i];
140
                                                        break;
141
                                                }
142
                                        }
143

    
144
                                        if (CurrReportIDInfo == NULL)
145
                                        {
146
                                                if (ParserData->TotalDeviceReports == HID_MAX_REPORT_IDS)
147
                                                  return HID_PARSE_InsufficientReportIDItems;
148

    
149
                                                CurrReportIDInfo = &ParserData->ReportIDSizes[ParserData->TotalDeviceReports++];
150
                                                memset(CurrReportIDInfo, 0x00, sizeof(HID_ReportSizeInfo_t));
151
                                        }
152
                                }
153

    
154
                                ParserData->UsingReportIDs = true;
155

    
156
                                CurrReportIDInfo->ReportID = CurrStateTable->ReportID;
157
                                break;
158
                        case HID_RI_USAGE(0):
159
                                if (UsageListSize == HID_USAGE_STACK_DEPTH)
160
                                  return HID_PARSE_UsageListOverflow;
161

    
162
                                UsageList[UsageListSize++] = ReportItemData;
163
                                break;
164
                        case HID_RI_USAGE_MINIMUM(0):
165
                                UsageMinMax.Minimum = ReportItemData;
166
                                break;
167
                        case HID_RI_USAGE_MAXIMUM(0):
168
                                UsageMinMax.Maximum = ReportItemData;
169
                                break;
170
                        case HID_RI_COLLECTION(0):
171
                                if (CurrCollectionPath == NULL)
172
                                {
173
                                        CurrCollectionPath = &ParserData->CollectionPaths[0];
174
                                }
175
                                else
176
                                {
177
                                        HID_CollectionPath_t* ParentCollectionPath = CurrCollectionPath;
178

    
179
                                        CurrCollectionPath = &ParserData->CollectionPaths[1];
180

    
181
                                        while (CurrCollectionPath->Parent != NULL)
182
                                        {
183
                                                if (CurrCollectionPath == &ParserData->CollectionPaths[HID_MAX_COLLECTIONS - 1])
184
                                                  return HID_PARSE_InsufficientCollectionPaths;
185

    
186
                                                CurrCollectionPath++;
187
                                        }
188

    
189
                                        CurrCollectionPath->Parent = ParentCollectionPath;
190
                                }
191

    
192
                                CurrCollectionPath->Type       = ReportItemData;
193
                                CurrCollectionPath->Usage.Page = CurrStateTable->Attributes.Usage.Page;
194

    
195
                                if (UsageListSize)
196
                                {
197
                                        CurrCollectionPath->Usage.Usage = UsageList[0];
198

    
199
                                        for (uint8_t i = 0; i < UsageListSize; i++)
200
                                          UsageList[i] = UsageList[i + 1];
201

    
202
                                        UsageListSize--;
203
                                }
204
                                else if (UsageMinMax.Minimum <= UsageMinMax.Maximum)
205
                                {
206
                                        CurrCollectionPath->Usage.Usage = UsageMinMax.Minimum++;
207
                                }
208

    
209
                                break;
210
                        case HID_RI_END_COLLECTION(0):
211
                                if (CurrCollectionPath == NULL)
212
                                  return HID_PARSE_UnexpectedEndCollection;
213

    
214
                                CurrCollectionPath = CurrCollectionPath->Parent;
215
                                break;
216
                        case HID_RI_INPUT(0):
217
                        case HID_RI_OUTPUT(0):
218
                        case HID_RI_FEATURE(0):
219
                                for (uint8_t ReportItemNum = 0; ReportItemNum < CurrStateTable->ReportCount; ReportItemNum++)
220
                                {
221
                                        HID_ReportItem_t NewReportItem;
222

    
223
                                        memcpy(&NewReportItem.Attributes,
224
                                               &CurrStateTable->Attributes,
225
                                               sizeof(HID_ReportItem_Attributes_t));
226

    
227
                                        NewReportItem.ItemFlags      = ReportItemData;
228
                                        NewReportItem.CollectionPath = CurrCollectionPath;
229
                                        NewReportItem.ReportID       = CurrStateTable->ReportID;
230

    
231
                                        if (UsageListSize)
232
                                        {
233
                                                NewReportItem.Attributes.Usage.Usage = UsageList[0];
234

    
235
                                                for (uint8_t i = 0; i < UsageListSize; i++)
236
                                                  UsageList[i] = UsageList[i + 1];
237

    
238
                                                UsageListSize--;
239
                                        }
240
                                        else if (UsageMinMax.Minimum <= UsageMinMax.Maximum)
241
                                        {
242
                                                NewReportItem.Attributes.Usage.Usage = UsageMinMax.Minimum++;
243
                                        }
244

    
245
                                        uint8_t ItemTypeTag = (HIDReportItem & (HID_RI_TYPE_MASK | HID_RI_TAG_MASK));
246

    
247
                                        if (ItemTypeTag == HID_RI_INPUT(0))
248
                                          NewReportItem.ItemType = HID_REPORT_ITEM_In;
249
                                        else if (ItemTypeTag == HID_RI_OUTPUT(0))
250
                                          NewReportItem.ItemType = HID_REPORT_ITEM_Out;
251
                                        else
252
                                          NewReportItem.ItemType = HID_REPORT_ITEM_Feature;
253

    
254
                                        NewReportItem.BitOffset = CurrReportIDInfo->ReportSizeBits[NewReportItem.ItemType];
255

    
256
                                        CurrReportIDInfo->ReportSizeBits[NewReportItem.ItemType] += CurrStateTable->Attributes.BitSize;
257

    
258
                                        ParserData->LargestReportSizeBits = MAX(ParserData->LargestReportSizeBits, CurrReportIDInfo->ReportSizeBits[NewReportItem.ItemType]);
259

    
260
                                        if (ParserData->TotalReportItems == HID_MAX_REPORTITEMS)
261
                                          return HID_PARSE_InsufficientReportItems;
262

    
263
                                        memcpy(&ParserData->ReportItems[ParserData->TotalReportItems],
264
                                               &NewReportItem, sizeof(HID_ReportItem_t));
265

    
266
                                        if (!(ReportItemData & HID_IOF_CONSTANT) && CALLBACK_HIDParser_FilterHIDReportItem(&NewReportItem))
267
                                          ParserData->TotalReportItems++;
268
                                }
269

    
270
                                break;
271
                }
272

    
273
                if ((HIDReportItem & HID_RI_TYPE_MASK) == HID_RI_TYPE_MAIN)
274
                {
275
                        UsageMinMax.Minimum = 0;
276
                        UsageMinMax.Maximum = 0;
277
                        UsageListSize       = 0;
278
                }
279
        }
280

    
281
        if (!(ParserData->TotalReportItems))
282
          return HID_PARSE_NoUnfilteredReportItems;
283

    
284
        return HID_PARSE_Successful;
285
}
286

    
287
bool USB_GetHIDReportItemInfo(const uint8_t* ReportData,
288
                              HID_ReportItem_t* const ReportItem)
289
{
290
        if (ReportItem == NULL)
291
          return false;
292

    
293
        uint16_t DataBitsRem  = ReportItem->Attributes.BitSize;
294
        uint16_t CurrentBit   = ReportItem->BitOffset;
295
        uint32_t BitMask      = (1 << 0);
296

    
297
        if (ReportItem->ReportID)
298
        {
299
                if (ReportItem->ReportID != ReportData[0])
300
                  return false;
301

    
302
                ReportData++;
303
        }
304

    
305
        ReportItem->PreviousValue = ReportItem->Value;
306
        ReportItem->Value = 0;
307

    
308
        while (DataBitsRem--)
309
        {
310
                if (ReportData[CurrentBit / 8] & (1 << (CurrentBit % 8)))
311
                  ReportItem->Value |= BitMask;
312

    
313
                CurrentBit++;
314
                BitMask <<= 1;
315
        }
316

    
317
        return true;
318
}
319

    
320
void USB_SetHIDReportItemInfo(uint8_t* ReportData,
321
                              HID_ReportItem_t* const ReportItem)
322
{
323
        if (ReportItem == NULL)
324
          return;
325

    
326
        uint16_t DataBitsRem  = ReportItem->Attributes.BitSize;
327
        uint16_t CurrentBit   = ReportItem->BitOffset;
328
        uint32_t BitMask      = (1 << 0);
329

    
330
        if (ReportItem->ReportID)
331
        {
332
                ReportData[0] = ReportItem->ReportID;
333
                ReportData++;
334
        }
335

    
336
        ReportItem->PreviousValue = ReportItem->Value;
337

    
338
        while (DataBitsRem--)
339
        {
340
                if (ReportItem->Value & (1 << (CurrentBit % 8)))
341
                  ReportData[CurrentBit / 8] |= BitMask;
342

    
343
                CurrentBit++;
344
                BitMask <<= 1;
345
        }
346
}
347

    
348
uint16_t USB_GetHIDReportSize(HID_ReportInfo_t* const ParserData,
349
                              const uint8_t ReportID,
350
                              const uint8_t ReportType)
351
{
352
        for (uint8_t i = 0; i < HID_MAX_REPORT_IDS; i++)
353
        {
354
                uint16_t ReportSizeBits = ParserData->ReportIDSizes[i].ReportSizeBits[ReportType];
355

    
356
                if (ParserData->ReportIDSizes[i].ReportID == ReportID)
357
                  return (ReportSizeBits / 8) + ((ReportSizeBits % 8) ? 1 : 0);
358
        }
359

    
360
        return 0;
361
}