From 6883c221e68097e585212cfb8125364dc164fcdd Mon Sep 17 00:00:00 2001 From: vandroiy2013 Date: Mon, 3 Aug 2020 18:02:08 +0300 Subject: [PATCH 01/40] Fix changelog formatting --- Changelog.md | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/Changelog.md b/Changelog.md index cf696167..2170bf74 100644 --- a/Changelog.md +++ b/Changelog.md @@ -1,12 +1,11 @@ VoodooPS2 Changelog ============================ -- Fix Command key being pressed after disabling the keyboard and trackpad with Command-PrtScr key combo -- Added a message to allow other kexts to disable the keyboard - #### v2.1.6 - Upgraded to VoodooInput 1.0.7 - Fixed swiping desktops when holding a dragged item by improving thumb detection - Fixed keyboard timeout error on some laptop configurations +- Fix Command key being pressed after disabling the keyboard and trackpad with Command-PrtScr key combo +- Added a message to allow other kexts to disable the keyboard #### v2.1.5 - Upgraded to VoodooInput 1.0.6 From 179cd7258c32941c2664fe0d907e1c8698bb8e2c Mon Sep 17 00:00:00 2001 From: vandroiy2013 Date: Mon, 3 Aug 2020 19:06:27 +0300 Subject: [PATCH 02/40] Bump version --- VoodooPS2Controller.xcodeproj/project.pbxproj | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/VoodooPS2Controller.xcodeproj/project.pbxproj b/VoodooPS2Controller.xcodeproj/project.pbxproj index 7af7e71a..8946e592 100644 --- a/VoodooPS2Controller.xcodeproj/project.pbxproj +++ b/VoodooPS2Controller.xcodeproj/project.pbxproj @@ -797,7 +797,7 @@ GCC_WARN_UNUSED_VARIABLE = YES; "LLVM_LTO[arch=x86_64]" = YES; MACOSX_DEPLOYMENT_TARGET = 10.11; - MODULE_VERSION = 2.1.6; + MODULE_VERSION = 2.1.7; ONLY_ACTIVE_ARCH = YES; "OTHER_LDFLAGS[arch=x86_64]" = "-dead_strip"; PRODUCT_NAME = VoodooPS2Controller; @@ -849,7 +849,7 @@ GCC_WARN_UNUSED_VARIABLE = YES; "LLVM_LTO[arch=x86_64]" = YES; MACOSX_DEPLOYMENT_TARGET = 10.11; - MODULE_VERSION = 2.1.6; + MODULE_VERSION = 2.1.7; "OTHER_LDFLAGS[arch=x86_64]" = "-dead_strip"; PRODUCT_NAME = VoodooPS2Controller; SDKROOT = macosx; From 8e1c01b2b6a8d902e955a59286b3e07c5eb7cb4a Mon Sep 17 00:00:00 2001 From: Le Bao Hiep Date: Wed, 9 Sep 2020 00:08:22 +0700 Subject: [PATCH 03/40] Fix trackpad not working after sleep --- VoodooPS2Trackpad/VoodooPS2Elan.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/VoodooPS2Trackpad/VoodooPS2Elan.cpp b/VoodooPS2Trackpad/VoodooPS2Elan.cpp index e2bc9df9..bfe87c47 100644 --- a/VoodooPS2Trackpad/VoodooPS2Elan.cpp +++ b/VoodooPS2Trackpad/VoodooPS2Elan.cpp @@ -562,6 +562,7 @@ void ApplePS2Elan::setDevicePowerState( UInt32 whatToDo ) // stale packet fragments. // + resetMouse(); elantechSetupPS2(); _packetByteCount = 0; From d25dbb5181bcee817f663499ab0708fca5fecac5 Mon Sep 17 00:00:00 2001 From: Le Bao Hiep Date: Wed, 9 Sep 2020 00:24:20 +0700 Subject: [PATCH 04/40] Fix spaces --- VoodooPS2Trackpad/VoodooPS2Elan.cpp | 335 ++++++++++++++-------------- VoodooPS2Trackpad/VoodooPS2Elan.h | 31 ++- 2 files changed, 182 insertions(+), 184 deletions(-) diff --git a/VoodooPS2Trackpad/VoodooPS2Elan.cpp b/VoodooPS2Trackpad/VoodooPS2Elan.cpp index bfe87c47..77bc6c85 100644 --- a/VoodooPS2Trackpad/VoodooPS2Elan.cpp +++ b/VoodooPS2Trackpad/VoodooPS2Elan.cpp @@ -85,10 +85,10 @@ bool ApplePS2Elan::init(OSDictionary * dict) return false; // announce version - extern kmod_info_t kmod_info; + extern kmod_info_t kmod_info; DEBUG_LOG("VoodooPS2Elan: Version %s starting on OS X Darwin %d.%d.\n", kmod_info.version, version_major, version_minor); - setProperty ("Revision", 24, 32); + setProperty ("Revision", 24, 32); return true; } @@ -158,7 +158,7 @@ ApplePS2Elan* ApplePS2Elan::probe(IOService * provider, SInt32 * score) if (disable && disable->isTrue()) { config->release(); - _device = 0; + _device = 0; return 0; } #ifdef DEBUG @@ -294,7 +294,7 @@ bool ApplePS2Elan::start(IOService* provider) setProperty(kIOHIDPointerAccelerationTypeKey, kIOHIDTrackpadAccelerationType); setProperty(kIOHIDScrollAccelerationTypeKey, kIOHIDTrackpadScrollAccelerationKey); - setProperty(kIOHIDScrollResolutionKey, _scrollresolution << 16, 32); + setProperty(kIOHIDScrollResolutionKey, _scrollresolution << 16, 32); // added for Sierra precise scrolling (credit usr-sse2) setProperty("HIDScrollResolutionX", _scrollresolution << 16, 32); setProperty("HIDScrollResolutionY", _scrollresolution << 16, 32); @@ -307,10 +307,10 @@ bool ApplePS2Elan::start(IOService* provider) if (!pWorkLoop || !_cmdGate) { _device->release(); - _device = nullptr; + _device = nullptr; return false; } - + // // Lock the controller during initialization // @@ -339,12 +339,12 @@ bool ApplePS2Elan::start(IOService* provider) _device->unlock(); // - // Install our power control handler. - // + // Install our power control handler. + // - _device->installPowerControlAction( this, + _device->installPowerControlAction( this, OSMemberFunctionCast(PS2PowerControlAction, this, &ApplePS2Elan::setDevicePowerState) ); - _powerControlHandlerInstalled = true; + _powerControlHandlerInstalled = true; // // Request message registration for keyboard to trackpad communication @@ -429,38 +429,38 @@ void ApplePS2Elan::stop( IOService * provider ) // OSSafeReleaseNULL(_provider); - super::stop(provider); + super::stop(provider); } void ApplePS2Elan::setParamPropertiesGated(OSDictionary * config) { - if (NULL == config) - return; - - const struct {const char *name; int *var;} int32vars[]={ - {"WakeDelay", &wakedelay}, - {"ScrollResolution", &_scrollresolution}, - {"TrackpointMultiplierX", &_trackpointMultiplierX}, - {"TrackpointMultiplierY", &_trackpointMultiplierY}, - {"TrackpointDividerX", &_trackpointDividerX}, - {"TrackpointDividerY", &_trackpointDividerY}, - {"MouseResolution", &_mouseResolution}, - {"MouseSampleRate", &_mouseSampleRate}, - }; - const struct {const char *name; int *var;} boolvars[]={ - {"ProcessUSBMouseStopsTrackpad", &_processusbmouse}, + if (NULL == config) + return; + + const struct {const char *name; int *var;} int32vars[]={ + {"WakeDelay", &wakedelay}, + {"ScrollResolution", &_scrollresolution}, + {"TrackpointMultiplierX", &_trackpointMultiplierX}, + {"TrackpointMultiplierY", &_trackpointMultiplierY}, + {"TrackpointDividerX", &_trackpointDividerX}, + {"TrackpointDividerY", &_trackpointDividerY}, + {"MouseResolution", &_mouseResolution}, + {"MouseSampleRate", &_mouseSampleRate}, + }; + const struct {const char *name; int *var;} boolvars[]={ + {"ProcessUSBMouseStopsTrackpad", &_processusbmouse}, {"ProcessBluetoothMouseStopsTrackpad", &_processbluetoothmouse}, - {"SetHwResolution", &_set_hw_resolution} - }; + {"SetHwResolution", &_set_hw_resolution} + }; const struct {const char* name; bool* var;} lowbitvars[]={ - {"USBMouseStopsTrackpad", &usb_mouse_stops_trackpad}, + {"USBMouseStopsTrackpad", &usb_mouse_stops_trackpad}, }; const struct {const char* name; uint64_t* var; } int64vars[]={ }; // highrate? - OSBoolean *bl; - if ((bl=OSDynamicCast (OSBoolean, config->getObject ("UseHighRate")))) + OSBoolean *bl; + if ((bl=OSDynamicCast (OSBoolean, config->getObject ("UseHighRate")))) { setProperty("UseHighRate", bl->isTrue()); } @@ -474,25 +474,25 @@ void ApplePS2Elan::setParamPropertiesGated(OSDictionary * config) setProperty(int64vars[i].name, *int64vars[i].var, 64); } // boolean config items - for (int i = 0; i < countof(boolvars); i++) - if ((bl=OSDynamicCast (OSBoolean,config->getObject (boolvars[i].name)))) + for (int i = 0; i < countof(boolvars); i++) + if ((bl=OSDynamicCast (OSBoolean,config->getObject (boolvars[i].name)))) { - *boolvars[i].var = bl->isTrue(); + *boolvars[i].var = bl->isTrue(); setProperty(boolvars[i].name, *boolvars[i].var ? kOSBooleanTrue : kOSBooleanFalse); } // 32-bit config items - for (int i = 0; i < countof(int32vars);i++) - if ((num=OSDynamicCast (OSNumber,config->getObject (int32vars[i].name)))) + for (int i = 0; i < countof(int32vars);i++) + if ((num=OSDynamicCast (OSNumber,config->getObject (int32vars[i].name)))) { - *int32vars[i].var = num->unsigned32BitValue(); + *int32vars[i].var = num->unsigned32BitValue(); setProperty(int32vars[i].name, *int32vars[i].var, 32); } // lowbit config items - for (int i = 0; i < countof(lowbitvars); i++) + for (int i = 0; i < countof(lowbitvars); i++) { - if ((num=OSDynamicCast (OSNumber,config->getObject(lowbitvars[i].name)))) + if ((num=OSDynamicCast (OSNumber,config->getObject(lowbitvars[i].name)))) { - *lowbitvars[i].var = (num->unsigned32BitValue()&0x1)?true:false; + *lowbitvars[i].var = (num->unsigned32BitValue()&0x1)?true:false; setProperty(lowbitvars[i].name, *lowbitvars[i].var ? 1 : 0, 32); } //REVIEW: are these items ever carried in a boolean? @@ -525,14 +525,14 @@ IOReturn ApplePS2Elan::setParamProperties(OSDictionary* dict) IOReturn ApplePS2Elan::setProperties(OSObject *props) { - OSDictionary *dict = OSDynamicCast(OSDictionary, props); + OSDictionary *dict = OSDynamicCast(OSDictionary, props); if (dict && _cmdGate) { // synchronize through workloop... _cmdGate->runAction(OSMemberFunctionCast(IOCommandGate::Action, this, &ApplePS2Elan::setParamPropertiesGated), dict); } - return super::setProperties(props); + return super::setProperties(props); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -888,10 +888,10 @@ int ApplePS2Elan::elantechDetect() unsigned char param[3]; if (ps2_command<0>(NULL, kDP_SetDefaults) || - ps2_command<0>( NULL, kDP_SetDefaultsAndDisable) || - ps2_command<0>( NULL, kDP_SetMouseScaling1To1) || - ps2_command<0>( NULL, kDP_SetMouseScaling1To1) || - ps2_command<0>( NULL, kDP_SetMouseScaling1To1) || + ps2_command<0>(NULL, kDP_SetDefaultsAndDisable) || + ps2_command<0>(NULL, kDP_SetMouseScaling1To1) || + ps2_command<0>(NULL, kDP_SetMouseScaling1To1) || + ps2_command<0>(NULL, kDP_SetMouseScaling1To1) || ps2_command<3>(param, kDP_GetMouseInformation)) { IOLog("VoodooPS2Elan: sending Elantech magic knock failed.\n"); return -1; @@ -940,18 +940,18 @@ int ApplePS2Elan::elantechSetProperties() info.hw_version = 1; else { switch (ver) { - case 2: - case 4: + case 2: + case 4: info.hw_version = 2; - break; - case 5: + break; + case 5: info.hw_version = 3; - break; - case 6 ... 15: + break; + case 6 ... 15: info.hw_version = 4; - break; - default: - return -1; + break; + default: + return -1; } } @@ -1052,14 +1052,14 @@ int ApplePS2Elan::elantechQueryInfo() { /* query range information */ switch (info.hw_version) { - case 1: + case 1: info.x_min = ETP_XMIN_V1; info.y_min = ETP_YMIN_V1; info.x_max = ETP_XMAX_V1; info.y_max = ETP_YMAX_V1; - break; + break; - case 2: + case 2: if (info.fw_version == 0x020800 || info.fw_version == 0x020b00 || info.fw_version == 0x020030) { @@ -1067,54 +1067,54 @@ int ApplePS2Elan::elantechQueryInfo() { info.y_min = ETP_YMIN_V2; info.x_max = ETP_XMAX_V2; info.y_max = ETP_YMAX_V2; - } else { - int i; - int fixed_dpi; - - i = (info.fw_version > 0x020800 && - info.fw_version < 0x020900) ? 1 : 2; - - if (send_cmd<3>(ETP_FW_ID_QUERY, param)) - return -1; + } else { + int i; + int fixed_dpi; - fixed_dpi = param[1] & 0x10; + i = (info.fw_version > 0x020800 && + info.fw_version < 0x020900) ? 1 : 2; - if (((info.fw_version >> 16) == 0x14) && fixed_dpi) { - if (send_cmd<3>(ETP_SAMPLE_QUERY, param)) + if (send_cmd<3>(ETP_FW_ID_QUERY, param)) return -1; - info.x_max = (info.capabilities[1] - i) * param[1] / 2; - info.y_max = (info.capabilities[2] - i) * param[2] / 2; - } else if (info.fw_version == 0x040216) { - info.x_max = 819; - info.y_max = 405; - } else if (info.fw_version == 0x040219 || info.fw_version == 0x040215) { - info.x_max = 900; - info.y_max = 500; - } else { - info.x_max = (info.capabilities[1] - i) * 64; - info.y_max = (info.capabilities[2] - i) * 64; + fixed_dpi = param[1] & 0x10; + + if (((info.fw_version >> 16) == 0x14) && fixed_dpi) { + if (send_cmd<3>(ETP_SAMPLE_QUERY, param)) + return -1; + + info.x_max = (info.capabilities[1] - i) * param[1] / 2; + info.y_max = (info.capabilities[2] - i) * param[2] / 2; + } else if (info.fw_version == 0x040216) { + info.x_max = 819; + info.y_max = 405; + } else if (info.fw_version == 0x040219 || info.fw_version == 0x040215) { + info.x_max = 900; + info.y_max = 500; + } else { + info.x_max = (info.capabilities[1] - i) * 64; + info.y_max = (info.capabilities[2] - i) * 64; + } } - } - break; + break; - case 3: + case 3: if (send_cmd<3>(ETP_FW_ID_QUERY, param)) - return -1; + return -1; info.x_max = (0x0f & param[0]) << 8 | param[1]; info.y_max = (0xf0 & param[0]) << 4 | param[2]; - break; + break; - case 4: - if (send_cmd<3>(ETP_FW_ID_QUERY, param)) - return -1; + case 4: + if (send_cmd<3>(ETP_FW_ID_QUERY, param)) + return -1; info.x_max = (0x0f & param[0]) << 8 | param[1]; info.y_max = (0xf0 & param[0]) << 4 | param[2]; traces = info.capabilities[1]; if ((traces < 2) || (traces > info.x_max)) - return -1; + return -1; info.width = info.x_max / (traces - 1); @@ -1126,7 +1126,7 @@ int ApplePS2Elan::elantechQueryInfo() { if ((traces >= 2) && (traces <= info.y_max)) info.y_traces = traces; - break; + break; } /* check for the middle button: DMI matching or new v4 firmwares */ @@ -1213,52 +1213,52 @@ int ApplePS2Elan::elantechWriteReg(unsigned char reg, unsigned char val) return -1; switch (info.hw_version) { - case 1: - if (ps2_sliced_command(ETP_REGISTER_WRITE) || - ps2_sliced_command(reg) || - ps2_sliced_command(val) || - ps2_command<0>(NULL, kDP_SetMouseScaling1To1)) { - rc = -1; - } - break; - - case 2: - if (elantech_ps2_command<0>(NULL, ETP_PS2_CUSTOM_COMMAND) || - elantech_ps2_command<0>(NULL, ETP_REGISTER_WRITE) || - elantech_ps2_command<0>(NULL, ETP_PS2_CUSTOM_COMMAND) || - elantech_ps2_command<0>(NULL, reg) || - elantech_ps2_command<0>(NULL, ETP_PS2_CUSTOM_COMMAND) || - elantech_ps2_command<0>(NULL, val) || - elantech_ps2_command<0>(NULL, kDP_SetMouseScaling1To1)) { - rc = -1; - } - break; - - case 3: - if (elantech_ps2_command<0>(NULL, ETP_PS2_CUSTOM_COMMAND) || - elantech_ps2_command<0>(NULL, ETP_REGISTER_READWRITE) || - elantech_ps2_command<0>(NULL, ETP_PS2_CUSTOM_COMMAND) || - elantech_ps2_command<0>(NULL, reg) || - elantech_ps2_command<0>(NULL, ETP_PS2_CUSTOM_COMMAND) || - elantech_ps2_command<0>(NULL, val) || - elantech_ps2_command<0>(NULL, kDP_SetMouseScaling1To1)) { - rc = -1; - } - break; - - case 4: - if (elantech_ps2_command<0>(NULL, ETP_PS2_CUSTOM_COMMAND) || - elantech_ps2_command<0>(NULL, ETP_REGISTER_READWRITE) || - elantech_ps2_command<0>(NULL, ETP_PS2_CUSTOM_COMMAND) || - elantech_ps2_command<0>(NULL, reg) || - elantech_ps2_command<0>(NULL, ETP_PS2_CUSTOM_COMMAND) || - elantech_ps2_command<0>(NULL, ETP_REGISTER_READWRITE) || - elantech_ps2_command<0>(NULL, ETP_PS2_CUSTOM_COMMAND) || - elantech_ps2_command<0>(NULL, val) || - elantech_ps2_command<0>(NULL, kDP_SetMouseScaling1To1)) { - rc = -1; - } - break; + case 1: + if (ps2_sliced_command(ETP_REGISTER_WRITE) || + ps2_sliced_command(reg) || + ps2_sliced_command(val) || + ps2_command<0>(NULL, kDP_SetMouseScaling1To1)) { + rc = -1; + } + break; + + case 2: + if (elantech_ps2_command<0>(NULL, ETP_PS2_CUSTOM_COMMAND) || + elantech_ps2_command<0>(NULL, ETP_REGISTER_WRITE) || + elantech_ps2_command<0>(NULL, ETP_PS2_CUSTOM_COMMAND) || + elantech_ps2_command<0>(NULL, reg) || + elantech_ps2_command<0>(NULL, ETP_PS2_CUSTOM_COMMAND) || + elantech_ps2_command<0>(NULL, val) || + elantech_ps2_command<0>(NULL, kDP_SetMouseScaling1To1)) { + rc = -1; + } + break; + + case 3: + if (elantech_ps2_command<0>(NULL, ETP_PS2_CUSTOM_COMMAND) || + elantech_ps2_command<0>(NULL, ETP_REGISTER_READWRITE) || + elantech_ps2_command<0>(NULL, ETP_PS2_CUSTOM_COMMAND) || + elantech_ps2_command<0>(NULL, reg) || + elantech_ps2_command<0>(NULL, ETP_PS2_CUSTOM_COMMAND) || + elantech_ps2_command<0>(NULL, val) || + elantech_ps2_command<0>(NULL, kDP_SetMouseScaling1To1)) { + rc = -1; + } + break; + + case 4: + if (elantech_ps2_command<0>(NULL, ETP_PS2_CUSTOM_COMMAND) || + elantech_ps2_command<0>(NULL, ETP_REGISTER_READWRITE) || + elantech_ps2_command<0>(NULL, ETP_PS2_CUSTOM_COMMAND) || + elantech_ps2_command<0>(NULL, reg) || + elantech_ps2_command<0>(NULL, ETP_PS2_CUSTOM_COMMAND) || + elantech_ps2_command<0>(NULL, ETP_REGISTER_READWRITE) || + elantech_ps2_command<0>(NULL, ETP_PS2_CUSTOM_COMMAND) || + elantech_ps2_command<0>(NULL, val) || + elantech_ps2_command<0>(NULL, kDP_SetMouseScaling1To1)) { + rc = -1; + } + break; } if (rc) @@ -1478,45 +1478,44 @@ void ApplePS2Elan::elantechReportAbsoluteV3(int packetType) fingers = (packet[0] & 0xc0) >> 6; switch (fingers) { - case 3: - case 1: - /* - * byte 1: . . . . x11 x10 x9 x8 - * byte 2: x7 x6 x5 x4 x4 x2 x1 x0 - */ - x1 = ((packet[1] & 0x0f) << 8) | packet[2]; - /* - * byte 4: . . . . y11 y10 y9 y8 - * byte 5: y7 y6 y5 y4 y3 y2 y1 y0 - */ - y1 = info.y_max - (((packet[4] & 0x0f) << 8) | packet[5]); - break; - - case 2: - if (packetType == PACKET_V3_HEAD) { - /* - * byte 1: . . . . ax11 ax10 ax9 ax8 - * byte 2: ax7 ax6 ax5 ax4 ax3 ax2 ax1 ax0 - */ - etd.mt[0].x = ((packet[1] & 0x0f) << 8) | packet[2]; + case 3: + case 1: /* - * byte 4: . . . . ay11 ay10 ay9 ay8 - * byte 5: ay7 ay6 ay5 ay4 ay3 ay2 ay1 ay0 + * byte 1: . . . . x11 x10 x9 x8 + * byte 2: x7 x6 x5 x4 x4 x2 x1 x0 */ - etd.mt[0].y = info.y_max - - (((packet[4] & 0x0f) << 8) | packet[5]); + x1 = ((packet[1] & 0x0f) << 8) | packet[2]; /* - * wait for next packet + * byte 4: . . . . y11 y10 y9 y8 + * byte 5: y7 y6 y5 y4 y3 y2 y1 y0 */ - return; - } + y1 = info.y_max - (((packet[4] & 0x0f) << 8) | packet[5]); + break; + + case 2: + if (packetType == PACKET_V3_HEAD) { + /* + * byte 1: . . . . ax11 ax10 ax9 ax8 + * byte 2: ax7 ax6 ax5 ax4 ax3 ax2 ax1 ax0 + */ + etd.mt[0].x = ((packet[1] & 0x0f) << 8) | packet[2]; + /* + * byte 4: . . . . ay11 ay10 ay9 ay8 + * byte 5: ay7 ay6 ay5 ay4 ay3 ay2 ay1 ay0 + */ + etd.mt[0].y = info.y_max - (((packet[4] & 0x0f) << 8) | packet[5]); + /* + * wait for next packet + */ + return; + } - /* packet_type == PACKET_V3_TAIL */ + /* packet_type == PACKET_V3_TAIL */ x1 = etd.mt[0].x; y1 = etd.mt[0].y; x2 = ((packet[1] & 0x0f) << 8) | packet[2]; y2 = info.y_max - (((packet[4] & 0x0f) << 8) | packet[5]); - break; + break; } pres = (packet[1] & 0xf0) | ((packet[4] & 0xf0) >> 4); @@ -2052,7 +2051,7 @@ void ApplePS2Elan::packetReady() } } -void ApplePS2Elan::elantechTouchpadEnable(bool enable ) +void ApplePS2Elan::elantechTouchpadEnable(bool enable) { ps2_command<0>(NULL, enable ? kDP_Enable : kDP_SetDefaultsAndDisable); } diff --git a/VoodooPS2Trackpad/VoodooPS2Elan.h b/VoodooPS2Trackpad/VoodooPS2Elan.h index a21a0bac..18e293b7 100644 --- a/VoodooPS2Trackpad/VoodooPS2Elan.h +++ b/VoodooPS2Trackpad/VoodooPS2Elan.h @@ -163,7 +163,7 @@ struct virtual_finger_state { uint8_t width; bool touch; bool button; - MT2FingerType fingerType; + MT2FingerType fingerType; }; struct virtual_finger_state_2 { @@ -371,21 +371,20 @@ struct elantech_data { class EXPORT ApplePS2Elan : public IOHIPointing { typedef IOHIPointing super; - OSDeclareDefaultStructors(ApplePS2Elan); + OSDeclareDefaultStructors(ApplePS2Elan); private: IOService* voodooInputInstance {nullptr}; ApplePS2MouseDevice* _device {nullptr}; - bool _interruptHandlerInstalled {false}; + bool _interruptHandlerInstalled {false}; bool _powerControlHandlerInstalled {false}; - UInt32 _packetByteCount {0}; - UInt8 _lastdata {0}; + UInt32 _packetByteCount {0}; RingBuffer _ringBuffer {}; - IOCommandGate* _cmdGate {nullptr}; + IOCommandGate* _cmdGate {nullptr}; IOACPIPlatformDevice* _provider {nullptr}; - VoodooInputEvent inputEvent {}; + VoodooInputEvent inputEvent {}; // when trackpad has physical buttons @@ -424,7 +423,7 @@ class EXPORT ApplePS2Elan : public IOHIPointing int _set_hw_resolution {false}; - static_assert(SYNAPTICS_MAX_FINGERS <= kMT2FingerTypeLittleFinger, "Too many fingers for one hand"); + static_assert(SYNAPTICS_MAX_FINGERS <= kMT2FingerTypeLittleFinger, "Too many fingers for one hand"); bool ignoreall {false}; bool usb_mouse_stops_trackpad {true}; @@ -440,7 +439,7 @@ class EXPORT ApplePS2Elan : public IOHIPointing IONotifier* bluetooth_hid_publish_notify {nullptr}; // Notification when a bluetooth HID device is connected IONotifier* bluetooth_hid_terminate_notify {nullptr}; // Notification when a bluetooth HID device is disconnected - virtual PS2InterruptResult interruptOccurred(UInt8 data); + virtual PS2InterruptResult interruptOccurred(UInt8 data); virtual void packetReady(); virtual void setDevicePowerState(UInt32 whatToDo); @@ -476,7 +475,7 @@ class EXPORT ApplePS2Elan : public IOHIPointing void processPacketHeadV4(); void processPacketMotionV4(); void elantechInputSyncV4(); - void elantechTouchpadEnable(bool enable ); + void elantechTouchpadEnable(bool enable); template int ps2_command(UInt8* params, unsigned int command); @@ -501,16 +500,16 @@ class EXPORT ApplePS2Elan : public IOHIPointing } public: - bool init (OSDictionary* properties) override; - ApplePS2Elan* probe (IOService* provider, SInt32 * score) override; - bool start (IOService* provider ) override; - void stop (IOService* provider ) override; + bool init(OSDictionary* properties) override; + ApplePS2Elan* probe(IOService* provider, SInt32 * score) override; + bool start(IOService* provider) override; + void stop(IOService* provider) override; UInt32 deviceType() override; UInt32 interfaceID() override; - IOReturn setParamProperties(OSDictionary* dict) override; - IOReturn setProperties(OSObject *props) override; + IOReturn setParamProperties(OSDictionary* dict) override; + IOReturn setProperties(OSObject *props) override; // IOReturn message(UInt32 type, IOService* provider, void* argument) override; }; From 6bd360bab8dacd09a0b141fdd5425d41cccf6e19 Mon Sep 17 00:00:00 2001 From: Le Bao Hiep Date: Wed, 9 Sep 2020 00:25:24 +0700 Subject: [PATCH 05/40] Sort alphabetically --- VoodooPS2Controller.xcodeproj/project.pbxproj | 4 +- .../VoodooPS2Trackpad-Info.plist | 126 +++++++++--------- 2 files changed, 65 insertions(+), 65 deletions(-) diff --git a/VoodooPS2Controller.xcodeproj/project.pbxproj b/VoodooPS2Controller.xcodeproj/project.pbxproj index bcbd3eeb..099e7914 100644 --- a/VoodooPS2Controller.xcodeproj/project.pbxproj +++ b/VoodooPS2Controller.xcodeproj/project.pbxproj @@ -301,13 +301,13 @@ 356B895D23007F1A0042F30F /* VoodooInput Headers */, 84833FAC161B62A900845294 /* VoodooPS2ALPSGlidePoint.h */, 84833FAB161B62A900845294 /* VoodooPS2ALPSGlidePoint.cpp */, + 9828A92D24A2B6C200550FAA /* VoodooPS2Elan.cpp */, + 9828A92E24A2B6C200550FAA /* VoodooPS2Elan.h */, 84833FAE161B62A900845294 /* VoodooPS2SentelicFSP.h */, 84833FAD161B62A900845294 /* VoodooPS2SentelicFSP.cpp */, 84833FB0161B62A900845294 /* VoodooPS2SynapticsTouchPad.h */, 84833FAF161B62A900845294 /* VoodooPS2SynapticsTouchPad.cpp */, 84167857161B56C4002C60E6 /* Supporting Files */, - 9828A92D24A2B6C200550FAA /* VoodooPS2Elan.cpp */, - 9828A92E24A2B6C200550FAA /* VoodooPS2Elan.h */, ); path = VoodooPS2Trackpad; sourceTree = ""; diff --git a/VoodooPS2Trackpad/VoodooPS2Trackpad-Info.plist b/VoodooPS2Trackpad/VoodooPS2Trackpad-Info.plist index 47524ea8..64d8ac91 100644 --- a/VoodooPS2Trackpad/VoodooPS2Trackpad-Info.plist +++ b/VoodooPS2Trackpad/VoodooPS2Trackpad-Info.plist @@ -22,6 +22,69 @@ ${MODULE_VERSION} IOKitPersonalities + ALPS GlidePoint + + CFBundleIdentifier + as.acidanthera.voodoo.driver.PS2Trackpad + IOClass + ApplePS2ALPSGlidePoint + IOProbeScore + 1500 + IOProviderClass + ApplePS2MouseDevice + Platform Profile + + Default + + DisableDevice + + + HPQOEM + + 1411 + ProBook + 1619 + ProBook + 161C + ProBook + 164F + ProBook + 167C + ProBook + 167E + ProBook + 1680 + ProBook + 179B + ProBook + 179C + ProBook + 17A9 + ProBook + 17F0 + ProBook + 17F3 + ProBook + 17F6 + ProBook + 1942 + ProBook + 1949 + ProBook + 198F + ProBook + ProBook + + DisableDevice + + + ProBook-102 + ProBook + ProBook-87 + ProBook + + + Elantech TouchPad IOProbeScore @@ -86,69 +149,6 @@ - ALPS GlidePoint - - CFBundleIdentifier - as.acidanthera.voodoo.driver.PS2Trackpad - IOClass - ApplePS2ALPSGlidePoint - IOProbeScore - 1500 - IOProviderClass - ApplePS2MouseDevice - Platform Profile - - Default - - DisableDevice - - - HPQOEM - - 1411 - ProBook - 1619 - ProBook - 161C - ProBook - 164F - ProBook - 167C - ProBook - 167E - ProBook - 1680 - ProBook - 179B - ProBook - 179C - ProBook - 17A9 - ProBook - 17F0 - ProBook - 17F3 - ProBook - 17F6 - ProBook - 1942 - ProBook - 1949 - ProBook - 198F - ProBook - ProBook - - DisableDevice - - - ProBook-102 - ProBook - ProBook-87 - ProBook - - - Native Multitouch Engine CFBundleIdentifier From 2a8868f187f14104444fbabe9bfda20931906f46 Mon Sep 17 00:00:00 2001 From: Le Bao Hiep Date: Sun, 13 Sep 2020 03:45:49 +0700 Subject: [PATCH 06/40] Cleanup unused code --- VoodooPS2Trackpad/VoodooPS2Elan.cpp | 8 +- VoodooPS2Trackpad/VoodooPS2Elan.h | 151 +--------------------------- 2 files changed, 6 insertions(+), 153 deletions(-) diff --git a/VoodooPS2Trackpad/VoodooPS2Elan.cpp b/VoodooPS2Trackpad/VoodooPS2Elan.cpp index 77bc6c85..2976b641 100644 --- a/VoodooPS2Trackpad/VoodooPS2Elan.cpp +++ b/VoodooPS2Trackpad/VoodooPS2Elan.cpp @@ -1401,11 +1401,11 @@ int ApplePS2Elan::elantechSetupPS2() request.commands[1].command = kPS2C_SendMouseCommandAndCompareAck; request.commands[1].inOrOut = kDP_SetMouseSampleRate; // 0xF3 request.commands[2].command = kPS2C_SendMouseCommandAndCompareAck; - request.commands[2].inOrOut = _mouseSampleRate ; //0x64 * 2; // 200 dpi + request.commands[2].inOrOut = _mouseSampleRate; // 200 dpi request.commands[3].command = kPS2C_SendMouseCommandAndCompareAck; request.commands[3].inOrOut = kDP_SetMouseResolution; // 0xE8 request.commands[4].command = kPS2C_SendMouseCommandAndCompareAck; - request.commands[4].inOrOut = _mouseResolution; // 0x03; // 0x03 = 8 counts/mm + request.commands[4].inOrOut = _mouseResolution; // 0x03 = 8 counts/mm request.commands[5].command = kPS2C_SendMouseCommandAndCompareAck; request.commands[5].inOrOut = kDP_SetMouseScaling1To1; // 0xE6 request.commands[6].command = kPS2C_SendMouseCommandAndCompareAck; @@ -1420,9 +1420,9 @@ PS2InterruptResult ApplePS2Elan::interruptOccurred(UInt8 data) { UInt8* packet = _ringBuffer.head(); packet[_packetByteCount++] = data; - if (_packetByteCount == kPacketLengthMax) + if (_packetByteCount == kPacketLength) { - _ringBuffer.advanceHead(kPacketLengthMax); + _ringBuffer.advanceHead(kPacketLength); _packetByteCount = 0; return kPS2IR_packetReady; } diff --git a/VoodooPS2Trackpad/VoodooPS2Elan.h b/VoodooPS2Trackpad/VoodooPS2Elan.h index 18e293b7..2f295bb0 100644 --- a/VoodooPS2Trackpad/VoodooPS2Elan.h +++ b/VoodooPS2Trackpad/VoodooPS2Elan.h @@ -22,151 +22,7 @@ #include "VoodooInputMultitouch/VoodooInputEvent.h" -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -// SimpleAverage Class Declaration -// - -template -class SimpleAverage -{ -private: - T m_buffer[N]; - int m_count; - int m_sum; - int m_index; - -public: - inline SimpleAverage() { reset(); } - T filter(T data) - { - // add new entry to sum - m_sum += data; - // if full buffer, then we are overwriting, so subtract old from sum - if (m_count == N) - m_sum -= m_buffer[m_index]; - // new entry into buffer - m_buffer[m_index] = data; - // move index to next position with wrap around - if (++m_index >= N) - m_index = 0; - // keep count moving until buffer is full - if (m_count < N) - ++m_count; - // return average of current items - return m_sum / m_count; - } - inline void reset() - { - m_count = 0; - m_sum = 0; - m_index = 0; - } - inline int count() const { return m_count; } - inline int sum() const { return m_sum; } - T oldest() const - { - // undefined if nothing in here, return zero - if (m_count == 0) - return 0; - // if it is not full, oldest is at index 0 - // if full, it is right where the next one goes - if (m_count < N) - return m_buffer[0]; - else - return m_buffer[m_index]; - } - T newest() const - { - // undefined if nothing in here, return zero - if (m_count == 0) - return 0; - // newest is index - 1, with wrap - int index = m_index; - if (--index < 0) - index = m_count-1; - return m_buffer[index]; - } - T average() const - { - if (m_count == 0) - return 0; - return m_sum / m_count; - } -}; - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -// DecayingAverage Class Declaration -// - -template -class DecayingAverage -{ -private: - T m_last; - bool m_lastvalid; - -public: - inline DecayingAverage() { reset(); } - T filter(T data, int fingers) - { - TT result = data; - TT last = m_last; - if (m_lastvalid) - result = (result * N1) / D + (last * N2) / D; - m_lastvalid = true; - m_last = (T)result; - return m_last; - } - inline void reset() - { - m_lastvalid = false; - } -}; - -template -class UndecayAverage -{ -private: - T m_last; - bool m_lastvalid; - -public: - inline UndecayAverage() { reset(); } - T filter(T data) - { - TT result = data; - TT last = m_last; - if (m_lastvalid) - result = (result * D) / N1 - (last * N2) / N1; - m_lastvalid = true; - m_last = (T)data; - return (T)result; - } - inline void reset() - { - m_lastvalid = false; - } -}; - -struct synaptics_hw_state { - int x; - int y; - int z; - int w; - int virtualFingerIndex; -}; - struct virtual_finger_state { - SimpleAverage x_avg; - SimpleAverage y_avg; - uint8_t pressure; - uint8_t width; - bool touch; - bool button; - MT2FingerType fingerType; -}; - -struct virtual_finger_state_2 { TouchCoordinates prev; TouchCoordinates now; bool touch; @@ -182,10 +38,7 @@ typedef enum { FORCE_TOUCH_CUSTOM = 4 } ForceTouchMode; -#define SYNAPTICS_MAX_FINGERS 5 - #define kPacketLength 6 -#define kPacketLengthMax 6 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // @@ -409,7 +262,7 @@ class EXPORT ApplePS2Elan : public IOHIPointing int heldFingers = 0; int headPacketsCount = 0; - virtual_finger_state_2 virtualFinger[ETP_MAX_FINGERS] {}; + virtual_finger_state virtualFinger[ETP_MAX_FINGERS] {}; int _scrollresolution {2300}; int wakedelay {1000}; @@ -423,7 +276,7 @@ class EXPORT ApplePS2Elan : public IOHIPointing int _set_hw_resolution {false}; - static_assert(SYNAPTICS_MAX_FINGERS <= kMT2FingerTypeLittleFinger, "Too many fingers for one hand"); + static_assert(ETP_MAX_FINGERS <= kMT2FingerTypeLittleFinger, "Too many fingers for one hand"); bool ignoreall {false}; bool usb_mouse_stops_trackpad {true}; From 7051549f3141812b5760b069f3313101a0a3eb29 Mon Sep 17 00:00:00 2001 From: Le Bao Hiep Date: Sun, 13 Sep 2020 15:53:10 +0700 Subject: [PATCH 07/40] Fix gestures for trackpad without trackpoint --- VoodooPS2Trackpad/VoodooPS2Elan.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VoodooPS2Trackpad/VoodooPS2Elan.cpp b/VoodooPS2Trackpad/VoodooPS2Elan.cpp index 2976b641..52bba57f 100644 --- a/VoodooPS2Trackpad/VoodooPS2Elan.cpp +++ b/VoodooPS2Trackpad/VoodooPS2Elan.cpp @@ -1593,7 +1593,7 @@ int ApplePS2Elan::elantechPacketCheckV4() INTERRUPT_LOG("VoodooPS2Elan: Packet dump (%04x, %04x, %04x, %04x, %04x, %04x)\n", packet[0], packet[1], packet[2], packet[3], packet[4], packet[5] ); - if ((packet[3] & 0x0f) == 0x06) + if (info.has_trackpoint && (packet[3] & 0x0f) == 0x06) return PACKET_TRACKPOINT; /* This represents the version of IC body. */ From 0dfacf6dd5e6a43433dc003c447af876619f7237 Mon Sep 17 00:00:00 2001 From: Le Bao Hiep Date: Sun, 13 Sep 2020 19:38:18 +0700 Subject: [PATCH 08/40] Some cleanup --- VoodooPS2Trackpad/VoodooPS2Elan.cpp | 32 ++++++++--------------------- VoodooPS2Trackpad/VoodooPS2Elan.h | 2 +- 2 files changed, 9 insertions(+), 25 deletions(-) diff --git a/VoodooPS2Trackpad/VoodooPS2Elan.cpp b/VoodooPS2Trackpad/VoodooPS2Elan.cpp index 52bba57f..3b2825a3 100644 --- a/VoodooPS2Trackpad/VoodooPS2Elan.cpp +++ b/VoodooPS2Trackpad/VoodooPS2Elan.cpp @@ -41,23 +41,6 @@ #include "VoodooInputMultitouch/VoodooInputTransducer.h" #include "VoodooInputMultitouch/VoodooInputMessages.h" - -#define kIOFBTransformKey "IOFBTransform" - -enum { - // transforms - kIOFBRotateFlags = 0x0000000f, - - kIOFBSwapAxes = 0x00000001, - kIOFBInvertX = 0x00000002, - kIOFBInvertY = 0x00000004, - - kIOFBRotate0 = 0x00000000, - kIOFBRotate90 = kIOFBSwapAxes | kIOFBInvertX, - kIOFBRotate180 = kIOFBInvertX | kIOFBInvertY, - kIOFBRotate270 = kIOFBSwapAxes | kIOFBInvertY -}; - // ============================================================================= // ApplePS2Elan Class Implementation // @@ -1581,7 +1564,7 @@ void ApplePS2Elan::elantechReportAbsoluteV3(int packetType) } lastFingersV3 = fingers; - elantechInputSyncV4(); + sendTouchData(); } int ApplePS2Elan::elantechPacketCheckV4() @@ -1669,7 +1652,7 @@ void ApplePS2Elan::processPacketStatusV4() { // so that we report all fingers at once. // if count == 0, we have to report the fact fingers are taken off, because there won't be any HEAD packets if (count == 0) - elantechInputSyncV4(); + sendTouchData(); } void ApplePS2Elan::reportLeft(int state, int finger, bool status) @@ -1757,7 +1740,7 @@ void ApplePS2Elan::processPacketHeadV4() { if (headPacketsCount == heldFingers) { headPacketsCount = 0; - elantechInputSyncV4(); + sendTouchData(); } } @@ -1816,7 +1799,7 @@ void ApplePS2Elan::processPacketMotionV4() { //reportMiddle(packet[3] & 4, sid+1); } - elantechInputSyncV4(); + sendTouchData(); } void ApplePS2Elan::elantechReportTrackpoint() { @@ -1855,20 +1838,21 @@ static MT2FingerType GetBestFingerType(int i) { return kMT2FingerTypeIndexFinger; } -void ApplePS2Elan::elantechInputSyncV4() { +void ApplePS2Elan::sendTouchData() { AbsoluteTime timestamp; clock_get_uptime(×tamp); bool is_buttonpad = elantech_is_buttonpad(); + static_assert(VOODOO_INPUT_MAX_TRANSDUCERS >= ETP_MAX_FINGERS, "Trackpad supports too many fingers"); + int count = 0; - for (int i = 0; i < 5; ++i){ + for (int i = 0; i < ETP_MAX_FINGERS; ++i){ if (!virtualFinger[i].touch) continue; inputEvent.transducers[count].currentCoordinates = virtualFinger[i].now; inputEvent.transducers[count].previousCoordinates = virtualFinger[i].prev; - inputEvent.transducers[count].isValid = true; inputEvent.transducers[count].isPhysicalButtonDown = is_buttonpad && virtualFinger[i].button; diff --git a/VoodooPS2Trackpad/VoodooPS2Elan.h b/VoodooPS2Trackpad/VoodooPS2Elan.h index 2f295bb0..808d2fdf 100644 --- a/VoodooPS2Trackpad/VoodooPS2Elan.h +++ b/VoodooPS2Trackpad/VoodooPS2Elan.h @@ -327,7 +327,7 @@ class EXPORT ApplePS2Elan : public IOHIPointing void processPacketStatusV4(); void processPacketHeadV4(); void processPacketMotionV4(); - void elantechInputSyncV4(); + void sendTouchData(); void elantechTouchpadEnable(bool enable); template From 91173a75919262705de82b34dc99c47154b72bda Mon Sep 17 00:00:00 2001 From: Le Bao Hiep Date: Sun, 13 Sep 2020 19:51:44 +0700 Subject: [PATCH 09/40] Rename and reorder functions Related functions are grouped together --- VoodooPS2Trackpad/VoodooPS2Elan.cpp | 691 ++++++++++++++-------------- VoodooPS2Trackpad/VoodooPS2Elan.h | 16 +- 2 files changed, 351 insertions(+), 356 deletions(-) diff --git a/VoodooPS2Trackpad/VoodooPS2Elan.cpp b/VoodooPS2Trackpad/VoodooPS2Elan.cpp index 3b2825a3..aff871a4 100644 --- a/VoodooPS2Trackpad/VoodooPS2Elan.cpp +++ b/VoodooPS2Trackpad/VoodooPS2Elan.cpp @@ -316,7 +316,7 @@ bool ApplePS2Elan::start(IOService* provider) OSMemberFunctionCast(PS2PacketAction, this, &ApplePS2Elan::packetReady)); _interruptHandlerInstalled = true; - elantechTouchpadEnable(true); + setTouchPadEnable(true); // now safe to allow other threads _device->unlock(); @@ -367,7 +367,7 @@ void ApplePS2Elan::stop( IOService * provider ) // Disable the mouse itself, so that it may stop reporting mouse events. // - elantechTouchpadEnable(false); + setTouchPadEnable(false); // free up timer for scroll momentum IOWorkLoop* pWorkLoop = getWorkLoop(); @@ -529,7 +529,7 @@ void ApplePS2Elan::setDevicePowerState( UInt32 whatToDo ) // Disable touchpad (synchronous). // - elantechTouchpadEnable(false); + setTouchPadEnable(false); break; case kPS2C_EnableDevice: @@ -551,7 +551,7 @@ void ApplePS2Elan::setDevicePowerState( UInt32 whatToDo ) _packetByteCount = 0; _ringBuffer.reset(); - elantechTouchpadEnable(true); + setTouchPadEnable(true); break; } } @@ -837,7 +837,6 @@ static unsigned int elantech_convert_res(unsigned int val) return (val * 10 + 790) * 10 / 254; } - int ApplePS2Elan::elantech_get_resolution_v4(unsigned int *x_res, unsigned int *y_res, unsigned int *bus) @@ -910,64 +909,6 @@ int ApplePS2Elan::elantechDetect() return 0; } -/* - * determine hardware version and set some properties according to it. - */ -int ApplePS2Elan::elantechSetProperties() -{ - /* This represents the version of IC body. */ - int ver = (info.fw_version & 0x0f0000) >> 16; - - /* Early version of Elan touchpads doesn't obey the rule. */ - if (info.fw_version < 0x020030 || info.fw_version == 0x020600) - info.hw_version = 1; - else { - switch (ver) { - case 2: - case 4: - info.hw_version = 2; - break; - case 5: - info.hw_version = 3; - break; - case 6 ... 15: - info.hw_version = 4; - break; - default: - return -1; - } - } - - /* Turn on packet checking by default */ - info.paritycheck = 1; - - /* - * This firmware suffers from misreporting coordinates when - * a touch action starts causing the mouse cursor or scrolled page - * to jump. Enable a workaround. - */ - info.jumpy_cursor = (info.fw_version == 0x020022 || info.fw_version == 0x020600); - - if (info.hw_version > 1) { - /* For now show extra debug information */ - info.debug = 1; - - if (info.fw_version >= 0x020800) - info.reports_pressure = true; - } - - /* - * The signatures of v3 and v4 packets change depending on the - * value of this hardware flag. - */ - info.crc_enabled = (info.fw_version & 0x4000) == 0x4000; - - /* Enable real hardware resolution on hw_version 3 ? */ - info.set_hw_resolution = _set_hw_resolution;//!dmi_check_system(no_hw_res_dmi_table); - - return 0; -} - int ApplePS2Elan::elantechQueryInfo() { unsigned char param[3]; unsigned char traces; @@ -1120,135 +1061,80 @@ int ApplePS2Elan::elantechQueryInfo() { return 0; } -void ApplePS2Elan::resetMouse() { - UInt8 params[2]; - ps2_command<2>(params, kDP_Reset); - - if (params[0] != 0xaa && params[1] != 0x00) { - IOLog("VoodooPS2Elan: failed resetting.\n"); - } -} - /* - * Send an Elantech style special command to read a value from a register + * determine hardware version and set some properties according to it. */ -int ApplePS2Elan::elantechReadReg(unsigned char reg, unsigned char *val) { - unsigned char param[3]; - int rc = 0; - - if (reg < 0x07 || reg > 0x26) - return -1; +int ApplePS2Elan::elantechSetProperties() +{ + /* This represents the version of IC body. */ + int ver = (info.fw_version & 0x0f0000) >> 16; - if (reg > 0x11 && reg < 0x20) - return -1; + /* Early version of Elan touchpads doesn't obey the rule. */ + if (info.fw_version < 0x020030 || info.fw_version == 0x020600) + info.hw_version = 1; + else { + switch (ver) { + case 2: + case 4: + info.hw_version = 2; + break; + case 5: + info.hw_version = 3; + break; + case 6 ... 15: + info.hw_version = 4; + break; + default: + return -1; + } + } + + /* Turn on packet checking by default */ + info.paritycheck = 1; - switch (info.hw_version) { - case 1: - if (ps2_sliced_command(ETP_REGISTER_READ) || - ps2_sliced_command(reg) || - ps2_command<3>(param, kDP_GetMouseInformation)) { - rc = -1; - } - break; + /* + * This firmware suffers from misreporting coordinates when + * a touch action starts causing the mouse cursor or scrolled page + * to jump. Enable a workaround. + */ + info.jumpy_cursor = (info.fw_version == 0x020022 || info.fw_version == 0x020600); - case 2: - if (elantech_ps2_command<0>( NULL, ETP_PS2_CUSTOM_COMMAND) || - elantech_ps2_command<0>( NULL, ETP_REGISTER_READ) || - elantech_ps2_command<0>( NULL, ETP_PS2_CUSTOM_COMMAND) || - elantech_ps2_command<0>( NULL, reg) || - elantech_ps2_command<3>(param, kDP_GetMouseInformation)) { - rc = -1; - } - break; + if (info.hw_version > 1) { + /* For now show extra debug information */ + info.debug = 1; - case 3 ... 4: - if (elantech_ps2_command<0>(NULL, ETP_PS2_CUSTOM_COMMAND) || - elantech_ps2_command<0>(NULL, ETP_REGISTER_READWRITE) || - elantech_ps2_command<0>(NULL, ETP_PS2_CUSTOM_COMMAND) || - elantech_ps2_command<0>(NULL, reg) || - elantech_ps2_command<3>(param, kDP_GetMouseInformation)) { - rc = -1; - } - break; + if (info.fw_version >= 0x020800) + info.reports_pressure = true; } - if (rc) - IOLog("VoodooPS2Elan: failed to read register 0x%02x.\n", reg); - else if (info.hw_version != 4) - *val = param[0]; - else - *val = param[1]; + /* + * The signatures of v3 and v4 packets change depending on the + * value of this hardware flag. + */ + info.crc_enabled = (info.fw_version & 0x4000) == 0x4000; - return rc; + /* Enable real hardware resolution on hw_version 3 ? */ + info.set_hw_resolution = _set_hw_resolution;//!dmi_check_system(no_hw_res_dmi_table); + + return 0; } /* - * Send an Elantech style special command to write a register with a value + * Set the appropriate event bits for the input subsystem */ -int ApplePS2Elan::elantechWriteReg(unsigned char reg, unsigned char val) +int ApplePS2Elan::elantechSetInputParams() { - int rc = 0; - - if (reg < 0x07 || reg > 0x26) - return -1; - - if (reg > 0x11 && reg < 0x20) - return -1; - - switch (info.hw_version) { - case 1: - if (ps2_sliced_command(ETP_REGISTER_WRITE) || - ps2_sliced_command(reg) || - ps2_sliced_command(val) || - ps2_command<0>(NULL, kDP_SetMouseScaling1To1)) { - rc = -1; - } - break; - - case 2: - if (elantech_ps2_command<0>(NULL, ETP_PS2_CUSTOM_COMMAND) || - elantech_ps2_command<0>(NULL, ETP_REGISTER_WRITE) || - elantech_ps2_command<0>(NULL, ETP_PS2_CUSTOM_COMMAND) || - elantech_ps2_command<0>(NULL, reg) || - elantech_ps2_command<0>(NULL, ETP_PS2_CUSTOM_COMMAND) || - elantech_ps2_command<0>(NULL, val) || - elantech_ps2_command<0>(NULL, kDP_SetMouseScaling1To1)) { - rc = -1; - } - break; - - case 3: - if (elantech_ps2_command<0>(NULL, ETP_PS2_CUSTOM_COMMAND) || - elantech_ps2_command<0>(NULL, ETP_REGISTER_READWRITE) || - elantech_ps2_command<0>(NULL, ETP_PS2_CUSTOM_COMMAND) || - elantech_ps2_command<0>(NULL, reg) || - elantech_ps2_command<0>(NULL, ETP_PS2_CUSTOM_COMMAND) || - elantech_ps2_command<0>(NULL, val) || - elantech_ps2_command<0>(NULL, kDP_SetMouseScaling1To1)) { - rc = -1; - } - break; + setProperty(VOODOO_INPUT_LOGICAL_MAX_X_KEY, info.x_max - info.x_min, 32); + setProperty(VOODOO_INPUT_LOGICAL_MAX_Y_KEY, info.y_max - info.y_min, 32); - case 4: - if (elantech_ps2_command<0>(NULL, ETP_PS2_CUSTOM_COMMAND) || - elantech_ps2_command<0>(NULL, ETP_REGISTER_READWRITE) || - elantech_ps2_command<0>(NULL, ETP_PS2_CUSTOM_COMMAND) || - elantech_ps2_command<0>(NULL, reg) || - elantech_ps2_command<0>(NULL, ETP_PS2_CUSTOM_COMMAND) || - elantech_ps2_command<0>(NULL, ETP_REGISTER_READWRITE) || - elantech_ps2_command<0>(NULL, ETP_PS2_CUSTOM_COMMAND) || - elantech_ps2_command<0>(NULL, val) || - elantech_ps2_command<0>(NULL, kDP_SetMouseScaling1To1)) { - rc = -1; - } - break; - } + setProperty(VOODOO_INPUT_PHYSICAL_MAX_X_KEY, (info.x_max + 1) * 100 / info.x_res, 32); + setProperty(VOODOO_INPUT_PHYSICAL_MAX_Y_KEY, (info.y_max + 1) * 100 / info.y_res, 32); - if (rc) - IOLog("VoodooPS2Elan: failed to write register 0x%02x with value 0x%02x.\n", - reg, val); + setProperty("IOFBTransform", 0ull, 32); + setProperty("VoodooInputSupported", kOSBooleanTrue); + registerService(); - return rc; + return 0; } /* @@ -1333,24 +1219,6 @@ int ApplePS2Elan::elantechSetAbsoluteMode() return rc; } -/* - * Set the appropriate event bits for the input subsystem - */ -int ApplePS2Elan::elantechSetInputParams() -{ - setProperty(VOODOO_INPUT_LOGICAL_MAX_X_KEY, info.x_max - info.x_min, 32); - setProperty(VOODOO_INPUT_LOGICAL_MAX_Y_KEY, info.y_max - info.y_min, 32); - - setProperty(VOODOO_INPUT_PHYSICAL_MAX_X_KEY, (info.x_max + 1) * 100 / info.x_res, 32); - setProperty(VOODOO_INPUT_PHYSICAL_MAX_Y_KEY, (info.y_max + 1) * 100 / info.y_res, 32); - - setProperty("IOFBTransform", 0ull, 32); - setProperty("VoodooInputSupported", kOSBooleanTrue); - registerService(); - - return 0; -} - /* * Initialize the touchpad */ @@ -1399,18 +1267,126 @@ int ApplePS2Elan::elantechSetupPS2() return 0; } -PS2InterruptResult ApplePS2Elan::interruptOccurred(UInt8 data) { - UInt8* packet = _ringBuffer.head(); - packet[_packetByteCount++] = data; - - if (_packetByteCount == kPacketLength) - { - _ringBuffer.advanceHead(kPacketLength); - _packetByteCount = 0; - return kPS2IR_packetReady; +/* + * Send an Elantech style special command to read a value from a register + */ +int ApplePS2Elan::elantechReadReg(unsigned char reg, unsigned char *val) { + unsigned char param[3]; + int rc = 0; + + if (reg < 0x07 || reg > 0x26) + return -1; + + if (reg > 0x11 && reg < 0x20) + return -1; + + switch (info.hw_version) { + case 1: + if (ps2_sliced_command(ETP_REGISTER_READ) || + ps2_sliced_command(reg) || + ps2_command<3>(param, kDP_GetMouseInformation)) { + rc = -1; + } + break; + + case 2: + if (elantech_ps2_command<0>( NULL, ETP_PS2_CUSTOM_COMMAND) || + elantech_ps2_command<0>( NULL, ETP_REGISTER_READ) || + elantech_ps2_command<0>( NULL, ETP_PS2_CUSTOM_COMMAND) || + elantech_ps2_command<0>( NULL, reg) || + elantech_ps2_command<3>(param, kDP_GetMouseInformation)) { + rc = -1; + } + break; + + case 3 ... 4: + if (elantech_ps2_command<0>(NULL, ETP_PS2_CUSTOM_COMMAND) || + elantech_ps2_command<0>(NULL, ETP_REGISTER_READWRITE) || + elantech_ps2_command<0>(NULL, ETP_PS2_CUSTOM_COMMAND) || + elantech_ps2_command<0>(NULL, reg) || + elantech_ps2_command<3>(param, kDP_GetMouseInformation)) { + rc = -1; + } + break; } - return kPS2IR_packetBuffering; + if (rc) + IOLog("VoodooPS2Elan: failed to read register 0x%02x.\n", reg); + else if (info.hw_version != 4) + *val = param[0]; + else + *val = param[1]; + + return rc; +} + +/* + * Send an Elantech style special command to write a register with a value + */ +int ApplePS2Elan::elantechWriteReg(unsigned char reg, unsigned char val) +{ + int rc = 0; + + if (reg < 0x07 || reg > 0x26) + return -1; + + if (reg > 0x11 && reg < 0x20) + return -1; + + switch (info.hw_version) { + case 1: + if (ps2_sliced_command(ETP_REGISTER_WRITE) || + ps2_sliced_command(reg) || + ps2_sliced_command(val) || + ps2_command<0>(NULL, kDP_SetMouseScaling1To1)) { + rc = -1; + } + break; + + case 2: + if (elantech_ps2_command<0>(NULL, ETP_PS2_CUSTOM_COMMAND) || + elantech_ps2_command<0>(NULL, ETP_REGISTER_WRITE) || + elantech_ps2_command<0>(NULL, ETP_PS2_CUSTOM_COMMAND) || + elantech_ps2_command<0>(NULL, reg) || + elantech_ps2_command<0>(NULL, ETP_PS2_CUSTOM_COMMAND) || + elantech_ps2_command<0>(NULL, val) || + elantech_ps2_command<0>(NULL, kDP_SetMouseScaling1To1)) { + rc = -1; + } + break; + + case 3: + if (elantech_ps2_command<0>(NULL, ETP_PS2_CUSTOM_COMMAND) || + elantech_ps2_command<0>(NULL, ETP_REGISTER_READWRITE) || + elantech_ps2_command<0>(NULL, ETP_PS2_CUSTOM_COMMAND) || + elantech_ps2_command<0>(NULL, reg) || + elantech_ps2_command<0>(NULL, ETP_PS2_CUSTOM_COMMAND) || + elantech_ps2_command<0>(NULL, val) || + elantech_ps2_command<0>(NULL, kDP_SetMouseScaling1To1)) { + rc = -1; + } + break; + + case 4: + if (elantech_ps2_command<0>(NULL, ETP_PS2_CUSTOM_COMMAND) || + elantech_ps2_command<0>(NULL, ETP_REGISTER_READWRITE) || + elantech_ps2_command<0>(NULL, ETP_PS2_CUSTOM_COMMAND) || + elantech_ps2_command<0>(NULL, reg) || + elantech_ps2_command<0>(NULL, ETP_PS2_CUSTOM_COMMAND) || + elantech_ps2_command<0>(NULL, ETP_REGISTER_READWRITE) || + elantech_ps2_command<0>(NULL, ETP_PS2_CUSTOM_COMMAND) || + elantech_ps2_command<0>(NULL, val) || + elantech_ps2_command<0>(NULL, kDP_SetMouseScaling1To1)) { + rc = -1; + } + break; + } + + if (rc) + IOLog("VoodooPS2Elan: failed to write register 0x%02x with value 0x%02x.\n", + reg, val); + + return rc; } int ApplePS2Elan::elantechPacketCheckV3() @@ -1451,6 +1427,55 @@ int ApplePS2Elan::elantechPacketCheckV3() return PACKET_UNKNOWN; } +int ApplePS2Elan::elantechPacketCheckV4() +{ + unsigned char *packet = _ringBuffer.tail(); + unsigned char packet_type = packet[3] & 0x03; + unsigned int ic_version; + bool sanity_check; + + INTERRUPT_LOG("VoodooPS2Elan: Packet dump (%04x, %04x, %04x, %04x, %04x, %04x)\n", packet[0], packet[1], packet[2], packet[3], packet[4], packet[5] ); + + if (info.has_trackpoint && (packet[3] & 0x0f) == 0x06) + return PACKET_TRACKPOINT; + + /* This represents the version of IC body. */ + ic_version = (info.fw_version & 0x0f0000) >> 16; + + INTERRUPT_LOG("VoodooPS2Elan: icVersion(%d), crc(%d), samples[1](%d) \n", ic_version, info.crc_enabled, info.samples[1]); + + /* + * Sanity check based on the constant bits of a packet. + * The constant bits change depending on the value of + * the hardware flag 'crc_enabled' and the version of + * the IC body, but are the same for every packet, + * regardless of the type. + */ + if (info.crc_enabled) + sanity_check = ((packet[3] & 0x08) == 0x00); + else if (ic_version == 7 && info.samples[1] == 0x2A) + sanity_check = ((packet[3] & 0x1c) == 0x10); + else + sanity_check = ((packet[0] & 0x08) == 0x00 && + (packet[3] & 0x1c) == 0x10); + + if (!sanity_check) + return PACKET_UNKNOWN; + + switch (packet_type) { + case 0: + return PACKET_V4_STATUS; + + case 1: + return PACKET_V4_HEAD; + + case 2: + return PACKET_V4_MOTION; + } + + return PACKET_UNKNOWN; +} + void ApplePS2Elan::elantechReportAbsoluteV3(int packetType) { unsigned char *packet = _ringBuffer.tail(); @@ -1567,53 +1592,71 @@ void ApplePS2Elan::elantechReportAbsoluteV3(int packetType) sendTouchData(); } -int ApplePS2Elan::elantechPacketCheckV4() -{ - unsigned char *packet = _ringBuffer.tail(); - unsigned char packet_type = packet[3] & 0x03; - unsigned int ic_version; - bool sanity_check; - - INTERRUPT_LOG("VoodooPS2Elan: Packet dump (%04x, %04x, %04x, %04x, %04x, %04x)\n", packet[0], packet[1], packet[2], packet[3], packet[4], packet[5] ); - - if (info.has_trackpoint && (packet[3] & 0x0f) == 0x06) - return PACKET_TRACKPOINT; - - /* This represents the version of IC body. */ - ic_version = (info.fw_version & 0x0f0000) >> 16; - - INTERRUPT_LOG("VoodooPS2Elan: icVersion(%d), crc(%d), samples[1](%d) \n", ic_version, info.crc_enabled, info.samples[1]); +void ApplePS2Elan::elantechReportAbsoluteV4(int packetType) { + AbsoluteTime timestamp; + clock_get_uptime(×tamp); - /* - * Sanity check based on the constant bits of a packet. - * The constant bits change depending on the value of - * the hardware flag 'crc_enabled' and the version of - * the IC body, but are the same for every packet, - * regardless of the type. - */ - if (info.crc_enabled) - sanity_check = ((packet[3] & 0x08) == 0x00); - else if (ic_version == 7 && info.samples[1] == 0x2A) - sanity_check = ((packet[3] & 0x1c) == 0x10); - else - sanity_check = ((packet[0] & 0x08) == 0x00 && - (packet[3] & 0x1c) == 0x10); + inputEvent.timestamp = timestamp; - if (!sanity_check) - return PACKET_UNKNOWN; + switch (packetType) { + case PACKET_V4_STATUS: + INTERRUPT_LOG("VoodooPS2Elan: Got status packet\n"); + processPacketStatusV4(); + break; - switch (packet_type) { - case 0: - return PACKET_V4_STATUS; + case PACKET_V4_HEAD: + INTERRUPT_LOG("VoodooPS2Elan: Got head packet\n"); + processPacketHeadV4(); + break; - case 1: - return PACKET_V4_HEAD; + case PACKET_V4_MOTION: + INTERRUPT_LOG("VoodooPS2Elan: Got motion packet\n"); + processPacketMotionV4(); + break; + case PACKET_UNKNOWN: + default: + /* impossible to get here */ + break; + } + + if (voodooInputInstance) { + if (changed) + { + VoodooInputDimensions d; + d.min_x = info.x_min; + d.max_x = info.x_max; + d.min_y = info.y_min; + d.max_y = info.y_max; + super::messageClient(kIOMessageVoodooInputUpdateDimensionsMessage, voodooInputInstance, &d, sizeof(VoodooInputDimensions)); - case 2: - return PACKET_V4_MOTION; + changed = false; + } + } + else + INTERRUPT_LOG("VoodooPS2Elan: no voodooInputInstance\n"); +} - return PACKET_UNKNOWN; +void ApplePS2Elan::elantechReportTrackpoint() { + unsigned char *packet = _ringBuffer.tail(); + + trackpointLeftButton = packet[0] & 0x1; + trackpointRightButton = packet[0] & 0x2; + //middleButton = packet[0] & 0x4; + + int dx = packet[4]; + int dy = packet[5]; + + dx = packet[4] - (int)((packet[1]^0x80)<<1); + dy = (int)((packet[2]^0x80)<<1) - packet[5]; + + dx = dx * _trackpointMultiplierX / _trackpointDividerX; + dy = dy * _trackpointMultiplierY / _trackpointDividerY; + + AbsoluteTime timestamp; + clock_get_uptime(×tamp); + + dispatchRelativePointerEvent(dx, dy, trackpointRightButton | trackpointLeftButton /*| middleButton*/, timestamp); } void ApplePS2Elan::processPacketStatusV4() { @@ -1647,53 +1690,12 @@ void ApplePS2Elan::processPacketStatusV4() { headPacketsCount = 0; - // if count > 0 - // then we wait for HEAD packets to report - // so that we report all fingers at once. + // if count > 0, we wait for HEAD packets to report so that we report all fingers at once. // if count == 0, we have to report the fact fingers are taken off, because there won't be any HEAD packets if (count == 0) sendTouchData(); } -void ApplePS2Elan::reportLeft(int state, int finger, bool status) -{ - if (leftButtons[finger] != state) - { - auto str = status ? "STATUS" : "HEAD/MOTION"; - if (state == 0) - IOLog("VoodooPS2ElanButtons: [%s] left button, finger %d lifted (fingers on touchpad: %d)\n", str, finger, heldFingers); - else - IOLog("VoodooPS2ElanButtons: [%s] left button, finger %d pressed (fingers on touchpad: %d)\n", str, finger, heldFingers); - leftButtons[finger] = state; - } -} -/* -void ApplePS2Elan::reportMiddle(int state, int finger) -{ - if (middleButtons[finger] != state) - { - if (state == 0) - IOLog("VoodooPS2ElanButtons: middle button, finger %d lifted (fingers on touchpad: %d)\n", finger, heldFingers); - else - IOLog("VoodooPS2ElanButtons: middle button, finger %d pressed (fingers on touchpad: %d)\n", finger, heldFingers); - middleButtons[finger] = state; - } -}*/ - -void ApplePS2Elan::reportRight(int state, int finger, bool status) -{ - if (rightButtons[finger] != state) - { - auto str = status ? "STATUS" : "HEAD/MOTION"; - - if (state == 0) - IOLog("VoodooPS2ElanButtons: [%s] right button, finger %d lifted (fingers on touchpad: %d)\n", str, finger, heldFingers); - else - IOLog("VoodooPS2ElanButtons: [%s] right button, finger %d pressed (fingers on touchpad: %d)\n", str, finger, heldFingers); - rightButtons[finger] = state; - } -} - void ApplePS2Elan::processPacketHeadV4() { unsigned char *packet = _ringBuffer.tail(); @@ -1777,7 +1779,6 @@ void ApplePS2Elan::processPacketMotionV4() { //reportLeft(packet[0] & 1, id+1); //reportRight(packet[0] & 2, id+1); //reportMiddle(packet[0] & 4, id+1); - virtualFinger[id].button = (packet[0] & 1); virtualFinger[id].prev = virtualFinger[id].now; @@ -1802,26 +1803,43 @@ void ApplePS2Elan::processPacketMotionV4() { sendTouchData(); } -void ApplePS2Elan::elantechReportTrackpoint() { - unsigned char *packet = _ringBuffer.tail(); - - trackpointLeftButton = packet[0] & 0x1; - trackpointRightButton = packet[0] & 0x2; - //middleButton = packet[0] & 0x4; - - int dx = packet[4]; - int dy = packet[5]; - - dx = packet[4] - (int)((packet[1]^0x80)<<1); - dy = (int)((packet[2]^0x80)<<1) - packet[5]; - - dx = dx * _trackpointMultiplierX / _trackpointDividerX; - dy = dy * _trackpointMultiplierY / _trackpointDividerY; - - AbsoluteTime timestamp; - clock_get_uptime(×tamp); +void ApplePS2Elan::reportLeft(int state, int finger, bool status) +{ + if (leftButtons[finger] != state) + { + auto str = status ? "STATUS" : "HEAD/MOTION"; + if (state == 0) + IOLog("VoodooPS2ElanButtons: [%s] left button, finger %d lifted (fingers on touchpad: %d)\n", str, finger, heldFingers); + else + IOLog("VoodooPS2ElanButtons: [%s] left button, finger %d pressed (fingers on touchpad: %d)\n", str, finger, heldFingers); + leftButtons[finger] = state; + } +} +/* +void ApplePS2Elan::reportMiddle(int state, int finger) +{ + if (middleButtons[finger] != state) + { + if (state == 0) + IOLog("VoodooPS2ElanButtons: middle button, finger %d lifted (fingers on touchpad: %d)\n", finger, heldFingers); + else + IOLog("VoodooPS2ElanButtons: middle button, finger %d pressed (fingers on touchpad: %d)\n", finger, heldFingers); + middleButtons[finger] = state; + } +}*/ - dispatchRelativePointerEvent(dx, dy, trackpointRightButton | trackpointLeftButton /*| middleButton*/, timestamp); +void ApplePS2Elan::reportRight(int state, int finger, bool status) +{ + if (rightButtons[finger] != state) + { + auto str = status ? "STATUS" : "HEAD/MOTION"; + + if (state == 0) + IOLog("VoodooPS2ElanButtons: [%s] right button, finger %d lifted (fingers on touchpad: %d)\n", str, finger, heldFingers); + else + IOLog("VoodooPS2ElanButtons: [%s] right button, finger %d pressed (fingers on touchpad: %d)\n", str, finger, heldFingers); + rightButtons[finger] = state; + } } static MT2FingerType GetBestFingerType(int i) { @@ -1932,50 +1950,18 @@ void ApplePS2Elan::sendTouchData() { } } - -void ApplePS2Elan::elantechReportAbsoluteV4(int packetType) { - AbsoluteTime timestamp; - clock_get_uptime(×tamp); - - inputEvent.timestamp = timestamp; - - switch (packetType) { - case PACKET_V4_STATUS: - INTERRUPT_LOG("VoodooPS2Elan: Got status packet\n"); - processPacketStatusV4(); - break; - - case PACKET_V4_HEAD: - INTERRUPT_LOG("VoodooPS2Elan: Got head packet\n"); - processPacketHeadV4(); - break; - - case PACKET_V4_MOTION: - INTERRUPT_LOG("VoodooPS2Elan: Got motion packet\n"); - processPacketMotionV4(); - break; - case PACKET_UNKNOWN: - default: - /* impossible to get here */ - break; - } +PS2InterruptResult ApplePS2Elan::interruptOccurred(UInt8 data) { + UInt8* packet = _ringBuffer.head(); + packet[_packetByteCount++] = data; - if (voodooInputInstance) { - if (changed) - { - VoodooInputDimensions d; - d.min_x = info.x_min; - d.max_x = info.x_max; - d.min_y = info.y_min; - d.max_y = info.y_max; - super::messageClient(kIOMessageVoodooInputUpdateDimensionsMessage, voodooInputInstance, &d, sizeof(VoodooInputDimensions)); - - changed = false; - } - + if (_packetByteCount == kPacketLength) + { + _ringBuffer.advanceHead(kPacketLength); + _packetByteCount = 0; + return kPS2IR_packetReady; } - else - INTERRUPT_LOG("VoodooPS2Elan: no voodooInputInstance\n"); + + return kPS2IR_packetBuffering; } void ApplePS2Elan::packetReady() @@ -2035,7 +2021,16 @@ void ApplePS2Elan::packetReady() } } -void ApplePS2Elan::elantechTouchpadEnable(bool enable) +void ApplePS2Elan::resetMouse() { + UInt8 params[2]; + ps2_command<2>(params, kDP_Reset); + + if (params[0] != 0xaa && params[1] != 0x00) { + IOLog("VoodooPS2Elan: failed resetting.\n"); + } +} + +void ApplePS2Elan::setTouchPadEnable(bool enable) { ps2_command<0>(NULL, enable ? kDP_Enable : kDP_SetDefaultsAndDisable); } diff --git a/VoodooPS2Trackpad/VoodooPS2Elan.h b/VoodooPS2Trackpad/VoodooPS2Elan.h index 808d2fdf..adda7adc 100644 --- a/VoodooPS2Trackpad/VoodooPS2Elan.h +++ b/VoodooPS2Trackpad/VoodooPS2Elan.h @@ -311,24 +311,24 @@ class EXPORT ApplePS2Elan : public IOHIPointing elantech_data etd {}; elantech_device_info info {}; int elantechDetect(); - void resetMouse(); int elantechQueryInfo(); int elantechSetProperties(); - int elantechSetupPS2(); int elantechSetAbsoluteMode(); - int elantechWriteReg(unsigned char reg, unsigned char val); - int elantechReadReg(unsigned char reg, unsigned char *val); int elantechSetInputParams(); - int elantechPacketCheckV4(); + int elantechSetupPS2(); + int elantechReadReg(unsigned char reg, unsigned char *val); + int elantechWriteReg(unsigned char reg, unsigned char val); int elantechPacketCheckV3(); - void elantechReportTrackpoint(); - void elantechReportAbsoluteV4(int packetType); + int elantechPacketCheckV4(); void elantechReportAbsoluteV3(int packetType); + void elantechReportAbsoluteV4(int packetType); + void elantechReportTrackpoint(); void processPacketStatusV4(); void processPacketHeadV4(); void processPacketMotionV4(); void sendTouchData(); - void elantechTouchpadEnable(bool enable); + void resetMouse(); + void setTouchPadEnable(bool enable); template int ps2_command(UInt8* params, unsigned int command); From fdaf761a08805e54f7a2859c6186584d11619a57 Mon Sep 17 00:00:00 2001 From: Le Bao Hiep Date: Sun, 13 Sep 2020 19:57:27 +0700 Subject: [PATCH 10/40] Remove blank line --- VoodooPS2Trackpad/VoodooPS2Elan.cpp | 1 - VoodooPS2Trackpad/VoodooPS2Elan.h | 3 --- 2 files changed, 4 deletions(-) diff --git a/VoodooPS2Trackpad/VoodooPS2Elan.cpp b/VoodooPS2Trackpad/VoodooPS2Elan.cpp index aff871a4..eaee6a06 100644 --- a/VoodooPS2Trackpad/VoodooPS2Elan.cpp +++ b/VoodooPS2Trackpad/VoodooPS2Elan.cpp @@ -785,7 +785,6 @@ int ApplePS2Elan::synaptics_send_cmd(unsigned char c, unsigned char *param) return 0; } - /* * V3 and later support this fast command */ diff --git a/VoodooPS2Trackpad/VoodooPS2Elan.h b/VoodooPS2Trackpad/VoodooPS2Elan.h index adda7adc..27acd8bb 100644 --- a/VoodooPS2Trackpad/VoodooPS2Elan.h +++ b/VoodooPS2Trackpad/VoodooPS2Elan.h @@ -44,7 +44,6 @@ typedef enum { // // FROM LINUX ELANTECH.C - /* * Command values for Synaptics style queries */ @@ -215,8 +214,6 @@ struct elantech_data { unsigned char parity[256]; }; - - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // ApplePS2Elan Class Declaration // From 15ef9d2a0e736e92f2e10ad6e1a5698b8c799846 Mon Sep 17 00:00:00 2001 From: Le Bao Hiep Date: Sun, 13 Sep 2020 20:02:18 +0700 Subject: [PATCH 11/40] Fix indentations --- VoodooPS2Trackpad/VoodooPS2Elan.h | 88 ++++++++++++++----------------- 1 file changed, 40 insertions(+), 48 deletions(-) diff --git a/VoodooPS2Trackpad/VoodooPS2Elan.h b/VoodooPS2Trackpad/VoodooPS2Elan.h index 27acd8bb..e6a65b99 100644 --- a/VoodooPS2Trackpad/VoodooPS2Elan.h +++ b/VoodooPS2Trackpad/VoodooPS2Elan.h @@ -30,14 +30,6 @@ struct virtual_finger_state { MT2FingerType fingerType; }; -typedef enum { - FORCE_TOUCH_DISABLED = 0, - FORCE_TOUCH_BUTTON = 1, - FORCE_TOUCH_THRESHOLD = 2, - FORCE_TOUCH_VALUE = 3, - FORCE_TOUCH_CUSTOM = 4 -} ForceTouchMode; - #define kPacketLength 6 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -47,17 +39,17 @@ typedef enum { /* * Command values for Synaptics style queries */ -#define ETP_FW_ID_QUERY 0x00 -#define ETP_FW_VERSION_QUERY 0x01 +#define ETP_FW_ID_QUERY 0x00 +#define ETP_FW_VERSION_QUERY 0x01 #define ETP_CAPABILITIES_QUERY 0x02 -#define ETP_SAMPLE_QUERY 0x03 -#define ETP_RESOLUTION_QUERY 0x04 +#define ETP_SAMPLE_QUERY 0x03 +#define ETP_RESOLUTION_QUERY 0x04 /* * Command values for register reading or writing */ -#define ETP_REGISTER_READ 0x10 -#define ETP_REGISTER_WRITE 0x11 +#define ETP_REGISTER_READ 0x10 +#define ETP_REGISTER_WRITE 0x11 #define ETP_REGISTER_READWRITE 0x00 /* @@ -68,86 +60,86 @@ typedef enum { /* * Times to retry a ps2_command and millisecond delay between tries */ -#define ETP_PS2_COMMAND_TRIES 3 -#define ETP_PS2_COMMAND_DELAY 500 +#define ETP_PS2_COMMAND_TRIES 3 +#define ETP_PS2_COMMAND_DELAY 500 /* * Times to try to read back a register and millisecond delay between tries */ -#define ETP_READ_BACK_TRIES 5 -#define ETP_READ_BACK_DELAY 2000 +#define ETP_READ_BACK_TRIES 5 +#define ETP_READ_BACK_DELAY 2000 /* * Register bitmasks for hardware version 1 */ -#define ETP_R10_ABSOLUTE_MODE 0x04 -#define ETP_R11_4_BYTE_MODE 0x02 +#define ETP_R10_ABSOLUTE_MODE 0x04 +#define ETP_R11_4_BYTE_MODE 0x02 /* * Capability bitmasks */ -#define ETP_CAP_HAS_ROCKER 0x04 +#define ETP_CAP_HAS_ROCKER 0x04 /* * One hard to find application note states that X axis range is 0 to 576 * and Y axis range is 0 to 384 for harware version 1. * Edge fuzz might be necessary because of bezel around the touchpad */ -#define ETP_EDGE_FUZZ_V1 32 +#define ETP_EDGE_FUZZ_V1 32 -#define ETP_XMIN_V1 ( 0 + ETP_EDGE_FUZZ_V1) -#define ETP_XMAX_V1 (576 - ETP_EDGE_FUZZ_V1) -#define ETP_YMIN_V1 ( 0 + ETP_EDGE_FUZZ_V1) -#define ETP_YMAX_V1 (384 - ETP_EDGE_FUZZ_V1) +#define ETP_XMIN_V1 ( 0 + ETP_EDGE_FUZZ_V1) +#define ETP_XMAX_V1 (576 - ETP_EDGE_FUZZ_V1) +#define ETP_YMIN_V1 ( 0 + ETP_EDGE_FUZZ_V1) +#define ETP_YMAX_V1 (384 - ETP_EDGE_FUZZ_V1) /* * The resolution for older v2 hardware doubled. * (newer v2's firmware provides command so we can query) */ -#define ETP_XMIN_V2 0 -#define ETP_XMAX_V2 1152 -#define ETP_YMIN_V2 0 -#define ETP_YMAX_V2 768 +#define ETP_XMIN_V2 0 +#define ETP_XMAX_V2 1152 +#define ETP_YMIN_V2 0 +#define ETP_YMAX_V2 768 // Preasure min-max -#define ETP_PMIN_V2 0 -#define ETP_PMAX_V2 255 +#define ETP_PMIN_V2 0 +#define ETP_PMAX_V2 255 // Width min-max -#define ETP_WMIN_V2 0 -#define ETP_WMAX_V2 15 +#define ETP_WMIN_V2 0 +#define ETP_WMAX_V2 15 /* * v3 hardware has 2 kinds of packet types, * v4 hardware has 3. */ -#define PACKET_UNKNOWN 0x01 -#define PACKET_DEBOUNCE 0x02 -#define PACKET_V3_HEAD 0x03 -#define PACKET_V3_TAIL 0x04 -#define PACKET_V4_HEAD 0x05 -#define PACKET_V4_MOTION 0x06 -#define PACKET_V4_STATUS 0x07 -#define PACKET_TRACKPOINT 0x08 +#define PACKET_UNKNOWN 0x01 +#define PACKET_DEBOUNCE 0x02 +#define PACKET_V3_HEAD 0x03 +#define PACKET_V3_TAIL 0x04 +#define PACKET_V4_HEAD 0x05 +#define PACKET_V4_MOTION 0x06 +#define PACKET_V4_STATUS 0x07 +#define PACKET_TRACKPOINT 0x08 /* * track up to 5 fingers for v4 hardware */ -#define ETP_MAX_FINGERS 5 +#define ETP_MAX_FINGERS 5 /* * weight value for v4 hardware */ -#define ETP_WEIGHT_VALUE 5 +#define ETP_WEIGHT_VALUE 5 /* * Bus information on 3rd byte of query ETP_RESOLUTION_QUERY(0x04) */ -#define ETP_BUS_PS2_ONLY 0 +#define ETP_BUS_PS2_ONLY 0 #define ETP_BUS_SMB_ALERT_ONLY 1 -#define ETP_BUS_SMB_HST_NTFY_ONLY 2 -#define ETP_BUS_PS2_SMB_ALERT 3 -#define ETP_BUS_PS2_SMB_HST_NTFY 4 +#define ETP_BUS_SMB_HST_NTFY_ONLY 2 +#define ETP_BUS_PS2_SMB_ALERT 3 +#define ETP_BUS_PS2_SMB_HST_NTFY 4 /* * New ICs are either using SMBus Host Notify or just plain PS2. From d4934c932c9467463b298a020c3e3ff34249c7d2 Mon Sep 17 00:00:00 2001 From: Le Bao Hiep Date: Sun, 13 Sep 2020 23:55:22 +0700 Subject: [PATCH 12/40] Remove TPDN (leftover code from VoodooPS2SynapticsTouchPad) --- VoodooPS2Trackpad/VoodooPS2Elan.cpp | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/VoodooPS2Trackpad/VoodooPS2Elan.cpp b/VoodooPS2Trackpad/VoodooPS2Elan.cpp index eaee6a06..f1559a88 100644 --- a/VoodooPS2Trackpad/VoodooPS2Elan.cpp +++ b/VoodooPS2Trackpad/VoodooPS2Elan.cpp @@ -22,8 +22,6 @@ //#define PACKET_DEBUG #endif -#define kTPDN "TPDN" // Trackpad Disable Notification - #include "LegacyIOService.h" #pragma clang diagnostic push @@ -334,15 +332,6 @@ bool ApplePS2Elan::start(IOService* provider) // //setProperty(kDeliverNotifications, true); - // get IOACPIPlatformDevice for Device (PS2M) - //REVIEW: should really look at the parent chain for IOACPIPlatformDevice instead. - _provider = (IOACPIPlatformDevice*)IORegistryEntry::fromPath("IOService:/AppleACPIPlatformExpert/PS2M"); - if (_provider && kIOReturnSuccess != _provider->validateObject(kTPDN)) - { - _provider->release(); - _provider = NULL; - } - return true; } From d5f05415ac087ed4411b51ce73ac19c021bbaf48 Mon Sep 17 00:00:00 2001 From: zhen-zen <66577170+zhen-zen@users.noreply.github.com> Date: Sun, 13 Sep 2020 12:46:30 -0700 Subject: [PATCH 13/40] Get ACPI notification for brightness keys from GFX0.DD1F/DD02 (#22) --- .gitignore | 1 + .travis.yml | 2 + Changelog.md | 4 + README.md | 2 + VoodooPS2Controller.xcodeproj/project.pbxproj | 7 +- .../xcschemes/VoodooPS2Controller.xcscheme | 2 +- .../xcschemes/VoodooPS2Keyboard.xcscheme | 2 +- .../xcschemes/VoodooPS2Mouse.xcscheme | 2 +- .../xcschemes/VoodooPS2Trackpad.xcscheme | 2 +- VoodooPS2Controller/ApplePS2Device.h | 10 ++ VoodooPS2Controller/VoodooPS2Controller.cpp | 4 +- .../VoodooPS2Keyboard-Info.plist | 4 + VoodooPS2Keyboard/VoodooPS2Keyboard.cpp | 155 +++++++++++++++++- VoodooPS2Keyboard/VoodooPS2Keyboard.h | 11 +- 14 files changed, 199 insertions(+), 9 deletions(-) diff --git a/.gitignore b/.gitignore index 839586ec..c661a348 100644 --- a/.gitignore +++ b/.gitignore @@ -7,3 +7,4 @@ xcuserdata xcshareddata project.xcworkspace VoodooInput +Lilu.kext diff --git a/.travis.yml b/.travis.yml index 3025b1b4..fd9de90a 100644 --- a/.travis.yml +++ b/.travis.yml @@ -8,6 +8,7 @@ matrix: compiler: clang script: + - src=$(/usr/bin/curl -Lfs https://raw.githubusercontent.com/acidanthera/Lilu/master/Lilu/Scripts/bootstrap.sh) && eval "$src" || exit 1 - src=$(/usr/bin/curl -Lfs https://raw.githubusercontent.com/acidanthera/VoodooInput/master/VoodooInput/Scripts/bootstrap.sh) && eval "$src" || exit 1 - xcodebuild -configuration Debug - xcodebuild -configuration Release @@ -28,6 +29,7 @@ matrix: compiler: clang script: + - src=$(/usr/bin/curl -Lfs https://raw.githubusercontent.com/acidanthera/Lilu/master/Lilu/Scripts/bootstrap.sh) && eval "$src" || exit 1 - src=$(/usr/bin/curl -Lfs https://raw.githubusercontent.com/acidanthera/VoodooInput/master/VoodooInput/Scripts/bootstrap.sh) && eval "$src" || exit 1 - xcodebuild analyze -quiet -scheme VoodooPS2Controller -configuration Debug CLANG_ANALYZER_OUTPUT=plist-html CLANG_ANALYZER_OUTPUT_DIR="$(pwd)/clang-analyze" && [ "$(find clang-analyze -name "*.html")" = "" ] - xcodebuild analyze -quiet -scheme VoodooPS2Controller -configuration Release CLANG_ANALYZER_OUTPUT=plist-html CLANG_ANALYZER_OUTPUT_DIR="$(pwd)/clang-analyze" && [ "$(find clang-analyze -name "*.html")" = "" ] diff --git a/Changelog.md b/Changelog.md index 2170bf74..3264b86f 100644 --- a/Changelog.md +++ b/Changelog.md @@ -1,5 +1,9 @@ VoodooPS2 Changelog ============================ +#### v2.1.7 +- Added ability for native brightness keys discovery with `Lilu` API, please be aware of this new dependecy and drop SSDT modification to corresponding `_QXX`. +- Added constants for 11.0 support + #### v2.1.6 - Upgraded to VoodooInput 1.0.7 - Fixed swiping desktops when holding a dragged item by improving thumb detection diff --git a/README.md b/README.md index b4702bde..c5cae4c8 100644 --- a/README.md +++ b/README.md @@ -34,6 +34,8 @@ The parameters in the formula are configured using `ForceTouchCustomUpThreshold` ## Installation and compilation +For native brightness keys discovery, `Lilu` is required to probe graphics devices. + For VoodooPS2Trackpad.kext to work multitouch interface engine, named VoodooInput.kext, is required. - For released binaries a compatible version of VoodooInput.kext is already included in the PlugIns directory. diff --git a/VoodooPS2Controller.xcodeproj/project.pbxproj b/VoodooPS2Controller.xcodeproj/project.pbxproj index 8946e592..e7feb1a5 100644 --- a/VoodooPS2Controller.xcodeproj/project.pbxproj +++ b/VoodooPS2Controller.xcodeproj/project.pbxproj @@ -213,6 +213,7 @@ 84167814161B55B2002C60E6 /* Products */, ); sourceTree = ""; + usesTabs = 0; }; 84167814161B55B2002C60E6 /* Products */ = { isa = PBXGroup; @@ -524,7 +525,7 @@ 84167808161B55B2002C60E6 /* Project object */ = { isa = PBXProject; attributes = { - LastUpgradeCheck = 1140; + LastUpgradeCheck = 1200; ORGANIZATIONNAME = Acidanthera; }; buildConfigurationList = 8416780B161B55B2002C60E6 /* Build configuration list for PBXProject "VoodooPS2Controller" */; @@ -752,6 +753,7 @@ isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; + ARCHS = "$(NATIVE_ARCH_ACTUAL)"; CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; CLANG_CXX_LANGUAGE_STANDARD = "c++1y"; CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; @@ -811,6 +813,7 @@ isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; + ARCHS = "$(NATIVE_ARCH_ACTUAL)"; CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; CLANG_CXX_LANGUAGE_STANDARD = "c++1y"; CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; @@ -905,6 +908,7 @@ COMBINE_HIDPI_IMAGES = YES; CONFIGURATION_BUILD_DIR = "$(BUILD_DIR)/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)/VoodooPS2Controller.kext/Contents/PlugIns"; GCC_PRECOMPILE_PREFIX_HEADER = YES; + HEADER_SEARCH_PATHS = "$(PROJECT_DIR)/Lilu.kext/Contents/Resources"; INFOPLIST_FILE = "VoodooPS2Keyboard/VoodooPS2Keyboard-Info.plist"; LIBRARY_SEARCH_PATHS = ( "$(inherited)", @@ -926,6 +930,7 @@ COMBINE_HIDPI_IMAGES = YES; CONFIGURATION_BUILD_DIR = "$(BUILD_DIR)/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)/VoodooPS2Controller.kext/Contents/PlugIns"; GCC_PRECOMPILE_PREFIX_HEADER = YES; + HEADER_SEARCH_PATHS = "$(PROJECT_DIR)/Lilu.kext/Contents/Resources"; INFOPLIST_FILE = "VoodooPS2Keyboard/VoodooPS2Keyboard-Info.plist"; LIBRARY_SEARCH_PATHS = ( "$(inherited)", diff --git a/VoodooPS2Controller.xcodeproj/xcshareddata/xcschemes/VoodooPS2Controller.xcscheme b/VoodooPS2Controller.xcodeproj/xcshareddata/xcschemes/VoodooPS2Controller.xcscheme index d9cf0273..53cfca6d 100644 --- a/VoodooPS2Controller.xcodeproj/xcshareddata/xcschemes/VoodooPS2Controller.xcscheme +++ b/VoodooPS2Controller.xcodeproj/xcshareddata/xcschemes/VoodooPS2Controller.xcscheme @@ -1,6 +1,6 @@ OSBundleLibraries + com.apple.iokit.IOACPIFamily + 1.0.0d1 com.apple.iokit.IOHIDFamily 1.0.0b1 com.apple.kpi.bsd @@ -583,6 +585,8 @@ 8.0.0 as.acidanthera.voodoo.driver.PS2Controller ${MODULE_VERSION} + as.vit9696.Lilu + 1.2.0 OSBundleRequired Console diff --git a/VoodooPS2Keyboard/VoodooPS2Keyboard.cpp b/VoodooPS2Keyboard/VoodooPS2Keyboard.cpp index 08718119..f96b3eee 100644 --- a/VoodooPS2Keyboard/VoodooPS2Keyboard.cpp +++ b/VoodooPS2Keyboard/VoodooPS2Keyboard.cpp @@ -43,6 +43,7 @@ #include "ApplePS2ToADBMap.h" #include "AppleACPIPS2Nub.h" #include +#include // Constants for Info.plist settings @@ -65,6 +66,11 @@ #define kMacroTranslation "Macro Translation" #define kMaxMacroTime "MaximumMacroTime" +// Constants for brightness keys + +#define kBrightnessDevice "BrightnessDevice" +#define kBrightnessKey "BrightnessKey" + // Definitions for Macro Inversion data format //REVIEW: This should really be defined as some sort of structure #define kIgnoreBytes 2 // first two bytes of macro data are ignored (always 0xffff) @@ -176,6 +182,12 @@ bool ApplePS2Keyboard::init(OSDictionary * dict) _keysSpecial = 0; _f12ejectdelay = 250; // default is 250 ms + // initialize ACPI support for brightness key + _panel = 0; + _panelNotified = false; + _panelPrompt = false; + _panelNotifiers = 0; + // initialize ACPI support for keyboard backlight/screen brightness _provider = 0; _brightnessLevels = 0; @@ -336,6 +348,64 @@ ApplePS2Keyboard* ApplePS2Keyboard::probe(IOService * provider, SInt32 * score) // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +IORegistryEntry* ApplePS2Keyboard::getDevicebyAddress(IORegistryEntry *parent, int address) { + IORegistryEntry* child = NULL; + auto iter = parent->getChildIterator(gIODTPlane); + if (iter) { + IORegistryEntry* dev; + int addr; + while ((dev = (IORegistryEntry*)iter->getNextObject())) { + auto location = dev->getLocation(); + // The device need to be present in ACPI scope and follow the naming convention ('A'-'Z', '_') + auto name = dev->getName(); + if (location && name && name [0] <= '_' && + sscanf(dev->getLocation(), "%x", &addr) == 1 && addr == address) { + child = dev; + break; + } + } + } + OSSafeRelease(iter); + return child; +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + +IOACPIPlatformDevice* ApplePS2Keyboard::getBrightnessPanel() { + IOACPIPlatformDevice *panel = nullptr; + + auto info = DeviceInfo::create(); + + auto getAcpiDevice = [](IORegistryEntry *dev) -> IOACPIPlatformDevice * { + if (dev == nullptr) + return nullptr; + + auto path = OSDynamicCast(OSString, dev->getProperty("acpi-path")); + if (path != nullptr) { + auto p = IORegistryEntry::fromPath(path->getCStringNoCopy()); + auto r = OSDynamicCast(IOACPIPlatformDevice, p); + if (r) return r; + OSSafeRelease(p); + } + return nullptr; + }; + + if (info) { + if (info->videoBuiltin != nullptr) + panel = getAcpiDevice(getDevicebyAddress(info->videoBuiltin, 0x400)); + + if (panel == nullptr) + for (size_t i = 0; panel == nullptr && i < info->videoExternal.size(); ++i) + panel = getAcpiDevice(getDevicebyAddress(info->videoExternal[i].video, 0x110)); + + DeviceInfo::deleter(info); + } + + return panel; +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + bool ApplePS2Keyboard::start(IOService * provider) { DEBUG_LOG("ApplePS2Keyboard::start entered...\n"); @@ -379,6 +449,15 @@ bool ApplePS2Keyboard::start(IOService * provider) return false; } + // get IOACPIPlatformDevice for built-in panel + _panel = getBrightnessPanel(); + if (_panel != nullptr) { + if ((_panelNotifiers = _panel->registerInterest(gIOGeneralInterest, _panelNotification, this))) + setProperty(kBrightnessDevice, _panel->getName()); + else + IOLog("ps2br: unable to register interest for GFX notifications\n"); + } + // get IOACPIPlatformDevice for Device (PS2K) //REVIEW: should really look at the parent chain for IOACPIPlatformDevice instead. _provider = (IOACPIPlatformDevice*)IORegistryEntry::fromPath("IOService:/AppleACPIPlatformExpert/PS2K"); @@ -950,8 +1029,11 @@ void ApplePS2Keyboard::stop(IOService * provider) OSSafeReleaseNULL(_device); // - // Release ACPI provider for PS2K ACPI device + // Release ACPI provider for panel and PS2K ACPI device // + if (_panel && _panelNotifiers) + _panelNotifiers->remove(); + OSSafeReleaseNULL(_panel); OSSafeReleaseNULL(_provider); // @@ -1809,6 +1891,19 @@ bool ApplePS2Keyboard::dispatchKeyboardEventWithPacket(const UInt8* packet) // special cases switch (adbKeyCode) { + case BRIGHTNESS_UP: + case BRIGHTNESS_DOWN: + if (_panelNotified) { + eatKey = true; + if (!_panelPrompt) { + _panelPrompt = true; + IOLog("%s: Already got brightness key from GFX device, please revert DSDT modification.\n", getName()); + } + } else if (!_panel && !_panelPrompt) { + _panelPrompt = true; + IOLog("%s: Unrecognized GFX device, please consider report your case.\n", getName()); + } + break; case 0x90: case 0x91: if (_brightnessLevels) @@ -1920,6 +2015,64 @@ bool ApplePS2Keyboard::dispatchKeyboardEventWithPacket(const UInt8* packet) // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +IOReturn ApplePS2Keyboard::_panelNotification(void *target, void *refCon, UInt32 messageType, IOService *provider, void *messageArgument, vm_size_t argSize) { + if (messageType == kIOACPIMessageDeviceNotification) { + if (NULL == target) { + DEBUG_LOG("%s kIOACPIMessageDeviceNotification target is null\n", provider->getName()); + return kIOReturnError; + } + + auto self = OSDynamicCast(ApplePS2Keyboard, reinterpret_cast(target)); + if (NULL == self) { + DEBUG_LOG("%s kIOACPIMessageDeviceNotification target is not a ApplePS2Keyboard\n", provider->getName()); + return kIOReturnError; + } + + if (NULL != messageArgument) { + uint64_t now_abs; + UInt32 arg = *static_cast(messageArgument); + switch (arg) { + case kIOACPIMessageBrightnessUp: + clock_get_uptime(&now_abs); + self->dispatchKeyboardEventX(BRIGHTNESS_UP, true, now_abs); + clock_get_uptime(&now_abs); + self->dispatchKeyboardEventX(BRIGHTNESS_UP, false, now_abs); + DEBUG_LOG("%s ACPI brightness up\n", self->getName()); + break; + + case kIOACPIMessageBrightnessDown: + clock_get_uptime(&now_abs); + self->dispatchKeyboardEventX(BRIGHTNESS_DOWN, true, now_abs); + clock_get_uptime(&now_abs); + self->dispatchKeyboardEventX(BRIGHTNESS_DOWN, false, now_abs); + DEBUG_LOG("%s ACPI brightness down\n", self->getName()); + break; + + case kIOACPIMessageBrightnessCycle: + case kIOACPIMessageBrightnessZero: + case kIOACPIMessageBrightnessOff: + DEBUG_LOG("%s ACPI brightness operation 0x%02x not implemented\n", self->getName(), *((UInt32 *) messageArgument)); + return kIOReturnSuccess; + + default: + DEBUG_LOG("%s unknown ACPI notification 0x%04x\n", self->getName(), *((UInt32 *) messageArgument)); + return kIOReturnSuccess; + } + if (!self->_panelNotified) { + self->_panelNotified = true; + self->setProperty(kBrightnessKey, "ACPI"); + } + } else { + DEBUG_LOG("%s %s received unknown kIOACPIMessageDeviceNotification\n", self->getName(), provider->getName()); + } + } else { + DEBUG_LOG("%s received %08X\n", provider->getName(), messageType); + } + return kIOReturnSuccess; +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + void ApplePS2Keyboard::setAlphaLockFeedback(bool locked) { // diff --git a/VoodooPS2Keyboard/VoodooPS2Keyboard.h b/VoodooPS2Keyboard/VoodooPS2Keyboard.h index c69dde74..20b4adfa 100644 --- a/VoodooPS2Keyboard/VoodooPS2Keyboard.h +++ b/VoodooPS2Keyboard/VoodooPS2Keyboard.h @@ -30,6 +30,7 @@ #pragma clang diagnostic push #pragma clang diagnostic ignored "-Winconsistent-missing-override" #include +#include #pragma clang diagnostic pop #include @@ -106,7 +107,12 @@ class EXPORT ApplePS2Keyboard : public IOHIKeyboard IOTimerEventSource* _sleepEjectTimer; UInt32 _maxsleeppresstime; - // ACPI support for screen brightness + // ACPI support for panel brightness + IOACPIPlatformDevice * _panel; + bool _panelNotified; + bool _panelPrompt; + IONotifier * _panelNotifiers; + IOACPIPlatformDevice * _provider; int * _brightnessLevels; int _brightnessCount; @@ -138,6 +144,9 @@ class EXPORT ApplePS2Keyboard : public IOHIKeyboard virtual void setKeyboardEnable(bool enable); virtual void initKeyboard(); virtual void setDevicePowerState(UInt32 whatToDo); + IORegistryEntry* getDevicebyAddress(IORegistryEntry *parent, int address); + IOACPIPlatformDevice* getBrightnessPanel(); + static IOReturn _panelNotification(void *target, void *refCon, UInt32 messageType, IOService *provider, void *messageArgument, vm_size_t argSize); void modifyKeyboardBacklight(int adbKeyCode, bool goingDown); void modifyScreenBrightness(int adbKeyCode, bool goingDown); inline bool checkModifierState(UInt16 mask) From ba1d423042968b1b30cd64d854d2e83e16882a9d Mon Sep 17 00:00:00 2001 From: Le Bao Hiep Date: Tue, 15 Sep 2020 17:01:26 +0700 Subject: [PATCH 14/40] Update credits --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index c5cae4c8..3afb87c4 100644 --- a/README.md +++ b/README.md @@ -57,7 +57,8 @@ In addition, for 2-in-1 systems that do not support disabling the keyboard in ha * VoodooPS2Controller etc. – turbo, mackerintel, @RehabMan, nhand42, phb, Chunnan, jape, bumby (see RehabMan's repository). * Magic Trackpad 2 reverse engineering and implementation – https://github.com/alexandred/VoodooI2C project team. * VoodooPS2Trackpad integration – @kprinssu. -* Force Touch emulation and finger renumbering algorithm** - @usr-sse2. +* Force Touch emulation and finger renumbering algorithm** – @usr-sse2. +* Elan driver – @BAndysc and @hieplpvip \* On my touchpad this gesture was practically impossible to perform with the old VoodooPS2Trackpad. Now it works well. \*\* Due to the limitations of PS/2 bus, Synaptics touchpad reports only the number of fingers and coordinates of two of them to the computer. When there are two fingers on the touchpad and third finger is added, a 'jump' may happen, because the coordinates of one of the fingers are replaced with the coordinates of the added finger. Finger renumbering algorithm estimates the distance from old coordinates to new ones in order to hide this 'jump' from the OS ~~and to calculate approximate position of the 'hidden' finger, in assumption that fingers move together in parallel to each other~~. Now third and fourth fingers are reported at the same position as one of the first two fingers. It allows Launchpad/Show desktop gesture to work more reliably. From 457e3da905bde1e5719ed80f7a6548b5174c6b1f Mon Sep 17 00:00:00 2001 From: Le Bao Hiep Date: Tue, 15 Sep 2020 17:05:01 +0700 Subject: [PATCH 15/40] Remove unused code --- VoodooPS2Trackpad/VoodooPS2Elan.cpp | 68 ----------------------------- VoodooPS2Trackpad/VoodooPS2Elan.h | 8 ---- 2 files changed, 76 deletions(-) diff --git a/VoodooPS2Trackpad/VoodooPS2Elan.cpp b/VoodooPS2Trackpad/VoodooPS2Elan.cpp index f1559a88..558f2870 100644 --- a/VoodooPS2Trackpad/VoodooPS2Elan.cpp +++ b/VoodooPS2Trackpad/VoodooPS2Elan.cpp @@ -1672,10 +1672,6 @@ void ApplePS2Elan::processPacketStatusV4() { heldFingers = count; - //reportLeft(packet[0] & 1, 0, true); - //reportRight(packet[0] & 2, 0, true); - //reportMiddle(packet[0] & 4, 0, true); - headPacketsCount = 0; // if count > 0, we wait for HEAD packets to report so that we report all fingers at once. @@ -1710,15 +1706,6 @@ void ApplePS2Elan::processPacketHeadV4() { traces = (packet[0] & 0xf0) >> 4; INTERRUPT_LOG("VoodooPS2Elan: pres: %d, traces: %d, width: %d\n", pres, traces, etd.width); - - - //reportLeft(packet[0] & 1, 0, false); - //reportRight(packet[0] & 2, 0, false); - //reportMiddle(packet[0] & 4, 0); - - //reportLeft(packet[0] & 1, id+1); - //reportRight(packet[0] & 2, id+1); - //reportMiddle(packet[0] & 4, id+1); virtualFinger[id].button = (packet[0] & 1); virtualFinger[id].prev = virtualFinger[id].now; @@ -1759,14 +1746,6 @@ void ApplePS2Elan::processPacketMotionV4() { delta_y1 = (signed char)packet[2]; delta_x2 = (signed char)packet[4]; delta_y2 = (signed char)packet[5]; - - //reportLeft(packet[0] & 1, 0, false); - //reportRight(packet[0] & 2, 0, false); - //reportMiddle(packet[0] & 4, 0); - - //reportLeft(packet[0] & 1, id+1); - //reportRight(packet[0] & 2, id+1); - //reportMiddle(packet[0] & 4, id+1); virtualFinger[id].button = (packet[0] & 1); virtualFinger[id].prev = virtualFinger[id].now; @@ -1778,58 +1757,11 @@ void ApplePS2Elan::processPacketMotionV4() { virtualFinger[sid].prev = virtualFinger[sid].now; virtualFinger[sid].now.x += delta_x2 * weight; virtualFinger[sid].now.y -= delta_y2 * weight; - - //reportLeft(packet[3] & 1, 0); - //reportRight(packet[3] & 2, 0); - //reportMiddle(packet[3] & 4, 0); - - //reportLeft(packet[3] & 1, sid+1); - //reportRight(packet[3] & 2, sid+1); - //reportMiddle(packet[3] & 4, sid+1); } sendTouchData(); } -void ApplePS2Elan::reportLeft(int state, int finger, bool status) -{ - if (leftButtons[finger] != state) - { - auto str = status ? "STATUS" : "HEAD/MOTION"; - if (state == 0) - IOLog("VoodooPS2ElanButtons: [%s] left button, finger %d lifted (fingers on touchpad: %d)\n", str, finger, heldFingers); - else - IOLog("VoodooPS2ElanButtons: [%s] left button, finger %d pressed (fingers on touchpad: %d)\n", str, finger, heldFingers); - leftButtons[finger] = state; - } -} -/* -void ApplePS2Elan::reportMiddle(int state, int finger) -{ - if (middleButtons[finger] != state) - { - if (state == 0) - IOLog("VoodooPS2ElanButtons: middle button, finger %d lifted (fingers on touchpad: %d)\n", finger, heldFingers); - else - IOLog("VoodooPS2ElanButtons: middle button, finger %d pressed (fingers on touchpad: %d)\n", finger, heldFingers); - middleButtons[finger] = state; - } -}*/ - -void ApplePS2Elan::reportRight(int state, int finger, bool status) -{ - if (rightButtons[finger] != state) - { - auto str = status ? "STATUS" : "HEAD/MOTION"; - - if (state == 0) - IOLog("VoodooPS2ElanButtons: [%s] right button, finger %d lifted (fingers on touchpad: %d)\n", str, finger, heldFingers); - else - IOLog("VoodooPS2ElanButtons: [%s] right button, finger %d pressed (fingers on touchpad: %d)\n", str, finger, heldFingers); - rightButtons[finger] = state; - } -} - static MT2FingerType GetBestFingerType(int i) { switch (i) { case 0: return kMT2FingerTypeIndexFinger; diff --git a/VoodooPS2Trackpad/VoodooPS2Elan.h b/VoodooPS2Trackpad/VoodooPS2Elan.h index e6a65b99..2264039a 100644 --- a/VoodooPS2Trackpad/VoodooPS2Elan.h +++ b/VoodooPS2Trackpad/VoodooPS2Elan.h @@ -241,14 +241,6 @@ class EXPORT ApplePS2Elan : public IOHIPointing UInt32 lastFingersV3 = 0; - UInt32 leftButtons[8] = {0, 0, 0, 0, 0, 0, 0, 0}; - UInt32 rightButtons[8] = {0, 0, 0, 0, 0, 0, 0, 0}; - //UInt32 middleButtons[8] = {0, 0, 0, 0, 0, 0, 0, 0}; - - void reportLeft(int state, int finger, bool status); - //void reportMiddle(int state, int finger, bool status); - void reportRight(int state, int finger, bool status); - int heldFingers = 0; int headPacketsCount = 0; virtual_finger_state virtualFinger[ETP_MAX_FINGERS] {}; From 8af5a9d4b58764659cf3cb9fd77a2fb783e483af Mon Sep 17 00:00:00 2001 From: Le Bao Hiep Date: Tue, 15 Sep 2020 17:15:18 +0700 Subject: [PATCH 16/40] Remove unnecessary code & Support scrolling with trackpoint --- VoodooPS2Trackpad/VoodooPS2Elan.cpp | 46 +++++++++++++---------------- VoodooPS2Trackpad/VoodooPS2Elan.h | 13 +++----- 2 files changed, 24 insertions(+), 35 deletions(-) diff --git a/VoodooPS2Trackpad/VoodooPS2Elan.cpp b/VoodooPS2Trackpad/VoodooPS2Elan.cpp index 558f2870..bad03a80 100644 --- a/VoodooPS2Trackpad/VoodooPS2Elan.cpp +++ b/VoodooPS2Trackpad/VoodooPS2Elan.cpp @@ -1606,45 +1606,39 @@ void ApplePS2Elan::elantechReportAbsoluteV4(int packetType) { /* impossible to get here */ break; } - - if (voodooInputInstance) { - if (changed) - { - VoodooInputDimensions d; - d.min_x = info.x_min; - d.max_x = info.x_max; - d.min_y = info.y_min; - d.max_y = info.y_max; - super::messageClient(kIOMessageVoodooInputUpdateDimensionsMessage, voodooInputInstance, &d, sizeof(VoodooInputDimensions)); - - changed = false; - } - - } - else - INTERRUPT_LOG("VoodooPS2Elan: no voodooInputInstance\n"); } void ApplePS2Elan::elantechReportTrackpoint() { unsigned char *packet = _ringBuffer.tail(); - trackpointLeftButton = packet[0] & 0x1; - trackpointRightButton = packet[0] & 0x2; - //middleButton = packet[0] & 0x4; - - int dx = packet[4]; - int dy = packet[5]; + int trackpointLeftButton = packet[0] & 0x1; + int trackpointRightButton = packet[0] & 0x2; + int trackpointMiddleButton = packet[0] & 0x4; - dx = packet[4] - (int)((packet[1]^0x80)<<1); - dy = (int)((packet[2]^0x80)<<1) - packet[5]; + int dx = packet[4] - (int)((packet[1] ^ 0x80) << 1); + int dy = (int)((packet[2] ^ 0x80) << 1) - packet[5]; dx = dx * _trackpointMultiplierX / _trackpointDividerX; dy = dy * _trackpointMultiplierY / _trackpointDividerY; + // enable trackpoint scroll mode when middle button was pressed and the trackpoint moved + if (trackpointMiddleButton == 4 && (dx != 0 || dy != 0)) { + trackpointScrolling = true; + } + + // disable trackpoint scrolling mode when middle button is released + if (trackpointScrolling && trackpointMiddleButton == 0) { + trackpointScrolling = false; + } + AbsoluteTime timestamp; clock_get_uptime(×tamp); - dispatchRelativePointerEvent(dx, dy, trackpointRightButton | trackpointLeftButton /*| middleButton*/, timestamp); + if (trackpointScrolling) { + dispatchScrollWheelEvent(dx, dy, 0, timestamp); + } else { + dispatchRelativePointerEvent(dx, dy, trackpointRightButton | trackpointLeftButton | trackpointMiddleButton, timestamp); + } } void ApplePS2Elan::processPacketStatusV4() { diff --git a/VoodooPS2Trackpad/VoodooPS2Elan.h b/VoodooPS2Trackpad/VoodooPS2Elan.h index 2264039a..c0742874 100644 --- a/VoodooPS2Trackpad/VoodooPS2Elan.h +++ b/VoodooPS2Trackpad/VoodooPS2Elan.h @@ -228,19 +228,16 @@ class EXPORT ApplePS2Elan : public IOHIPointing VoodooInputEvent inputEvent {}; - // when trackpad has physical buttons - - UInt32 trackpointLeftButton = 0; - UInt32 trackpointRightButton = 0; - + // when trackpad has physical button UInt32 leftButton = 0; UInt32 rightButton = 0; - UInt32 lastLeftButton = 0; UInt32 lastRightButton = 0; UInt32 lastFingersV3 = 0; + bool trackpointScrolling {false}; + int heldFingers = 0; int headPacketsCount = 0; virtual_finger_state virtualFinger[ETP_MAX_FINGERS] {}; @@ -325,9 +322,7 @@ class EXPORT ApplePS2Elan : public IOHIPointing template int send_cmd(unsigned char c, unsigned char *param); - - bool changed = true; - + bool elantech_is_buttonpad() { return (info.fw_version & 0x001000) != 0; From 6a1b1ab578d0a4754bc1ccbafdce89239af3c5ae Mon Sep 17 00:00:00 2001 From: Le Bao Hiep Date: Tue, 15 Sep 2020 17:19:06 +0700 Subject: [PATCH 17/40] Don't expose static functions to kernel space --- VoodooPS2Trackpad/VoodooPS2Elan.cpp | 4 ++-- VoodooPS2Trackpad/VoodooPS2Elan.h | 3 +++ 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/VoodooPS2Trackpad/VoodooPS2Elan.cpp b/VoodooPS2Trackpad/VoodooPS2Elan.cpp index bad03a80..263bfc38 100644 --- a/VoodooPS2Trackpad/VoodooPS2Elan.cpp +++ b/VoodooPS2Trackpad/VoodooPS2Elan.cpp @@ -820,7 +820,7 @@ bool ApplePS2Elan::elantech_is_signature_valid(const unsigned char *param) * (value from firmware) * 10 + 790 = dpi * we also have to convert dpi to dots/mm (*10/254 to avoid floating point) */ -static unsigned int elantech_convert_res(unsigned int val) +unsigned int ApplePS2Elan::elantech_convert_res(unsigned int val) { return (val * 10 + 790) * 10 / 254; } @@ -1756,7 +1756,7 @@ void ApplePS2Elan::processPacketMotionV4() { sendTouchData(); } -static MT2FingerType GetBestFingerType(int i) { +MT2FingerType ApplePS2Elan::GetBestFingerType(int i) { switch (i) { case 0: return kMT2FingerTypeIndexFinger; case 1: return kMT2FingerTypeMiddleFinger; diff --git a/VoodooPS2Trackpad/VoodooPS2Elan.h b/VoodooPS2Trackpad/VoodooPS2Elan.h index c0742874..e41c8f14 100644 --- a/VoodooPS2Trackpad/VoodooPS2Elan.h +++ b/VoodooPS2Trackpad/VoodooPS2Elan.h @@ -308,6 +308,8 @@ class EXPORT ApplePS2Elan : public IOHIPointing void resetMouse(); void setTouchPadEnable(bool enable); + static MT2FingerType GetBestFingerType(int i); + template int ps2_command(UInt8* params, unsigned int command); template @@ -318,6 +320,7 @@ class EXPORT ApplePS2Elan : public IOHIPointing template int elantech_send_cmd(unsigned char c, unsigned char *param); bool elantech_is_signature_valid(const unsigned char *param); + static unsigned int elantech_convert_res(unsigned int val); int elantech_get_resolution_v4(unsigned int *x_res, unsigned int *y_res, unsigned int *bus); template From b58aa0119b234f5c3a4f51926a033e95549e13f9 Mon Sep 17 00:00:00 2001 From: Le Bao Hiep Date: Tue, 15 Sep 2020 18:16:03 +0700 Subject: [PATCH 18/40] Cleanup --- VoodooPS2Trackpad/VoodooPS2Elan.cpp | 1041 ++++++++++++--------------- VoodooPS2Trackpad/VoodooPS2Elan.h | 92 ++- 2 files changed, 505 insertions(+), 628 deletions(-) diff --git a/VoodooPS2Trackpad/VoodooPS2Elan.cpp b/VoodooPS2Trackpad/VoodooPS2Elan.cpp index 263bfc38..c2f250f8 100644 --- a/VoodooPS2Trackpad/VoodooPS2Elan.cpp +++ b/VoodooPS2Trackpad/VoodooPS2Elan.cpp @@ -53,91 +53,82 @@ UInt32 ApplePS2Elan::interfaceID() #define abs(x) ((x) < 0 ? -(x) : (x)) -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -bool ApplePS2Elan::init(OSDictionary * dict) -{ - // +bool ApplePS2Elan::init(OSDictionary *dict) { // Initialize this object's minimal state. This is invoked right after this // object is instantiated. - // - - if (!super::init(dict)) + + if (!super::init(dict)) { return false; + } // announce version extern kmod_info_t kmod_info; DEBUG_LOG("VoodooPS2Elan: Version %s starting on OS X Darwin %d.%d.\n", kmod_info.version, version_major, version_minor); - setProperty ("Revision", 24, 32); - + setProperty("Revision", 24, 32); + return true; } -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void ApplePS2Elan::injectVersionDependentProperties(OSDictionary *config) -{ +void ApplePS2Elan::injectVersionDependentProperties(OSDictionary *config) { // inject properties specific to the version of Darwin that is runnning... char buf[32]; - OSDictionary* dict = NULL; - do - { + OSDictionary *dict = NULL; + do { // check for "Darwin major.minor" snprintf(buf, sizeof(buf), "Darwin %d.%d", version_major, version_minor); - if ((dict = OSDynamicCast(OSDictionary, config->getObject(buf)))) + if ((dict = OSDynamicCast(OSDictionary, config->getObject(buf)))) { break; + } + // check for "Darwin major.x" snprintf(buf, sizeof(buf), "Darwin %d.x", version_major); - if ((dict = OSDynamicCast(OSDictionary, config->getObject(buf)))) + if ((dict = OSDynamicCast(OSDictionary, config->getObject(buf)))) { break; + } + // check for "Darwin 16+" (this is what is used currently, other formats are for future) - if (version_major >= 16 && (dict = OSDynamicCast(OSDictionary, config->getObject("Darwin 16+")))) + if (version_major >= 16 && (dict = OSDynamicCast(OSDictionary, config->getObject("Darwin 16+")))) { break; + } } while (0); - if (dict) - { + if (dict) { // found version specific properties above, inject... - if (OSCollectionIterator* iter = OSCollectionIterator::withCollection(dict)) - { + if (OSCollectionIterator *iter = OSCollectionIterator::withCollection(dict)) { // Note: OSDictionary always contains OSSymbol* - while (const OSSymbol* key = static_cast(iter->getNextObject())) - { - if (OSObject* value = dict->getObject(key)) + while (const OSSymbol *key = static_cast(iter->getNextObject())) { + if (OSObject *value = dict->getObject(key)) { setProperty(key, value); + } } iter->release(); } } } -ApplePS2Elan* ApplePS2Elan::probe(IOService * provider, SInt32 * score) -{ +ApplePS2Elan *ApplePS2Elan::probe(IOService *provider, SInt32 *score) { DEBUG_LOG("ApplePS2Elan::probe entered...\n"); - - // + // The driver has been instructed to verify the presence of the actual // hardware we represent. We are guaranteed by the controller that the // mouse clock is enabled and the mouse itself is disabled (thus it // won't send any asynchronous mouse data that may mess up the // responses expected by the commands we send it). - // - - if (!super::probe(provider, score)) + + if (!super::probe(provider, score)) { return 0; + } - _device = (ApplePS2MouseDevice*)provider; + _device = (ApplePS2MouseDevice*)provider; // find config specific to Platform Profile - OSDictionary* list = OSDynamicCast(OSDictionary, getProperty(kPlatformProfile)); - OSDictionary* config = _device->getController()->makeConfigurationNode(list, "Elantech TouchPad"); - if (config) - { + OSDictionary *list = OSDynamicCast(OSDictionary, getProperty(kPlatformProfile)); + OSDictionary *config = _device->getController()->makeConfigurationNode(list, "Elantech TouchPad"); + if (config) { // if DisableDevice is Yes, then do not load at all... - OSBoolean* disable = OSDynamicCast(OSBoolean, config->getObject(kDisableDevice)); - if (disable && disable->isTrue()) - { + OSBoolean *disable = OSDynamicCast(OSBoolean, config->getObject(kDisableDevice)); + if (disable && disable->isTrue()) { config->release(); _device = 0; return 0; @@ -147,12 +138,12 @@ ApplePS2Elan* ApplePS2Elan::probe(IOService * provider, SInt32 * score) setProperty(kMergedConfiguration, config); #endif - // load settings specific to Platform Profile - setParamPropertiesGated(config); - injectVersionDependentProperties(config); - OSSafeReleaseNULL(config); + // load settings specific to Platform Profile + setParamPropertiesGated(config); + injectVersionDependentProperties(config); + OSSafeReleaseNULL(config); } - + resetMouse(); IOLog("VoodooPS2Elan: send magic knock to the device.\n"); @@ -161,15 +152,14 @@ ApplePS2Elan* ApplePS2Elan::probe(IOService * provider, SInt32 * score) IOLog("VoodooPS2Elan: elantouchpad not detected\n"); return NULL; } - + resetMouse(); - - if (elantechQueryInfo()) - { + + if (elantechQueryInfo()) { IOLog("VoodooPS2Elan: query info failed\n"); return NULL; } - + IOLog("VoodooPS2Elan: capabilities: %x %x %x\n", info.capabilities[0], info.capabilities[1], info.capabilities[2]); IOLog("VoodooPS2Elan: samples: %x %x %x\n", info.capabilities[0], info.capabilities[1], info.capabilities[2]); IOLog("VoodooPS2Elan: hw_version: %x\n", info.hw_version); @@ -184,7 +174,6 @@ ApplePS2Elan* ApplePS2Elan::probe(IOService * provider, SInt32 * score) IOLog("VoodooPS2Elan: y_traces: %d\n", info.y_traces); IOLog("VoodooPS2Elan: width: %d\n", info.width); IOLog("VoodooPS2Elan: bus: %d\n", info.bus); - IOLog("VoodooPS2Elan: paritycheck: %d\n", info.paritycheck); IOLog("VoodooPS2Elan: jumpy_cursor: %d\n", info.jumpy_cursor); IOLog("VoodooPS2Elan: reports_pressure: %d\n", info.reports_pressure); @@ -192,17 +181,16 @@ ApplePS2Elan* ApplePS2Elan::probe(IOService * provider, SInt32 * score) IOLog("VoodooPS2Elan: set_hw_resolution: %d\n", info.set_hw_resolution); IOLog("VoodooPS2Elan: has_trackpoint: %d\n", info.has_trackpoint); IOLog("VoodooPS2Elan: has_middle_button: %d\n", info.has_middle_button); - - if (info.hw_version <= 2) - { + + if (info.hw_version <= 2) { IOLog("VoodooPS2Elan: Unsupported ELAN PS2 Touchpad version. Currently only v4 and v3 version is supported. You have: %d\n", info.hw_version); return nullptr; } - + IOLog("VoodooPS2Elan: elan touchpad detected. Probing finished.\n"); - + _device = nullptr; - + return this; } @@ -222,194 +210,143 @@ void ApplePS2Elan::handleClose(IOService *forClient, IOOptionBits options) { super::handleClose(forClient, options); } -bool ApplePS2Elan::start(IOService* provider) -{ - // +bool ApplePS2Elan::start(IOService *provider) { // The driver has been instructed to start. This is called after a // successful probe and match. - // - if (!super::start(provider)) + if (!super::start(provider)) { return false; + } - // // Maintain a pointer to and retain the provider object. - // - - _device = (ApplePS2MouseDevice *) provider; + _device = (ApplePS2MouseDevice *)provider; _device->retain(); - - // - // Announce hardware properties. - // + // Announce hardware properties. char buf[128]; snprintf(buf, sizeof(buf), "Elan v %d, fw: %x, bus: %d", info.hw_version, info.fw_version, info.bus); setProperty("RM,TrackpadInfo", buf); - if (info.bus == ETP_BUS_PS2_ONLY) + if (info.bus == ETP_BUS_PS2_ONLY) { setProperty("Bus", "ETP_BUS_PS2_ONLY"); - else if (info.bus == ETP_BUS_SMB_ALERT_ONLY) + } else if (info.bus == ETP_BUS_SMB_ALERT_ONLY) { setProperty("Bus", "ETP_BUS_SMB_ALERT_ONLY"); - else if (info.bus == ETP_BUS_SMB_HST_NTFY_ONLY) + } else if (info.bus == ETP_BUS_SMB_HST_NTFY_ONLY) { setProperty("Bus", "ETP_BUS_SMB_HST_NTFY_ONLY"); - else if (info.bus == ETP_BUS_PS2_SMB_ALERT) + } else if (info.bus == ETP_BUS_PS2_SMB_ALERT) { setProperty("Bus", "ETP_BUS_PS2_SMB_ALERT"); - else if (info.bus == ETP_BUS_PS2_SMB_HST_NTFY) + } else if (info.bus == ETP_BUS_PS2_SMB_HST_NTFY) { setProperty("Bus", "ETP_BUS_PS2_SMB_HST_NTFY"); - + } + if (info.bus == ETP_BUS_SMB_HST_NTFY_ONLY || info.bus == ETP_BUS_PS2_SMB_HST_NTFY || - ETP_NEW_IC_SMBUS_HOST_NOTIFY(info.fw_version)) + ETP_NEW_IC_SMBUS_HOST_NOTIFY(info.fw_version)) { setProperty("SMBus NOTE", "It looks like your touchpad is supported by VoodooSMBus kext, which gives better multitouch experience. We recommend you to try it."); - else if (info.bus == ETP_BUS_PS2_ONLY) + } else if (info.bus == ETP_BUS_PS2_ONLY) { setProperty("SMBus NOTE", "It looks like your touchpad does not support SMBus protocol."); + } - // // Advertise the current state of the tapping feature. // // Must add this property to let our superclass know that it should handle // trackpad acceleration settings from user space. Without this, tracking // speed adjustments from the mouse prefs panel have no effect. - // - setProperty(kIOHIDPointerAccelerationTypeKey, kIOHIDTrackpadAccelerationType); setProperty(kIOHIDScrollAccelerationTypeKey, kIOHIDTrackpadScrollAccelerationKey); setProperty(kIOHIDScrollResolutionKey, _scrollresolution << 16, 32); - // added for Sierra precise scrolling (credit usr-sse2) + // added for Sierra precise scrolling (credit @usr-sse2) setProperty("HIDScrollResolutionX", _scrollresolution << 16, 32); setProperty("HIDScrollResolutionY", _scrollresolution << 16, 32); - - // + // Setup workloop with command gate for thread syncronization... - // - IOWorkLoop* pWorkLoop = getWorkLoop(); + IOWorkLoop *pWorkLoop = getWorkLoop(); _cmdGate = IOCommandGate::commandGate(this); - if (!pWorkLoop || !_cmdGate) - { - _device->release(); - _device = nullptr; + if (!pWorkLoop || !_cmdGate) { + OSSafeReleaseNULL(_device); return false; } - - // + // Lock the controller during initialization - // - _device->lock(); - + attachedHIDPointerDevices = OSSet::withCapacity(1); registerHIDPointerNotifications(); - + pWorkLoop->addEventSource(_cmdGate); - + elantechSetupPS2(); - // // Install our driver's interrupt handler, for asynchronous data delivery. - // - _device->installInterruptAction(this, OSMemberFunctionCast(PS2InterruptAction,this,&ApplePS2Elan::interruptOccurred), OSMemberFunctionCast(PS2PacketAction, this, &ApplePS2Elan::packetReady)); _interruptHandlerInstalled = true; - + + // Enable the touchpad setTouchPadEnable(true); - - // now safe to allow other threads + + // Now it is safe to allow other threads _device->unlock(); - - // - // Install our power control handler. - // - - _device->installPowerControlAction( this, - OSMemberFunctionCast(PS2PowerControlAction, this, &ApplePS2Elan::setDevicePowerState) ); + + // Install our power control handler + _device->installPowerControlAction(this, OSMemberFunctionCast(PS2PowerControlAction, this, &ApplePS2Elan::setDevicePowerState)); _powerControlHandlerInstalled = true; - - // + // Request message registration for keyboard to trackpad communication - // - //setProperty(kDeliverNotifications, true); - + setProperty(kDeliverNotifications, true); + return true; } -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void ApplePS2Elan::stop( IOService * provider ) -{ +void ApplePS2Elan::stop(IOService *provider) { DEBUG_LOG("%s: stop called\n", getName()); - - // - // The driver has been instructed to stop. Note that we must break all + + // The driver has been instructed to stop. Note that we must break all // connections to other service objects now (ie. no registered actions, // no pointers and retains to objects, etc), if any. - // assert(_device == provider); unregisterHIDPointerNotifications(); OSSafeReleaseNULL(attachedHIDPointerDevices); - - // - // Disable the mouse itself, so that it may stop reporting mouse events. - // + // Disable the touchpad setTouchPadEnable(false); - // free up timer for scroll momentum - IOWorkLoop* pWorkLoop = getWorkLoop(); - if (pWorkLoop) - { - if (_cmdGate) - { + // Release command gate + IOWorkLoop *pWorkLoop = getWorkLoop(); + if (pWorkLoop) { + if (_cmdGate) { pWorkLoop->removeEventSource(_cmdGate); - _cmdGate->release(); - _cmdGate = 0; + OSSafeReleaseNULL(_cmdGate); } } - - // - // Uninstall the interrupt handler. - // - if (_interruptHandlerInstalled) - { + // Uninstall the interrupt handler + if (_interruptHandlerInstalled) { _device->uninstallInterruptAction(); _interruptHandlerInstalled = false; } - // - // Uninstall the power control handler. - // - - if (_powerControlHandlerInstalled) - { + // Uninstall the power control handler + if (_powerControlHandlerInstalled) { _device->uninstallPowerControlAction(); _powerControlHandlerInstalled = false; } - - // + // Release the pointer to the provider object. - // - OSSafeReleaseNULL(_device); - - // - // Release ACPI provider for PS2M ACPI device - // - OSSafeReleaseNULL(_provider); - + super::stop(provider); } -void ApplePS2Elan::setParamPropertiesGated(OSDictionary * config) -{ - if (NULL == config) +void ApplePS2Elan::setParamPropertiesGated(OSDictionary *config) { + if (NULL == config) { return; - - const struct {const char *name; int *var;} int32vars[]={ + } + + const struct {const char *name; int *var;} int32vars[] = { {"WakeDelay", &wakedelay}, {"ScrollResolution", &_scrollresolution}, {"TrackpointMultiplierX", &_trackpointMultiplierX}, @@ -419,57 +356,58 @@ void ApplePS2Elan::setParamPropertiesGated(OSDictionary * config) {"MouseResolution", &_mouseResolution}, {"MouseSampleRate", &_mouseSampleRate}, }; - const struct {const char *name; int *var;} boolvars[]={ + + const struct {const char *name; int *var;} boolvars[] = { {"ProcessUSBMouseStopsTrackpad", &_processusbmouse}, {"ProcessBluetoothMouseStopsTrackpad", &_processbluetoothmouse}, {"SetHwResolution", &_set_hw_resolution} }; - const struct {const char* name; bool* var;} lowbitvars[]={ + + const struct {const char *name; bool *var;} lowbitvars[] = { {"USBMouseStopsTrackpad", &usb_mouse_stops_trackpad}, }; - const struct {const char* name; uint64_t* var; } int64vars[]={ - }; - - // highrate? + + const struct {const char *name; uint64_t *var;} int64vars[] = {}; + OSBoolean *bl; - if ((bl=OSDynamicCast (OSBoolean, config->getObject ("UseHighRate")))) - { + OSNumber *num; + + // highrate? + if ((bl = OSDynamicCast(OSBoolean, config->getObject("UseHighRate")))) { setProperty("UseHighRate", bl->isTrue()); } - - OSNumber *num; + // 64-bit config items - for (int i = 0; i < countof(int64vars); i++) - if ((num=OSDynamicCast(OSNumber, config->getObject(int64vars[i].name)))) - { + for (int i = 0; i < countof(int64vars); i++) { + if ((num = OSDynamicCast(OSNumber, config->getObject(int64vars[i].name)))) { *int64vars[i].var = num->unsigned64BitValue(); setProperty(int64vars[i].name, *int64vars[i].var, 64); } + } + // boolean config items - for (int i = 0; i < countof(boolvars); i++) - if ((bl=OSDynamicCast (OSBoolean,config->getObject (boolvars[i].name)))) - { + for (int i = 0; i < countof(boolvars); i++) { + if ((bl = OSDynamicCast(OSBoolean, config->getObject(boolvars[i].name)))) { *boolvars[i].var = bl->isTrue(); setProperty(boolvars[i].name, *boolvars[i].var ? kOSBooleanTrue : kOSBooleanFalse); } + } + // 32-bit config items - for (int i = 0; i < countof(int32vars);i++) - if ((num=OSDynamicCast (OSNumber,config->getObject (int32vars[i].name)))) - { + for (int i = 0; i < countof(int32vars); i++) { + if ((num = OSDynamicCast(OSNumber,config->getObject(int32vars[i].name)))) { *int32vars[i].var = num->unsigned32BitValue(); setProperty(int32vars[i].name, *int32vars[i].var, 32); } + } + // lowbit config items - for (int i = 0; i < countof(lowbitvars); i++) - { - if ((num=OSDynamicCast (OSNumber,config->getObject(lowbitvars[i].name)))) - { - *lowbitvars[i].var = (num->unsigned32BitValue()&0x1)?true:false; + for (int i = 0; i < countof(lowbitvars); i++) { + if ((num = OSDynamicCast(OSNumber, config->getObject(lowbitvars[i].name)))) { + *lowbitvars[i].var = (num->unsigned32BitValue() & 0x1) ? true : false; setProperty(lowbitvars[i].name, *lowbitvars[i].var ? 1 : 0, 32); - } - //REVIEW: are these items ever carried in a boolean? - else if ((bl=OSDynamicCast(OSBoolean, config->getObject(lowbitvars[i].name)))) - { + } else if ((bl = OSDynamicCast(OSBoolean, config->getObject(lowbitvars[i].name)))) { + //REVIEW: are these items ever carried in a boolean? *lowbitvars[i].var = bl->isTrue(); setProperty(lowbitvars[i].name, *lowbitvars[i].var ? kOSBooleanTrue : kOSBooleanFalse); } @@ -481,97 +419,74 @@ void ApplePS2Elan::setParamPropertiesGated(OSDictionary * config) } } -IOReturn ApplePS2Elan::setParamProperties(OSDictionary* dict) -{ - ////IOReturn result = super::IOHIDevice::setParamProperties(dict); - if (_cmdGate) - { +IOReturn ApplePS2Elan::setParamProperties(OSDictionary *dict) { + if (_cmdGate) { // syncronize through workloop... - ////_cmdGate->runAction(OSMemberFunctionCast(IOCommandGate::Action, this, &ApplePS2Elan::setParamPropertiesGated), dict); + //_cmdGate->runAction(OSMemberFunctionCast(IOCommandGate::Action, this, &ApplePS2Elan::setParamPropertiesGated), dict); setParamPropertiesGated(dict); } - + return super::setParamProperties(dict); - ////return result; } -IOReturn ApplePS2Elan::setProperties(OSObject *props) -{ +IOReturn ApplePS2Elan::setProperties(OSObject *props) { OSDictionary *dict = OSDynamicCast(OSDictionary, props); - if (dict && _cmdGate) - { + if (dict && _cmdGate) { // synchronize through workloop... _cmdGate->runAction(OSMemberFunctionCast(IOCommandGate::Action, this, &ApplePS2Elan::setParamPropertiesGated), dict); } - + return super::setProperties(props); } -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void ApplePS2Elan::setDevicePowerState( UInt32 whatToDo ) -{ - switch ( whatToDo ) - { +void ApplePS2Elan::setDevicePowerState(UInt32 whatToDo) { + switch (whatToDo) { case kPS2C_DisableDevice: - // - // Disable touchpad (synchronous). - // - + // Disable the touchpad setTouchPadEnable(false); break; case kPS2C_EnableDevice: - // // Must not issue any commands before the device has - // completed its power-on self-test and calibration. - // - + // completed its power-on self-test and calibration IOSleep(wakedelay); - - // Reset and enable the touchpad. - // Clear packet buffer pointer to avoid issues caused by - // stale packet fragments. - // - resetMouse(); - elantechSetupPS2(); - + // Clear packet buffer pointer to avoid issues caused by stale packet fragments _packetByteCount = 0; _ringBuffer.reset(); - + + // Reset and enable the touchpad + resetMouse(); + elantechSetupPS2(); setTouchPadEnable(true); break; } } -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void ApplePS2Elan::registerHIDPointerNotifications() -{ +void ApplePS2Elan::registerHIDPointerNotifications() { IOServiceMatchingNotificationHandler notificationHandler = OSMemberFunctionCast(IOServiceMatchingNotificationHandler, this, &ApplePS2Elan::notificationHIDAttachedHandler); - + // Determine if we should listen for USB mouse attach events as per configuration if (_processusbmouse) { // USB mouse HID description as per USB spec: http://www.usb.org/developers/hidpage/HID1_11.pdf - OSDictionary* matchingDictionary = serviceMatching("IOUSBInterface"); - + OSDictionary *matchingDictionary = serviceMatching("IOUSBInterface"); + propertyMatching(OSSymbol::withCString(kUSBHostMatchingPropertyInterfaceClass), OSNumber::withNumber(kUSBHIDInterfaceClass, 8), matchingDictionary); propertyMatching(OSSymbol::withCString(kUSBHostMatchingPropertyInterfaceSubClass), OSNumber::withNumber(kUSBHIDBootInterfaceSubClass, 8), matchingDictionary); propertyMatching(OSSymbol::withCString(kUSBHostMatchingPropertyInterfaceProtocol), OSNumber::withNumber(kHIDMouseInterfaceProtocol, 8), matchingDictionary); - + // Register for future services usb_hid_publish_notify = addMatchingNotification(gIOFirstPublishNotification, matchingDictionary, notificationHandler, this, NULL, 10000); usb_hid_terminate_notify = addMatchingNotification(gIOTerminatedNotification, matchingDictionary, notificationHandler, this, NULL, 10000); OSSafeReleaseNULL(matchingDictionary); } - + // Determine if we should listen for bluetooth mouse attach events as per configuration if (_processbluetoothmouse) { // Bluetooth HID devices - OSDictionary* matchingDictionary = serviceMatching("IOBluetoothHIDDriver"); + OSDictionary *matchingDictionary = serviceMatching("IOBluetoothHIDDriver"); propertyMatching(OSSymbol::withCString(kIOHIDVirtualHIDevice), kOSBooleanFalse, matchingDictionary); - + // Register for future services bluetooth_hid_publish_notify = addMatchingNotification(gIOFirstPublishNotification, matchingDictionary, notificationHandler, this, NULL, 10000); bluetooth_hid_terminate_notify = addMatchingNotification(gIOTerminatedNotification, matchingDictionary, notificationHandler, this, NULL, 10000); @@ -579,60 +494,61 @@ void ApplePS2Elan::registerHIDPointerNotifications() } } -void ApplePS2Elan::unregisterHIDPointerNotifications() -{ +void ApplePS2Elan::unregisterHIDPointerNotifications() { // Free device matching notifiers // remove() releases them - if (usb_hid_publish_notify) + + if (usb_hid_publish_notify) { usb_hid_publish_notify->remove(); + } - if (usb_hid_terminate_notify) + if (usb_hid_terminate_notify) { usb_hid_terminate_notify->remove(); + } - if (bluetooth_hid_publish_notify) + if (bluetooth_hid_publish_notify) { bluetooth_hid_publish_notify->remove(); + } - if (bluetooth_hid_terminate_notify) + if (bluetooth_hid_terminate_notify) { bluetooth_hid_terminate_notify->remove(); + } attachedHIDPointerDevices->flushCollection(); } -void ApplePS2Elan::notificationHIDAttachedHandlerGated(IOService * newService, - IONotifier * notifier) -{ +void ApplePS2Elan::notificationHIDAttachedHandlerGated(IOService *newService, IONotifier *notifier) { char path[256]; int len = 255; memset(path, 0, len); newService->getPath(path, &len, gIOServicePlane); - + if (notifier == usb_hid_publish_notify) { attachedHIDPointerDevices->setObject(newService); DEBUG_LOG("%s: USB pointer HID device published: %s, # devices: %d\n", getName(), path, attachedHIDPointerDevices->getCount()); } - + if (notifier == usb_hid_terminate_notify) { attachedHIDPointerDevices->removeObject(newService); DEBUG_LOG("%s: USB pointer HID device terminated: %s, # devices: %d\n", getName(), path, attachedHIDPointerDevices->getCount()); } - + if (notifier == bluetooth_hid_publish_notify) { - // Filter on specific CoD (Class of Device) bluetooth devices only - OSNumber* propDeviceClass = OSDynamicCast(OSNumber, newService->getProperty("ClassOfDevice")); - + OSNumber *propDeviceClass = OSDynamicCast(OSNumber, newService->getProperty("ClassOfDevice")); + if (propDeviceClass != NULL) { - + long classOfDevice = propDeviceClass->unsigned32BitValue(); - + long deviceClassMajor = (classOfDevice & 0x1F00) >> 8; long deviceClassMinor = (classOfDevice & 0xFF) >> 2; - + if (deviceClassMajor == kBluetoothDeviceClassMajorPeripheral) { // Bluetooth peripheral devices - + long deviceClassMinor1 = (deviceClassMinor) & 0x30; long deviceClassMinor2 = (deviceClassMinor) & 0x0F; - + if (deviceClassMinor1 == kBluetoothDeviceClassMinorPeripheral1Pointing || // Seperate pointing device deviceClassMinor1 == kBluetoothDeviceClassMinorPeripheral1Combo) // Combo bluetooth keyboard/touchpad { @@ -640,7 +556,6 @@ void ApplePS2Elan::notificationHIDAttachedHandlerGated(IOService * newService, deviceClassMinor2 == kBluetoothDeviceClassMinorPeripheral2DigitizerTablet || // Magic Touchpad deviceClassMinor2 == kBluetoothDeviceClassMinorPeripheral2DigitalPen) // Wacom Tablet { - attachedHIDPointerDevices->setObject(newService); DEBUG_LOG("%s: Bluetooth pointer HID device published: %s, # devices: %d\n", getName(), path, attachedHIDPointerDevices->getCount()); } @@ -648,19 +563,19 @@ void ApplePS2Elan::notificationHIDAttachedHandlerGated(IOService * newService, } } } - + if (notifier == bluetooth_hid_terminate_notify) { attachedHIDPointerDevices->removeObject(newService); DEBUG_LOG("%s: Bluetooth pointer HID device terminated: %s, # devices: %d\n", getName(), path, attachedHIDPointerDevices->getCount()); } - + if (notifier == usb_hid_publish_notify || notifier == bluetooth_hid_publish_notify) { if (usb_mouse_stops_trackpad && attachedHIDPointerDevices->getCount() > 0) { // One or more USB or Bluetooth pointer devices attached, disable trackpad ignoreall = true; } } - + if (notifier == usb_hid_terminate_notify || notifier == bluetooth_hid_terminate_notify) { if (usb_mouse_stops_trackpad && attachedHIDPointerDevices->getCount() == 0) { // No USB or bluetooth pointer devices attached, re-enable trackpad @@ -669,10 +584,7 @@ void ApplePS2Elan::notificationHIDAttachedHandlerGated(IOService * newService, } } -bool ApplePS2Elan::notificationHIDAttachedHandler(void * refCon, - IOService * newService, - IONotifier * notifier) -{ +bool ApplePS2Elan::notificationHIDAttachedHandler(void *refCon, IOService *newService, IONotifier *notifier) { if (_cmdGate) { // defensive _cmdGate->runAction(OSMemberFunctionCast(IOCommandGate::Action, this, &ApplePS2Elan::notificationHIDAttachedHandlerGated), newService, notifier); } @@ -680,25 +592,24 @@ bool ApplePS2Elan::notificationHIDAttachedHandler(void * refCon, return true; } - -/// elantech.c port - +// elantech.c port template -int ApplePS2Elan::ps2_command(UInt8* params, unsigned int command) -{ +int ApplePS2Elan::ps2_command(UInt8 *params, unsigned int command) { TPS2Request<1 + I> request; request.commands[0].command = kPS2C_SendMouseCommandAndCompareAck; request.commands[0].inOrOut = command; - for (int i = 0; i < I; ++i) + for (int i = 0; i < I; i++) { request.commands[1 + i].command = kPS2C_ReadDataPort; + } request.commandsCount = 1 + I; assert(request.commandsCount <= countof(request.commands)); _device->submitRequestAndBlock(&request); - - for (int i = 0; i < I; ++i) + + for (int i = 0; i < I; i++) { params[i] = request.commands[i + 1].inOrOut; + } return request.commandsCount != 1 + I; } @@ -707,22 +618,23 @@ int ApplePS2Elan::ps2_command(UInt8* params, unsigned int command) * A retrying version of ps2_command */ template -int ApplePS2Elan::elantech_ps2_command(unsigned char *param, int command) -{ +int ApplePS2Elan::elantech_ps2_command(unsigned char *param, int command) { int rc; int tries = ETP_PS2_COMMAND_TRIES; do { rc = ps2_command(param, command); - if (rc == 0) + if (rc == 0) { break; + } tries--; IOLog("VoodooPS2Elan: retrying ps2 command 0x%02x (%d).\n", command, tries); IOSleep(ETP_PS2_COMMAND_DELAY); } while (tries > 0); - if (rc) + if (rc) { IOLog("VoodooPS2Elan: ps2 command 0x%02x failed.\n", command); + } return rc; } @@ -734,28 +646,25 @@ int ApplePS2Elan::elantech_ps2_command(unsigned char *param, int command) * 0xE6 0xE8 rr 0xE8 ss 0xE8 tt 0xE8 uu where (rr*64)+(ss*16)+(tt*4)+uu * is the command. */ - -int ApplePS2Elan::ps2_sliced_command(UInt8 command) -{ +int ApplePS2Elan::ps2_sliced_command(UInt8 command) { int j = 0; - + TPS2Request<> request; request.commands[j].command = kPS2C_SendMouseCommandAndCompareAck; request.commands[j++].inOrOut = kDP_SetMouseScaling1To1; - for (int i = 6; i >= 0; i -= 2) { UInt8 d = (command >> i) & 3; request.commands[j].command = kPS2C_SendMouseCommandAndCompareAck; request.commands[j++].inOrOut = kDP_SetMouseResolution; - + request.commands[j].command = kPS2C_SendMouseCommandAndCompareAck; request.commands[j++].inOrOut = d; } - + request.commandsCount = j; _device->submitRequestAndBlock(&request); - + return request.commandsCount != j; } @@ -763,11 +672,9 @@ int ApplePS2Elan::ps2_sliced_command(UInt8 command) * Send a Synaptics style sliced query command */ template -int ApplePS2Elan::synaptics_send_cmd(unsigned char c, unsigned char *param) -{ - if (ps2_sliced_command(c) || - ps2_command(param, kDP_GetMouseInformation)) { - IOLog("VoodooPS2Elan: query 0x%02x failed.\n", c); +int ApplePS2Elan::synaptics_send_cmd(unsigned char c, unsigned char *param) { + if (ps2_sliced_command(c) || ps2_command(param, kDP_GetMouseInformation)) { + IOLog("VoodooPS2Elan: query 0x%02x failed.\n", c); return -1; } @@ -777,9 +684,8 @@ int ApplePS2Elan::synaptics_send_cmd(unsigned char c, unsigned char *param) /* * V3 and later support this fast command */ - template -int ApplePS2Elan::elantech_send_cmd(unsigned char c, unsigned char* param) -{ +template +int ApplePS2Elan::elantech_send_cmd(unsigned char c, unsigned char *param) { if (ps2_command<0>(NULL, ETP_PS2_CUSTOM_COMMAND) || ps2_command<0>(NULL, c) || ps2_command(param, kDP_GetMouseInformation)) { @@ -790,28 +696,37 @@ int ApplePS2Elan::elantech_send_cmd(unsigned char c, unsigned char* param) return 0; } -bool ApplePS2Elan::elantech_is_signature_valid(const unsigned char *param) -{ +template +int ApplePS2Elan::send_cmd(unsigned char c, unsigned char *param) { + if (info.hw_version >= 3) { + return elantech_send_cmd(c, param); + } else { + return synaptics_send_cmd(c, param); + } +} + +bool ApplePS2Elan::elantech_is_signature_valid(const unsigned char *param) { static const unsigned char rates[] = { 200, 100, 80, 60, 40, 20, 10 }; - int i; - if (param[0] == 0) + if (param[0] == 0) { return false; + } - if (param[1] == 0) + if (param[1] == 0) { return true; + } - /* - * Some hw_version >= 4 models have a revision higher then 20. Meaning - * that param[2] may be 10 or 20, skip the rates check for these. - */ - if ((param[0] & 0x0f) >= 0x06 && (param[1] & 0xaf) == 0x0f && - param[2] < 40) + // Some hw_version >= 4 models have a revision higher then 20. + // Meaning that param[2] may be 10 or 20, skip the rates check for these. + if ((param[0] & 0x0f) >= 0x06 && (param[1] & 0xaf) == 0x0f && param[2] < 40) { return true; + } - for (i = 0; i < sizeof(rates)/sizeof(*rates); i++) - if (param[2] == rates[i]) + for (int i = 0; i < sizeof(rates)/sizeof(*rates); i++) { + if (param[2] == rates[i]) { return false; + } + } return true; } @@ -820,19 +735,16 @@ bool ApplePS2Elan::elantech_is_signature_valid(const unsigned char *param) * (value from firmware) * 10 + 790 = dpi * we also have to convert dpi to dots/mm (*10/254 to avoid floating point) */ -unsigned int ApplePS2Elan::elantech_convert_res(unsigned int val) -{ +unsigned int ApplePS2Elan::elantech_convert_res(unsigned int val) { return (val * 10 + 790) * 10 / 254; } -int ApplePS2Elan::elantech_get_resolution_v4(unsigned int *x_res, - unsigned int *y_res, - unsigned int *bus) -{ +int ApplePS2Elan::elantech_get_resolution_v4(unsigned int *x_res, unsigned int *y_res, unsigned int *bus) { unsigned char param[3]; - if (elantech_send_cmd<3>(ETP_RESOLUTION_QUERY, param)) + if (elantech_send_cmd<3>(ETP_RESOLUTION_QUERY, param)) { return -1; + } *x_res = elantech_convert_res(param[1] & 0x0f); *y_res = elantech_convert_res((param[1] & 0xf0) >> 4); @@ -841,20 +753,10 @@ int ApplePS2Elan::elantech_get_resolution_v4(unsigned int *x_res, return 0; } -template -int ApplePS2Elan::send_cmd(unsigned char c, unsigned char *param) -{ - if (info.hw_version >= 3) - return elantech_send_cmd(c, param); - else - return synaptics_send_cmd(c, param); -} - /* * Use magic knock to detect Elantech touchpad */ -int ApplePS2Elan::elantechDetect() -{ +int ApplePS2Elan::elantechDetect() { unsigned char param[3]; if (ps2_command<0>(NULL, kDP_SetDefaults) || @@ -867,21 +769,16 @@ int ApplePS2Elan::elantechDetect() return -1; } - /* - * Report this in case there are Elantech models that use a different - * set of magic numbers - */ - if (param[0] != 0x3c || param[1] != 0x03 || - (param[2] != 0xc8 && param[2] != 0x00)) { + // Report this in case there are Elantech models that use a different + // set of magic numbers + if (param[0] != 0x3c || param[1] != 0x03 || (param[2] != 0xc8 && param[2] != 0x00)) { IOLog("VoodooPS2Elan: unexpected magic knock result 0x%02x, 0x%02x, 0x%02x.\n", param[0], param[1], param[2]); return -1; } - /* - * Query touchpad's firmware version and see if it reports known - * value to avoid mis-detection. Logitech mice are known to respond - * to Elantech magic knock and there might be more. - */ + // Query touchpad's firmware version and see if it reports known + // value to avoid mis-detection. Logitech mice are known to respond + // to Elantech magic knock and there might be more. if (synaptics_send_cmd<3>(ETP_FW_VERSION_QUERY, param)) { IOLog("VoodooPS2Elan: failed to query firmware version.\n"); return -1; @@ -901,14 +798,12 @@ int ApplePS2Elan::elantechQueryInfo() { unsigned char param[3]; unsigned char traces; - /* - * Do the version query again so we can store the result - */ + // Do the version query again so we can store the result if (synaptics_send_cmd<3>(ETP_FW_VERSION_QUERY, param)) { IOLog("VoodooPS2Elan: failed to query firmware version.\n"); return -1; } - + info.fw_version = (param[0] << 16) | (param[1] << 8) | param[2]; if (elantechSetProperties()) { @@ -940,29 +835,24 @@ int ApplePS2Elan::elantechQueryInfo() { } if (info.samples[1] == 0x74 && info.hw_version == 0x03) { - /* - * This module has a bug which makes absolute mode - * unusable, so let's abort so we'll be using standard - * PS/2 protocol. - */ + // This module has a bug which makes absolute mode unusable, + // so let's abort so we'll be using standard PS/2 protocol. IOLog("VoodooPS2Elan: absolute mode broken, forcing standard PS/2 protocol\n"); return -1; } - /* The MSB indicates the presence of the trackpoint */ + // The MSB indicates the presence of the trackpoint info.has_trackpoint = (info.capabilities[0] & 0x80) == 0x80; info.x_res = 31; info.y_res = 31; if (info.hw_version == 4) { - if (elantech_get_resolution_v4(&info.x_res, - &info.y_res, - &info.bus)) { + if (elantech_get_resolution_v4(&info.x_res, &info.y_res, &info.bus)) { IOLog("VoodooPS2Elan: failed to query resolution data.\n"); } } - /* query range information */ + // query range information switch (info.hw_version) { case 1: info.x_min = ETP_XMIN_V1; @@ -980,20 +870,17 @@ int ApplePS2Elan::elantechQueryInfo() { info.x_max = ETP_XMAX_V2; info.y_max = ETP_YMAX_V2; } else { - int i; - int fixed_dpi; - - i = (info.fw_version > 0x020800 && - info.fw_version < 0x020900) ? 1 : 2; - - if (send_cmd<3>(ETP_FW_ID_QUERY, param)) + if (send_cmd<3>(ETP_FW_ID_QUERY, param)) { return -1; + } - fixed_dpi = param[1] & 0x10; + int i = (info.fw_version > 0x020800 && info.fw_version < 0x020900) ? 1 : 2; + int fixed_dpi = param[1] & 0x10; if (((info.fw_version >> 16) == 0x14) && fixed_dpi) { - if (send_cmd<3>(ETP_SAMPLE_QUERY, param)) + if (send_cmd<3>(ETP_SAMPLE_QUERY, param)) { return -1; + } info.x_max = (info.capabilities[1] - i) * param[1] / 2; info.y_max = (info.capabilities[2] - i) * param[2] / 2; @@ -1011,36 +898,40 @@ int ApplePS2Elan::elantechQueryInfo() { break; case 3: - if (send_cmd<3>(ETP_FW_ID_QUERY, param)) + if (send_cmd<3>(ETP_FW_ID_QUERY, param)) { return -1; + } info.x_max = (0x0f & param[0]) << 8 | param[1]; info.y_max = (0xf0 & param[0]) << 4 | param[2]; break; case 4: - if (send_cmd<3>(ETP_FW_ID_QUERY, param)) + if (send_cmd<3>(ETP_FW_ID_QUERY, param)) { return -1; + } info.x_max = (0x0f & param[0]) << 8 | param[1]; info.y_max = (0xf0 & param[0]) << 4 | param[2]; traces = info.capabilities[1]; - if ((traces < 2) || (traces > info.x_max)) + if ((traces < 2) || (traces > info.x_max)) { return -1; + } info.width = info.x_max / (traces - 1); - /* column number of traces */ + // column number of traces info.x_traces = traces; - /* row number of traces */ + // row number of traces traces = info.capabilities[2]; - if ((traces >= 2) && (traces <= info.y_max)) + if ((traces >= 2) && (traces <= info.y_max)) { info.y_traces = traces; + } break; } - + /* check for the middle button: DMI matching or new v4 firmwares */ //info.has_middle_button = dmi_check_system(elantech_dmi_has_middle_button) || // (ETP_NEW_IC_SMBUS_HOST_NOTIFY(info.fw_version) && @@ -1052,15 +943,14 @@ int ApplePS2Elan::elantechQueryInfo() { /* * determine hardware version and set some properties according to it. */ -int ApplePS2Elan::elantechSetProperties() -{ - /* This represents the version of IC body. */ +int ApplePS2Elan::elantechSetProperties() { + // This represents the version of IC body int ver = (info.fw_version & 0x0f0000) >> 16; - /* Early version of Elan touchpads doesn't obey the rule. */ - if (info.fw_version < 0x020030 || info.fw_version == 0x020600) + // Early version of Elan touchpads doesn't obey the rule + if (info.fw_version < 0x020030 || info.fw_version == 0x020600) { info.hw_version = 1; - else { + } else { switch (ver) { case 2: case 4: @@ -1076,32 +966,29 @@ int ApplePS2Elan::elantechSetProperties() return -1; } } - - /* Turn on packet checking by default */ + + // Turn on packet checking by default info.paritycheck = 1; - /* - * This firmware suffers from misreporting coordinates when - * a touch action starts causing the mouse cursor or scrolled page - * to jump. Enable a workaround. - */ + // This firmware suffers from misreporting coordinates when + // a touch action starts causing the mouse cursor or scrolled page + // to jump. Enable a workaround. info.jumpy_cursor = (info.fw_version == 0x020022 || info.fw_version == 0x020600); if (info.hw_version > 1) { - /* For now show extra debug information */ + // For now show extra debug information info.debug = 1; - if (info.fw_version >= 0x020800) + if (info.fw_version >= 0x020800) { info.reports_pressure = true; + } } - /* - * The signatures of v3 and v4 packets change depending on the - * value of this hardware flag. - */ + // The signatures of v3 and v4 packets change depending on the + // value of this hardware flag. info.crc_enabled = (info.fw_version & 0x4000) == 0x4000; - /* Enable real hardware resolution on hw_version 3 ? */ + // Enable real hardware resolution on hw_version 3 ? info.set_hw_resolution = _set_hw_resolution;//!dmi_check_system(no_hw_res_dmi_table); return 0; @@ -1110,8 +997,7 @@ int ApplePS2Elan::elantechSetProperties() /* * Set the appropriate event bits for the input subsystem */ -int ApplePS2Elan::elantechSetInputParams() -{ +int ApplePS2Elan::elantechSetInputParams() { setProperty(VOODOO_INPUT_LOGICAL_MAX_X_KEY, info.x_max - info.x_min, 32); setProperty(VOODOO_INPUT_LOGICAL_MAX_Y_KEY, info.y_max - info.y_min, 32); @@ -1128,8 +1014,7 @@ int ApplePS2Elan::elantechSetInputParams() /* * Put the touchpad into absolute mode */ -int ApplePS2Elan::elantechSetAbsoluteMode() -{ +int ApplePS2Elan::elantechSetAbsoluteMode() { unsigned char val; int tries = ETP_READ_BACK_TRIES; int rc = 0; @@ -1145,10 +1030,10 @@ int ApplePS2Elan::elantechSetAbsoluteMode() break; case 2: - /* Windows driver values */ + // Windows driver values etd.reg_10 = 0x54; - etd.reg_11 = 0x88; /* 0x8a */ - etd.reg_21 = 0x60; /* 0x00 */ + etd.reg_11 = 0x88; // 0x8a + etd.reg_21 = 0x60; // 0x00 if (elantechWriteReg(0x10, etd.reg_10) || elantechWriteReg(0x11, etd.reg_11) || elantechWriteReg(0x21, etd.reg_21)) { @@ -1157,35 +1042,37 @@ int ApplePS2Elan::elantechSetAbsoluteMode() break; case 3: - if (info.set_hw_resolution) + if (info.set_hw_resolution) { etd.reg_10 = 0x0b; - else + } else { etd.reg_10 = 0x01; + } - if (elantechWriteReg(0x10, etd.reg_10)) + if (elantechWriteReg(0x10, etd.reg_10)) { rc = -1; + } break; case 4: etd.reg_07 = 0x01; - if (elantechWriteReg(0x07, etd.reg_07)) + if (elantechWriteReg(0x07, etd.reg_07)) { rc = -1; + } - goto skip_readback_reg_10; /* v4 has no reg 0x10 to read */ + goto skip_readback_reg_10; // v4 has no reg 0x10 to read } if (rc == 0) { - /* - * Read back reg 0x10. For hardware version 1 we must make - * sure the absolute mode bit is set. For hardware version 2 - * the touchpad is probably initializing and not ready until - * we read back the value we just wrote. - */ + // Read back reg 0x10. For hardware version 1 we must make + // sure the absolute mode bit is set. For hardware version 2 + // the touchpad is probably initializing and not ready until + // we read back the value we just wrote. do { rc = elantechReadReg(0x10, &val); - if (rc == 0) + if (rc == 0) { break; + } tries--; IOLog("VoodooPS2Elan: retrying read (%d).\n", tries); IOSleep(ETP_READ_BACK_DELAY); @@ -1193,16 +1080,16 @@ int ApplePS2Elan::elantechSetAbsoluteMode() if (rc) { IOLog("VoodooPS2Elan: failed to read back register 0x10.\n"); - } else if (info.hw_version == 1 && - !(val & ETP_R10_ABSOLUTE_MODE)) { + } else if (info.hw_version == 1 && !(val & ETP_R10_ABSOLUTE_MODE)) { IOLog("VoodooPS2Elan: touchpad refuses to switch to absolute mode.\n"); rc = -1; } } - skip_readback_reg_10: - if (rc) +skip_readback_reg_10: + if (rc) { IOLog("VoodooPS2Elan: failed to initialise registers.\n"); + } return rc; } @@ -1210,12 +1097,9 @@ int ApplePS2Elan::elantechSetAbsoluteMode() /* * Initialize the touchpad */ -int ApplePS2Elan::elantechSetupPS2() -{ - int i; - +int ApplePS2Elan::elantechSetupPS2() { etd.parity[0] = 1; - for (i = 1; i < 256; i++) + for (int i = 1; i < 256; i++) etd.parity[i] = etd.parity[i & (i - 1)] ^ 1; if (elantechSetAbsoluteMode()) { @@ -1232,7 +1116,7 @@ int ApplePS2Elan::elantechSetupPS2() IOLog("VoodooPS2: failed to query touchpad range.\n"); return -1; } - + // set resolution and dpi TPS2Request<> request; request.commands[0].command = kPS2C_SendMouseCommandAndCompareAck; @@ -1251,7 +1135,7 @@ int ApplePS2Elan::elantechSetupPS2() request.commands[6].inOrOut = kDP_Enable; // 0xF4, Enable Data Reporting request.commandsCount = 7; _device->submitRequestAndBlock(&request); - + return 0; } @@ -1262,11 +1146,13 @@ int ApplePS2Elan::elantechReadReg(unsigned char reg, unsigned char *val) { unsigned char param[3]; int rc = 0; - if (reg < 0x07 || reg > 0x26) + if (reg < 0x07 || reg > 0x26) { return -1; + } - if (reg > 0x11 && reg < 0x20) + if (reg > 0x11 && reg < 0x20) { return -1; + } switch (info.hw_version) { case 1: @@ -1298,12 +1184,13 @@ int ApplePS2Elan::elantechReadReg(unsigned char reg, unsigned char *val) { break; } - if (rc) + if (rc) { IOLog("VoodooPS2Elan: failed to read register 0x%02x.\n", reg); - else if (info.hw_version != 4) + } else if (info.hw_version != 4) { *val = param[0]; - else + } else { *val = param[1]; + } return rc; } @@ -1311,15 +1198,16 @@ int ApplePS2Elan::elantechReadReg(unsigned char reg, unsigned char *val) { /* * Send an Elantech style special command to write a register with a value */ -int ApplePS2Elan::elantechWriteReg(unsigned char reg, unsigned char val) -{ +int ApplePS2Elan::elantechWriteReg(unsigned char reg, unsigned char val) { int rc = 0; - if (reg < 0x07 || reg > 0x26) + if (reg < 0x07 || reg > 0x26) { return -1; + } - if (reg > 0x11 && reg < 0x20) + if (reg > 0x11 && reg < 0x20) { return -1; + } switch (info.hw_version) { case 1: @@ -1370,85 +1258,85 @@ int ApplePS2Elan::elantechWriteReg(unsigned char reg, unsigned char val) break; } - if (rc) - IOLog("VoodooPS2Elan: failed to write register 0x%02x with value 0x%02x.\n", - reg, val); + if (rc) { + IOLog("VoodooPS2Elan: failed to write register 0x%02x with value 0x%02x.\n", reg, val); + } return rc; } -int ApplePS2Elan::elantechPacketCheckV3() -{ +int ApplePS2Elan::elantechPacketCheckV3() { static const uint8_t debounce_packet[] = { 0xc4, 0xff, 0xff, 0x02, 0xff, 0xff }; unsigned char *packet = _ringBuffer.tail(); - /* - * check debounce first, it has the same signature in byte 0 - * and byte 3 as PACKET_V3_HEAD. - */ - if (!memcmp(packet, debounce_packet, sizeof(debounce_packet))) + // check debounce first, it has the same signature in byte 0 + // and byte 3 as PACKET_V3_HEAD. + if (!memcmp(packet, debounce_packet, sizeof(debounce_packet))) { return PACKET_DEBOUNCE; + } - /* - * If the hardware flag 'crc_enabled' is set the packets have - * different signatures. - */ + // If the hardware flag 'crc_enabled' is set the packets have different signatures. if (info.crc_enabled) { - if ((packet[3] & 0x09) == 0x08) + if ((packet[3] & 0x09) == 0x08) { return PACKET_V3_HEAD; + } - if ((packet[3] & 0x09) == 0x09) + if ((packet[3] & 0x09) == 0x09) { return PACKET_V3_TAIL; + } } else { - if ((packet[0] & 0x0c) == 0x04 && (packet[3] & 0xcf) == 0x02) + if ((packet[0] & 0x0c) == 0x04 && (packet[3] & 0xcf) == 0x02) { return PACKET_V3_HEAD; + } - if ((packet[0] & 0x0c) == 0x0c && (packet[3] & 0xce) == 0x0c) + if ((packet[0] & 0x0c) == 0x0c && (packet[3] & 0xce) == 0x0c) { return PACKET_V3_TAIL; - if ((packet[3] & 0x0f) == 0x06) + } + + if ((packet[3] & 0x0f) == 0x06) { return PACKET_TRACKPOINT; + } } return PACKET_UNKNOWN; } -int ApplePS2Elan::elantechPacketCheckV4() -{ +int ApplePS2Elan::elantechPacketCheckV4() { unsigned char *packet = _ringBuffer.tail(); unsigned char packet_type = packet[3] & 0x03; unsigned int ic_version; bool sanity_check; - + INTERRUPT_LOG("VoodooPS2Elan: Packet dump (%04x, %04x, %04x, %04x, %04x, %04x)\n", packet[0], packet[1], packet[2], packet[3], packet[4], packet[5] ); - if (info.has_trackpoint && (packet[3] & 0x0f) == 0x06) + if (info.has_trackpoint && (packet[3] & 0x0f) == 0x06) { return PACKET_TRACKPOINT; + } - /* This represents the version of IC body. */ + // This represents the version of IC body. ic_version = (info.fw_version & 0x0f0000) >> 16; - + INTERRUPT_LOG("VoodooPS2Elan: icVersion(%d), crc(%d), samples[1](%d) \n", ic_version, info.crc_enabled, info.samples[1]); - /* - * Sanity check based on the constant bits of a packet. - * The constant bits change depending on the value of - * the hardware flag 'crc_enabled' and the version of - * the IC body, but are the same for every packet, - * regardless of the type. - */ - if (info.crc_enabled) + // Sanity check based on the constant bits of a packet. + // The constant bits change depending on the value of + // the hardware flag 'crc_enabled' and the version of + // the IC body, but are the same for every packet, + // regardless of the type. + if (info.crc_enabled) { sanity_check = ((packet[3] & 0x08) == 0x00); - else if (ic_version == 7 && info.samples[1] == 0x2A) + } else if (ic_version == 7 && info.samples[1] == 0x2A) { sanity_check = ((packet[3] & 0x1c) == 0x10); - else - sanity_check = ((packet[0] & 0x08) == 0x00 && - (packet[3] & 0x1c) == 0x10); + } else { + sanity_check = ((packet[0] & 0x08) == 0x00 && (packet[3] & 0x1c) == 0x10); + } - if (!sanity_check) + if (!sanity_check) { return PACKET_UNKNOWN; + } switch (packet_type) { case 0: @@ -1464,49 +1352,41 @@ int ApplePS2Elan::elantechPacketCheckV4() return PACKET_UNKNOWN; } -void ApplePS2Elan::elantechReportAbsoluteV3(int packetType) -{ +void ApplePS2Elan::elantechReportAbsoluteV3(int packetType) { unsigned char *packet = _ringBuffer.tail(); unsigned int fingers = 0, x1 = 0, y1 = 0, x2 = 0, y2 = 0; unsigned int width = 0, pres = 0; - /* byte 0: n1 n0 . . . . R L */ + // byte 0: n1 n0 . . . . R L fingers = (packet[0] & 0xc0) >> 6; switch (fingers) { case 3: case 1: - /* - * byte 1: . . . . x11 x10 x9 x8 - * byte 2: x7 x6 x5 x4 x4 x2 x1 x0 - */ + // byte 1: . . . . x11 x10 x9 x8 + // byte 2: x7 x6 x5 x4 x4 x2 x1 x0 x1 = ((packet[1] & 0x0f) << 8) | packet[2]; - /* - * byte 4: . . . . y11 y10 y9 y8 - * byte 5: y7 y6 y5 y4 y3 y2 y1 y0 - */ + + // byte 4: . . . . y11 y10 y9 y8 + // byte 5: y7 y6 y5 y4 y3 y2 y1 y0 y1 = info.y_max - (((packet[4] & 0x0f) << 8) | packet[5]); break; case 2: if (packetType == PACKET_V3_HEAD) { - /* - * byte 1: . . . . ax11 ax10 ax9 ax8 - * byte 2: ax7 ax6 ax5 ax4 ax3 ax2 ax1 ax0 - */ + // byte 1: . . . . ax11 ax10 ax9 ax8 + // byte 2: ax7 ax6 ax5 ax4 ax3 ax2 ax1 ax0 etd.mt[0].x = ((packet[1] & 0x0f) << 8) | packet[2]; - /* - * byte 4: . . . . ay11 ay10 ay9 ay8 - * byte 5: ay7 ay6 ay5 ay4 ay3 ay2 ay1 ay0 - */ + + // byte 4: . . . . ay11 ay10 ay9 ay8 + // byte 5: ay7 ay6 ay5 ay4 ay3 ay2 ay1 ay0 etd.mt[0].y = info.y_max - (((packet[4] & 0x0f) << 8) | packet[5]); - /* - * wait for next packet - */ + + // wait for next packet return; } - /* packet_type == PACKET_V3_TAIL */ + // packet_type == PACKET_V3_TAIL x1 = etd.mt[0].x; y1 = etd.mt[0].y; x2 = ((packet[1] & 0x0f) << 8) | packet[2]; @@ -1520,62 +1400,62 @@ void ApplePS2Elan::elantechReportAbsoluteV3(int packetType) virtualFinger[0].touch = false; virtualFinger[1].touch = false; virtualFinger[2].touch = false; - + leftButton = packet[0] & 0x01; rightButton = packet[0] & 0x02; - - if (fingers == 1 || fingers == 2) - { + + if (fingers == 1 || fingers == 2) { virtualFinger[0].touch = true; virtualFinger[0].button = packet[0] & 0x03; virtualFinger[0].prev = virtualFinger[0].now; virtualFinger[0].now.x = x1; virtualFinger[0].now.y = y1; - if (lastFingersV3 != 1 && lastFingersV3 != 2) + if (lastFingersV3 != 1 && lastFingersV3 != 2) { virtualFinger[0].prev = virtualFinger[0].now; + } } - if (fingers == 2) - { + + if (fingers == 2) { virtualFinger[1].touch = true; virtualFinger[1].button = packet[0] & 0x03; virtualFinger[1].prev = virtualFinger[1].now; virtualFinger[1].now.x = x2; virtualFinger[1].now.y = y2; - if (lastFingersV3 != 2) + if (lastFingersV3 != 2) { virtualFinger[1].prev = virtualFinger[1].now; + } } - if (fingers == 3) - { + + if (fingers == 3) { virtualFinger[0].touch = virtualFinger[1].touch = virtualFinger[2].touch = true; virtualFinger[0].button = virtualFinger[1].button = virtualFinger[2].button = packet[0] & 0x03; virtualFinger[0].prev = virtualFinger[0].now; virtualFinger[1].prev = virtualFinger[1].now; virtualFinger[2].prev = virtualFinger[2].now; - + float sin30deg = 0.5f; float cos30deg = 0.86602540378f; - + int h = 100; int dy = (int)(sin30deg * h); int dx = (int)(cos30deg * h); - + virtualFinger[0].now.x = x1; virtualFinger[0].now.y = y1 - h; - + virtualFinger[1].now.x = x1 - dx; virtualFinger[1].now.y = y1 + dy; - + virtualFinger[2].now.x = x1 + dx; virtualFinger[2].now.y = y1 + dy; - - if (lastFingersV3 != 3) - { + + if (lastFingersV3 != 3) { virtualFinger[0].prev = virtualFinger[0].now; virtualFinger[1].prev = virtualFinger[1].now; virtualFinger[2].prev = virtualFinger[2].now; } } - + lastFingersV3 = fingers; sendTouchData(); } @@ -1601,36 +1481,37 @@ void ApplePS2Elan::elantechReportAbsoluteV4(int packetType) { INTERRUPT_LOG("VoodooPS2Elan: Got motion packet\n"); processPacketMotionV4(); break; + case PACKET_UNKNOWN: default: - /* impossible to get here */ + // impossible to get here break; } } void ApplePS2Elan::elantechReportTrackpoint() { unsigned char *packet = _ringBuffer.tail(); - + int trackpointLeftButton = packet[0] & 0x1; int trackpointRightButton = packet[0] & 0x2; int trackpointMiddleButton = packet[0] & 0x4; - + int dx = packet[4] - (int)((packet[1] ^ 0x80) << 1); int dy = (int)((packet[2] ^ 0x80) << 1) - packet[5]; - + dx = dx * _trackpointMultiplierX / _trackpointDividerX; dy = dy * _trackpointMultiplierY / _trackpointDividerY; - + // enable trackpoint scroll mode when middle button was pressed and the trackpoint moved if (trackpointMiddleButton == 4 && (dx != 0 || dy != 0)) { trackpointScrolling = true; } - + // disable trackpoint scrolling mode when middle button is released if (trackpointScrolling && trackpointMiddleButton == 0) { trackpointScrolling = false; } - + AbsoluteTime timestamp; clock_get_uptime(×tamp); @@ -1647,7 +1528,7 @@ void ApplePS2Elan::processPacketStatusV4() { leftButton = packet[0] & 0x1; rightButton = packet[0] & 0x2; - /* notify finger state change */ + // notify finger state change fingers = packet[1] & 0x1f; int count = 0; for (int i = 0; i < ETP_MAX_FINGERS; i++) { @@ -1655,19 +1536,17 @@ void ApplePS2Elan::processPacketStatusV4() { // finger has been lifted off the touchpad INTERRUPT_LOG("VoodooPS2Elan: %d finger has been lifted off the touchpad\n", i); virtualFinger[i].touch = false; - } - else - { + } else { virtualFinger[i].touch = true; INTERRUPT_LOG("VoodooPS2Elan: %d finger has been touched the touchpad\n", i); count++; } } - + heldFingers = count; - + headPacketsCount = 0; - + // if count > 0, we wait for HEAD packets to report so that we report all fingers at once. // if count == 0, we have to report the fact fingers are taken off, because there won't be any HEAD packets if (count == 0) @@ -1676,15 +1555,15 @@ void ApplePS2Elan::processPacketStatusV4() { void ApplePS2Elan::processPacketHeadV4() { unsigned char *packet = _ringBuffer.tail(); - + leftButton = packet[0] & 0x1; rightButton = packet[0] & 0x2; - + int id = ((packet[3] & 0xe0) >> 5) - 1; int pres, traces; headPacketsCount++; - + if (id < 0) { INTERRUPT_LOG("VoodooPS2Elan: invalid id, aborting\n"); return; @@ -1698,17 +1577,17 @@ void ApplePS2Elan::processPacketHeadV4() { pres = (packet[1] & 0xf0) | ((packet[4] & 0xf0) >> 4); traces = (packet[0] & 0xf0) >> 4; - + INTERRUPT_LOG("VoodooPS2Elan: pres: %d, traces: %d, width: %d\n", pres, traces, etd.width); - + virtualFinger[id].button = (packet[0] & 1); virtualFinger[id].prev = virtualFinger[id].now; virtualFinger[id].now.pressure = pres; virtualFinger[id].now.width = traces; - + virtualFinger[id].now.x = x; virtualFinger[id].now.y = y; - + if (headPacketsCount == heldFingers) { headPacketsCount = 0; sendTouchData(); @@ -1722,37 +1601,36 @@ void ApplePS2Elan::processPacketMotionV4() { leftButton = packet[0] & 0x1; rightButton = packet[0] & 0x2; - + id = ((packet[0] & 0xe0) >> 5) - 1; if (id < 0) { INTERRUPT_LOG("VoodooPS2Elan: invalid id, aborting\n"); return; } - + sid = ((packet[3] & 0xe0) >> 5) - 1; weight = (packet[0] & 0x10) ? ETP_WEIGHT_VALUE : 1; - /* - * Motion packets give us the delta of x, y values of specific fingers, - * but in two's complement. Let the compiler do the conversion for us. - * Also _enlarge_ the numbers to int, in case of overflow. - */ + + // Motion packets give us the delta of x, y values of specific fingers, + // but in two's complement. Let the compiler do the conversion for us. + // Also _enlarge_ the numbers to int, in case of overflow. delta_x1 = (signed char)packet[1]; delta_y1 = (signed char)packet[2]; delta_x2 = (signed char)packet[4]; delta_y2 = (signed char)packet[5]; - + virtualFinger[id].button = (packet[0] & 1); virtualFinger[id].prev = virtualFinger[id].now; virtualFinger[id].now.x += delta_x1 * weight; virtualFinger[id].now.y -= delta_y1 * weight; - + if (sid >= 0) { virtualFinger[sid].button = (packet[0] & 1); virtualFinger[sid].prev = virtualFinger[sid].now; virtualFinger[sid].now.x += delta_x2 * weight; virtualFinger[sid].now.y -= delta_y2 * weight; } - + sendTouchData(); } @@ -1773,40 +1651,41 @@ MT2FingerType ApplePS2Elan::GetBestFingerType(int i) { void ApplePS2Elan::sendTouchData() { AbsoluteTime timestamp; clock_get_uptime(×tamp); - + bool is_buttonpad = elantech_is_buttonpad(); - + static_assert(VOODOO_INPUT_MAX_TRANSDUCERS >= ETP_MAX_FINGERS, "Trackpad supports too many fingers"); - + int count = 0; - for (int i = 0; i < ETP_MAX_FINGERS; ++i){ - if (!virtualFinger[i].touch) + for (int i = 0; i < ETP_MAX_FINGERS; i++) { + if (!virtualFinger[i].touch) { continue; - + } + inputEvent.transducers[count].currentCoordinates = virtualFinger[i].now; inputEvent.transducers[count].previousCoordinates = virtualFinger[i].prev; - + inputEvent.transducers[count].isValid = true; inputEvent.transducers[count].isPhysicalButtonDown = is_buttonpad && virtualFinger[i].button; inputEvent.transducers[count].isTransducerActive = true; - + inputEvent.transducers[count].secondaryId = count; inputEvent.transducers[count].fingerType = GetBestFingerType(count); inputEvent.transducers[count].type = FINGER; - + // it looks like Elan PS2 pressure and width is very inaccurate // it is better to leave it that way inputEvent.transducers[count].supportsPressure = false; - + inputEvent.transducers[count].timestamp = timestamp; - + count++; } - + // set the thumb to improve 4F pinch and spread gesture if (count == 4) { // simple thumb detection: to find the lowest finger touch. - SInt16 y_min = info.y_max / 2; + UInt32 y_min = info.y_max / 2; int thumb_index = 0; int currentThumbIndex = 0; for (int i = 0; i < count; i++) { @@ -1814,36 +1693,32 @@ void ApplePS2Elan::sendTouchData() { y_min = inputEvent.transducers[i].currentCoordinates.y; thumb_index = i; } - if (inputEvent.transducers[i].fingerType == kMT2FingerTypeThumb) + if (inputEvent.transducers[i].fingerType == kMT2FingerTypeThumb) { currentThumbIndex = i; + } } inputEvent.transducers[currentThumbIndex].fingerType = inputEvent.transducers[thumb_index].fingerType; inputEvent.transducers[thumb_index].fingerType = kMT2FingerTypeThumb; } - - for (int i = count; i < VOODOO_INPUT_MAX_TRANSDUCERS; ++i) { + + for (int i = count; i < VOODOO_INPUT_MAX_TRANSDUCERS; i++) { inputEvent.transducers[i].isValid = false; inputEvent.transducers[i].isPhysicalButtonDown = false; inputEvent.transducers[i].isTransducerActive = false; } - + inputEvent.contact_count = count; inputEvent.timestamp = timestamp; - - if (voodooInputInstance) - { + + if (voodooInputInstance) { super::messageClient(kIOMessageVoodooInputMessage, voodooInputInstance, &inputEvent, sizeof(VoodooInputEvent)); } - - if (!is_buttonpad) - { - if (inputEvent.contact_count == 0) - { + + if (!is_buttonpad) { + if (inputEvent.contact_count == 0) { UInt32 buttons = leftButton | rightButton; dispatchRelativePointerEvent(0, 0, buttons, timestamp); - } - else - { + } else { UInt32 buttons = 0; bool send = false; if (lastLeftButton != leftButton) { @@ -1854,8 +1729,9 @@ void ApplePS2Elan::sendTouchData() { buttons |= rightButton; send = true; } - if (send) + if (send) { dispatchRelativePointerEvent(0, 0, buttons, timestamp); + } } lastLeftButton = leftButton; @@ -1865,11 +1741,10 @@ void ApplePS2Elan::sendTouchData() { } PS2InterruptResult ApplePS2Elan::interruptOccurred(UInt8 data) { - UInt8* packet = _ringBuffer.head(); + UInt8 *packet = _ringBuffer.head(); packet[_packetByteCount++] = data; - - if (_packetByteCount == kPacketLength) - { + + if (_packetByteCount == kPacketLength) { _ringBuffer.advanceHead(kPacketLength); _packetByteCount = 0; return kPS2IR_packetReady; @@ -1878,39 +1753,43 @@ PS2InterruptResult ApplePS2Elan::interruptOccurred(UInt8 data) { return kPS2IR_packetBuffering; } -void ApplePS2Elan::packetReady() -{ +void ApplePS2Elan::packetReady() { INTERRUPT_LOG("VoodooPS2Elan: packet ready occurred\n"); // empty the ring buffer, dispatching each packet... - while (_ringBuffer.count() >= kPacketLength) - { + while (_ringBuffer.count() >= kPacketLength) { int packetType; switch (info.hw_version) { case 1: case 2: - INTERRUPT_LOG("VoodooPS2Elan: packet ready occurred, but unsupported version\n"); // V1 and V2 are ancient hardware, not going to implement right away + INTERRUPT_LOG("VoodooPS2Elan: packet ready occurred, but unsupported version\n"); break; + case 3: packetType = elantechPacketCheckV3(); + INTERRUPT_LOG("VoodooPS2Elan: Packet Type %d\n", packetType); + switch (packetType) { case PACKET_UNKNOWN: INTERRUPT_LOG("VoodooPS2Elan: invalid packet received\n"); break; + case PACKET_DEBOUNCE: - /* ignore debounce */ + // ignore debounce break; + case PACKET_TRACKPOINT: elantechReportTrackpoint(); break; + default: elantechReportAbsoluteV3(packetType); break; } break; + case 4: packetType = elantechPacketCheckV4(); - INTERRUPT_LOG("VoodooPS2Elan: Packet Type %d\n", packetType); switch (packetType) { @@ -1922,11 +1801,14 @@ void ApplePS2Elan::packetReady() INTERRUPT_LOG("VoodooPS2Elan: Handling trackpoint mode\n"); elantechReportTrackpoint(); break; + default: INTERRUPT_LOG("VoodooPS2Elan: Handling absolute mode\n"); elantechReportAbsoluteV4(packetType); + break; } break; + default: INTERRUPT_LOG("VoodooPS2Elan: invalid packet received\n"); } @@ -1938,13 +1820,12 @@ void ApplePS2Elan::packetReady() void ApplePS2Elan::resetMouse() { UInt8 params[2]; ps2_command<2>(params, kDP_Reset); - + if (params[0] != 0xaa && params[1] != 0x00) { IOLog("VoodooPS2Elan: failed resetting.\n"); } } -void ApplePS2Elan::setTouchPadEnable(bool enable) -{ +void ApplePS2Elan::setTouchPadEnable(bool enable) { ps2_command<0>(NULL, enable ? kDP_Enable : kDP_SetDefaultsAndDisable); } diff --git a/VoodooPS2Trackpad/VoodooPS2Elan.h b/VoodooPS2Trackpad/VoodooPS2Elan.h index e41c8f14..1a779796 100644 --- a/VoodooPS2Trackpad/VoodooPS2Elan.h +++ b/VoodooPS2Trackpad/VoodooPS2Elan.h @@ -190,7 +190,6 @@ struct elantech_device_info { }; struct elantech_data { - char tp_phys[32]; unsigned char reg_07; unsigned char reg_10; unsigned char reg_11; @@ -210,8 +209,7 @@ struct elantech_data { // ApplePS2Elan Class Declaration // -class EXPORT ApplePS2Elan : public IOHIPointing -{ +class EXPORT ApplePS2Elan : public IOHIPointing { typedef IOHIPointing super; OSDeclareDefaultStructors(ApplePS2Elan); @@ -222,70 +220,69 @@ class EXPORT ApplePS2Elan : public IOHIPointing bool _powerControlHandlerInstalled {false}; UInt32 _packetByteCount {0}; RingBuffer _ringBuffer {}; - + IOCommandGate* _cmdGate {nullptr}; - IOACPIPlatformDevice* _provider {nullptr}; - + VoodooInputEvent inputEvent {}; - + // when trackpad has physical button UInt32 leftButton = 0; UInt32 rightButton = 0; UInt32 lastLeftButton = 0; UInt32 lastRightButton = 0; - + UInt32 lastFingersV3 = 0; - + bool trackpointScrolling {false}; - + int heldFingers = 0; int headPacketsCount = 0; virtual_finger_state virtualFinger[ETP_MAX_FINGERS] {}; - + + static_assert(ETP_MAX_FINGERS <= kMT2FingerTypeLittleFinger, "Too many fingers for one hand"); + int _scrollresolution {2300}; int wakedelay {1000}; int _trackpointMultiplierX {200}; int _trackpointMultiplierY {200}; int _trackpointDividerX {200}; int _trackpointDividerY {200}; - - int _mouseResolution { 0x3 }; - int _mouseSampleRate { 200 }; - + + int _mouseResolution {0x3}; + int _mouseSampleRate {200}; + int _set_hw_resolution {false}; - - static_assert(ETP_MAX_FINGERS <= kMT2FingerTypeLittleFinger, "Too many fingers for one hand"); bool ignoreall {false}; bool usb_mouse_stops_trackpad {true}; - + int _processusbmouse {true}; int _processbluetoothmouse {true}; - OSSet* attachedHIDPointerDevices {nullptr}; - - IONotifier* usb_hid_publish_notify {nullptr}; // Notification when an USB mouse HID device is connected - IONotifier* usb_hid_terminate_notify {nullptr}; // Notification when an USB mouse HID device is disconnected - - IONotifier* bluetooth_hid_publish_notify {nullptr}; // Notification when a bluetooth HID device is connected - IONotifier* bluetooth_hid_terminate_notify {nullptr}; // Notification when a bluetooth HID device is disconnected - + OSSet *attachedHIDPointerDevices {nullptr}; + + IONotifier *usb_hid_publish_notify {nullptr}; // Notification when an USB mouse HID device is connected + IONotifier *usb_hid_terminate_notify {nullptr}; // Notification when an USB mouse HID device is disconnected + + IONotifier *bluetooth_hid_publish_notify {nullptr}; // Notification when a bluetooth HID device is connected + IONotifier *bluetooth_hid_terminate_notify {nullptr}; // Notification when a bluetooth HID device is disconnected + virtual PS2InterruptResult interruptOccurred(UInt8 data); virtual void packetReady(); virtual void setDevicePowerState(UInt32 whatToDo); - + bool handleOpen(IOService *forClient, IOOptionBits options, void *arg) override; void handleClose(IOService *forClient, IOOptionBits options) override; - - void setParamPropertiesGated(OSDictionary* dict); - void injectVersionDependentProperties(OSDictionary* dict); + + void setParamPropertiesGated(OSDictionary *dict); + void injectVersionDependentProperties(OSDictionary *dict); void registerHIDPointerNotifications(); void unregisterHIDPointerNotifications(); - - void notificationHIDAttachedHandlerGated(IOService * newService, IONotifier * notifier); - bool notificationHIDAttachedHandler(void * refCon, IOService * newService, IONotifier * notifier); - + + void notificationHIDAttachedHandlerGated(IOService *newService, IONotifier *notifier); + bool notificationHIDAttachedHandler(void *refCon, IOService *newService, IONotifier *notifier); + elantech_data etd {}; elantech_device_info info {}; int elantechDetect(); @@ -307,7 +304,7 @@ class EXPORT ApplePS2Elan : public IOHIPointing void sendTouchData(); void resetMouse(); void setTouchPadEnable(bool enable); - + static MT2FingerType GetBestFingerType(int i); template @@ -319,30 +316,29 @@ class EXPORT ApplePS2Elan : public IOHIPointing int synaptics_send_cmd(unsigned char c, unsigned char *param); template int elantech_send_cmd(unsigned char c, unsigned char *param); + template + int send_cmd(unsigned char c, unsigned char *param); + bool elantech_is_signature_valid(const unsigned char *param); static unsigned int elantech_convert_res(unsigned int val); int elantech_get_resolution_v4(unsigned int *x_res, unsigned int *y_res, unsigned int *bus); - - template - int send_cmd(unsigned char c, unsigned char *param); - - bool elantech_is_buttonpad() - { + + bool elantech_is_buttonpad() { return (info.fw_version & 0x001000) != 0; } - + public: - bool init(OSDictionary* properties) override; - ApplePS2Elan* probe(IOService* provider, SInt32 * score) override; - bool start(IOService* provider) override; - void stop(IOService* provider) override; - + bool init(OSDictionary *properties) override; + ApplePS2Elan *probe(IOService *provider, SInt32 *score) override; + bool start(IOService *provider) override; + void stop(IOService *provider) override; + UInt32 deviceType() override; UInt32 interfaceID() override; IOReturn setParamProperties(OSDictionary* dict) override; IOReturn setProperties(OSObject *props) override; - + // IOReturn message(UInt32 type, IOService* provider, void* argument) override; }; From f33953485227d59ca1be25c0b920c9b7687df1ea Mon Sep 17 00:00:00 2001 From: Le Bao Hiep Date: Tue, 15 Sep 2020 18:34:45 +0700 Subject: [PATCH 19/40] Update credits --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 3afb87c4..56fb1da1 100644 --- a/README.md +++ b/README.md @@ -58,7 +58,7 @@ In addition, for 2-in-1 systems that do not support disabling the keyboard in ha * Magic Trackpad 2 reverse engineering and implementation – https://github.com/alexandred/VoodooI2C project team. * VoodooPS2Trackpad integration – @kprinssu. * Force Touch emulation and finger renumbering algorithm** – @usr-sse2. -* Elan driver – @BAndysc and @hieplpvip +* Elan touchpad driver – @BAndysc and @hieplpvip \* On my touchpad this gesture was practically impossible to perform with the old VoodooPS2Trackpad. Now it works well. \*\* Due to the limitations of PS/2 bus, Synaptics touchpad reports only the number of fingers and coordinates of two of them to the computer. When there are two fingers on the touchpad and third finger is added, a 'jump' may happen, because the coordinates of one of the fingers are replaced with the coordinates of the added finger. Finger renumbering algorithm estimates the distance from old coordinates to new ones in order to hide this 'jump' from the OS ~~and to calculate approximate position of the 'hidden' finger, in assumption that fingers move together in parallel to each other~~. Now third and fourth fingers are reported at the same position as one of the first two fingers. It allows Launchpad/Show desktop gesture to work more reliably. From 1468814779788237c80beeb9b26d3d2ba5a9bf39 Mon Sep 17 00:00:00 2001 From: Le Bao Hiep Date: Tue, 15 Sep 2020 18:49:48 +0700 Subject: [PATCH 20/40] Handle messages from keyboard --- VoodooPS2Trackpad/VoodooPS2Elan.cpp | 81 ++++++++++++++++++- VoodooPS2Trackpad/VoodooPS2Elan.h | 5 +- .../VoodooPS2Trackpad-Info.plist | 2 + 3 files changed, 83 insertions(+), 5 deletions(-) diff --git a/VoodooPS2Trackpad/VoodooPS2Elan.cpp b/VoodooPS2Trackpad/VoodooPS2Elan.cpp index c2f250f8..8b4f9040 100644 --- a/VoodooPS2Trackpad/VoodooPS2Elan.cpp +++ b/VoodooPS2Trackpad/VoodooPS2Elan.cpp @@ -367,7 +367,9 @@ void ApplePS2Elan::setParamPropertiesGated(OSDictionary *config) { {"USBMouseStopsTrackpad", &usb_mouse_stops_trackpad}, }; - const struct {const char *name; uint64_t *var;} int64vars[] = {}; + const struct {const char *name; uint64_t *var;} int64vars[] = { + {"QuietTimeAfterTyping", &maxaftertyping}, + }; OSBoolean *bl; OSNumber *num; @@ -439,6 +441,62 @@ IOReturn ApplePS2Elan::setProperties(OSObject *props) { return super::setProperties(props); } +IOReturn ApplePS2Elan::message(UInt32 type, IOService* provider, void* argument) { + // Here is where we receive messages from the keyboard driver + // + // This allows for the keyboard driver to enable/disable the trackpad + // when a certain keycode is pressed. + // + // It also allows the trackpad driver to learn the last time a key + // has been pressed, so it can implement various "ignore trackpad + // input while typing" options. + switch (type) { + case kPS2M_getDisableTouchpad: + { + bool* pResult = (bool*)argument; + *pResult = !ignoreall; + break; + } + + case kPS2M_setDisableTouchpad: + { + bool enable = *((bool*)argument); + ignoreall = !enable; + break; + } + + case kPS2M_resetTouchpad: + { + int *reqCode = (int*)argument; + IOLog("VoodooPS2Elan::kPS2M_resetTouchpad reqCode: %d\n", *reqCode); + if (*reqCode == 1) { + setTouchPadEnable(false); + IOSleep(wakedelay); + + ignoreall = false; + _packetByteCount = 0; + _ringBuffer.reset(); + + resetMouse(); + elantechSetupPS2(); + setTouchPadEnable(true); + } + break; + } + + case kPS2M_notifyKeyPressed: + { + // just remember last time key pressed... this can be used in + // interrupt handler to detect unintended input while typing + PS2KeyInfo* pInfo = (PS2KeyInfo*)argument; + keytime = pInfo->time; + break; + } + } + + return kIOReturnSuccess; +} + void ApplePS2Elan::setDevicePowerState(UInt32 whatToDo) { switch (whatToDo) { case kPS2C_DisableDevice: @@ -1549,8 +1607,9 @@ void ApplePS2Elan::processPacketStatusV4() { // if count > 0, we wait for HEAD packets to report so that we report all fingers at once. // if count == 0, we have to report the fact fingers are taken off, because there won't be any HEAD packets - if (count == 0) + if (count == 0) { sendTouchData(); + } } void ApplePS2Elan::processPacketHeadV4() { @@ -1651,6 +1710,13 @@ MT2FingerType ApplePS2Elan::GetBestFingerType(int i) { void ApplePS2Elan::sendTouchData() { AbsoluteTime timestamp; clock_get_uptime(×tamp); + uint64_t timestamp_ns; + absolutetime_to_nanoseconds(timestamp, ×tamp_ns); + + // Ignore input for specified time after keyboard usage + if (timestamp_ns - keytime < maxaftertyping) { + return; + } bool is_buttonpad = elantech_is_buttonpad(); @@ -1757,6 +1823,11 @@ void ApplePS2Elan::packetReady() { INTERRUPT_LOG("VoodooPS2Elan: packet ready occurred\n"); // empty the ring buffer, dispatching each packet... while (_ringBuffer.count() >= kPacketLength) { + if (ignoreall) { + _ringBuffer.advanceTail(kPacketLength); + continue; + } + int packetType; switch (info.hw_version) { case 1: @@ -1779,10 +1850,12 @@ void ApplePS2Elan::packetReady() { break; case PACKET_TRACKPOINT: + INTERRUPT_LOG("VoodooPS2Elan: Handling trackpoint packet\n"); elantechReportTrackpoint(); break; default: + INTERRUPT_LOG("VoodooPS2Elan: Handling absolute mode\n"); elantechReportAbsoluteV3(packetType); break; } @@ -1794,11 +1867,11 @@ void ApplePS2Elan::packetReady() { switch (packetType) { case PACKET_UNKNOWN: - INTERRUPT_LOG("VoodooPS2Elan: Handling unknown mode\n"); + INTERRUPT_LOG("VoodooPS2Elan: invalid packet received\n"); break; case PACKET_TRACKPOINT: - INTERRUPT_LOG("VoodooPS2Elan: Handling trackpoint mode\n"); + INTERRUPT_LOG("VoodooPS2Elan: Handling trackpoint packet\n"); elantechReportTrackpoint(); break; diff --git a/VoodooPS2Trackpad/VoodooPS2Elan.h b/VoodooPS2Trackpad/VoodooPS2Elan.h index 1a779796..560b6b2c 100644 --- a/VoodooPS2Trackpad/VoodooPS2Elan.h +++ b/VoodooPS2Trackpad/VoodooPS2Elan.h @@ -259,6 +259,9 @@ class EXPORT ApplePS2Elan : public IOHIPointing { int _processusbmouse {true}; int _processbluetoothmouse {true}; + uint64_t keytime {0}; + uint64_t maxaftertyping {500000000}; + OSSet *attachedHIDPointerDevices {nullptr}; IONotifier *usb_hid_publish_notify {nullptr}; // Notification when an USB mouse HID device is connected @@ -339,7 +342,7 @@ class EXPORT ApplePS2Elan : public IOHIPointing { IOReturn setParamProperties(OSDictionary* dict) override; IOReturn setProperties(OSObject *props) override; -// IOReturn message(UInt32 type, IOService* provider, void* argument) override; + IOReturn message(UInt32 type, IOService* provider, void* argument) override; }; #endif /* _ApplePS2Elan_H */ diff --git a/VoodooPS2Trackpad/VoodooPS2Trackpad-Info.plist b/VoodooPS2Trackpad/VoodooPS2Trackpad-Info.plist index 64d8ac91..232c9953 100644 --- a/VoodooPS2Trackpad/VoodooPS2Trackpad-Info.plist +++ b/VoodooPS2Trackpad/VoodooPS2Trackpad-Info.plist @@ -138,6 +138,8 @@ ProcessUSBMouseStopsTrackpad + QuietTimeAfterTyping + 500000000 ScrollResolution 400 USBMouseStopsTrackpad From 3341680285ebd6f73447bd1034521dff7ade6650 Mon Sep 17 00:00:00 2001 From: Le Bao Hiep Date: Tue, 15 Sep 2020 19:47:16 +0700 Subject: [PATCH 21/40] Force Touch emulation --- README.md | 2 + VoodooPS2Trackpad/VoodooPS2Elan.cpp | 83 ++++++++----------- VoodooPS2Trackpad/VoodooPS2Elan.h | 14 +++- .../VoodooPS2Trackpad-Info.plist | 22 ++--- 4 files changed, 62 insertions(+), 59 deletions(-) diff --git a/README.md b/README.md index 56fb1da1..ef6d435f 100644 --- a/README.md +++ b/README.md @@ -32,6 +32,8 @@ In addition this kext supports **Force Touch** emulation (*configured in `Info.p * **Mode 4** (*by @Tarik02*) – pressure is passed to the system using the following formula: ![formula](Docs/force_touch.png) The parameters in the formula are configured using `ForceTouchCustomUpThreshold`, `ForceTouchCustomDownThreshold` and `ForceTouchCustomPower` keys in `Info.plist` or configuration SSDT. Note that `ForceTouchCustomDownThreshold` is the *upper* limit on the pressure value and vice versa, because it corresponds to the touchpad being fully pressed *down*. +For Elan touchpad, only mode 0 and mode 1 are supported. + ## Installation and compilation For native brightness keys discovery, `Lilu` is required to probe graphics devices. diff --git a/VoodooPS2Trackpad/VoodooPS2Elan.cpp b/VoodooPS2Trackpad/VoodooPS2Elan.cpp index 8b4f9040..b0cc95b1 100644 --- a/VoodooPS2Trackpad/VoodooPS2Elan.cpp +++ b/VoodooPS2Trackpad/VoodooPS2Elan.cpp @@ -355,12 +355,13 @@ void ApplePS2Elan::setParamPropertiesGated(OSDictionary *config) { {"TrackpointDividerY", &_trackpointDividerY}, {"MouseResolution", &_mouseResolution}, {"MouseSampleRate", &_mouseSampleRate}, + {"ForceTouchMode", (int*)&_forceTouchMode}, }; const struct {const char *name; int *var;} boolvars[] = { {"ProcessUSBMouseStopsTrackpad", &_processusbmouse}, {"ProcessBluetoothMouseStopsTrackpad", &_processbluetoothmouse}, - {"SetHwResolution", &_set_hw_resolution} + {"SetHwResolution", &_set_hw_resolution}, }; const struct {const char *name; bool *var;} lowbitvars[] = { @@ -1641,8 +1642,8 @@ void ApplePS2Elan::processPacketHeadV4() { virtualFinger[id].button = (packet[0] & 1); virtualFinger[id].prev = virtualFinger[id].now; - virtualFinger[id].now.pressure = pres; - virtualFinger[id].now.width = traces; + virtualFinger[id].pressure = pres; + virtualFinger[id].width = traces; virtualFinger[id].now.x = x; virtualFinger[id].now.y = y; @@ -1718,43 +1719,51 @@ void ApplePS2Elan::sendTouchData() { return; } - bool is_buttonpad = elantech_is_buttonpad(); - static_assert(VOODOO_INPUT_MAX_TRANSDUCERS >= ETP_MAX_FINGERS, "Trackpad supports too many fingers"); - int count = 0; + int transducers_count = 0; for (int i = 0; i < ETP_MAX_FINGERS; i++) { - if (!virtualFinger[i].touch) { + const auto& state = virtualFinger[i]; + if (!state.touch) { continue; } - inputEvent.transducers[count].currentCoordinates = virtualFinger[i].now; - inputEvent.transducers[count].previousCoordinates = virtualFinger[i].prev; + auto& transducer = inputEvent.transducers[transducers_count++]; - inputEvent.transducers[count].isValid = true; - inputEvent.transducers[count].isPhysicalButtonDown = is_buttonpad && virtualFinger[i].button; - inputEvent.transducers[count].isTransducerActive = true; + transducer.currentCoordinates = state.now; + transducer.previousCoordinates = state.prev; + transducer.timestamp = timestamp; - inputEvent.transducers[count].secondaryId = count; - inputEvent.transducers[count].fingerType = GetBestFingerType(count); - inputEvent.transducers[count].type = FINGER; + transducer.isValid = true; + transducer.isTransducerActive = true; - // it looks like Elan PS2 pressure and width is very inaccurate - // it is better to leave it that way - inputEvent.transducers[count].supportsPressure = false; + transducer.secondaryId = i; //transducers_count + transducer.fingerType = GetBestFingerType(transducers_count); + transducer.type = FINGER; - inputEvent.transducers[count].timestamp = timestamp; + switch (_forceTouchMode) { + case FORCE_TOUCH_BUTTON: // Physical button is translated into force touch instead of click + transducer.isPhysicalButtonDown = false; + transducer.supportsPressure = true; + transducer.currentCoordinates.pressure = state.button ? 255 : 0; + transducer.currentCoordinates.width = 20; + break; - count++; + case FORCE_TOUCH_DISABLED: + default: + transducer.isPhysicalButtonDown = state.button; + transducer.supportsPressure = false; + break; + } } // set the thumb to improve 4F pinch and spread gesture - if (count == 4) { + if (transducers_count == 4) { // simple thumb detection: to find the lowest finger touch. UInt32 y_min = info.y_max / 2; int thumb_index = 0; int currentThumbIndex = 0; - for (int i = 0; i < count; i++) { + for (int i = 0; i < transducers_count; i++) { if (inputEvent.transducers[i].currentCoordinates.y > y_min) { y_min = inputEvent.transducers[i].currentCoordinates.y; thumb_index = i; @@ -1767,42 +1776,22 @@ void ApplePS2Elan::sendTouchData() { inputEvent.transducers[thumb_index].fingerType = kMT2FingerTypeThumb; } - for (int i = count; i < VOODOO_INPUT_MAX_TRANSDUCERS; i++) { + for (int i = transducers_count; i < VOODOO_INPUT_MAX_TRANSDUCERS; i++) { inputEvent.transducers[i].isValid = false; inputEvent.transducers[i].isPhysicalButtonDown = false; inputEvent.transducers[i].isTransducerActive = false; } - inputEvent.contact_count = count; + inputEvent.contact_count = transducers_count; inputEvent.timestamp = timestamp; if (voodooInputInstance) { super::messageClient(kIOMessageVoodooInputMessage, voodooInputInstance, &inputEvent, sizeof(VoodooInputEvent)); } - if (!is_buttonpad) { - if (inputEvent.contact_count == 0) { - UInt32 buttons = leftButton | rightButton; - dispatchRelativePointerEvent(0, 0, buttons, timestamp); - } else { - UInt32 buttons = 0; - bool send = false; - if (lastLeftButton != leftButton) { - buttons |= leftButton; - send = true; - } - if (lastRightButton != rightButton) { - buttons |= rightButton; - send = true; - } - if (send) { - dispatchRelativePointerEvent(0, 0, buttons, timestamp); - } - } - - lastLeftButton = leftButton; - lastRightButton = rightButton; - //lastMiddleButton = middleButton; + if (!elantech_is_buttonpad() && inputEvent.contact_count == 0) { + UInt32 buttons = leftButton | rightButton; + dispatchRelativePointerEvent(0, 0, buttons, timestamp); } } diff --git a/VoodooPS2Trackpad/VoodooPS2Elan.h b/VoodooPS2Trackpad/VoodooPS2Elan.h index 560b6b2c..d1353655 100644 --- a/VoodooPS2Trackpad/VoodooPS2Elan.h +++ b/VoodooPS2Trackpad/VoodooPS2Elan.h @@ -25,11 +25,21 @@ struct virtual_finger_state { TouchCoordinates prev; TouchCoordinates now; + uint8_t pressure; + uint8_t width; bool touch; bool button; MT2FingerType fingerType; }; +typedef enum { + FORCE_TOUCH_DISABLED = 0, + FORCE_TOUCH_BUTTON = 1, + FORCE_TOUCH_THRESHOLD = 2, + FORCE_TOUCH_VALUE = 3, + FORCE_TOUCH_CUSTOM = 4 +} ForceTouchMode; + #define kPacketLength 6 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -228,8 +238,6 @@ class EXPORT ApplePS2Elan : public IOHIPointing { // when trackpad has physical button UInt32 leftButton = 0; UInt32 rightButton = 0; - UInt32 lastLeftButton = 0; - UInt32 lastRightButton = 0; UInt32 lastFingersV3 = 0; @@ -241,6 +249,8 @@ class EXPORT ApplePS2Elan : public IOHIPointing { static_assert(ETP_MAX_FINGERS <= kMT2FingerTypeLittleFinger, "Too many fingers for one hand"); + ForceTouchMode _forceTouchMode {FORCE_TOUCH_BUTTON}; + int _scrollresolution {2300}; int wakedelay {1000}; int _trackpointMultiplierX {200}; diff --git a/VoodooPS2Trackpad/VoodooPS2Trackpad-Info.plist b/VoodooPS2Trackpad/VoodooPS2Trackpad-Info.plist index 232c9953..05abf0f2 100644 --- a/VoodooPS2Trackpad/VoodooPS2Trackpad-Info.plist +++ b/VoodooPS2Trackpad/VoodooPS2Trackpad-Info.plist @@ -99,16 +99,6 @@ Default - SetHwResolution - - MouseResolution - 3 - MouseSampleRate - 200 - TrackpointMultiplierY - 120 - TrackpointMultiplierX - 120 ButtonCount 3 Darwin 16+ @@ -134,6 +124,12 @@ DisableDevice + ForceTouchMode + 1 + MouseResolution + 3 + MouseSampleRate + 200 ProcessBluetoothMouseStopsTrackpad ProcessUSBMouseStopsTrackpad @@ -142,6 +138,12 @@ 500000000 ScrollResolution 400 + SetHwResolution + + TrackpointMultiplierX + 120 + TrackpointMultiplierY + 120 USBMouseStopsTrackpad 0 UseHighRate From eb52949d5e3565600912632af69f0e1ce77be54b Mon Sep 17 00:00:00 2001 From: Le Bao Hiep Date: Tue, 15 Sep 2020 19:47:48 +0700 Subject: [PATCH 22/40] Update README --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index ef6d435f..4413300c 100644 --- a/README.md +++ b/README.md @@ -63,5 +63,7 @@ In addition, for 2-in-1 systems that do not support disabling the keyboard in ha * Elan touchpad driver – @BAndysc and @hieplpvip \* On my touchpad this gesture was practically impossible to perform with the old VoodooPS2Trackpad. Now it works well. + \*\* Due to the limitations of PS/2 bus, Synaptics touchpad reports only the number of fingers and coordinates of two of them to the computer. When there are two fingers on the touchpad and third finger is added, a 'jump' may happen, because the coordinates of one of the fingers are replaced with the coordinates of the added finger. Finger renumbering algorithm estimates the distance from old coordinates to new ones in order to hide this 'jump' from the OS ~~and to calculate approximate position of the 'hidden' finger, in assumption that fingers move together in parallel to each other~~. Now third and fourth fingers are reported at the same position as one of the first two fingers. It allows Launchpad/Show desktop gesture to work more reliably. + \*\*\* The touchpad reports both finger width (ranged from 4 to 15) and pressure (ranged from 0 to 255), but in practice the measured width is almost always 4, and the reported pressure depends more on actual touch width than on actual pressure. From f53b818ccf26b53bb93c38897624397245a4fb42 Mon Sep 17 00:00:00 2001 From: Le Bao Hiep Date: Tue, 15 Sep 2020 19:54:00 +0700 Subject: [PATCH 23/40] Enable SetHwResolution by default --- VoodooPS2Trackpad/VoodooPS2Trackpad-Info.plist | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VoodooPS2Trackpad/VoodooPS2Trackpad-Info.plist b/VoodooPS2Trackpad/VoodooPS2Trackpad-Info.plist index 05abf0f2..e76c7cff 100644 --- a/VoodooPS2Trackpad/VoodooPS2Trackpad-Info.plist +++ b/VoodooPS2Trackpad/VoodooPS2Trackpad-Info.plist @@ -139,7 +139,7 @@ ScrollResolution 400 SetHwResolution - + TrackpointMultiplierX 120 TrackpointMultiplierY From 03eab8bcda9f3cbe391e732c0df488d4ca02facd Mon Sep 17 00:00:00 2001 From: Le Bao Hiep Date: Tue, 15 Sep 2020 20:03:28 +0700 Subject: [PATCH 24/40] Fix typo --- VoodooPS2Controller.xcodeproj/project.pbxproj | 2 +- VoodooPS2Trackpad/VoodooPS2Elan.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/VoodooPS2Controller.xcodeproj/project.pbxproj b/VoodooPS2Controller.xcodeproj/project.pbxproj index c8b00c12..130ff3e7 100644 --- a/VoodooPS2Controller.xcodeproj/project.pbxproj +++ b/VoodooPS2Controller.xcodeproj/project.pbxproj @@ -302,8 +302,8 @@ 356B895D23007F1A0042F30F /* VoodooInput Headers */, 84833FAC161B62A900845294 /* VoodooPS2ALPSGlidePoint.h */, 84833FAB161B62A900845294 /* VoodooPS2ALPSGlidePoint.cpp */, - 9828A92D24A2B6C200550FAA /* VoodooPS2Elan.cpp */, 9828A92E24A2B6C200550FAA /* VoodooPS2Elan.h */, + 9828A92D24A2B6C200550FAA /* VoodooPS2Elan.cpp */, 84833FAE161B62A900845294 /* VoodooPS2SentelicFSP.h */, 84833FAD161B62A900845294 /* VoodooPS2SentelicFSP.cpp */, 84833FB0161B62A900845294 /* VoodooPS2SynapticsTouchPad.h */, diff --git a/VoodooPS2Trackpad/VoodooPS2Elan.cpp b/VoodooPS2Trackpad/VoodooPS2Elan.cpp index b0cc95b1..2e95a51d 100644 --- a/VoodooPS2Trackpad/VoodooPS2Elan.cpp +++ b/VoodooPS2Trackpad/VoodooPS2Elan.cpp @@ -878,7 +878,7 @@ int ApplePS2Elan::elantechQueryInfo() { return -1; } - IOLog("VoodooPS2Elan: Synaptics capabilities query result 0x%02x, 0x%02x, 0x%02x.\n", + IOLog("VoodooPS2Elan: Elan capabilities query result 0x%02x, 0x%02x, 0x%02x.\n", info.capabilities[0], info.capabilities[1], info.capabilities[2]); From 035d962c10eea771ebb7516a32b160b84f701cbe Mon Sep 17 00:00:00 2001 From: Le Bao Hiep Date: Tue, 15 Sep 2020 23:28:46 +0700 Subject: [PATCH 25/40] Linting + cleanup --- VoodooPS2Trackpad/VoodooPS2Elan.cpp | 58 +++++++++++++---------------- VoodooPS2Trackpad/VoodooPS2Elan.h | 8 ++-- 2 files changed, 29 insertions(+), 37 deletions(-) diff --git a/VoodooPS2Trackpad/VoodooPS2Elan.cpp b/VoodooPS2Trackpad/VoodooPS2Elan.cpp index 2e95a51d..bcbf177f 100644 --- a/VoodooPS2Trackpad/VoodooPS2Elan.cpp +++ b/VoodooPS2Trackpad/VoodooPS2Elan.cpp @@ -10,18 +10,12 @@ // generally one cannot IOLog from interrupt context, it eventually leads to kernel panic // but it is useful sometimes -#ifdef PACKET_DEBUG +#if 0 #define INTERRUPT_LOG(args...) do { IOLog(args); } while (0) #else #define INTERRUPT_LOG(args...) do { } while (0) #endif -// enable for trackpad debugging -#ifdef DEBUG_MSG -#define DEBUG_VERBOSE -//#define PACKET_DEBUG -#endif - #include "LegacyIOService.h" #pragma clang diagnostic push @@ -279,7 +273,7 @@ bool ApplePS2Elan::start(IOService *provider) { // Install our driver's interrupt handler, for asynchronous data delivery. _device->installInterruptAction(this, - OSMemberFunctionCast(PS2InterruptAction,this,&ApplePS2Elan::interruptOccurred), + OSMemberFunctionCast(PS2InterruptAction, this, &ApplePS2Elan::interruptOccurred), OSMemberFunctionCast(PS2PacketAction, this, &ApplePS2Elan::packetReady)); _interruptHandlerInstalled = true; @@ -398,7 +392,7 @@ void ApplePS2Elan::setParamPropertiesGated(OSDictionary *config) { // 32-bit config items for (int i = 0; i < countof(int32vars); i++) { - if ((num = OSDynamicCast(OSNumber,config->getObject(int32vars[i].name)))) { + if ((num = OSDynamicCast(OSNumber, config->getObject(int32vars[i].name)))) { *int32vars[i].var = num->unsigned32BitValue(); setProperty(int32vars[i].name, *int32vars[i].var, 32); } @@ -410,7 +404,7 @@ void ApplePS2Elan::setParamPropertiesGated(OSDictionary *config) { *lowbitvars[i].var = (num->unsigned32BitValue() & 0x1) ? true : false; setProperty(lowbitvars[i].name, *lowbitvars[i].var ? 1 : 0, 32); } else if ((bl = OSDynamicCast(OSBoolean, config->getObject(lowbitvars[i].name)))) { - //REVIEW: are these items ever carried in a boolean? + // REVIEW: are these items ever carried in a boolean? *lowbitvars[i].var = bl->isTrue(); setProperty(lowbitvars[i].name, *lowbitvars[i].var ? kOSBooleanTrue : kOSBooleanFalse); } @@ -597,16 +591,14 @@ void ApplePS2Elan::notificationHIDAttachedHandlerGated(IOService *newService, IO OSNumber *propDeviceClass = OSDynamicCast(OSNumber, newService->getProperty("ClassOfDevice")); if (propDeviceClass != NULL) { + UInt32 classOfDevice = propDeviceClass->unsigned32BitValue(); - long classOfDevice = propDeviceClass->unsigned32BitValue(); - - long deviceClassMajor = (classOfDevice & 0x1F00) >> 8; - long deviceClassMinor = (classOfDevice & 0xFF) >> 2; + UInt32 deviceClassMajor = (classOfDevice & 0x1F00) >> 8; + UInt32 deviceClassMinor = (classOfDevice & 0xFF) >> 2; if (deviceClassMajor == kBluetoothDeviceClassMajorPeripheral) { // Bluetooth peripheral devices - - long deviceClassMinor1 = (deviceClassMinor) & 0x30; - long deviceClassMinor2 = (deviceClassMinor) & 0x0F; + UInt32 deviceClassMinor1 = (deviceClassMinor) & 0x30; + UInt32 deviceClassMinor2 = (deviceClassMinor) & 0x0F; if (deviceClassMinor1 == kBluetoothDeviceClassMinorPeripheral1Pointing || // Seperate pointing device deviceClassMinor1 == kBluetoothDeviceClassMinorPeripheral1Combo) // Combo bluetooth keyboard/touchpad @@ -644,7 +636,7 @@ void ApplePS2Elan::notificationHIDAttachedHandlerGated(IOService *newService, IO } bool ApplePS2Elan::notificationHIDAttachedHandler(void *refCon, IOService *newService, IONotifier *notifier) { - if (_cmdGate) { // defensive + if (_cmdGate) { _cmdGate->runAction(OSMemberFunctionCast(IOCommandGate::Action, this, &ApplePS2Elan::notificationHIDAttachedHandlerGated), newService, notifier); } @@ -781,7 +773,7 @@ bool ApplePS2Elan::elantech_is_signature_valid(const unsigned char *param) { return true; } - for (int i = 0; i < sizeof(rates)/sizeof(*rates); i++) { + for (int i = 0; i < sizeof(rates) / sizeof(*rates); i++) { if (param[2] == rates[i]) { return false; } @@ -991,10 +983,8 @@ int ApplePS2Elan::elantechQueryInfo() { break; } - /* check for the middle button: DMI matching or new v4 firmwares */ - //info.has_middle_button = dmi_check_system(elantech_dmi_has_middle_button) || - // (ETP_NEW_IC_SMBUS_HOST_NOTIFY(info.fw_version) && - // !elantech_is_buttonpad(info)); + // check for the middle button + info.has_middle_button = (ETP_NEW_IC_SMBUS_HOST_NOTIFY(info.fw_version) && !elantech_is_buttonpad()); return 0; } @@ -1048,7 +1038,7 @@ int ApplePS2Elan::elantechSetProperties() { info.crc_enabled = (info.fw_version & 0x4000) == 0x4000; // Enable real hardware resolution on hw_version 3 ? - info.set_hw_resolution = _set_hw_resolution;//!dmi_check_system(no_hw_res_dmi_table); + info.set_hw_resolution = _set_hw_resolution; return 0; } @@ -1166,10 +1156,12 @@ int ApplePS2Elan::elantechSetupPS2() { return -1; } + /* if (info.fw_version == 0x381f17) { - //etd.original_set_rate = psmouse->set_rate; - //psmouse->set_rate = elantech_set_rate_restore_reg_07; + etd.original_set_rate = psmouse->set_rate; + psmouse->set_rate = elantech_set_rate_restore_reg_07; } + */ if (elantechSetInputParams()) { IOLog("VoodooPS2: failed to query touchpad range.\n"); @@ -1223,10 +1215,10 @@ int ApplePS2Elan::elantechReadReg(unsigned char reg, unsigned char *val) { break; case 2: - if (elantech_ps2_command<0>( NULL, ETP_PS2_CUSTOM_COMMAND) || - elantech_ps2_command<0>( NULL, ETP_REGISTER_READ) || - elantech_ps2_command<0>( NULL, ETP_PS2_CUSTOM_COMMAND) || - elantech_ps2_command<0>( NULL, reg) || + if (elantech_ps2_command<0>(NULL, ETP_PS2_CUSTOM_COMMAND) || + elantech_ps2_command<0>(NULL, ETP_REGISTER_READ) || + elantech_ps2_command<0>(NULL, ETP_PS2_CUSTOM_COMMAND) || + elantech_ps2_command<0>(NULL, reg) || elantech_ps2_command<3>(param, kDP_GetMouseInformation)) { rc = -1; } @@ -1369,7 +1361,7 @@ int ApplePS2Elan::elantechPacketCheckV4() { unsigned int ic_version; bool sanity_check; - INTERRUPT_LOG("VoodooPS2Elan: Packet dump (%04x, %04x, %04x, %04x, %04x, %04x)\n", packet[0], packet[1], packet[2], packet[3], packet[4], packet[5] ); + INTERRUPT_LOG("VoodooPS2Elan: Packet dump (%04x, %04x, %04x, %04x, %04x, %04x)\n", packet[0], packet[1], packet[2], packet[3], packet[4], packet[5]); if (info.has_trackpoint && (packet[3] & 0x0f) == 0x06) { return PACKET_TRACKPOINT; @@ -1737,7 +1729,7 @@ void ApplePS2Elan::sendTouchData() { transducer.isValid = true; transducer.isTransducerActive = true; - transducer.secondaryId = i; //transducers_count + transducer.secondaryId = i; transducer.fingerType = GetBestFingerType(transducers_count); transducer.type = FINGER; @@ -1759,7 +1751,7 @@ void ApplePS2Elan::sendTouchData() { // set the thumb to improve 4F pinch and spread gesture if (transducers_count == 4) { - // simple thumb detection: to find the lowest finger touch. + // simple thumb detection: find the lowest finger touch UInt32 y_min = info.y_max / 2; int thumb_index = 0; int currentThumbIndex = 0; diff --git a/VoodooPS2Trackpad/VoodooPS2Elan.h b/VoodooPS2Trackpad/VoodooPS2Elan.h index d1353655..9590a0ad 100644 --- a/VoodooPS2Trackpad/VoodooPS2Elan.h +++ b/VoodooPS2Trackpad/VoodooPS2Elan.h @@ -274,11 +274,11 @@ class EXPORT ApplePS2Elan : public IOHIPointing { OSSet *attachedHIDPointerDevices {nullptr}; - IONotifier *usb_hid_publish_notify {nullptr}; // Notification when an USB mouse HID device is connected - IONotifier *usb_hid_terminate_notify {nullptr}; // Notification when an USB mouse HID device is disconnected + IONotifier *usb_hid_publish_notify {nullptr}; // Notification when an USB mouse HID device is connected + IONotifier *usb_hid_terminate_notify {nullptr}; // Notification when an USB mouse HID device is disconnected - IONotifier *bluetooth_hid_publish_notify {nullptr}; // Notification when a bluetooth HID device is connected - IONotifier *bluetooth_hid_terminate_notify {nullptr}; // Notification when a bluetooth HID device is disconnected + IONotifier *bluetooth_hid_publish_notify {nullptr}; // Notification when a bluetooth HID device is connected + IONotifier *bluetooth_hid_terminate_notify {nullptr}; // Notification when a bluetooth HID device is disconnected virtual PS2InterruptResult interruptOccurred(UInt8 data); virtual void packetReady(); From 81d72b474475958c4673769f102696971415f6ea Mon Sep 17 00:00:00 2001 From: Le Bao Hiep Date: Wed, 16 Sep 2020 02:49:49 +0700 Subject: [PATCH 26/40] Implement hardware v2 support --- VoodooPS2Trackpad/VoodooPS2Elan.cpp | 178 ++++++++++++++++++++++++++-- VoodooPS2Trackpad/VoodooPS2Elan.h | 5 +- 2 files changed, 174 insertions(+), 9 deletions(-) diff --git a/VoodooPS2Trackpad/VoodooPS2Elan.cpp b/VoodooPS2Trackpad/VoodooPS2Elan.cpp index bcbf177f..ca248aa5 100644 --- a/VoodooPS2Trackpad/VoodooPS2Elan.cpp +++ b/VoodooPS2Trackpad/VoodooPS2Elan.cpp @@ -176,8 +176,8 @@ ApplePS2Elan *ApplePS2Elan::probe(IOService *provider, SInt32 *score) { IOLog("VoodooPS2Elan: has_trackpoint: %d\n", info.has_trackpoint); IOLog("VoodooPS2Elan: has_middle_button: %d\n", info.has_middle_button); - if (info.hw_version <= 2) { - IOLog("VoodooPS2Elan: Unsupported ELAN PS2 Touchpad version. Currently only v4 and v3 version is supported. You have: %d\n", info.hw_version); + if (info.hw_version == 1) { + IOLog("VoodooPS2Elan: ELAN PS2 Touchpad v1 is unsupported.\n"); return nullptr; } @@ -1316,6 +1316,43 @@ int ApplePS2Elan::elantechWriteReg(unsigned char reg, unsigned char val) { return rc; } +int ApplePS2Elan::elantechDebounceCheckV2() { + // When we encounter packet that matches this exactly, it means the + // hardware is in debounce status. Just ignore the whole packet. + static const uint8_t debounce_packet[] = { + 0x84, 0xff, 0xff, 0x02, 0xff, 0xff + }; + + unsigned char *packet = _ringBuffer.tail(); + + return !memcmp(packet, debounce_packet, sizeof(debounce_packet)); +} + +int ApplePS2Elan::elantechPacketCheckV2() { + unsigned char *packet = _ringBuffer.tail(); + + // V2 hardware has two flavors. Older ones that do not report pressure, + // and newer ones that reports pressure and width. With newer ones, all + // packets (1, 2, 3 finger touch) have the same constant bits. With + // older ones, 1/3 finger touch packets and 2 finger touch packets + // have different constant bits. + // With all three cases, if the constant bits are not exactly what I + // expected, I consider them invalid. + + if (info.reports_pressure) { + return (packet[0] & 0x0c) == 0x04 && (packet[3] & 0x0f) == 0x02; + } + + if ((packet[0] & 0xc0) == 0x80) { + return (packet[0] & 0x0c) == 0x0c && (packet[3] & 0x0e) == 0x08; + } + + return (packet[0] & 0x3c) == 0x3c && + (packet[1] & 0xf0) == 0x00 && + (packet[3] & 0x3e) == 0x38 && + (packet[4] & 0xf0) == 0x00; +} + int ApplePS2Elan::elantechPacketCheckV3() { static const uint8_t debounce_packet[] = { 0xc4, 0xff, 0xff, 0x02, 0xff, 0xff @@ -1403,6 +1440,116 @@ int ApplePS2Elan::elantechPacketCheckV4() { return PACKET_UNKNOWN; } +void ApplePS2Elan::elantechReportAbsoluteV2() { + unsigned char *packet = _ringBuffer.tail(); + unsigned int fingers = 0, x1 = 0, y1 = 0, x2 = 0, y2 = 0; + unsigned int width = 0, pres = 0; + + // byte 0: n1 n0 . . . . R L + fingers = (packet[0] & 0xc0) >> 6; + + switch (fingers) { + case 3: + case 1: + // byte 1: . . . . x11 x10 x9 x8 + // byte 2: x7 x6 x5 x4 x4 x2 x1 x0 + x1 = ((packet[1] & 0x0f) << 8) | packet[2]; + + // byte 4: . . . . y11 y10 y9 y8 + // byte 5: y7 y6 y5 y4 y3 y2 y1 y0 + y1 = info.y_max - (((packet[4] & 0x0f) << 8) | packet[5]); + + pres = (packet[1] & 0xf0) | ((packet[4] & 0xf0) >> 4); + width = ((packet[0] & 0x30) >> 2) | ((packet[3] & 0x30) >> 4); + break; + + case 2: + // The coordinate of each finger is reported separately + // with a lower resolution for two finger touches: + + // byte 0: . . ay8 ax8 . . . . + // byte 1: ax7 ax6 ax5 ax4 ax3 ax2 ax1 ax0 + x1 = (((packet[0] & 0x10) << 4) | packet[1]) << 2; + + // byte 2: ay7 ay6 ay5 ay4 ay3 ay2 ay1 ay0 + y1 = info.y_max - ((((packet[0] & 0x20) << 3) | packet[2]) << 2); + + // byte 3: . . by8 bx8 . . . . + // byte 4: bx7 bx6 bx5 bx4 bx3 bx2 bx1 bx0 + x2 = (((packet[3] & 0x10) << 4) | packet[4]) << 2; + + // byte 5: by7 by8 by5 by4 by3 by2 by1 by0 + y2 = info.y_max - ((((packet[3] & 0x20) << 3) | packet[5]) << 2); + + // Unknown so just report sensible values + pres = 127; + width = 7; + break; + } + + virtualFinger[0].touch = false; + virtualFinger[1].touch = false; + virtualFinger[2].touch = false; + + leftButton = packet[0] & 0x01; + rightButton = packet[0] & 0x02; + + if (fingers == 1 || fingers == 2) { + virtualFinger[0].touch = true; + virtualFinger[0].button = packet[0] & 0x03; + virtualFinger[0].prev = virtualFinger[0].now; + virtualFinger[0].now.x = x1; + virtualFinger[0].now.y = y1; + if (lastFingers != 1 && lastFingers != 2) { + virtualFinger[0].prev = virtualFinger[0].now; + } + } + + if (fingers == 2) { + virtualFinger[1].touch = true; + virtualFinger[1].button = packet[0] & 0x03; + virtualFinger[1].prev = virtualFinger[1].now; + virtualFinger[1].now.x = x2; + virtualFinger[1].now.y = y2; + if (lastFingers != 2) { + virtualFinger[1].prev = virtualFinger[1].now; + } + } + + if (fingers == 3) { + virtualFinger[0].touch = virtualFinger[1].touch = virtualFinger[2].touch = true; + virtualFinger[0].button = virtualFinger[1].button = virtualFinger[2].button = packet[0] & 0x03; + virtualFinger[0].prev = virtualFinger[0].now; + virtualFinger[1].prev = virtualFinger[1].now; + virtualFinger[2].prev = virtualFinger[2].now; + + float sin30deg = 0.5f; + float cos30deg = 0.86602540378f; + + int h = 100; + int dy = (int)(sin30deg * h); + int dx = (int)(cos30deg * h); + + virtualFinger[0].now.x = x1; + virtualFinger[0].now.y = y1 - h; + + virtualFinger[1].now.x = x1 - dx; + virtualFinger[1].now.y = y1 + dy; + + virtualFinger[2].now.x = x1 + dx; + virtualFinger[2].now.y = y1 + dy; + + if (lastFingers != 3) { + virtualFinger[0].prev = virtualFinger[0].now; + virtualFinger[1].prev = virtualFinger[1].now; + virtualFinger[2].prev = virtualFinger[2].now; + } + } + + lastFingers = fingers; + sendTouchData(); +} + void ApplePS2Elan::elantechReportAbsoluteV3(int packetType) { unsigned char *packet = _ringBuffer.tail(); unsigned int fingers = 0, x1 = 0, y1 = 0, x2 = 0, y2 = 0; @@ -1461,7 +1608,7 @@ void ApplePS2Elan::elantechReportAbsoluteV3(int packetType) { virtualFinger[0].prev = virtualFinger[0].now; virtualFinger[0].now.x = x1; virtualFinger[0].now.y = y1; - if (lastFingersV3 != 1 && lastFingersV3 != 2) { + if (lastFingers != 1 && lastFingers != 2) { virtualFinger[0].prev = virtualFinger[0].now; } } @@ -1472,7 +1619,7 @@ void ApplePS2Elan::elantechReportAbsoluteV3(int packetType) { virtualFinger[1].prev = virtualFinger[1].now; virtualFinger[1].now.x = x2; virtualFinger[1].now.y = y2; - if (lastFingersV3 != 2) { + if (lastFingers != 2) { virtualFinger[1].prev = virtualFinger[1].now; } } @@ -1500,14 +1647,14 @@ void ApplePS2Elan::elantechReportAbsoluteV3(int packetType) { virtualFinger[2].now.x = x1 + dx; virtualFinger[2].now.y = y1 + dy; - if (lastFingersV3 != 3) { + if (lastFingers != 3) { virtualFinger[0].prev = virtualFinger[0].now; virtualFinger[1].prev = virtualFinger[1].now; virtualFinger[2].prev = virtualFinger[2].now; } } - lastFingersV3 = fingers; + lastFingers = fingers; sendTouchData(); } @@ -1812,11 +1959,26 @@ void ApplePS2Elan::packetReady() { int packetType; switch (info.hw_version) { case 1: - case 2: - // V1 and V2 are ancient hardware, not going to implement right away + // V1 is ancient hardware, not going to implement right away INTERRUPT_LOG("VoodooPS2Elan: packet ready occurred, but unsupported version\n"); break; + case 2: + if (elantechDebounceCheckV2()) { + // ignore debounce + break; + } + + if (info.paritycheck && !elantechPacketCheckV2()) { + // ignore invalid packet + INTERRUPT_LOG("VoodooPS2Elan: invalid packet received\n"); + break; + } + + INTERRUPT_LOG("VoodooPS2Elan: Handling absolute mode\n"); + elantechReportAbsoluteV2(); + break; + case 3: packetType = elantechPacketCheckV3(); INTERRUPT_LOG("VoodooPS2Elan: Packet Type %d\n", packetType); diff --git a/VoodooPS2Trackpad/VoodooPS2Elan.h b/VoodooPS2Trackpad/VoodooPS2Elan.h index 9590a0ad..5fdae95f 100644 --- a/VoodooPS2Trackpad/VoodooPS2Elan.h +++ b/VoodooPS2Trackpad/VoodooPS2Elan.h @@ -239,7 +239,7 @@ class EXPORT ApplePS2Elan : public IOHIPointing { UInt32 leftButton = 0; UInt32 rightButton = 0; - UInt32 lastFingersV3 = 0; + UInt32 lastFingers = 0; bool trackpointScrolling {false}; @@ -306,8 +306,11 @@ class EXPORT ApplePS2Elan : public IOHIPointing { int elantechSetupPS2(); int elantechReadReg(unsigned char reg, unsigned char *val); int elantechWriteReg(unsigned char reg, unsigned char val); + int elantechDebounceCheckV2(); + int elantechPacketCheckV2(); int elantechPacketCheckV3(); int elantechPacketCheckV4(); + void elantechReportAbsoluteV2(); void elantechReportAbsoluteV3(int packetType); void elantechReportAbsoluteV4(int packetType); void elantechReportTrackpoint(); From 650f79a24ba4d1d16ef56b425f37ec45bea10533 Mon Sep 17 00:00:00 2001 From: Le Bao Hiep Date: Wed, 16 Sep 2020 03:32:57 +0700 Subject: [PATCH 27/40] Implement hardware v1 support --- VoodooPS2Trackpad/VoodooPS2Elan.cpp | 157 ++++++++++++++++++++++++---- VoodooPS2Trackpad/VoodooPS2Elan.h | 9 +- 2 files changed, 146 insertions(+), 20 deletions(-) diff --git a/VoodooPS2Trackpad/VoodooPS2Elan.cpp b/VoodooPS2Trackpad/VoodooPS2Elan.cpp index ca248aa5..4823be7e 100644 --- a/VoodooPS2Trackpad/VoodooPS2Elan.cpp +++ b/VoodooPS2Trackpad/VoodooPS2Elan.cpp @@ -176,11 +176,6 @@ ApplePS2Elan *ApplePS2Elan::probe(IOService *provider, SInt32 *score) { IOLog("VoodooPS2Elan: has_trackpoint: %d\n", info.has_trackpoint); IOLog("VoodooPS2Elan: has_middle_button: %d\n", info.has_middle_button); - if (info.hw_version == 1) { - IOLog("VoodooPS2Elan: ELAN PS2 Touchpad v1 is unsupported.\n"); - return nullptr; - } - IOLog("VoodooPS2Elan: elan touchpad detected. Probing finished.\n"); _device = nullptr; @@ -1016,6 +1011,9 @@ int ApplePS2Elan::elantechSetProperties() { } } + // Determine packet length (4 for v1, 6 for v2 and newer) + info.packet_length = (info.hw_version == 1) ? 4 : 6; + // Turn on packet checking by default info.paritycheck = 1; @@ -1328,6 +1326,28 @@ int ApplePS2Elan::elantechDebounceCheckV2() { return !memcmp(packet, debounce_packet, sizeof(debounce_packet)); } +int ApplePS2Elan::elantechPacketCheckV1() { + unsigned char *packet = _ringBuffer.tail(); + unsigned char p1, p2, p3; + + // Parity bits are placed differently + if (info.fw_version < 0x020000) { + // byte 0: D U p1 p2 1 p3 R L + p1 = (packet[0] & 0x20) >> 5; + p2 = (packet[0] & 0x10) >> 4; + } else { + // byte 0: n1 n0 p2 p1 1 p3 R L + p1 = (packet[0] & 0x10) >> 4; + p2 = (packet[0] & 0x20) >> 5; + } + + p3 = (packet[0] & 0x04) >> 2; + + return etd.parity[packet[1]] == p1 && + etd.parity[packet[2]] == p2 && + etd.parity[packet[3]] == p3; +} + int ApplePS2Elan::elantechPacketCheckV2() { unsigned char *packet = _ringBuffer.tail(); @@ -1440,6 +1460,107 @@ int ApplePS2Elan::elantechPacketCheckV4() { return PACKET_UNKNOWN; } +void ApplePS2Elan::elantechReportAbsoluteV1() { + unsigned char *packet = _ringBuffer.tail(); + unsigned int fingers = 0, x = 0, y = 0; + + if (info.fw_version < 0x020000) { + // byte 0: D U p1 p2 1 p3 R L + // byte 1: f 0 th tw x9 x8 y9 y8 + fingers = ((packet[1] & 0x80) >> 7) + ((packet[1] & 0x30) >> 4); + } else { + // byte 0: n1 n0 p2 p1 1 p3 R L + // byte 1: 0 0 0 0 x9 x8 y9 y8 + fingers = (packet[0] & 0xc0) >> 6; + } + + if (info.jumpy_cursor) { + if (fingers != 1) { + etd.single_finger_reports = 0; + } else if (etd.single_finger_reports < 2) { + // Discard first 2 reports of one finger, bogus + etd.single_finger_reports++; + INTERRUPT_LOG("VoodooPS2Elan: discarding packet\n"); + return; + } + } + + // byte 2: x7 x6 x5 x4 x3 x2 x1 x0 + // byte 3: y7 y6 y5 y4 y3 y2 y1 y0 + x = ((packet[1] & 0x0c) << 6) | packet[2]; + y = info.y_max - (((packet[1] & 0x03) << 8) | packet[3]); + + virtualFinger[0].touch = false; + virtualFinger[1].touch = false; + virtualFinger[2].touch = false; + + leftButton = packet[0] & 0x01; + rightButton = packet[0] & 0x02; + + if (fingers == 1) { + virtualFinger[0].touch = true; + virtualFinger[0].button = packet[0] & 0x03; + virtualFinger[0].prev = virtualFinger[0].now; + virtualFinger[0].now.x = x; + virtualFinger[0].now.y = y; + if (lastFingers != 1) { + virtualFinger[0].prev = virtualFinger[0].now; + } + } + + if (fingers == 2) { + virtualFinger[0].touch = virtualFinger[1].touch = true; + virtualFinger[0].button = virtualFinger[1].button = packet[0] & 0x03; + virtualFinger[0].prev = virtualFinger[0].now; + virtualFinger[1].prev = virtualFinger[1].now; + + int h = 100; + int dy = (int)(sin30deg * h); + int dx = (int)(cos30deg * h); + + virtualFinger[0].now.x = x; + virtualFinger[0].now.y = y - h; + + virtualFinger[1].now.x = x + dx; + virtualFinger[1].now.y = y + dy; + + if (lastFingers != 2) { + virtualFinger[0].prev = virtualFinger[0].now; + virtualFinger[1].prev = virtualFinger[1].now; + } + } + + if (fingers == 3) { + virtualFinger[0].touch = virtualFinger[1].touch = virtualFinger[2].touch = true; + virtualFinger[0].button = virtualFinger[1].button = virtualFinger[2].button = packet[0] & 0x03; + virtualFinger[0].prev = virtualFinger[0].now; + virtualFinger[1].prev = virtualFinger[1].now; + virtualFinger[2].prev = virtualFinger[2].now; + + int h = 100; + int dy = (int)(sin30deg * h); + int dx = (int)(cos30deg * h); + + virtualFinger[0].now.x = x; + virtualFinger[0].now.y = y - h; + + virtualFinger[1].now.x = x - dx; + virtualFinger[1].now.y = y + dy; + + virtualFinger[2].now.x = x + dx; + virtualFinger[2].now.y = y + dy; + + if (lastFingers != 3) { + virtualFinger[0].prev = virtualFinger[0].now; + virtualFinger[1].prev = virtualFinger[1].now; + virtualFinger[2].prev = virtualFinger[2].now; + } + } + + lastFingers = fingers; + sendTouchData(); +} + void ApplePS2Elan::elantechReportAbsoluteV2() { unsigned char *packet = _ringBuffer.tail(); unsigned int fingers = 0, x1 = 0, y1 = 0, x2 = 0, y2 = 0; @@ -1523,9 +1644,6 @@ void ApplePS2Elan::elantechReportAbsoluteV2() { virtualFinger[1].prev = virtualFinger[1].now; virtualFinger[2].prev = virtualFinger[2].now; - float sin30deg = 0.5f; - float cos30deg = 0.86602540378f; - int h = 100; int dy = (int)(sin30deg * h); int dx = (int)(cos30deg * h); @@ -1631,9 +1749,6 @@ void ApplePS2Elan::elantechReportAbsoluteV3(int packetType) { virtualFinger[1].prev = virtualFinger[1].now; virtualFinger[2].prev = virtualFinger[2].now; - float sin30deg = 0.5f; - float cos30deg = 0.86602540378f; - int h = 100; int dy = (int)(sin30deg * h); int dx = (int)(cos30deg * h); @@ -1938,8 +2053,8 @@ PS2InterruptResult ApplePS2Elan::interruptOccurred(UInt8 data) { UInt8 *packet = _ringBuffer.head(); packet[_packetByteCount++] = data; - if (_packetByteCount == kPacketLength) { - _ringBuffer.advanceHead(kPacketLength); + if (_packetByteCount == info.packet_length) { + _ringBuffer.advanceHead(info.packet_length); _packetByteCount = 0; return kPS2IR_packetReady; } @@ -1950,17 +2065,23 @@ PS2InterruptResult ApplePS2Elan::interruptOccurred(UInt8 data) { void ApplePS2Elan::packetReady() { INTERRUPT_LOG("VoodooPS2Elan: packet ready occurred\n"); // empty the ring buffer, dispatching each packet... - while (_ringBuffer.count() >= kPacketLength) { + while (_ringBuffer.count() >= info.packet_length) { if (ignoreall) { - _ringBuffer.advanceTail(kPacketLength); + _ringBuffer.advanceTail(info.packet_length); continue; } int packetType; switch (info.hw_version) { case 1: - // V1 is ancient hardware, not going to implement right away - INTERRUPT_LOG("VoodooPS2Elan: packet ready occurred, but unsupported version\n"); + if (info.paritycheck && !elantechPacketCheckV1()) { + // ignore invalid packet + INTERRUPT_LOG("VoodooPS2Elan: invalid packet received\n"); + break; + } + + INTERRUPT_LOG("VoodooPS2Elan: Handling absolute mode\n"); + elantechReportAbsoluteV1(); break; case 2: @@ -2029,7 +2150,7 @@ void ApplePS2Elan::packetReady() { INTERRUPT_LOG("VoodooPS2Elan: invalid packet received\n"); } - _ringBuffer.advanceTail(kPacketLength); + _ringBuffer.advanceTail(info.packet_length); } } diff --git a/VoodooPS2Trackpad/VoodooPS2Elan.h b/VoodooPS2Trackpad/VoodooPS2Elan.h index 5fdae95f..b94e086c 100644 --- a/VoodooPS2Trackpad/VoodooPS2Elan.h +++ b/VoodooPS2Trackpad/VoodooPS2Elan.h @@ -40,7 +40,7 @@ typedef enum { FORCE_TOUCH_CUSTOM = 4 } ForceTouchMode; -#define kPacketLength 6 +#define kPacketLengthMax 6 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // @@ -180,6 +180,7 @@ struct elantech_device_info { unsigned char debug; unsigned char hw_version; unsigned int fw_version; + unsigned int packet_length; unsigned int x_min; unsigned int y_min; unsigned int x_max; @@ -229,7 +230,7 @@ class EXPORT ApplePS2Elan : public IOHIPointing { bool _interruptHandlerInstalled {false}; bool _powerControlHandlerInstalled {false}; UInt32 _packetByteCount {0}; - RingBuffer _ringBuffer {}; + RingBuffer _ringBuffer {}; IOCommandGate* _cmdGate {nullptr}; @@ -239,6 +240,8 @@ class EXPORT ApplePS2Elan : public IOHIPointing { UInt32 leftButton = 0; UInt32 rightButton = 0; + const float sin30deg = 0.5f; + const float cos30deg = 0.86602540378f; UInt32 lastFingers = 0; bool trackpointScrolling {false}; @@ -307,9 +310,11 @@ class EXPORT ApplePS2Elan : public IOHIPointing { int elantechReadReg(unsigned char reg, unsigned char *val); int elantechWriteReg(unsigned char reg, unsigned char val); int elantechDebounceCheckV2(); + int elantechPacketCheckV1(); int elantechPacketCheckV2(); int elantechPacketCheckV3(); int elantechPacketCheckV4(); + void elantechReportAbsoluteV1(); void elantechReportAbsoluteV2(); void elantechReportAbsoluteV3(int packetType); void elantechReportAbsoluteV4(int packetType); From d9c3ed1248b3352d7d5dce4ba7af235d888ae73f Mon Sep 17 00:00:00 2001 From: Le Bao Hiep Date: Wed, 16 Sep 2020 03:34:32 +0700 Subject: [PATCH 28/40] Move elantech_is_buttonpad to cpp file --- VoodooPS2Trackpad/VoodooPS2Elan.cpp | 4 ++++ VoodooPS2Trackpad/VoodooPS2Elan.h | 5 +---- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/VoodooPS2Trackpad/VoodooPS2Elan.cpp b/VoodooPS2Trackpad/VoodooPS2Elan.cpp index 4823be7e..b7caefc4 100644 --- a/VoodooPS2Trackpad/VoodooPS2Elan.cpp +++ b/VoodooPS2Trackpad/VoodooPS2Elan.cpp @@ -751,6 +751,10 @@ int ApplePS2Elan::send_cmd(unsigned char c, unsigned char *param) { } } +bool ApplePS2Elan::elantech_is_buttonpad() { + return (info.fw_version & 0x001000) != 0; +} + bool ApplePS2Elan::elantech_is_signature_valid(const unsigned char *param) { static const unsigned char rates[] = { 200, 100, 80, 60, 40, 20, 10 }; diff --git a/VoodooPS2Trackpad/VoodooPS2Elan.h b/VoodooPS2Trackpad/VoodooPS2Elan.h index b94e086c..3cccf38a 100644 --- a/VoodooPS2Trackpad/VoodooPS2Elan.h +++ b/VoodooPS2Trackpad/VoodooPS2Elan.h @@ -340,14 +340,11 @@ class EXPORT ApplePS2Elan : public IOHIPointing { template int send_cmd(unsigned char c, unsigned char *param); + bool elantech_is_buttonpad(); bool elantech_is_signature_valid(const unsigned char *param); static unsigned int elantech_convert_res(unsigned int val); int elantech_get_resolution_v4(unsigned int *x_res, unsigned int *y_res, unsigned int *bus); - bool elantech_is_buttonpad() { - return (info.fw_version & 0x001000) != 0; - } - public: bool init(OSDictionary *properties) override; ApplePS2Elan *probe(IOService *provider, SInt32 *score) override; From 99b1b0f325777d6aaab3d470b304211948fc535b Mon Sep 17 00:00:00 2001 From: Le Bao Hiep Date: Wed, 16 Sep 2020 16:00:13 +0700 Subject: [PATCH 29/40] Cleanup --- VoodooPS2Trackpad/VoodooPS2Elan.cpp | 44 ++++++++++++++--------------- VoodooPS2Trackpad/VoodooPS2Elan.h | 8 +++--- 2 files changed, 26 insertions(+), 26 deletions(-) diff --git a/VoodooPS2Trackpad/VoodooPS2Elan.cpp b/VoodooPS2Trackpad/VoodooPS2Elan.cpp index b7caefc4..c6861ce7 100644 --- a/VoodooPS2Trackpad/VoodooPS2Elan.cpp +++ b/VoodooPS2Trackpad/VoodooPS2Elan.cpp @@ -347,7 +347,11 @@ void ApplePS2Elan::setParamPropertiesGated(OSDictionary *config) { {"ForceTouchMode", (int*)&_forceTouchMode}, }; - const struct {const char *name; int *var;} boolvars[] = { + const struct {const char *name; uint64_t *var;} int64vars[] = { + {"QuietTimeAfterTyping", &maxaftertyping}, + }; + + const struct {const char *name; bool *var;} boolvars[] = { {"ProcessUSBMouseStopsTrackpad", &_processusbmouse}, {"ProcessBluetoothMouseStopsTrackpad", &_processbluetoothmouse}, {"SetHwResolution", &_set_hw_resolution}, @@ -357,10 +361,6 @@ void ApplePS2Elan::setParamPropertiesGated(OSDictionary *config) { {"USBMouseStopsTrackpad", &usb_mouse_stops_trackpad}, }; - const struct {const char *name; uint64_t *var;} int64vars[] = { - {"QuietTimeAfterTyping", &maxaftertyping}, - }; - OSBoolean *bl; OSNumber *num; @@ -369,6 +369,14 @@ void ApplePS2Elan::setParamPropertiesGated(OSDictionary *config) { setProperty("UseHighRate", bl->isTrue()); } + // 32-bit config items + for (int i = 0; i < countof(int32vars); i++) { + if ((num = OSDynamicCast(OSNumber, config->getObject(int32vars[i].name)))) { + *int32vars[i].var = num->unsigned32BitValue(); + setProperty(int32vars[i].name, *int32vars[i].var, 32); + } + } + // 64-bit config items for (int i = 0; i < countof(int64vars); i++) { if ((num = OSDynamicCast(OSNumber, config->getObject(int64vars[i].name)))) { @@ -385,14 +393,6 @@ void ApplePS2Elan::setParamPropertiesGated(OSDictionary *config) { } } - // 32-bit config items - for (int i = 0; i < countof(int32vars); i++) { - if ((num = OSDynamicCast(OSNumber, config->getObject(int32vars[i].name)))) { - *int32vars[i].var = num->unsigned32BitValue(); - setProperty(int32vars[i].name, *int32vars[i].var, 32); - } - } - // lowbit config items for (int i = 0; i < countof(lowbitvars); i++) { if ((num = OSDynamicCast(OSNumber, config->getObject(lowbitvars[i].name)))) { @@ -457,7 +457,7 @@ IOReturn ApplePS2Elan::message(UInt32 type, IOService* provider, void* argument) case kPS2M_resetTouchpad: { - int *reqCode = (int*)argument; + int *reqCode = (int *)argument; IOLog("VoodooPS2Elan::kPS2M_resetTouchpad reqCode: %d\n", *reqCode); if (*reqCode == 1) { setTouchPadEnable(false); @@ -1015,9 +1015,6 @@ int ApplePS2Elan::elantechSetProperties() { } } - // Determine packet length (4 for v1, 6 for v2 and newer) - info.packet_length = (info.hw_version == 1) ? 4 : 6; - // Turn on packet checking by default info.paritycheck = 1; @@ -1042,6 +1039,9 @@ int ApplePS2Elan::elantechSetProperties() { // Enable real hardware resolution on hw_version 3 ? info.set_hw_resolution = _set_hw_resolution; + // Set packet length (4 for v1, 6 for v2 and newer) + _packetLength = (info.hw_version == 1) ? 4 : 6; + return 0; } @@ -2057,8 +2057,8 @@ PS2InterruptResult ApplePS2Elan::interruptOccurred(UInt8 data) { UInt8 *packet = _ringBuffer.head(); packet[_packetByteCount++] = data; - if (_packetByteCount == info.packet_length) { - _ringBuffer.advanceHead(info.packet_length); + if (_packetByteCount == _packetLength) { + _ringBuffer.advanceHead(_packetLength); _packetByteCount = 0; return kPS2IR_packetReady; } @@ -2069,9 +2069,9 @@ PS2InterruptResult ApplePS2Elan::interruptOccurred(UInt8 data) { void ApplePS2Elan::packetReady() { INTERRUPT_LOG("VoodooPS2Elan: packet ready occurred\n"); // empty the ring buffer, dispatching each packet... - while (_ringBuffer.count() >= info.packet_length) { + while (_ringBuffer.count() >= _packetLength) { if (ignoreall) { - _ringBuffer.advanceTail(info.packet_length); + _ringBuffer.advanceTail(_packetLength); continue; } @@ -2154,7 +2154,7 @@ void ApplePS2Elan::packetReady() { INTERRUPT_LOG("VoodooPS2Elan: invalid packet received\n"); } - _ringBuffer.advanceTail(info.packet_length); + _ringBuffer.advanceTail(_packetLength); } } diff --git a/VoodooPS2Trackpad/VoodooPS2Elan.h b/VoodooPS2Trackpad/VoodooPS2Elan.h index 3cccf38a..a85aadee 100644 --- a/VoodooPS2Trackpad/VoodooPS2Elan.h +++ b/VoodooPS2Trackpad/VoodooPS2Elan.h @@ -180,7 +180,6 @@ struct elantech_device_info { unsigned char debug; unsigned char hw_version; unsigned int fw_version; - unsigned int packet_length; unsigned int x_min; unsigned int y_min; unsigned int x_max; @@ -230,6 +229,7 @@ class EXPORT ApplePS2Elan : public IOHIPointing { bool _interruptHandlerInstalled {false}; bool _powerControlHandlerInstalled {false}; UInt32 _packetByteCount {0}; + UInt32 _packetLength {0}; RingBuffer _ringBuffer {}; IOCommandGate* _cmdGate {nullptr}; @@ -264,13 +264,13 @@ class EXPORT ApplePS2Elan : public IOHIPointing { int _mouseResolution {0x3}; int _mouseSampleRate {200}; - int _set_hw_resolution {false}; + bool _set_hw_resolution {false}; bool ignoreall {false}; bool usb_mouse_stops_trackpad {true}; - int _processusbmouse {true}; - int _processbluetoothmouse {true}; + bool _processusbmouse {true}; + bool _processbluetoothmouse {true}; uint64_t keytime {0}; uint64_t maxaftertyping {500000000}; From 1c62681e654e3e49c5a1c9b56cffaba069b5279f Mon Sep 17 00:00:00 2001 From: Le Bao Hiep Date: Wed, 16 Sep 2020 18:49:30 +0700 Subject: [PATCH 30/40] Fix Force Touch emulation --- VoodooPS2Trackpad/VoodooPS2Elan.cpp | 27 +++++++++++++-------------- 1 file changed, 13 insertions(+), 14 deletions(-) diff --git a/VoodooPS2Trackpad/VoodooPS2Elan.cpp b/VoodooPS2Trackpad/VoodooPS2Elan.cpp index c6861ce7..47dbed97 100644 --- a/VoodooPS2Trackpad/VoodooPS2Elan.cpp +++ b/VoodooPS2Trackpad/VoodooPS2Elan.cpp @@ -1986,32 +1986,31 @@ void ApplePS2Elan::sendTouchData() { continue; } - auto& transducer = inputEvent.transducers[transducers_count++]; + auto &transducer = inputEvent.transducers[transducers_count++]; transducer.currentCoordinates = state.now; transducer.previousCoordinates = state.prev; transducer.timestamp = timestamp; transducer.isValid = true; + transducer.isPhysicalButtonDown = state.button; transducer.isTransducerActive = true; transducer.secondaryId = i; transducer.fingerType = GetBestFingerType(transducers_count); transducer.type = FINGER; - switch (_forceTouchMode) { - case FORCE_TOUCH_BUTTON: // Physical button is translated into force touch instead of click - transducer.isPhysicalButtonDown = false; - transducer.supportsPressure = true; - transducer.currentCoordinates.pressure = state.button ? 255 : 0; - transducer.currentCoordinates.width = 20; - break; - - case FORCE_TOUCH_DISABLED: - default: - transducer.isPhysicalButtonDown = state.button; - transducer.supportsPressure = false; - break; + // it looks like Elan PS2 pressure and width is very inaccurate + // it is better to leave it that way + transducer.supportsPressure = false; + + // Force Touch emulation + // Physical button is translated into force touch instead of click + if (state.button && _forceTouchMode == FORCE_TOUCH_BUTTON) { + transducer.supportsPressure = true; + transducer.isPhysicalButtonDown = false; + transducer.currentCoordinates.pressure = 255; + transducer.currentCoordinates.width = 10; } } From 1416196e52fdb1a20d300c4b7f6a564f4f451db9 Mon Sep 17 00:00:00 2001 From: Le Bao Hiep Date: Wed, 16 Sep 2020 18:56:40 +0700 Subject: [PATCH 31/40] Simplify buttonpad check --- VoodooPS2Trackpad/VoodooPS2Elan.cpp | 11 +++++------ VoodooPS2Trackpad/VoodooPS2Elan.h | 2 +- 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/VoodooPS2Trackpad/VoodooPS2Elan.cpp b/VoodooPS2Trackpad/VoodooPS2Elan.cpp index 47dbed97..28ee1440 100644 --- a/VoodooPS2Trackpad/VoodooPS2Elan.cpp +++ b/VoodooPS2Trackpad/VoodooPS2Elan.cpp @@ -751,10 +751,6 @@ int ApplePS2Elan::send_cmd(unsigned char c, unsigned char *param) { } } -bool ApplePS2Elan::elantech_is_buttonpad() { - return (info.fw_version & 0x001000) != 0; -} - bool ApplePS2Elan::elantech_is_signature_valid(const unsigned char *param) { static const unsigned char rates[] = { 200, 100, 80, 60, 40, 20, 10 }; @@ -982,8 +978,11 @@ int ApplePS2Elan::elantechQueryInfo() { break; } + // check if device has buttonpad + info.is_buttonpad = (info.fw_version & 0x001000) != 0; + // check for the middle button - info.has_middle_button = (ETP_NEW_IC_SMBUS_HOST_NOTIFY(info.fw_version) && !elantech_is_buttonpad()); + info.has_middle_button = ETP_NEW_IC_SMBUS_HOST_NOTIFY(info.fw_version) && !info.is_buttonpad; return 0; } @@ -2046,7 +2045,7 @@ void ApplePS2Elan::sendTouchData() { super::messageClient(kIOMessageVoodooInputMessage, voodooInputInstance, &inputEvent, sizeof(VoodooInputEvent)); } - if (!elantech_is_buttonpad() && inputEvent.contact_count == 0) { + if (!info.is_buttonpad && inputEvent.contact_count == 0) { UInt32 buttons = leftButton | rightButton; dispatchRelativePointerEvent(0, 0, buttons, timestamp); } diff --git a/VoodooPS2Trackpad/VoodooPS2Elan.h b/VoodooPS2Trackpad/VoodooPS2Elan.h index a85aadee..ea1a1c8b 100644 --- a/VoodooPS2Trackpad/VoodooPS2Elan.h +++ b/VoodooPS2Trackpad/VoodooPS2Elan.h @@ -195,6 +195,7 @@ struct elantech_device_info { bool reports_pressure; bool crc_enabled; bool set_hw_resolution; + bool is_buttonpad; bool has_trackpoint; bool has_middle_button; }; @@ -340,7 +341,6 @@ class EXPORT ApplePS2Elan : public IOHIPointing { template int send_cmd(unsigned char c, unsigned char *param); - bool elantech_is_buttonpad(); bool elantech_is_signature_valid(const unsigned char *param); static unsigned int elantech_convert_res(unsigned int val); int elantech_get_resolution_v4(unsigned int *x_res, unsigned int *y_res, unsigned int *bus); From 605c526d79f3d8ea13aad05a58c3a7a4f8e0aa22 Mon Sep 17 00:00:00 2001 From: Le Bao Hiep Date: Wed, 16 Sep 2020 19:31:38 +0700 Subject: [PATCH 32/40] Validate trackpoint packet --- VoodooPS2Trackpad/VoodooPS2Elan.cpp | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/VoodooPS2Trackpad/VoodooPS2Elan.cpp b/VoodooPS2Trackpad/VoodooPS2Elan.cpp index 28ee1440..c9b1e561 100644 --- a/VoodooPS2Trackpad/VoodooPS2Elan.cpp +++ b/VoodooPS2Trackpad/VoodooPS2Elan.cpp @@ -1806,6 +1806,30 @@ void ApplePS2Elan::elantechReportAbsoluteV4(int packetType) { } void ApplePS2Elan::elantechReportTrackpoint() { + // byte 0: 0 0 sx sy 0 M R L + // byte 1: ~sx 0 0 0 0 0 0 0 + // byte 2: ~sy 0 0 0 0 0 0 0 + // byte 3: 0 0 ~sy ~sx 0 1 1 0 + // byte 4: x7 x6 x5 x4 x3 x2 x1 x0 + // byte 5: y7 y6 y5 y4 y3 y2 y1 y0 + // + // x and y are written in two's complement spread + // over 9 bits with sx/sy the relative top bit and + // x7..x0 and y7..y0 the lower bits. + // ~sx is the inverse of sx, ~sy is the inverse of sy. + // The sign of y is opposite to what the input driver + // expects for a relative movement + + UInt32 *t = (UInt32 *)_ringBuffer.tail(); + UInt32 signature = *t & ~7U; + if (signature != 0x06000030U && + signature != 0x16008020U && + signature != 0x26800010U && + signature != 0x36808000U) { + INTERRUPT_LOG("VoodooPS2Elan: unexpected trackpoint packet skipped\n"); + return; + } + unsigned char *packet = _ringBuffer.tail(); int trackpointLeftButton = packet[0] & 0x1; From 5918f6f1d443489ca393d57b99cf7dccf8be879b Mon Sep 17 00:00:00 2001 From: Le Bao Hiep Date: Fri, 18 Sep 2020 20:03:31 +0700 Subject: [PATCH 33/40] Fix receiving notifications from keyboard --- VoodooPS2Trackpad/VoodooPS2Elan.cpp | 2 +- VoodooPS2Trackpad/VoodooPS2Trackpad-Info.plist | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/VoodooPS2Trackpad/VoodooPS2Elan.cpp b/VoodooPS2Trackpad/VoodooPS2Elan.cpp index c9b1e561..e90fbb84 100644 --- a/VoodooPS2Trackpad/VoodooPS2Elan.cpp +++ b/VoodooPS2Trackpad/VoodooPS2Elan.cpp @@ -283,7 +283,7 @@ bool ApplePS2Elan::start(IOService *provider) { _powerControlHandlerInstalled = true; // Request message registration for keyboard to trackpad communication - setProperty(kDeliverNotifications, true); + //setProperty(kDeliverNotifications, true); return true; } diff --git a/VoodooPS2Trackpad/VoodooPS2Trackpad-Info.plist b/VoodooPS2Trackpad/VoodooPS2Trackpad-Info.plist index e76c7cff..3ec0ba2b 100644 --- a/VoodooPS2Trackpad/VoodooPS2Trackpad-Info.plist +++ b/VoodooPS2Trackpad/VoodooPS2Trackpad-Info.plist @@ -152,6 +152,8 @@ 1000 + RM,deliverNotifications + Native Multitouch Engine From 3a4d715b87b2599f4659ffde64f5674169f47c4d Mon Sep 17 00:00:00 2001 From: Le Bao Hiep Date: Fri, 18 Sep 2020 20:22:38 +0700 Subject: [PATCH 34/40] Ignore input after trackpoint usage --- VoodooPS2Trackpad/VoodooPS2Elan.cpp | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/VoodooPS2Trackpad/VoodooPS2Elan.cpp b/VoodooPS2Trackpad/VoodooPS2Elan.cpp index e90fbb84..97bc4a54 100644 --- a/VoodooPS2Trackpad/VoodooPS2Elan.cpp +++ b/VoodooPS2Trackpad/VoodooPS2Elan.cpp @@ -1855,6 +1855,12 @@ void ApplePS2Elan::elantechReportTrackpoint() { AbsoluteTime timestamp; clock_get_uptime(×tamp); + // remember last time trackpoint was used. this can be used in + // interrupt handler to detect unintended input + uint64_t timestamp_ns; + absolutetime_to_nanoseconds(timestamp, ×tamp_ns); + keytime = timestamp_ns; + if (trackpointScrolling) { dispatchScrollWheelEvent(dx, dy, 0, timestamp); } else { @@ -1995,7 +2001,7 @@ void ApplePS2Elan::sendTouchData() { uint64_t timestamp_ns; absolutetime_to_nanoseconds(timestamp, ×tamp_ns); - // Ignore input for specified time after keyboard usage + // Ignore input for specified time after keyboard/trackpoint usage if (timestamp_ns - keytime < maxaftertyping) { return; } From 646f9247023229b0b6beab96d76adb1af7ab57c5 Mon Sep 17 00:00:00 2001 From: Le Bao Hiep Date: Fri, 18 Sep 2020 21:02:43 +0700 Subject: [PATCH 35/40] Typo --- VoodooPS2Trackpad/VoodooPS2Elan.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VoodooPS2Trackpad/VoodooPS2Elan.cpp b/VoodooPS2Trackpad/VoodooPS2Elan.cpp index 97bc4a54..dbd86929 100644 --- a/VoodooPS2Trackpad/VoodooPS2Elan.cpp +++ b/VoodooPS2Trackpad/VoodooPS2Elan.cpp @@ -2010,7 +2010,7 @@ void ApplePS2Elan::sendTouchData() { int transducers_count = 0; for (int i = 0; i < ETP_MAX_FINGERS; i++) { - const auto& state = virtualFinger[i]; + const auto &state = virtualFinger[i]; if (!state.touch) { continue; } From 8354f0d803b8fefebe4a49f6bf26a6678b32c78a Mon Sep 17 00:00:00 2001 From: Le Bao Hiep Date: Fri, 18 Sep 2020 21:51:40 +0700 Subject: [PATCH 36/40] Fix right button click --- VoodooPS2Trackpad/VoodooPS2Elan.cpp | 29 ++++++++++++++++++++++++----- VoodooPS2Trackpad/VoodooPS2Elan.h | 2 ++ 2 files changed, 26 insertions(+), 5 deletions(-) diff --git a/VoodooPS2Trackpad/VoodooPS2Elan.cpp b/VoodooPS2Trackpad/VoodooPS2Elan.cpp index dbd86929..a1f3e687 100644 --- a/VoodooPS2Trackpad/VoodooPS2Elan.cpp +++ b/VoodooPS2Trackpad/VoodooPS2Elan.cpp @@ -2022,7 +2022,7 @@ void ApplePS2Elan::sendTouchData() { transducer.timestamp = timestamp; transducer.isValid = true; - transducer.isPhysicalButtonDown = state.button; + transducer.isPhysicalButtonDown = info.is_buttonpad && state.button; transducer.isTransducerActive = true; transducer.secondaryId = i; @@ -2035,7 +2035,7 @@ void ApplePS2Elan::sendTouchData() { // Force Touch emulation // Physical button is translated into force touch instead of click - if (state.button && _forceTouchMode == FORCE_TOUCH_BUTTON) { + if (_forceTouchMode == FORCE_TOUCH_BUTTON && transducer.isPhysicalButtonDown) { transducer.supportsPressure = true; transducer.isPhysicalButtonDown = false; transducer.currentCoordinates.pressure = 255; @@ -2075,9 +2075,28 @@ void ApplePS2Elan::sendTouchData() { super::messageClient(kIOMessageVoodooInputMessage, voodooInputInstance, &inputEvent, sizeof(VoodooInputEvent)); } - if (!info.is_buttonpad && inputEvent.contact_count == 0) { - UInt32 buttons = leftButton | rightButton; - dispatchRelativePointerEvent(0, 0, buttons, timestamp); + if (!info.is_buttonpad) { + if (transducers_count == 0) { + UInt32 buttons = leftButton | rightButton; + dispatchRelativePointerEvent(0, 0, buttons, timestamp); + } else { + UInt32 buttons = 0; + bool send = false; + if (lastLeftButton != leftButton) { + buttons |= leftButton; + send = true; + } + if (lastRightButton != rightButton) { + buttons |= rightButton; + send = true; + } + if (send) { + dispatchRelativePointerEvent(0, 0, buttons, timestamp); + } + } + + lastLeftButton = leftButton; + lastRightButton = rightButton; } } diff --git a/VoodooPS2Trackpad/VoodooPS2Elan.h b/VoodooPS2Trackpad/VoodooPS2Elan.h index ea1a1c8b..f1e2989d 100644 --- a/VoodooPS2Trackpad/VoodooPS2Elan.h +++ b/VoodooPS2Trackpad/VoodooPS2Elan.h @@ -240,6 +240,8 @@ class EXPORT ApplePS2Elan : public IOHIPointing { // when trackpad has physical button UInt32 leftButton = 0; UInt32 rightButton = 0; + UInt32 lastLeftButton = 0; + UInt32 lastRightButton = 0; const float sin30deg = 0.5f; const float cos30deg = 0.86602540378f; From a471041e4afaf7fd612d25faa47be1155f548c67 Mon Sep 17 00:00:00 2001 From: Le Bao Hiep Date: Fri, 18 Sep 2020 23:25:56 +0700 Subject: [PATCH 37/40] Improve finger type assignment and thumb detection --- VoodooPS2Trackpad/VoodooPS2Elan.cpp | 24 +++++++++++++----------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/VoodooPS2Trackpad/VoodooPS2Elan.cpp b/VoodooPS2Trackpad/VoodooPS2Elan.cpp index a1f3e687..792a6d91 100644 --- a/VoodooPS2Trackpad/VoodooPS2Elan.cpp +++ b/VoodooPS2Trackpad/VoodooPS2Elan.cpp @@ -2015,7 +2015,7 @@ void ApplePS2Elan::sendTouchData() { continue; } - auto &transducer = inputEvent.transducers[transducers_count++]; + auto &transducer = inputEvent.transducers[transducers_count]; transducer.currentCoordinates = state.now; transducer.previousCoordinates = state.prev; @@ -2041,25 +2041,27 @@ void ApplePS2Elan::sendTouchData() { transducer.currentCoordinates.pressure = 255; transducer.currentCoordinates.width = 10; } + + transducers_count++; } - // set the thumb to improve 4F pinch and spread gesture - if (transducers_count == 4) { - // simple thumb detection: find the lowest finger touch - UInt32 y_min = info.y_max / 2; - int thumb_index = 0; + // set the thumb to improve 4F pinch and spread gesture and cross-screen dragging + if (transducers_count >= 4) { + // simple thumb detection: find the lowest finger touch in the vertical direction + UInt32 minY = info.y_max; + int newThumbIndex = 0; int currentThumbIndex = 0; for (int i = 0; i < transducers_count; i++) { - if (inputEvent.transducers[i].currentCoordinates.y > y_min) { - y_min = inputEvent.transducers[i].currentCoordinates.y; - thumb_index = i; + if (inputEvent.transducers[i].currentCoordinates.y < minY) { + minY = inputEvent.transducers[i].currentCoordinates.y; + newThumbIndex = i; } if (inputEvent.transducers[i].fingerType == kMT2FingerTypeThumb) { currentThumbIndex = i; } } - inputEvent.transducers[currentThumbIndex].fingerType = inputEvent.transducers[thumb_index].fingerType; - inputEvent.transducers[thumb_index].fingerType = kMT2FingerTypeThumb; + inputEvent.transducers[currentThumbIndex].fingerType = inputEvent.transducers[newThumbIndex].fingerType; + inputEvent.transducers[newThumbIndex].fingerType = kMT2FingerTypeThumb; } for (int i = transducers_count; i < VOODOO_INPUT_MAX_TRANSDUCERS; i++) { From b68c721d2a5994b1f9b9220210def2812c672c09 Mon Sep 17 00:00:00 2001 From: Le Bao Hiep Date: Sat, 19 Sep 2020 04:37:21 +0700 Subject: [PATCH 38/40] Fix thumb detection --- VoodooPS2Trackpad/VoodooPS2Elan.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/VoodooPS2Trackpad/VoodooPS2Elan.cpp b/VoodooPS2Trackpad/VoodooPS2Elan.cpp index 792a6d91..a955ab58 100644 --- a/VoodooPS2Trackpad/VoodooPS2Elan.cpp +++ b/VoodooPS2Trackpad/VoodooPS2Elan.cpp @@ -2048,12 +2048,13 @@ void ApplePS2Elan::sendTouchData() { // set the thumb to improve 4F pinch and spread gesture and cross-screen dragging if (transducers_count >= 4) { // simple thumb detection: find the lowest finger touch in the vertical direction - UInt32 minY = info.y_max; + // note: the origin is top left corner, so lower finger means higher y coordinate + UInt32 maxY = 0; int newThumbIndex = 0; int currentThumbIndex = 0; for (int i = 0; i < transducers_count; i++) { - if (inputEvent.transducers[i].currentCoordinates.y < minY) { - minY = inputEvent.transducers[i].currentCoordinates.y; + if (inputEvent.transducers[i].currentCoordinates.y > maxY) { + maxY = inputEvent.transducers[i].currentCoordinates.y; newThumbIndex = i; } if (inputEvent.transducers[i].fingerType == kMT2FingerTypeThumb) { From 997c3bf5bed4944e22d110426227699cd8730645 Mon Sep 17 00:00:00 2001 From: Le Bao Hiep Date: Sat, 19 Sep 2020 07:54:38 +0700 Subject: [PATCH 39/40] Map both buttons to hardclick for clickpads --- VoodooPS2Trackpad/VoodooPS2Elan.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/VoodooPS2Trackpad/VoodooPS2Elan.cpp b/VoodooPS2Trackpad/VoodooPS2Elan.cpp index a955ab58..815599e4 100644 --- a/VoodooPS2Trackpad/VoodooPS2Elan.cpp +++ b/VoodooPS2Trackpad/VoodooPS2Elan.cpp @@ -1927,7 +1927,7 @@ void ApplePS2Elan::processPacketHeadV4() { INTERRUPT_LOG("VoodooPS2Elan: pres: %d, traces: %d, width: %d\n", pres, traces, etd.width); - virtualFinger[id].button = (packet[0] & 1); + virtualFinger[id].button = (packet[0] & 0x3); virtualFinger[id].prev = virtualFinger[id].now; virtualFinger[id].pressure = pres; virtualFinger[id].width = traces; @@ -1966,13 +1966,13 @@ void ApplePS2Elan::processPacketMotionV4() { delta_x2 = (signed char)packet[4]; delta_y2 = (signed char)packet[5]; - virtualFinger[id].button = (packet[0] & 1); + virtualFinger[id].button = (packet[0] & 0x3); virtualFinger[id].prev = virtualFinger[id].now; virtualFinger[id].now.x += delta_x1 * weight; virtualFinger[id].now.y -= delta_y1 * weight; if (sid >= 0) { - virtualFinger[sid].button = (packet[0] & 1); + virtualFinger[sid].button = (packet[0] & 0x3); virtualFinger[sid].prev = virtualFinger[sid].now; virtualFinger[sid].now.x += delta_x2 * weight; virtualFinger[sid].now.y -= delta_y2 * weight; From 90b8a33ed8a5288d2d76f3273393f76fe7757530 Mon Sep 17 00:00:00 2001 From: Le Bao Hiep Date: Sat, 19 Sep 2020 08:06:43 +0700 Subject: [PATCH 40/40] Only log probing info in debug version --- VoodooPS2Trackpad/VoodooPS2Elan.cpp | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/VoodooPS2Trackpad/VoodooPS2Elan.cpp b/VoodooPS2Trackpad/VoodooPS2Elan.cpp index 815599e4..21fb408d 100644 --- a/VoodooPS2Trackpad/VoodooPS2Elan.cpp +++ b/VoodooPS2Trackpad/VoodooPS2Elan.cpp @@ -59,8 +59,6 @@ bool ApplePS2Elan::init(OSDictionary *dict) { extern kmod_info_t kmod_info; DEBUG_LOG("VoodooPS2Elan: Version %s starting on OS X Darwin %d.%d.\n", kmod_info.version, version_major, version_minor); - setProperty("Revision", 24, 32); - return true; } @@ -140,10 +138,10 @@ ApplePS2Elan *ApplePS2Elan::probe(IOService *provider, SInt32 *score) { resetMouse(); - IOLog("VoodooPS2Elan: send magic knock to the device.\n"); + DEBUG_LOG("VoodooPS2Elan: send magic knock to the device.\n"); // send magic knock to the device if (elantechDetect()) { - IOLog("VoodooPS2Elan: elantouchpad not detected\n"); + DEBUG_LOG("VoodooPS2Elan: elan touchpad not detected\n"); return NULL; } @@ -811,7 +809,7 @@ int ApplePS2Elan::elantechDetect() { ps2_command<0>(NULL, kDP_SetMouseScaling1To1) || ps2_command<0>(NULL, kDP_SetMouseScaling1To1) || ps2_command<3>(param, kDP_GetMouseInformation)) { - IOLog("VoodooPS2Elan: sending Elantech magic knock failed.\n"); + DEBUG_LOG("VoodooPS2Elan: sending Elantech magic knock failed.\n"); return -1; }