1/*
2 *
3 * @APPLE_LICENSE_HEADER_START@
4 *
5 * Copyright (c) 1999-2009 Apple Computer, Inc.  All Rights Reserved.
6 *
7 * This file contains Original Code and/or Modifications of Original Code
8 * as defined in and that are subject to the Apple Public Source License
9 * Version 2.0 (the 'License'). You may not use this file except in
10 * compliance with the License. Please obtain a copy of the License at
11 * http://www.opensource.apple.com/apsl/ and read it before using this
12 * file.
13 *
14 * The Original Code and all software distributed under the License are
15 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
16 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
17 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
19 * Please see the License for the specific language governing rights and
20 * limitations under the License.
21 *
22 * @APPLE_LICENSE_HEADER_END@
23 */
24
25#include "IOHIDEventSystem.h"
26#include "IOHIDWorkLoop.h"
27
28
29typedef struct _EventServiceInfo
30{
31    IOHIDEventService * service;
32
33} EventServiceInfo, * EventServiceInfoRef;
34
35typedef struct _HIDEventArgs
36{
37    void *              refCon;
38    AbsoluteTime        timeStamp;
39    UInt32              eventCount;
40    IOHIDEvent *        events;
41    IOOptionBits        options;
42} HIDEventArgs, * HIDEventArgsRef;
43
44
45#define super IOService
46OSDefineMetaClassAndStructors(IOHIDEventSystem, IOService)
47
48
49//====================================================================================================
50// IOHIDEventService::init
51//====================================================================================================
52bool IOHIDEventSystem::init(OSDictionary * properties)
53{
54    if ( super::init(properties) == false )
55        return false;
56
57    _eventServiceInfoArray = OSArray::withCapacity(4);
58
59    return true;
60
61}
62
63//====================================================================================================
64// IOHIDEventService::start
65//====================================================================================================
66bool IOHIDEventSystem::start(IOService * provider)
67{
68    if ( super::start(provider) == false )
69        return false;
70
71    _workLoop       = IOHIDWorkLoop::workLoop();
72    _commandGate    = IOCommandGate::commandGate(this);
73
74    if ( !_workLoop || !_commandGate )
75        return false;
76
77    if ( _workLoop->addEventSource(_commandGate) != kIOReturnSuccess )
78        return false;
79
80    _publishNotify = addNotification(
81                        gIOPublishNotification,
82                        serviceMatching("IOHIDEventService"),
83                        OSMemberFunctionCast(IOServiceNotificationHandler, this, &IOHIDEventSystem::notificationHandler),
84                        this,
85                        (void *)OSMemberFunctionCast(IOCommandGate::Action, this, &IOHIDEventSystem::handleServicePublicationGated) );
86
87    _terminateNotify = addNotification(
88                        gIOTerminatedNotification,
89                        serviceMatching("IOHIDEventService"),
90                        OSMemberFunctionCast(IOServiceNotificationHandler, this, &IOHIDEventSystem::notificationHandler),
91                        this,
92                        (void *)OSMemberFunctionCast(IOCommandGate::Action, this, &IOHIDEventSystem::handleServiceTerminationGated) );
93
94    if (!_publishNotify || !_terminateNotify)
95        return false;
96
97    _eventsOpen = true;
98
99    registerService();
100
101    return true;
102}
103
104//====================================================================================================
105// IOHIDEventService::free
106//====================================================================================================
107void IOHIDEventSystem::free()
108{
109    if (workLoop) {
110        workLoop->disableAllEventSources();
111    }
112
113    if ( _publishNotify ) {
114        _publishNotify->remove();
115        _publishNotify = 0;
116    }
117
118    if ( _terminateNotify ) {
119        _terminateNotify->remove();
120        _terminateNotify = 0;
121    }
122
123    if ( _eventServiceInfoArray ) {
124        _eventServiceInfoArray->release();
125        _eventServiceInfoArray = 0;
126    }
127
128    if ( _commandGate ) {
129        _commandGate->release();
130        _commandGate = 0;
131    }
132
133    if ( _workLoop ) {
134        _workLoop->release();
135        _workLoop = 0;
136    }
137    super::free();
138}
139
140//====================================================================================================
141// IOHIDEventService::message
142//====================================================================================================
143IOReturn IOHIDEventSystem::message(UInt32 type, IOService * provider, void * argument)
144{
145    return super::message(type, provider, argument);
146}
147
148//====================================================================================================
149// IOHIDEventService::setProperties
150//====================================================================================================
151IOReturn IOHIDEventSystem::setProperties( OSObject * properties )
152{
153    return super::setProperties(properties);
154}
155
156//====================================================================================================
157// IOHIDEventService::notificationHandler
158//====================================================================================================
159bool IOHIDEventSystem::notificationHandler( void * refCon,  IOService * service )
160{
161    IOLog("IOHIDEventSystem::notificationHandler\n");
162
163    _commandGate->runAction((IOCommandGate::Action)refCon, service);
164
165    return true;
166}
167
168//====================================================================================================
169// IOHIDEventService::handleServicePublicationGated
170//====================================================================================================
171void IOHIDEventSystem::handleServicePublicationGated(IOService * service)
172{
173    IOLog("IOHIDEventSystem::handleServicePublicationGated\n");
174
175    EventServiceInfo    tempEventServiceInfo;
176    OSData *            tempData;
177    IOHIDEventService * eventService;
178
179    if ( !(eventService = OSDynamicCast(IOHIDEventService, service)) )
180        return;
181
182    attach( eventService );
183
184    tempEventServiceInfo.service = eventService;
185
186    tempData = OSData::withBytes(&tempEventServiceInfo, sizeof(EventServiceInfo));
187
188    if ( tempData )
189    {
190        _eventServiceInfoArray->setObject(tempData);
191        tempData->release();
192    }
193
194    if ( _eventsOpen )
195        registerEventSource( eventService );
196
197}
198
199//====================================================================================================
200// IOHIDEventService::handleServiceTerminationGated
201//====================================================================================================
202void IOHIDEventSystem::handleServiceTerminationGated(IOService * service)
203{
204    EventServiceInfoRef tempEventServiceInfoRef;
205    OSData *            tempData;
206    UInt32              index;
207
208    IOLog("IOHIDEventSystem::handleServiceTerminationGated\n");
209
210    if ( _eventsOpen )
211        service->close(this);
212
213    for ( index = 0; index<_eventServiceInfoArray->getCount(); index++ )
214    {
215        if ( (tempData = OSDynamicCast(OSData, _eventServiceInfoArray->getObject(index)))
216            && (tempEventServiceInfoRef = (EventServiceInfoRef)tempData->getBytesNoCopy())
217            && (tempEventServiceInfoRef->service == service) )
218        {
219            _eventServiceInfoArray->removeObject(index);
220            break;
221        }
222    }
223
224    detach(service);
225}
226
227//====================================================================================================
228// IOHIDEventService::registerEventSource
229//====================================================================================================
230void IOHIDEventSystem::registerEventSource(IOHIDEventService * service)
231{
232    EventServiceInfoRef tempEventServiceInfoRef;
233    OSData *            tempData = NULL;
234    UInt32              index;
235
236    IOLog("IOHIDEventSystem::registerEventSource\n");
237
238    for ( index = 0; index<_eventServiceInfoArray->getCount(); index++ )
239    {
240        if ( (tempData = OSDynamicCast(OSData, _eventServiceInfoArray->getObject(index)))
241            && (tempEventServiceInfoRef = (EventServiceInfoRef)tempData->getBytesNoCopy())
242            && (tempEventServiceInfoRef->service == service) )
243            break;
244
245        tempData = NULL;
246    }
247
248    service->open(this, 0, tempData,
249                OSMemberFunctionCast(IOHIDEventService::HIDEventCallback, this, &IOHIDEventSystem::handleHIDEvent));
250}
251
252
253//====================================================================================================
254// IOHIDEventService::handleHIDEvent
255//====================================================================================================
256void IOHIDEventSystem::handleHIDEvent(
257                            void *                          refCon,
258                            AbsoluteTime                    timeStamp,
259                            UInt32                          eventCount,
260                            IOHIDEvent *                    events,
261                            IOOptionBits                    options)
262{
263    IOLog("IOHIDEventSystem::handleHIDEvent\n");
264
265    HIDEventArgs args;
266
267    args.refCon     = refCon;
268    args.timeStamp  = timeStamp;
269    args.eventCount = eventCount;
270    args.events     = events;
271    args.options    = options;
272
273    _commandGate->runAction(OSMemberFunctionCast(IOCommandGate::Action, this, &IOHIDEventSystem::handleHIDEventGated), (void *)&args);
274}
275
276//====================================================================================================
277// IOHIDEventService::handleHIDEventGated
278//====================================================================================================
279void IOHIDEventSystem::handleHIDEventGated(void * args)
280{
281    HIDEventArgsRef eventArgsRef = (HIDEventArgsRef)args;
282
283    if ( !eventArgsRef->events )
284    {
285        IOLog("IOHIDEventSystem::handleHIDEventGated: type=%d timestamp=%lld\n", 0, *((UInt64 *)&(eventArgsRef->timeStamp)));
286        return;
287    }
288
289    IOLog("IOHIDEventSystem::handleHIDEventGated: eventCount=%d timestamp=%lld\n", eventArgsRef->eventCount, *((UInt64 *)&(eventArgsRef->timeStamp)));
290    for ( UInt32 i=0; i<eventArgsRef->eventCount; i++)
291    {
292        IOHIDEvent * event = &(eventArgsRef->events[i]);
293
294        IOLog("IOHIDEventSystem::handleHIDEventGated: type=%d", event->type);
295        switch ( event->type )
296        {
297            case kIOHIDKeyboardEvent:
298                IOLog(" usagePage=%x usage=%x value=%d repeat=%d", event->data.keyboard.usagePage, event->data.keyboard.usage, event->data.keyboard.value, event->data.keyboard.repeat);
299                break;
300
301            case kIOHIDMouseEvent:
302                IOLog(" buttons=%x dx=%d dy=%d", event->data.mouse.buttons, event->data.mouse.dx, event->data.mouse.dy);
303                break;
304
305            case kIOHIDScrollEvent:
306                IOLog(" deltaAxis1=%d deltaAxis2=%d deltaAxis3=%d", event->data.scroll.lines.deltaAxis1, event->data.scroll.lines.deltaAxis2, event->data.scroll.lines.deltaAxis3);
307                break;
308
309            default:
310                break;
311        }
312        IOLog("\n");
313    }
314
315}
316