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