ApplePS2SynapticsTouchPad.cpp [plain text]
#include <IOKit/assert.h>
#include <IOKit/IOLib.h>
#include <IOKit/hidsystem/IOHIDParameter.h>
#include "ApplePS2SynapticsTouchPad.h"
enum {
kModeByteValueGesturesEnabled = 0x00,
kModeByteValueGesturesDisabled = 0x04
};
#define super IOHIPointing
OSDefineMetaClassAndStructors(ApplePS2SynapticsTouchPad, IOHIPointing);
UInt32 ApplePS2SynapticsTouchPad::deviceType()
{ return NX_EVS_DEVICE_TYPE_MOUSE; };
UInt32 ApplePS2SynapticsTouchPad::interfaceID()
{ return NX_EVS_DEVICE_INTERFACE_BUS_ACE; };
IOItemCount ApplePS2SynapticsTouchPad::buttonCount() { return 2; };
IOFixed ApplePS2SynapticsTouchPad::resolution() { return _resolution; };
bool ApplePS2SynapticsTouchPad::init( OSDictionary * properties )
{
if (!super::init(properties)) return false;
_device = 0;
_interruptHandlerInstalled = false;
_packetByteCount = 0;
_resolution = (100) << 16; _touchPadModeByte = kModeByteValueGesturesDisabled;
return true;
}
ApplePS2SynapticsTouchPad *
ApplePS2SynapticsTouchPad::probe( IOService * provider, SInt32 * score )
{
ApplePS2MouseDevice * device = (ApplePS2MouseDevice *) provider;
PS2Request * request = device->allocateRequest();
bool success = false;
if (!super::probe(provider, score) || !request) return 0;
request->commands[0].command = kPS2C_SendMouseCommandAndCompareAck;
request->commands[0].inOrOut = kDP_SetDefaultsAndDisable;
request->commands[1].command = kPS2C_SendMouseCommandAndCompareAck;
request->commands[1].inOrOut = kDP_SetMouseResolution;
request->commands[2].command = kPS2C_SendMouseCommandAndCompareAck;
request->commands[2].inOrOut = 0;
request->commands[3].command = kPS2C_SendMouseCommandAndCompareAck;
request->commands[3].inOrOut = kDP_SetMouseResolution;
request->commands[4].command = kPS2C_SendMouseCommandAndCompareAck;
request->commands[4].inOrOut = 0;
request->commands[5].command = kPS2C_SendMouseCommandAndCompareAck;
request->commands[5].inOrOut = kDP_SetMouseResolution;
request->commands[6].command = kPS2C_SendMouseCommandAndCompareAck;
request->commands[6].inOrOut = 0;
request->commands[7].command = kPS2C_SendMouseCommandAndCompareAck;
request->commands[7].inOrOut = kDP_SetMouseResolution;
request->commands[8].command = kPS2C_SendMouseCommandAndCompareAck;
request->commands[8].inOrOut = 0;
request->commands[9].command = kPS2C_SendMouseCommandAndCompareAck;
request->commands[9].inOrOut = kDP_GetMouseInformation;
request->commands[10].command = kPS2C_ReadDataPort;
request->commands[10].inOrOut = 0;
request->commands[11].command = kPS2C_ReadDataPort;
request->commands[11].inOrOut = 0;
request->commands[12].command = kPS2C_ReadDataPort;
request->commands[12].inOrOut = 0;
request->commands[13].command = kPS2C_SendMouseCommandAndCompareAck;
request->commands[13].inOrOut = kDP_SetDefaults;
request->commandsCount = 14;
device->submitRequestAndBlock(request);
if ( request->commandsCount == 14 &&
request->commands[11].inOrOut == 0x47 )
{
_touchPadVersion = (request->commands[12].inOrOut & 0x0f) << 8
| request->commands[10].inOrOut;
if ( _touchPadVersion >= 0x400 ) success = true;
}
device->freeRequest(request);
return (success) ? this : 0;
}
bool ApplePS2SynapticsTouchPad::start( IOService * provider )
{
UInt64 gesturesEnabled;
if (!super::start(provider)) return false;
_device = (ApplePS2MouseDevice *) provider;
_device->retain();
IOLog("ApplePS2Trackpad: Synaptics TouchPad v%d.%d\n",
(UInt8)(_touchPadVersion >> 8), (UInt8)(_touchPadVersion));
setTouchPadModeByte(_touchPadModeByte);
gesturesEnabled = (_touchPadModeByte == kModeByteValueGesturesEnabled)
? 1 : 0;
setProperty("Clicking", gesturesEnabled, sizeof(gesturesEnabled)*8);
setProperty(kIOHIDPointerAccelerationTypeKey, kIOHIDTrackpadAccelerationType);
_device->installInterruptAction(this,
(PS2InterruptAction)&ApplePS2SynapticsTouchPad::interruptOccurred);
_interruptHandlerInstalled = true;
setCommandByte( kCB_EnableMouseIRQ, kCB_DisableMouseClock );
setTouchPadEnable(true);
return true;
}
void ApplePS2SynapticsTouchPad::stop( IOService * provider )
{
assert(_device == provider);
setTouchPadEnable(false);
setCommandByte( kCB_DisableMouseClock, kCB_EnableMouseIRQ );
if ( _interruptHandlerInstalled ) _device->uninstallInterruptAction();
_interruptHandlerInstalled = false;
super::stop(provider);
}
void ApplePS2SynapticsTouchPad::free()
{
if (_device)
{
_device->release();
_device = 0;
}
super::free();
}
void ApplePS2SynapticsTouchPad::interruptOccurred( UInt8 data )
{
if (_packetByteCount == 0 && ((data == kSC_Acknowledge) || !(data & 0x08)))
{
return;
}
_packetBuffer[_packetByteCount++] = data;
if (_packetByteCount == 3)
{
dispatchRelativePointerEventWithPacket(_packetBuffer, 3);
_packetByteCount = 0;
}
}
void ApplePS2SynapticsTouchPad::
dispatchRelativePointerEventWithPacket( UInt8 * packet,
UInt32 packetSize )
{
UInt32 buttons = 0;
SInt32 dx, dy;
AbsoluteTime now;
if ( (packet[0] & 0x1) ) buttons |= 0x1; if ( (packet[0] & 0x2) ) buttons |= 0x2; if ( (packet[0] & 0x4) ) buttons |= 0x4;
dx = ((packet[0] & 0x10) ? 0xffffff00 : 0 ) | packet[1];
dy = -(((packet[0] & 0x20) ? 0xffffff00 : 0 ) | packet[2]);
clock_get_uptime(&now);
dispatchRelativePointerEvent(dx, dy, buttons, now);
}
void ApplePS2SynapticsTouchPad::setTouchPadEnable( bool enable )
{
PS2Request * request = _device->allocateRequest();
if ( !request ) return;
request->commands[0].command = kPS2C_SendMouseCommandAndCompareAck;
request->commands[0].inOrOut = (enable)?kDP_Enable:kDP_SetDefaultsAndDisable;
request->commandsCount = 1;
_device->submitRequest(request); }
UInt32 ApplePS2SynapticsTouchPad::getTouchPadData( UInt8 dataSelector )
{
PS2Request * request = _device->allocateRequest();
UInt32 returnValue = (UInt32)(-1);
if ( !request ) return returnValue;
request->commands[0].command = kPS2C_SendMouseCommandAndCompareAck;
request->commands[0].inOrOut = kDP_SetDefaultsAndDisable;
request->commands[1].command = kPS2C_SendMouseCommandAndCompareAck;
request->commands[1].inOrOut = kDP_SetMouseResolution;
request->commands[2].command = kPS2C_SendMouseCommandAndCompareAck;
request->commands[2].inOrOut = (dataSelector >> 6) & 0x3;
request->commands[3].command = kPS2C_SendMouseCommandAndCompareAck;
request->commands[3].inOrOut = kDP_SetMouseResolution;
request->commands[4].command = kPS2C_SendMouseCommandAndCompareAck;
request->commands[4].inOrOut = (dataSelector >> 4) & 0x3;
request->commands[5].command = kPS2C_SendMouseCommandAndCompareAck;
request->commands[5].inOrOut = kDP_SetMouseResolution;
request->commands[6].command = kPS2C_SendMouseCommandAndCompareAck;
request->commands[6].inOrOut = (dataSelector >> 2) & 0x3;
request->commands[7].command = kPS2C_SendMouseCommandAndCompareAck;
request->commands[7].inOrOut = kDP_SetMouseResolution;
request->commands[8].command = kPS2C_SendMouseCommandAndCompareAck;
request->commands[8].inOrOut = (dataSelector >> 0) & 0x3;
request->commands[9].command = kPS2C_SendMouseCommandAndCompareAck;
request->commands[9].inOrOut = kDP_GetMouseInformation;
request->commands[10].command = kPS2C_ReadDataPort;
request->commands[10].inOrOut = 0;
request->commands[11].command = kPS2C_ReadDataPort;
request->commands[11].inOrOut = 0;
request->commands[12].command = kPS2C_ReadDataPort;
request->commands[12].inOrOut = 0;
request->commandsCount = 13;
_device->submitRequestAndBlock(request);
if (request->commandsCount == 13) {
returnValue = ((UInt32)request->commands[10].inOrOut << 16) |
((UInt32)request->commands[11].inOrOut << 8) |
((UInt32)request->commands[12].inOrOut);
}
_device->freeRequest(request);
return returnValue;
}
bool ApplePS2SynapticsTouchPad::setTouchPadModeByte( UInt8 modeByteValue,
bool enableStreamMode )
{
PS2Request * request = _device->allocateRequest();
bool success;
if ( !request ) return false;
request->commands[0].command = kPS2C_SendMouseCommandAndCompareAck;
request->commands[0].inOrOut = kDP_SetDefaultsAndDisable;
request->commands[1].command = kPS2C_SendMouseCommandAndCompareAck;
request->commands[1].inOrOut = kDP_SetMouseResolution;
request->commands[2].command = kPS2C_SendMouseCommandAndCompareAck;
request->commands[2].inOrOut = (modeByteValue >> 6) & 0x3;
request->commands[3].command = kPS2C_SendMouseCommandAndCompareAck;
request->commands[3].inOrOut = kDP_SetMouseResolution;
request->commands[4].command = kPS2C_SendMouseCommandAndCompareAck;
request->commands[4].inOrOut = (modeByteValue >> 4) & 0x3;
request->commands[5].command = kPS2C_SendMouseCommandAndCompareAck;
request->commands[5].inOrOut = kDP_SetMouseResolution;
request->commands[6].command = kPS2C_SendMouseCommandAndCompareAck;
request->commands[6].inOrOut = (modeByteValue >> 2) & 0x3;
request->commands[7].command = kPS2C_SendMouseCommandAndCompareAck;
request->commands[7].inOrOut = kDP_SetMouseResolution;
request->commands[8].command = kPS2C_SendMouseCommandAndCompareAck;
request->commands[8].inOrOut = (modeByteValue >> 0) & 0x3;
request->commands[9].command = kPS2C_SendMouseCommandAndCompareAck;
request->commands[9].inOrOut = kDP_SetMouseSampleRate;
request->commands[10].command = kPS2C_SendMouseCommandAndCompareAck;
request->commands[10].inOrOut = 20;
request->commands[11].command = kPS2C_SendMouseCommandAndCompareAck;
request->commands[11].inOrOut = enableStreamMode ?
kDP_Enable :
kDP_SetMouseScaling1To1;
request->commandsCount = 12;
_device->submitRequestAndBlock(request);
success = (request->commandsCount == 12);
_device->freeRequest(request);
return success;
}
void ApplePS2SynapticsTouchPad::setCommandByte( UInt8 setBits, UInt8 clearBits )
{
UInt8 commandByte;
UInt8 commandByteNew;
PS2Request * request = _device->allocateRequest();
if ( !request ) return;
do
{
request->commands[0].command = kPS2C_WriteCommandPort;
request->commands[0].inOrOut = kCP_GetCommandByte;
request->commands[1].command = kPS2C_ReadDataPort;
request->commands[1].inOrOut = 0;
request->commandsCount = 2;
_device->submitRequestAndBlock(request);
commandByte = request->commands[1].inOrOut;
commandByteNew = (commandByte | setBits) & (~clearBits);
request->commands[0].command = kPS2C_WriteCommandPort;
request->commands[0].inOrOut = kCP_GetCommandByte;
request->commands[1].command = kPS2C_ReadDataPortAndCompare;
request->commands[1].inOrOut = commandByte;
request->commands[2].command = kPS2C_WriteCommandPort;
request->commands[2].inOrOut = kCP_SetCommandByte;
request->commands[3].command = kPS2C_WriteDataPort;
request->commands[3].inOrOut = commandByteNew;
request->commandsCount = 4;
_device->submitRequestAndBlock(request);
} while (request->commandsCount != 4);
_device->freeRequest(request);
}
IOReturn ApplePS2SynapticsTouchPad::setParamProperties( OSDictionary * dict )
{
OSNumber * clicking = OSDynamicCast( OSNumber, dict->getObject("Clicking") );
if ( clicking )
{
UInt8 newModeByteValue = clicking->unsigned32BitValue() & 0x1 ?
kModeByteValueGesturesEnabled :
kModeByteValueGesturesDisabled;
if (_touchPadModeByte != newModeByteValue)
{
_touchPadModeByte = newModeByteValue;
setTouchPadModeByte(_touchPadModeByte, true);
setProperty("Clicking", clicking);
}
}
return super::setParamProperties(dict);
}