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 "IOAudioPort.h"
24#include "IOAudioControl.h"
25#include "IOAudioDevice.h"
26#include "IOAudioTypes.h"
27#include "IOAudioDefines.h"
28#include "IOAudioDebug.h"
29#include "AudioTracepoints.h"
30
31#include <libkern/c++/OSSet.h>
32#include <libkern/c++/OSCollectionIterator.h>
33
34#include <IOKit/IOLib.h>
35
36#define super IOService
37
38OSDefineMetaClassAndStructors(IOAudioPort, IOService)
39OSMetaClassDefineReservedUnused(IOAudioPort, 0);
40OSMetaClassDefineReservedUnused(IOAudioPort, 1);
41OSMetaClassDefineReservedUnused(IOAudioPort, 2);
42OSMetaClassDefineReservedUnused(IOAudioPort, 3);
43OSMetaClassDefineReservedUnused(IOAudioPort, 4);
44OSMetaClassDefineReservedUnused(IOAudioPort, 5);
45OSMetaClassDefineReservedUnused(IOAudioPort, 6);
46OSMetaClassDefineReservedUnused(IOAudioPort, 7);
47OSMetaClassDefineReservedUnused(IOAudioPort, 8);
48OSMetaClassDefineReservedUnused(IOAudioPort, 9);
49OSMetaClassDefineReservedUnused(IOAudioPort, 10);
50OSMetaClassDefineReservedUnused(IOAudioPort, 11);
51OSMetaClassDefineReservedUnused(IOAudioPort, 12);
52OSMetaClassDefineReservedUnused(IOAudioPort, 13);
53OSMetaClassDefineReservedUnused(IOAudioPort, 14);
54OSMetaClassDefineReservedUnused(IOAudioPort, 15);
55OSMetaClassDefineReservedUnused(IOAudioPort, 16);
56OSMetaClassDefineReservedUnused(IOAudioPort, 17);
57OSMetaClassDefineReservedUnused(IOAudioPort, 18);
58OSMetaClassDefineReservedUnused(IOAudioPort, 19);
59OSMetaClassDefineReservedUnused(IOAudioPort, 20);
60OSMetaClassDefineReservedUnused(IOAudioPort, 21);
61OSMetaClassDefineReservedUnused(IOAudioPort, 22);
62OSMetaClassDefineReservedUnused(IOAudioPort, 23);
63OSMetaClassDefineReservedUnused(IOAudioPort, 24);
64OSMetaClassDefineReservedUnused(IOAudioPort, 25);
65OSMetaClassDefineReservedUnused(IOAudioPort, 26);
66OSMetaClassDefineReservedUnused(IOAudioPort, 27);
67OSMetaClassDefineReservedUnused(IOAudioPort, 28);
68OSMetaClassDefineReservedUnused(IOAudioPort, 29);
69OSMetaClassDefineReservedUnused(IOAudioPort, 30);
70OSMetaClassDefineReservedUnused(IOAudioPort, 31);
71
72IOAudioPort *IOAudioPort::withAttributes(UInt32 portType, const char *portName, UInt32 subType, OSDictionary *properties)
73{
74    IOAudioPort *port;
75
76    port = new IOAudioPort;
77    if (port) {
78        if (!port->initWithAttributes(portType, portName, subType, properties)) {
79            port->release();
80            port = 0;
81        }
82    }
83
84    return port;
85}
86
87bool IOAudioPort::initWithAttributes(UInt32 portType, const char *portName, UInt32 subType, OSDictionary *properties)
88{
89    if (!init(properties)) {
90        return false;
91    }
92
93    if (portType == 0) {
94        return false;
95    }
96
97    audioDevice = 0;
98    isRegistered = false;
99
100    setType(portType);
101
102    if (portName != 0) {
103        setName(portName);
104    }
105
106    if (subType != 0) {
107        setSubType(subType);
108    }
109
110    audioControls = OSSet::withCapacity(1);
111    if (!audioControls) {
112        return false;
113    }
114
115    return true;
116}
117
118void IOAudioPort::free()
119{
120    if (audioControls) {
121        audioControls->release();
122    }
123
124    super::free();
125}
126
127void IOAudioPort::setType(UInt32 portType)
128{
129    setProperty(kIOAudioPortTypeKey, portType, sizeof(UInt32)*8);
130}
131
132void IOAudioPort::setSubType(UInt32 subType)
133{
134    setProperty(kIOAudioPortSubTypeKey, subType, sizeof(UInt32)*8);
135}
136
137void IOAudioPort::setName(const char *portName)
138{
139    setProperty(kIOAudioPortNameKey, portName);
140}
141
142bool IOAudioPort::start(IOService *provider)
143{
144    AudioTrace_Start(kAudioTIOAudioPort, kTPIOAudioPortStart, (uintptr_t)this, (uintptr_t)provider, 0, 0);
145    if (!super::start(provider)) {
146        return false;
147    }
148
149    if (!(audioDevice = OSDynamicCast(IOAudioDevice, provider))) {
150        return false;
151    }
152
153    AudioTrace_End(kAudioTIOAudioPort, kTPIOAudioPortStart, (uintptr_t)this, (uintptr_t)provider, true, 0);
154    return true;
155}
156
157void IOAudioPort::stop(IOService *provider)
158{
159    deactivateAudioControls();
160    super::stop(provider);
161}
162
163void IOAudioPort::registerService(IOOptionBits options)
164{
165    super::registerService(options);
166
167    if (audioControls && !isRegistered) {
168        OSCollectionIterator *iterator;
169
170        iterator = OSCollectionIterator::withCollection(audioControls);
171	if (iterator) {
172            IOAudioControl *control;
173
174            while ( (control = (IOAudioControl *)iterator->getNextObject()) ) {
175                if (control->getProvider() == this) {
176                    control->registerService();
177                }
178            }
179            iterator->release();
180	}
181    }
182
183    isRegistered = true;
184}
185
186IOAudioDevice *IOAudioPort::getAudioDevice()
187{
188    return audioDevice;
189}
190
191IOReturn IOAudioPort::addAudioControl(IOAudioControl *control)
192{
193    bool controlWasStarted;
194
195    if (!control || !audioControls) {
196        return kIOReturnBadArgument;
197    }
198
199    if (!control->attach(this)) {
200        return kIOReturnError;
201    }
202
203    controlWasStarted = control->getIsStarted();
204
205    if (!controlWasStarted) {
206        if (!control->start(this)) {
207            control->detach(this);
208            return kIOReturnError;
209        }
210    }
211
212    audioControls->setObject(control);
213
214    if (isRegistered && !controlWasStarted) {
215        control->registerService();
216    }
217
218    return kIOReturnSuccess;
219}
220
221void IOAudioPort::deactivateAudioControls()
222{
223    OSCollectionIterator *iterator;
224
225    if (!audioControls) {
226        return;
227    }
228
229    iterator = OSCollectionIterator::withCollection(audioControls);
230
231    if (iterator) {
232        IOAudioControl *control;
233
234        while ( (control = (IOAudioControl *)iterator->getNextObject()) ) {
235            // Should we check to see if we're the provider?
236            if (!isInactive()) {
237                control->terminate();
238            }
239        }
240
241        iterator->release();
242    }
243
244    audioControls->flushCollection();
245}
246