1/* 2 * 3 * @APPLE_LICENSE_HEADER_START@ 4 * 5 * Copyright (c) 1999-2012 Apple Computer, Inc. All Rights Reserved. 6 * 7 * This file contains Original Code and/or Modifications of Original Code 8 * as defined in and that are subject to the Apple Public Source License 9 * Version 2.0 (the 'License'). You may not use this file except in 10 * compliance with the License. Please obtain a copy of the License at 11 * http://www.opensource.apple.com/apsl/ and read it before using this 12 * file. 13 * 14 * The Original Code and all software distributed under the License are 15 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 16 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 17 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 18 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 19 * Please see the License for the specific language governing rights and 20 * limitations under the License. 21 * 22 * @APPLE_LICENSE_HEADER_END@ 23 */ 24 25#include <AssertMacros.h> 26#include <pthread.h> 27#include <dispatch/dispatch.h> 28#include <mach/mach.h> 29#include <mach/mach_time.h> 30#include <CoreFoundation/CFRuntime.h> 31#include <CoreFoundation/CFBase.h> 32#include <IOKit/IOCFPlugIn.h> 33#include <IOKit/IOKitLib.h> 34#include <IOKit/IOCFSerialize.h> 35#include <IOKit/hid/IOHIDKeys.h> 36#include <IOKit/hid/IOHIDResourceUserClient.h> 37#include <IOKit/IODataQueueClient.h> 38#include "IOHIDUserDevice.h" 39#include <IOKit/IOKitLibPrivate.h> 40 41static IOHIDUserDeviceRef __IOHIDUserDeviceCreate( 42 CFAllocatorRef allocator, 43 CFAllocatorContext * context __unused, 44 IOOptionBits options); 45static void __IOHIDUserDeviceRelease( CFTypeRef object ); 46static void __IOHIDUserDeviceRegister(void); 47static void __IOHIDUserDeviceQueueCallback(CFMachPortRef port, void *msg, CFIndex size, void *info); 48static void __IOHIDUserDeviceHandleReportAsyncCallback(void *refcon, IOReturn result); 49static Boolean __IOHIDUserDeviceSetupAsyncSupport(IOHIDUserDeviceRef device); 50static IOReturn __IOHIDUserDeviceStartDevice(IOHIDUserDeviceRef device, IOOptionBits options); 51 52 53typedef struct __IOHIDUserDevice 54{ 55 CFRuntimeBase cfBase; // base CFType information 56 57 io_service_t service; 58 io_connect_t connect; 59 CFDictionaryRef properties; 60 IOOptionBits options; 61 62 CFRunLoopRef runLoop; 63 CFStringRef runLoopMode; 64 65 dispatch_queue_t dispatchQueue; 66 67 struct { 68 CFMachPortRef port; 69 CFRunLoopSourceRef source; 70 dispatch_source_t dispatchSource; 71 IODataQueueMemory * data; 72 } queue; 73 74 struct { 75 IONotificationPortRef port; 76 CFRunLoopSourceRef source; 77 IODataQueueMemory * data; 78 } async; 79 80 struct { 81 IOHIDUserDeviceReportCallback callback; 82 void * refcon; 83 } setReport, getReport; 84 85 struct { 86 IOHIDUserDeviceReportWithReturnLengthCallback callback; 87 void * refcon; 88 } getReportWithReturnLength; 89 90} __IOHIDUserDevice, *__IOHIDUserDeviceRef; 91 92static const CFRuntimeClass __IOHIDUserDeviceClass = { 93 0, // version 94 "IOHIDUserDevice", // className 95 NULL, // init 96 NULL, // copy 97 __IOHIDUserDeviceRelease, // finalize 98 NULL, // equal 99 NULL, // hash 100 NULL, // copyFormattingDesc 101 NULL, 102 NULL, 103 NULL 104}; 105 106static pthread_once_t __deviceTypeInit = PTHREAD_ONCE_INIT; 107static CFTypeID __kIOHIDUserDeviceTypeID = _kCFRuntimeNotATypeID; 108static mach_port_t __masterPort = MACH_PORT_NULL; 109 110 111typedef struct __IOHIDDeviceHandleReportAsyncContext { 112 IOHIDUserDeviceHandleReportAsyncCallback callback; 113 void * refcon; 114} IOHIDDeviceHandleReportAsyncContext; 115 116 117//------------------------------------------------------------------------------ 118// __IOHIDUserDeviceRegister 119//------------------------------------------------------------------------------ 120void __IOHIDUserDeviceRegister(void) 121{ 122 IOMasterPort(bootstrap_port, &__masterPort); 123 __kIOHIDUserDeviceTypeID = _CFRuntimeRegisterClass(&__IOHIDUserDeviceClass); 124} 125 126//------------------------------------------------------------------------------ 127// __IOHIDUserDeviceCreate 128//------------------------------------------------------------------------------ 129IOHIDUserDeviceRef __IOHIDUserDeviceCreate( 130 CFAllocatorRef allocator, 131 CFAllocatorContext * context __unused, 132 IOOptionBits options) 133{ 134 IOHIDUserDeviceRef device = NULL; 135 void * offset = NULL; 136 uint32_t size; 137 138 /* allocate service */ 139 size = sizeof(__IOHIDUserDevice) - sizeof(CFRuntimeBase); 140 device = (IOHIDUserDeviceRef)_CFRuntimeCreateInstance(allocator, IOHIDUserDeviceGetTypeID(), size, NULL); 141 142 if (!device) 143 return NULL; 144 145 offset = device; 146 bzero(offset + sizeof(CFRuntimeBase), size); 147 148 device->options = options; 149 150 return device; 151} 152 153//------------------------------------------------------------------------------ 154// __IOHIDUserDeviceRelease 155//------------------------------------------------------------------------------ 156void __IOHIDUserDeviceRelease( CFTypeRef object ) 157{ 158 IOHIDUserDeviceRef device = (IOHIDUserDeviceRef)object; 159 160 if ( device->queue.data ) 161 { 162#if !__LP64__ 163 vm_address_t mappedMem = (vm_address_t)device->queue.data; 164#else 165 mach_vm_address_t mappedMem = (mach_vm_address_t)device->queue.data; 166#endif 167 IOConnectUnmapMemory ( device->connect, 168 0, 169 mach_task_self(), 170 mappedMem); 171 device->queue.data = NULL; 172 } 173 174 if ( device->queue.dispatchSource ) { 175 dispatch_release(device->queue.dispatchSource); 176 device->queue.dispatchSource = NULL; 177 } 178 179 if ( device->queue.source ) { 180 CFRelease(device->queue.source); 181 device->queue.source = NULL; 182 } 183 184 if ( device->queue.port ) { 185 mach_port_t port = CFMachPortGetPort(device->queue.port); 186 187 CFMachPortInvalidate(device->queue.port); 188 CFRelease(device->queue.port); 189 190 mach_port_mod_refs(mach_task_self(), 191 port, 192 MACH_PORT_RIGHT_RECEIVE, 193 -1); 194 195 device->queue.port = NULL; 196 } 197 198 if ( device->async.port ) { 199 IONotificationPortDestroy(device->async.port); 200 device->async.port = NULL; 201 } 202 203 if ( device->properties ) { 204 CFRelease(device->properties); 205 device->properties = NULL; 206 } 207 208 if ( device->connect ) { 209 IOObjectRelease(device->connect); 210 device->connect = 0; 211 } 212 213 if ( device->service ) { 214 IOObjectRelease(device->service); 215 device->service = 0; 216 } 217 218} 219 220//------------------------------------------------------------------------------ 221// IOHIDUserDeviceGetTypeID 222//------------------------------------------------------------------------------ 223CFTypeID IOHIDUserDeviceGetTypeID(void) 224{ 225 if ( _kCFRuntimeNotATypeID == __kIOHIDUserDeviceTypeID ) 226 pthread_once(&__deviceTypeInit, __IOHIDUserDeviceRegister); 227 228 return __kIOHIDUserDeviceTypeID; 229} 230 231//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 232// __IOHIDUserDeviceStartDevice 233//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 234IOReturn __IOHIDUserDeviceStartDevice(IOHIDUserDeviceRef device, IOOptionBits options) 235{ 236 CFDataRef data = NULL; 237 IOReturn kr; 238 uint64_t input = options; 239 240 data = IOCFSerialize(device->properties, 0); 241 require_action(data, error, kr=kIOReturnNoMemory); 242 243 kr = IOConnectCallMethod(device->connect, kIOHIDResourceDeviceUserClientMethodCreate, &input, 1, CFDataGetBytePtr(data), CFDataGetLength(data), NULL, NULL, NULL, NULL); 244 require_noerr(kr, error); 245 246error: 247 if ( data ) 248 CFRelease(data); 249 250 return kr; 251 252} 253 254//------------------------------------------------------------------------------ 255// IOHIDUserDeviceCreate 256//------------------------------------------------------------------------------ 257IOHIDUserDeviceRef IOHIDUserDeviceCreate( 258 CFAllocatorRef allocator, 259 CFDictionaryRef properties) 260{ 261 return IOHIDUserDeviceCreateWithOptions(allocator, properties, 0); 262} 263 264//------------------------------------------------------------------------------ 265// IOHIDUserDeviceCreateWithOptions 266//------------------------------------------------------------------------------ 267IOHIDUserDeviceRef IOHIDUserDeviceCreateWithOptions(CFAllocatorRef allocator, CFDictionaryRef properties, IOOptionBits options) 268{ 269 IOHIDUserDeviceRef device = NULL; 270 IOHIDUserDeviceRef result = NULL; 271 kern_return_t kr; 272 273 require(properties, error); 274 275 device = __IOHIDUserDeviceCreate(allocator, NULL, options); 276 require(device, error); 277 278 device->properties = CFDictionaryCreateCopy(allocator, properties); 279 require(device->properties, error); 280 281 device->service = IOServiceGetMatchingService(__masterPort, IOServiceMatching("IOHIDResource")); 282 require(device->service, error); 283 284 kr = IOServiceOpen(device->service, mach_task_self(), kIOHIDResourceUserClientTypeDevice, &device->connect); 285 require_noerr(kr, error); 286 287 if ( (device->options & kIOHIDUserDeviceCreateOptionStartWhenScheduled) == 0 ) { 288 kr = __IOHIDUserDeviceStartDevice(device, device->options); 289 require_noerr(kr, error); 290 } 291 292 result = device; 293 CFRetain(result); 294 295error: 296 297 if ( device ) 298 CFRelease(device); 299 300 return result; 301} 302 303//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 304// __IOHIDUserDeviceSetupAsyncSupport 305//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 306Boolean __IOHIDUserDeviceSetupAsyncSupport(IOHIDUserDeviceRef device) 307{ 308 Boolean result; 309 310 if ( !device->queue.data ) { 311 IOReturn ret; 312 #if !__LP64__ 313 vm_address_t address = 0; 314 vm_size_t size = 0; 315 #else 316 mach_vm_address_t address = 0; 317 mach_vm_size_t size = 0; 318 #endif 319 320 ret = IOConnectMapMemory(device->connect, 0, mach_task_self(), &address, &size, kIOMapAnywhere); 321 require_noerr_action(ret, exit, result=false); 322 323 device->queue.data =(IODataQueueMemory * )address; 324 } 325 326 if ( !device->queue.port ) { 327 mach_port_t port = IODataQueueAllocateNotificationPort(); 328 329 if ( port != MACH_PORT_NULL ) { 330 CFMachPortContext context = {0, device, NULL, NULL, NULL}; 331 332 device->queue.port = CFMachPortCreateWithPort(CFGetAllocator(device), port, __IOHIDUserDeviceQueueCallback, &context, FALSE); 333 } 334 } 335 require_action(device->queue.port, exit, result=false); 336 337 if ( !device->async.port ) { 338 device->async.port = IONotificationPortCreate(kIOMasterPortDefault); 339 } 340 341 require_action(device->async.port, exit, result=false); 342 343 result = true; 344 345exit: 346 347 return true; 348} 349 350//------------------------------------------------------------------------------ 351// IOHIDUserDeviceScheduleWithRunLoop 352//------------------------------------------------------------------------------ 353void IOHIDUserDeviceScheduleWithRunLoop(IOHIDUserDeviceRef device, CFRunLoopRef runLoop, CFStringRef runLoopMode) 354{ 355 if ( !__IOHIDUserDeviceSetupAsyncSupport(device) ) 356 return; 357 358 if ( !device->queue.source ) { 359 device->queue.source = CFMachPortCreateRunLoopSource(CFGetAllocator(device), device->queue.port, 0); 360 if ( !device->queue.source ) 361 return; 362 } 363 364 if ( !device->async.source ) { 365 device->async.source = IONotificationPortGetRunLoopSource(device->async.port); 366 if ( !device->async.source ) 367 return; 368 } 369 370 CFRunLoopAddSource(runLoop, device->async.source, runLoopMode); 371 CFRunLoopAddSource(runLoop, device->queue.source, runLoopMode); 372 IOConnectSetNotificationPort(device->connect, 0, CFMachPortGetPort(device->queue.port), (uintptr_t)NULL); 373 374 if ( device->options & kIOHIDUserDeviceCreateOptionStartWhenScheduled ) { 375 __IOHIDUserDeviceStartDevice(device, device->options); 376 } 377 378} 379 380//------------------------------------------------------------------------------ 381// IOHIDUserDeviceUnscheduleFromRunLoop 382//------------------------------------------------------------------------------ 383void IOHIDUserDeviceUnscheduleFromRunLoop(IOHIDUserDeviceRef device, CFRunLoopRef runLoop, CFStringRef runLoopMode) 384{ 385 if ( !device->queue.port ) 386 return; 387 388 IOConnectSetNotificationPort(device->connect, 0, MACH_PORT_NULL, (uintptr_t)NULL); 389 CFRunLoopRemoveSource(runLoop, device->queue.source, runLoopMode); 390 CFRunLoopRemoveSource(runLoop, device->async.source, runLoopMode); 391} 392 393//------------------------------------------------------------------------------ 394// IOHIDUserDeviceScheduleWithDispatchQueue 395//------------------------------------------------------------------------------ 396void IOHIDUserDeviceScheduleWithDispatchQueue(IOHIDUserDeviceRef device, dispatch_queue_t queue) 397{ 398 if ( !__IOHIDUserDeviceSetupAsyncSupport(device) ) 399 return; 400 401 if ( !device->queue.dispatchSource ) { 402 device->queue.dispatchSource = dispatch_source_create(DISPATCH_SOURCE_TYPE_MACH_RECV, CFMachPortGetPort(device->queue.port), 0, queue); 403 404 if ( !device->queue.dispatchSource ) 405 return; 406 407 dispatch_source_set_event_handler(device->queue.dispatchSource, ^{ 408 CFRetain(device); 409 mach_msg_size_t size = sizeof(mach_msg_header_t) + MAX_TRAILER_SIZE; 410 mach_msg_header_t *msg = (mach_msg_header_t *)CFAllocatorAllocate(CFGetAllocator(device), size, 0); 411 msg->msgh_size = size; 412 for (;;) { 413 msg->msgh_bits = 0; 414 msg->msgh_local_port = CFMachPortGetPort(device->queue.port); 415 msg->msgh_remote_port = MACH_PORT_NULL; 416 msg->msgh_id = 0; 417 kern_return_t ret = mach_msg(msg, MACH_RCV_MSG|MACH_RCV_LARGE|MACH_RCV_TRAILER_TYPE(MACH_MSG_TRAILER_FORMAT_0)|MACH_RCV_TRAILER_ELEMENTS(MACH_RCV_TRAILER_AV), 0, msg->msgh_size, CFMachPortGetPort(device->queue.port), 0, MACH_PORT_NULL); 418 if (MACH_MSG_SUCCESS == ret) break; 419 if (MACH_RCV_TOO_LARGE != ret) goto inner_exit; 420 uint32_t newSize = round_msg(msg->msgh_size + MAX_TRAILER_SIZE); 421 msg = CFAllocatorReallocate(CFGetAllocator(device), msg, newSize, 0); 422 msg->msgh_size = newSize; 423 } 424 425 __IOHIDUserDeviceQueueCallback(device->queue.port, msg, msg->msgh_size, device); 426 427 inner_exit: 428 CFAllocatorDeallocate(kCFAllocatorSystemDefault, msg); 429 CFRelease(device); 430 }); 431 } 432 433 IONotificationPortSetDispatchQueue(device->async.port, queue); 434 435 dispatch_resume(device->queue.dispatchSource); 436 IOConnectSetNotificationPort(device->connect, 0, CFMachPortGetPort(device->queue.port), (uintptr_t)NULL); 437 438 device->dispatchQueue = queue; 439 440 if ( device->options & kIOHIDUserDeviceCreateOptionStartWhenScheduled ) { 441 __IOHIDUserDeviceStartDevice(device, device->options); 442 } 443 444} 445 446//------------------------------------------------------------------------------ 447// IOHIDUserDeviceUnscheduleFromDispatchQueue 448//------------------------------------------------------------------------------ 449void IOHIDUserDeviceUnscheduleFromDispatchQueue(IOHIDUserDeviceRef device, dispatch_queue_t queue) 450{ 451 if ( !device->queue.port || device->dispatchQueue != queue) 452 return; 453 454 IOConnectSetNotificationPort(device->connect, 0, MACH_PORT_NULL, (uintptr_t)NULL); 455 456 if ( device->queue.dispatchSource ) { 457 dispatch_release(device->queue.dispatchSource); 458 device->queue.dispatchSource = NULL; 459 } 460 461 if ( device->async.port ) { 462 IONotificationPortDestroy(device->async.port); 463 device->async.port = NULL; 464 } 465} 466 467//------------------------------------------------------------------------------ 468// IOHIDUserDeviceRegisterGetReportCallback 469//------------------------------------------------------------------------------ 470void IOHIDUserDeviceRegisterGetReportCallback(IOHIDUserDeviceRef device, IOHIDUserDeviceReportCallback callback, void * refcon) 471{ 472 device->getReport.callback = callback; 473 device->getReport.refcon = refcon; 474} 475 476//------------------------------------------------------------------------------ 477// IOHIDUserDeviceRegisterGetReportCallback 478//------------------------------------------------------------------------------ 479void IOHIDUserDeviceRegisterGetReportWithReturnLengthCallback(IOHIDUserDeviceRef device, IOHIDUserDeviceReportWithReturnLengthCallback callback, void * refcon) 480{ 481 device->getReportWithReturnLength.callback = callback; 482 device->getReportWithReturnLength.refcon = refcon; 483} 484 485 486//------------------------------------------------------------------------------ 487// IOHIDUserDeviceRegisterSetReportCallback 488//------------------------------------------------------------------------------ 489void IOHIDUserDeviceRegisterSetReportCallback(IOHIDUserDeviceRef device, IOHIDUserDeviceReportCallback callback, void * refcon) 490{ 491 device->setReport.callback = callback; 492 device->setReport.refcon = refcon; 493} 494 495#ifndef min 496#define min(a, b) \ 497 ((a < b) ? a:b) 498#endif 499//------------------------------------------------------------------------------ 500// __IOHIDUserDeviceQueueCallback 501//------------------------------------------------------------------------------ 502void __IOHIDUserDeviceQueueCallback(CFMachPortRef port __unused, void *msg __unused, CFIndex size __unused, void *info) 503{ 504 IOHIDUserDeviceRef device = (IOHIDUserDeviceRef)info; 505 506 if ( !device->queue.data ) 507 return; 508 509 // check entry size 510 IODataQueueEntry * nextEntry; 511 uint32_t dataSize; 512 513 // if queue empty, then stop 514 while ((nextEntry = IODataQueuePeek(device->queue.data))) { 515 516 IOHIDResourceDataQueueHeader * header = (IOHIDResourceDataQueueHeader*)&(nextEntry->data); 517 uint64_t response[kIOHIDResourceUserClientResponseIndexCount] = {kIOReturnUnsupported,header->token}; 518 uint8_t * responseReport = NULL; 519 CFIndex responseLength = 0; 520 521 // set report 522 if ( header->direction == kIOHIDResourceReportDirectionOut ) { 523 CFIndex reportLength = min(header->length, (nextEntry->size - sizeof(IOHIDResourceDataQueueHeader))); 524 uint8_t * report = ((uint8_t*)header)+sizeof(IOHIDResourceDataQueueHeader); 525 526 if ( device->setReport.callback ) 527 response[kIOHIDResourceUserClientResponseIndexResult] = (*device->setReport.callback)(device->setReport.refcon, header->type, header->reportID, report, reportLength); 528 529 } 530 else if ( header->direction == kIOHIDResourceReportDirectionIn ) { 531 // RY: malloc our own data that we'll send back to the kernel. 532 // I thought about mapping the mem dec from the caller in kernel, 533 // but given the typical usage, it is so not worth it 534 responseReport = (uint8_t *)malloc(header->length); 535 responseLength = header->length; 536 537 if ( device->getReport.callback ) 538 response[kIOHIDResourceUserClientResponseIndexResult] = (*device->getReport.callback)(device->getReport.refcon, header->type, header->reportID, responseReport, responseLength); 539 540 if ( device->getReportWithReturnLength.callback ) 541 response[kIOHIDResourceUserClientResponseIndexResult] = (*device->getReportWithReturnLength.callback)(device->getReportWithReturnLength.refcon, header->type, header->reportID, responseReport, &responseLength); 542 } 543 544 // post the response 545 IOConnectCallMethod(device->connect, kIOHIDResourceDeviceUserClientMethodPostReportResponse, response, sizeof(response)/sizeof(uint64_t), responseReport, responseLength, NULL, NULL, NULL, NULL); 546 547 if ( responseReport ) 548 free(responseReport); 549 550 // dequeue the item 551 dataSize = 0; 552 IODataQueueDequeue(device->queue.data, NULL, &dataSize); 553 } 554} 555 556 557//------------------------------------------------------------------------------ 558// __IOHIDUserDeviceHandleReportAsyncCallback 559//------------------------------------------------------------------------------ 560void __IOHIDUserDeviceHandleReportAsyncCallback(void *refcon, IOReturn result) 561{ 562 IOHIDDeviceHandleReportAsyncContext *pContext = (IOHIDDeviceHandleReportAsyncContext *)refcon; 563 564 if (pContext->callback) 565 pContext->callback(pContext->refcon, result); 566 567 free(pContext); 568} 569 570//------------------------------------------------------------------------------ 571// IOHIDUserDeviceHandleReportAsync 572//------------------------------------------------------------------------------ 573IOReturn IOHIDUserDeviceHandleReportAsyncWithTimeStamp(IOHIDUserDeviceRef device, uint64_t timestamp, uint8_t *report, CFIndex reportLength, IOHIDUserDeviceHandleReportAsyncCallback callback, void * refcon) 574{ 575 IOHIDDeviceHandleReportAsyncContext *pContext = malloc(sizeof(IOHIDDeviceHandleReportAsyncContext)); 576 577 if (!pContext) 578 return kIOReturnNoMemory; 579 580 pContext->callback = callback; 581 pContext->refcon = refcon; 582 583 mach_port_t wakePort = MACH_PORT_NULL; 584 uint64_t asyncRef[kOSAsyncRef64Count]; 585 586 wakePort = IONotificationPortGetMachPort(device->async.port); 587 588 asyncRef[kIOAsyncCalloutFuncIndex] = (uint64_t)(uintptr_t)__IOHIDUserDeviceHandleReportAsyncCallback; 589 asyncRef[kIOAsyncCalloutRefconIndex] = (uint64_t)(uintptr_t)pContext; 590 591 return IOConnectCallAsyncMethod(device->connect, kIOHIDResourceDeviceUserClientMethodHandleReport, wakePort, asyncRef, kOSAsyncRef64Count, ×tamp, 1, report, reportLength, NULL, NULL, NULL, NULL); 592} 593 594//------------------------------------------------------------------------------ 595// IOHIDUserDeviceHandleReportWithTimeStamp 596//------------------------------------------------------------------------------ 597IOReturn IOHIDUserDeviceHandleReportWithTimeStamp(IOHIDUserDeviceRef device, uint64_t timestamp, uint8_t * report, CFIndex reportLength) 598{ 599 return IOConnectCallMethod(device->connect, kIOHIDResourceDeviceUserClientMethodHandleReport, ×tamp, 1, report, reportLength, NULL, NULL, NULL, NULL); 600} 601 602//------------------------------------------------------------------------------ 603// IOHIDUserDeviceHandleReport 604//------------------------------------------------------------------------------ 605IOReturn IOHIDUserDeviceHandleReport(IOHIDUserDeviceRef device, uint8_t * report, CFIndex reportLength) 606{ 607 return IOHIDUserDeviceHandleReportWithTimeStamp(device, mach_absolute_time(), report, reportLength); 608} 609 610//------------------------------------------------------------------------------ 611// IOHIDUserDeviceHandleReportAsync 612//------------------------------------------------------------------------------ 613IOReturn IOHIDUserDeviceHandleReportAsync(IOHIDUserDeviceRef device, uint8_t * report, CFIndex reportLength, IOHIDUserDeviceHandleReportAsyncCallback callback, void * refcon) 614{ 615 return IOHIDUserDeviceHandleReportAsyncWithTimeStamp(device, mach_absolute_time(), report, reportLength, callback, refcon); 616} 617 618