1/* 2 * Copyright (c) 1998-2014 Apple Computer, Inc. All rights reserved. 3 * 4 * @APPLE_LICENSE_HEADER_START@ 5 * 6 * The contents of this file constitute Original Code as defined in and 7 * are subject to the Apple Public Source License Version 1.1 (the 8 * "License"). You may not use this file except in compliance with the 9 * License. Please obtain a copy of the License at 10 * http://www.apple.com/publicsource and read it before using this file. 11 * 12 * This Original Code and all software distributed under the License are 13 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER 14 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 15 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 16 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the 17 * License for the specific language governing rights and limitations 18 * under the License. 19 * 20 * @APPLE_LICENSE_HEADER_END@ 21 */ 22 23#include "IOAudioDebug.h" 24#include "IOAudioControl.h" 25#include "IOAudioControlUserClient.h" 26#include "IOAudioTypes.h" 27#include "IOAudioDefines.h" 28#include "AudioTracepoints.h" 29 30#include <IOKit/IOLib.h> 31#include <IOKit/IOWorkLoop.h> 32#include <IOKit/IOCommandGate.h> 33 34// <rdar://8518215> 35enum 36{ 37 kCommandGateStatus_Normal = 0, 38 kCommandGateStatus_RemovalPending, 39 kCommandGateStatus_Invalid 40}; 41 42#define super IOService 43 44OSDefineMetaClassAndStructors(IOAudioControl, IOService) 45OSMetaClassDefineReservedUsed(IOAudioControl, 0); 46OSMetaClassDefineReservedUsed(IOAudioControl, 1); 47OSMetaClassDefineReservedUsed(IOAudioControl, 2); 48OSMetaClassDefineReservedUsed(IOAudioControl, 3); 49 50OSMetaClassDefineReservedUnused(IOAudioControl, 4); 51OSMetaClassDefineReservedUnused(IOAudioControl, 5); 52OSMetaClassDefineReservedUnused(IOAudioControl, 6); 53OSMetaClassDefineReservedUnused(IOAudioControl, 7); 54OSMetaClassDefineReservedUnused(IOAudioControl, 8); 55OSMetaClassDefineReservedUnused(IOAudioControl, 9); 56OSMetaClassDefineReservedUnused(IOAudioControl, 10); 57OSMetaClassDefineReservedUnused(IOAudioControl, 11); 58OSMetaClassDefineReservedUnused(IOAudioControl, 12); 59OSMetaClassDefineReservedUnused(IOAudioControl, 13); 60OSMetaClassDefineReservedUnused(IOAudioControl, 14); 61OSMetaClassDefineReservedUnused(IOAudioControl, 15); 62OSMetaClassDefineReservedUnused(IOAudioControl, 16); 63OSMetaClassDefineReservedUnused(IOAudioControl, 17); 64OSMetaClassDefineReservedUnused(IOAudioControl, 18); 65OSMetaClassDefineReservedUnused(IOAudioControl, 19); 66OSMetaClassDefineReservedUnused(IOAudioControl, 20); 67OSMetaClassDefineReservedUnused(IOAudioControl, 21); 68OSMetaClassDefineReservedUnused(IOAudioControl, 22); 69OSMetaClassDefineReservedUnused(IOAudioControl, 23); 70 71// New code 72 73// OSMetaClassDefineReservedUsed(IOAudioControl, 3); 74IOReturn IOAudioControl::createUserClient(task_t task, void *securityID, UInt32 taskType, IOAudioControlUserClient **newUserClient, OSDictionary *properties) 75{ 76 IOReturn result = kIOReturnSuccess; 77 IOAudioControlUserClient *userClient; 78 79 userClient = IOAudioControlUserClient::withAudioControl(this, task, securityID, taskType, properties); 80 81 if (userClient) { 82 *newUserClient = userClient; 83 } else { 84 result = kIOReturnNoMemory; 85 } 86 87 return result; 88} 89 90void IOAudioControl::sendChangeNotification(UInt32 notificationType) 91{ 92 OSCollectionIterator *iterator; 93 IOAudioControlUserClient *client; 94 95 if (!userClients || !isStarted) { 96 return; 97 } 98 99 // If we're doing a config change, just queue the notification for later. 100 if (reserved->providerEngine->configurationChangeInProgress) { 101 OSNumber *notificationNumber; 102 UInt32 i, count; 103 bool dupe = FALSE; 104 105 if (!reserved->notificationQueue) { 106 reserved->notificationQueue = OSArray::withCapacity (1); 107 if (!reserved->notificationQueue) { 108 return; 109 } 110 } 111 112 notificationNumber = OSNumber::withNumber (notificationType, sizeof (notificationType) * 8); 113 if (!notificationNumber) 114 return; 115 116 // Check to see if this is a unique notification, there is no need to send dupes. 117 count = reserved->notificationQueue->getCount (); 118 for (i = 0; i < count; i++) { 119 if (notificationNumber->isEqualTo ((OSNumber *)reserved->notificationQueue->getObject (i))) { 120 dupe = TRUE; 121 break; // no need to send duplicate notifications 122 } 123 } 124 if (!dupe) { 125 reserved->notificationQueue->setObject (notificationNumber); 126 } 127 notificationNumber->release (); 128 } else { 129 iterator = OSCollectionIterator::withCollection(userClients); 130 if (iterator) { 131 while ( (client = (IOAudioControlUserClient *)iterator->getNextObject()) ) { 132 client->sendChangeNotification(notificationType); 133 } 134 135 iterator->release(); 136 } 137 } 138} 139 140void IOAudioControl::sendQueuedNotifications(void) 141{ 142 UInt32 i; 143 UInt32 count; 144 145 // Send our the queued notications and release the queue. 146 if (reserved && reserved->notificationQueue) { 147 count = reserved->notificationQueue->getCount (); 148 for (i = 0; i < count; i++) { 149 if (!isInactive()) { // <radr://9320521,9040208> 150 sendChangeNotification(((OSNumber *)reserved->notificationQueue->getObject(i))->unsigned32BitValue()); 151 } 152 } 153 reserved->notificationQueue->release(); 154 reserved->notificationQueue = NULL; 155 } 156} 157 158// Original code here... 159IOAudioControl *IOAudioControl::withAttributes(UInt32 type, 160 OSObject *initialValue, 161 UInt32 channelID, 162 const char *channelName, 163 UInt32 cntrlID, 164 UInt32 subType, 165 UInt32 usage) 166{ 167 IOAudioControl *control; 168 169 control = new IOAudioControl; 170 171 if (control) { 172 if (!control->init(type, initialValue, channelID, channelName, cntrlID, subType, usage)) { 173 control->release(); 174 control = 0; 175 } 176 } 177 178 return control; 179} 180 181bool IOAudioControl::init(UInt32 _type, 182 OSObject *initialValue, 183 UInt32 newChannelID, 184 const char *channelName, 185 UInt32 cntrlID, 186 UInt32 _subType, 187 UInt32 _usage, 188 OSDictionary *properties) 189{ 190 if (!super::init(properties)) { 191 return false; 192 } 193 194 if (initialValue == NULL) { 195 return false; 196 } 197 198 if (_type == 0) { 199 return false; 200 } 201 202 setType(_type); 203 204 setChannelID(newChannelID); 205 setControlID(cntrlID); 206 207 setSubType(_subType); 208 209 if (channelName) { 210 setChannelName(channelName); 211 } 212 213 if (_usage != 0) { 214 setUsage(_usage); 215 } 216 217 _setValue(initialValue); 218 219 userClients = OSSet::withCapacity(1); 220 if (!userClients) { 221 return false; 222 } 223 224 reserved = (ExpansionData *)IOMalloc (sizeof(struct ExpansionData)); 225 if (!reserved) { 226 return false; 227 } 228 229 reserved->providerEngine = NULL; 230 reserved->notificationQueue = NULL; 231 reserved->commandGateStatus = kCommandGateStatus_Normal; // <rdar://8518215> 232 reserved->commandGateUsage = 0; // <rdar://8518215> 233 isStarted = false; 234 235 return true; 236} 237 238void IOAudioControl::setType(UInt32 _type) 239{ 240 this->type = _type; 241 setProperty(kIOAudioControlTypeKey, type, sizeof(UInt32)*8); 242} 243 244void IOAudioControl::setSubType(UInt32 _subType) 245{ 246 this->subType = _subType; 247 setProperty(kIOAudioControlSubTypeKey, subType, sizeof(UInt32)*8); 248} 249 250void IOAudioControl::setChannelName(const char *channelName) 251{ 252 setProperty(kIOAudioControlChannelNameKey, channelName); 253} 254 255void IOAudioControl::setUsage(UInt32 _usage) 256{ 257 this->usage = _usage; 258 setProperty(kIOAudioControlUsageKey, usage, sizeof(UInt32)*8); 259} 260 261void IOAudioControl::setCoreAudioPropertyID(UInt32 propertyID) 262{ 263 setProperty(kIOAudioControlCoreAudioPropertyIDKey, propertyID, sizeof(UInt32)*8); 264 setUsage(kIOAudioControlUsageCoreAudioProperty); 265} 266 267void IOAudioControl::setReadOnlyFlag() 268{ 269 setProperty(kIOAudioControlValueIsReadOnlyKey, (bool)true); 270} 271 272UInt32 IOAudioControl::getType() 273{ 274 return type; 275} 276 277UInt32 IOAudioControl::getSubType() 278{ 279 return subType; 280} 281 282UInt32 IOAudioControl::getUsage() 283{ 284 return usage; 285} 286 287void IOAudioControl::free() 288{ 289 audioDebugIOLog(3, "+ IOAudioControl[%p]::free()\n", this); 290 291 if (userClients) { 292 // should we do some sort of notification here? 293 userClients->release(); 294 userClients = NULL; 295 } 296 297 if (valueChangeTarget) { 298 valueChangeTarget->release(); 299 valueChangeTarget = NULL; 300 } 301 302 if (commandGate) { 303 if (workLoop) { 304 workLoop->removeEventSource(commandGate); 305 } 306 307 commandGate->release(); 308 commandGate = NULL; 309 } 310 311 if (workLoop) { 312 workLoop->release(); 313 workLoop = NULL; 314 } 315 316 if (reserved) { 317 if (reserved->notificationQueue) { 318 reserved->notificationQueue->release(); 319 reserved->notificationQueue = NULL; 320 } 321 322 IOFree (reserved, sizeof (struct ExpansionData)); 323 reserved = NULL; 324 } 325 326 super::free(); 327 audioDebugIOLog(3, "- IOAudioControl[%p]::free()\n", this); 328} 329 330bool IOAudioControl::start(IOService *provider) 331{ 332 AudioTrace_Start(kAudioTIOAudioControl, kTPIOAudioControlStart, (uintptr_t)this, (uintptr_t)provider, 0, 0); 333 if (!super::start(provider)) { 334 return false; 335 } 336 337 isStarted = true; 338 reserved->providerEngine = OSDynamicCast (IOAudioEngine, provider); 339 340 AudioTrace_End(kAudioTIOAudioControl, kTPIOAudioControlStart, (uintptr_t)this, (uintptr_t)provider, true, 0); 341 return true; 342} 343 344bool IOAudioControl::attachAndStart(IOService *provider) 345{ 346 bool result = true; 347 348 if (attach(provider)) { 349 if (!isStarted) { 350 result = start(provider); 351 if (!result) { 352 detach(provider); 353 } 354 } 355 } else { 356 result = false; 357 } 358 359 return result; 360} 361 362void IOAudioControl::stop(IOService *provider) 363{ 364 audioDebugIOLog(3, "+ IOAudioControl[%p]::stop(%p)\n", this, provider); 365 366 if (userClients && (userClients->getCount() > 0)) { 367 IOCommandGate *cg; 368 369 cg = getCommandGate(); 370 371 if (cg) { 372 cg->runAction(detachUserClientsAction); 373 } 374 } 375 376 if (valueChangeTarget) { 377 valueChangeTarget->release(); 378 valueChangeTarget = NULL; 379 valueChangeHandler.intHandler = NULL; 380 } 381 382 // <rdar://7233118>, <rdar://7029696> Remove the event source here as performing heavy workloop operation in free() could lead 383 // to deadlock since the context which free() is called is not known. stop() is called on the workloop, so it is safe to remove 384 // the event source here. 385 if (reserved->commandGateUsage == 0) { // <rdar://8518215> 386 reserved->commandGateStatus = kCommandGateStatus_Invalid; // <rdar://8518215> 387 388 if (commandGate) { 389 if (workLoop) { 390 workLoop->removeEventSource(commandGate); 391 } 392 393 commandGate->release(); 394 commandGate = NULL; 395 } 396 } 397 else { // <rdar://8518215> 398 reserved->commandGateStatus = kCommandGateStatus_RemovalPending; 399 } 400 401 super::stop(provider); 402 403 isStarted = false; 404 405 audioDebugIOLog(3, "- IOAudioControl[%p]::stop(%p)\n", this, provider); 406} 407 408bool IOAudioControl::getIsStarted() 409{ 410 return isStarted; 411} 412 413IOWorkLoop *IOAudioControl::getWorkLoop() 414{ 415 return workLoop; 416} 417 418void IOAudioControl::setWorkLoop(IOWorkLoop *wl) 419{ 420 if (!workLoop) { 421 workLoop = wl; 422 423 if (workLoop) { 424 workLoop->retain(); 425 426 commandGate = IOCommandGate::commandGate(this); 427 428 if (commandGate) { 429 workLoop->addEventSource(commandGate); 430 } 431 } 432 } 433} 434 435IOCommandGate *IOAudioControl::getCommandGate() 436{ 437 return commandGate; 438} 439 440// <rdar://7529580> 441IOReturn IOAudioControl::_setValueAction(OSObject *target, void *arg0, void *arg1, void *arg2, void *arg3) 442{ 443 IOReturn result = kIOReturnBadArgument; 444 445 if (target) { 446 IOAudioControl *audioControl = OSDynamicCast(IOAudioControl, target); 447 if (audioControl) { 448 IOCommandGate *cg; 449 450 cg = audioControl->getCommandGate(); 451 452 if (cg) { 453 setCommandGateUsage(audioControl, true); // <rdar://8518215> 454 result = cg->runAction(setValueAction, arg0, arg1, arg2, arg3); 455 setCommandGateUsage(audioControl, false); // <rdar://8518215> 456 } else { 457 result = kIOReturnError; 458 } 459 } 460 } 461 462 return result; 463} 464 465IOReturn IOAudioControl::setValueAction(OSObject *owner, void *arg1, void *arg2, void *arg3, void *arg4) 466{ 467 IOReturn result = kIOReturnBadArgument; 468 469 if (owner) { 470 IOAudioControl *audioControl = OSDynamicCast(IOAudioControl, owner); 471 if (audioControl) { 472 result = audioControl->setValue((OSObject *)arg1); 473 } 474 } 475 476 return result; 477} 478 479IOReturn IOAudioControl::setValue(OSObject *newValue) 480{ 481 IOReturn result = kIOReturnSuccess; 482 483 if (OSDynamicCast(OSNumber, newValue)) { 484 audioDebugIOLog(3, "+ IOAudioControl[%p]::setValue(int = %d)\n", this, ((OSNumber *)newValue)->unsigned32BitValue()); 485 } else { 486 audioDebugIOLog(3, "+ IOAudioControl[%p]::setValue(%p)\n", this, newValue); 487 } 488 489 if (newValue) { 490 if (!value || !value->isEqualTo(newValue)) { 491 result = validateValue(newValue); 492 if (result == kIOReturnSuccess) { 493 result = performValueChange(newValue); 494 if (result == kIOReturnSuccess) { 495 result = updateValue(newValue); 496 } else { 497 audioDebugIOLog(2, " Error 0x%x received from driver - value not set!\n", result); 498 } 499 } else { 500 audioDebugIOLog(2, " Error 0x%x - invalid value.\n", result); 501 } 502 } 503 } else { 504 result = kIOReturnBadArgument; 505 } 506 507 if (OSDynamicCast(OSNumber, newValue)) { 508 audioDebugIOLog(3, "- IOAudioControl[%p]::setValue(int = %d) returns 0x%lX\n", this, ((OSNumber *)newValue)->unsigned32BitValue(), (long unsigned int)result ); 509 } else { 510 audioDebugIOLog(3, "- IOAudioControl[%p]::setValue(%p) returns 0x%lX\n", this, newValue, (long unsigned int)result ); 511 } 512 513 return result; 514} 515 516IOReturn IOAudioControl::setValue(SInt32 intValue) 517{ 518 IOReturn result = kIOReturnError; 519 OSNumber *number; 520 521 number = OSNumber::withNumber(intValue, sizeof(SInt32)*8); 522 if (number) { 523 result = setValue(number); 524 number->release(); 525 } 526 527 return result; 528} 529 530IOReturn IOAudioControl::validateValue(OSObject *_value) 531{ 532 return kIOReturnSuccess; 533} 534 535IOReturn IOAudioControl::updateValue(OSObject *newValue) 536{ 537 IOReturn result; 538 539 result = _setValue(newValue); 540 if (result == kIOReturnSuccess) { 541 sendValueChangeNotification(); 542 } 543 544 return result; 545} 546 547IOReturn IOAudioControl::_setValue(OSObject *newValue) 548{ 549 if (value != newValue) { 550 if (value) { 551 value->release(); 552 } 553 value = newValue; 554 value->retain(); 555 556 setProperty(kIOAudioControlValueKey, value); 557 } 558 559 return kIOReturnSuccess; 560} 561 562IOReturn IOAudioControl::hardwareValueChanged(OSObject *newValue) 563{ 564 IOReturn result = kIOReturnSuccess; 565 566 audioDebugIOLog(3, "+ IOAudioControl[%p]::hardwareValueChanged(%p)\n", this, newValue); 567 568 if (newValue) { 569 if (!value || !value->isEqualTo(newValue)) { 570 result = validateValue(newValue); 571 if (result == kIOReturnSuccess) { 572 result = updateValue(newValue); 573 } else { 574 IOLog("IOAudioControl[%p]::hardwareValueChanged(%p) - Error 0x%x - invalid value.\n", this, newValue, result); 575 } 576 } 577 } else { 578 result = kIOReturnBadArgument; 579 } 580 581 audioDebugIOLog(3, "- IOAudioControl[%p]::hardwareValueChanged(%p) returns 0x%lX\n", this, newValue, (long unsigned int)result ); 582 return result; 583} 584 585void IOAudioControl::setValueChangeHandler(IntValueChangeHandler intValueChangeHandler, OSObject *target) 586{ 587 valueChangeHandlerType = kIntValueChangeHandler; 588 valueChangeHandler.intHandler = intValueChangeHandler; 589 setValueChangeTarget(target); 590} 591 592void IOAudioControl::setValueChangeHandler(DataValueChangeHandler dataValueChangeHandler, OSObject *target) 593{ 594 valueChangeHandlerType = kDataValueChangeHandler; 595 valueChangeHandler.dataHandler = dataValueChangeHandler; 596 setValueChangeTarget(target); 597} 598 599void IOAudioControl::setValueChangeHandler(ObjectValueChangeHandler objectValueChangeHandler, OSObject *target) 600{ 601 valueChangeHandlerType = kObjectValueChangeHandler; 602 valueChangeHandler.objectHandler = objectValueChangeHandler; 603 setValueChangeTarget(target); 604} 605 606void IOAudioControl::setValueChangeTarget(OSObject *target) 607{ 608 if (target) { 609 target->retain(); 610 } 611 612 if (valueChangeTarget) { 613 valueChangeTarget->release(); 614 } 615 616 valueChangeTarget = target; 617} 618 619IOReturn IOAudioControl::performValueChange(OSObject *newValue) 620{ 621 IOReturn result = kIOReturnError; 622 623 audioDebugIOLog(3, "+ IOAudioControl[%p]::performValueChange(%p)\n", this, newValue); 624 625 if (valueChangeHandler.intHandler != NULL) { 626 switch(valueChangeHandlerType) { 627 case kIntValueChangeHandler: 628 OSNumber *oldNumber, *newNumber; 629 630 if ((oldNumber = OSDynamicCast(OSNumber, getValue())) == NULL) { 631 IOLog("IOAudioControl[%p]::performValueChange(%p) - Error: can't call handler - int handler set and old value is not an OSNumber.\n", this, newValue); 632 break; 633 } 634 635 if ((newNumber = OSDynamicCast(OSNumber, newValue)) == NULL) { 636 IOLog("IOAudioControl[%p]::performValueChange(%p) - Error: can't call handler - int handler set and new value is not an OSNumber.\n", this, newValue); 637 break; 638 } 639 640 result = valueChangeHandler.intHandler(valueChangeTarget, this, oldNumber->unsigned32BitValue(), newNumber->unsigned32BitValue()); 641 642 break; 643 case kDataValueChangeHandler: 644 OSData *oldData, *newData; 645 const void *oldBytes, *newBytes; 646 UInt32 oldSize, newSize; 647 648 if (getValue()) { 649 if ((oldData = OSDynamicCast(OSData, getValue())) == NULL) { 650 IOLog("IOAudioControl[%p]::performValueChange(%p) - Error: can't call handler - data handler set and old value is not an OSData.\n", this, newValue); 651 break; 652 } 653 654 oldBytes = oldData->getBytesNoCopy(); 655 oldSize = oldData->getLength(); 656 } else { 657 oldBytes = NULL; 658 oldSize = 0; 659 } 660 661 if (newValue) { 662 if ((newData = OSDynamicCast(OSData, newValue)) == NULL) { 663 IOLog("IOAudioControl[%p]::performValueChange(%p) - Error: can't call handler - data handler set and new value is not an OSData.\n", this, newValue); 664 break; 665 } 666 667 newBytes = newData->getBytesNoCopy(); 668 newSize = newData->getLength(); 669 } else { 670 newBytes = NULL; 671 newSize = 0; 672 } 673 674 result = valueChangeHandler.dataHandler(valueChangeTarget, this, oldBytes, oldSize, newBytes, newSize); 675 676 break; 677 case kObjectValueChangeHandler: 678 result = valueChangeHandler.objectHandler(valueChangeTarget, this, getValue(), newValue); 679 break; 680 } 681 } 682 683 audioDebugIOLog(3, "- IOAudioControl[%p]::performValueChange(%p) returns 0x%lX\n", this, newValue, (long unsigned int)result ); 684 return result; 685} 686 687IOReturn IOAudioControl::flushValue() 688{ 689 return performValueChange(getValue()); 690} 691 692OSObject *IOAudioControl::getValue() 693{ 694 return value; 695} 696 697SInt32 IOAudioControl::getIntValue() 698{ 699 OSNumber *number; 700 SInt32 intValue = 0; 701 702 number = OSDynamicCast(OSNumber, getValue()); 703 if (number) { 704 intValue = (SInt32)number->unsigned32BitValue(); 705 } 706 707 return intValue; 708} 709 710const void *IOAudioControl::getDataBytes() 711{ 712 const void *bytes = NULL; 713 OSData *data; 714 715 data = OSDynamicCast(OSData, getValue()); 716 if (data) { 717 bytes = data->getBytesNoCopy(); 718 } 719 720 return bytes; 721} 722 723UInt32 IOAudioControl::getDataLength() 724{ 725 UInt32 length = 0; 726 OSData *data; 727 728 data = OSDynamicCast(OSData, getValue()); 729 if (data) { 730 length = data->getLength(); 731 } 732 733 return length; 734} 735 736void IOAudioControl::sendValueChangeNotification() 737{ 738 OSCollectionIterator *iterator; 739 IOAudioControlUserClient *client; 740 741 if (!userClients) { 742 return; 743 } 744 745 iterator = OSCollectionIterator::withCollection(userClients); 746 if (iterator) { 747 while ( (client = (IOAudioControlUserClient *)iterator->getNextObject()) ) { 748 client->sendValueChangeNotification(); 749 } 750 751 iterator->release(); 752 } 753} 754 755void IOAudioControl::setControlID(UInt32 newControlID) 756{ 757 controlID = newControlID; 758 setProperty(kIOAudioControlIDKey, newControlID, sizeof(UInt32)*8); 759} 760 761UInt32 IOAudioControl::getControlID() 762{ 763 return controlID; 764} 765 766void IOAudioControl::setChannelID(UInt32 newChannelID) 767{ 768 channelID = newChannelID; 769 setProperty(kIOAudioControlChannelIDKey, newChannelID, sizeof(UInt32)*8); 770} 771 772UInt32 IOAudioControl::getChannelID() 773{ 774 return channelID; 775} 776 777void IOAudioControl::setChannelNumber(SInt32 channelNumber) 778{ 779 setProperty(kIOAudioControlChannelNumberKey, channelNumber, sizeof(SInt32)*8); 780} 781 782IOReturn IOAudioControl::createUserClient(task_t task, void *securityID, UInt32 taskType, IOAudioControlUserClient **newUserClient) 783{ 784 IOReturn result = kIOReturnSuccess; 785 IOAudioControlUserClient *userClient; 786 787 userClient = IOAudioControlUserClient::withAudioControl(this, task, securityID, taskType); 788 789 if (userClient) { 790 *newUserClient = userClient; 791 } else { 792 result = kIOReturnNoMemory; 793 } 794 795 return result; 796} 797 798IOReturn IOAudioControl::newUserClient(task_t task, void *securityID, UInt32 taskType, IOUserClient **handler) 799{ 800#if __i386__ || __x86_64__ 801 return kIOReturnUnsupported; 802#else 803 IOReturn result = kIOReturnSuccess; 804 IOAudioControlUserClient *client = NULL; 805 806 audioDebugIOLog(3, "+ IOAudioControl[%p]::newUserClient()\n", this); 807 808 *handler = NULL; // <rdar://8370885> 809 810 if (!isInactive()) { // <rdar://7324947> 811 result = createUserClient(task, securityID, taskType, &client); 812 813 if ((result == kIOReturnSuccess) && (client != NULL)) { 814 if (workLoop) { // <rdar://7324947> 815 result = workLoop->runAction(_addUserClientAction, this, client); // <rdar://7324947>, <rdar://7529580> 816 817 if (result == kIOReturnSuccess) { 818 *handler = client; 819 } else { 820 client->release(); // <rdar://8370885> 821 } 822 823 } else { 824 client->release(); // <rdar://8370885> 825 result = kIOReturnError; 826 } 827 } 828 } else { // <rdar://7324947> 829 result = kIOReturnNoDevice; 830 } 831 832 audioDebugIOLog(3, "- IOAudioControl[%p]::newUserClient() returns 0x%lX\n", this, (long unsigned int)result ); 833 return result; 834#endif 835} 836 837// <rdar://8121989> Restructured for single point of entry and single point of exit so that 838// the indentifier post processing tool can properly insert scope when post processing a log file 839// obtained via fwkpfv. 840 841IOReturn IOAudioControl::newUserClient(task_t task, void *securityID, UInt32 taskType, OSDictionary *properties, IOUserClient **handler) 842{ 843 IOReturn result = kIOReturnSuccess; 844 IOAudioControlUserClient * client = NULL; 845 846 audioDebugIOLog(3, "+ IOAudioControl[%p]::newUserClient()\n", this); 847 848 *handler = NULL; // <rdar://8370885> 849 850 if ( !isInactive () ) // <rdar://7324947> 851 { 852 if ( kIOReturnSuccess != newUserClient ( task, securityID, taskType, handler ) ) 853 { 854 result = createUserClient ( task, securityID, taskType, &client, properties ); 855 856 if ( ( kIOReturnSuccess == result ) && ( NULL != client ) ) 857 { 858 if ( workLoop ) // <rdar://7324947> 859 { 860 result = workLoop->runAction ( _addUserClientAction, this, client ); // <rdar://7324947>, <rdar://7529580> 861 862 if ( result == kIOReturnSuccess ) 863 { 864 *handler = client; 865 } 866 else 867 { 868 client->release(); // <rdar://8370885> 869 } 870 } 871 else 872 { 873 client->release(); // <rdar://8370885> 874 result = kIOReturnError; 875 } 876 } 877 } 878 } 879 else // <rdar://7324947> 880 { 881 result = kIOReturnNoDevice; 882 } 883 884 audioDebugIOLog(3, "- IOAudioControl[%p]::newUserClient() returns 0x%lX\n", this, (long unsigned int)result ); 885 return result; 886} 887 888void IOAudioControl::clientClosed(IOAudioControlUserClient *client) 889{ 890 audioDebugIOLog(3, "+ IOAudioControl[%p]::clientClosed(%p)\n", this, client); 891 892 if (client) { 893 if (workLoop) { // <rdar://7529580> 894 workLoop->runAction(_removeUserClientAction, this, client); // <rdar://7529580> 895 } 896 } 897 audioDebugIOLog(3, "- IOAudioControl[%p]::clientClosed(%p)\n", this, client); 898} 899 900// <rdar://7529580> 901IOReturn IOAudioControl::_addUserClientAction(OSObject *target, void *arg0, void *arg1, void *arg2, void *arg3) 902{ 903 IOReturn result = kIOReturnBadArgument; 904 905 if (target) { 906 IOAudioControl *audioControl = OSDynamicCast(IOAudioControl, target); 907 if (audioControl) { 908 IOCommandGate *cg; 909 910 cg = audioControl->getCommandGate(); 911 912 if (cg) { 913 setCommandGateUsage(audioControl, true); // <rdar://8518215> 914 result = cg->runAction(addUserClientAction, arg0, arg1, arg2, arg3); 915 setCommandGateUsage(audioControl, false); // <rdar://8518215> 916 } else { 917 result = kIOReturnError; 918 } 919 } 920 } 921 922 return result; 923} 924 925IOReturn IOAudioControl::addUserClientAction(OSObject *owner, void *arg1, void *arg2, void *arg3, void *arg4) 926{ 927 IOReturn result = kIOReturnBadArgument; 928 929 if (owner) { 930 IOAudioControl *audioControl = OSDynamicCast(IOAudioControl, owner); 931 if (audioControl) { 932 result = audioControl->addUserClient((IOAudioControlUserClient *)arg1); 933 } 934 } 935 936 return result; 937} 938 939// <rdar://7529580> 940IOReturn IOAudioControl::_removeUserClientAction(OSObject *target, void *arg0, void *arg1, void *arg2, void *arg3) 941{ 942 IOReturn result = kIOReturnBadArgument; 943 944 if (target) { 945 IOAudioControl *audioControl = OSDynamicCast(IOAudioControl, target); 946 if (audioControl) { 947 IOCommandGate *cg; 948 949 cg = audioControl->getCommandGate(); 950 951 if (cg) { 952 setCommandGateUsage(audioControl, true); // <rdar://8518215> 953 result = cg->runAction(removeUserClientAction, arg0, arg1, arg2, arg3); 954 setCommandGateUsage(audioControl, false); // <rdar://8518215> 955 } else { 956 result = kIOReturnError; 957 } 958 } 959 } 960 961 return result; 962} 963 964IOReturn IOAudioControl::removeUserClientAction(OSObject *owner, void *arg1, void *arg2, void *arg3, void *arg4) 965{ 966 IOReturn result = kIOReturnBadArgument; 967 968 if (owner) { 969 IOAudioControl *audioControl = OSDynamicCast(IOAudioControl, owner); 970 if (audioControl) { 971 result = audioControl->removeUserClient((IOAudioControlUserClient *)arg1); 972 } 973 } 974 975 return result; 976} 977 978IOReturn IOAudioControl::detachUserClientsAction(OSObject *owner, void *arg1, void *arg2, void *arg3, void *arg4) 979{ 980 IOReturn result = kIOReturnBadArgument; 981 982 if (owner) { 983 IOAudioControl *audioControl = OSDynamicCast(IOAudioControl, owner); 984 if (audioControl) { 985 result = audioControl->detachUserClients(); 986 } 987 } 988 989 return result; 990} 991 992IOReturn IOAudioControl::addUserClient(IOAudioControlUserClient *newUserClient) 993{ 994 IOReturn result = kIOReturnSuccess; // <rdar://8370885> 995 996 audioDebugIOLog(3, "+ IOAudioControl[%p]::addUserClient(%p)\n", this, newUserClient); 997 998 assert(userClients); 999 1000 // <rdar://8370885> 1001 if (!isInactive()) { 1002 if (!newUserClient->attach(this)) { 1003 result = kIOReturnError; 1004 } else if (!newUserClient->start(this) || !userClients) { 1005 newUserClient->detach(this); 1006 result = kIOReturnError; 1007 } else { 1008 userClients->setObject(newUserClient); 1009 } 1010 } else { 1011 result = kIOReturnNoDevice; 1012 } 1013 1014 audioDebugIOLog(3, "- IOAudioControl[%p]::addUserClient(%p) returns 0x%lX\n", this, newUserClient, (long unsigned int)kIOReturnSuccess ); 1015 return result; // <rdar://8370885> 1016} 1017 1018IOReturn IOAudioControl::removeUserClient(IOAudioControlUserClient *userClient) 1019{ 1020 audioDebugIOLog(3, "+ IOAudioControl[%p]::removeUserClient(%p)\n", this, userClient); 1021 1022 assert(userClients); 1023 1024 userClient->retain(); 1025 1026 userClients->removeObject(userClient); 1027 1028 if (!isInactive()) { 1029 userClient->terminate(); 1030 } 1031 1032 userClient->release(); 1033 1034 audioDebugIOLog(3, "- IOAudioControl[%p]::removeUserClient(%p) returns 0x%lX\n", this, userClient, (long unsigned int)kIOReturnSuccess ); 1035 return kIOReturnSuccess; 1036} 1037 1038IOReturn IOAudioControl::detachUserClients() 1039{ 1040 IOReturn result = kIOReturnSuccess; 1041 1042 audioDebugIOLog(3, "+ IOAudioControl[%p]::detachUserClients()\n", this); 1043 1044 assert(userClients); 1045 1046 if (!isInactive()) { 1047 OSIterator *iterator; 1048 1049 iterator = OSCollectionIterator::withCollection(userClients); 1050 1051 if (iterator) { 1052 IOAudioControlUserClient *userClient; 1053 1054 while ( (userClient = (IOAudioControlUserClient *)iterator->getNextObject()) ) { 1055 userClient->terminate(); 1056 } 1057 1058 iterator->release(); 1059 } 1060 } 1061 1062 userClients->flushCollection(); 1063 1064 audioDebugIOLog(3, "- IOAudioControl[%p]::detachUserClients() returns 0x%lX\n", this, (long unsigned int)result ); 1065 return result; 1066} 1067 1068// <rdar://8518215> 1069void IOAudioControl::setCommandGateUsage(IOAudioControl *control, bool increment) 1070{ 1071 if (control->reserved) { 1072 if (increment) { 1073 switch (control->reserved->commandGateStatus) 1074 { 1075 case kCommandGateStatus_Normal: 1076 case kCommandGateStatus_RemovalPending: 1077 control->reserved->commandGateUsage++; 1078 break; 1079 case kCommandGateStatus_Invalid: 1080 // Should never be here. If so, something went bad... 1081 break; 1082 } 1083 } 1084 else { 1085 switch (control->reserved->commandGateStatus) 1086 { 1087 case kCommandGateStatus_Normal: 1088 if (control->reserved->commandGateUsage > 0) { 1089 control->reserved->commandGateUsage--; 1090 } 1091 break; 1092 case kCommandGateStatus_RemovalPending: 1093 if (control->reserved->commandGateUsage > 0) { 1094 control->reserved->commandGateUsage--; 1095 1096 if (control->reserved->commandGateUsage == 0) { 1097 control->reserved->commandGateStatus = kCommandGateStatus_Invalid; 1098 1099 if (control->commandGate) { 1100 if (control->workLoop) { 1101 control->workLoop->removeEventSource(control->commandGate); 1102 } 1103 1104 control->commandGate->release(); 1105 control->commandGate = NULL; 1106 } 1107 } 1108 } 1109 break; 1110 case kCommandGateStatus_Invalid: 1111 // Should never be here. If so, something went bad... 1112 break; 1113 } 1114 } 1115 } 1116} 1117 1118IOReturn IOAudioControl::setProperties(OSObject *properties) 1119{ 1120 OSDictionary *props; 1121 IOReturn result = kIOReturnSuccess; 1122 1123 if (properties && (props = OSDynamicCast(OSDictionary, properties))) { 1124 OSNumber *number = OSDynamicCast(OSNumber, props->getObject(kIOAudioControlValueKey)); 1125 1126 if (number) { 1127 if (workLoop) { // <rdar://7529580> 1128 result = workLoop->runAction(_setValueAction, this, (void *)number); // <rdar://7529580> 1129 } else { 1130 result = kIOReturnError; 1131 } 1132 } 1133 } else { 1134 result = kIOReturnBadArgument; 1135 } 1136 1137 return result; 1138} 1139