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 "IOAudioControlUserClient.h"
25#include "IOAudioControl.h"
26#include "IOAudioTypes.h"
27#include "IOAudioDefines.h"
28
29#include <IOKit/IOLib.h>
30#include <IOKit/IOCommandGate.h>
31#include <IOKit/IOKitKeys.h>
32
33#define super IOUserClient
34
35OSDefineMetaClassAndStructors(IOAudioControlUserClient, IOUserClient)
36OSMetaClassDefineReservedUsed(IOAudioControlUserClient, 0);
37OSMetaClassDefineReservedUsed(IOAudioControlUserClient, 1);
38
39OSMetaClassDefineReservedUnused(IOAudioControlUserClient, 2);
40OSMetaClassDefineReservedUnused(IOAudioControlUserClient, 3);
41OSMetaClassDefineReservedUnused(IOAudioControlUserClient, 4);
42OSMetaClassDefineReservedUnused(IOAudioControlUserClient, 5);
43OSMetaClassDefineReservedUnused(IOAudioControlUserClient, 6);
44OSMetaClassDefineReservedUnused(IOAudioControlUserClient, 7);
45OSMetaClassDefineReservedUnused(IOAudioControlUserClient, 8);
46OSMetaClassDefineReservedUnused(IOAudioControlUserClient, 9);
47OSMetaClassDefineReservedUnused(IOAudioControlUserClient, 10);
48OSMetaClassDefineReservedUnused(IOAudioControlUserClient, 11);
49OSMetaClassDefineReservedUnused(IOAudioControlUserClient, 12);
50OSMetaClassDefineReservedUnused(IOAudioControlUserClient, 13);
51OSMetaClassDefineReservedUnused(IOAudioControlUserClient, 14);
52OSMetaClassDefineReservedUnused(IOAudioControlUserClient, 15);
53
54// New code here
55
56// OSMetaClassDefineReservedUsed(IOAudioControlUserClient, 1);
57bool IOAudioControlUserClient::initWithAudioControl(IOAudioControl *control, task_t task, void *securityID, UInt32 type, OSDictionary *properties)
58{
59	// Declare Rosetta compatibility
60	if (properties) {
61		properties->setObject(kIOUserClientCrossEndianCompatibleKey, kOSBooleanTrue);
62	}
63
64    if (!initWithTask(task, securityID, type, properties)) {
65        return false;
66    }
67/*
68	// For 3019260
69	if (clientHasPrivilege(securityID, kIOClientPrivilegeLocalUser)) {
70		// You don't have enough privileges to control the audio
71		return false;
72	}
73*/
74    if (!control) {
75        return false;
76    }
77
78    audioControl = control;
79	audioControl->retain();
80    clientTask = task;
81    notificationMessage = 0;
82
83    return true;
84}
85
86// OSMetaClassDefineReservedUsed(IOAudioControlUserClient, 0);
87void IOAudioControlUserClient::sendChangeNotification(UInt32 notificationType)
88{
89    if (notificationMessage) {
90        kern_return_t kr;
91
92		notificationMessage->type = notificationType;
93        kr = mach_msg_send_from_kernel(&notificationMessage->messageHeader, notificationMessage->messageHeader.msgh_size);
94        if ((kr != MACH_MSG_SUCCESS) && (kr != MACH_SEND_TIMED_OUT)) {
95            IOLog("IOAudioControlUserClient: sendRangeChangeNotification() failed - msg_send returned: %d\n", kr);
96        }
97    }
98}
99
100IOAudioControlUserClient *IOAudioControlUserClient::withAudioControl(IOAudioControl *control, task_t clientTask, void *securityID, UInt32 type, OSDictionary *properties)
101{
102    IOAudioControlUserClient *client;
103
104    client = new IOAudioControlUserClient;
105
106    if (client) {
107        if (!client->initWithAudioControl(control, clientTask, securityID, type, properties)) {
108            client->release();
109            client = 0;
110        }
111    }
112
113    return client;
114}
115
116// Original code here...
117IOAudioControlUserClient *IOAudioControlUserClient::withAudioControl(IOAudioControl *control, task_t clientTask, void *securityID, UInt32 type)
118{
119    IOAudioControlUserClient *client;
120
121    client = new IOAudioControlUserClient;
122
123    if (client) {
124        if (!client->initWithAudioControl(control, clientTask, securityID, type)) {
125            client->release();
126            client = 0;
127        }
128    }
129
130    return client;
131}
132
133bool IOAudioControlUserClient::initWithAudioControl(IOAudioControl *control, task_t task, void *securityID, UInt32 type)
134{
135    if (!initWithTask(task, securityID, type)) {
136        return false;
137    }
138/*
139	// For 3019260
140	if (clientHasPrivilege(securityID, kIOClientPrivilegeLocalUser)) {
141		// You don't have enough privileges to control the audio
142		return false;
143	}
144*/
145    if (!control) {
146        return false;
147    }
148
149    audioControl = control;
150	audioControl->retain();
151    clientTask = task;
152    notificationMessage = 0;
153
154    return true;
155}
156
157void IOAudioControlUserClient::free()
158{
159    audioDebugIOLog(3, "+ IOAudioControlUserClient[%p]::free()\n", this);
160
161    if (notificationMessage) {
162        IOFreeAligned(notificationMessage, sizeof(IOAudioNotificationMessage));
163        notificationMessage = 0;
164    }
165
166	if (audioControl) {
167		audioControl->release ();
168		audioControl = 0;
169	}
170
171	if (reserved) {
172		IOFree (reserved, sizeof(struct ExpansionData));
173	}
174
175    super::free();
176    audioDebugIOLog(3, "- IOAudioControlUserClient[%p]::free()\n", this);
177}
178
179IOReturn IOAudioControlUserClient::clientClose()
180{
181    audioDebugIOLog(3, "+ IOAudioControlUserClient[%p]::clientClose()\n", this);
182
183    if (audioControl) {
184		if (!audioControl->isInactive () && !isInactive()) {
185			audioControl->clientClosed(this);
186		}
187		audioControl->release();
188        audioControl = 0;
189    }
190
191    audioDebugIOLog(3, "- IOAudioControlUserClient[%p]::clientClose() returns 0x%lX\n", this, (long unsigned int)kIOReturnSuccess );
192    return kIOReturnSuccess;
193}
194
195IOReturn IOAudioControlUserClient::clientDied()
196{
197	IOReturn			result = kIOReturnError;
198
199    audioDebugIOLog(3, "+ IOAudioControlUserClient[%p]::clientDied()\n", this);
200
201    result =  clientClose();
202
203    audioDebugIOLog(3, "- IOAudioControlUserClient[%p]::clientDied() returns 0x%lX\n", this, (long unsigned int)result );
204	return result;
205}
206
207IOReturn IOAudioControlUserClient::registerNotificationPort(mach_port_t port,
208                                                            UInt32 type,			// No longer used now that we have the generic sendChangeNotification routine
209                                                            UInt32 refCon)
210{
211    IOReturn result = kIOReturnSuccess;
212
213    if (!isInactive()) {
214        if (notificationMessage == 0) {
215            notificationMessage = (IOAudioNotificationMessage *)IOMallocAligned(sizeof(IOAudioNotificationMessage), sizeof (IOAudioNotificationMessage *));
216            if (!notificationMessage) {
217                return kIOReturnNoMemory;
218            }
219        }
220
221        notificationMessage->messageHeader.msgh_bits = MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND, 0);
222        notificationMessage->messageHeader.msgh_size = sizeof(IOAudioNotificationMessage);
223        notificationMessage->messageHeader.msgh_remote_port = port;
224        notificationMessage->messageHeader.msgh_local_port = MACH_PORT_NULL;
225        notificationMessage->messageHeader.msgh_reserved = 0;
226        notificationMessage->messageHeader.msgh_id = 0;
227
228        // notificationMessage->type = type;				// ignored now that we have the generic sendChangeNotification routine
229        notificationMessage->ref = refCon;
230    } else {
231        result = kIOReturnNoDevice;
232    }
233
234    return result;
235}
236
237void IOAudioControlUserClient::sendValueChangeNotification()
238{
239	return sendChangeNotification(kIOAudioControlValueChangeNotification);
240}
241