1/*
2 *
3 *  Created by jguyton on Sun Apr 01 2001.
4 *  Copyright (c) 2001 __CompanyName__. All rights reserved.
5 *
6 */
7
8#include "IrDAUser.h"
9#include "AppleIrDA.h"
10#include "IrDAComm.h"
11#include "IrDALog.h"
12#include "IrDADebugging.h"
13
14#define super   IOUserClient
15#undef ELG
16#define ELG(x,y,z,msg) ((void)0)
17
18OSDefineMetaClassAndStructors(IrDAUserClient, IOUserClient)
19
20/*static*/
21IrDAUserClient*
22IrDAUserClient::withTask(task_t owningTask)
23{
24    IrDAUserClient *client;
25    ELG(0, owningTask, 'irda', "IrDAUser: withTask");
26
27    client = new IrDAUserClient;
28
29    if (client != NULL) {
30	if (client->init() == false) {
31	    client->release();
32	    client = NULL;
33	}
34    }
35    if (client != NULL) {
36	client->fTask = owningTask;
37    }
38    return (client);
39}
40
41bool
42IrDAUserClient::start(IOService *provider)
43{
44    bool result = false;
45    ELG(0, 0, 'irda', "IrDAUser: start");
46
47    fDriver = OSDynamicCast(AppleIrDASerial, provider);
48
49    if (fDriver != NULL)
50	result = super::start(provider);
51    else
52	result = false;
53
54    if (result == false) {
55	IOLog("IrDAUserClient: provider start failed\n");
56    }
57    else {
58	// Initialize the call structure. The method with index
59	// kSerialDoOneTrial calls the doOneTrial method
60	// with two parameters, a scalar and a buffer pointer
61	// that doOneTrial will write to. A pointer to this
62	// method structure is returned to the kernel when the
63	// user executes io_connect_method_scalarI_structureO.
64	// Thie kernel uses it to dispatch the command to the
65	// driver (running in kernel space)
66
67	fMethods[0].object = this;
68	fMethods[0].func   = (IOMethod) &IrDAUserClient::userPostCommand;
69	fMethods[0].count0 = 0xFFFFFFFF;                /* One input as big as I need */
70	fMethods[0].count1 = 0xFFFFFFFF;                /* One output as big as I need */
71	fMethods[0].flags  = kIOUCStructIStructO;
72    }
73    return (result);
74}
75IOReturn
76IrDAUserClient::clientClose(void)
77{
78    ELG(0, 0, 'irda', "IrDAUser: client close");
79    detach(fDriver);
80    return (kIOReturnSuccess);
81}
82
83IOReturn
84IrDAUserClient::clientDied(void)
85{
86    ELG(0, 0, 'irda', "IrDAUser: client died");
87   return (clientClose());
88}
89
90IOReturn
91IrDAUserClient::connectClient(IOUserClient *client)
92{
93    ELG(0, 0, 'irda', "IrDAUser: connect client");
94    return (kIOReturnSuccess);
95}
96
97IOReturn
98IrDAUserClient::registerNotificationPort(mach_port_t port, UInt32 type)
99{
100    ELG(0, 0, 'irda', "IrDAUser: register notification ignored");
101    return (kIOReturnUnsupported);
102}
103
104IOExternalMethod *
105IrDAUserClient::getExternalMethodForIndex(UInt32 index)
106{
107    IOExternalMethod *result    = NULL;
108    ELG(0, index, 'irda', "IrDAUser: get external method");
109
110    if (index == 0) {
111	result = &fMethods[0];
112    }
113    return (result);
114}
115
116IOReturn
117IrDAUserClient::userPostCommand(void *pIn, void *pOut, IOByteCount inputSize, IOByteCount *outPutSize)
118{
119    // check first byte of input data for a command code
120    if (pIn && pOut && inputSize > 0) {
121	unsigned char *input = (unsigned char *)pIn;
122	switch(*input) {
123	    case kIrDAUserCmd_GetLog:
124		    return getIrDALog(pIn, pOut, inputSize, outPutSize);
125
126	    case kIrDAUserCmd_GetStatus:
127		    return getIrDAStatus(pIn, pOut, inputSize, outPutSize);
128
129	    case kIrDAUserCmd_Enable:
130		    return setIrDAState(true);
131
132	    case kIrDAUserCmd_Disable:
133		    return setIrDAState(false);
134
135	    default:
136		    IOLog("IrDA: Bad command to userPostCommand, %d\n", *input);
137	}
138    }
139    else IOLog("IrDA: pin/pout,size error\n");
140
141    return kIOReturnBadArgument;
142}
143
144// get irda log
145//
146// input is 9 bytes:
147//      command code (kIrDAUserCmd_GetLog)
148//      four bytes of buffer address
149//      four bytes of buffer size
150//
151// output set to IrDALogInfo record
152//      and buffer filled with log data
153
154IOReturn
155IrDAUserClient::getIrDALog(void *pIn, void *pOut, IOByteCount inputSize, IOByteCount *outPutSize)
156{
157#if (hasTracing > 0)
158
159    IOMemoryDescriptor *md;         // make a memory descriptor for the client's big buffer
160    unsigned char *input = (unsigned char *)pIn;
161    mach_vm_address_t bigaddr;
162    IOByteCount   biglen;
163    IrDALogInfo *info;
164
165    require(inputSize == 9, Fail);
166    require(outPutSize, Fail);
167    require(*outPutSize == sizeof(IrDALogInfo), Fail);
168
169    //bigaddr = input[1] << 24 | input[2] << 16 | input[3] << 8 | input[4];
170    //biglen  = input[5] << 24 | input[6] << 16 | input[7] << 8 | input[8];
171    bcopy(&input[1], &bigaddr, sizeof(bigaddr));
172    bcopy(&input[5], &biglen, sizeof(biglen));
173
174    //IOLog("biglen is %d\n", biglen);
175
176    // create and init the memory descriptor
177    //md = IOMemoryDescriptor::withAddress(bigaddr, biglen, kIODirectionOutIn, fTask);        // REVIEW direction
178    //use withAddressRange() and prepare() instead
179    md = IOMemoryDescriptor::withAddressRange(bigaddr, biglen, kIODirectionOutIn, fTask);        // REVIEW direction
180    md->prepare(kIODirectionOutIn);
181
182    require(md, Fail);
183
184    info = IrDALogGetInfo();        // get the info block
185
186    //ELG(info->hdr,       info->hdrSize,       'irda', "info hdr");
187    //ELG(info->eventLog,  info->eventLogSize,  'irda', "info events");
188    //ELG(info->msgBuffer, info->msgBufferSize, 'irda', "info msg buf");
189
190    bcopy(info, pOut, sizeof(*info));       // copy the info record back to the client
191    *outPutSize = sizeof(*info);            // set the output size (nop, it already is)
192
193    // copy the buffer over now if there is room
194    if (biglen >= info->hdrSize + info->eventLogSize + info->msgBufferSize) {
195	IOByteCount ct;
196	IOReturn rc;
197
198	rc = md->prepare(kIODirectionNone);
199	if (rc)  {ELG(-1, rc, 'irda', "prepare failed"); }
200
201	ct = md->writeBytes(0,                              info->hdr,       info->hdrSize);
202	if (ct != info->hdrSize) ELG(-1, rc, 'irda', "write of hdr failed");
203
204	ct = md->writeBytes(info->hdrSize,                   info->eventLog,  info->eventLogSize);
205	if (ct != info->eventLogSize) ELG(-1, rc, 'irda', "write of events failed");
206
207	ct = md->writeBytes(info->hdrSize+info->eventLogSize, info->msgBuffer, info->msgBufferSize);
208	if (ct != info->msgBufferSize) ELG(-1, rc, 'irda', "write of msgs failed");
209
210	ELG(0, info->hdrSize+info->eventLogSize, 'irda', "wrote msgs at offset");
211
212	rc = md->complete(kIODirectionNone);
213	if (!rc) { ELG(0, 0, 'irda', "complete worked"); }
214	else    { ELG(-1, rc, 'irda', "complete failed"); }
215
216	// todo check return code of above before resetting the buffer
217	IrDALogReset();     // reset the buffer now
218    }
219    md->release();  // free it
220
221    return kIOReturnSuccess;
222
223
224Fail:
225
226#endif          // hasTracing > 0
227
228    return kIOReturnBadArgument;
229}
230
231// get irda status
232//
233// input: just the command byte
234// output: status buffer returned directly to pOut
235
236IOReturn
237IrDAUserClient::getIrDAStatus(void *pIn, void *pOut, IOByteCount inputSize, IOByteCount *outPutSize)
238{
239    IrDAComm *irda;
240
241    require(*outPutSize == sizeof(IrDAStatus), Fail);
242    require(fDriver, Fail);
243
244	bzero(pOut, sizeof(IrDAStatus));
245
246    irda = fDriver->GetIrDAComm();
247	if (irda)                               // sometimes IrDA may not be there
248	    irda->GetIrDAStatus((IrDAStatus *)pOut);
249
250    fDriver->GetIrDAStatus((IrDAStatus *)pOut);
251    return kIOReturnSuccess;
252
253Fail:
254    IOLog("IrDA: Failing to get status\n");
255    return kIOReturnBadArgument;
256}
257
258// set irda state
259//
260// input: just the state (true = on, false = off)
261// output: none
262
263IOReturn
264IrDAUserClient::setIrDAState(bool state)
265{
266    IOReturn    rtn = kIOReturnSuccess;
267
268    require(fDriver, Fail);
269
270    rtn = fDriver->SetIrDAUserClientState(state);
271    return rtn;
272
273Fail:
274    IOLog("IrDA: Failing to set IrDA state\n");
275    return kIOReturnBadArgument;
276}
277