1/*
2 * @APPLE_LICENSE_HEADER_START@
3 *
4 * Copyright (c) 1999-2003 Apple Computer, Inc.  All Rights Reserved.
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
11 * file.
12 *
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23/*
24	File:		HIDProcessLocalItem.c
25
26	Contains:	xxx put contents here xxx
27
28	Version:	xxx put version here xxx
29
30	Copyright:	� 1999 by Apple Computer, Inc., all rights reserved.
31
32	File Ownership:
33
34		DRI:				xxx put dri here xxx
35
36		Other Contact:		xxx put other contact here xxx
37
38		Technology:			xxx put technology here xxx
39
40	Writers:
41
42		(BWS)	Brent Schorsch
43
44	Change History (most recent first):
45
46	  <USB1>	  3/5/99	BWS		first checked in
47*/
48
49#include "HIDLib.h"
50
51/*
52 *------------------------------------------------------------------------------
53 *
54 * HIDProcessLocalItem - Process a LocalItem
55 *
56 *   Input:
57 *            ptDescriptor          - The Descriptor Structure
58 *            ptPreparsedData       - The PreParsedData Structure
59 *   Output:
60 *            ptPreparsedData       - The PreParsedData Structure
61 *   Returns:
62 *            kHIDSuccess          - Success
63 *            kHIDNullPointerErr      - Argument, Pointer was Null
64 *
65 *------------------------------------------------------------------------------
66*/
67OSStatus HIDProcessLocalItem(HIDReportDescriptor *ptDescriptor,
68                                  HIDPreparsedDataPtr ptPreparsedData)
69{
70    HIDDesignatorItem *ptDesignatorItem;
71    HIDStringItem *ptStringItem;
72    HIDP_UsageItem *ptUsageItem;
73    HIDItem *ptItem;
74/*
75 *  Disallow NULL Pointers
76*/
77    if ((ptDescriptor == NULL) || (ptPreparsedData == NULL))
78        return kHIDNullPointerErr;
79/*
80 *  Process the LocalItem by tag
81*/
82    ptItem = &ptDescriptor->item;
83    switch (ptItem->tag)
84    {
85/*
86 *      Note that Tag = usage Item may represent either
87 *          a UsagePair with the usagePage implied, or
88 *          a UsagePair defined by an extended usage
89 *      If a Tag = usage Item has 1 or 2 bytes of data
90 *          then the current usagePage is used
91 *      If a Tag = usage Item has 4 bytes of data
92 *          then the high order bytes are the usagePage
93 *
94 *      Note that the Microsoft HID Parser uses the last
95 *          usagePage defined before the MainItem with which
96 *          the usage is associated rather than the current
97 *          usagePage.  The method used here is more generic
98 *          although multiple UsagePages for a MainItem are
99 *          unlikely due to the MS limitation.
100*/
101        case kHIDTagUsage:
102            ptUsageItem = &ptPreparsedData->usageItems[ptPreparsedData->usageItemCount++];
103            ptUsageItem->isRange = false;
104            if (ptItem->byteCount == 4)
105            {
106                ptUsageItem->usagePage = ptItem->unsignedValue>>16;
107                ptUsageItem->usage = ptItem->unsignedValue&0xFFFFL;
108            }
109            else
110            {
111                ptUsageItem->usagePage = ptDescriptor->globals.usagePage;
112                ptUsageItem->usage = ptItem->unsignedValue;
113            }
114            break;
115/*
116 *      Note that Tag = usage Minimum Item may represent either
117 *          a UsagePair with the usagePage implied, or
118 *          a UsagePair defined by an extended usage
119 *      If a Tag = usage Item has 1 or 2 bytes of data
120 *          then the current usagePage is used
121 *      If a Tag = usage Item has 4 bytes of data
122 *          then the high order bytes are the usagePage
123*/
124        case kHIDTagUsageMinimum:
125            if (ptDescriptor->haveUsageMax)
126            {
127                ptUsageItem = &ptPreparsedData->usageItems[ptPreparsedData->usageItemCount++];
128                ptUsageItem->isRange = true;
129                if (ptItem->byteCount == 4)
130                {
131                    ptUsageItem->usagePage = ptItem->unsignedValue>>16;
132                    ptUsageItem->usageMinimum = ptItem->unsignedValue&0xFFFFL;
133                }
134                else
135                {
136                    ptUsageItem->usagePage = ptDescriptor->globals.usagePage;
137                    ptUsageItem->usageMinimum = ptItem->unsignedValue;
138                }
139                if (ptUsageItem->usagePage != ptDescriptor->rangeUsagePage)
140                    return kHIDInvalidRangePageErr;
141                ptUsageItem->usageMaximum = ptDescriptor->usageMaximum;
142                if (ptUsageItem->usageMaximum < ptUsageItem->usageMinimum)
143                    return kHIDInvertedUsageRangeErr;
144                ptDescriptor->haveUsageMax = false;
145                ptDescriptor->haveUsageMin = false;
146            }
147            else
148            {
149                if (ptItem->byteCount == 4)
150                {
151                    ptDescriptor->rangeUsagePage = ptItem->unsignedValue>>16;
152                    ptDescriptor->usageMinimum = ptItem->unsignedValue&0xFFFFL;
153                }
154                else
155                {
156                    ptDescriptor->rangeUsagePage = ptDescriptor->globals.usagePage;
157                    ptDescriptor->usageMinimum = ptItem->unsignedValue;
158                }
159                ptDescriptor->haveUsageMin = true;
160            }
161            break;
162/*
163 *      Note that Tag = usage Maximum Item may represent either
164 *          a UsagePair with the usagePage implied, or
165 *          a UsagePair defined by an extended usage
166 *      If a Tag = usage Item has 1 or 2 bytes of data
167 *          then the current usagePage is used
168 *      If a Tag = usage Item has 4 bytes of data
169 *          then the high order bytes are the usagePage
170*/
171        case kHIDTagUsageMaximum:
172            if (ptDescriptor->haveUsageMin)
173            {
174                ptUsageItem = &ptPreparsedData->usageItems[ptPreparsedData->usageItemCount++];
175                ptUsageItem->isRange = true;
176                if (ptItem->byteCount == 4)
177                {
178                    ptUsageItem->usagePage = ptItem->unsignedValue>>16;
179                    ptUsageItem->usageMaximum = ptItem->unsignedValue&0xFFFFL;
180                }
181                else
182                {
183                    ptUsageItem->usagePage = ptDescriptor->globals.usagePage;
184                    ptUsageItem->usageMaximum = ptItem->unsignedValue;
185                }
186                if (ptUsageItem->usagePage != ptDescriptor->rangeUsagePage)
187                    return kHIDInvalidRangePageErr;
188                ptUsageItem->usageMinimum = ptDescriptor->usageMinimum;
189                if (ptUsageItem->usageMaximum < ptUsageItem->usageMinimum)
190                    return kHIDInvertedUsageRangeErr;
191                ptDescriptor->haveUsageMax = false;
192                ptDescriptor->haveUsageMin = false;
193            }
194            else
195            {
196                if (ptItem->byteCount == 4)
197                {
198                    ptDescriptor->rangeUsagePage = ptItem->unsignedValue>>16;
199                    ptDescriptor->usageMaximum = ptItem->unsignedValue&0xFFFFL;
200                }
201                else
202                {
203                    ptDescriptor->rangeUsagePage = ptDescriptor->globals.usagePage;
204                    ptDescriptor->usageMaximum = ptItem->unsignedValue;
205                }
206                ptDescriptor->haveUsageMax = true;
207            }
208            break;
209/*
210 *      Designators
211*/
212        case kHIDTagDesignatorIndex:
213            ptDesignatorItem = &ptPreparsedData->desigItems[ptPreparsedData->desigItemCount++];
214            ptDesignatorItem->isRange = false;
215            ptDesignatorItem->index = ptItem->unsignedValue;
216            break;
217        case kHIDTagDesignatorMinimum:
218            if (ptDescriptor->haveDesigMax)
219            {
220                ptDesignatorItem = &ptPreparsedData->desigItems[ptPreparsedData->desigItemCount++];
221                ptDesignatorItem->isRange = true;
222                ptDesignatorItem->minimum = ptItem->unsignedValue;
223                ptDesignatorItem->maximum = ptDescriptor->desigMaximum;
224                ptDescriptor->haveDesigMin = false;
225                ptDescriptor->haveDesigMax = false;
226            }
227            else
228            {
229                ptDescriptor->desigMinimum = ptItem->unsignedValue;
230                ptDescriptor->haveDesigMin = true;
231            }
232            break;
233        case kHIDTagDesignatorMaximum:
234            if (ptDescriptor->haveDesigMin)
235            {
236                ptDesignatorItem = &ptPreparsedData->desigItems[ptPreparsedData->desigItemCount++];
237                ptDesignatorItem->isRange = true;
238                ptDesignatorItem->maximum = ptItem->unsignedValue;
239                ptDesignatorItem->minimum = ptDescriptor->desigMinimum;
240                ptDescriptor->haveDesigMin = false;
241                ptDescriptor->haveDesigMax = false;
242            }
243            else
244            {
245                ptDescriptor->desigMaximum = ptItem->unsignedValue;
246                ptDescriptor->haveDesigMax = true;
247            }
248            break;
249/*
250 *      Strings
251*/
252        case kHIDTagStringIndex:
253            ptStringItem = &ptPreparsedData->stringItems[ptPreparsedData->stringItemCount++];
254            ptStringItem->isRange = false;
255            ptStringItem->index = ptItem->unsignedValue;
256            break;
257        case kHIDTagStringMinimum:
258            if (ptDescriptor->haveStringMax)
259            {
260                ptStringItem = &ptPreparsedData->stringItems[ptPreparsedData->stringItemCount++];
261                ptStringItem->isRange = true;
262                ptStringItem->minimum = ptItem->unsignedValue;
263                ptStringItem->maximum = ptDescriptor->stringMaximum;
264                ptDescriptor->haveStringMin = false;
265                ptDescriptor->haveStringMax = false;
266            }
267            else
268            {
269                ptDescriptor->stringMinimum = ptItem->unsignedValue;
270                ptDescriptor->haveStringMin = true;
271            }
272            break;
273        case kHIDTagStringMaximum:
274            if (ptDescriptor->haveStringMin)
275            {
276                ptStringItem = &ptPreparsedData->stringItems[ptPreparsedData->stringItemCount++];
277                ptStringItem->isRange = true;
278                ptStringItem->maximum = ptItem->unsignedValue;
279                ptStringItem->minimum = ptDescriptor->stringMinimum;
280                ptDescriptor->haveStringMin = false;
281                ptDescriptor->haveStringMax = false;
282            }
283            else
284            {
285                ptDescriptor->stringMaximum = ptItem->unsignedValue;
286                ptDescriptor->haveStringMax = true;
287            }
288            break;
289/*
290 *      Delimiters (are not processed)
291*/
292        case kHIDTagSetDelimiter:
293            break;
294    }
295    return kHIDSuccess;
296}
297