1/*
2 * Copyright (c) 1998-2000 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
11 * file.
12 *
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23/*
24 * Copyright (c) 1999 Apple Computer, Inc.  All rights reserved.
25 *
26 */
27
28#include <sys/systm.h>
29#include <sys/proc.h>
30#include <kern/task.h>
31#include "AppleSmartBatteryManagerUserClient.h"
32
33#define super IOUserClient
34
35enum {
36    kCallOnOwner = 0,
37    kCallOnSelf = 1
38};
39
40
41/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
42
43OSDefineMetaClassAndStructors(AppleSmartBatteryManagerUserClient, IOUserClient)
44
45/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
46
47bool AppleSmartBatteryManagerUserClient::initWithTask(task_t owningTask,
48                    void *security_id, UInt32 type, OSDictionary * properties)
49{
50    uint32_t            _pid;
51
52     /* 1. Only root processes may open a SmartBatteryManagerUserClient.
53      * 2. Attempts to create exclusive UserClients will fail if an
54      *     exclusive user client is attached.
55      * 3. Non-exclusive clients will not be able to perform transactions
56      *     while an exclusive client is attached.
57      * 3a. Only battery firmware updaters should bother being exclusive.
58      */
59    if ( kIOReturnSuccess !=
60            clientHasPrivilege(owningTask, kIOClientPrivilegeAdministrator))
61    {
62        return false;
63    }
64
65    if (!super::initWithTask(owningTask, security_id, type, properties)) {
66        return false;
67    }
68
69    fUserClientType = type;
70
71	_pid = proc_selfpid();
72	setProperty("pid", _pid, 32);
73
74    fOwningTask = owningTask;
75    task_reference (fOwningTask);
76    return true;
77}
78
79
80bool AppleSmartBatteryManagerUserClient::start( IOService * provider )
81{
82    fOwner = (AppleSmartBatteryManager *)provider;
83
84    /*
85     * exclusive access user client?
86     * shut up the AppleSmartBattery from doing ongoing polls
87     *
88     */
89    if (kSBExclusiveSMBusAccessType == fUserClientType)
90    {
91        if(!fOwner->requestExclusiveSMBusAccess(true)) {
92            // requestExclusiveSMBusAccess will return false if there's already
93            // an exclusive user client.
94            return false;
95        }
96    }
97
98    if(!super::start(provider))
99        return false;
100
101    return true;
102}
103
104IOReturn AppleSmartBatteryManagerUserClient::secureInflowDisable(
105    int level,
106    int *return_code)
107{
108    int             admin_priv = 0;
109    IOReturn        ret = kIOReturnNotPrivileged;
110
111    if( !(level == 0 || level == 1))
112    {
113        *return_code = kIOReturnBadArgument;
114        return kIOReturnSuccess;
115    }
116
117    ret = clientHasPrivilege(fOwningTask, kIOClientPrivilegeAdministrator);
118    admin_priv = (kIOReturnSuccess == ret);
119
120    if(admin_priv && fOwner) {
121        *return_code = fOwner->disableInflow( level );
122        return kIOReturnSuccess;
123    } else {
124        *return_code = kIOReturnNotPrivileged;
125        return kIOReturnSuccess;
126    }
127
128}
129
130IOReturn AppleSmartBatteryManagerUserClient::secureChargeInhibit(
131    int level,
132    int *return_code)
133{
134    int             admin_priv = 0;
135    IOReturn        ret = kIOReturnNotPrivileged;
136
137    if( !(level == 0 || level == 1))
138    {
139        *return_code = kIOReturnBadArgument;
140        return kIOReturnSuccess;
141    }
142
143    ret = clientHasPrivilege(fOwningTask, kIOClientPrivilegeAdministrator);
144    admin_priv = (kIOReturnSuccess == ret);
145
146    if(admin_priv && fOwner) {
147        *return_code = fOwner->inhibitCharging(level);
148        return kIOReturnSuccess;
149    } else {
150        *return_code = kIOReturnNotPrivileged;
151        return kIOReturnSuccess;
152    }
153
154}
155
156
157IOReturn AppleSmartBatteryManagerUserClient::clientClose( void )
158{
159    /* remove our request for exclusive SMBus access */
160    if (kSBExclusiveSMBusAccessType == fUserClientType) {
161        fOwner->requestExclusiveSMBusAccess(false);
162    }
163
164    detach(fOwner);
165
166    if(fOwningTask) {
167        task_deallocate(fOwningTask);
168        fOwningTask = 0;
169    }
170
171    // We only have one application client. If the app is closed,
172    // we can terminate the user client.
173    terminate();
174
175    return kIOReturnSuccess;
176}
177
178IOReturn
179AppleSmartBatteryManagerUserClient::externalMethod(
180    uint32_t selector,
181    IOExternalMethodArguments * arguments,
182    IOExternalMethodDispatch * dispatch __unused,
183    OSObject * target __unused,
184    void * reference __unused )
185{
186    if (selector >= kNumBattMethods) {
187        // Invalid selector
188        return kIOReturnBadArgument;
189    }
190
191    switch (selector)
192    {
193        case kSBInflowDisable:
194            // 1 scalar in, 1 scalar out
195            return this->secureInflowDisable((int)arguments->scalarInput[0],
196                                            (int *)&arguments->scalarOutput[0]);
197            break;
198
199        case kSBChargeInhibit:
200            // 1 scalar in, 1 scalar out
201            return this->secureChargeInhibit((int)arguments->scalarInput[0],
202                                            (int *)&arguments->scalarOutput[0]);
203            break;
204
205        case kSBSetPollingInterval:
206            // Deprecated. AppleSmartBattery doesn't have a polling interval.
207            return kIOReturnBadArgument;
208
209        case kSBSMBusReadWriteWord:
210            if ((kSBExclusiveSMBusAccessType != fUserClientType) && fOwner->hasExclusiveClient())
211            {
212                /* SmartBatteryManager should not perform this request if there's an exclusive client
213                 * attached, and this client isn't the exclusive client. */
214                return kIOReturnSuccess;
215            }
216            // Struct in, struct out
217            return fOwner->performExternalTransaction(
218                                            (void *)arguments->structureInput,
219                                            (void *)arguments->structureOutput,
220                                            (IOByteCount)arguments->structureInputSize,
221                                            (IOByteCount *)&arguments->structureOutputSize);
222            break;
223
224        case kSBRequestPoll:
225            // 1 scalar in; 0 scalar out
226            return fOwner->requestPoll(arguments->scalarInput[0]);
227
228        default:
229            return kIOReturnBadArgument;
230    }
231}
232
233