IOUSBHIDDriver.cpp [plain text]
#include <libkern/OSByteOrder.h>
#include <IOKit/IOService.h>
#include <IOKit/IOBufferMemoryDescriptor.h>
#include <IOKit/IOMessage.h>
#include <IOKit/IOTimerEventSource.h>
#include <IOKit/IOKitKeys.h>
#include <IOKit/hid/IOHIDKeys.h>
#include <IOKit/usb/IOUSBInterface.h>
#include <IOKit/usb/IOUSBLog.h>
#include <IOKit/usb/IOUSBPipe.h>
#include <IOKit/usb/IOUSBHIDDriver.h>
#include <IOKit/usb/IOUSBHubPolicyMaker.h>
#import "USBTracepoints.h"
#ifndef IOUSBHIDDriver_USE_KPRINTF 0
#define IOUSBHIDDriver_USE_KPRINTF 0
#endif
#if IOUSBHIDDriver_USE_KPRINTF
#undef USBLog
#undef USBError
void kprintf(const char *format, ...)
__attribute__((format(printf, 1, 2)));
#define USBLog( LEVEL, FORMAT, ARGS... ) if ((LEVEL) <= IOUSBHIDDriver_USE_KPRINTF) { kprintf( FORMAT "\n", ## ARGS ) ; }
#define USBError( LEVEL, FORMAT, ARGS... ) { kprintf( FORMAT "\n", ## ARGS ) ; }
#endif
#define super IOHIDDevice
#define _WORKLOOP _usbHIDExpansionData->_workLoop
#define _HANDLE_REPORT_THREAD _usbHIDExpansionData->_handleReportThread
#define _ROOT_DOMAIN _usbHIDExpansionData->_rootDomain
#define _WAKEUP_TIME _usbHIDExpansionData->_wakeUpTime
#define _COMPLETION_WITH_TIMESTAMP _usbHIDExpansionData->_completionWithTimeStamp
#define _CHECK_FOR_TIMESTAMP _usbHIDExpansionData->_checkForTimeStamp
#define _MS_TO_IGNORE_TRANSACTIONS_AFTER_WAKE _usbHIDExpansionData->_msToIgnoreTransactionsAfterWake
#define _SUSPENDPORT_TIMER _usbHIDExpansionData->_suspendPortTimer
#define _PORT_SUSPENDED _usbHIDExpansionData->_portSuspended
#define _SUSPEND_TIMEOUT_IN_MS _usbHIDExpansionData->_suspendTimeoutInMS
#define _INTERFACE_NUMBER _usbHIDExpansionData->_interfaceNumber
#define _LOG_HID_REPORTS _usbHIDExpansionData->_logHIDReports
#define _HID_LOGGING_LEVEL _usbHIDExpansionData->_hidLoggingLevel
#define _NEED_TO_CLEARPIPESTALL _usbHIDExpansionData->_needToClearPipeStall
#define _QUEUED_REPORTS _usbHIDExpansionData->_queuedReports
#define _INTERRUPT_TIMESTAMP _usbHIDExpansionData->_interruptTimeStamp
#define _POWERSTATECHANGING _usbHIDExpansionData->_powerStateChanging
#define _MYPOWERSTATE _usbHIDExpansionData->_myPowerState
#define _PENDINGREAD _usbHIDExpansionData->_pendingRead
#define _DEAD_DEVICE_CHECK_LOCK _usbHIDExpansionData->_deviceDeadCheckLock
#define ABORTEXPECTED _deviceIsDead
#define kMaxQueuedReports 1
static IOPMPowerState ourPowerStates[kUSBHIDNumberPowerStates] = {
{ kIOPMPowerStateVersion1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
{ kIOPMPowerStateVersion1, kIOPMRestartCapability, kIOPMRestart, kIOPMRestart, 0, 0, 0, 0, 0, 0, 0, 0 },
{ kIOPMPowerStateVersion1, kIOPMSleepCapability, kIOPMSleep, kIOPMSleep, 0, 0, 0, 0, 0, 0, 0, 0 },
{ kIOPMPowerStateVersion1, kIOPMLowPower, kIOPMLowPower, kIOPMLowPower, 0, 0, 0, 0, 0, 0, 0, 0 },
{ kIOPMPowerStateVersion1, IOPMDeviceUsable, IOPMPowerOn, IOPMPowerOn, 0, 0, 0, 0, 0, 0, 0, 0 }
};
OSDefineMetaClassAndStructors(IOUSBHIDDriver, IOHIDDevice)
#pragma mark ееееееее IOService Methods еееееееее
bool
IOUSBHIDDriver::init(OSDictionary *properties)
{
if (!super::init(properties))
{
return false;
}
if (!_usbHIDExpansionData)
{
_usbHIDExpansionData = (IOUSBHIDDriverExpansionData *)IOMalloc(sizeof(IOUSBHIDDriverExpansionData));
if (!_usbHIDExpansionData)
return false;
bzero(_usbHIDExpansionData, sizeof(IOUSBHIDDriverExpansionData));
}
_retryCount = kHIDDriverRetryCount;
_maxReportSize = kMaxHIDReportSize;
_HID_LOGGING_LEVEL = 7;
return true;
}
void
IOUSBHIDDriver::stop(IOService * provider)
{
USBLog(7, "IOUSBHIDDriver(%s)[%p]::stop isInactive = %d", getName(), this, isInactive());
if (_WORKLOOP && _gate)
_WORKLOOP->removeEventSource(_gate);
if (_WORKLOOP && _SUSPENDPORT_TIMER)
_WORKLOOP->removeEventSource( _SUSPENDPORT_TIMER );
super::stop(provider);
}
void
IOUSBHIDDriver::free()
{
if (_gate)
{
_gate->release();
_gate = NULL;
}
if (_usbHIDExpansionData)
{
if ( _SUSPENDPORT_TIMER )
{
_SUSPENDPORT_TIMER->release();
_SUSPENDPORT_TIMER = NULL;
_SUSPEND_TIMEOUT_IN_MS= 0;
}
if (_WORKLOOP)
{
_WORKLOOP->release();
_WORKLOOP = NULL;
}
IOFree(_usbHIDExpansionData, sizeof(IOUSBHIDDriverExpansionData));
_usbHIDExpansionData = NULL;
}
super::free();
}
bool
IOUSBHIDDriver::start(IOService *provider)
{
IOReturn err = kIOReturnSuccess;
IOWorkLoop * workLoop = NULL;
IOCommandGate * commandGate = NULL;
OSNumber * locationIDProperty = NULL;
IOUSBFindEndpointRequest request;
bool addEventSourceSuccess = false;
UInt32 maxInputReportSize = 0;
OSNumber * inputReportSize = NULL;
OSNumber * numberObj = NULL;
OSObject * propertyObj = NULL;
OSBoolean * sixAxisProperty = NULL;
USBTrace_Start( kUSBTHID, kTPHIDStart, (uintptr_t)this, 0, 0, 0);
USBLog(7, "IOUSBHIDDriver(%s)[%p]::start", getName(), this);
IncrementOutstandingIO();
if ( provider )
{
propertyObj = provider->copyProperty(kUSBDevicePropertyLocationID);
locationIDProperty = OSDynamicCast( OSNumber, propertyObj);
if ( locationIDProperty )
{
_locationID = locationIDProperty->unsigned32BitValue();
}
if (propertyObj)
{
propertyObj->release();
propertyObj = NULL;
}
}
if (!super::start(provider))
{
USBLog(1, "IOUSBHIDDriver(%s)[%p]::start - super::start returned false!", getName(), this);
USBTrace( kUSBTHID, kTPHIDStart, (uintptr_t)this, 0, 0, 1 );
goto ErrorExit;
}
commandGate = IOCommandGate::commandGate(this);
if (!commandGate)
{
USBLog(1, "IOUSBHIDDriver(%s)[%p]::start - could not get a command gate", getName(), this);
USBTrace( kUSBTHID, kTPHIDStart, (uintptr_t)this, 0, 0, 2 );
goto ErrorExit;
}
workLoop = getWorkLoop();
if ( !workLoop)
{
USBLog(1, "IOUSBHIDDriver(%s)[%p]::start - unable to find my workloop", getName(), this);
USBTrace( kUSBTHID, kTPHIDStart, (uintptr_t)this, 0, 0, 3 );
goto ErrorExit;
}
workLoop->retain();
if (workLoop->addEventSource(commandGate) != kIOReturnSuccess)
{
USBLog(1, "IOUSBHIDDriver(%s)[%p]::start - unable to add gate to work loop", getName(), this);
USBTrace( kUSBTHID, kTPHIDStart, (uintptr_t)this, 0, 0, 4 );
goto ErrorExit;
}
addEventSourceSuccess = true;
request.type = kUSBInterrupt;
request.direction = kUSBOut;
_interruptOutPipe = _interface->FindNextPipe(NULL, &request);
request.type = kUSBInterrupt;
request.direction = kUSBIn;
_interruptPipe = _interface->FindNextPipe(NULL, &request);
if (!_interruptPipe)
{
USBLog(1, "IOUSBHIDDriver(%s)[%p]::start - unable to get interrupt pipe", getName(), this);
USBTrace( kUSBTHID, kTPHIDStart, (uintptr_t)this, 0, 0, 5 );
goto ErrorExit;
}
_interruptPipe->retain();
propertyObj = copyProperty(kIOHIDMaxInputReportSizeKey);
inputReportSize = OSDynamicCast( OSNumber, propertyObj);
if ( inputReportSize )
{
maxInputReportSize = inputReportSize->unsigned32BitValue();
}
if (propertyObj)
{
propertyObj->release();
propertyObj = NULL;
}
if (maxInputReportSize == 0)
maxInputReportSize = _interruptPipe->GetMaxPacketSize();
if ( maxInputReportSize > 0 )
{
_buffer = IOBufferMemoryDescriptor::withCapacity(maxInputReportSize, kIODirectionIn);
if ( !_buffer )
{
USBLog(1, "IOUSBHIDDriver(%s)[%p]::start - unable to get create buffer", getName(), this);
USBTrace( kUSBTHID, kTPHIDStart, (uintptr_t)this, 0, 0, 6 );
goto ErrorExit;
}
}
else
{
USBLog(5, "IOUSBHIDDriver(%s)[%p]::start - Device reports maxInputReportSize of 0", getName(), this);
_buffer = NULL;
}
if ( (_device->GetVendorID()) == 0x06a3 )
SetIdleMillisecs(0);
if ( (_interface->GetInterfaceClass() == kUSBHIDClass) &&
(_interface->GetInterfaceSubClass() == kUSBHIDBootInterfaceSubClass) &&
(_interface->GetInterfaceProtocol() == kHIDKeyboardInterfaceProtocol) )
{
if (_device->GetVendorID() == kIOUSBVendorIDAppleComputer)
{
SetIdleMillisecs(0);
}
else
{
SetIdleMillisecs(24);
}
}
propertyObj = provider->copyProperty("SIXAXIS compatibility");
sixAxisProperty = OSDynamicCast( OSBoolean, propertyObj);
if ( sixAxisProperty )
{
if ( sixAxisProperty->isTrue() )
{
IOUSBDevRequest requestPB;
UInt8 buffer[18];
USBLog(3, "IOUSBHIDDriver(%s)[%p]::start SIXAXIS compatibility", getName(), this);
requestPB.bmRequestType = USBmakebmRequestType(kUSBIn, kUSBClass, kUSBInterface);
requestPB.bRequest = kHIDRqGetReport;
requestPB.wValue = (3 << 8) | 0xf2;
requestPB.wIndex = _interface->GetInterfaceNumber();
requestPB.wLength = sizeof(buffer);
requestPB.pData = &buffer;
requestPB.wLenDone = 0;
err = _device->DeviceRequest(&requestPB);
if ( err != kIOReturnSuccess )
{
USBLog(3, "IOUSBHIDDriver(%s)[%p]::start getReport for SIXAXIS compatibility request failed; err = 0x%x)", getName(), this, err);
}
}
}
if (propertyObj)
{
propertyObj->release();
propertyObj = NULL;
}
if (_interface->GetInterfaceSubClass() == kUSBHIDBootInterfaceSubClass)
err = SetProtocol( kHIDReportProtocolValue );
_deviceDeadCheckThread = thread_call_allocate((thread_call_func_t)CheckForDeadDeviceEntry, (thread_call_param_t)this);
_clearFeatureEndpointHaltThread = thread_call_allocate((thread_call_func_t)ClearFeatureEndpointHaltEntry, (thread_call_param_t)this);
_HANDLE_REPORT_THREAD = thread_call_allocate((thread_call_func_t)HandleReportEntry, (thread_call_param_t)this);
if ( !_deviceDeadCheckThread || !_clearFeatureEndpointHaltThread || !_HANDLE_REPORT_THREAD )
{
USBLog(1, "[%s]%p: could not allocate all thread functions", getName(), this);
USBTrace( kUSBTHID, kTPHIDStart, (uintptr_t)this, 0, 0, 7 );
goto ErrorExit;
}
_INTERFACE_NUMBER = _interface->GetInterfaceNumber();
propertyObj = provider->copyProperty(kUSBHIDReportLoggingLevel);
numberObj = OSDynamicCast( OSNumber, propertyObj);
if ( numberObj )
{
_HID_LOGGING_LEVEL = numberObj->unsigned32BitValue();
_LOG_HID_REPORTS = true;
USBLog(5, "IOUSBHIDDriver[%p](Intfce: %d of device %s @ 0x%x)::start HID Report Logging at level %d", this, _INTERFACE_NUMBER, _device->getName(), (uint32_t)_locationID, _HID_LOGGING_LEVEL);
}
else
{
_HID_LOGGING_LEVEL = 7;
_LOG_HID_REPORTS = false;
}
if (propertyObj)
{
propertyObj->release();
propertyObj = NULL;
}
err = StartFinalProcessing();
if (err != kIOReturnSuccess)
{
USBLog(1, "IOUSBHIDDriver(%s)[%p]::start - err (%x) in StartFinalProcessing", getName(), this, err);
USBTrace( kUSBTHID, kTPHIDStart, (uintptr_t)this, 0, 0, 8 );
goto ErrorExit;
}
USBLog(1, "[%p] USB HID Interface #%d of device %s @ %d (0x%x)",this, _interface->GetInterfaceNumber(), _device->getName(), _device->GetAddress(), (uint32_t)_locationID );
USBTrace( kUSBTHID, kTPHIDStart, _interface->GetInterfaceNumber(), _device->GetAddress(), (uint32_t)_locationID, 0);
_gate = commandGate;
_WORKLOOP = workLoop;
err = InitializeUSBHIDPowerManagement(provider);
if (err)
{
USBLog(1, "IOUSBHIDDriver(%s)[%p]::start - err [%p] from InitializeUSBHIDPowerManagement", getName(), this, (void*)err);
USBTrace( kUSBTHID, kTPHIDStart, (uintptr_t)this, err, 0, 10);
}
USBTrace_End( kUSBTHID, kTPHIDStart, (uintptr_t)this, 0, 0, 0);
DecrementOutstandingIO();
return true;
ErrorExit:
USBLog(1, "IOUSBHIDDriver(%s)[%p]::start - @ 0x%x aborting startup", getName(), this, (uint32_t)_locationID);
USBTrace( kUSBTHID, kTPHIDStart, (uintptr_t)this, (uint32_t)_locationID, 0, 9 );
if ( commandGate != NULL )
{
if ( addEventSourceSuccess )
workLoop->removeEventSource(commandGate);
commandGate->release();
commandGate = NULL;
}
if ( workLoop != NULL )
{
workLoop->release();
workLoop = NULL;
}
if (_deviceDeadCheckThread)
thread_call_free(_deviceDeadCheckThread);
if (_clearFeatureEndpointHaltThread)
thread_call_free(_clearFeatureEndpointHaltThread);
if (_HANDLE_REPORT_THREAD)
thread_call_free(_HANDLE_REPORT_THREAD);
if (_interruptPipe)
{
_interruptPipe->release();
_interruptPipe = NULL;
}
if (_interface)
_interface->close(this);
DecrementOutstandingIO(); return false;
}
IOReturn
IOUSBHIDDriver::message( UInt32 type, IOService * provider, void * argument )
{
IOReturn err;
err = super::message (type, provider, argument);
switch ( type )
{
case kIOUSBMessagePortHasBeenReset:
USBLog(3, "IOUSBHIDDriver(%s)[%p]: received kIOUSBMessagePortHasBeenReset, checking idle and rearming interrupt read", getName(), this);
if ( _retryCount != 0 )
{
USBLog(5, "IOUSBHIDDriver(%s)[%p]: received kIOUSBMessagePortHasBeenReset, we did not initiate this reset, so abort our interrupt pipe", getName(), this);
ABORTEXPECTED = TRUE;
if (_interruptPipe)
{
_interruptPipe->Abort();
}
}
_retryCount = kHIDDriverRetryCount;
ABORTEXPECTED = FALSE;
_deviceHasBeenDisconnected = FALSE;
if ( _interface && _device )
{
if ( (_interface->GetInterfaceClass() == kUSBHIDClass) &&
(_interface->GetInterfaceSubClass() == kUSBHIDBootInterfaceSubClass) &&
(_interface->GetInterfaceProtocol() == kHIDKeyboardInterfaceProtocol) )
{
if (_device->GetVendorID() == kIOUSBVendorIDAppleComputer)
{
SetIdleMillisecs(0);
}
else
{
SetIdleMillisecs(24);
}
}
if (_interface->GetInterfaceSubClass() == kUSBHIDBootInterfaceSubClass)
err = SetProtocol( kHIDReportProtocolValue );
if ( (_device->GetVendorID()) == 0x06a3 )
SetIdleMillisecs(0);
}
err = RearmInterruptRead();
break;
case kIOUSBMessagePortHasBeenSuspended:
USBLog(3, "IOUSBHIDDriver(%s)[%p]: received kIOUSBMessagePortHasBeenSuspended", getName(), this);
_PORT_SUSPENDED = true;
break;
case kIOUSBMessagePortHasBeenResumed:
case kIOUSBMessagePortWasNotSuspended:
USBLog(3, "IOUSBHIDDriver(%s)[%p]: received message %s (0x%x), rearming interrupt read", getName(), this, type == kIOUSBMessagePortHasBeenResumed ? "kIOUSBMessagePortHasBeenResumed": "kIOUSBMessagePortWasNotSuspended", (uint32_t)type);
_PORT_SUSPENDED = FALSE;
ABORTEXPECTED = FALSE;
err = RearmInterruptRead();
if ( _SUSPENDPORT_TIMER )
{
USBLog(5, "IOUSBHIDDriver(%s)[%p]::message re-enabling the timer", getName(), this);
_SUSPENDPORT_TIMER->setTimeoutMS(_SUSPEND_TIMEOUT_IN_MS);
}
break;
default:
break;
}
return err;
}
bool
IOUSBHIDDriver::willTerminate( IOService * provider, IOOptionBits options )
{
USBLog(3, "IOUSBHIDDriver(%s)[%p]::willTerminate isInactive (%d) _outstandingIO(%d)", getName(), this, isInactive(), (int)_outstandingIO);
if (_outstandingIO)
{
if (_interruptPipe)
{
_interruptPipe->Abort();
}
if ( _SUSPENDPORT_TIMER )
{
_SUSPENDPORT_TIMER->cancelTimeout();
}
}
return super::willTerminate(provider, options);
}
bool
IOUSBHIDDriver::didTerminate( IOService * provider, IOOptionBits options, bool * defer )
{
USBLog(3, "IOUSBHIDDriver(%s)[%p]::didTerminate isInactive = %d, outstandingIO = %d", getName(), this, isInactive(), (uint32_t)_outstandingIO);
PMstop();
if (!_outstandingIO)
{
if (_interruptPipe)
{
_interruptPipe->release();
_interruptPipe = NULL;
}
_interface->close(this);
}
else
_needToClose = true;
return super::didTerminate(provider, options, defer);
}
#pragma mark ееееееее Power Manager Methods еееееееее
unsigned long
IOUSBHIDDriver::maxCapabilityForDomainState ( IOPMPowerFlags domainState )
{
unsigned long ret = super::maxCapabilityForDomainState(domainState);
if (isInactive())
{
USBLog(2, "IOUSBHIDDriver[%p]::maxCapabilityForDomainState - while inactive - ignoring", this);
return ret;
}
USBLog(5, "IOUSBHIDDriver(%s)[%p]::maxCapabilityForDomainState - domainState[%d] - returning[%d]", getName(), this, (int)domainState, (int)ret);
return ret;
}
IOReturn
IOUSBHIDDriver::powerStateWillChangeTo ( IOPMPowerFlags capabilities, unsigned long stateNumber, IOService* whatDevice)
{
USBTrace_Start( kUSBTHID, kTPHIDpowerStateWillChangeTo, (uintptr_t)this, capabilities, stateNumber, (uintptr_t)whatDevice );
if (isInactive())
{
USBLog(1, "IOUSBHIDDriver[%p]::powerStateWillChangeTo - while inactive - ignoring", this);
USBTrace( kUSBTHID, kTPHIDpowerStateWillChangeTo, (uintptr_t)this, IOPMAckImplied, 0, 1 );
return IOPMAckImplied;
}
USBLog(5, "IOUSBHIDDriver(%s)[%p]::powerStateWillChangeTo - capabilities[%p] stateNumber[%d] whatDevice[%p]", getName(), this, (void*)capabilities, (int)stateNumber, whatDevice);
if (whatDevice != this)
{
USBLog(5, "IOUSBHIDDriver(%s)[%p]::powerStateWillChangeTo - whatDevice[%p] is not me - ignoring", getName(), this, whatDevice);
return IOPMAckImplied;
}
if (stateNumber != _MYPOWERSTATE)
_POWERSTATECHANGING = true;
USBLog(5, "IOUSBHIDDriver(%s)[%p]::powerStateWillChangeTo state (%d) - returning (%p)", getName(), this, (int)stateNumber, (void*)IOPMAckImplied);
USBTrace_End( kUSBTHID, kTPHIDpowerStateWillChangeTo, (uintptr_t)this, stateNumber, IOPMAckImplied, 0);
return IOPMAckImplied;
}
IOReturn
IOUSBHIDDriver::setPowerState ( unsigned long powerStateOrdinal, IOService* whatDevice )
{
USBTrace_Start( kUSBTHID, kTPHIDsetPowerState, (uintptr_t)this, powerStateOrdinal, (uintptr_t)whatDevice, 0);
if ( isInactive() )
{
USBLog(3,"IOUSBHIDDriver[%p]::setPowerState - while inactive - ignoring", this);
return kIOPMAckImplied;
}
USBLog(5, "IOUSBHIDDriver(%s)[%p]::setPowerState - powerStateOrdinal[%d] whatDevice[%p] _device[%p](%s)", getName(), this, (int)powerStateOrdinal, whatDevice, _device, _device->getName());
if ( whatDevice != this )
{
USBLog(1,"IOUSBHIDDriver[%p]::setPowerState - whatDevice != this", this);
USBTrace( kUSBTHID, kTPHIDsetPowerState, (uintptr_t)this, 0, 0, 1 );
return kIOPMAckImplied;
}
if (powerStateOrdinal > kUSBHIDPowerStateOn)
{
USBLog(1,"IOUSBHIDDriver[%p]::setPowerState - bad ordinal(%d)", this, (int)powerStateOrdinal);
USBTrace( kUSBTHID, kTPHIDsetPowerState, (uintptr_t)this, powerStateOrdinal, 0, 2 );
return kIOPMNoSuchState;
}
if (_MYPOWERSTATE == powerStateOrdinal)
{
USBLog(5,"IOUSBHIDDriver[%p]::setPowerState - already in correct power state (%d) - no op", this, (int)_MYPOWERSTATE);
return kIOPMAckImplied;
}
if (powerStateOrdinal < kUSBHIDPowerStateOn)
{
USBLog(5, "IOUSBHIDDriver(%s)[%p]::setPowerState state(%d) - aborting pipe (%p)", getName(), this, (int)powerStateOrdinal, _interruptPipe);
if ( _interruptPipe )
{
ABORTEXPECTED = true;
_interruptPipe->Abort();
}
USBLog(5, "IOUSBHIDDriver(%s)[%p]::setPowerState state (%d)- cancelling timer (%p)", getName(), this, (int)powerStateOrdinal, _SUSPENDPORT_TIMER);
if ( _SUSPENDPORT_TIMER )
{
_SUSPENDPORT_TIMER->cancelTimeout();
}
}
switch (powerStateOrdinal)
{
case kUSBHIDPowerStateOn:
case kUSBHIDPowerStateLowPower:
case kUSBHIDPowerStateSleep:
case kUSBHIDPowerStateOff:
case kUSBHIDPowerStateRestart:
break;
default:
USBLog(1, "IOUSBHIDDriver(%s)[%p]::setPowerState - unknown ordinal (%d)", getName(), this, (int)powerStateOrdinal);
USBTrace( kUSBTHID, kTPHIDsetPowerState, (uintptr_t)this, powerStateOrdinal, 0, 3 );
}
USBTrace_End( kUSBTHID, kTPHIDsetPowerState, (uintptr_t)this, 0, 0, 0);
return IOPMAckImplied;
}
IOReturn
IOUSBHIDDriver::powerStateDidChangeTo ( IOPMPowerFlags capabilities, unsigned long stateNumber, IOService* whatDevice)
{
IOReturn err;
USBTrace_Start( kUSBTHID, kTPHIDpowerStateDidChangeTo, (uintptr_t)this, capabilities, stateNumber, (uintptr_t)whatDevice );
if ( isInactive() )
{
USBLog(3,"IOUSBHIDDriver[%p]::powerStateDidChangeTo - while inactive - ignoring", this);
return kIOPMAckImplied;
}
if (whatDevice != this)
{
USBLog(5, "IOUSBHIDDriver(%s)[%p]::powerStateDidChangeTo - whatDevice[%p] is not me - ignoring", getName(), this, whatDevice);
return IOPMAckImplied;
}
_MYPOWERSTATE = stateNumber;
if (stateNumber == kUSBHIDPowerStateOn)
{
if (!_QUEUED_REPORTS)
{
USBLog(5, "IOUSBHIDDriver(%s)[%p]::powerStateDidChangeTo - _device (%s) going into RUN mode - issuing read and starting timer", getName(), this, _device->getName());
ABORTEXPECTED = false;
err = RearmInterruptRead();
if (err)
{
USBLog(1, "IOUSBHIDDriver(%s)[%p]::powerStateDidChangeTo - err (%p) returned from RearmInterruptRead", getName(), this, (void*)err);
USBTrace( kUSBTHID, kTPHIDpowerStateDidChangeTo, (uintptr_t)this, err, 0, 0);
}
if ( _SUSPENDPORT_TIMER )
{
_SUSPENDPORT_TIMER->setTimeoutMS(_SUSPEND_TIMEOUT_IN_MS);
}
}
else
{
USBLog(2, "IOUSBHIDDriver(%s)[%p]::powerStateDidChangeTo(ON) - not ReArming because _QUEUED_REPORTS was >0", getName(), this);
}
}
USBTrace_End( kUSBTHID, kTPHIDpowerStateDidChangeTo, (uintptr_t)this, 0, 0, 0);
return IOPMAckImplied;
}
void
IOUSBHIDDriver::powerChangeDone ( unsigned long fromState)
{
USBTrace_Start( kUSBTHID, kTPHIDpowerChangeDone, (uintptr_t)this, fromState, 0, 0);
if (isInactive())
{
USBLog(1, "IOUSBHIDDriver[%p]::powerChangeDone - from state (%d) - ignoring", this, (int)fromState);
USBTrace( kUSBTHID, kTPHIDpowerChangeDone, (uintptr_t)this, fromState, 0, 0);
return;
}
USBTrace_End( kUSBTHID, kTPHIDpowerChangeDone, (uintptr_t)this, 0, 0, 0);
USBLog((fromState == _MYPOWERSTATE) ? 7 : 5, "IOUSBHIDDriver[%p]::powerChangeDone from state (%d) to state (%d) _device name(%s)", this, (int)fromState, (int)_MYPOWERSTATE, _device->getName());
_POWERSTATECHANGING = false;
super::powerChangeDone(fromState);
}
#pragma mark ееееееее IOHIDDevice Methods еееееееее
bool
IOUSBHIDDriver::handleStart(IOService * provider)
{
USBLog(7, "IOUSBHIDDriver(%s)[%p]::handleStart", getName(), this);
USBTrace_Start( kUSBTHID, kTPHIDhandleStart, (uintptr_t)this, (uintptr_t)provider, 0, 0);
if ( !super::handleStart(provider))
{
return false;
}
if ( !provider->open(this))
{
USBLog(1, "IOUSBHIDDriver(%s)[%p]::handleStart - unable to open provider. returning false", getName(), this);
USBTrace( kUSBTHID, kTPHIDhandleStart, (uintptr_t)this, 0, 0, 1 );
return (false);
}
_interface = OSDynamicCast(IOUSBInterface, provider);
if (!_interface)
{
USBLog(1, "IOUSBHIDDriver(%s)[%p]::handleStart - Our provider is not an IOUSBInterface!!", getName(), this);
USBTrace( kUSBTHID, kTPHIDhandleStart, (uintptr_t)this, 0, 0, 2 );
return false;
}
_device = _interface->GetDevice();
if (!_device)
{
USBLog(1, "IOUSBHIDDriver(%s)[%p]::handleStart - Cannot get our provider's USB device. This is bad.", getName(), this);
USBTrace( kUSBTHID, kTPHIDhandleStart, (uintptr_t)this, 0, 0, 3 );
return false;
}
USBTrace_End( kUSBTHID, kTPHIDhandleStart, (uintptr_t)this, (uintptr_t)_interface, (uintptr_t)_device, 0);
return true;
}
void
IOUSBHIDDriver::handleStop(IOService * provider)
{
USBLog(7, "IOUSBHIDDriver(%s)[%p]::handleStop", getName(), this);
if (_buffer)
{
_buffer->release();
_buffer = NULL;
}
if (_deviceDeadCheckThread)
{
thread_call_cancel(_deviceDeadCheckThread);
thread_call_free(_deviceDeadCheckThread);
}
if (_clearFeatureEndpointHaltThread)
{
thread_call_cancel(_clearFeatureEndpointHaltThread);
thread_call_free(_clearFeatureEndpointHaltThread);
}
if (_HANDLE_REPORT_THREAD)
{
thread_call_cancel(_HANDLE_REPORT_THREAD);
thread_call_free(_HANDLE_REPORT_THREAD);
}
super::handleStop(provider);
}
IOReturn
IOUSBHIDDriver::getReport( IOMemoryDescriptor * report,
IOHIDReportType reportType,
IOOptionBits options )
{
UInt8 reportID;
IOReturn ret;
UInt8 usbReportType;
IOUSBDevRequestDesc requestPB;
if ( _device->GetVendorID() == 0x046d )
{
UInt16 prodID = _device->GetProductID();
if ( (prodID == 0xc202) || (prodID == 0xc207) || (prodID == 0xc208) ||
(prodID == 0xc209) || (prodID == 0xc20a) || (prodID == 0xc212) ||
(prodID == 0xc285) || (prodID == 0xc293) || (prodID == 0xc294) ||
(prodID == 0xc295) || (prodID == 0xc283) )
{
return kIOReturnUnsupported;
}
}
IncrementOutstandingIO();
reportID = (UInt8) ( options & 0x000000ff);
usbReportType = HIDMGR2USBREPORTTYPE(reportType);
requestPB.bmRequestType = USBmakebmRequestType(kUSBIn, kUSBClass, kUSBInterface);
requestPB.bRequest = kHIDRqGetReport;
requestPB.wValue = (usbReportType << 8) | reportID;
requestPB.wIndex = _interface->GetInterfaceNumber();
requestPB.wLength = report->getLength();
requestPB.pData = report;
requestPB.wLenDone = 0;
ret = _device->DeviceRequest(&requestPB);
if ( ret != kIOReturnSuccess )
{
USBLog(3, "IOUSBHIDDriver(%s)[%p]::getReport request failed; err = 0x%x)", getName(), this, ret);
}
DecrementOutstandingIO();
if ( _LOG_HID_REPORTS )
{
USBLog(_HID_LOGGING_LEVEL, "IOUSBHIDDriver[%p](Intfce: %d of device %s @ 0x%x)::getReport(%d, type = %s) returned success:", this, _INTERFACE_NUMBER, _device->getName(), (uint32_t)_locationID, reportID,
usbReportType == 1 ? "input" : (usbReportType == 2 ? "output" : (usbReportType == 3 ? "feature" : "unknown")) );
LogMemReport(_HID_LOGGING_LEVEL, report, report->getLength());
}
return ret;
}
IOReturn
IOUSBHIDDriver::setReport( IOMemoryDescriptor * report,
IOHIDReportType reportType,
IOOptionBits options)
{
UInt8 reportID;
IOReturn ret;
UInt8 usbReportType;
IOUSBDevRequestDesc requestPB;
IncrementOutstandingIO();
reportID = (UInt8) ( options & 0x000000ff);
usbReportType = HIDMGR2USBREPORTTYPE(reportType);
if ( kHIDOutputReport == usbReportType && _interruptOutPipe )
{
if ( _LOG_HID_REPORTS )
{
USBLog(_HID_LOGGING_LEVEL, "IOUSBHIDDriver[%p](Intfce: %d of device %s @ 0x%x)::setReport sending out interrupt out pipe buffer (%p,%d):", this, _INTERFACE_NUMBER, _device->getName(), (uint32_t)_locationID, report, (uint32_t)report->getLength() );
LogMemReport(_HID_LOGGING_LEVEL, report, report->getLength());
}
ret = _interruptOutPipe->Write(report);
if (ret == kIOReturnSuccess)
{
DecrementOutstandingIO();
return ret;
}
else
{
USBLog(3, "IOUSBHIDDriver(%s)[%p]::setReport _interruptOutPipe->Write failed; err = 0x%x)", getName(), this, ret);
}
}
if ( _LOG_HID_REPORTS )
{
USBLog(_HID_LOGGING_LEVEL, "IOUSBHIDDriver[%p](Intfce: %d of device %s @ 0x%x)::SetReport sending out control pipe:", this, _INTERFACE_NUMBER, _device->getName(), (uint32_t)_locationID);
LogMemReport(_HID_LOGGING_LEVEL, report, report->getLength());
}
requestPB.bmRequestType = USBmakebmRequestType(kUSBOut, kUSBClass, kUSBInterface);
requestPB.bRequest = kHIDRqSetReport;
requestPB.wValue = (usbReportType << 8) | reportID;
requestPB.wIndex = _interface->GetInterfaceNumber();
requestPB.wLength = report->getLength();
requestPB.pData = report;
requestPB.wLenDone = 0;
ret = _device->DeviceRequest(&requestPB);
if (ret != kIOReturnSuccess)
{
USBLog(3, "IOUSBHIDDriver(%s)[%p]::setReport request failed; err = 0x%x)", getName(), this, ret);
}
DecrementOutstandingIO();
USBLog(_HID_LOGGING_LEVEL, "IOUSBHIDDriver[%p](Intfce: %d of device %s @ 0x%x)::setReport returning 0x%x", this, _INTERFACE_NUMBER, _device->getName(), (uint32_t)_locationID, (uint32_t)ret);
return ret;
}
OSNumber *
IOUSBHIDDriver::newLocationIDNumber() const
{
OSNumber * newLocationID = NULL;
OSNumber * locationID = NULL;
OSObject * propertyObj = NULL;
if (_interface != NULL)
{
propertyObj = _interface->copyProperty(kUSBDevicePropertyLocationID);
locationID = OSDynamicCast( OSNumber, propertyObj);
if ( locationID )
{
newLocationID = OSNumber::withNumber(locationID->unsigned32BitValue(), 32);
}
if (propertyObj)
propertyObj->release();
}
return newLocationID;
}
OSString *
IOUSBHIDDriver::newManufacturerString() const
{
char manufacturerString[256];
UInt32 strSize;
UInt8 index;
IOReturn err;
manufacturerString[0] = 0;
index = _device->GetManufacturerStringIndex();
strSize = sizeof(manufacturerString);
err = GetIndexedString(index, (UInt8 *)manufacturerString, &strSize);
if ( err == kIOReturnSuccess )
return OSString::withCString(manufacturerString);
else
return NULL;
}
OSNumber *
IOUSBHIDDriver::newProductIDNumber() const
{
UInt16 productID = 0;
if (_device != NULL)
productID = _device->GetProductID();
return OSNumber::withNumber(productID, 16);
}
OSString *
IOUSBHIDDriver::newProductString() const
{
char productString[256];
UInt32 strSize;
UInt8 index;
IOReturn err;
productString[0] = 0;
index = _device->GetProductStringIndex();
strSize = sizeof(productString);
err = GetIndexedString(index, (UInt8 *)productString, &strSize);
if ( err == kIOReturnSuccess )
return OSString::withCString(productString);
else
return NULL;
}
IOReturn
IOUSBHIDDriver::newReportDescriptor(IOMemoryDescriptor ** desc) const
{
IOBufferMemoryDescriptor * bufferDesc = NULL;
IOReturn ret = kIOReturnNoMemory;
IOUSBHIDDriver * me = (IOUSBHIDDriver *) this;
UInt32 inOutSize = 0;
ret = me->GetHIDDescriptor(kUSBReportDesc, 0, NULL, &inOutSize);
if ( ret == kIOReturnSuccess && inOutSize != 0)
{
bufferDesc = IOBufferMemoryDescriptor::withCapacity(inOutSize, kIODirectionOutIn);
}
if (bufferDesc)
{
ret = me->GetHIDDescriptor(kUSBReportDesc, 0, (UInt8 *)bufferDesc->getBytesNoCopy(), &inOutSize);
if ( ret != kIOReturnSuccess )
{
bufferDesc->release();
bufferDesc = NULL;
}
}
*desc = bufferDesc;
return ret;
}
OSString *
IOUSBHIDDriver::newSerialNumberString() const
{
char serialNumberString[256];
UInt32 strSize;
UInt8 index;
IOReturn err;
serialNumberString[0] = 0;
index = _device->GetSerialNumberStringIndex();
strSize = sizeof(serialNumberString);
err = GetIndexedString(index, (UInt8 *)serialNumberString, &strSize);
if ( err == kIOReturnSuccess )
return OSString::withCString(serialNumberString);
else
return NULL;
}
OSString *
IOUSBHIDDriver::newTransportString() const
{
return OSString::withCString("USB");
}
OSNumber *
IOUSBHIDDriver::newVendorIDNumber() const
{
UInt16 vendorID = 0;
if (_device != NULL)
vendorID = _device->GetVendorID();
return OSNumber::withNumber(vendorID, 16);
}
OSNumber *
IOUSBHIDDriver::newVersionNumber() const
{
UInt16 releaseNum = 0;
if (_device != NULL)
releaseNum = _device->GetDeviceRelease();
return OSNumber::withNumber(releaseNum, 16);
}
OSNumber *
IOUSBHIDDriver::newCountryCodeNumber() const
{
IOUSBHIDDescriptor *theHIDDesc;
if (!_interface)
{
USBLog(2, "IOUSBHIDDriver(%s)[%p]::newCountryCodeNumber - no _interface", getName(), this);
return NULL;
}
theHIDDesc = (IOUSBHIDDescriptor *)_interface->FindNextAssociatedDescriptor(NULL, kUSBHIDDesc);
if (theHIDDesc == NULL)
{
USBLog(2, "IOUSBHIDDriver(%s)[%p]::newCountryCodeNumber - FindNextAssociatedDescriptor(NULL, kUSBHIDDesc) failed", getName(), this);
return NULL;
}
return OSNumber::withNumber((unsigned long long)theHIDDesc->hidCountryCode, 8);
}
#pragma mark ееееееее Static Methods еееееееее
void
IOUSBHIDDriver::InterruptReadHandlerEntry(OSObject *target, void *param, IOReturn status, UInt32 bufferSizeRemaining)
{
IOUSBHIDDriver * me = OSDynamicCast(IOUSBHIDDriver, target);
uint64_t timeStamp;
if (!me)
return;
timeStamp = mach_absolute_time();
me->InterruptReadHandler(status, bufferSizeRemaining, *(AbsoluteTime *)&timeStamp);
me->DecrementOutstandingIO();
}
void
IOUSBHIDDriver::InterruptReadHandlerWithTimeStampEntry(OSObject *target, void *param, IOReturn status, UInt32 bufferSizeRemaining, AbsoluteTime timeStamp)
{
IOUSBHIDDriver * me = OSDynamicCast(IOUSBHIDDriver, target);
if (!me)
return;
me->InterruptReadHandler(status, bufferSizeRemaining, timeStamp);
me->DecrementOutstandingIO();
}
void
IOUSBHIDDriver::InterruptReadHandler(IOReturn status, UInt32 bufferSizeRemaining, AbsoluteTime timeStamp)
{
bool queueAnother = false; IOReturn err = kIOReturnSuccess;
_PENDINGREAD = false;
_INTERRUPT_TIMESTAMP = timeStamp;
USBLog(7, "IOUSBHIDDriver(%s)[%p]::InterruptReadHandler bufferSizeRemaining: %d, error 0x%x", getName(), this, (uint32_t)bufferSizeRemaining, status);
if ( status == kIOReturnSuccess )
{
vm_size_t capacity = (_buffer ? _buffer->getCapacity() : 0);
USBTrace( kUSBTHID, kTPHIDInterruptRead, (uintptr_t)this, capacity - bufferSizeRemaining, capacity, 0);
}
else
{
USBTrace( kUSBTHID, kTPHIDInterruptRead, (uintptr_t)this, (uintptr_t)status, _deviceHasBeenDisconnected, 1);
}
_NEED_TO_CLEARPIPESTALL = false;
switch (status)
{
case kIOReturnOverrun:
USBLog(3, "IOUSBHIDDriver(%s)[%p]::InterruptReadHandler kIOReturnOverrun error", getName(), this);
if (!isInactive() && _interruptPipe)
{
_interruptPipe->ClearStall();
_NEED_TO_CLEARPIPESTALL = true;
}
case kIOReturnSuccess:
_retryCount = kHIDDriverRetryCount;
_deviceHasBeenDisconnected = FALSE;
if ( bufferSizeRemaining != 0 )
{
_buffer->setLength(_buffer->getCapacity()-bufferSizeRemaining);
}
if ( _QUEUED_REPORTS < kMaxQueuedReports)
{
if ( bufferSizeRemaining != _buffer->getCapacity() )
{
IncrementOutstandingIO();
_QUEUED_REPORTS++; if ( thread_call_enter1(_HANDLE_REPORT_THREAD, (thread_call_param_t) &_INTERRUPT_TIMESTAMP) == TRUE)
{
USBLog(3, "IOUSBHIDDriver(%s)[%p]::InterruptReadHandler _HANDLE_REPORT_THREAD was already queued!", getName(), this);
USBTrace( kUSBTHID, kTPHIDInterruptRead, (uintptr_t)this, 0, 0, 3);
DecrementOutstandingIO();
_QUEUED_REPORTS--;
}
}
else
{
queueAnother = true;
USBTrace( kUSBTHID, kTPHIDInterruptRead, (uintptr_t)this, 0, 0, 4);
}
}
else
{
USBLog(2, "IOUSBHIDDriver(%s)[%p]::InterruptReadHandler Not calling handleReport thread because we already have a report queued", getName(), this);
USBTrace( kUSBTHID, kTPHIDInterruptRead, (uintptr_t)this, 0, 0, 5);
}
break;
case kIOReturnNotResponding:
case kIOUSBHighSpeedSplitError:
USBLog(3, "IOUSBHIDDriver(%s)[%p]::InterruptReadHandler 0x%x (%s)", getName(), this, status, USBStringFromReturn(status));
if ( IsPortSuspended() && _interruptPipe)
{
USBLog(4, "IOUSBHIDDriver(%s)[%p]::InterruptReadHandler kIOReturnNotResponding error but port is suspended", getName(), this);
USBTrace( kUSBTHID, kTPHIDInterruptRead, (uintptr_t)this, 0, 0, 6);
_interruptPipe->ClearStall();
}
else
{
if ( !_deviceHasBeenDisconnected && !isInactive() && _interruptPipe)
{
USBLog(3, "IOUSBHIDDriver(%s)[%p]::InterruptReadHandler Checking to see if HID device is still connected", getName(), this);
USBTrace( kUSBTHID, kTPHIDInterruptRead, (uintptr_t)this, 0, 0, 7);
IncrementOutstandingIO();
if ( thread_call_enter(_deviceDeadCheckThread) == TRUE )
{
USBLog(3, "IOUSBHIDDriver(%s)[%p]::InterruptReadHandler _deviceDeadCheckThread was already queued!", getName(), this);
DecrementOutstandingIO();
USBTrace( kUSBTHID, kTPHIDInterruptRead, (uintptr_t)this, 0, 0, 8);
}
_interruptPipe->ClearStall();
queueAnother = true; }
}
break;
case kIOReturnAborted:
if (!isInactive() && !ABORTEXPECTED && _interruptPipe)
{
USBLog(3, "IOUSBHIDDriver(%s)[%p]::InterruptReadHandler error kIOReturnAborted. Try again.", getName(), this);
USBTrace( kUSBTHID, kTPHIDInterruptRead, (uintptr_t)this, 0, 0, 9);
queueAnother = true;
}
else if ( ABORTEXPECTED )
{
USBLog(5, "IOUSBHIDDriver(%s)[%p]::InterruptReadHandler error kIOReturnAborted. Expected. Not rearming interrupt", getName(), this);
USBTrace( kUSBTHID, kTPHIDInterruptRead, (uintptr_t)this, 0, 0, 10);
}
USBTrace( kUSBTHID, kTPHIDInterruptReadError, (uintptr_t)this, ABORTEXPECTED, queueAnother, status);
break;
case kIOReturnUnderrun:
case kIOUSBPipeStalled:
case kIOUSBLinkErr:
case kIOUSBNotSent2Err:
case kIOUSBNotSent1Err:
case kIOUSBBufferUnderrunErr:
case kIOUSBBufferOverrunErr:
case kIOUSBWrongPIDErr:
case kIOUSBPIDCheckErr:
case kIOUSBDataToggleErr:
case kIOUSBBitstufErr:
case kIOUSBCRCErr:
USBLog(3, "IOUSBHIDDriver(%s)[%p]::InterruptReadHandler error (0x%x) reading interrupt pipe", getName(), this, status);
if (!isInactive() && _interruptPipe)
{
USBTrace( kUSBTHID, kTPHIDInterruptRead, (uintptr_t)this, 0, 0, 11);
_interruptPipe->ClearStall();
IncrementOutstandingIO();
if ( thread_call_enter(_clearFeatureEndpointHaltThread) == TRUE ) {
USBLog(3, "IOUSBHIDDriver(%s)[%p]::InterruptReadHandler _clearFeatureEndpointHaltThread was already queued!", getName(), this);
DecrementOutstandingIO();
USBTrace( kUSBTHID, kTPHIDInterruptRead, (uintptr_t)this, 0, 0, 12);
}
}
break;
default:
USBLog(3, "IOUSBHIDDriver(%s)[%p]::InterruptReadHandler Unknown error (0x%x) reading interrupt pipe", getName(), this, status);
USBTrace( kUSBTHID, kTPHIDInterruptRead, (uintptr_t)this, status, 0, 12);
if ( !isInactive() && _interruptPipe )
_interruptPipe->ClearStall();
queueAnother = true;
break;
}
if ( queueAnother )
{
USBLog(7, "IOUSBHIDDriver(%s)[%p]::InterruptReadHandler - queueing another", getName(), this);
(void) RearmInterruptRead();
}
}
void
IOUSBHIDDriver::CheckForDeadDeviceEntry(OSObject *target)
{
IOUSBHIDDriver * me = OSDynamicCast(IOUSBHIDDriver, target);
if (!me)
return;
me->CheckForDeadDevice();
me->DecrementOutstandingIO();
}
void
IOUSBHIDDriver::CheckForDeadDevice()
{
IOReturn err = kIOReturnSuccess;
bool gotLock;
if (isInactive())
{
USBLog(4, "IOUSBHIDDriver(%s)[%p]::CheckForDeadDevice - called while inActive - ignoring", getName(), this);
USBTrace( kUSBTHID, kTPHIDCheckForDeadDevice, (uintptr_t)this, 0, 0, 12);
return;
}
gotLock = OSCompareAndSwap(0, 1, &_DEAD_DEVICE_CHECK_LOCK);
if ( !gotLock )
{
USBLog(5, "IOUSBHIDDriver(%s)[%p]::CheckForDeadDevice already active, returning", getName(), this );
USBTrace( kUSBTHID, kTPHIDCheckForDeadDevice, (uintptr_t)this, _retryCount, _deviceHasBeenDisconnected, 1);
return;
}
USBTrace( kUSBTHID, kTPHIDCheckForDeadDevice, (uintptr_t)this, _retryCount, _deviceHasBeenDisconnected, 2);
if ( _interface && _device )
{
UInt32 info = 0;
_device->retain();
err = _device->GetDeviceInformation(&info);
_device->release();
USBLog(6, "IOUSBHIDDriver(%s)[%p]::CheckForDeadDevice GetDeviceInformation returned error 0x%x, info: 0x%x, retryCount: %d", getName(), this, err, (uint32_t)info, (uint32_t)_retryCount);
if ( err != kIOReturnSuccess )
{
USBTrace( kUSBTHID, kTPHIDCheckForDeadDevice, (uintptr_t)this, err, _retryCount, 3);
if (_retryCount != 0)
_retryCount--;
if (_retryCount == 0 )
{
_deviceHasBeenDisconnected = TRUE;
USBLog(5, "IOUSBHIDDriver(%s)[%p]: CheckForDeadDevice: GetDeviceInformation and our retryCount is 0, so assume device has been unplugged", getName(), this);
USBTrace( kUSBTHID, kTPHIDCheckForDeadDevice, (uintptr_t)this, 0, 0, 4);
}
else
{
USBLog(5, "IOUSBHIDDriver(%s)[%p]: CheckForDeadDevice: GetDeviceInformation returned an error, but our retryCount is not 0", getName(), this);
USBTrace( kUSBTHID, kTPHIDCheckForDeadDevice, (uintptr_t)this, _retryCount, 0, 13);
}
}
else
{
USBTrace( kUSBTHID, kTPHIDCheckForDeadDevice, (uintptr_t)this, info, _retryCount, 5);
if ((info & kUSBInformationDeviceIsConnectedMask) && (info & kUSBInformationDeviceIsEnabledMask))
{
USBTrace( kUSBTHID, kTPHIDCheckForDeadDevice, (uintptr_t)this, _retryCount, 0, 6);
if (_retryCount != 0)
_retryCount--;
if (_retryCount == 0 )
{
ABORTEXPECTED = TRUE;
USBLog(1, "IOUSBHIDDriver(%s)[%p]: Detected an kIONotResponding error but still connected. Resetting port", getName(), this);
if (_interruptPipe)
{
_interruptPipe->Abort();
}
USBTrace( kUSBTHID, kTPHIDCheckForDeadDevice, (uintptr_t)this, 0, 0, 7);
_device->ResetDevice();
}
else
{
USBLog(5, "IOUSBHIDDriver(%s)[%p]: Still connected but retry count (%d) not reached", getName(), this, (uint32_t)_retryCount);
USBTrace( kUSBTHID, kTPHIDCheckForDeadDevice, (uintptr_t)this, _retryCount, 0, 11);
}
}
else
{
_deviceHasBeenDisconnected = TRUE;
USBLog(5, "IOUSBHIDDriver(%s)[%p]: CheckForDeadDevice: device %s has been unplugged", getName(), this, _device->getName());
USBTrace( kUSBTHID, kTPHIDCheckForDeadDevice, (uintptr_t)this, (uintptr_t)_device, 0, 8);
}
}
}
else
{
USBTrace( kUSBTHID, kTPHIDCheckForDeadDevice, (uintptr_t)this, 0, 0, 9);
}
_DEAD_DEVICE_CHECK_LOCK = 0;
}
void
IOUSBHIDDriver::ClearFeatureEndpointHaltEntry(OSObject *target)
{
IOUSBHIDDriver * me = OSDynamicCast(IOUSBHIDDriver, target);
if (!me)
return;
me->ClearFeatureEndpointHalt();
me->DecrementOutstandingIO();
}
void
IOUSBHIDDriver::ClearFeatureEndpointHalt( )
{
IOReturn status;
IOUSBDevRequest request;
UInt32 retries = 2;
if (!_interruptPipe)
{
USBLog(1, "IOUSBHIDDriver(%s)[%p]::ClearFeatureEndpointHalt - no interrupt pipe - bailing", getName(), this);
USBTrace( kUSBTHID, kTPHIDClearFeatureEndpointHalt, (uintptr_t)this, 0, 0, 0);
return;
}
bzero( &request, sizeof(IOUSBDevRequest));
while ( (retries > 0) && (_interruptPipe) )
{
retries--;
request.bmRequestType = USBmakebmRequestType(kUSBNone, kUSBStandard, kUSBEndpoint);
request.bRequest = kUSBRqClearFeature;
request.wValue = 0; request.wIndex = _interruptPipe->GetEndpointNumber() | 0x80 ; request.wLength = 0;
request.pData = NULL;
status = _device->DeviceRequest(&request, 5000, 0);
if ( status != kIOReturnSuccess )
{
USBLog(3, "IOUSBHIDDriver(%s)[%p]::ClearFeatureEndpointHalt - DeviceRequest returned: 0x%x, retries = %d", getName(), this, status, (uint32_t)retries);
IOSleep(100);
}
else
break;
}
USBLog(5, "IOUSBHIDDriver(%s)[%p]::ClearFeatureEndpointHalt - rearming interrupt read", getName(), this);
(void) RearmInterruptRead();
}
void
IOUSBHIDDriver::HandleReportEntry(OSObject *target, thread_call_param_t timeStamp)
{
IOUSBHIDDriver * me = OSDynamicCast(IOUSBHIDDriver, target);
if (!me)
return;
me->HandleReport( * (AbsoluteTime *)timeStamp );
me->DecrementOutstandingIO();
}
void
IOUSBHIDDriver::HandleReport(AbsoluteTime timeStamp)
{
IOReturn status;
IOUSBDevRequest request;
if ( _buffer->getLength() > 0 )
{
if ( _LOG_HID_REPORTS )
{
USBLog(_HID_LOGGING_LEVEL, "IOUSBHIDDriver(%s)[%p](Intfce: %d of device %s @ 0x%x) Interrupt IN report came in (%d of %d):", getName(), this, _INTERFACE_NUMBER, _device->getName(), (uint32_t)_locationID, (uint32_t)_buffer->getLength(), (uint32_t)_buffer->getCapacity() );
LogMemReport(_HID_LOGGING_LEVEL, _buffer, _buffer->getLength() );
}
status = handleReport(_buffer);
if ( status != kIOReturnSuccess)
{
UInt32 bytesToLog = _buffer->getLength() > 16 ? 16 : _buffer->getLength();
USBLog(1, "IOUSBHIDDriver(%s)[%p]::HandleReport handleReportWithTime() returned 0x%x (%s), report data (%d of %d bytes):", getName(), this, status, USBStringFromReturn(status), (uint32_t)bytesToLog, (uint32_t)_buffer->getLength());
LogMemReport(1, _buffer, bytesToLog );
USBTrace( kUSBTHID, kTPHIDHandleReport, (uintptr_t)this, status, 0, 0);
}
}
_QUEUED_REPORTS--;
if ( _SUSPENDPORT_TIMER )
{
USBLog(5, "IOUSBHIDDriver(%s)[%p]::HandleReport cancelling the timeout", getName(), this);
_SUSPENDPORT_TIMER->cancelTimeout();
_SUSPENDPORT_TIMER->setTimeoutMS(_SUSPEND_TIMEOUT_IN_MS);
}
if ( !isInactive() )
{
if ( _NEED_TO_CLEARPIPESTALL )
{
IncrementOutstandingIO();
if ( thread_call_enter(_clearFeatureEndpointHaltThread) == TRUE ) {
USBLog(3, "IOUSBHIDDriver(%s)[%p]::HandleReport _clearFeatureEndpointHaltThread was already queued!", getName(), this);
DecrementOutstandingIO();
}
}
else
{
USBLog(7, "IOUSBHIDDriver(%s)[%p]::HandleReport calling RearmInterruptRead()", getName(), this);
(void) RearmInterruptRead();
}
}
}
void
IOUSBHIDDriver::SuspendPortTimer(OSObject *target, IOTimerEventSource *source)
{
IOUSBHIDDriver * me = OSDynamicCast(IOUSBHIDDriver, target);
IOReturn status;
if (!me || !source || me->isInactive())
{
return;
}
USBLog(5, "IOUSBHIDDriver(%s)[%p]::SuspendPortTimer calling AbortAndSuspend()", me->getName(), me);
(void) me->AbortAndSuspend( true );
}
#pragma mark ееееееее HID Driver Methods еееееееее
UInt32
IOUSBHIDDriver::getMaxReportSize()
{
UInt32 maxInputReportSize = 0;
UInt32 maxFeatureReportSize = 0;
OSNumber * inputReportSize = NULL;
OSNumber * featureReportSize = NULL;
OSObject * propertyObj = NULL;
propertyObj = copyProperty(kIOHIDMaxInputReportSizeKey);
inputReportSize = OSDynamicCast( OSNumber, propertyObj);
if ( inputReportSize )
maxInputReportSize = inputReportSize->unsigned32BitValue();
if (propertyObj)
{
propertyObj->release();
propertyObj = NULL;
}
propertyObj = copyProperty(kIOHIDMaxFeatureReportSizeKey);
featureReportSize = OSDynamicCast( OSNumber, propertyObj);
if ( featureReportSize )
maxFeatureReportSize = featureReportSize->unsigned32BitValue();
if (propertyObj)
propertyObj->release();
return ( (maxInputReportSize > maxFeatureReportSize) ? maxInputReportSize : maxFeatureReportSize);
}
IOReturn
IOUSBHIDDriver::GetHIDDescriptor(UInt8 inDescriptorType, UInt8 inDescriptorIndex, UInt8 *vOutBuf, UInt32 *vOutSize)
{
IOUSBDevRequest requestPB;
IOUSBHIDDescriptor *theHIDDesc;
IOUSBHIDReportDesc *hidTypeSizePtr; UInt8 *descPtr;
UInt32 providedBufferSize;
UInt16 descSize;
UInt8 descType;
UInt8 typeIndex;
UInt8 numberOwnedDesc;
IOReturn err = kIOReturnSuccess;
Boolean foundIt;
if (!vOutSize)
return kIOReturnBadArgument;
if (!_interface)
{
USBLog(2, "IOUSBHIDDriver(%s)[%p]::GetHIDDescriptor - no _interface", getName(), this);
return kIOReturnNotFound;
}
theHIDDesc = (IOUSBHIDDescriptor *)_interface->FindNextAssociatedDescriptor(NULL, kUSBHIDDesc);
if (theHIDDesc == NULL)
{
USBLog(2, "IOUSBHIDDriver(%s)[%p]::GetHIDDescriptor - FindNextAssociatedDescriptor(NULL, kUSBHIDDesc) failed", getName(), this);
return kIOReturnNotFound;
}
providedBufferSize = *vOutSize;
if (inDescriptorType == kUSBHIDDesc || (inDescriptorType == 0 && inDescriptorIndex == 0))
{
descSize = theHIDDesc->descLen;
descPtr = (UInt8 *)theHIDDesc;
*vOutSize = descSize;
if (providedBufferSize == 0)
err = kIOReturnSuccess;
else if (descSize > providedBufferSize)
err = kIOReturnNoSpace;
else if (vOutBuf == NULL)
err = kIOReturnBadArgument;
else
{
memcpy(vOutBuf, descPtr, descSize);
}
}
else
{ numberOwnedDesc = ((IOUSBHIDDescriptor *)theHIDDesc)->hidNumDescriptors;
hidTypeSizePtr = (IOUSBHIDReportDesc *)&((IOUSBHIDDescriptor *)theHIDDesc)->hidDescriptorType;
typeIndex = 0;
foundIt = false;
err = kIOReturnNotFound;
for (UInt8 i = 0; i < numberOwnedDesc; i++)
{
descType = hidTypeSizePtr->hidDescriptorType;
if (inDescriptorType != 0)
{
if (inDescriptorType == descType)
{
if (inDescriptorIndex == typeIndex)
{
foundIt = true;
}
else
{
typeIndex++;
}
}
}
else if (inDescriptorIndex == i + 1)
{
typeIndex = i;
foundIt = true;
}
if (foundIt)
{
err = kIOReturnSuccess; descSize = (hidTypeSizePtr->hidDescriptorLengthHi << 8) + hidTypeSizePtr->hidDescriptorLengthLo;
*vOutSize = descSize;
if (providedBufferSize == 0)
err = kIOReturnSuccess;
else if (descSize > providedBufferSize)
err = kIOReturnNoSpace;
else if (vOutBuf == NULL)
err = kIOReturnBadArgument;
else
{
if (!_device)
{
USBLog(2, "IOUSBHIDDriver(%s)[%p]::GetHIDDescriptor - no _device", getName(), this);
return kIOReturnNotFound;
}
requestPB.bmRequestType = USBmakebmRequestType(kUSBIn, kUSBStandard, kUSBInterface);
requestPB.bRequest = kUSBRqGetDescriptor;
requestPB.wValue = (inDescriptorType << 8) + typeIndex; requestPB.wIndex = _interface->GetInterfaceNumber();
requestPB.wLength = descSize;
requestPB.pData = vOutBuf; err = _device->DeviceRequest(&requestPB, 5000, 0);
if (err != kIOReturnSuccess)
{
USBLog(3, "IOUSBHIDDriver(%s)[%p]::GetHIDDescriptor Final request failed; err = 0x%x", getName(), this, err);
return err;
}
}
break; }
hidTypeSizePtr = (IOUSBHIDReportDesc *)(((UInt8 *)hidTypeSizePtr) + 3);
}
}
return err;
}
IOReturn
IOUSBHIDDriver::GetIndexedString(UInt8 index, UInt8 *vOutBuf, UInt32 *vOutSize, UInt16 lang) const
{
char strBuf[256];
UInt16 strLen = sizeof(strBuf) - 1; UInt32 outSize = *vOutSize;
IOReturn err;
if (index == 0)
{
return kIOReturnBadArgument;
}
if (lang == 0)
{
lang = 0x409; }
err = _device->GetStringDescriptor((UInt8)index, strBuf, strLen, (UInt16)lang);
if (err != kIOReturnSuccess)
{
return err;
}
strLen = (strBuf[0] == 0) ? 0 : strlen(strBuf) + 1;
if (outSize == 0)
{
*vOutSize = strLen;
return kIOReturnSuccess;
}
else if (outSize < strLen)
{
return kIOReturnMessageTooLarge;
}
strlcpy((char *)vOutBuf, strBuf, (size_t)strlen);
*vOutSize = strLen;
return kIOReturnSuccess;
}
OSString *
IOUSBHIDDriver::newIndexedString(UInt8 index) const
{
char string[256];
UInt32 strSize;
IOReturn err = kIOReturnSuccess;
string[0] = 0;
strSize = sizeof(string);
err = GetIndexedString(index, (UInt8 *)string, &strSize );
if ( err == kIOReturnSuccess )
return OSString::withCString(string);
else
return NULL;
}
IOReturn
IOUSBHIDDriver::StartFinalProcessing(void)
{
IOReturn err = kIOReturnSuccess;
_COMPLETION_WITH_TIMESTAMP.target = (void *)this;
_COMPLETION_WITH_TIMESTAMP.action = (IOUSBCompletionActionWithTimeStamp) &IOUSBHIDDriver::InterruptReadHandlerWithTimeStampEntry;
_COMPLETION_WITH_TIMESTAMP.parameter = (void *)0;
_completion.target = (void *)this;
_completion.action = (IOUSBCompletionAction) &IOUSBHIDDriver::InterruptReadHandlerEntry;
_completion.parameter = (void *)0;
return err;
}
IOReturn
IOUSBHIDDriver::SetIdleMillisecs(UInt16 msecs)
{
IOReturn err = kIOReturnSuccess;
IOUSBDevRequest request;
request.bmRequestType = USBmakebmRequestType(kUSBOut, kUSBClass, kUSBInterface);
request.bRequest = kHIDRqSetIdle; request.wValue = (msecs/4) << 8;
request.wIndex = _interface->GetInterfaceNumber();
request.wLength = 0;
request.pData = NULL;
err = _device->DeviceRequest(&request, 5000, 0);
if (err != kIOReturnSuccess)
{
USBLog(3, "IOUSBHIDDriver(%s)[%p]::SetIdleMillisecs returned error 0x%x",getName(), this, err);
}
return err;
}
IOReturn
IOUSBHIDDriver::SetProtocol(UInt32 protocol)
{
IOReturn err = kIOReturnSuccess;
IOUSBDevRequest request;
request.bmRequestType = USBmakebmRequestType(kUSBOut, kUSBClass, kUSBInterface);
request.bRequest = kHIDRqSetProtocol; request.wValue = protocol;
request.wIndex = _interface->GetInterfaceNumber();
request.wLength = 0;
request.pData = NULL;
err = _device->DeviceRequest(&request, 5000, 0);
if (err != kIOReturnSuccess)
{
USBLog(3, "IOUSBHIDDriver(%s)[%p]::SetProtocol returned error 0x%x",getName(), this, err);
}
return err;
}
OSMetaClassDefineReservedUsed(IOUSBHIDDriver, 1);
IOReturn
IOUSBHIDDriver::SuspendPort(bool suspendPort, UInt32 timeoutInMS )
{
IOReturn status = kIOReturnSuccess;
if ( isInactive() )
return kIOReturnNotPermitted;
USBLog(5, "IOUSBHIDDriver(%s)[%p]::SuspendPort (%s), timeout: %d, _outstandingIO = %d", getName(), this, suspendPort ? "suspend": "resume", (uint32_t)timeoutInMS, (uint32_t)_outstandingIO );
if ( suspendPort )
{
do
{
if ( timeoutInMS != 0 )
{
if ( _SUSPENDPORT_TIMER )
{
if (_SUSPEND_TIMEOUT_IN_MS != timeoutInMS)
{
_SUSPEND_TIMEOUT_IN_MS = timeoutInMS;
_SUSPENDPORT_TIMER->cancelTimeout();
_SUSPENDPORT_TIMER->setTimeoutMS(_SUSPEND_TIMEOUT_IN_MS);
}
break;
}
if ( _WORKLOOP )
{
_SUSPENDPORT_TIMER = IOTimerEventSource::timerEventSource(this, SuspendPortTimer);
if (!_SUSPENDPORT_TIMER)
{
USBLog(1, "IOUSBHIDDriver(%s)[%p]::SuspendPort - could not create _SUSPENDPORT_TIMER", getName(), this);
USBTrace( kUSBTHID, kTPHIDSuspendPort, (uintptr_t)this, kIOReturnNoResources,0, 1 );
status = kIOReturnNoResources;
break;
}
status = _WORKLOOP->addEventSource(_SUSPENDPORT_TIMER);
if ( status != kIOReturnSuccess)
{
USBLog(1, "IOUSBHIDDriver(%s)[%p]::SuspendPort - addEventSource returned 0x%x", getName(), this, status);
USBTrace( kUSBTHID, kTPHIDSuspendPort, (uintptr_t)this, status, 0, 2 );
break;
}
_SUSPEND_TIMEOUT_IN_MS = timeoutInMS;
_SUSPENDPORT_TIMER->setTimeoutMS(_SUSPEND_TIMEOUT_IN_MS);
}
else
{
USBLog(1, "IOUSBHIDDriver(%s)[%p]::SuspendPort - no workloop!", getName(), this);
USBTrace( kUSBTHID, kTPHIDSuspendPort, (uintptr_t)this, kIOReturnNoResources, 0, 3 );
status = kIOReturnNoResources;
}
}
else
{
status = AbortAndSuspend( true );
}
} while (false);
}
if ( !suspendPort and (status == kIOReturnSuccess) )
{
if ( _SUSPENDPORT_TIMER )
{
_SUSPENDPORT_TIMER->cancelTimeout();
if ( _WORKLOOP )
_WORKLOOP->removeEventSource( _SUSPENDPORT_TIMER );
_SUSPENDPORT_TIMER->release();
_SUSPENDPORT_TIMER = NULL;
_SUSPEND_TIMEOUT_IN_MS = 0;
}
status = AbortAndSuspend( false );
}
USBLog(5, "IOUSBHIDDriver(%s)[%p]::SuspendPort returning 0x%x", getName(), this, status );
return status;
}
IOReturn
IOUSBHIDDriver::AbortAndSuspend(bool suspendPort )
{
IOReturn status = kIOReturnSuccess;
if ( suspendPort )
{
if ( _outstandingIO )
{
ABORTEXPECTED = true;
if ( _interruptPipe )
{
status = _interruptPipe->Abort();
if ( status != kIOReturnSuccess)
{
USBLog(4, "IOUSBHIDDriver(%s)[%p]::AbortAndSuspend _interruptPipe->ClearPipeStall returned 0x%x", getName(), this, status );
}
}
}
else
{
USBLog(4, "IOUSBHIDDriver(%s)[%p]::AbortAndSuspend suspending device, but no outstandingIO", getName(), this );
}
status = _interface->GetDevice()->SuspendDevice(true);
if ( status == kIOReturnSuccess )
_PORT_SUSPENDED = true;
else
{
USBLog(4, "IOUSBHIDDriver(%s)[%p]::AbortAndSuspend SuspendDevice returned 0x%x", getName(), this, status );
}
}
else
{
ABORTEXPECTED = false;
USBLog(2, "IOUSBHIDDriver(%s)[%p]::AbortAndSuspend - calling SuspendDevice(false)", getName(), this );
status = _interface->GetDevice()->SuspendDevice(false);
if ( status != kIOReturnSuccess )
{
USBLog(1, "IOUSBHIDDriver(%s)[%p]::AbortAndSuspend resuming the device returned 0x%x", getName(), this, status);
USBTrace( kUSBTHID, kTPHIDAbortAndSuspend, (uintptr_t)this, status, 0, 0);
}
status = RearmInterruptRead();
}
return status;
}
OSMetaClassDefineReservedUsed(IOUSBHIDDriver, 2);
bool
IOUSBHIDDriver::IsPortSuspended()
{
return _PORT_SUSPENDED;
}
#pragma mark ееееееее Bookkeeping Methods еееееееее
IOReturn
IOUSBHIDDriver::ClaimPendingRead(OSObject *target, void *param1, void *param2, void *param3, void *param4)
{
IOUSBHIDDriver *me = OSDynamicCast(IOUSBHIDDriver, target);
bool *retVal = (bool*)param1;
bool myPend;
if (!me)
{
USBLog(1, "IOUSBHIDDriver::ClaimPendingRead - invalid target");
USBTrace( kUSBTHID, kTPHIDClaimPendingRead, (uintptr_t)param2, (uintptr_t)param3, (uintptr_t)param4, 1 );
return kIOReturnSuccess;
}
if (me->_PENDINGREAD)
{
myPend = false;
}
else
{
myPend = true;
me->_PENDINGREAD = true;
}
if (!retVal)
{
USBLog(1, "IOUSBHIDDriver::ClaimPendingRead - NULL retVal!!");
USBTrace( kUSBTHID, kTPHIDClaimPendingRead, (uintptr_t)param2, (uintptr_t)param3, (uintptr_t)param4, 2 );
}
else
{
*retVal = myPend;
}
return kIOReturnSuccess;
}
IOReturn
IOUSBHIDDriver::ChangeOutstandingIO(OSObject *target, void *param1, void *param2, void *param3, void *param4)
{
IOUSBHIDDriver *me = OSDynamicCast(IOUSBHIDDriver, target);
UInt32 direction = (uintptr_t)param1;
if (!me)
{
USBLog(1, "IOUSBHIDDriver::ChangeOutstandingIO - invalid target");
USBTrace( kUSBTHID, kTPHIDChangeOutstandingIO, (uintptr_t)me, kIOReturnSuccess, direction, 1 );
return kIOReturnSuccess;
}
switch (direction)
{
case 1:
me->_outstandingIO++;
break;
case -1:
if (!--me->_outstandingIO && me->_needToClose)
{
USBLog(3, "IOUSBHIDDriver(%s)[%p]::ChangeOutstandingIO isInactive = %d, outstandingIO = %d - closing device", me->getName(), me, me->isInactive(), (uint32_t)me->_outstandingIO);
if (me->_interruptPipe)
{
me->_interruptPipe->release();
me->_interruptPipe = NULL;
}
me->_interface->close(me);
}
break;
default:
USBLog(1, "IOUSBHIDDriver(%s)[%p]::ChangeOutstandingIO - invalid direction", me->getName(), me);
USBTrace( kUSBTHID, kTPHIDChangeOutstandingIO, (uintptr_t)me, me->_outstandingIO, kIOReturnSuccess, direction );
}
return kIOReturnSuccess;
}
void
IOUSBHIDDriver::DecrementOutstandingIO(void)
{
if (!_gate)
{
if (!--_outstandingIO && _needToClose)
{
USBLog(3, "IOUSBHIDDriver(%s)[%p]::DecrementOutstandingIO isInactive = %d, outstandingIO = %d - closing device", getName(), this, isInactive(), (uint32_t)_outstandingIO);
if (_interruptPipe)
{
_interruptPipe->release();
_interruptPipe = NULL;
}
_interface->close(this);
}
return;
}
_gate->runAction(ChangeOutstandingIO, (void*)-1);
}
void
IOUSBHIDDriver::IncrementOutstandingIO(void)
{
if (!_gate)
{
_outstandingIO++;
return;
}
_gate->runAction(ChangeOutstandingIO, (void*)1);
}
#pragma mark ееееееее Debug Methods еееееееее
OSMetaClassDefineReservedUsed(IOUSBHIDDriver, 3);
void
IOUSBHIDDriver::LogMemReport(UInt8 level, IOMemoryDescriptor * reportBuffer, IOByteCount size)
{
IOByteCount reportSize;
IOByteCount tempSize, offset;
char outBuffer[1024];
char in[128];
char *out;
char inChar;
out = (char *)&outBuffer;
reportSize = size;
offset = 0;
while (reportSize)
{
if (reportSize > 128)
tempSize = 128;
else
tempSize = reportSize;
reportBuffer->readBytes(offset, in, tempSize );
for (unsigned int i = 0; i < tempSize; i++)
{
inChar = in[i];
*out++ = GetHexChar(inChar >> 4);
*out++ = GetHexChar(inChar & 0x0F);
*out++ = ' ';
}
*out = 0;
USBLog(level, "IOUSBHIDDriver(%s)[%p] %s", getName(), this, outBuffer);
out = (char *)&outBuffer;
offset += tempSize;
reportSize -= tempSize;
}
}
char
IOUSBHIDDriver::GetHexChar(char hexChar)
{
char hexChars[] = {'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'};
return hexChars[0x0F & hexChar];
}
#pragma mark ееееееее Obsolete Methods еееееееее
void
IOUSBHIDDriver::processPacket(void *data, UInt32 size)
{
return;
}
IOReturn
IOUSBHIDDriver::GetReport(UInt8 inReportType, UInt8 inReportID, UInt8 *vInBuf, UInt32 *vInSize)
{
return kIOReturnSuccess;
}
IOReturn
IOUSBHIDDriver::SetReport(UInt8 outReportType, UInt8 outReportID, UInt8 *vOutBuf, UInt32 vOutSize)
{
return kIOReturnSuccess;
}
#pragma mark ееееееее Padding Methods еееееееее
OSMetaClassDefineReservedUsed(IOUSBHIDDriver, 0);
IOReturn
IOUSBHIDDriver::RearmInterruptRead()
{
IOReturn err = kIOReturnUnsupported;
SInt32 retries = 0;
bool gotPend = false;
if ( (_buffer == NULL) || (_interruptPipe == NULL))
{
USBLog(1, "IOUSBHIDDriver(%s)[%p]::RearmInterruptRead - no _buffer or _interruptPipe", getName(), this);
USBTrace( kUSBTHID, kTPHIDRearmInterruptRead, (uintptr_t)this, 0, 0, 1 );
return err;
}
if ((_COMPLETION_WITH_TIMESTAMP.action == NULL) && (_completion.action == NULL))
{
USBLog(1, "IOUSBHIDDriver(%s)[%p]::RearmInterruptRead - no action method", getName(), this);
USBTrace( kUSBTHID, kTPHIDRearmInterruptRead, (uintptr_t)this, 0, 0, 2 );
return err;
}
if (isInactive())
{
USBLog(5, "IOUSBHIDDriver(%s)[%p]::RearmInterruptRead - isInactive() - returning kIOReturnNotResponding", getName(), this);
USBTrace( kUSBTHID, kTPHIDRearmInterruptRead, (uintptr_t)this, 0, 0, 6 );
return kIOReturnNotResponding;
}
if (!_gate || _gate->runAction(ClaimPendingRead, (void*)&gotPend))
{
USBLog(1, "IOUSBHIDDriver(%s)[%p]::RearmInterruptRead - unable to check for pending", getName(), this);
USBTrace( kUSBTHID, kTPHIDRearmInterruptRead, (uintptr_t)this, 0, 0, 3 );
return err;
}
if (!gotPend)
{
USBLog(2, "IOUSBHIDDriver(%s)[%p]::RearmInterruptRead - already had outstanding read pending - just ignoring", getName(), this);
return kIOReturnSuccess;
}
_buffer->setLength(_buffer->getCapacity());
USBLog(7, "IOUSBHIDDriver(%s)[%p]::RearmInterruptRead - _completion.action(%p)", getName(), this, _completion.action);
IncrementOutstandingIO();
while ( (err != kIOReturnSuccess) && (err != kIOReturnNoBandwidth) && ( retries++ < 30 ) && (_buffer != NULL) && (_interruptPipe != NULL))
{
if (isInactive())
{
USBLog(5, "IOUSBHIDDriver(%s)[%p]::RearmInterruptRead - isInactive() - returning kIOReturnNotResponding", getName(), this);
USBTrace( kUSBTHID, kTPHIDRearmInterruptRead, (uintptr_t)this, 0, 0, 6 );
err = kIOReturnNotResponding;
break;
}
if (_COMPLETION_WITH_TIMESTAMP.action)
{
err = _interruptPipe->Read(_buffer, 0, 0, _buffer->getLength(), &_COMPLETION_WITH_TIMESTAMP);
if ((err == kIOReturnNotResponding) && (_POWERSTATECHANGING || (_MYPOWERSTATE < kUSBHIDPowerStateOn)))
{
USBLog(3, "IOUSBHIDDriver(%s)[%p]::RearmInterruptRead - err(kIOReturnNotResponding) while _POWERSTATECHANGING(%s) or (_MYPOWERSTATE < kUSBHIDPowerStateOn)(%d) - no posting read", getName(), this, _POWERSTATECHANGING ? "true" : "false", (int)_MYPOWERSTATE);
USBTrace( kUSBTHID, kTPHIDRearmInterruptRead, (uintptr_t)this, _POWERSTATECHANGING, _MYPOWERSTATE, 7 );
break; }
}
else
{
err = kIOReturnUnsupported;
}
if ( (err == kIOReturnUnsupported) && (_interruptPipe != NULL) && (_buffer != NULL))
{
err = _interruptPipe->Read(_buffer, 0, 0, _buffer->getLength(), &_completion);
if ((err == kIOReturnNotResponding) && (_POWERSTATECHANGING || (_MYPOWERSTATE < kUSBHIDPowerStateOn)))
{
USBLog(3, "IOUSBHIDDriver(%s)[%p]::RearmInterruptRead - err(kIOReturnNotResponding) while _POWERSTATECHANGING(%s) or (_MYPOWERSTATE < kUSBHIDPowerStateOn)(%d) - no posting read", getName(), this, _POWERSTATECHANGING ? "true" : "false", (int)_MYPOWERSTATE);
USBTrace( kUSBTHID, kTPHIDRearmInterruptRead, (uintptr_t)this, _POWERSTATECHANGING, _MYPOWERSTATE, 8 );
break; }
}
if ( (err != kIOReturnSuccess) && (err != kIOReturnNoBandwidth) && (_interruptPipe != NULL))
{
USBLog(1, "IOUSBHIDDriver(%s)[%p]::RearmInterruptRead immediate error 0x%x queueing read, clearing stall and trying again(%d)", getName(), this, err, (uint32_t)retries);
USBTrace( kUSBTHID, kTPHIDRearmInterruptRead, (uintptr_t)this, err, (uint32_t)retries, 4 );
_interruptPipe->ClearPipeStall(false);
IOSleep(10);
}
}
if ( err )
{
if (isInactive())
{
USBLog(5, "IOUSBHIDDriver(%s)[%p]::RearmInterruptRead returning error 0x%x, not issuing any reads to device", getName(), this, err);
USBTrace( kUSBTHID, kTPHIDRearmInterruptRead, (uintptr_t)this, err, 0, 6 );
}
else
{
if ( err != kIOReturnNoBandwidth )
{
USBError(1, "IOUSBHIDDriver(%s)[%p]::RearmInterruptRead returning error 0x%x, not issuing any reads to device", getName(), this, err);
}
else
{
USBLog(3, "IOUSBHIDDriver(%s)[%p]::RearmInterruptRead returning error 0x%x, not issuing any reads to device", getName(), this, err);
}
}
_PENDINGREAD = false;
DecrementOutstandingIO();
}
USBTrace( kUSBTHID, kTPHIDRearmInterruptRead, (uintptr_t)this, err, 0, 5 );
return err;
}
OSMetaClassDefineReservedUsed(IOUSBHIDDriver, 4)
IOReturn
IOUSBHIDDriver::InitializeUSBHIDPowerManagement(IOService *provider)
{
IOReturn err = kIOReturnSuccess;
PMinit();
provider->joinPMtree(this);
makeUsable();
err = registerPowerDriver(this, ourPowerStates, kUSBHIDNumberPowerStates);
if (err)
{
USBLog(1, "IOUSBHIDDriver(%s)[%p]::InitializeUSBHIDPowerManagement - err [%p] from registerPowerDriver", getName(), this, (void*)err);
USBTrace( kUSBTHID, kTPHIDInitializeUSBHIDPowerManagement, (uintptr_t)this, err, 0, 0);
PMstop();
}
return err;
}
OSMetaClassDefineReservedUnused(IOUSBHIDDriver, 5);
OSMetaClassDefineReservedUnused(IOUSBHIDDriver, 6);
OSMetaClassDefineReservedUnused(IOUSBHIDDriver, 7);
OSMetaClassDefineReservedUnused(IOUSBHIDDriver, 8);
OSMetaClassDefineReservedUnused(IOUSBHIDDriver, 9);
OSMetaClassDefineReservedUnused(IOUSBHIDDriver, 10);
OSMetaClassDefineReservedUnused(IOUSBHIDDriver, 11);
OSMetaClassDefineReservedUnused(IOUSBHIDDriver, 12);
OSMetaClassDefineReservedUnused(IOUSBHIDDriver, 13);
OSMetaClassDefineReservedUnused(IOUSBHIDDriver, 14);
OSMetaClassDefineReservedUnused(IOUSBHIDDriver, 15);
OSMetaClassDefineReservedUnused(IOUSBHIDDriver, 16);
OSMetaClassDefineReservedUnused(IOUSBHIDDriver, 17);
OSMetaClassDefineReservedUnused(IOUSBHIDDriver, 18);
OSMetaClassDefineReservedUnused(IOUSBHIDDriver, 19);