1/*
2 * Copyright (c) 1998-2000 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 <IOKit/IOLib.h>
24#include <IOKit/IOUserClient.h>
25#include <IOKit/IOLocks.h>
26#include <IOKit/pwr_mgt/RootDomain.h>
27#include <IOKit/ndrvsupport/IONDRVFramebuffer.h>
28#include <IOKit/assert.h>
29#include <libkern/c++/OSContainers.h>
30
31#include <IOKit/i2c/IOI2CInterfacePrivate.h>
32
33/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
34
35#undef super
36#define super IOService
37
38OSDefineMetaClassAndAbstractStructors(IOI2CInterface, IOService)
39
40/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
41
42bool IOI2CInterface::registerI2C( UInt64 id )
43{
44    bool result = true;
45
46    fID = id;
47
48    setProperty(kIOI2CInterfaceIDKey, id, 64);
49
50    registerService();
51
52    return (result);
53}
54
55IOReturn IOI2CInterface::newUserClient( task_t          owningTask,
56                                        void *          security_id,
57                                        UInt32          type,
58                                        IOUserClient ** handler )
59
60{
61    IOReturn            err = kIOReturnSuccess;
62    IOUserClient *      newConnect = 0;
63
64    if (type)
65        return (kIOReturnBadArgument);
66
67    newConnect = IOI2CInterfaceUserClient::withTask(owningTask);
68
69    if (newConnect)
70    {
71        if (!newConnect->attach(this)
72                || !newConnect->start(this))
73        {
74            newConnect->detach( this );
75            newConnect->release();
76            newConnect = 0;
77        }
78    }
79
80    *handler = newConnect;
81
82    return (err);
83}
84
85/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
86
87#undef super
88#define super IOUserClient
89
90OSDefineMetaClassAndStructors(IOI2CInterfaceUserClient, IOUserClient)
91
92/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
93
94IOI2CInterfaceUserClient * IOI2CInterfaceUserClient::withTask( task_t owningTask )
95{
96    IOI2CInterfaceUserClient * inst;
97
98    inst = new IOI2CInterfaceUserClient;
99    if (inst && !inst->init())
100    {
101        inst->release();
102        inst = 0;
103    }
104    if (inst)
105        inst->fTask = owningTask;
106
107    return (inst);
108}
109
110bool IOI2CInterfaceUserClient::start( IOService * provider )
111{
112    if (!super::start(provider))
113        return (false);
114
115    return (true);
116}
117
118IOReturn IOI2CInterfaceUserClient::clientClose( void )
119{
120    terminate();
121    return (kIOReturnSuccess);
122}
123
124IOService * IOI2CInterfaceUserClient::getService( void )
125{
126    return (getProvider());
127}
128
129IOExternalMethod * IOI2CInterfaceUserClient::getTargetAndMethodForIndex(
130    IOService ** targetP, UInt32 index )
131{
132    static const IOExternalMethod methodTemplate[] = {
133                /* 0 */  { NULL, (IOMethod) &IOI2CInterfaceUserClient::extAcquireBus,
134                           kIOUCScalarIScalarO, 0, 0 },
135                /* 1 */  { NULL, (IOMethod) &IOI2CInterfaceUserClient::extReleaseBus,
136                           kIOUCScalarIScalarO, 0, 0 },
137                /* 3 */  { NULL, (IOMethod) &IOI2CInterfaceUserClient::extIO,
138                           kIOUCStructIStructO, 0xffffffff, 0xffffffff },
139            };
140
141    if (index > (sizeof(methodTemplate) / sizeof(methodTemplate[0])))
142        return (NULL);
143
144    *targetP = this;
145    return ((IOExternalMethod *)(methodTemplate + index));
146}
147
148IOReturn IOI2CInterfaceUserClient::setProperties( OSObject * properties )
149{
150    return (kIOReturnUnsupported);
151}
152
153IOReturn IOI2CInterfaceUserClient::extAcquireBus( void )
154{
155    IOReturn            ret = kIOReturnNotReady;
156    IOI2CInterface *    provider;
157
158    if ((provider = (IOI2CInterface *) copyParentEntry(gIOServicePlane)))
159    {
160        ret = provider->open( this ) ? kIOReturnSuccess : kIOReturnBusy;
161        provider->release();
162    }
163
164    return (ret);
165}
166
167IOReturn IOI2CInterfaceUserClient::extReleaseBus( void )
168{
169    IOReturn            ret = kIOReturnNotReady;
170    IOI2CInterface *    provider;
171
172    if ((provider = (IOI2CInterface *) copyParentEntry(gIOServicePlane)))
173    {
174        provider->close( this );
175        provider->release();
176        ret = kIOReturnSuccess;
177    }
178
179    return (ret);
180}
181
182IOReturn IOI2CInterfaceUserClient::extIO(
183    void * inStruct, void * outStruct,
184    IOByteCount inSize, IOByteCount * outSize )
185{
186    IOReturn            err = kIOReturnNotReady;
187    IOI2CInterface *    provider;
188    IOI2CBuffer *       buffer;
189
190    IOI2CRequest *                request;
191    IOI2CRequest_10_5_0 * requestV1 = NULL;
192    IOI2CRequest          requestV2;
193
194    if (inSize < sizeof(IOI2CBuffer))
195        return (kIOReturnNoSpace);
196    if (*outSize < inSize)
197        return (kIOReturnNoSpace);
198
199        buffer = (IOI2CBuffer *) inStruct;
200        request = &buffer->request;
201
202        if (!request->sendTransactionType && !request->replyTransactionType)
203        {
204                requestV1 = (typeof (requestV1)) &buffer->request;
205                bzero(&requestV2, sizeof(requestV2));
206                request = &requestV2;
207
208                request->sendTransactionType  = requestV1->sendTransactionType;
209                request->replyTransactionType = requestV1->replyTransactionType;
210                request->sendAddress          = requestV1->sendAddress;
211                request->replyAddress         = requestV1->replyAddress;
212                request->sendBytes            = requestV1->sendBytes;
213                request->replyBytes           = requestV1->replyBytes;
214                request->sendSubAddress       = requestV1->sendSubAddress;
215                request->replySubAddress      = requestV1->replySubAddress;
216                request->commFlags            = requestV1->commFlags;
217                request->minReplyDelay        = requestV1->minReplyDelay;
218        }
219
220    if ((provider = (IOI2CInterface *) copyParentEntry(gIOServicePlane)))
221        do
222        {
223            if (!provider->isOpen(this))
224            {
225                err = kIOReturnNotOpen;
226                continue;
227            }
228
229            if (request->sendBytes)
230            {
231                if (!request->sendBuffer)
232                    request->sendBuffer = (vm_address_t)  &buffer->inlineBuffer[0];
233                else
234                {
235                    err = kIOReturnMessageTooLarge;
236                    continue;
237                }
238            }
239            if (request->replyBytes)
240            {
241                if (!request->replyBuffer)
242                    request->replyBuffer = (vm_address_t) &buffer->inlineBuffer[0];
243                else
244                {
245                    err = kIOReturnMessageTooLarge;
246                    continue;
247                }
248            }
249
250            err = provider->startIO( request );
251
252                        if (requestV1)
253                                requestV1->result = request->result;
254        }
255        while (false);
256
257    if (provider)
258        provider->release();
259
260    if (kIOReturnSuccess == err)
261    {
262        *outSize = inSize;
263        bcopy(inStruct, outStruct, inSize);
264    }
265    else
266        *outSize = 0;
267
268    return (err);
269}
270
271/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
272
273
274