]> git.saurik.com Git - apple/xnu.git/blob - iokit/Families/IOHIDSystem/IOHIDDescriptorParser/HIDGetButtonCaps.c
53b9108839c68c08f9c37db0f0f5a9951a94a6f2
[apple/xnu.git] / iokit / Families / IOHIDSystem / IOHIDDescriptorParser / HIDGetButtonCaps.c
1 /*
2 * Copyright (c) 1998-2000 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * The contents of this file constitute Original Code as defined in and
7 * are subject to the Apple Public Source License Version 1.1 (the
8 * "License"). You may not use this file except in compliance with the
9 * License. Please obtain a copy of the License at
10 * http://www.apple.com/publicsource and read it before using this file.
11 *
12 * This Original Code and all software distributed under the License are
13 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
14 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
15 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
17 * License for the specific language governing rights and limitations
18 * under the License.
19 *
20 * @APPLE_LICENSE_HEADER_END@
21 */
22 /*
23 File: HIDGetButtonCaps.c
24
25 Contains: xxx put contents here xxx
26
27 Version: xxx put version here xxx
28
29 Copyright: © 1999-2001 by Apple Computer, Inc., all rights reserved.
30
31 File Ownership:
32
33 DRI: xxx put dri here xxx
34
35 Other Contact: xxx put other contact here xxx
36
37 Technology: xxx put technology here xxx
38
39 Writers:
40
41 (KH) Keithen Hayenga
42 (BWS) Brent Schorsch
43
44 Change History (most recent first):
45
46 <USB5> 4/21/00 KH Added HIDGetButtonCapabilities and
47 HIDGetSpecificButtonCapabilities that now allow users to find
48 HID report units and exponents.
49 <USB4> 11/1/99 BWS [2405720] We need a better check for 'bit padding' items,
50 rather than just is constant. We will check to make sure the
51 item is constant, and has no usage, or zero usage. This means we
52 need to pass an additional parameter to some internal functions
53 <USB3> 5/3/99 BWS We were not setting isStringRange, isDesignatorRange, and
54 isAbsolute
55 <USB2> 3/7/99 BWS When range/notRange were made a union, we missed this case where
56 they were both being set indescriminately
57 <USB1> 3/5/99 BWS first checked in
58 */
59
60 #include "HIDLib.h"
61
62 /*
63 *------------------------------------------------------------------------------
64 *
65 * HIDGetSpecificButtonCaps - Get the binary values for a report type
66 *
67 * Input:
68 * reportType - HIDP_Input, HIDP_Output, HIDP_Feature
69 * usagePage - Page Criteria or zero
70 * iCollection - Collection Criteria or zero
71 * usage - usage Criteria or zero
72 * buttonCaps - ButtonCaps Array
73 * piButtonCapsLength - Maximum Entries
74 * ptPreparsedData - Pre-Parsed Data
75 * Output:
76 * piButtonCapsLength - Entries Populated
77 * Returns:
78 *
79 *------------------------------------------------------------------------------
80 */
81 OSStatus HIDGetSpecificButtonCaps(HIDReportType reportType,
82 HIDUsage usagePage,
83 UInt32 iCollection,
84 HIDUsage usage,
85 HIDButtonCapsPtr buttonCaps,
86 UInt32 *piButtonCapsLength,
87 HIDPreparsedDataRef preparsedDataRef)
88 {
89 HIDPreparsedDataPtr ptPreparsedData = (HIDPreparsedDataPtr) preparsedDataRef;
90 HIDCollection *ptCollection;
91 HIDCollection *ptParent;
92 HIDReportItem *ptReportItem;
93 HIDP_UsageItem *ptUsageItem;
94 HIDStringItem *ptStringItem;
95 HIDDesignatorItem *ptDesignatorItem;
96 HIDP_UsageItem *ptFirstCollectionUsageItem;
97 HIDButtonCaps *ptCapability;
98 int iR, iU;
99 int parent;
100 int iReportItem, iUsageItem;
101 int iMaxCaps;
102 // There are 3 versions of HID Parser code all based on the same logic: OS 9 HID Library;
103 // OSX xnu; OSX IOKitUser. They should all be nearly the same logic. This version (xnu)
104 // is based on older OS 9 code. This version has added logic to maintain this startBit.
105 // I don't know why it is here, but believe if it is needed here, it would probably be
106 // needed in the other two implementations. Didn't have time to determine that at this
107 // time, so i'll leave this comment to remind me that we should reconcile the 3 versions.
108 UInt32 startBit; // Added esb 9-29-99
109 /*If I remember correctly, it was an optimization. Each time you ask for
110 a specific value capability, it would search through the entire report
111 descriptor to find it (my recollection is kind of hazy on this part).
112 The start bit allowed somebody (client maybe) to cache the information
113 on where in the report a specific value resided and the use that later
114 when fetching that value. That way, you don't have to keep going
115 through the parse tree to find where a value exists. I don't remember
116 if the implementation was completed or if I even used it. -esb */
117 /*
118 * Disallow Null Pointers
119 */
120 if ((buttonCaps == NULL)
121 || (piButtonCapsLength == NULL)
122 || (ptPreparsedData == NULL))
123 return kHIDNullPointerErr;
124 if (ptPreparsedData->hidTypeIfValid != kHIDOSType)
125 return kHIDInvalidPreparsedDataErr;
126 /*
127 * Save the buffer size
128 */
129 iMaxCaps = *piButtonCapsLength;
130 *piButtonCapsLength = 0;
131 /*
132 * The Collection must be in range
133 */
134 if ((iCollection < 0) || (iCollection >= ptPreparsedData->collectionCount))
135 return kHIDBadParameterErr;
136 /*
137 * Search only the scope of the Collection specified
138 */
139 ptCollection = &ptPreparsedData->collections[iCollection];
140 for (iR=0; iR<ptCollection->reportItemCount; iR++)
141 {
142 iReportItem = ptCollection->firstReportItem + iR;
143 ptReportItem = &ptPreparsedData->reportItems[iReportItem];
144 /*
145 * Search only reports of the proper type
146 */
147 if ((ptReportItem->reportType == reportType)
148 && HIDIsButton(ptReportItem, preparsedDataRef))
149 {
150 startBit = ptReportItem->startBit;
151 /*
152 * Search the usages
153 */
154 for (iU=0; iU<ptReportItem->usageItemCount; iU++)
155 {
156 /*
157 * Copy all usages if the usage above is zero
158 * or copy all that are "match"
159 */
160 iUsageItem = ptReportItem->firstUsageItem + iU;
161 ptUsageItem = &ptPreparsedData->usageItems[iUsageItem];
162
163 // ¥¥ we assume there is a 1-1 corresponence between usage items, string items, and designator items
164 // ¥¥Êthis is not necessarily the case, but its better than nothing
165 ptStringItem = &ptPreparsedData->stringItems[ptReportItem->firstStringItem + iU];
166 ptDesignatorItem = &ptPreparsedData->desigItems[ptReportItem->firstDesigItem + iU];
167
168 if (HIDUsageInRange(ptUsageItem,usagePage,usage))
169 {
170 /*
171 * Only copy if there's room
172 */
173 if (*piButtonCapsLength >= iMaxCaps)
174 return kHIDBufferTooSmallErr;
175 ptCapability = &buttonCaps[(*piButtonCapsLength)++];
176 /*
177 * Populate the Capability Structure
178 */
179 parent = ptReportItem->parent;
180 ptParent = &ptPreparsedData->collections[parent];
181 ptFirstCollectionUsageItem
182 = &ptPreparsedData->usageItems[ptParent->firstUsageItem];
183 ptCapability->collection = parent;
184 ptCapability->collectionUsagePage = ptParent->usagePage;
185 ptCapability->collectionUsage = ptFirstCollectionUsageItem->usage;
186 ptCapability->bitField = ptReportItem->dataModes;
187 ptCapability->reportID = ptReportItem->globals.reportID;
188 ptCapability->usagePage = ptUsageItem->usagePage;
189
190 ptCapability->isStringRange = false; // ¥¥ todo: set this and stringMin,stringMax,stringIndex
191 ptCapability->isDesignatorRange = false; // ¥¥ todo: set this and designatorMin,designatorMax,designatorIndex
192 ptCapability->isAbsolute = !(ptReportItem->dataModes & kHIDDataRelative);
193
194 ptCapability->isRange = ptUsageItem->isRange;
195 if (ptUsageItem->isRange)
196 {
197 ptCapability->u.range.usageMin = ptUsageItem->usageMinimum;
198 ptCapability->u.range.usageMax = ptUsageItem->usageMaximum;
199 }
200 else
201 ptCapability->u.notRange.usage = ptUsageItem->usage;
202
203 // if there really are that many items
204 if (iU < ptReportItem->stringItemCount)
205 {
206 ptCapability->isStringRange = ptStringItem->isRange;
207
208 if (ptStringItem->isRange)
209 {
210 ptCapability->u.range.stringMin = ptStringItem->minimum;
211 ptCapability->u.range.stringMax = ptStringItem->maximum;
212 }
213 else
214 ptCapability->u.notRange.stringIndex = ptStringItem->index;
215 }
216 // default, clear it
217 else
218 {
219 ptCapability->isStringRange = false;
220 ptCapability->u.notRange.stringIndex = 0;
221 }
222
223 // if there really are that many items
224 if (iU < ptReportItem->desigItemCount)
225 {
226 ptCapability->isDesignatorRange = ptDesignatorItem->isRange;
227
228 if (ptDesignatorItem->isRange)
229 {
230 ptCapability->u.range.designatorMin = ptDesignatorItem->minimum;
231 ptCapability->u.range.designatorMax = ptDesignatorItem->maximum;
232 }
233 else
234 ptCapability->u.notRange.designatorIndex = ptDesignatorItem->index;
235 }
236 // default, clear it
237 else
238 {
239 ptCapability->isDesignatorRange = false;
240 ptCapability->u.notRange.designatorIndex = 0;
241 }
242 ptCapability->startBit = startBit;
243 }
244 startBit += (ptReportItem->globals.reportSize * ptReportItem->globals.reportCount);
245 }
246 }
247 }
248 return kHIDSuccess;
249 }
250
251 /*
252 *------------------------------------------------------------------------------
253 *
254 * HIDGetButtonCaps - Get the binary values for a report type
255 *
256 * Input:
257 * reportType - HIDP_Input, HIDP_Output, HIDP_Feature
258 * buttonCaps - ButtonCaps Array
259 * piButtonCapsLength - Maximum Entries
260 * ptPreparsedData - Pre-Parsed Data
261 * Output:
262 * piButtonCapsLength - Entries Populated
263 * Returns:
264 *
265 *------------------------------------------------------------------------------
266 */
267 OSStatus HIDGetButtonCaps(HIDReportType reportType,
268 HIDButtonCapsPtr buttonCaps,
269 UInt32 *piButtonCapsLength,
270 HIDPreparsedDataRef preparsedDataRef)
271 {
272 return HIDGetSpecificButtonCaps(reportType,0,0,0,buttonCaps,
273 piButtonCapsLength,preparsedDataRef);
274 }
275
276
277 /*
278 *------------------------------------------------------------------------------
279 *
280 * HIDGetSpecificButtonCapabilities - Get the binary values for a report type
281 * This is the same as HIDGetSpecificButtonCaps,
282 * except that it takes a HIDButtonCapabilitiesPtr
283 * so it can return units and unitExponents.
284 *
285 * Input:
286 * reportType - HIDP_Input, HIDP_Output, HIDP_Feature
287 * usagePage - Page Criteria or zero
288 * iCollection - Collection Criteria or zero
289 * usage - usage Criteria or zero
290 * buttonCaps - ButtonCaps Array
291 * piButtonCapsLength - Maximum Entries
292 * ptPreparsedData - Pre-Parsed Data
293 * Output:
294 * piButtonCapsLength - Entries Populated
295 * Returns:
296 *
297 *------------------------------------------------------------------------------
298 */
299 OSStatus HIDGetSpecificButtonCapabilities(HIDReportType reportType,
300 HIDUsage usagePage,
301 UInt32 iCollection,
302 HIDUsage usage,
303 HIDButtonCapabilitiesPtr buttonCaps,
304 UInt32 *piButtonCapsLength,
305 HIDPreparsedDataRef preparsedDataRef)
306 {
307 HIDPreparsedDataPtr ptPreparsedData = (HIDPreparsedDataPtr) preparsedDataRef;
308 HIDCollection *ptCollection;
309 HIDCollection *ptParent;
310 HIDReportItem *ptReportItem;
311 HIDP_UsageItem *ptUsageItem;
312 HIDStringItem *ptStringItem;
313 HIDDesignatorItem *ptDesignatorItem;
314 HIDP_UsageItem *ptFirstCollectionUsageItem;
315 HIDButtonCapabilities *ptCapability;
316 int iR, iU;
317 int parent;
318 int iReportItem, iUsageItem;
319 int iMaxCaps;
320 // There are 3 versions of HID Parser code all based on the same logic: OS 9 HID Library;
321 // OSX xnu; OSX IOKitUser. They should all be nearly the same logic. This version (xnu)
322 // is based on older OS 9 code. This version has added logic to maintain this startBit.
323 // I don't know why it is here, but believe if it is needed here, it would probably be
324 // needed in the other two implementations. Didn't have time to determine that at this
325 // time, so i'll leave this comment to remind me that we should reconcile the 3 versions.
326 UInt32 startBit;
327 /*
328 * Disallow Null Pointers
329 */
330 if ((buttonCaps == NULL)
331 || (piButtonCapsLength == NULL)
332 || (ptPreparsedData == NULL))
333 return kHIDNullPointerErr;
334 if (ptPreparsedData->hidTypeIfValid != kHIDOSType)
335 return kHIDInvalidPreparsedDataErr;
336 /*
337 * Save the buffer size
338 */
339 iMaxCaps = *piButtonCapsLength;
340 *piButtonCapsLength = 0;
341 /*
342 * The Collection must be in range
343 */
344 if ((iCollection < 0) || (iCollection >= ptPreparsedData->collectionCount))
345 return kHIDBadParameterErr;
346 /*
347 * Search only the scope of the Collection specified
348 */
349 ptCollection = &ptPreparsedData->collections[iCollection];
350 for (iR=0; iR<ptCollection->reportItemCount; iR++)
351 {
352 iReportItem = ptCollection->firstReportItem + iR;
353 ptReportItem = &ptPreparsedData->reportItems[iReportItem];
354 /*
355 * Search only reports of the proper type
356 */
357 if ((ptReportItem->reportType == reportType)
358 && HIDIsButton(ptReportItem, preparsedDataRef))
359 {
360 startBit = ptReportItem->startBit;
361 /*
362 * Search the usages
363 */
364 for (iU=0; iU<ptReportItem->usageItemCount; iU++)
365 {
366 /*
367 * Copy all usages if the usage above is zero
368 * or copy all that are "match"
369 */
370 iUsageItem = ptReportItem->firstUsageItem + iU;
371 ptUsageItem = &ptPreparsedData->usageItems[iUsageItem];
372
373 // ¥¥ we assume there is a 1-1 corresponence between usage items, string items, and designator items
374 // ¥¥Êthis is not necessarily the case, but its better than nothing
375 ptStringItem = &ptPreparsedData->stringItems[ptReportItem->firstStringItem + iU];
376 ptDesignatorItem = &ptPreparsedData->desigItems[ptReportItem->firstDesigItem + iU];
377
378 if (HIDUsageInRange(ptUsageItem,usagePage,usage))
379 {
380 /*
381 * Only copy if there's room
382 */
383 if (*piButtonCapsLength >= iMaxCaps)
384 return kHIDBufferTooSmallErr;
385 ptCapability = &buttonCaps[(*piButtonCapsLength)++];
386 /*
387 * Populate the Capability Structure
388 */
389 parent = ptReportItem->parent;
390 ptParent = &ptPreparsedData->collections[parent];
391 ptFirstCollectionUsageItem
392 = &ptPreparsedData->usageItems[ptParent->firstUsageItem];
393 ptCapability->collection = parent;
394 ptCapability->collectionUsagePage = ptParent->usagePage;
395 ptCapability->collectionUsage = ptFirstCollectionUsageItem->usage;
396 ptCapability->bitField = ptReportItem->dataModes;
397 ptCapability->reportID = ptReportItem->globals.reportID;
398 ptCapability->usagePage = ptUsageItem->usagePage;
399 ptCapability->unitExponent = ptReportItem->globals.unitExponent;
400 ptCapability->units = ptReportItem->globals.units;
401 // ptCapability->reserved = 0; // for future OS 9 expansion
402 ptCapability->startBit = 0; // init esb added field.
403 // ptCapability->pbVersion = kHIDCurrentCapabilitiesPBVersion;
404 ptCapability->pbVersion = 2;
405
406 ptCapability->isStringRange = false; // ¥¥ todo: set this and stringMin,stringMax,stringIndex
407 ptCapability->isDesignatorRange = false; // ¥¥ todo: set this and designatorMin,designatorMax,designatorIndex
408 ptCapability->isAbsolute = !(ptReportItem->dataModes & kHIDDataRelative);
409
410 ptCapability->isRange = ptUsageItem->isRange;
411 if (ptUsageItem->isRange)
412 {
413 ptCapability->u.range.usageMin = ptUsageItem->usageMinimum;
414 ptCapability->u.range.usageMax = ptUsageItem->usageMaximum;
415 }
416 else
417 ptCapability->u.notRange.usage = ptUsageItem->usage;
418
419 // if there really are that many items
420 if (iU < ptReportItem->stringItemCount)
421 {
422 ptCapability->isStringRange = ptStringItem->isRange;
423
424 if (ptStringItem->isRange)
425 {
426 ptCapability->u.range.stringMin = ptStringItem->minimum;
427 ptCapability->u.range.stringMax = ptStringItem->maximum;
428 }
429 else
430 ptCapability->u.notRange.stringIndex = ptStringItem->index;
431 }
432 // default, clear it
433 else
434 {
435 ptCapability->isStringRange = false;
436 ptCapability->u.notRange.stringIndex = 0;
437 }
438
439 // if there really are that many items
440 if (iU < ptReportItem->desigItemCount)
441 {
442 ptCapability->isDesignatorRange = ptDesignatorItem->isRange;
443
444 if (ptDesignatorItem->isRange)
445 {
446 ptCapability->u.range.designatorMin = ptDesignatorItem->minimum;
447 ptCapability->u.range.designatorMax = ptDesignatorItem->maximum;
448 }
449 else
450 ptCapability->u.notRange.designatorIndex = ptDesignatorItem->index;
451 }
452 // default, clear it
453 else
454 {
455 ptCapability->isDesignatorRange = false;
456 ptCapability->u.notRange.designatorIndex = 0;
457 }
458 ptCapability->startBit = startBit;
459 }
460 startBit += (ptReportItem->globals.reportSize * ptReportItem->globals.reportCount);
461 }
462 }
463 }
464 return kHIDSuccess;
465 }
466
467 /*
468 *------------------------------------------------------------------------------
469 *
470 * HIDGetButtonCapabilities - Get the binary values for a report type
471 * This is the same as HIDGetButtonCaps,
472 * except that it takes a HIDButtonCapabilitiesPtr
473 * so it can return units and unitExponents.
474 *
475 * Input:
476 * reportType - HIDP_Input, HIDP_Output, HIDP_Feature
477 * buttonCaps - ButtonCaps Array
478 * piButtonCapsLength - Maximum Entries
479 * ptPreparsedData - Pre-Parsed Data
480 * Output:
481 * piButtonCapsLength - Entries Populated
482 * Returns:
483 *
484 *------------------------------------------------------------------------------
485 */
486 OSStatus HIDGetButtonCapabilities(HIDReportType reportType,
487 HIDButtonCapabilitiesPtr buttonCaps,
488 UInt32 *piButtonCapsLength,
489 HIDPreparsedDataRef preparsedDataRef)
490 {
491 return HIDGetSpecificButtonCapabilities(reportType,0,0,0,buttonCaps,
492 piButtonCapsLength,preparsedDataRef);
493 }