AppleADBButtons.cpp [plain text]
#include "AppleADBButtons.h"
#include <IOKit/IOLib.h>
#include <IOKit/pwr_mgt/IOPM.h>
#include <IOKit/hidsystem/IOHIDTypes.h>
#include <IOKit/hidsystem/IOHIDParameter.h>
#define super IOHIKeyboard
OSDefineMetaClassAndStructors(AppleADBButtons,IOHIKeyboard)
void button_data ( IOService * us, UInt8 adbCommand, IOByteCount length, UInt8 * data );
void asyncFunc ( void * );
static void check_eject_held(thread_call_param_t arg);
bool AppleADBButtons::init(OSDictionary * properties)
{
if ( !super::init(properties) )
return false;
_pADBKeyboard = 0;
_cachedKeyboardFlags = 0;
_eject_released = true; _publishNotify = 0;
_terminateNotify = 0;
_peject_timer = thread_call_allocate((thread_call_func_t)check_eject_held, (thread_call_param_t)this);
_register_for_button = OSSymbol::withCString("register_for_button");
return TRUE;
}
bool AppleADBButtons::start ( IOService * theNub )
{
int i;
for ( i = 0; i < kMax_registrations; i++ ) {
keycodes[i] = kNullKey;
downHandlerThreadCalls[i] = NULL;
}
adbDevice = (IOADBDevice *)theNub;
_initial_handler_id = adbDevice->handlerID();
if (_initial_handler_id == 0xc0)
{
return false; }
if( !super::start(theNub))
return false;
if( !adbDevice->seizeForClient(this, button_data) ) {
IOLog("%s: Seize failed\n", getName());
return false;
}
_publishNotify = addNotification(
gIOPublishNotification, serviceMatching("AppleADBKeyboard"),
&AppleADBButtons::_publishNotificationHandler,
this, 0 );
_terminateNotify = addNotification(
gIOTerminatedNotification, serviceMatching("AppleADBKeyboard"),
&AppleADBButtons::_terminateNotificationHandler,
this, 0 );
return true;
}
void AppleADBButtons::free()
{
if ( _publishNotify )
{
_publishNotify->remove();
_publishNotify = 0;
}
if ( _terminateNotify )
{
_terminateNotify->remove();
_terminateNotify = 0;
}
if (_register_for_button)
{
_register_for_button->release();
_register_for_button = 0;
}
if ( _peject_timer )
{
thread_call_cancel( _peject_timer );
thread_call_free( _peject_timer );
}
for ( int i = 0; i < kMax_registrations; i++ ) {
if ( downHandlerThreadCalls[i] ) {
thread_call_free ( downHandlerThreadCalls[i] );
}
}
super::free();
}
bool AppleADBButtons::_publishNotificationHandler( void * target,
void * ref, IOService * newService )
{
if ( target )
{
AppleADBButtons *self = (AppleADBButtons *)target;
if ( !self->_pADBKeyboard && newService )
self->_pADBKeyboard = OSDynamicCast( IOHIKeyboard, newService );
}
return true;
}
bool AppleADBButtons::_terminateNotificationHandler( void * target,
void * ref, IOService * service )
{
if ( target )
((AppleADBButtons *)target)->_pADBKeyboard = 0;
return true;
}
IOReturn AppleADBButtons::callPlatformFunction(const OSSymbol *functionName,
bool waitForFunction,
void *param1, void *param2,
void *param3, void *param4)
{
if ( functionName == _register_for_button )
{
registerForButton( (unsigned int)param1, (IOService *)param2,
(button_handler)param3, (bool)param4 );
return kIOReturnSuccess;
}
return kIOReturnBadArgument;
}
bool AppleADBButtons::doesKeyLock(unsigned key)
{
if ( key == NX_KEYTYPE_NUM_LOCK )
return TRUE;
return super::doesKeyLock( key );
}
UInt64 AppleADBButtons::getGUID()
{
return(kAppleOnboardGUID);
}
UInt32 AppleADBButtons::interfaceID()
{
return NX_EVS_DEVICE_INTERFACE_ADB;
}
UInt32 AppleADBButtons::deviceType()
{
OSNumber *xml_handlerID;
xml_handlerID = OSDynamicCast( OSNumber, getProperty("alt_handler_id"));
if (xml_handlerID)
{
return xml_handlerID->unsigned32BitValue();
}
if ( _initial_handler_id == 31 )
{
if ( _pADBKeyboard )
{
return _pADBKeyboard->deviceType();
}
else
{
return 195; }
}
return adbDevice->handlerID();
}
void AppleADBButtons::setDeviceFlags(unsigned flags)
{
if ( _pADBKeyboard )
_pADBKeyboard->setDeviceFlags(flags);
super::setDeviceFlags(flags);
}
IOReturn AppleADBButtons::registerForButton ( unsigned int keycode, IOService * registrant, button_handler handler, bool down )
{
int i;
for ( i = 0; i < kMax_registrations; i++ ) {
if ( keycodes[i] == kNullKey ) {
if ( down ) {
downHandlerThreadCalls[i] = thread_call_allocate( (thread_call_func_t) handler, (thread_call_param_t)registrant);
keycodes[i] = keycode;
break;
}
}
}
return kIOReturnSuccess;
}
void button_data ( IOService * us, UInt8 adbCommand, IOByteCount length, UInt8 * data )
{
((AppleADBButtons *)us)->packet(data,length,adbCommand);
}
IOReturn AppleADBButtons::packet (UInt8 * data, IOByteCount count, UInt8 adbCommand )
{
unsigned int keycode;
bool down;
keycode = *data;
down = ((keycode & 0x80) == 0);
keycode &= 0x7f;
dispatchButtonEvent(keycode,down);
keycode = *(data + 1);
if( keycode != 0xff ) {
down = ((keycode & 0x80) == 0);
keycode &= 0x7f;
dispatchButtonEvent(keycode,down);
}
return kIOReturnSuccess;
}
void AppleADBButtons::dispatchButtonEvent (unsigned int keycode, bool down )
{
int i;
AbsoluteTime now;
clock_get_uptime(&now);
for ( i = 0; i < kMax_registrations; i++ ) {
if ( keycodes[i] == keycode ) {
if ( down ) {
if (downHandlerThreadCalls[i] != NULL ) {
thread_call_enter(downHandlerThreadCalls[i]);
}
}
}
}
if ((_initial_handler_id == 31) && _pADBKeyboard)
{
UInt32 currentFlags;
currentFlags = deviceFlags() & ~_cachedKeyboardFlags;
_cachedKeyboardFlags = _pADBKeyboard->deviceFlags();
currentFlags |= _cachedKeyboardFlags;
setDeviceFlags(currentFlags);
}
switch (keycode)
{
case kVolume_up:
case kVolume_down:
case kMute:
case kBrightness_up:
case kBrightness_down:
case kNum_lock_on_laptops:
case kVideoMirror:
case kIllumination_toggle:
case kIllumination_down:
case kIllumination_up:
dispatchKeyboardEvent(keycode, down, now);
break;
case kEject:
if ( _peject_timer )
{
if ( down )
{
AbsoluteTime deadline;
OSNumber *plist_time;
_eject_released = false;
_eject_delay = 250; plist_time = OSDynamicCast( OSNumber, getProperty("Eject Delay Milliseconds"));
if ( plist_time )
{
_eject_delay = plist_time->unsigned32BitValue();
}
clock_interval_to_deadline(_eject_delay, kMillisecondScale, &deadline);
thread_call_enter_delayed(_peject_timer, deadline);
}
else
{
_eject_released = true;
thread_call_cancel( _peject_timer );
dispatchKeyboardEvent( kEject, FALSE, now );
}
}
default: break;
}
}
static void check_eject_held(thread_call_param_t us)
{
((AppleADBButtons *)us)->_check_eject_held();
}
void AppleADBButtons::_check_eject_held( void )
{
AbsoluteTime now;
if (!_eject_released)
{
clock_get_uptime(&now);
dispatchKeyboardEvent(kEject, TRUE, now);
}
}
const unsigned char *AppleADBButtons::defaultKeymapOfLength(UInt32 *length)
{
static const unsigned char appleADBButtonsKeyMap[] = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x0B, NX_KEYTYPE_SOUND_UP, kVolume_up,
NX_KEYTYPE_SOUND_DOWN, kVolume_down,
NX_KEYTYPE_MUTE, kMute,
NX_KEYTYPE_BRIGHTNESS_UP, kBrightness_up,
NX_KEYTYPE_BRIGHTNESS_DOWN, kBrightness_down,
NX_KEYTYPE_NUM_LOCK, kNum_lock_on_laptops,
NX_KEYTYPE_EJECT, kEject,
NX_KEYTYPE_VIDMIRROR, kVideoMirror,
NX_KEYTYPE_ILLUMINATION_TOGGLE, kIllumination_toggle,
NX_KEYTYPE_ILLUMINATION_DOWN, kIllumination_down,
NX_KEYTYPE_ILLUMINATION_UP, kIllumination_up,
};
*length = sizeof(appleADBButtonsKeyMap);
return appleADBButtonsKeyMap;
}
IOReturn AppleADBButtons::setParamProperties(OSDictionary *dict)
{
dict->removeObject(kIOHIDKeyMappingKey);
return super::setParamProperties(dict);
}