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)
bool displayWranglerFound( OSObject *, void *, IOService * );
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::start ( IOService * theNub )
{
int i;
for ( i = 0; i < kMax_registrations; i++ ) {
keycodes[i] = kNullKey;
downHandlers[i] = NULL;
}
adbDevice = (IOADBDevice *)theNub;
register_for_button = OSSymbol::withCString("register_for_button");
if( !super::start(theNub))
return false;
if( !adbDevice->seizeForClient(this, button_data) ) {
IOLog("%s: Seize failed\n", getName());
return false;
}
addNotification( gIOPublishNotification,serviceMatching("IODisplayWrangler"), (IOServiceNotificationHandler)displayWranglerFound, this, 0 );
_initial_handler_id = adbDevice->handlerID();
_eject_released = true; _peject_timer = thread_call_allocate((thread_call_func_t)check_eject_held, (thread_call_param_t)this);
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;
}
UInt64 AppleADBButtons::getGUID()
{
return(kAppleOnboardGUID);
}
bool displayWranglerFound( OSObject * us, void * ref, IOService * yourDevice )
{
if ( yourDevice != NULL ) {
((AppleADBButtons *)us)->displayManager = yourDevice;
}
return true;
}
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)
{
return 195; }
else
return adbDevice->handlerID();
}
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 ) {
registrants[i] = registrant;
downHandlers[i] = handler;
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, 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);
}
if ( displayManager != NULL ) { displayManager->activityTickle(kIOPMSuperclassPolicy1); }
return kIOReturnSuccess;
}
void AppleADBButtons::dispatchButtonEvent (unsigned int keycode, bool down )
{
int i;
AbsoluteTime now;
if (_initial_handler_id == 0xc0) {
switch (keycode)
{
case kVolume_up_AV:
keycode = kVolume_up;
break;
case kVolume_down_AV:
keycode = kVolume_down;
break;
case kMute_AV:
keycode = kMute;
break;
default:
break;
}
}
clock_get_uptime(&now);
for ( i = 0; i < kMax_registrations; i++ ) {
if ( keycodes[i] == keycode ) {
if ( down ) {
if (downHandlers[i] != NULL ) {
thread_call_func((thread_call_func_t)downHandlers[i],
(thread_call_param_t)registrants[i],
true);
}
}
}
}
if (_initial_handler_id == 31)
{
mach_timespec_t t;
unsigned adb_keyboard_flags;
t.tv_sec = 1; t.tv_nsec = 0;
_pADBKeyboard = waitForService(serviceMatching("AppleADBKeyboard"), &t);
if (_pADBKeyboard)
{
const OSSymbol *get_device_flags;
get_device_flags = OSSymbol::withCString("get_device_flags");
_pADBKeyboard->callPlatformFunction(get_device_flags, false,
(void *)&adb_keyboard_flags, 0, 0, 0);
super::setDeviceFlags(adb_keyboard_flags);
}
}
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 (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);
}