2 * Copyright (c) 1998-2000 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
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.
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
20 * @APPLE_LICENSE_HEADER_END@
23 File: HIDGetValueCaps.c
25 Contains: xxx put contents here xxx
27 Version: xxx put version here xxx
29 Copyright: © 1999-2000 by Apple Computer, Inc., all rights reserved.
33 DRI: xxx put dri here xxx
35 Other Contact: xxx put other contact here xxx
37 Technology: xxx put technology here xxx
44 Change History (most recent first):
46 <USB8> 12/12/00 KH range count off by 1.
47 <USB7> 4/21/00 KH Added HIDGetValueCapabilities and
48 HIDGetSpecificValueCapabilities that now allow users to find HID
49 report units and exponents.
50 <USB6> 11/1/99 BWS [2405720] We need a better check for 'bit padding' items,
51 rather than just is constant. We will check to make sure the
52 item is constant, and has no usage, or zero usage. This means we
53 need to pass an additional parameter to some internal functions
54 <USB5> 5/3/99 BWS Fix typo
55 <USB4> 5/3/99 BWS We were not setting isStringRange, isDesignatorRange, and
57 <USB3> 3/7/99 BWS When range/notRange were made a union, we missed this case where
58 they were both being set indescriminately
59 <USB2> 3/7/99 BWS [2311411] Had added missing fields to caps structure, but they
60 were not being filled in
61 <USB1> 3/5/99 BWS first checked in
67 *------------------------------------------------------------------------------
69 * HIDGetSpecificValueCaps - Get the binary values for a report type
72 * reportType - HIDP_Input, HIDP_Output, HIDP_Feature
73 * usagePage - Page Criteria or zero
74 * iCollection - Collection Criteria or zero
75 * usage - usage Criteria or zero
76 * valueCaps - ValueCaps Array
77 * piValueCapsLength - Maximum Entries
78 * ptPreparsedData - Pre-Parsed Data
80 * piValueCapsLength - Entries Populated
83 *------------------------------------------------------------------------------
85 OSStatus
HIDGetSpecificValueCaps(HIDReportType reportType
,
89 HIDValueCapsPtr valueCaps
,
90 UInt32
*piValueCapsLength
,
91 HIDPreparsedDataRef preparsedDataRef
)
93 HIDPreparsedDataPtr ptPreparsedData
= (HIDPreparsedDataPtr
) preparsedDataRef
;
94 HIDCollection
*ptCollection
;
95 HIDCollection
*ptParent
;
96 HIDReportItem
*ptReportItem
;
97 HIDP_UsageItem
*ptUsageItem
;
98 HIDStringItem
*ptStringItem
;
99 HIDDesignatorItem
*ptDesignatorItem
;
100 HIDP_UsageItem
*ptFirstCollectionUsageItem
;
101 HIDValueCaps
*ptCapability
;
104 int iReportItem
, iUsageItem
;
107 // There are 3 versions of HID Parser code all based on the same logic: OS 9 HID Library;
108 // OSX xnu; OSX IOKitUser. They should all be nearly the same logic. This version (xnu)
109 // is based on older OS 9 code. This version has added logic to maintain this startBit.
110 // I don't know why it is here, but believe if it is needed here, it would probably be
111 // needed in the other two implementations. Didn't have time to determine that at this
112 // time, so i'll leave this comment to remind me that we should reconcile the 3 versions.
113 UInt32 startBit
; // Added esb 9-29-99
114 /*If I remember correctly, it was an optimization. Each time you ask for
115 a specific value capability, it would search through the entire report
116 descriptor to find it (my recollection is kind of hazy on this part).
117 The start bit allowed somebody (client maybe) to cache the information
118 on where in the report a specific value resided and the use that later
119 when fetching that value. That way, you don't have to keep going
120 through the parse tree to find where a value exists. I don't remember
121 if the implementation was completed or if I even used it. -esb */
123 * Disallow Null Pointers
125 if ((valueCaps
== NULL
)
126 || (piValueCapsLength
== NULL
)
127 || (ptPreparsedData
== NULL
))
128 return kHIDNullPointerErr
;
129 if (ptPreparsedData
->hidTypeIfValid
!= kHIDOSType
)
130 return kHIDInvalidPreparsedDataErr
;
132 * Save the buffer size
134 iMaxCaps
= *piValueCapsLength
;
135 *piValueCapsLength
= 0;
137 * The Collection must be in range
139 if ((iCollection
< 0) || (iCollection
>= ptPreparsedData
->collectionCount
))
140 return kHIDBadParameterErr
;
142 * Search only the scope of the Collection specified
144 ptCollection
= &ptPreparsedData
->collections
[iCollection
];
145 for (iR
=0; iR
<ptCollection
->reportItemCount
; iR
++)
147 iReportItem
= ptCollection
->firstReportItem
+ iR
;
148 ptReportItem
= &ptPreparsedData
->reportItems
[iReportItem
];
150 * Search only reports of the proper type
152 if ((ptReportItem
->reportType
== reportType
)
153 && ((ptReportItem
->globals
.usagePage
== usagePage
)
155 && HIDIsVariable(ptReportItem
, preparsedDataRef
))
157 startBit
= ptReportItem
->startBit
; // Added esb 9-28-99
161 for (iU
=0; iU
<ptReportItem
->usageItemCount
; iU
++)
164 * Copy all usages if the usage above is zero
165 * or copy all that "match"
167 iUsageItem
= ptReportItem
->firstUsageItem
+ iU
;
168 ptUsageItem
= &ptPreparsedData
->usageItems
[iUsageItem
];
170 // ¥¥ we assume there is a 1-1 corresponence between usage items, string items, and designator items
171 // ¥¥Êthis is not necessarily the case, but its better than nothing
172 ptStringItem
= &ptPreparsedData
->stringItems
[ptReportItem
->firstStringItem
+ iU
];
173 ptDesignatorItem
= &ptPreparsedData
->desigItems
[ptReportItem
->firstDesigItem
+ iU
];
175 if (HIDUsageInRange(ptUsageItem
,usagePage
,usage
))
178 * Only copy if there's room
180 if (*piValueCapsLength
>= iMaxCaps
)
181 return kHIDBufferTooSmallErr
;
182 ptCapability
= &valueCaps
[(*piValueCapsLength
)++];
184 * Populate the Capability Structure
186 parent
= ptReportItem
->parent
;
187 ptParent
= &ptPreparsedData
->collections
[parent
];
188 ptFirstCollectionUsageItem
= &ptPreparsedData
->usageItems
[ptParent
->firstUsageItem
];
189 ptCapability
->collection
= parent
;
190 ptCapability
->collectionUsagePage
= ptParent
->usagePage
;
191 ptCapability
->collectionUsage
= ptFirstCollectionUsageItem
->usage
;
192 ptCapability
->bitField
= ptReportItem
->dataModes
;
193 ptCapability
->reportID
= ptReportItem
->globals
.reportID
;
194 ptCapability
->usagePage
= ptUsageItem
->usagePage
;
196 ptCapability
->isAbsolute
= !(ptReportItem
->dataModes
& kHIDDataRelative
);
198 ptCapability
->isRange
= ptUsageItem
->isRange
;
199 if (ptUsageItem
->isRange
)
201 ptCapability
->u
.range
.usageMin
= ptUsageItem
->usageMinimum
;
202 ptCapability
->u
.range
.usageMax
= ptUsageItem
->usageMaximum
;
205 ptCapability
->u
.notRange
.usage
= ptUsageItem
->usage
;
207 // if there really are that many items
208 if (iU
< ptReportItem
->stringItemCount
)
210 ptCapability
->isStringRange
= ptStringItem
->isRange
;
212 if (ptStringItem
->isRange
)
214 ptCapability
->u
.range
.stringMin
= ptStringItem
->minimum
;
215 ptCapability
->u
.range
.stringMax
= ptStringItem
->maximum
;
218 ptCapability
->u
.notRange
.stringIndex
= ptStringItem
->index
;
223 ptCapability
->isStringRange
= false;
224 ptCapability
->u
.notRange
.stringIndex
= 0;
227 // if there really are that many items
228 if (iU
< ptReportItem
->desigItemCount
)
230 ptCapability
->isDesignatorRange
= ptDesignatorItem
->isRange
;
232 if (ptDesignatorItem
->isRange
)
234 ptCapability
->u
.range
.designatorMin
= ptDesignatorItem
->minimum
;
235 ptCapability
->u
.range
.designatorMax
= ptDesignatorItem
->maximum
;
238 ptCapability
->u
.notRange
.designatorIndex
= ptDesignatorItem
->index
;
243 ptCapability
->isDesignatorRange
= false;
244 ptCapability
->u
.notRange
.designatorIndex
= 0;
247 ptCapability
->bitSize
= ptReportItem
->globals
.reportSize
;
249 ptCapability
->logicalMin
= ptReportItem
->globals
.logicalMinimum
;
250 ptCapability
->logicalMax
= ptReportItem
->globals
.logicalMaximum
;
251 ptCapability
->physicalMin
= ptReportItem
->globals
.physicalMinimum
;
252 ptCapability
->physicalMax
= ptReportItem
->globals
.physicalMaximum
;
254 if (ptUsageItem
->isRange
)
256 iCount
= ptUsageItem
->usageMaximum
- ptUsageItem
->usageMinimum
;
259 iCount
++; // Range count was off by one.
262 // If we're not in a range, then there should be just one usage.
263 // Why do we have to call this function to determine that? Are we checking
264 // that there is that usage before we decide if usage count is 0 or 1?
265 // But haven't we already verified that we have this usage by the time we
267 HIDHasUsage(preparsedDataRef
,ptReportItem
,
268 ptUsageItem
->usagePage
,ptUsageItem
->usage
,
270 ptCapability
->reportCount
= iCount
;
271 ptCapability
->startBit
= startBit
;
272 startBit
+= (ptCapability
->bitSize
* ptCapability
->reportCount
);
281 *------------------------------------------------------------------------------
283 * HIDGetValueCaps - Get the binary values for a report type
286 * reportType - HIDP_Input, HIDP_Output, HIDP_Feature
287 * valueCaps - ValueCaps Array
288 * piValueCapsLength - Maximum Entries
289 * ptPreparsedData - Pre-Parsed Data
291 * piValueCapsLength - Entries Populated
294 *------------------------------------------------------------------------------
296 OSStatus
HIDGetValueCaps(HIDReportType reportType
,
297 HIDValueCapsPtr valueCaps
,
298 UInt32
*piValueCapsLength
,
299 HIDPreparsedDataRef preparsedDataRef
)
301 return HIDGetSpecificValueCaps(reportType
,0,0,0,valueCaps
,
302 piValueCapsLength
,preparsedDataRef
);
307 *------------------------------------------------------------------------------
309 * HIDGetSpecificValueCapabilities - Get the binary values for a report type
310 * This is the same as HIDGetSpecificValueCaps,
311 * except that it takes a HIDValueCapabilitiesPtr
312 * so it can return units and unitExponents.
315 * reportType - HIDP_Input, HIDP_Output, HIDP_Feature
316 * usagePage - Page Criteria or zero
317 * iCollection - Collection Criteria or zero
318 * usage - usage Criteria or zero
319 * valueCaps - ValueCaps Array
320 * piValueCapsLength - Maximum Entries
321 * ptPreparsedData - Pre-Parsed Data
323 * piValueCapsLength - Entries Populated
326 *------------------------------------------------------------------------------
328 OSStatus
HIDGetSpecificValueCapabilities(HIDReportType reportType
,
332 HIDValueCapabilitiesPtr valueCaps
,
333 UInt32
*piValueCapsLength
,
334 HIDPreparsedDataRef preparsedDataRef
)
336 HIDPreparsedDataPtr ptPreparsedData
= (HIDPreparsedDataPtr
) preparsedDataRef
;
337 HIDCollection
*ptCollection
;
338 HIDCollection
*ptParent
;
339 HIDReportItem
*ptReportItem
;
340 HIDP_UsageItem
*ptUsageItem
;
341 HIDStringItem
*ptStringItem
;
342 HIDDesignatorItem
*ptDesignatorItem
;
343 HIDP_UsageItem
*ptFirstCollectionUsageItem
;
344 HIDValueCapabilities
*ptCapability
;
347 int iReportItem
, iUsageItem
;
350 // There are 3 versions of HID Parser code all based on the same logic: OS 9 HID Library;
351 // OSX xnu; OSX IOKitUser. They should all be nearly the same logic. This version (xnu)
352 // is based on older OS 9 code. This version has added logic to maintain this startBit.
353 // I don't know why it is here, but believe if it is needed here, it would probably be
354 // needed in the other two implementations. Didn't have time to determine that at this
355 // time, so i'll leave this comment to remind me that we should reconcile the 3 versions.
356 UInt32 startBit
; // Carried esb's logic down here when we added HIDGetSpecificValueCapabilities().
358 * Disallow Null Pointers
360 if ((valueCaps
== NULL
)
361 || (piValueCapsLength
== NULL
)
362 || (ptPreparsedData
== NULL
))
363 return kHIDNullPointerErr
;
364 if (ptPreparsedData
->hidTypeIfValid
!= kHIDOSType
)
365 return kHIDInvalidPreparsedDataErr
;
367 * Save the buffer size
369 iMaxCaps
= *piValueCapsLength
;
370 *piValueCapsLength
= 0;
372 * The Collection must be in range
374 if ((iCollection
< 0) || (iCollection
>= ptPreparsedData
->collectionCount
))
375 return kHIDBadParameterErr
;
377 * Search only the scope of the Collection specified
379 ptCollection
= &ptPreparsedData
->collections
[iCollection
];
380 for (iR
=0; iR
<ptCollection
->reportItemCount
; iR
++)
382 iReportItem
= ptCollection
->firstReportItem
+ iR
;
383 ptReportItem
= &ptPreparsedData
->reportItems
[iReportItem
];
385 * Search only reports of the proper type
387 if ((ptReportItem
->reportType
== reportType
)
388 && ((ptReportItem
->globals
.usagePage
== usagePage
)
390 && HIDIsVariable(ptReportItem
, preparsedDataRef
))
392 startBit
= ptReportItem
->startBit
; // Same logic as Added esb 9-28-99
396 for (iU
=0; iU
<ptReportItem
->usageItemCount
; iU
++)
399 * Copy all usages if the usage above is zero
400 * or copy all that "match"
402 iUsageItem
= ptReportItem
->firstUsageItem
+ iU
;
403 ptUsageItem
= &ptPreparsedData
->usageItems
[iUsageItem
];
405 // ¥¥ we assume there is a 1-1 corresponence between usage items, string items, and designator items
406 // ¥¥Êthis is not necessarily the case, but its better than nothing
407 ptStringItem
= &ptPreparsedData
->stringItems
[ptReportItem
->firstStringItem
+ iU
];
408 ptDesignatorItem
= &ptPreparsedData
->desigItems
[ptReportItem
->firstDesigItem
+ iU
];
410 if (HIDUsageInRange(ptUsageItem
,usagePage
,usage
))
413 * Only copy if there's room
415 if (*piValueCapsLength
>= iMaxCaps
)
416 return kHIDBufferTooSmallErr
;
417 ptCapability
= &valueCaps
[(*piValueCapsLength
)++];
420 * Populate the Capability Structure
422 parent
= ptReportItem
->parent
;
423 ptParent
= &ptPreparsedData
->collections
[parent
];
424 ptFirstCollectionUsageItem
= &ptPreparsedData
->usageItems
[ptParent
->firstUsageItem
];
425 ptCapability
->collection
= parent
;
426 ptCapability
->collectionUsagePage
= ptParent
->usagePage
;
427 ptCapability
->collectionUsage
= ptFirstCollectionUsageItem
->usage
;
428 ptCapability
->bitField
= ptReportItem
->dataModes
;
429 ptCapability
->reportID
= ptReportItem
->globals
.reportID
;
430 ptCapability
->usagePage
= ptUsageItem
->usagePage
;
431 ptCapability
->unitExponent
= ptReportItem
->globals
.unitExponent
;
432 ptCapability
->units
= ptReportItem
->globals
.units
;
433 // ptCapability->reserved = 0; // for future OS 9 expansion
434 ptCapability
->startBit
= 0; // init esb added field.
435 // ptCapability->pbVersion = kHIDCurrentCapabilitiesPBVersion;
436 ptCapability
->pbVersion
= 2;
438 ptCapability
->isAbsolute
= !(ptReportItem
->dataModes
& kHIDDataRelative
);
440 ptCapability
->isRange
= ptUsageItem
->isRange
;
441 if (ptUsageItem
->isRange
)
443 ptCapability
->u
.range
.usageMin
= ptUsageItem
->usageMinimum
;
444 ptCapability
->u
.range
.usageMax
= ptUsageItem
->usageMaximum
;
447 ptCapability
->u
.notRange
.usage
= ptUsageItem
->usage
;
449 // if there really are that many items
450 if (iU
< ptReportItem
->stringItemCount
)
452 ptCapability
->isStringRange
= ptStringItem
->isRange
;
454 if (ptStringItem
->isRange
)
456 ptCapability
->u
.range
.stringMin
= ptStringItem
->minimum
;
457 ptCapability
->u
.range
.stringMax
= ptStringItem
->maximum
;
460 ptCapability
->u
.notRange
.stringIndex
= ptStringItem
->index
;
465 ptCapability
->isStringRange
= false;
466 ptCapability
->u
.notRange
.stringIndex
= 0;
469 // if there really are that many items
470 if (iU
< ptReportItem
->desigItemCount
)
472 ptCapability
->isDesignatorRange
= ptDesignatorItem
->isRange
;
474 if (ptDesignatorItem
->isRange
)
476 ptCapability
->u
.range
.designatorMin
= ptDesignatorItem
->minimum
;
477 ptCapability
->u
.range
.designatorMax
= ptDesignatorItem
->maximum
;
480 ptCapability
->u
.notRange
.designatorIndex
= ptDesignatorItem
->index
;
485 ptCapability
->isDesignatorRange
= false;
486 ptCapability
->u
.notRange
.designatorIndex
= 0;
489 ptCapability
->bitSize
= ptReportItem
->globals
.reportSize
;
491 ptCapability
->logicalMin
= ptReportItem
->globals
.logicalMinimum
;
492 ptCapability
->logicalMax
= ptReportItem
->globals
.logicalMaximum
;
493 ptCapability
->physicalMin
= ptReportItem
->globals
.physicalMinimum
;
494 ptCapability
->physicalMax
= ptReportItem
->globals
.physicalMaximum
;
496 if (ptUsageItem
->isRange
)
498 iCount
= ptUsageItem
->usageMaximum
- ptUsageItem
->usageMinimum
;
501 iCount
++; // Range count was off by one.
504 HIDHasUsage(preparsedDataRef
,ptReportItem
,
505 ptUsageItem
->usagePage
,ptUsageItem
->usage
,
507 ptCapability
->reportCount
= iCount
;
508 ptCapability
->startBit
= startBit
; // more of same logic.
509 startBit
+= (ptCapability
->bitSize
* ptCapability
->reportCount
);
518 *------------------------------------------------------------------------------
520 * HIDGetValueCapabilities - Get the binary values for a report type
521 * This is the same as HIDGetValueCaps,
522 * except that it takes a HIDValueCapabilitiesPtr
523 * so it can return units and unitExponents.
526 * reportType - HIDP_Input, HIDP_Output, HIDP_Feature
527 * valueCaps - ValueCaps Array
528 * piValueCapsLength - Maximum Entries
529 * ptPreparsedData - Pre-Parsed Data
531 * piValueCapsLength - Entries Populated
534 *------------------------------------------------------------------------------
536 OSStatus
HIDGetValueCapabilities(HIDReportType reportType
,
537 HIDValueCapabilitiesPtr valueCaps
,
538 UInt32
*piValueCapsLength
,
539 HIDPreparsedDataRef preparsedDataRef
)
541 return HIDGetSpecificValueCapabilities(reportType
,0,0,0,valueCaps
,
542 piValueCapsLength
,preparsedDataRef
);