1/*
2 *
3 * @APPLE_LICENSE_HEADER_START@
4 *
5 * Copyright (c) 1999-2003 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 <IOKit/IOKitKeys.h>
26
27#include <IOKit/hidsystem/ev_keymap.h>
28#include <IOKit/hidsystem/IOHIDShared.h>
29#include <IOKit/hidsystem/IOHIDUsageTables.h>
30
31#include "IOHIDElement.h"
32#include "IOHIDConsumer.h"
33#include "AppleHIDUsageTables.h"
34
35
36//====================================================================================================
37// Defines
38//====================================================================================================
39
40#define super 			IOHIKeyboard
41
42#define DEBUGGING_LEVEL 	0
43
44OSDefineMetaClassAndStructors( IOHIDConsumer, IOHIKeyboard )
45
46//====================================================================================================
47// Consumer - constructor
48//====================================================================================================
49IOHIDConsumer *
50IOHIDConsumer::Consumer(bool isDispatcher)
51{
52    IOHIDConsumer *consumer = new IOHIDConsumer;
53
54    if ((consumer == 0) || !consumer->init())
55    {
56        if (consumer) consumer->release();
57        return 0;
58    }
59
60    consumer->_isDispatcher = isDispatcher;
61
62    return consumer;
63}
64
65//====================================================================================================
66// init
67//====================================================================================================
68bool
69IOHIDConsumer::init(OSDictionary *properties)
70{
71  if (!super::init(properties))  return false;
72
73    _otherEventFlags 	= 0;
74    _otherCapsLockOn 	= FALSE;
75
76	_repeat				= true;
77	setRepeatMode(_repeat);
78
79    return true;
80}
81
82//====================================================================================================
83// start
84//====================================================================================================
85bool IOHIDConsumer::start(IOService * provider)
86{
87    setProperty(kIOHIDVirtualHIDevice, kOSBooleanTrue);
88
89    return super::start(provider);
90}
91
92//====================================================================================================
93// stop
94//====================================================================================================
95void IOHIDConsumer::stop(IOService * provider)
96{
97    OSSafeReleaseNULL(_keyboardNub);
98    super::stop(provider);
99}
100
101
102void IOHIDConsumer::dispatchConsumerEvent(
103                                IOHIDKeyboard *             sendingkeyboardNub,
104                                AbsoluteTime                timeStamp,
105                                UInt32                      usagePage,
106                                UInt32                      usage,
107                                UInt32						value,
108                                IOOptionBits                options)
109{
110    SInt32  keyCode = -1;
111    bool    repeat  = ((options & kHIDDispatchOptionKeyboardNoRepeat) == 0);
112
113    if (usagePage == kHIDPage_Consumer)
114    {
115        switch(usage)
116        {
117            case kHIDUsage_Csmr_Power:
118            case kHIDUsage_Csmr_Reset:
119            case kHIDUsage_Csmr_Sleep:
120                keyCode = NX_POWER_KEY;
121                break;
122            case kHIDUsage_Csmr_Play:
123            case kHIDUsage_Csmr_PlayOrPause:
124            case kHIDUsage_Csmr_PlayOrSkip:
125                keyCode = NX_KEYTYPE_PLAY;
126                break;
127            case kHIDUsage_Csmr_ScanNextTrack:
128                keyCode = NX_KEYTYPE_NEXT;
129                break;
130            case kHIDUsage_Csmr_ScanPreviousTrack:
131                keyCode = NX_KEYTYPE_PREVIOUS;
132                break;
133            case kHIDUsage_Csmr_FastForward:
134                keyCode = NX_KEYTYPE_FAST;
135                break;
136            case kHIDUsage_Csmr_Rewind:
137                keyCode = NX_KEYTYPE_REWIND;
138                break;
139            case kHIDUsage_Csmr_StopOrEject:
140            case kHIDUsage_Csmr_Eject:
141                keyCode = NX_KEYTYPE_EJECT;
142                break;
143            case kHIDUsage_Csmr_VolumeIncrement:
144                keyCode = NX_KEYTYPE_SOUND_UP;
145                break;
146            case kHIDUsage_Csmr_VolumeDecrement:
147                keyCode = NX_KEYTYPE_SOUND_DOWN;
148                break;
149            case kHIDUsage_Csmr_Mute:
150                keyCode = NX_KEYTYPE_MUTE;
151                break;
152            case kHIDUsage_Csmr_DisplayBrightnessIncrement:
153                keyCode = NX_KEYTYPE_BRIGHTNESS_UP;
154                break;
155            case kHIDUsage_Csmr_DisplayBrightnessDecrement:
156                keyCode = NX_KEYTYPE_BRIGHTNESS_DOWN;
157                break;
158            default:
159                break;
160        }
161    }
162    else if (usagePage == kHIDPage_GenericDesktop)
163    {
164        switch (usage)
165        {
166            case kHIDUsage_GD_SystemPowerDown:
167            case kHIDUsage_GD_SystemSleep:
168            case kHIDUsage_GD_SystemWakeUp:
169                keyCode = NX_POWER_KEY;
170                break;
171        }
172    }
173    else if (usagePage == kHIDPage_AppleVendorTopCase)
174    {
175        switch (usage)
176        {
177            case kHIDUsage_AV_TopCase_BrightnessUp:
178                keyCode = NX_KEYTYPE_BRIGHTNESS_UP;
179                break;
180            case kHIDUsage_AV_TopCase_BrightnessDown:
181                keyCode = NX_KEYTYPE_BRIGHTNESS_DOWN;
182                break;
183            case kHIDUsage_AV_TopCase_VideoMirror:
184                keyCode = NX_KEYTYPE_VIDMIRROR;
185                break;
186            case kHIDUsage_AV_TopCase_IlluminationDown:
187                keyCode = NX_KEYTYPE_ILLUMINATION_DOWN;
188                break;
189            case kHIDUsage_AV_TopCase_IlluminationUp:
190                keyCode = NX_KEYTYPE_ILLUMINATION_UP;
191                break;
192            case kHIDUsage_AV_TopCase_IlluminationToggle:
193                keyCode = NX_KEYTYPE_ILLUMINATION_TOGGLE;
194                break;
195        }
196    }
197    else if ((usagePage == kHIDPage_KeyboardOrKeypad) &&
198                (usage == kHIDUsage_KeyboardLockingNumLock))
199    {
200        keyCode = NX_KEYTYPE_NUM_LOCK;
201    }
202
203
204    if (keyCode == -1)
205        return;
206
207	if (repeat != _repeat)
208	{
209		_repeat = repeat;
210		setRepeatMode(_repeat);
211	}
212
213    //Copy the device flags (modifier flags) from the ADB keyboard driver
214    OSSafeReleaseNULL(_keyboardNub);
215    if ( NULL != (_keyboardNub = sendingkeyboardNub) )
216    {
217        UInt32  currentFlags;
218
219        currentFlags        = deviceFlags() & ~_cachedEventFlags;
220        _cachedEventFlags   = _keyboardNub->deviceFlags();
221        currentFlags       |= _cachedEventFlags;
222        _deviceType         = _keyboardNub->deviceType();
223
224        setDeviceFlags(currentFlags);
225        _keyboardNub->retain();
226    }
227    else
228    {
229        findKeyboardsAndGetModifiers();
230    }
231
232    dispatchKeyboardEvent( keyCode, value, timeStamp );
233}
234
235//====================================================================================================
236// eventFlags - IOHIKeyboard override. This is necessary because we will need to return the state
237// of the modifier keys on attached keyboards. If we don't, then we the HIDSystem gets
238// the event, it will look like all modifiers are off.
239//====================================================================================================
240unsigned IOHIDConsumer::eventFlags()
241{
242    unsigned flags = 0;
243
244    flags = (_keyboardNub) ? _keyboardNub->eventFlags() : _otherEventFlags;
245
246    return( flags );
247}
248
249//====================================================================================================
250// deviceFlags - IOHIKeyboard override. This is necessary because we will need to return the state
251// of the modifier keys on attached keyboards. If we don't, then we the HIDSystem gets
252// the event, it will look like all modifiers are off.
253//====================================================================================================
254unsigned IOHIDConsumer::deviceFlags()
255{
256    unsigned flags = 0;
257
258    flags = (_keyboardNub) ? _keyboardNub->deviceFlags() : _otherEventFlags;
259
260    return( flags );
261}
262
263//====================================================================================================
264// setDeviceFlags - IOHIKeyboard override. This is necessary because we will need to return the state
265// of the modifier keys on attached keyboards. If we don't, then we the HIDSystem gets
266// the event, it will look like all modifiers are off.
267//====================================================================================================
268void IOHIDConsumer::setDeviceFlags(unsigned flags)
269{
270    if ( _keyboardNub )
271        _keyboardNub->setDeviceFlags(flags);
272
273    super::setDeviceFlags(flags);
274}
275
276
277//====================================================================================================
278// alphaLock  - IOHIKeyboard override. This is necessary because we will need to return the state
279// of the caps lock keys on attached keyboards. If we don't, then we the HIDSystem gets
280// the event, it will look like caps lock keys are off.
281//====================================================================================================
282bool IOHIDConsumer::alphaLock()
283{
284    bool state = false;
285
286    state = (_keyboardNub) ? _keyboardNub->alphaLock() : _otherCapsLockOn;
287
288    return( state );
289}
290
291//====================================================================================================
292// setNumLock  - IOHIKeyboard override. This is necessary because we will need to toggle the num lock
293// led on the keyboard interface
294//====================================================================================================
295void IOHIDConsumer::setNumLock(bool val)
296{
297    if (_keyboardNub) _keyboardNub->setNumLock(val);
298}
299
300//====================================================================================================
301// numLock  - IOHIKeyboard override. This is necessary because we will need to check the num lock
302// status on the keyboard interface
303//====================================================================================================
304bool IOHIDConsumer::numLock()
305{
306    bool state = false;
307
308    state = (_keyboardNub) ? _keyboardNub->numLock() : super::numLock();
309
310    return( state );
311}
312
313//====================================================================================================
314// doesKeyLock  - IOHIKeyboard override. This is necessary because the system will only toggle the led
315// and set appropriate event flags if the num lock key physically locks.
316//====================================================================================================
317bool IOHIDConsumer:: doesKeyLock ( unsigned key)
318{
319    if ( key == NX_KEYTYPE_NUM_LOCK )
320        return true;
321
322    return false;
323}
324
325//====================================================================================================
326// defaultKeymapOfLength - IOHIKeyboard override
327// This allows us to associate the scancodes we choose with the special
328// keys we are interested in posting later. This gives us auto-repeats for free. Kewl.
329//====================================================================================================
330const unsigned char * IOHIDConsumer::defaultKeymapOfLength( UInt32 * length )
331{
332    static const unsigned char ConsumerKeyMap[] =
333    {
334		// The first 16 bits are always read first, to determine if the rest of
335        // the keymap is in shorts (16 bits) or bytes (8 bits). If the first 16 bits
336        // equals 0, data is in bytes; if first 16 bits equal 1, data is in shorts.
337
338        0x00,0x00,		// data is in bytes
339
340        // The next value is the number of modifier keys. We have none in our driver.
341
342        0x00,
343
344        // The next value is number of key definitions. We have none in our driver.
345
346        0x00,
347
348        // The next value is number of of sequence definitions there are. We have none.
349
350        0x00,
351
352        // The next value is the number of special keys. We use these.
353
354        NX_NUMSPECIALKEYS,
355
356        // Special Key	  	SCANCODE
357        //-----------------------------------------------------------
358
359        NX_KEYTYPE_SOUND_UP,		NX_KEYTYPE_SOUND_UP,
360        NX_KEYTYPE_SOUND_DOWN,		NX_KEYTYPE_SOUND_DOWN,
361        NX_KEYTYPE_BRIGHTNESS_UP,	NX_KEYTYPE_BRIGHTNESS_UP,
362        NX_KEYTYPE_BRIGHTNESS_DOWN,	NX_KEYTYPE_BRIGHTNESS_DOWN,
363        NX_KEYTYPE_CAPS_LOCK,		NX_KEYTYPE_CAPS_LOCK,
364        NX_KEYTYPE_HELP,		NX_KEYTYPE_HELP,
365        NX_POWER_KEY,			NX_POWER_KEY,
366        NX_KEYTYPE_MUTE,		NX_KEYTYPE_MUTE,
367        NX_UP_ARROW_KEY,		NX_UP_ARROW_KEY,
368        NX_DOWN_ARROW_KEY,		NX_DOWN_ARROW_KEY,
369        NX_KEYTYPE_NUM_LOCK,		NX_KEYTYPE_NUM_LOCK,
370        NX_KEYTYPE_CONTRAST_UP,		NX_KEYTYPE_CONTRAST_UP,
371        NX_KEYTYPE_CONTRAST_DOWN,	NX_KEYTYPE_CONTRAST_DOWN,
372        NX_KEYTYPE_LAUNCH_PANEL,	NX_KEYTYPE_LAUNCH_PANEL,
373        NX_KEYTYPE_EJECT,		NX_KEYTYPE_EJECT,
374        NX_KEYTYPE_VIDMIRROR,		NX_KEYTYPE_VIDMIRROR,
375        NX_KEYTYPE_PLAY,		NX_KEYTYPE_PLAY,
376        NX_KEYTYPE_NEXT,		NX_KEYTYPE_NEXT,
377        NX_KEYTYPE_PREVIOUS,		NX_KEYTYPE_PREVIOUS,
378        NX_KEYTYPE_FAST,		NX_KEYTYPE_FAST,
379        NX_KEYTYPE_REWIND,		NX_KEYTYPE_REWIND,
380        NX_KEYTYPE_ILLUMINATION_UP,	NX_KEYTYPE_ILLUMINATION_UP,
381        NX_KEYTYPE_ILLUMINATION_DOWN,	NX_KEYTYPE_ILLUMINATION_DOWN,
382        NX_KEYTYPE_ILLUMINATION_TOGGLE,	NX_KEYTYPE_ILLUMINATION_TOGGLE
383
384    };
385
386
387    if( length ) *length = sizeof( ConsumerKeyMap );
388
389    return( ConsumerKeyMap );
390}
391
392//====================================================================================================
393// findKeyboardsAndGetModifiers
394//====================================================================================================
395UInt32 IOHIDConsumer::findKeyboardsAndGetModifiers()
396{
397	OSIterator	*iterator = NULL;
398	OSDictionary	*matchingDictionary = NULL;
399	IOHIKeyboard	*device = NULL;
400
401	_otherEventFlags = 0;
402    _cachedEventFlags = 0;
403	_otherCapsLockOn = FALSE;
404
405	// Get matching dictionary.
406
407	matchingDictionary = IOService::serviceMatching( "IOHIKeyboard" );
408	if( !matchingDictionary )
409	{
410		goto exit;
411	}
412
413	// Get an iterator for the IOHIKeyboard devices.
414
415	iterator = IOService::getMatchingServices( matchingDictionary );
416	if( !iterator )
417	{
418		goto exit;
419	}
420
421	// User iterator to find devices and eject.
422	//
423	while( (device = (IOHIKeyboard*) iterator->getNextObject()) )
424	{
425
426		//Ignore the eventFlags keyboards that don't have modifiers defined
427		if (!device->getProperty(kIOHIDKeyboardSupportedModifiersKey))
428			continue;
429
430		// Save the caps lock state. If more than one keyboard has it down, that's fine -- we
431		// just want to know if ANY keyboards have the key down.
432		//
433		if( device->alphaLock() )
434		{
435			_otherCapsLockOn = TRUE;
436		}
437
438		// OR in the flags, so we get a combined IOHIKeyboard device flags state. That
439		// way, if the user is pressing command on one keyboard, shift on another, and
440		// then hits an eject key, we'll get both modifiers.
441		//
442		_otherEventFlags |= device->eventFlags();
443	}
444
445exit:
446
447	if( matchingDictionary ) matchingDictionary->release();
448	if( iterator ) iterator->release();
449
450	return( _otherEventFlags );
451}
452
453