1/* 2 * Copyright (c) 1999-2008 Apple Computer, Inc. All Rights Reserved. 3 * 4 * @APPLE_LICENSE_HEADER_START@ 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#include <pthread.h> 25#include <System/libkern/OSCrossEndian.h> 26#include <CoreFoundation/CFRuntime.h> 27#include <CoreFoundation/CFData.h> 28#include <IOKit/hid/IOHIDValue.h> 29#include <IOKit/hid/IOHIDElement.h> 30#include <IOKit/hid/IOHIDLibUserClient.h> 31#include <IOKit/hid/IOHIDLibPrivate.h> 32 33#ifndef min 34 #define min(a,b) (a<b?a:b) 35#endif 36 37static IOHIDValueRef __IOHIDValueCreatePrivate(CFAllocatorRef allocator, CFAllocatorContext * context __unused, size_t extraBytes); 38static void __IOHIDValueRelease( CFTypeRef object ); 39static void __IOHIDValueConvertByteToWord(const UInt8 * src, uint32_t * dst, uint32_t bytesToCopy, Boolean signExtend); 40static void __IOHIDValueConvertWordToByte(const uint32_t * src, UInt8 * dst, uint32_t bytesToCopy); 41static void __IOHIDValueConvertByteToLongWord(const UInt8 * src, uint64_t * dst, uint64_t bytesToCopy, Boolean signExtend); 42static void __IOHIDValueConvertLongWordToByte(const uint64_t * src, UInt8 * dst, uint64_t bytesToCopy); 43typedef struct __IOHIDValue 44{ 45 CFRuntimeBase cfBase; // base CFType information 46 47 IOHIDElementRef element; 48 uint64_t timeStamp; 49 uint32_t length; 50 uint8_t * bytePtr; 51 uint8_t bytes[]; 52} __IOHIDValue, *__IOHIDValueRef; 53 54static const CFRuntimeClass __IOHIDValueClass = { 55 0, // version 56 "IOHIDValue", // className 57 NULL, // init 58 NULL, // copy 59 __IOHIDValueRelease, // finalize 60 NULL, // equal 61 NULL, // hash 62 NULL, // copyFormattingDesc 63 NULL, 64 NULL, 65 NULL 66}; 67 68static CFTypeID __valueTypeID = _kCFRuntimeNotATypeID; 69static pthread_once_t __valueTypeInit = PTHREAD_ONCE_INIT; 70 71void __IOHIDValueRegister(void) 72{ 73 __valueTypeID = _CFRuntimeRegisterClass(&__IOHIDValueClass); 74} 75 76CFTypeID IOHIDValueGetTypeID(void) 77{ 78 /* initialize runtime */ 79 if ( __valueTypeID == _kCFRuntimeNotATypeID ) 80 pthread_once(&__valueTypeInit, __IOHIDValueRegister); 81 82 return __valueTypeID; 83} 84 85IOHIDValueRef __IOHIDValueCreatePrivate(CFAllocatorRef allocator, CFAllocatorContext * context __unused, size_t dataLength) 86{ 87 IOHIDValueRef event = NULL; 88 void * offset = NULL; 89 uint32_t size; 90 91 /* allocate session */ 92 size = sizeof(__IOHIDValue) - sizeof(CFRuntimeBase) + dataLength; 93 event = (IOHIDValueRef)_CFRuntimeCreateInstance(allocator, IOHIDValueGetTypeID(), size, NULL); 94 95 if (!event) 96 return NULL; 97 98 offset = event; 99 bzero(offset + sizeof(CFRuntimeBase), size); 100 101 return event; 102} 103 104void __IOHIDValueRelease( CFTypeRef object ) 105{ 106 IOHIDValueRef event = ( IOHIDValueRef ) object; 107 108 if (event->element) CFRelease(event->element); 109} 110 111IOHIDValueRef _IOHIDValueCreateWithElementValuePtr(CFAllocatorRef allocator, IOHIDElementRef element, IOHIDElementValue * pElementValue) 112{ 113 IOHIDValueRef event = NULL; 114 uint32_t length = 0; 115 116 if ( !element || !pElementValue ) 117 return NULL; 118 119 length = _IOHIDElementGetLength(element); 120 event = __IOHIDValueCreatePrivate(allocator, NULL, length); 121 122 if (!event) 123 return NULL; 124 125 event->element = (IOHIDElementRef)CFRetain(element); 126 event->timeStamp = *((uint64_t *)&(pElementValue->timestamp)); 127 event->length = length; 128 129 __IOHIDValueConvertWordToByte((const uint32_t *)&(pElementValue->value[0]), event->bytes, length); 130 131 return event; 132} 133 134IOHIDValueRef _IOHIDValueCreateWithStruct(CFAllocatorRef allocator, IOHIDElementRef element, IOHIDEventStruct * pEventStruct) 135{ 136 IOHIDValueRef event = NULL; 137 Boolean isLongValue = FALSE; 138 uint32_t length = 0; 139 140 if ( !element || !pEventStruct ) 141 return NULL; 142 143 isLongValue = (pEventStruct->longValue && pEventStruct->longValueSize); 144 length = _IOHIDElementGetLength(element); 145 event = __IOHIDValueCreatePrivate(allocator, NULL, isLongValue ? 0 : length); 146 147 if (!event) 148 return NULL; 149 150 event->element = (IOHIDElementRef)CFRetain(element); 151 event->timeStamp = *((uint64_t *)&(pEventStruct->timestamp)); 152 event->length = length; 153 154 if ( isLongValue ) 155 { 156 event->bytePtr = pEventStruct->longValue; 157 } 158 else 159 __IOHIDValueConvertWordToByte((const uint32_t *)&(pEventStruct->value), event->bytes, min(sizeof(uint32_t), event->length)); 160 161 return event; 162} 163 164IOHIDValueRef IOHIDValueCreateWithIntegerValue(CFAllocatorRef allocator, IOHIDElementRef element, uint64_t timeStamp, CFIndex value) 165{ 166 IOHIDValueRef event = NULL; 167 uint32_t length = 0; 168 uint64_t tempValue; 169 170 if ( !element ) 171 return NULL; 172 173 length = _IOHIDElementGetLength(element); 174 event = __IOHIDValueCreatePrivate(allocator, NULL, length); 175 176 if (!event) 177 return NULL; 178 179 event->element = (IOHIDElementRef)CFRetain(element); 180 event->timeStamp = timeStamp; 181 event->length = length; 182 183 tempValue = value; 184 185 __IOHIDValueConvertLongWordToByte((const uint64_t *)&tempValue, event->bytes, min(length, sizeof(uint32_t))); 186 187 return event; 188} 189 190IOHIDValueRef IOHIDValueCreateWithBytes(CFAllocatorRef allocator, IOHIDElementRef element, uint64_t timeStamp, const uint8_t * bytes, CFIndex byteLength) 191{ 192 IOHIDValueRef event = NULL; 193 CFIndex length = 0; 194 195 if ( !element || !bytes || !byteLength ) 196 return NULL; 197 198 length = _IOHIDElementGetLength(element); 199 event = __IOHIDValueCreatePrivate(allocator, NULL, length); 200 201 if (!event) 202 return NULL; 203 204 event->element = (IOHIDElementRef)CFRetain(element); 205 event->timeStamp = timeStamp; 206 event->length = length; 207 208 bcopy(bytes, event->bytes, min(length, byteLength)); 209 210 return event; 211} 212 213IOHIDValueRef IOHIDValueCreateWithBytesNoCopy(CFAllocatorRef allocator, IOHIDElementRef element, uint64_t timeStamp, const uint8_t * bytes, CFIndex length) 214{ 215 IOHIDValueRef event = NULL; 216 217 if ( !element || !bytes || !length ) 218 return NULL; 219 220 event = __IOHIDValueCreatePrivate(allocator, NULL, 0); 221 222 if (!event) 223 return NULL; 224 225 event->element = (IOHIDElementRef)CFRetain(element); 226 event->timeStamp = timeStamp; 227 event->length = min(length, _IOHIDElementGetLength(element)); 228 event->bytePtr = (uint8_t *)bytes; 229 230 return event; 231} 232 233 234IOHIDElementRef IOHIDValueGetElement(IOHIDValueRef event) 235{ 236 return event->element; 237} 238 239uint64_t IOHIDValueGetTimeStamp(IOHIDValueRef event) 240{ 241 return event->timeStamp; 242} 243 244CFIndex IOHIDValueGetIntegerValue(IOHIDValueRef event) 245{ 246 uint64_t value = 0; 247 IOHIDElementRef element = event->element; 248 __IOHIDValueConvertByteToLongWord(IOHIDValueGetBytePtr(event), &value, event->length, IOHIDElementGetLogicalMin(element) < 0 || IOHIDElementGetLogicalMax(element) < 0); 249 return (CFIndex)value; 250} 251 252double_t IOHIDValueGetScaledValue(IOHIDValueRef event, IOHIDValueScaleType type) 253{ 254 IOHIDElementRef element = event->element; 255 CFIndex logicalValue = IOHIDValueGetIntegerValue(event); 256 CFIndex logicalMin = IOHIDElementGetLogicalMin(element); 257 CFIndex logicalMax = IOHIDElementGetLogicalMax(element); 258 CFIndex logicalRange = 0; 259 CFIndex scaledMin = 0; 260 CFIndex scaledMax = 0; 261 CFIndex scaledRange = 0; 262 double_t granularity = 0.0; 263 double_t returnValue = 0.0; 264 265 if ( type == kIOHIDValueScaleTypeCalibrated ){ 266 IOHIDCalibrationInfo * calibrationInfo; 267 268 calibrationInfo = _IOHIDElementGetCalibrationInfo(element); 269 270 if ( calibrationInfo ) { 271 if ( calibrationInfo->min != calibrationInfo->max ) { 272 scaledMin = calibrationInfo->min; 273 scaledMax = calibrationInfo->max; 274 } else { 275 scaledMin = -1; 276 scaledMax = 1; 277 } 278 279 // check saturation first 280 if ( calibrationInfo->satMin != calibrationInfo->satMax ) { 281 if ( logicalValue <= calibrationInfo->satMin ) 282 return scaledMin; 283 if ( logicalValue >= calibrationInfo->satMax ) 284 return scaledMax; 285 286 logicalMin = calibrationInfo->satMin; 287 logicalMax = calibrationInfo->satMax; 288 } 289 290 // now check the dead zone 291 if (calibrationInfo->dzMin != calibrationInfo->dzMax) { 292 double_t scaledMid = scaledMin + ((scaledMax - scaledMin) / 2.0); 293 if (logicalValue < calibrationInfo->dzMin) { 294 logicalMax = calibrationInfo->dzMin; 295 scaledMax = scaledMid; 296 } else if ( logicalValue > calibrationInfo->dzMax) { 297 logicalMin = calibrationInfo->dzMax; 298 scaledMin = scaledMid; 299 } else { 300 return scaledMid; 301 } 302 } 303 304 granularity = calibrationInfo->gran; 305 } 306 } else { // kIOHIDValueScaleTypePhysical 307 scaledMin = IOHIDElementGetPhysicalMin(element); 308 scaledMax = IOHIDElementGetPhysicalMax(element); 309 } 310 311 logicalRange = logicalMax - logicalMin; 312 scaledRange = scaledMax - scaledMin; 313 returnValue = ((double_t)(logicalValue - logicalMin) * (double_t)scaledRange / (double_t)logicalRange) + scaledMin; 314 315 if ( granularity ) 316 returnValue = granularity * llround(returnValue / granularity); 317 318 return returnValue; 319} 320 321CFIndex IOHIDValueGetLength(IOHIDValueRef event) 322{ 323 return event->length; 324} 325 326const uint8_t * IOHIDValueGetBytePtr(IOHIDValueRef event) 327{ 328 return event->bytePtr ? event->bytePtr : event->bytes; 329} 330 331void _IOHIDValueCopyToElementValuePtr(IOHIDValueRef value, IOHIDElementValue * pElementValue) 332{ 333 IOHIDElementRef element = IOHIDValueGetElement(value); 334 335 __IOHIDValueConvertByteToWord(IOHIDValueGetBytePtr(value), (uint32_t *)(pElementValue->value), value->length, IOHIDElementGetLogicalMin(element) < 0 || IOHIDElementGetLogicalMax(element) < 0); 336} 337 338#if defined (__LITTLE_ENDIAN__) 339 #define ON_INTEL 1 340#else 341 #define ON_INTEL 0 342#endif 343 344#define BIT_MASK(bits) (((uint64_t)1 << (bits)) - 1) 345 346void __IOHIDValueConvertByteToWord(const UInt8 * src, uint32_t * dst, uint32_t length, Boolean signExtend) 347{ 348 bcopy(src, dst, length); 349 350 if ( signExtend && length ) 351 { 352 uint32_t lastOffset = length / sizeof(uint32_t); 353 uint32_t wordBitsProcessed = length % sizeof(uint32_t); 354 355 lastOffset += (wordBitsProcessed) ? 0:-1; 356 wordBitsProcessed = wordBitsProcessed << 3; 357 358 if (wordBitsProcessed && (dst[lastOffset] & (1<<(wordBitsProcessed-1)))) 359 dst[lastOffset] |= ~(BIT_MASK(wordBitsProcessed)); 360 } 361} 362 363void __IOHIDValueConvertWordToByte(const uint32_t * src, UInt8 * dst, uint32_t bytesToCopy) 364{ 365 bcopy(src, dst, bytesToCopy); 366} 367 368void __IOHIDValueConvertByteToLongWord(const UInt8 * src, uint64_t * dst, uint64_t length, Boolean signExtend) 369{ 370 bcopy(src, dst, length); 371 372 if ( signExtend && length ) 373 { 374 uint32_t lastOffset = length / sizeof(uint64_t); 375 uint32_t longWordBitsProcessed = length % sizeof(uint64_t); 376 377 lastOffset += (longWordBitsProcessed) ? 0:-1; 378 longWordBitsProcessed = longWordBitsProcessed << 3; 379 380 if (longWordBitsProcessed && (dst[lastOffset] & (1<<(longWordBitsProcessed-1)))) 381 dst[lastOffset] |= ~(BIT_MASK(longWordBitsProcessed)); 382 } 383} 384 385void __IOHIDValueConvertLongWordToByte(const uint64_t * src, UInt8 * dst, uint64_t bytesToCopy) 386{ 387 bcopy(src, dst, bytesToCopy); 388} 389