AppleUSBCDCWCM.cpp [plain text]
#include <machine/limits.h>
#include <libkern/OSByteOrder.h>
#include <IOKit/assert.h>
#include <IOKit/IOLib.h>
#include <IOKit/IOService.h>
#include <IOKit/IOBufferMemoryDescriptor.h>
#include <IOKit/IOMessage.h>
#include <IOKit/pwr_mgt/RootDomain.h>
#include <IOKit/usb/IOUSBBus.h>
#include <IOKit/usb/IOUSBNub.h>
#include <IOKit/usb/IOUSBDevice.h>
#include <IOKit/usb/IOUSBLog.h>
#include <IOKit/usb/IOUSBPipe.h>
#include <IOKit/usb/USB.h>
#include <IOKit/usb/IOUSBInterface.h>
#include <IOKit/serial/IOSerialKeys.h>
#include <IOKit/serial/IOSerialDriverSync.h>
#include <IOKit/serial/IOModemSerialStreamSync.h>
#include <IOKit/serial/IORS232SerialStreamSync.h>
#include <UserNotification/KUNCUserNotifications.h>
#define DEBUG_NAME "AppleUSBCDCWCM"
#include "AppleUSBCDCWCM.h"
static IOPMPowerState gOurPowerStates[kNumCDCStates] =
{
{1,0,0,0,0,0,0,0,0,0,0,0},
{1,IOPMDeviceUsable,IOPMPowerOn,IOPMPowerOn,0,0,0,0,0,0,0,0}
};
#define super IOService
OSDefineMetaClassAndStructors(AppleUSBCDCWCM, IOService);
IOService* AppleUSBCDCWCM::probe( IOService *provider, SInt32 *score )
{
IOService *res;
OSBoolean *boolObj = OSDynamicCast(OSBoolean, provider->getProperty("kDoNotClassMatchThisInterface"));
if (boolObj && boolObj->isTrue())
{
XTRACE(this, 0, 0, "probe - provider doesn't want us to match");
return NULL;
}
res = super::probe(provider, score);
return res;
}
bool AppleUSBCDCWCM::start(IOService *provider)
{
fTerminate = false;
fStopping = false;
fControlLen = 0;
fControlMap = NULL;
XTRACE(this, 0, provider, "start - provider.");
if(!super::start(provider))
{
ALERT(0, 0, "start - super failed");
return false;
}
fInterface = OSDynamicCast(IOUSBInterface, provider);
if(!fInterface)
{
ALERT(0, 0, "start - provider invalid");
return false;
}
if (!configureDevice())
{
ALERT(0, 0, "start - configureDevice failed");
return false;
}
if (!allocateResources())
{
ALERT(0, 0, "start - allocateResources failed");
return false;
}
if (!initForPM(provider))
{
ALERT(0, 0, "start - initForPM failed");
return false;
}
fInterface->retain();
registerService();
XTRACE(this, 0, 0, "start - successful");
Log(DEBUG_NAME ": Version number - %s\n", VersionNumber);
return true;
}
void AppleUSBCDCWCM::stop(IOService *provider)
{
XTRACE(this, 0, 0, "stop");
fStopping = true;
releaseResources();
PMstop();
if (fControlMap)
{
IOFree(fControlMap, fControlLen);
fControlMap = NULL;
fControlLen = 0;
}
super::stop(provider);
}
bool AppleUSBCDCWCM::configureWHCM()
{
XTRACE(this, 0, 0, "configureWHCM");
fInterfaceNumber = fInterface->GetInterfaceNumber();
XTRACE(this, 0, fInterfaceNumber, "configureWHCM - Comm interface number.");
if (!getFunctionalDescriptors())
{
XTRACE(this, 0, 0, "configureWHCM - getFunctionalDescriptors failed");
return false;
}
return true;
}
bool AppleUSBCDCWCM::configureDevice()
{
bool configOK = false;
XTRACE(this, 0, 0, "configureDevice");
fInterfaceNumber = fInterface->GetInterfaceNumber();
fSubClass = fInterface->GetInterfaceSubClass();
XTRACE(this, fSubClass, fInterfaceNumber, "configureDevice - Subclass and interface number.");
switch (fSubClass)
{
case kUSBWirelessHandsetControlModel:
if (configureWHCM())
{
configOK = true;
}
break;
default:
XTRACE(this, 0, fSubClass, "configureDevice - Unsupported subclass");
break;
}
if (!configOK)
{
XTRACE(this, 0, 0, "configureDevice - configuration failed");
return false;
}
return true;
}
bool AppleUSBCDCWCM::getFunctionalDescriptors()
{
bool gotDescriptors = false;
UInt16 vers;
UInt16 *chkVers;
const FunctionalDescriptorHeader *funcDesc = NULL;
HDRFunctionalDescriptor *HDRFDesc; WHCMFunctionalDescriptor *WCMFDesc; UnionFunctionalDescriptor *UNNFDesc;
XTRACE(this, 0, 0, "getFunctionalDescriptors");
do
{
funcDesc = (const FunctionalDescriptorHeader *)fInterface->FindNextAssociatedDescriptor((void*)funcDesc, CS_INTERFACE);
if (!funcDesc)
{
gotDescriptors = true; } else {
switch (funcDesc->bDescriptorSubtype)
{
case Header_FunctionalDescriptor:
HDRFDesc = (HDRFunctionalDescriptor *)funcDesc;
XTRACE(this, funcDesc->bDescriptorType, funcDesc->bDescriptorSubtype, "getFunctionalDescriptors - Header Functional Descriptor");
chkVers = (UInt16 *)&HDRFDesc->bcdCDC1;
vers = USBToHostWord(*chkVers);
if (vers > kUSBRel11)
{
XTRACE(this, vers, kUSBRel11, "getFunctionalDescriptors - Header descriptor version number is incorrect");
}
break;
case Union_FunctionalDescriptor:
UNNFDesc = (UnionFunctionalDescriptor *)funcDesc;
XTRACE(this, funcDesc->bDescriptorType, funcDesc->bDescriptorSubtype, "getFunctionalDescriptors - Union Functional Descriptor");
if (UNNFDesc->bFunctionLength > sizeof(FunctionalDescriptorHeader))
{
if (fInterfaceNumber != UNNFDesc->bMasterInterface)
{
XTRACE(this, fInterfaceNumber, UNNFDesc->bMasterInterface, "getFunctionalDescriptors - Master interface incorrect");
} else {
fControlLen = UNNFDesc->bFunctionLength - sizeof(FunctionalDescriptorHeader);
fControlLen -= sizeof(UNNFDesc->bMasterInterface); fControlMap = (UInt8 *)IOMalloc(fControlLen);
bcopy(&UNNFDesc->bSlaveInterface, fControlMap, fControlLen); XTRACE(this, fControlMap, fControlLen, "getFunctionalDescriptors - Map and length");
}
} else {
XTRACE(this, UNNFDesc->bFunctionLength, 0, "getFunctionalDescriptors - Union descriptor length error");
}
break;
case WCM_FunctionalDescriptor:
WCMFDesc = (WHCMFunctionalDescriptor *)funcDesc;
XTRACE(this, funcDesc->bDescriptorType, funcDesc->bDescriptorSubtype, "getFunctionalDescriptors - WHCM Functional Descriptor");
chkVers = (UInt16 *)&WCMFDesc->bcdCDC1;
vers = USBToHostWord(*chkVers);
if (vers > kUSBRel10)
{
XTRACE(this, vers, kUSBRel10, "getFunctionalDescriptors - WHCM descriptor version number is incorrect");
}
break;
default:
XTRACE(this, funcDesc->bDescriptorType, funcDesc->bDescriptorSubtype, "getFunctionalDescriptors - unknown Functional Descriptor");
break;
}
}
} while(!gotDescriptors);
return true;
}
bool AppleUSBCDCWCM::allocateResources()
{
XTRACE(this, 0, 0, "allocateResources.");
if (!fInterface->open(this))
{
XTRACE(this, 0, 0, "allocateResources - open comm interface failed.");
return false;
}
return true;
}
void AppleUSBCDCWCM::releaseResources()
{
XTRACE(this, 0, 0, "releaseResources");
if (fInterface)
{
fInterface->close(this);
fInterface->release();
fInterface = NULL;
}
}
void AppleUSBCDCWCM::resetLogicalHandset(void)
{
XTRACE(this, 0, 0, "resetLogicalHandset");
if ((fStopping) || (fInterface == NULL))
{
return;
}
}
IOReturn AppleUSBCDCWCM::message(UInt32 type, IOService *provider, void *argument)
{
XTRACE(this, 0, type, "message");
switch (type)
{
case kIOMessageServiceIsTerminated:
XTRACE(this, 0, type, "message - kIOMessageServiceIsTerminated");
fTerminate = true; releaseResources();
return kIOReturnSuccess;
case kIOMessageServiceIsSuspended:
XTRACE(this, 0, type, "message - kIOMessageServiceIsSuspended");
break;
case kIOMessageServiceIsResumed:
XTRACE(this, 0, type, "message - kIOMessageServiceIsResumed");
break;
case kIOMessageServiceIsRequestingClose:
XTRACE(this, 0, type, "message - kIOMessageServiceIsRequestingClose");
break;
case kIOMessageServiceWasClosed:
XTRACE(this, 0, type, "message - kIOMessageServiceWasClosed");
break;
case kIOMessageServiceBusyStateChange:
XTRACE(this, 0, type, "message - kIOMessageServiceBusyStateChange");
break;
case kIOUSBMessagePortHasBeenResumed:
XTRACE(this, 0, type, "message - kIOUSBMessagePortHasBeenResumed");
break;
case kIOUSBMessageHubResumePort:
XTRACE(this, 0, type, "message - kIOUSBMessageHubResumePort");
break;
default:
XTRACE(this, 0, type, "message - unknown message");
break;
}
return kIOReturnUnsupported;
}
bool AppleUSBCDCWCM::initForPM(IOService *provider)
{
XTRACE(this, 0, 0, "initForPM");
fPowerState = kCDCPowerOnState; PMinit(); provider->joinPMtree(this); if (pm_vars != NULL)
{
registerPowerDriver(this, gOurPowerStates, kNumCDCStates);
return true;
} else {
XTRACE(this, 0, 0, "initForPM - Initializing power manager failed");
}
return false;
}
unsigned long AppleUSBCDCWCM::initialPowerStateForDomainState(IOPMPowerFlags flags)
{
XTRACE(this, 0, flags, "initialPowerStateForDomainState");
return fPowerState;
}
IOReturn AppleUSBCDCWCM::setPowerState(unsigned long powerStateOrdinal, IOService *whatDevice)
{
XTRACE(this, 0, powerStateOrdinal, "setPowerState");
if (powerStateOrdinal == kCDCPowerOffState || powerStateOrdinal == kCDCPowerOnState)
{
if (powerStateOrdinal == fPowerState)
return IOPMAckImplied;
fPowerState = powerStateOrdinal;
if (fPowerState == kCDCPowerOnState)
{
resetLogicalHandset();
}
return IOPMAckImplied;
}
return IOPMAckImplied;
}