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@
25 Contains: HIDInitReport call for HID Library
29 Copyright: © 2000 by Apple Computer, Inc., all rights reserved.
35 Other Contact: Keithen Hayenga
37 Technology: technologies, usb
42 Change History (most recent first):
49 *------------------------------------------------------------------------------
51 * HIDInitReport - Initialize report to have report ID and, if possible, null values
52 * so that setting any one value will not inadvertantly change
53 * other items in the same report to 0.
56 * reportType - HIDP_Input, HIDP_Output, HIDP_Feature
57 * reportID - Report ID
58 * preparsedDataRef - Pre-Parsed Data
59 * report - An HID Report
60 * reportLength - The length of the Report
62 * report - Initialized HID Report
65 *------------------------------------------------------------------------------
67 OSStatus HIDInitReport
68 (HIDReportType reportType
,
70 HIDPreparsedDataRef preparsedDataRef
,
72 ByteCount reportLength
)
74 HIDPreparsedDataPtr ptPreparsedData
= (HIDPreparsedDataPtr
) preparsedDataRef
;
75 HIDReportItem
* ptReportItem
;
79 OSStatus iStatus
= kHIDSuccess
;
81 //Disallow Null Pointers
83 if ((ptPreparsedData
== NULL
) || (report
== NULL
))
84 return kHIDNullPointerErr
;
85 if (ptPreparsedData
->hidTypeIfValid
!= kHIDOSType
)
86 return kHIDInvalidPreparsedDataErr
;
87 if (reportLength
== 0)
88 return kHIDReportSizeZeroErr
;
90 // Report length must also be great enough to hold report.
91 HIDGetReportLength(reportType
, reportID
, &minLength
, preparsedDataRef
);
92 // I know that HIDGetReportLength repeats the first tests above, but it
93 // was easier to duplicate that logic than build test cases for the other
94 // errors that could be returned by HIDGetReportLength that i don't care
97 if (reportLength
< minLength
)
98 return kHIDInvalidReportLengthErr
;
100 // First byte of report must be reportID. Unless it is report ID 0;
101 // in which case 0 is just the first byte of the following initialization.
103 iPtr
= (UInt8
*)report
;
106 // Default initialization is to zero out all values.
108 for (iR
= 1; iR
< reportLength
; iR
++)
113 // Search through all report items to see if they belong in this report.
115 for (iR
= 0; iR
< ptPreparsedData
->reportItemCount
; iR
++)
117 ptReportItem
= &ptPreparsedData
->reportItems
[iR
];
119 if (ptReportItem
->reportType
== reportType
&&
120 ptReportItem
->globals
.reportID
== reportID
)
122 // Is there a null value for this item?
129 // The HID spec "highly encourages" 0 to be a null value, so test
132 if ( 0 < ptReportItem
->globals
.logicalMinimum
||
133 0 > ptReportItem
->globals
.logicalMaximum
)
134 continue; // Default initialization was good enough.
136 nullValue
= 0; // We can test if this changes below.
138 // Determine the maximum and minimum signed numbers that will fit into this
139 // item and then see if they are outside the bounds of what the descriptor
140 // says are the allowed min and max.
141 // What the possible ranges are depends upon if the device is accepting
142 // signed or unsigned numbers. I haven't noticed that information in the
143 // preparsed data, so i'll take an educated guess. If logicalMinimum is
144 // less than 0 it must be using signed numbers. Conversly, logicalMaximum
145 // using the high order bit of it's bitfield would indicate unsigned. In
146 // case of a tie, we'll say signed since that agrees with the SInt32 that
147 // logicalMinimum and logicalMaximum are stored in.
149 // The mininimum 8 bit value would be 0x80 (-128). To be -128 in UInt32 = 0xFFFFFF80.
150 // This just happens to also set the high order bit that we need to test in the
151 // maximum value using the high order bit, such as 64, 0x80.
152 bitSize
= ptReportItem
->globals
.reportSize
;
153 bitwiseMin
= -1 << (bitSize
- 1);
155 // Logical max should not have any bit set higher than the high order bit of our
156 // size, so anding with 0xFFFFFF80 should only test field's high order bit.
157 isSigned
= (ptReportItem
->globals
.logicalMinimum
< 0) ||
158 !(ptReportItem
->globals
.logicalMaximum
& bitwiseMin
);
160 // If signed, we test from 0x80 to 0x7F. If not, 0x00 to 0xFF.
163 --bitSize
; // Don't let max value flow into sign bit.
170 // Our compare uses SInt32, so even for unsigned values, we can't let them
171 // overflow into real sign bit. (So 0x80000000 is not a legal HID positive number.)
172 if (bitSize
>= 32) bitSize
= 31;
174 // The theory behind this greatly simplified set of compares. 1. I was worried about
175 // the case of a 4 bit field with a max = 4 and a min = -2. Then if i chose a value
176 // of 7 for my bitwise max, it could also be -1 for min, which would make it a null
177 // positive value, but a legal negative one. But while HID specs say a field can be
178 // either a signed or unsigned value, i don't see how it can be both, so i haven't
179 // allowed for such a situation. 2. I originally built logic that tested for signed
180 // or unsigned fields as above, but had seperate logic based on what would happen
181 // after that. I have resolved that logic down to the main part below and the only
182 // exceptions i had are now filtered out into the 2 lines of "if (signed)" etc. above.
184 bitwiseMax
= (1<<bitSize
) - 1;
186 if (bitwiseMax
> ptReportItem
->globals
.logicalMaximum
)
188 nullValue
= bitwiseMax
;
192 if (bitwiseMin
< ptReportItem
->globals
.logicalMinimum
)
194 nullValue
= bitwiseMin
;
198 // If we found a null value, store it into the proper place in the report.
202 // Write out the data.
207 HIDPreProcessRIValue(ptReportItem
, &nullValue
);
209 // For a reportItem, there can be multiple identical usages.
210 for (lR
= 0; lR
< ptReportItem
->usageItemCount
; lR
++)
212 iStart
= ptReportItem
->startBit
213 + (ptReportItem
->globals
.reportSize
* lR
);
214 tempStatus
= HIDPutData(report
, reportLength
, iStart
,
215 ptReportItem
->globals
.reportSize
, nullValue
);
217 iStatus
= tempStatus
; // Pass on any bad news.