1/*
2 * @APPLE_LICENSE_HEADER_START@
3 *
4 * Copyright (c) 1999-2012 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:		HIDProcessReportItem.c
25
26	Contains:	xxx put contents here xxx
27
28	Version:	xxx put version here xxx
29
30	Copyright:	� 1999-2000 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		(KH)	Keithen Hayenga
43		(DF)	David Ferguson
44		(BWS)	Brent Schorsch
45
46	Change History (most recent first):
47
48	 <USB10>	 1/11/00	KH		Tweaking last fix. For logical maximum, limit shifting into the
49									sign bit only for report sizes of 32 bits or greater.
50	  <USB9>	 1/10/00	DF		re-do last change (better fix).
51	  <USB8>	 1/10/00	DF		do proper logical range test for 32-bit report items.
52	  <USB7>	  4/7/99	BWS		Add support for reversed report items
53	  <USB6>	 3/20/99	BWS		Oops, strict error checking does not work if there is no error.
54									We should only return error if it is not 0
55	  <USB5>	 3/17/99	BWS		[2314839]  Added flags field to HIDPreparsedData which is set in
56									new parameter to HIDOpenReportDescriptor. We check the
57									StrictErrorCheck bit to determine whether we return errors or
58									just try to work around problems we find
59	  <USB4>	  3/7/99	BWS		[2311413]  Do not error check min/max ranges for constants
60	  <USB3>	  3/7/99	BWS		[2311412]  We need to handle the cases where physical min/max is
61									either (0/0) which is valid according to the spec, and means to
62									use the logical min/max, and the invalid case, that some devices
63									exibit, which has (0/-1) which we will treat the same,
64	  <USB2>	  3/5/99	BWS		[2311359]  HIDProcessReportItem does not initialize startBit
65									field of HIDReportItem!
66	  <USB1>	  3/5/99	BWS		first checked in
67*/
68
69#include "HIDLib.h"
70
71/*
72 *------------------------------------------------------------------------------
73 *
74 * HIDProcessReportItem - Process a Report Item MainItem
75 *
76 *	 Input:
77 *			  ptDescriptor			- The Descriptor Structure
78 *			  ptPreparsedData		- The PreParsedData Structure
79 *	 Output:
80 *			  ptDescriptor			- The Descriptor Structure
81 *			  ptPreparsedData		- The PreParsedData Structure
82 *	 Returns:
83 *			  kHIDSuccess		   - Success
84 *			  kHIDNullPointerErr	  - Argument, Pointer was Null
85 *
86 *------------------------------------------------------------------------------
87*/
88OSStatus HIDProcessReportItem(HIDReportDescriptor *ptDescriptor, HIDPreparsedDataPtr ptPreparsedData)
89{
90	OSStatus error = 0;
91	HIDReportItem *ptReportItem;
92	HIDReportSizes *ptReport;
93	int iBits;
94/*
95 *	Disallow NULL Pointers
96*/
97
98	if ((ptDescriptor == NULL) || (ptPreparsedData == NULL))
99		return kHIDNullPointerErr;
100/*
101 *	Begin to initialize the new Report Item structure
102*/
103
104	ptReportItem = &ptPreparsedData->reportItems[ptPreparsedData->reportItemCount++];
105	ptReportItem->dataModes = ptDescriptor->item.unsignedValue;
106	ptReportItem->globals = ptDescriptor->globals;
107	ptReportItem->flags = 0;
108
109/*
110 *	Reality Check on the Report Main Item
111*/
112	// Don't check ranges for constants (MS Sidewinder, for one, does not reset)
113	//if (!(ptReportItem->dataModes & kHIDDataConstantBit)) // don't think we need this anymore
114	{
115		// Determine the maximum signed value for a given report size.
116		// (Don't allow shifting into sign bit.)
117		SInt32 posSize = (ptReportItem->globals.reportSize >= 32) ?
118						31 : ptReportItem->globals.reportSize;
119		SInt32 realMax = (1<<posSize) - 1;
120
121		if (ptReportItem->globals.logicalMinimum > realMax)
122		{
123			error = kHIDBadLogicalMinimumErr;
124			ptReportItem->globals.logicalMinimum = 0;
125		}
126		if (ptReportItem->globals.logicalMaximum > realMax)
127		{
128			if (!error)
129				error = kHIDBadLogicalMaximumErr;
130			ptReportItem->globals.logicalMaximum = realMax;
131		}
132		if (ptReportItem->globals.logicalMinimum > ptReportItem->globals.logicalMaximum)
133		{
134			SInt32	temp;
135			if (!error)
136				error = kHIDInvertedLogicalRangeErr;
137
138			// mark as a 'reversed' item
139			ptReportItem->flags |= kHIDReportItemFlag_Reversed;
140
141			temp = ptReportItem->globals.logicalMaximum;
142			ptReportItem->globals.logicalMaximum = ptReportItem->globals.logicalMinimum;
143			ptReportItem->globals.logicalMinimum = temp;
144		}
145	}
146
147	// check to see if we got half a range (we don't need to fix this, since 'isRange' will be false
148	if ((!error) && (ptDescriptor->haveUsageMin || ptDescriptor->haveUsageMax))
149		error = kHIDUnmatchedUsageRangeErr;
150	if ((!error) && (ptDescriptor->haveStringMin || ptDescriptor->haveStringMax))
151		error = kHIDUnmatchedStringRangeErr;
152	if ((!error) && (ptDescriptor->haveDesigMin || ptDescriptor->haveDesigMax))
153		error = kHIDUnmatchedDesignatorRangeErr;
154
155	// if the physical min/max are out of wack, use the logical values
156	if (ptReportItem->globals.physicalMinimum >= ptReportItem->globals.physicalMaximum)
157	{
158		// equal to each other is not an error, just means to use the logical values
159		if ((!error) &&
160			(ptReportItem->globals.physicalMinimum > ptReportItem->globals.physicalMaximum))
161			error = kHIDInvertedPhysicalRangeErr;
162
163		ptReportItem->globals.physicalMinimum = ptReportItem->globals.logicalMinimum;
164		ptReportItem->globals.physicalMaximum = ptReportItem->globals.logicalMaximum;
165	}
166
167	// if strict error checking is true, return any errors
168	if (error && ptPreparsedData->flags & kHIDFlag_StrictErrorChecking)
169		return error;
170
171/*
172 *	Continue to initialize the new Report Item structure
173*/
174
175	ptReportItem->parent = ptDescriptor->parent;
176	ptReportItem->firstUsageItem = ptDescriptor->firstUsageItem;
177	ptDescriptor->firstUsageItem = ptPreparsedData->usageItemCount;
178	ptReportItem->usageItemCount = ptPreparsedData->usageItemCount - ptReportItem->firstUsageItem;
179	ptReportItem->firstStringItem = ptDescriptor->firstStringItem;
180	ptDescriptor->firstStringItem = ptPreparsedData->stringItemCount;
181	ptReportItem->stringItemCount = ptPreparsedData->stringItemCount - ptReportItem->firstStringItem;
182	ptReportItem->firstDesigItem = ptDescriptor->firstDesigItem;
183	ptDescriptor->firstDesigItem = ptPreparsedData->desigItemCount;
184	ptReportItem->desigItemCount = ptPreparsedData->desigItemCount - ptReportItem->firstDesigItem;
185/*
186 *	Update the Report by the size of this item
187*/
188
189	ptReport = &ptPreparsedData->reports[ptReportItem->globals.reportIndex];
190	iBits = ptReportItem->globals.reportSize * ptReportItem->globals.reportCount;
191	switch (ptDescriptor->item.tag)
192	{
193		case kHIDTagFeature:
194			ptReportItem->reportType = kHIDFeatureReport;
195            ptReportItem->startBit = ptReport->featureBitCount;
196			ptReport->featureBitCount += iBits;
197			break;
198		case kHIDTagOutput:
199			ptReportItem->reportType = kHIDOutputReport;
200            ptReportItem->startBit = ptReport->outputBitCount;
201			ptReport->outputBitCount += iBits;
202			break;
203		case kHIDTagInput:
204			ptReportItem->reportType = kHIDInputReport;
205            ptReportItem->startBit = ptReport->inputBitCount;
206			ptReport->inputBitCount += iBits;
207			break;
208		default:
209			ptReportItem->reportType = kHIDUnknownReport;
210            ptReportItem->startBit = 0;
211			break;
212	}
213	return kHIDSuccess;
214}
215