#include "AppleUSBAudioMuteControl.h" #define super IOAudioToggleControl OSDefineMetaClassAndStructors(AppleUSBAudioMuteControl, IOAudioToggleControl) AppleUSBAudioMuteControl *AppleUSBAudioMuteControl::create (UInt8 theUnitID, UInt8 theInterfaceNumber, UInt8 theChannelNumber, USBDeviceRequest theUSBDeviceRequest, void *theCallerRefCon, UInt32 usage, UInt32 subType, UInt32 controlID) { AppleUSBAudioMuteControl *control; debug7IOLog ("+AppleUSBAudioMuteControl::create (%d, %d, %d, 0x%x, %lX, %lX)\n", theUnitID, theInterfaceNumber, theChannelNumber, theUSBDeviceRequest, usage, controlID); control = new AppleUSBAudioMuteControl; if (control) { if (FALSE == control->init (theUnitID, theInterfaceNumber, theChannelNumber, theUSBDeviceRequest, theCallerRefCon, usage, subType, controlID)) { control->release (); control = NULL; } } debug7IOLog ("-AppleUSBAudioMuteControl[0x%x]::create (%d, %d, %d, 0x%x, %lX, %lX)\n", theUnitID, theInterfaceNumber, theChannelNumber, theUSBDeviceRequest, usage, controlID); return control; } bool AppleUSBAudioMuteControl::init (UInt8 theUnitID, UInt8 theInterfaceNumber, UInt8 theChannelNumber, USBDeviceRequest theUSBDeviceRequest, void *theCallerRefCon, UInt32 usage, UInt32 subType, UInt32 controlID, OSDictionary *properties) { const char * channelName = NULL; UInt8 currentValue; IOReturn ret; Boolean result; debug8IOLog ("+AppleUSBAudioMuteControl[0x%x]::init (%d, %d, %d, 0x%x, 0x%x, %lX)\n", this, theUnitID, theInterfaceNumber, theChannelNumber, theUSBDeviceRequest, usage, properties); result = FALSE; FailIf (NULL == theUSBDeviceRequest, Exit); setValueThreadCall = thread_call_allocate ((thread_call_func_t)updateValueCallback, this); FailIf (NULL == setValueThreadCall, Exit); unitID = theUnitID; interfaceNumber = theInterfaceNumber; channelNumber = theChannelNumber; callerRefCon = theCallerRefCon; usbDeviceRequest = theUSBDeviceRequest; switch (channelNumber) { case kIOAudioControlChannelIDAll: channelName = kIOAudioControlChannelNameAll; break; case kIOAudioControlChannelIDDefaultLeft: channelName = kIOAudioControlChannelNameLeft; break; case kIOAudioControlChannelIDDefaultRight: channelName = kIOAudioControlChannelNameRight; break; case 0xff: debugIOLog ("++AppleUSBAudioMuteControl: Does not support channel number 0xff.\n"); return FALSE; default: channelName = "Unknown"; break; } currentValue = GetCurMute (interfaceNumber, channelNumber, &ret); FailIf (kIOReturnSuccess != ret, Exit); FailIf (FALSE == super::init (currentValue, theChannelNumber, channelName, controlID, subType, usage), Exit); result = TRUE; Exit: debug8IOLog ("-AppleUSBAudioMuteControl[0x%x]::init (%d, %d, %d, 0x%x, 0x%x, %lX)\n", this, theUnitID, theInterfaceNumber, theChannelNumber, theUSBDeviceRequest, usage, properties); return result; } void AppleUSBAudioMuteControl::free () { debug2IOLog ("+AppleUSBAudioMuteControl[0x%x]::free ()\n", this); if (setValueThreadCall) { thread_call_free (setValueThreadCall); setValueThreadCall = NULL; } debug2IOLog ("-AppleUSBAudioMuteControl[0x%x]::free ()\n", this); super::free (); } IOReturn AppleUSBAudioMuteControl::performValueChange (OSObject * newValue) { OSNumber * newValueAsNumber; SInt32 newValueAsSInt32; debug3IOLog ("+AppleUSBAudioMuteControl[0x%x]::performValueChange (%d)\n", this, newValue); newValueAsNumber = OSDynamicCast (OSNumber, newValue); FailIf (NULL == newValueAsNumber, Exit); newValueAsSInt32 = newValueAsNumber->unsigned32BitValue (); debug3IOLog ("++AppleUSBAudioMuteControl[0x%x]::performValueChange (%ld)\n", this, newValueAsSInt32); // updateUSBValue (); // We should just be able to make an asynchronous deviceRequest, but for some reason that doesn't want to work // we get pipe stall errors and the change is never made assert (setValueThreadCall); thread_call_enter1 (setValueThreadCall, (thread_call_param_t)newValueAsSInt32); debug2IOLog ("-AppleUSBAudioMuteControl::performValueChange (%d)\n", newValueAsSInt32); Exit: return kIOReturnSuccess; } UInt8 AppleUSBAudioMuteControl::GetCurMute (UInt8 interfaceNumber, UInt8 channelNumber, IOReturn * error) { IOUSBDevRequest devReq; UInt8 theMuteState; devReq.bmRequestType = USBmakebmRequestType (kUSBIn, kUSBClass, kUSBInterface); devReq.bRequest = GET_CUR; devReq.wValue = (MUTE_CONTROL << 8) | channelNumber; devReq.wIndex = (unitID << 8) | interfaceNumber; devReq.wLength = 1; devReq.pData = &theMuteState; *error = usbDeviceRequest (&devReq, callerRefCon); FailIf (kIOReturnSuccess != *error, Error); Exit: return theMuteState; Error: theMuteState = 0; goto Exit; } IOReturn AppleUSBAudioMuteControl::SetCurMute (UInt8 interfaceNumber, UInt8 channelNumber, UInt8 theMuteState) { IOUSBDevRequest devReq; IOReturn error; devReq.bmRequestType = USBmakebmRequestType (kUSBOut, kUSBClass, kUSBInterface); devReq.bRequest = SET_CUR; devReq.wValue = (MUTE_CONTROL << 8) | channelNumber; devReq.wIndex = (unitID << 8) | interfaceNumber; devReq.wLength = 1; devReq.pData = &theMuteState; FailIf ((TRUE == isInactive()), DeviceInactive); // In case we've been unplugged during sleep error = usbDeviceRequest (&devReq, callerRefCon); FailIf (kIOReturnSuccess != error, Exit); Exit: return error; DeviceInactive: debugIOLog("AppleUSBAudioMuteControl::SetCurMute ERROR attempt to send a device request to and inactive device\n"); error = kIOReturnError; goto Exit; } void AppleUSBAudioMuteControl::updateUSBValue () { updateUSBValue (getIntValue ()); } void AppleUSBAudioMuteControl::updateUSBValue (SInt32 newValue) { UInt8 theValue; IOReturn ret; debug2IOLog ("+AppleUSBAudioMuteControl::updateUSBValue (%d)\n", newValue); theValue = (newValue != 0); ret = SetCurMute (interfaceNumber, channelNumber, theValue); #if 0 if (getSubType () != kIOAudioToggleControlSubTypeLFEMute && getUsage () == kIOAudioControlUsageOutput) { IOAudioToggleControl * iSubMute; IORegistryEntry * start; IORegistryEntry * parent; IORegistryEntry * engine; debugIOLog ("Looking for iSub mute control\n"); start = getParentEntry (gIOServicePlane); FailIf (NULL == start, Exit); parent = start->getParentEntry (gIOServicePlane); FailIf (NULL == parent, Exit); engine = parent->childFromPath ("AppleUSBAudioEngine", gIOServicePlane); FailIf (NULL == engine, Exit); iSubMute = (IOAudioToggleControl *)FindEntryByNameAndProperty (engine, "AppleUSBAudioMuteControl", kIOAudioControlSubTypeKey, kIOAudioToggleControlSubTypeLFEMute); engine->release (); if (NULL != iSubMute) { debugIOLog ("Setting the iSub mute control\n"); iSubMute->setValue (newValue); iSubMute->release (); } } #endif //Exit: if (ret != kIOReturnSuccess) { debug3IOLog ("++AppleUSBAudioMuteContol:updateUSBValue () - set current value for channel %d failed: 0x%x\n", channelNumber, ret); } debug2IOLog ("-AppleUSBAudioMuteControl::updateUSBValue (%d)\n", newValue); } void AppleUSBAudioMuteControl::updateValueCallback (void *arg1, void *arg2) { AppleUSBAudioMuteControl *muteControl; UInt32 value; debug3IOLog ("+AppleUSBAudioMuteControl::updateValueCallback (%d, %d)\n", (UInt32*)arg1, (UInt32*)arg2); muteControl = (AppleUSBAudioMuteControl *)arg1; value = (UInt32)arg2; if (muteControl && OSDynamicCast (AppleUSBAudioMuteControl, muteControl)) { muteControl->updateUSBValue (value); } debug3IOLog ("-AppleUSBAudioMuteControl::updateValueCallback (%d, %d)\n", (UInt32*)arg1, (UInt32*)arg2); } #if 0 IORegistryEntry * AppleUSBAudioMuteControl::FindEntryByNameAndProperty (const IORegistryEntry * start, const char * name, const char * key, UInt32 value) { OSIterator *iterator; IORegistryEntry *theEntry; IORegistryEntry *tmpReg; OSNumber *tmpNumber; theEntry = NULL; iterator = NULL; FailIf (NULL == start, Exit); iterator = start->getChildIterator (gIOServicePlane); FailIf (NULL == iterator, Exit); while (NULL == theEntry && (tmpReg = OSDynamicCast (IORegistryEntry, iterator->getNextObject ())) != NULL) { if (strcmp (tmpReg->getName (), name) == 0) { tmpNumber = OSDynamicCast (OSNumber, tmpReg->getProperty (key)); if (NULL != tmpNumber && tmpNumber->unsigned32BitValue () == value) { theEntry = tmpReg; theEntry->retain (); } } } Exit: if (NULL != iterator) { iterator->release (); } return theEntry; } #endif