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:		HIDGetUsageValue.c
25
26	Contains:	xxx put contents here xxx
27
28	Version:	xxx put version here xxx
29
30	Copyright:	� 1999-2001 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		(BWS)	Brent Schorsch
44
45	Change History (most recent first):
46
47	  <USB5>	 1/18/01	KH		Fix for complex descriptors only needed for buttons.
48	  <USB4>	 3/24/00	KH		Complex report descriptors could lead to reporting
49									kHIDUsageNotFoundErr's as kHIDIncompatibleReportErr's instead.
50	  <USB3>	 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	  <USB2>	  4/7/99	BWS		Add support for reversed report items
55	  <USB1>	  3/5/99	BWS		first checked in
56*/
57
58#include "HIDLib.h"
59
60/*
61 *------------------------------------------------------------------------------
62 *
63 * HIDGetUsageValue - Get the value for a usage
64 *
65 *	 Input:
66 *			  reportType		   - HIDP_Input, HIDP_Output, HIDP_Feature
67 *			  usagePage			   - Page Criteria or zero
68 *			  iCollection			- Collection Criteria or zero
69 *			  usage				   - The usage to get the value for
70 *			  piUsageValue			- User-supplied place to put value
71 *			  ptPreparsedData		- Pre-Parsed Data
72 *			  psReport				- An HID Report
73 *			  iReportLength			- The length of the Report
74 *	 Output:
75 *			  piValue				- Pointer to usage Value
76 *	 Returns:
77 *
78 *------------------------------------------------------------------------------
79*/
80OSStatus HIDGetUsageValue
81		  (HIDReportType			reportType,
82		   HIDUsage					usagePage,
83		   UInt32					iCollection,
84		   HIDUsage					usage,
85		   SInt32 *					piUsageValue,
86		   HIDPreparsedDataRef		preparsedDataRef,
87		   void *					psReport,
88		   IOByteCount              iReportLength)
89{
90	HIDPreparsedDataPtr ptPreparsedData = (HIDPreparsedDataPtr) preparsedDataRef;
91	HIDCollection *ptCollection;
92	HIDReportItem *ptReportItem;
93	OSStatus iStatus;
94	int iR;
95	SInt32 iValue;
96	int iStart;
97	int iReportItem;
98	UInt32 iUsageIndex;
99	Boolean bIncompatibleReport = false;
100/*
101 *	Disallow Null Pointers
102*/
103	if ((ptPreparsedData == NULL)
104	 || (piUsageValue == NULL)
105	 || (psReport == NULL))
106		return kHIDNullPointerErr;
107	if (ptPreparsedData->hidTypeIfValid != kHIDOSType)
108		return kHIDInvalidPreparsedDataErr;
109/*
110 *	The Collection must be in range
111*/
112	if (iCollection >= ptPreparsedData->collectionCount)
113		return kHIDBadParameterErr;
114/*
115 *	Search only the scope of the Collection specified
116 *	Go through the ReportItems
117 *	Filter on ReportType and usagePage
118*/
119	ptCollection = &ptPreparsedData->collections[iCollection];
120	for (iR=0; iR<ptCollection->reportItemCount; iR++)
121	{
122		iReportItem = ptCollection->firstReportItem + iR;
123		ptReportItem = &ptPreparsedData->reportItems[iReportItem];
124		if (HIDIsVariable(ptReportItem, preparsedDataRef)
125		 && HIDHasUsage(preparsedDataRef,ptReportItem,usagePage,usage,&iUsageIndex,NULL))
126		{
127/*
128 *			This may be the proper data to get
129 *			Let's check for the proper Report ID, Type, and Length
130*/
131			iStatus = HIDCheckReport(reportType,preparsedDataRef,ptReportItem,
132									   psReport,iReportLength);
133/*
134 *			The Report ID or Type may not match.
135 *			This may not be an error (yet)
136*/
137			if (iStatus == kHIDIncompatibleReportErr)
138				bIncompatibleReport = true;
139			else if (iStatus != kHIDSuccess)
140				return iStatus;
141			else
142			{
143/*
144 *				Pick up the data
145*/
146				iStart = ptReportItem->startBit
147					   + (ptReportItem->globals.reportSize * iUsageIndex);
148				iStatus = HIDGetData(psReport, iReportLength, iStart,
149									   ptReportItem->globals.reportSize, &iValue,
150									   ((ptReportItem->globals.logicalMinimum < 0)
151									  ||(ptReportItem->globals.logicalMaximum < 0)));
152				if (!iStatus)
153					iStatus = HIDPostProcessRIValue (ptReportItem, &iValue);
154				*piUsageValue = iValue;
155				return iStatus;
156			}
157		}
158	}
159	if (bIncompatibleReport)
160		return kHIDIncompatibleReportErr;
161	return kHIDUsageNotFoundErr;
162}
163
164/*
165 *------------------------------------------------------------------------------
166 *
167 * HIDGetScaledUsageValue - Get the value for a usage
168 *
169 *	 Input:
170 *			  reportType		   - HIDP_Input, HIDP_Output, HIDP_Feature
171 *			  usagePage			   - Page Criteria or zero
172 *			  iCollection			- Collection Criteria or zero
173 *			  usage				   - usage Criteria or zero
174 *			  piValue				- Pointer to usage Value
175 *			  ptPreparsedData		- Pre-Parsed Data
176 *			  psReport				- An HID Report
177 *			  iReportLength			- The length of the Report
178 *	 Output:
179 *			  piValue				- Pointer to usage Value
180 *	 Returns:
181 *
182 *------------------------------------------------------------------------------
183*/
184OSStatus HIDGetScaledUsageValue(HIDReportType reportType,
185									 HIDUsage usagePage,
186									 UInt32 iCollection,
187									 HIDUsage usage,
188									 SInt32 *piUsageValue,
189									 HIDPreparsedDataRef preparsedDataRef,
190									 void *psReport,
191									 IOByteCount iReportLength)
192{
193	HIDPreparsedDataPtr ptPreparsedData = (HIDPreparsedDataPtr) preparsedDataRef;
194	HIDCollection *ptCollection;
195	HIDReportItem *ptReportItem;
196	OSStatus iStatus;
197	int iR;
198	SInt32 iValue;
199	int iStart;
200	int iReportItem;
201	UInt32 iUsageIndex;
202	Boolean bIncompatibleReport = false;
203/*
204 *	Disallow Null Pointers
205*/
206	if ((ptPreparsedData == NULL)
207	 || (piUsageValue == NULL)
208	 || (psReport == NULL))
209		return kHIDNullPointerErr;
210	if (ptPreparsedData->hidTypeIfValid != kHIDOSType)
211		return kHIDInvalidPreparsedDataErr;
212/*
213 *	The Collection must be in range
214*/
215	if (iCollection >= ptPreparsedData->collectionCount)
216		return kHIDBadParameterErr;
217/*
218 *	Search only the scope of the Collection specified
219 *	Go through the ReportItems
220 *	Filter on ReportType and usagePage
221*/
222	ptCollection = &ptPreparsedData->collections[iCollection];
223	for (iR=0; iR<ptCollection->reportItemCount; iR++)
224	{
225		iReportItem = ptCollection->firstReportItem + iR;
226		ptReportItem = &ptPreparsedData->reportItems[iReportItem];
227		if (HIDIsVariable(ptReportItem, preparsedDataRef)
228		 && HIDHasUsage(preparsedDataRef,ptReportItem,usagePage,usage,&iUsageIndex,NULL))
229		{
230/*
231 *			This may be the proper data to get
232 *			Let's check for the proper Report ID, Type, and Length
233*/
234			iStatus = HIDCheckReport(reportType,preparsedDataRef,ptReportItem,
235									   psReport,iReportLength);
236/*
237 *			The Report ID or Type may not match.
238 *			This may not be an error (yet)
239*/
240			if (iStatus == kHIDIncompatibleReportErr)
241				bIncompatibleReport = true;
242			else if (iStatus != kHIDSuccess)
243				return iStatus;
244			else
245			{
246/*
247 *				Pick up the data
248*/
249				iStart = ptReportItem->startBit
250					   + (ptReportItem->globals.reportSize * iUsageIndex);
251				iStatus = HIDGetData(psReport, iReportLength, iStart,
252									   ptReportItem->globals.reportSize, &iValue,
253									   ((ptReportItem->globals.logicalMinimum < 0)
254									  ||(ptReportItem->globals.logicalMaximum < 0)));
255				if (!iStatus)
256					iStatus = HIDPostProcessRIValue (ptReportItem, &iValue);
257				if (iStatus != kHIDSuccess)
258					return iStatus;
259/*
260 *				Try to scale the data
261*/
262				 iStatus = HIDScaleUsageValueIn(ptReportItem,iValue,&iValue);
263				*piUsageValue = iValue;
264				return iStatus;
265			}
266		}
267	}
268	if (bIncompatibleReport)
269		return kHIDIncompatibleReportErr;
270	return kHIDUsageNotFoundErr;
271}
272