[plain text]
#include "AppleUSBAudioLevelControl.h"
#include "AppleUSBAudioDictionary.h"
#define super IOAudioLevelControl
OSDefineMetaClassAndStructors(AppleUSBAudioLevelControl, IOAudioLevelControl)
AppleUSBAudioLevelControl *AppleUSBAudioLevelControl::create (UInt8 theUnitID, UInt8 theInterfaceNumber, UInt8 theControlSelector, UInt8 theChannelNumber, Boolean shouldUpdatePRAM, USBDeviceRequest theUSBDeviceRequest, void *theCallerRefCon, UInt32 subType, UInt32 usage) {
AppleUSBAudioLevelControl * control;
debugIOLog ("+ AppleUSBAudioLevelControl::create (%d, %d, %d, %d, %p, %lX, %lX)", theUnitID, theInterfaceNumber, theControlSelector, theChannelNumber, theUSBDeviceRequest, subType, usage);
control = new AppleUSBAudioLevelControl;
FailIf (NULL == control, Exit);
if (FALSE == control->init (theUnitID, theInterfaceNumber, theControlSelector, theChannelNumber, shouldUpdatePRAM, theUSBDeviceRequest, theCallerRefCon, subType, usage)) {
control->release ();
control = NULL;
}
Exit:
debugIOLog ("- AppleUSBAudioLevelControl[%p]::create (%d, %d, %d, %d, %p, %lX, %lX)", control, theUnitID, theInterfaceNumber, theControlSelector, theChannelNumber, theUSBDeviceRequest, subType, usage);
return control;
}
bool AppleUSBAudioLevelControl::init (UInt8 theUnitID, UInt8 theInterfaceNumber, UInt8 theControlSelector, UInt8 theChannelNumber, Boolean shouldUpdatePRAM, USBDeviceRequest theUSBDeviceRequest, void *theCallerRefCon, UInt32 subType, UInt32 usage, OSDictionary *properties) {
const char * channelName = NULL;
SInt16 currentValue;
SInt16 deviceMin;
SInt16 deviceMax;
IOFixed deviceMinDB;
IOFixed deviceMaxDB;
IOFixed resolutionDB;
IOReturn ret;
Boolean result;
Boolean arePRAMControl;
debugIOLog ("+ AppleUSBAudioLevelControl[%p]::init (%d, %d, %d, %d, %p, %p)", this, theUnitID, theInterfaceNumber, theControlSelector, theChannelNumber, theUSBDeviceRequest, properties);
result = FALSE;
arePRAMControl = FALSE;
FailIf (NULL == theUSBDeviceRequest, Exit);
mSetValueThreadCall = thread_call_allocate ((thread_call_func_t)updateValueCallback, this);
FailIf (NULL == mSetValueThreadCall, Exit);
if (theControlSelector == 0xff)
{
theControlSelector = VOLUME_CONTROL;
arePRAMControl = TRUE;
}
if (kIOAudioLevelControlSubTypeLFEVolume == subType)
{
theChannelNumber = 1;
}
mUnitID = theUnitID;
mInterfaceNumber = theInterfaceNumber;
mControlSelector = theControlSelector;
mChannelNumber = theChannelNumber;
mCallerRefCon = theCallerRefCon;
mUSBDeviceRequest = theUSBDeviceRequest;
fShouldUpdatePRAM = shouldUpdatePRAM;
switch (mChannelNumber)
{
case kIOAudioControlChannelIDAll:
channelName = kIOAudioControlChannelNameAll;
break;
case kIOAudioControlChannelIDDefaultLeft:
channelName = kIOAudioControlChannelNameLeft;
break;
case kIOAudioControlChannelIDDefaultRight:
channelName = kIOAudioControlChannelNameRight;
break;
case 0xff:
debugIOLog ("! AppleUSBAudioLevelControl[%p]::init () - Does not support channel number 0xFF.", this);
return FALSE;
default:
channelName = "Unknown";
break;
}
ret = GetCurVolume (mInterfaceNumber, mChannelNumber, ¤tValue);
FailIf (kIOReturnSuccess != ret, Exit);
debugIOLog ("? AppleUSBAudioLevelControl[%p]::init () - mChannelNumber %d, currentValue = 0x%x", this, mChannelNumber, currentValue);
ret = GetVolumeResolution (mInterfaceNumber, mChannelNumber, &mVolRes);
FailIf (kIOReturnSuccess != ret, Exit);
debugIOLog ("? AppleUSBAudioLevelControl[%p]::init () - mVolRes = %d, ", this, mVolRes);
ret = GetMinVolume (mInterfaceNumber, mChannelNumber, &deviceMin);
FailIf (kIOReturnSuccess != ret, Exit);
debugIOLog ("? AppleUSBAudioLevelControl[%p]::init () - deviceMin = 0x%x, ", this, deviceMin);
ret = GetMaxVolume (mInterfaceNumber, mChannelNumber, &deviceMax);
FailIf (kIOReturnSuccess != ret, Exit);
debugIOLog ("? AppleUSBAudioLevelControl[%p]::init () - deviceMax = 0x%x", this, deviceMax);
if ((SInt16)0x8000 == deviceMin)
{
deviceMin = (SInt16)0x8001;
debugIOLog ("? AppleUSBAudioLevelControl[%p]::init () - deviceMin adjusted to = %d", this, deviceMin);
}
deviceMinDB = ConvertUSBVolumeTodB (deviceMin);
deviceMaxDB = ConvertUSBVolumeTodB (deviceMax);
resolutionDB = ConvertUSBVolumeTodB (mVolRes);
mOffset = -deviceMin;
debugIOLog ("? AppleUSBAudioLevelControl[%p]::init () - mOffset = %d", this, mOffset);
currentValue = (currentValue + mOffset) / mVolRes;
if (deviceMin < 0 && deviceMax > 0)
{
deviceMax += mVolRes;
debugIOLog ("? AppleUSBAudioLevelControl[%p]::init () - deviceMax adjusted to = 0x%x", this, deviceMax);
}
deviceMax = ((deviceMin + mOffset) + (deviceMax + mOffset)) / mVolRes;
if (kIOAudioLevelControlSubTypeLFEVolume == subType)
{
currentValue = currentValue / 2;
}
fMaxVolume = deviceMax;
fMinVolume = deviceMin + mOffset;
deviceMin = -1;
if (arePRAMControl)
{
UInt8 curPRAMVol;
#ifndef kNO_PRAM_SUPPORT
IODTPlatformExpert * platform = NULL;
#endif // kNO_PRAM_SUPPORT
curPRAMVol = 0;
#ifndef kNO_PRAM_SUPPORT
platform = OSDynamicCast (IODTPlatformExpert, getPlatform ());
if (NULL != platform)
{
platform->readXPRAM ((IOByteCount)kPRamVolumeAddr, &curPRAMVol, (IOByteCount)1);
curPRAMVol = (curPRAMVol & 0xF8);
}
#endif // kNO_PRAM_SUPPORT
currentValue = curPRAMVol;
deviceMin = 0;
deviceMax = 7;
subType = kIOAudioLevelControlSubTypePRAMVolume;
channelName = kIOAudioControlChannelNameAll;
theChannelNumber = 0; }
if (kIOAudioLevelControlSubTypeLFEVolume == subType)
{
theChannelNumber = 0;
channelName = kIOAudioControlChannelNameAll;
}
debugIOLog ("? AppleUSBAudioLevelControl[%p]::init () - min = %d, max = %d, current = %d", this, deviceMin, deviceMax, currentValue);
FailIf (FALSE == super::init (currentValue, deviceMin, deviceMax, deviceMinDB, deviceMaxDB, theChannelNumber, channelName, 0, subType, usage), Exit);
if (kIOAudioLevelControlSubTypeLFEVolume == subType)
{
updateUSBValue (currentValue);
}
result = TRUE;
Exit:
debugIOLog ("- AppleUSBAudioLevelControl[%p]::init (%d, %d, %d, %d, %p, %p)", this, theUnitID, theInterfaceNumber, theControlSelector, theChannelNumber, theUSBDeviceRequest, properties);
return result;
}
void AppleUSBAudioLevelControl::free () {
debugIOLog ("+ AppleUSBAudioLevelControl[%p]::free ()", this);
if (mSetValueThreadCall)
{
thread_call_free (mSetValueThreadCall);
mSetValueThreadCall = NULL;
}
super::free ();
debugIOLog ("- AppleUSBAudioLevelControl[%p]::free ()", this);
}
IOReturn AppleUSBAudioLevelControl::performValueChange (OSObject * newValue) {
OSNumber * newValueAsNumber;
SInt32 newValueAsSInt32;
debugIOLog ("+ AppleUSBAudioLevelControl[%p]::performValueChange (%p)", this, newValue);
newValueAsNumber = OSDynamicCast (OSNumber, newValue);
FailIf (NULL == newValueAsNumber, Exit);
newValueAsSInt32 = newValueAsNumber->unsigned32BitValue ();
debugIOLog ("? AppleUSBAudioLevelControl[%p]::performValueChange (%ld) [converted]", this, newValueAsSInt32);
if (NULL != mSetValueThreadCall)
{
thread_call_enter1 (mSetValueThreadCall, (thread_call_param_t)newValueAsSInt32);
}
debugIOLog ("- AppleUSBAudioLevelControl[%p]::performValueChange (%d)", this, newValueAsSInt32);
Exit:
return kIOReturnSuccess;
}
void AppleUSBAudioLevelControl::updateUSBValue () {
updateUSBValue (getIntValue ());
}
void AppleUSBAudioLevelControl::updateUSBValue (SInt32 newValue) {
SInt16 theValue;
SInt16 newVolume;
IOReturn ret;
debugIOLog ("+ AppleUSBAudioLevelControl[%p]::updateUSBValue (%d)", this, newValue);
if (newValue < 0)
{
newVolume = 0x8000;
}
else
{
if (newValue > 0)
{
newVolume = ((newValue - 1) * mVolRes) - mOffset;
}
else
{
newVolume = (newValue * mVolRes) - mOffset;
}
}
theValue = HostToUSBWord (newVolume);
debugIOLog ("? AppleUSBAudioLevelControl[%p]::updateUSBValue () - Volume value is 0x%x. Setting volume to 0x%x (little endian)", this, newVolume, theValue);
ret = SetCurVolume (mInterfaceNumber, mChannelNumber, theValue);
if (getSubType () == kIOAudioLevelControlSubTypeLFEVolume)
{
ret = SetCurVolume (mInterfaceNumber, 2, theValue);
}
#ifndef kNO_PRAM_SUPPORT
if (TRUE == fShouldUpdatePRAM && FALSE == gExpertMode)
{
WritePRAMVol (newValue, newValue);
}
#endif // kNO_PRAM_SUPPORT
if (ret != kIOReturnSuccess)
{
debugIOLog ("! AppleUSBAudioLevelContol::updateUSBValue () - Set current value for control selector %d, channel number %d failed with error 0x%x", mControlSelector, mChannelNumber, ret);
}
debugIOLog ("- AppleUSBAudioLevelControl[%p]::updateUSBValue (%d)", this, newValue);
}
IOReturn AppleUSBAudioLevelControl::GetCurVolume (UInt8 interfaceNumber, UInt8 channelNumber, SInt16 * target) {
IOUSBDevRequest devReq;
SInt16 theVolume;
IOReturn result;
result = kIOReturnError;
theVolume = 0;
FailIf ( NULL == target, Exit );
devReq.bmRequestType = USBmakebmRequestType (kUSBIn, kUSBClass, kUSBInterface);
devReq.bRequest = GET_CUR;
devReq.wValue = (mControlSelector << 8) | channelNumber;
devReq.wIndex = (mUnitID << 8) | interfaceNumber;
devReq.wLength = 2;
devReq.pData = &theVolume;
result = mUSBDeviceRequest (&devReq, mCallerRefCon, NULL);
FailIf (kIOReturnSuccess != result, Exit);
Exit:
if (NULL != target)
{
* target = USBToHostWord (theVolume);
}
return result;
}
IOReturn AppleUSBAudioLevelControl::GetMaxVolume (UInt8 interfaceNumber, UInt8 channelNumber, SInt16 * target) {
IOReturn result;
IOUSBDevRequest devReq;
SInt16 theVolume;
result = kIOReturnError;
theVolume = 0;
FailIf (NULL == target, Exit);
devReq.bmRequestType = USBmakebmRequestType (kUSBIn, kUSBClass, kUSBInterface);
devReq.bRequest = GET_MAX;
devReq.wValue = (mControlSelector << 8) | channelNumber;
devReq.wIndex = (mUnitID << 8) | interfaceNumber;
devReq.wLength = 2;
devReq.pData = &theVolume;
result = mUSBDeviceRequest (&devReq, mCallerRefCon, NULL);
FailIf (kIOReturnSuccess != result, Exit);
Exit:
if (NULL != target)
{
* target = USBToHostWord (theVolume);
}
return result;
}
IOReturn AppleUSBAudioLevelControl::GetMinVolume (UInt8 interfaceNumber, UInt8 channelNumber, SInt16 * target) {
IOReturn result;
IOUSBDevRequest devReq;
SInt16 theVolume;
result = kIOReturnError;
theVolume = 0;
FailIf (NULL == target, Exit);
devReq.bmRequestType = USBmakebmRequestType (kUSBIn, kUSBClass, kUSBInterface);
devReq.bRequest = GET_MIN;
devReq.wValue = (mControlSelector << 8) | channelNumber;
devReq.wIndex = (mUnitID << 8) | interfaceNumber;
devReq.wLength = 2;
devReq.pData = &theVolume;
result = mUSBDeviceRequest (&devReq, mCallerRefCon, NULL);
FailIf (kIOReturnSuccess != result, Exit);
Exit:
if (NULL != target)
{
* target = USBToHostWord (theVolume);
}
return result;
}
IOReturn AppleUSBAudioLevelControl::GetVolumeResolution (UInt8 interfaceNumber, UInt8 channelNumber, UInt16 * target) {
IOReturn result;
IOUSBDevRequest devReq;
UInt16 theResolution;
result = kIOReturnError;
theResolution = 0;
FailIf (NULL == target, Exit);
devReq.bmRequestType = USBmakebmRequestType (kUSBIn, kUSBClass, kUSBInterface);
devReq.bRequest = GET_RES;
devReq.wValue = (mControlSelector << 8) | channelNumber;
devReq.wIndex = (mUnitID << 8) | interfaceNumber;
devReq.wLength = 2;
devReq.pData = &theResolution;
result = mUSBDeviceRequest (&devReq, mCallerRefCon, NULL);
FailIf (kIOReturnSuccess != result, Exit);
Exit:
if (NULL != target)
{
* target = USBToHostWord (theResolution);
}
return result;
}
IOReturn AppleUSBAudioLevelControl::SetCurVolume (UInt8 interfaceNumber, UInt8 channelNumber, SInt16 volume) {
IOUSBDevRequest devReq;
IOReturn error;
devReq.bmRequestType = USBmakebmRequestType (kUSBOut, kUSBClass, kUSBInterface);
devReq.bRequest = SET_CUR;
devReq.wValue = (mControlSelector << 8) | channelNumber;
devReq.wIndex = (mUnitID << 8) | interfaceNumber;
devReq.wLength = 2;
devReq.pData = &volume;
FailIf ((TRUE == isInactive()), DeviceInactive); error = mUSBDeviceRequest (&devReq, mCallerRefCon, NULL);
FailIf (kIOReturnSuccess != error, Exit);
Exit:
return error;
DeviceInactive:
debugIOLog("! AppleUSBAudioLevelControl::SetCurVolume () - ERROR attempt to send a device request to and inactive device");
error = kIOReturnError;
goto Exit;
}
void AppleUSBAudioLevelControl::updateValueCallback (void *arg1, void *arg2) {
AppleUSBAudioLevelControl *levelControl;
SInt32 value;
UInt32 subType;
debugIOLog ("+ AppleUSBAudioLevelControl::updateValueCallback (%p, %p)", (UInt32*)arg1, (UInt32*)arg2);
levelControl = OSDynamicCast (AppleUSBAudioLevelControl, (OSObject*)arg1);
value = (SInt32)(intptr_t)arg2;
if (levelControl)
{
subType = levelControl->getSubType ();
if (kIOAudioLevelControlSubTypePRAMVolume == subType)
{
#ifndef kNO_PRAM_SUPPORT
UInt8 curPRAMVol;
IODTPlatformExpert * platform = NULL;
platform = OSDynamicCast (IODTPlatformExpert, getPlatform ());
if (NULL != platform)
{
platform->readXPRAM ((IOByteCount)kPRamVolumeAddr, &curPRAMVol, (IOByteCount)1);
curPRAMVol = (curPRAMVol & 0xF8) | value;
platform->writeXPRAM ((IOByteCount)kPRamVolumeAddr, &curPRAMVol, (IOByteCount)1);
}
#endif // kNO_PRAM_SUPPORT
}
else
{
levelControl->updateUSBValue (value);
}
}
debugIOLog ("- AppleUSBAudioLevelControl::updateValueCallback (%p, %p)", (UInt32*)arg1, (UInt32*)arg2);
}
IOFixed AppleUSBAudioLevelControl::ConvertUSBVolumeTodB (SInt16 volume) {
IOFixed dBVolumeFixed;
if (volume == (SInt16)0x8000)
{
dBVolumeFixed = ((SInt16)0x8000 * 256) << 8; }
else
{
dBVolumeFixed = volume * 256;
}
debugIOLog ("? AppleUSBAudioLevelControl::ConvertUSBVolumeTodB () - volume = %d, dBVolumeFixed = 0x%x", volume, dBVolumeFixed);
return dBVolumeFixed;
}
#pragma mark +PRAM VOLUME
#ifndef kNO_PRAM_SUPPORT
UInt8 AppleUSBAudioLevelControl::VolumeToPRAMValue (SInt32 leftVol, SInt32 rightVol) {
UInt32 pramVolume; UInt32 averageVolume; const UInt32 volumeRange = (fMaxVolume - fMinVolume + 1);
UInt32 volumeSteps;
if (leftVol < 0)
leftVol = 0;
if (rightVol < 0)
rightVol = 0;
averageVolume = (leftVol + rightVol) >> 1; volumeSteps = volumeRange / kMaximumPRAMVolume; pramVolume = averageVolume / volumeSteps;
if ((pramVolume == 0) && (leftVol != 0 || rightVol !=0 ))
{
pramVolume = 1;
}
return (pramVolume & 0x07);
}
void AppleUSBAudioLevelControl::WritePRAMVol (SInt32 leftVol, SInt32 rightVol) {
UInt8 pramVolume;
UInt8 curPRAMVol;
IODTPlatformExpert * platform = NULL;
platform = OSDynamicCast (IODTPlatformExpert, getPlatform ());
debugIOLog ("? AppleUSBAudioLevelControl::WritePRAMVol () - leftVol = %lu, rightVol = %lu",leftVol, rightVol);
if (NULL != platform)
{
pramVolume = VolumeToPRAMValue (leftVol, rightVol);
platform->readXPRAM ((IOByteCount)kPRamVolumeAddr, &curPRAMVol, (IOByteCount)1);
if (pramVolume != (curPRAMVol & 0x07))
{
curPRAMVol = (curPRAMVol & 0xF8) | pramVolume;
debugIOLog ("? AppleUSBAudioLevelControl::WritePRAMVol () - curPRAMVol = 0x%x", curPRAMVol);
platform->writeXPRAM ((IOByteCount)kPRamVolumeAddr, &curPRAMVol, (IOByteCount) 1);
}
}
}
#endif // kNO_PRAM_SUPPORT
Generated by GNU enscript 1.6.4.