From 19374b1db1b5f1cdd1cc0be02239d85dde301d8b Mon Sep 17 00:00:00 2001 From: Fabian R Date: Tue, 23 Jun 2020 04:03:09 -0500 Subject: [PATCH 001/101] Proposes fix to Synaptics touchpad not working after sleep wake, and improved PrntScr hotkey handling + Added Vendor Specific Message with code 151 (0x97) to ApplePS2Device used to request Trackpad resets from Keypad controller. - VoodooPS2Keyboard now requests a Trackpad reset too when the 3-finger salute (Ctrl+Alt+Del) is pressed on the Keypad. + Fix: Added an extra kDP_Enable command request on VoodooPS2SynapticsTouchPad when waking from sleep. This should auto-enable reluctant Synaptics touchpads on wake. + Added handling code for resetTouchpad IOkit messages on VoodooPS2SynapticsTouchPad, to actually reset and re-enable the device on request. - Bumped module version to 2.1.6 TL;DR: This commit tries to fix some Synaptics touchpad devices not working after waking from sleep. If that doesnt work automatically after a couple of seconds, press Ctrl+Alt+Del to issue a device reset. This can be done at any time. Dev note: It may be a good idea to implement the the reset message handling on any other touchpad driver too, this should give users a keyboard combo command to try to recover from non-working scenarios, before giving up and rebooting. (+1 squashed commit) Squashed commits: [3e7fb81] Remapped Touchpad reset to PrntScr and cleaned up special hotkey handling - Ctrl+Alt+PrntScrn key combo is now used to trigger Touchpad resets. This should fix collisions with Ctrl+Alt+Del on VMs/RDPs. - Cleaned and improved special hotkey handling on VoodooPS2Keyboard.cpp around the PrntScr/SysRq key. - VoodooPS2Keyboard now detect and correctly maps the SysRq key or the Alt+PrntScrn key combo, instead of just ignoring it. + VoodooPS2Keyboard now detects modifiers pressed on any side of the keyboard when handling special PrntScr hotkeys. - The keyboard module is now more verbose to the IOLog when built with DEBUG configurations. + Keyboard and Touchpad "Enabled" states are now synced up when using the Windows/Logo+PrntSrc keyboard combo. Both of them are disabled, or both enabled. + Pressing Shift+PrntSrc now sends a SysRq key instead, useful for VMs and RDPs, specially Linux-based ones. - Devs: Added inline method checkModifierStateAny(UInt16) to VoodooPS2Keyboard.h. This should allow a more flexible way to check if a modifier key is present without taking into account other modifier keys. The current list of supported hotkeys by VoodooPS2Keyboard are as follows: Supported Voodoo PrntScr Key combinations: - PrntScr: Enable/Disable touchpad - Windows+PrntScr: Enable/Disable touchpad+keyboard - Ctrl+Alt+PrntScr: Reset and enable touchpad - Shift+PrntScr: Send SysRq scancode to the kernel --- VoodooPS2Controller.xcodeproj/project.pbxproj | 4 +- VoodooPS2Controller/ApplePS2Device.h | 4 +- VoodooPS2Keyboard/VoodooPS2Keyboard.cpp | 114 ++++++++++++++++-- VoodooPS2Keyboard/VoodooPS2Keyboard.h | 2 + .../VoodooPS2SynapticsTouchPad.cpp | 18 +++ 5 files changed, 129 insertions(+), 13 deletions(-) diff --git a/VoodooPS2Controller.xcodeproj/project.pbxproj b/VoodooPS2Controller.xcodeproj/project.pbxproj index 6d45fd11..7af7e71a 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.5; + MODULE_VERSION = 2.1.6; 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.5; + MODULE_VERSION = 2.1.6; "OTHER_LDFLAGS[arch=x86_64]" = "-dead_strip"; PRODUCT_NAME = VoodooPS2Controller; SDKROOT = macosx; diff --git a/VoodooPS2Controller/ApplePS2Device.h b/VoodooPS2Controller/ApplePS2Device.h index 9629d352..0b62a535 100644 --- a/VoodooPS2Controller/ApplePS2Device.h +++ b/VoodooPS2Controller/ApplePS2Device.h @@ -525,7 +525,9 @@ enum kPS2M_getDisableTouchpad = iokit_vendor_specific_msg(101), // get disable/enable touchpad (data is bool*) kPS2M_notifyKeyPressed = iokit_vendor_specific_msg(102), // notify of time key pressed (data is PS2KeyInfo*) - kPS2M_notifyKeyTime = iokit_vendor_specific_msg(110) // notify of timestamp a non-modifier key was pressed (data is uint64_t*) + kPS2M_notifyKeyTime = iokit_vendor_specific_msg(110), // notify of timestamp a non-modifier key was pressed (data is uint64_t*) + + kPS2M_resetTouchpad = iokit_vendor_specific_msg(151), // Force touchpad reset (data is int*) }; typedef struct PS2KeyInfo diff --git a/VoodooPS2Keyboard/VoodooPS2Keyboard.cpp b/VoodooPS2Keyboard/VoodooPS2Keyboard.cpp index 972907c7..d0eff08b 100644 --- a/VoodooPS2Keyboard/VoodooPS2Keyboard.cpp +++ b/VoodooPS2Keyboard/VoodooPS2Keyboard.cpp @@ -1593,6 +1593,9 @@ bool ApplePS2Keyboard::dispatchKeyboardEventWithPacket(const UInt8* packet) dispatchKeyboardEventX(0x3b, false, now_abs); dispatchKeyboardEventX(0x7f, true, now_abs); dispatchKeyboardEventX(0x7f, false, now_abs); + + int val = 1; + _device->dispatchMessage(kPS2M_resetTouchpad, &val); // Reset touchpad } } break; @@ -1615,26 +1618,113 @@ bool ApplePS2Keyboard::dispatchKeyboardEventWithPacket(const UInt8* packet) //REVIEW: this is getting a bit ugly case 0x0128: // alternate that cannot fnkeys toggle (discrete trackpad toggle) + case 0x0054: // SysRq (PrntScr when combined with Alt modifier -left or right-) + { + // PrntScr is handled specially by some keyboard devices. + // See: 5.19 on https://www.win.tue.nl/~aeb/linux/kbd/scancodes-5.html#mtek +#ifdef DEBUG + UInt16 debug_originalModifiers = _PS2modifierState; +#endif + // Force Alt (Left) key to be down when receiving this keycode, dont rely on KB firmware + _PS2modifierState &= ~kMaskRightAlt; + _PS2modifierState |= kMaskLeftAlt; + keyCode = 0x0137; // Rewrite keycode + +#ifdef DEBUG + IOLog("VoodooPS2Keyboard: special PrntScr: modifiersBefore=%#.4X modifiersAfter=%#.4X\n", debug_originalModifiers, _PS2modifierState); +#endif + + // Fall to the original PrntScr handling case + } case 0x0137: // prt sc/sys rq { + /* Supported Voodoo PrntScr Key combinations: + PrntScr Enable/Disable touchpad + Windows+PrntScr Enable/Disable touchpad+keyboard + Ctrl+Alt+PrntScr Reset and enable touchpad + Shift+PrntScr Send SysRq scancode to the kernel + + Notes: + - Alt+Windows combo seems to be masked out by some keyboard devices and dont produce any ScanCode. + Dont rely on it. + */ + unsigned origKeyCode = keyCode; - keyCode = 0; + keyCode = 0; // Handle all these keycode variants internally + +#ifdef DEBUG + bool debug_control = checkModifierStateAny(kMaskLeftControl|kMaskRightControl); + bool debug_alt = checkModifierStateAny(kMaskLeftAlt|kMaskRightAlt); + bool debug_shift = checkModifierStateAny(kMaskLeftShift|kMaskRightShift); + bool debug_windows = checkModifierStateAny(kMaskLeftWindows|kMaskRightWindows); + + IOLog("VoodooPS2Keyboard: PrtScr:: goingDown=%s control=%s alt=%s shift=%s windows=%s modifiers=%d\n", + goingDown ? "Yes" : "No", + debug_control ? "Yes" : "No", + debug_alt ? "Yes" : "No", + debug_shift ? "Yes" : "No", + debug_windows ? "Yes" : "No", + _PS2modifierState); +#endif + if (!goingDown) break; - if (!checkModifierState(kMaskLeftControl)) + + if (checkModifierStateAny(kMaskLeftControl|kMaskRightControl)) { - // get current enabled status, and toggle it - bool enabled; - _device->dispatchMessage(kPS2M_getDisableTouchpad, &enabled); - enabled = !enabled; - _device->dispatchMessage(kPS2M_setDisableTouchpad, &enabled); - // Disable keyboard input along with the touchpad using Windows(Option)+prtsc, useful for 2-in-1 applications. - if (checkModifierState(kMaskLeftWindows)) + // Shift is ignored from this point onwards + if (checkModifierStateAny(kMaskLeftAlt|kMaskRightAlt)) { - _disableInput = !_disableInput; + // Ctrl+Alt+PrntScr + IOLog("VoodooPS2Keyboard: Sending RESET signal to touchpad."); // Dont wrap into a DEBUG compilation condition since this should be a workaroung to be used on faulty states only + int val = 1; + _device->dispatchMessage(kPS2M_resetTouchpad, &val); // Reset touchpad } + } + else + { + if (checkModifierState(kMaskLeftShift) || checkModifierState(kMaskRightShift)) + { + // Shift+PrntScr, no other modifiers present +#ifdef DEBUG + IOLog("VoodooPS2Keyboard: Sending SysRq virtual scancode 0x58"); +#endif + dispatchKeyboardEventX(0x58, true, now_abs); // Send SysRq to the kernel + dispatchKeyboardEventX(0x58, false, now_abs); + } + else + { + if (checkModifierStateAny(kMaskRightShift|kMaskLeftShift|kMaskRightAlt|kMaskLeftAlt)) + break; // Eat combinations where Ctrl is Up and Alt or Shift are Down (!Ctrl+[Alt|Shift]) + + bool enabled; + if (checkModifierStateAny(kMaskLeftWindows|kMaskRightWindows)) + { + // Windows+PrntScr + // Disable keyboard input along with the touchpad using Windows(Option)+prtsc, useful for 2-in-1 applications. +#ifdef DEBUG + IOLog("VoodooPS2Keyboard: Toggling keyboard+Touchpad enabled state."); +#endif + enabled = _disableInput; + _disableInput = !_disableInput; + _device->dispatchMessage(kPS2M_setDisableTouchpad, &enabled); // Sync Keyboard and Touchpad enabled states + } + else + { + // No other modifiers pressed down +#ifdef DEBUG + IOLog("VoodooPS2Keyboard: Toggling Touchpad enabled state."); +#endif + // Touchpad enable/disable: get current enabled status, and toggle it + _device->dispatchMessage(kPS2M_getDisableTouchpad, &enabled); + enabled = !enabled; + _device->dispatchMessage(kPS2M_setDisableTouchpad, &enabled); + } + } + break; } + if (origKeyCode != 0x0137) break; // do not fall through for 0x0128 // fall through @@ -1664,6 +1754,10 @@ bool ApplePS2Keyboard::dispatchKeyboardEventWithPacket(const UInt8* packet) } } break; +#ifdef DEBUG + default: + IOLog("VoodooPS2Keyboard: Unhandled keycode: %#.4X\n", keyCode); +#endif } // If keyboard input is disabled drop the key code.. diff --git a/VoodooPS2Keyboard/VoodooPS2Keyboard.h b/VoodooPS2Keyboard/VoodooPS2Keyboard.h index d74b51ce..c69dde74 100644 --- a/VoodooPS2Keyboard/VoodooPS2Keyboard.h +++ b/VoodooPS2Keyboard/VoodooPS2Keyboard.h @@ -142,6 +142,8 @@ class EXPORT ApplePS2Keyboard : public IOHIKeyboard void modifyScreenBrightness(int adbKeyCode, bool goingDown); inline bool checkModifierState(UInt16 mask) { return mask == (_PS2modifierState & mask); } + inline bool checkModifierStateAny(UInt16 mask) + { return (_PS2modifierState & mask); } void loadCustomPS2Map(OSArray* pArray); void loadBreaklessPS2(OSDictionary* dict, const char* name); diff --git a/VoodooPS2Trackpad/VoodooPS2SynapticsTouchPad.cpp b/VoodooPS2Trackpad/VoodooPS2SynapticsTouchPad.cpp index 34647232..6e8ac526 100644 --- a/VoodooPS2Trackpad/VoodooPS2SynapticsTouchPad.cpp +++ b/VoodooPS2Trackpad/VoodooPS2SynapticsTouchPad.cpp @@ -2356,6 +2356,10 @@ void ApplePS2SynapticsTouchPad::setDevicePowerState( UInt32 whatToDo ) // Reset and enable the touchpad. initTouchPad(); + + // Send extra kDP_Enable command + IOSleep(wakedelay); + setTouchPadEnable(true); break; } } @@ -2396,6 +2400,20 @@ IOReturn ApplePS2SynapticsTouchPad::message(UInt32 type, IOService* provider, vo break; } + case kPS2M_resetTouchpad: + { + int* reqCode = (int*)argument; + IOLog("VoodooPS2SynapticsTouchPad::kPS2M_resetTouchpad reqCode: %d\n", *reqCode); + if (*reqCode == 1) + { + ignoreall = false; + initTouchPad(); + IOSleep(wakedelay); + setTouchPadEnable(true); // Send extra kDP_Enable + updateTouchpadLED(); + } + break; + } case kPS2M_notifyKeyPressed: { // just remember last time key pressed... this can be used in From c43a1c7826d15be1d69e9c9bd766b846bddb891e Mon Sep 17 00:00:00 2001 From: Fabian R Date: Tue, 23 Jun 2020 06:54:04 -0500 Subject: [PATCH 002/101] Removed Touchpad reset code from Ctrl+Alt+Del key combo handler -- Removed touchpad reset signal dispatching code from VoodooPS2Keyboard.cpp. This change complements the previous commit. --- VoodooPS2Keyboard/VoodooPS2Keyboard.cpp | 3 --- 1 file changed, 3 deletions(-) diff --git a/VoodooPS2Keyboard/VoodooPS2Keyboard.cpp b/VoodooPS2Keyboard/VoodooPS2Keyboard.cpp index d0eff08b..11031077 100644 --- a/VoodooPS2Keyboard/VoodooPS2Keyboard.cpp +++ b/VoodooPS2Keyboard/VoodooPS2Keyboard.cpp @@ -1593,9 +1593,6 @@ bool ApplePS2Keyboard::dispatchKeyboardEventWithPacket(const UInt8* packet) dispatchKeyboardEventX(0x3b, false, now_abs); dispatchKeyboardEventX(0x7f, true, now_abs); dispatchKeyboardEventX(0x7f, false, now_abs); - - int val = 1; - _device->dispatchMessage(kPS2M_resetTouchpad, &val); // Reset touchpad } } break; From 071850a089de027dad3b1d372b3a2a53f5813016 Mon Sep 17 00:00:00 2001 From: naveenkrdy Date: Sun, 12 Jul 2020 01:00:03 +0530 Subject: [PATCH 003/101] add missing external references --- Docs/ACPI/SSDT-AlternateSwipes.dsl | 2 ++ Docs/ACPI/SSDT-DisableTrackpadProbe.dsl | 2 ++ Docs/ACPI/SSDT-Disable_DynamicEWMode.dsl | 2 ++ Docs/ACPI/SSDT-Enable_DynamicEWMode.dsl | 2 ++ Docs/ACPI/SSDT-HP-FixLidSleep.dsl | 2 ++ Docs/ACPI/SSDT-KEY-DELL-WN09.dsl | 2 ++ Docs/ACPI/SSDT-MouseAsTrackpad.dsl | 2 ++ Docs/ACPI/SSDT-PrtSc-F13.dsl | 2 ++ Docs/ACPI/SSDT-Swap-LeftControlCapsLock.dsl | 2 ++ Docs/ACPI/SSDT-Swap-LeftControlCommand.dsl | 2 ++ Docs/ACPI/SSDT-Thinkpad_Trackpad.dsl | 5 +++-- 11 files changed, 23 insertions(+), 2 deletions(-) diff --git a/Docs/ACPI/SSDT-AlternateSwipes.dsl b/Docs/ACPI/SSDT-AlternateSwipes.dsl index 701645d4..c03385c8 100644 --- a/Docs/ACPI/SSDT-AlternateSwipes.dsl +++ b/Docs/ACPI/SSDT-AlternateSwipes.dsl @@ -2,6 +2,8 @@ // instead of the Ctrl+Option+Arrows DefinitionBlock ("", "SSDT", 2, "ACDT", "ps2", 0) { + External (_SB_.PCI0.LPCB.PS2K, DeviceObj) + Name(_SB.PCI0.LPCB.PS2K.RMCF, Package() { "Keyboard", Package() diff --git a/Docs/ACPI/SSDT-DisableTrackpadProbe.dsl b/Docs/ACPI/SSDT-DisableTrackpadProbe.dsl index cb239b8c..df0519c8 100644 --- a/Docs/ACPI/SSDT-DisableTrackpadProbe.dsl +++ b/Docs/ACPI/SSDT-DisableTrackpadProbe.dsl @@ -5,6 +5,8 @@ // This can improve the reliability of VoodooPS2Mouse.kext and is more efficient as well. DefinitionBlock("", "SSDT", 2, "ACDT", "ps2", 0) { + External (_SB_.PCI0.LPCB.PS2K, DeviceObj) + Name(_SB.PCI0.LPCB.PS2K.RMCF, Package() { "Synaptics TouchPad", Package() diff --git a/Docs/ACPI/SSDT-Disable_DynamicEWMode.dsl b/Docs/ACPI/SSDT-Disable_DynamicEWMode.dsl index 75db07cc..bac74c44 100644 --- a/Docs/ACPI/SSDT-Disable_DynamicEWMode.dsl +++ b/Docs/ACPI/SSDT-Disable_DynamicEWMode.dsl @@ -1,5 +1,7 @@ DefinitionBlock ("", "SSDT", 2, "ACDT", "ps2", 0) { + External (_SB_.PCI0.LPCB.PS2K, DeviceObj) + Name(_SB.PCI0.LPCB.PS2K.RMCF, Package() { "Synaptics TouchPad", Package() diff --git a/Docs/ACPI/SSDT-Enable_DynamicEWMode.dsl b/Docs/ACPI/SSDT-Enable_DynamicEWMode.dsl index 41ef52f3..4566d29a 100644 --- a/Docs/ACPI/SSDT-Enable_DynamicEWMode.dsl +++ b/Docs/ACPI/SSDT-Enable_DynamicEWMode.dsl @@ -1,5 +1,7 @@ DefinitionBlock ("", "SSDT", 2, "ACDT", "ps2", 0) { + External (_SB_.PCI0.LPCB.PS2K, DeviceObj) + Name(_SB.PCI0.LPCB.PS2K.RMCF, Package() { "Synaptics TouchPad", Package() diff --git a/Docs/ACPI/SSDT-HP-FixLidSleep.dsl b/Docs/ACPI/SSDT-HP-FixLidSleep.dsl index 5af71a34..6aa4e9a3 100755 --- a/Docs/ACPI/SSDT-HP-FixLidSleep.dsl +++ b/Docs/ACPI/SSDT-HP-FixLidSleep.dsl @@ -3,6 +3,8 @@ // Make sure you verify _SB.PCI0.LPCB.PS2K ACPI path. DefinitionBlock ("", "SSDT", 2, "ACDT", "ps2", 0) { + External (_SB_.PCI0.LPCB.PS2K, DeviceObj) + Name(_SB.PCI0.LPCB.PS2K.RMCF, Package() { "Keyboard", Package() diff --git a/Docs/ACPI/SSDT-KEY-DELL-WN09.dsl b/Docs/ACPI/SSDT-KEY-DELL-WN09.dsl index 1fba5296..b60dcd5f 100644 --- a/Docs/ACPI/SSDT-KEY-DELL-WN09.dsl +++ b/Docs/ACPI/SSDT-KEY-DELL-WN09.dsl @@ -7,6 +7,8 @@ DefinitionBlock ("", "SSDT", 2, "ACDT", "ps2dell", 0) { + External (_SB_.PCI0.LPCB.PS2K, DeviceObj) + // Select Dell specific keyboard map in VoodooPS2Keyboard.kext Method(_SB.PCI0.LPCB.PS2K._DSM, 4) { diff --git a/Docs/ACPI/SSDT-MouseAsTrackpad.dsl b/Docs/ACPI/SSDT-MouseAsTrackpad.dsl index 99cbf9d0..4994d843 100644 --- a/Docs/ACPI/SSDT-MouseAsTrackpad.dsl +++ b/Docs/ACPI/SSDT-MouseAsTrackpad.dsl @@ -3,6 +3,8 @@ // enable a few extra features. DefinitionBlock("", "SSDT", 2, "ACDT", "ps2", 0) { + External (_SB_.PCI0.LPCB.PS2K, DeviceObj) + Name(_SB.PCI0.LPCB.PS2K.RMCF, Package() { "Mouse", Package() diff --git a/Docs/ACPI/SSDT-PrtSc-F13.dsl b/Docs/ACPI/SSDT-PrtSc-F13.dsl index 8df3f3f8..0b0cef0e 100755 --- a/Docs/ACPI/SSDT-PrtSc-F13.dsl +++ b/Docs/ACPI/SSDT-PrtSc-F13.dsl @@ -3,6 +3,8 @@ // via SysPrefs->Keyboard->Shortcuts DefinitionBlock ("", "SSDT", 2, "ACDT", "ps2", 0) { + External (_SB_.PCI0.LPCB.PS2K, DeviceObj) + Name(_SB.PCI0.LPCB.PS2K.RMCF, Package() { "Keyboard", Package() diff --git a/Docs/ACPI/SSDT-Swap-LeftControlCapsLock.dsl b/Docs/ACPI/SSDT-Swap-LeftControlCapsLock.dsl index 5ad51812..afe8d6ab 100644 --- a/Docs/ACPI/SSDT-Swap-LeftControlCapsLock.dsl +++ b/Docs/ACPI/SSDT-Swap-LeftControlCapsLock.dsl @@ -4,6 +4,8 @@ // For example, a Lenovo x1 Carbon 5th Gen would be "_SB.PCI0.LPCB.KBD.RMCF" DefinitionBlock ("", "SSDT", 2, "ACDT", "ps2", 0) { + External (_SB_.PCI0.LPCB.PS2K, DeviceObj) + Name(_SB.PCI0.LPCB.PS2K.RMCF, Package() { "Keyboard", Package() diff --git a/Docs/ACPI/SSDT-Swap-LeftControlCommand.dsl b/Docs/ACPI/SSDT-Swap-LeftControlCommand.dsl index e5f9ca53..d523721b 100755 --- a/Docs/ACPI/SSDT-Swap-LeftControlCommand.dsl +++ b/Docs/ACPI/SSDT-Swap-LeftControlCommand.dsl @@ -2,6 +2,8 @@ // and Command (left Alt) to Left Control. DefinitionBlock ("", "SSDT", 2, "ACDT", "ps2", 0) { + External (_SB_.PCI0.LPCB.PS2K, DeviceObj) + Name(_SB.PCI0.LPCB.PS2K.RMCF, Package() { "Keyboard", Package() diff --git a/Docs/ACPI/SSDT-Thinkpad_Trackpad.dsl b/Docs/ACPI/SSDT-Thinkpad_Trackpad.dsl index f5ea83b9..278ef104 100644 --- a/Docs/ACPI/SSDT-Thinkpad_Trackpad.dsl +++ b/Docs/ACPI/SSDT-Thinkpad_Trackpad.dsl @@ -1,8 +1,9 @@ // Example overrides for Thinkpad models with TrackPad DefinitionBlock ("", "SSDT", 2, "ACDT", "ps2", 0) { + External(_SB_.PCI0.LPCB.PS2K, DeviceObj) // Change _SB.PCI0.LPC.KBD if your PS2 keyboard is at a different ACPI path - External(_SB.PCI0.LPC.KBD, DeviceObj) + External(_SB_.PCI0.LPC.KBD, DeviceObj) Scope(_SB.PCI0.LPC.KBD) { // Select specific configuration in VoodooPS2Trackpad.kext @@ -54,4 +55,4 @@ DefinitionBlock ("", "SSDT", 2, "ACDT", "ps2", 0) }) } } -//EOF +//EOF \ No newline at end of file From ee051d3fd94e180e2a0e0af99c0ea666e672f656 Mon Sep 17 00:00:00 2001 From: Michael Belyaev Date: Sun, 12 Jul 2020 22:21:36 +0300 Subject: [PATCH 004/101] Allow unpressing keys when the keyboard is disable. Fix issue that Command key is left pressed when locking keyboard and trackpad with Command-PrtScr --- VoodooPS2Keyboard/VoodooPS2Keyboard.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VoodooPS2Keyboard/VoodooPS2Keyboard.cpp b/VoodooPS2Keyboard/VoodooPS2Keyboard.cpp index 11031077..67df5b43 100644 --- a/VoodooPS2Keyboard/VoodooPS2Keyboard.cpp +++ b/VoodooPS2Keyboard/VoodooPS2Keyboard.cpp @@ -1758,7 +1758,7 @@ bool ApplePS2Keyboard::dispatchKeyboardEventWithPacket(const UInt8* packet) } // If keyboard input is disabled drop the key code.. - if (_disableInput) + if (_disableInput && goingDown) keyCode=0; #ifdef DEBUG From 475e141edaaea3449ea12c902b0000ea8ca15504 Mon Sep 17 00:00:00 2001 From: Zhen <66577170+zhen-zen@users.noreply.github.com> Date: Sat, 4 Jul 2020 23:01:17 -0700 Subject: [PATCH 005/101] Ability to disable keyboard through message (from separate driver) --- VoodooPS2Controller/ApplePS2Device.h | 8 ++++++-- VoodooPS2Keyboard/VoodooPS2Keyboard.cpp | 17 +++++++++++++++++ 2 files changed, 23 insertions(+), 2 deletions(-) diff --git a/VoodooPS2Controller/ApplePS2Device.h b/VoodooPS2Controller/ApplePS2Device.h index 0b62a535..103b988b 100644 --- a/VoodooPS2Controller/ApplePS2Device.h +++ b/VoodooPS2Controller/ApplePS2Device.h @@ -524,10 +524,14 @@ enum kPS2M_setDisableTouchpad = iokit_vendor_specific_msg(100), // set disable/enable touchpad (data is bool*) kPS2M_getDisableTouchpad = iokit_vendor_specific_msg(101), // get disable/enable touchpad (data is bool*) kPS2M_notifyKeyPressed = iokit_vendor_specific_msg(102), // notify of time key pressed (data is PS2KeyInfo*) - + kPS2M_notifyKeyTime = iokit_vendor_specific_msg(110), // notify of timestamp a non-modifier key was pressed (data is uint64_t*) - + kPS2M_resetTouchpad = iokit_vendor_specific_msg(151), // Force touchpad reset (data is int*) + + // from sensor (such as yoga mode indicator) to keyboard + kPS2K_setDisableKeyboard = iokit_vendor_specific_msg(200), // set disable/enable keyboard (data is bool*) + kPS2K_getDisableKeyboard = iokit_vendor_specific_msg(201), // get disable/enable keyboard (data is bool*) }; typedef struct PS2KeyInfo diff --git a/VoodooPS2Keyboard/VoodooPS2Keyboard.cpp b/VoodooPS2Keyboard/VoodooPS2Keyboard.cpp index 67df5b43..b75ffd4b 100644 --- a/VoodooPS2Keyboard/VoodooPS2Keyboard.cpp +++ b/VoodooPS2Keyboard/VoodooPS2Keyboard.cpp @@ -1050,6 +1050,23 @@ IOReturn ApplePS2Keyboard::message(UInt32 type, IOService* provider, void* argum } } break; + + case kPS2K_getDisableKeyboard: + { + bool* pResult = (bool*)argument; + *pResult = _disableInput; + break; + } + + case kPS2K_setDisableKeyboard: + { + bool enable = *((bool*)argument); + if (enable == _disableInput) + { + _disableInput = !enable; + } + break; + } } return kIOReturnSuccess; From 75c962bb8808d4455846828d856d5179a6fbbe05 Mon Sep 17 00:00:00 2001 From: Zhen <66577170+zhen-zen@users.noreply.github.com> Date: Sun, 5 Jul 2020 00:00:04 -0700 Subject: [PATCH 006/101] Fix Clang Analyze; rename for less confusion --- VoodooPS2Controller/ApplePS2Device.h | 4 ++-- VoodooPS2Keyboard/VoodooPS2Keyboard.cpp | 22 ++++++++++++---------- 2 files changed, 14 insertions(+), 12 deletions(-) diff --git a/VoodooPS2Controller/ApplePS2Device.h b/VoodooPS2Controller/ApplePS2Device.h index 103b988b..1bf30a3f 100644 --- a/VoodooPS2Controller/ApplePS2Device.h +++ b/VoodooPS2Controller/ApplePS2Device.h @@ -530,8 +530,8 @@ enum kPS2M_resetTouchpad = iokit_vendor_specific_msg(151), // Force touchpad reset (data is int*) // from sensor (such as yoga mode indicator) to keyboard - kPS2K_setDisableKeyboard = iokit_vendor_specific_msg(200), // set disable/enable keyboard (data is bool*) - kPS2K_getDisableKeyboard = iokit_vendor_specific_msg(201), // get disable/enable keyboard (data is bool*) + kPS2K_setKeyboardStatus = iokit_vendor_specific_msg(200), // set disable/enable keyboard (data is bool*) + kPS2K_getKeyboardStatus = iokit_vendor_specific_msg(201), // get disable/enable keyboard (data is bool*) }; typedef struct PS2KeyInfo diff --git a/VoodooPS2Keyboard/VoodooPS2Keyboard.cpp b/VoodooPS2Keyboard/VoodooPS2Keyboard.cpp index b75ffd4b..08718119 100644 --- a/VoodooPS2Keyboard/VoodooPS2Keyboard.cpp +++ b/VoodooPS2Keyboard/VoodooPS2Keyboard.cpp @@ -1008,7 +1008,6 @@ IOReturn ApplePS2Keyboard::message(UInt32 type, IOService* provider, void* argum else IOLog("ApplePS2Keyboard::message: type=%x, provider=%p", type, provider); #endif - switch (type) { case kIOACPIMessageDeviceNotification: @@ -1051,24 +1050,27 @@ IOReturn ApplePS2Keyboard::message(UInt32 type, IOService* provider, void* argum } break; - case kPS2K_getDisableKeyboard: + case kPS2K_getKeyboardStatus: { - bool* pResult = (bool*)argument; - *pResult = _disableInput; + if (argument) { + bool* pResult = (bool*)argument; + *pResult = !_disableInput; + } break; } - case kPS2K_setDisableKeyboard: + case kPS2K_setKeyboardStatus: { - bool enable = *((bool*)argument); - if (enable == _disableInput) - { - _disableInput = !enable; + if (argument) { + bool enable = *((bool*)argument); + if (enable == _disableInput) + { + _disableInput = !enable; + } } break; } } - return kIOReturnSuccess; } From 60a4566c237f9c39bf38122ec8c0910a388dbe9d Mon Sep 17 00:00:00 2001 From: Michael Belyaev Date: Sun, 12 Jul 2020 22:27:52 +0300 Subject: [PATCH 007/101] Update Changelog.md --- Changelog.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Changelog.md b/Changelog.md index 8fa3399f..cf696167 100644 --- a/Changelog.md +++ b/Changelog.md @@ -1,5 +1,8 @@ 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 From 6883c221e68097e585212cfb8125364dc164fcdd Mon Sep 17 00:00:00 2001 From: vandroiy2013 Date: Mon, 3 Aug 2020 18:02:08 +0300 Subject: [PATCH 008/101] 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 009/101] 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 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 010/101] 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 9a8cd08f01de55071be4f4389102a8714809e6df Mon Sep 17 00:00:00 2001 From: vit9696 Date: Mon, 21 Sep 2020 04:37:58 +0300 Subject: [PATCH 011/101] Initial MacKernelSDK and Xcode 12 compatibility --- .gitignore | 1 + .travis.yml | 2 + Changelog.md | 3 + Library/LegacyIOHIDDevice.h | 753 -------- Library/LegacyIOHIKeyboard.h | 278 --- Library/LegacyIOHIPointing.h | 259 --- Library/LegacyIOService.h | 1721 ----------------- Library/LegacyLibkernMacros.h | 58 - Library/compat.cpp | 37 - Library/libkmod.a | Bin 1408 -> 0 bytes VoodooPS2Controller.xcodeproj/project.pbxproj | 104 +- VoodooPS2Controller/AppleACPIPS2Nub.h | 2 +- VoodooPS2Controller/ApplePS2Device.h | 2 +- VoodooPS2Controller/VoodooPS2Controller.cpp | 5 +- VoodooPS2Controller/VoodooPS2Controller.h | 2 +- VoodooPS2Keyboard/VoodooPS2Keyboard.cpp | 5 +- VoodooPS2Keyboard/VoodooPS2Keyboard.h | 5 +- VoodooPS2Mouse/VoodooPS2Mouse.cpp | 5 +- VoodooPS2Mouse/VoodooPS2Mouse.h | 5 +- VoodooPS2Trackpad/VoodooPS2ALPSGlidePoint.cpp | 2 +- VoodooPS2Trackpad/VoodooPS2ALPSGlidePoint.h | 2 +- VoodooPS2Trackpad/VoodooPS2SentelicFSP.cpp | 2 +- VoodooPS2Trackpad/VoodooPS2SentelicFSP.h | 2 +- .../VoodooPS2SynapticsTouchPad.cpp | 2 +- .../VoodooPS2SynapticsTouchPad.h | 2 +- 25 files changed, 48 insertions(+), 3211 deletions(-) delete mode 100644 Library/LegacyIOHIDDevice.h delete mode 100644 Library/LegacyIOHIKeyboard.h delete mode 100644 Library/LegacyIOHIPointing.h delete mode 100644 Library/LegacyIOService.h delete mode 100644 Library/LegacyLibkernMacros.h delete mode 100644 Library/compat.cpp delete mode 100755 Library/libkmod.a diff --git a/.gitignore b/.gitignore index c661a348..9a4e5a50 100644 --- a/.gitignore +++ b/.gitignore @@ -8,3 +8,4 @@ xcshareddata project.xcworkspace VoodooInput Lilu.kext +/MacKernelSDK diff --git a/.travis.yml b/.travis.yml index fd9de90a..11ce98dd 100644 --- a/.travis.yml +++ b/.travis.yml @@ -8,6 +8,7 @@ matrix: compiler: clang script: + - git clone https://github.com/acidanthera/MacKernelSDK - 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 @@ -29,6 +30,7 @@ matrix: compiler: clang script: + - git clone https://github.com/acidanthera/MacKernelSDK - 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")" = "" ] diff --git a/Changelog.md b/Changelog.md index 3264b86f..46214e84 100644 --- a/Changelog.md +++ b/Changelog.md @@ -1,5 +1,8 @@ VoodooPS2 Changelog ============================ +#### v2.1.8 +- Initial MacKernelSDK and Xcode 12 compatibility + #### 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 diff --git a/Library/LegacyIOHIDDevice.h b/Library/LegacyIOHIDDevice.h deleted file mode 100644 index c5b80b07..00000000 --- a/Library/LegacyIOHIDDevice.h +++ /dev/null @@ -1,753 +0,0 @@ -/* - * - * @APPLE_LICENSE_HEADER_START@ - * - * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved. - * - * This file contains Original Code and/or Modifications of Original Code - * as defined in and that are subject to the Apple Public Source License - * Version 2.0 (the 'License'). You may not use this file except in - * compliance with the License. Please obtain a copy of the License at - * http://www.opensource.apple.com/apsl/ and read it before using this - * file. - * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. - * Please see the License for the specific language governing rights and - * limitations under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ - -#ifndef _IOKIT_HID_IOHIDDEVICE_H -#define _IOKIT_HID_IOHIDDEVICE_H - -#include "LegacyIOService.h" -#include -#include -#include -#include -#include -#include - -class IOHIDSystem; -class IOHIDPointing; -class IOHIDKeyboard; -class IOHIDConsumer; -class IOHIDElementPrivate; -class IOHIDEventQueue; -class IOHIDInterface; -class IOHIDDeviceShim; -struct IOHIDReportHandler; -class IOHIDAsyncReportQueue; - -/*! - @typedef IOHIDCompletionAction - @abstract Function called when set/get report completes - @param target The target specified in the IOHIDCompletion struct. - @param parameter The parameter specified in the IOHIDCompletion struct. - @param status Completion status -*/ -typedef void (*IOHIDCompletionAction)( - void * target, - void * parameter, - IOReturn status, - UInt32 bufferSizeRemaining); - -#ifndef __MAC_10_15 -/*! - @typedef IOHIDCompletion - @abstract Struct spefifying action to perform when set/get report completes. - @var target The target to pass to the action function. - @var action The function to call. - @var parameter The parameter to pass to the action function. -*/ -typedef struct IOHIDCompletion { - void * target; - IOHIDCompletionAction action; - void * parameter; -} IOHIDCompletion; - -/*! - @enum IOHIDReportOption - @abstract Option bits for IOHIDDevice::handleReport, - IOHIDDevice::getReport, and IOHIDDevice::setReport - @constant kIOHIDReportOptionNotInterrupt Tells method that the report - passed was not interrupt driven. -*/ -enum -{ - kIOHIDReportOptionNotInterrupt = 0x100, - kIOHIDReportOptionVariableSize = 0x200 -}; -#endif - - -/*! @class IOHIDDevice : public IOService - @abstract IOHIDDevice defines a Human Interface Device (HID) object, - which will interact with the HID Manager by publishing static properties - in the registry, and also by reporting HID events through shared memory. - IOHIDDevice is an abstract class that must be subclassed to support a - specific type of HID devices, such as USB HID class devices. -
- Since most HID devices are expected to be USB devices, IOHIDDevice - uses the USB HID specification to define the format of the report - descriptor, and also reports that are used to communicate with the - hardware via some intervening transport layer. However, there is no - mandate that the transport layer must be restricted to USB. A subclass - may be created to support legacy ADB joysticks, and issue packets on - the ADB bus and translate those packets to USB reports, and vice versa. - IOHIDDevice does not care how those reports are generated or consumed - by the physical device, as long as the reports abide to the USB - specification. */ - -class IOHIDDevice : public IOService -{ - OSDeclareDefaultStructors( IOHIDDevice ) - - friend class IOHIDLibUserClient; - friend class IOHIDDeviceShim; - -private: - OSArray * _elementArray; - UInt32 _dataElementIndex; - IORecursiveLock * _elementLock; - IOHIDReportHandler * _reportHandlers; - IOBufferMemoryDescriptor * _elementValuesDescriptor; - bool _readyForInputReports; - UInt32 _reportCount; - UInt32 _maxInputReportSize; - UInt32 _maxOutputReportSize; - UInt32 _maxFeatureReportSize; - - struct ExpansionData { - OSSet * clientSet; - IOService * seizedClient; - AbsoluteTime eventDeadline; - OSArray * inputInterruptElementArray; - bool performTickle; - bool performWakeTickle; - OSArray * interfaceNubs; - IOHIDElementPrivate * rollOverElement; - OSArray * hierarchElements; - OSArray * interfaceElementArrays; - IOHIDAsyncReportQueue * asyncReportQueue; - IOWorkLoop * workLoop; - IOEventSource * eventSource; - IONotifier * deviceNotify; - }; - /*! @var reserved - Reserved for future use. (Internal use only) */ - ExpansionData * _reserved; - - // HID report descriptor parsing support. - - bool linkToParent( const OSArray * array, - UInt32 parentIndex, - UInt32 childIndex ); - - bool createCollectionElements( HIDPreparsedDataRef parseData, - OSArray * array, - UInt32 maxCount ); - - bool createValueElements( HIDPreparsedDataRef parseData, - OSArray * array, - UInt32 hidReportType, - IOHIDElementType elementType, - UInt32 maxCount ); - - bool createButtonElements( HIDPreparsedDataRef parseData, - OSArray * array, - UInt32 hidReportType, - IOHIDElementType elementType, - UInt32 maxCount ); - - bool createReportHandlerElements( HIDPreparsedDataRef parseData); - - bool getReportCountAndSizes( HIDPreparsedDataRef parseData ); - - bool setReportSize( UInt8 reportID, - IOHIDReportType reportType, - UInt32 bits ); - - IOReturn createElementHierarchy( HIDPreparsedDataRef parseData ); - - IOReturn parseReportDescriptor( IOMemoryDescriptor * report, - IOOptionBits options = 0 ); - - IOBufferMemoryDescriptor * createMemoryForElementValues(); - - OSNumber * newPrimaryUsageNumber(UInt32 interfaceIdx) const; - - OSNumber * newPrimaryUsagePageNumber(UInt32 interfaceIdx) const; - - OSArray * newDeviceUsagePairs(OSArray * elements, UInt32 start); - - static bool _publishDeviceNotificationHandler(void * target, - void * refCon, - IOService * newService, - IONotifier * notifier ); - -protected: - -/*! @function free - @abstract Free the IOHIDDevice object. - @discussion Release all resources that were previously allocated, - then call super::free() to propagate the call to our superclass. */ - - virtual void free() APPLE_KEXT_OVERRIDE; - -/*! @function handleOpen - @abstract Handle a client open on the interface. - @discussion This method is called by IOService::open() with the - arbitration lock held, and must return true to accept the client open. - This method will in turn call handleClientOpen() to qualify the client - requesting the open. - @param client The client object that requested the open. - @param options Options passed to IOService::open(). - @param argument Argument passed to IOService::open(). - @result true to accept the client open, false otherwise. */ - - virtual bool handleOpen(IOService * client, - IOOptionBits options, - void * argument) APPLE_KEXT_OVERRIDE; - -/*! @function handleClose - @abstract Handle a client close on the interface. - @discussion This method is called by IOService::close() with the - arbitration lock held. This method will in turn call handleClientClose() - to notify interested subclasses about the client close. If this represents - the last close, then the interface will also close the controller before - this method returns. The controllerWillClose() method will be called before - closing the controller. Subclasses should not override this method. - @param client The client object that requested the close. - @param options Options passed to IOService::close(). */ - - virtual void handleClose(IOService * client, IOOptionBits options) APPLE_KEXT_OVERRIDE; - -/*! @function handleIsOpen - @abstract Query whether a client has an open on the interface. - @discussion This method is always called by IOService with the - arbitration lock held. Subclasses should not override this method. - @result true if the specified client, or any client if none (0) is - specified, presently has an open on this object. */ - - virtual bool handleIsOpen(const IOService * client) const APPLE_KEXT_OVERRIDE; - -/*! @function handleStart - @abstract Prepare the hardware and driver to support I/O operations. - @discussion IOHIDDevice will call this method from start() before - any I/O operations are issued to the concrete subclass. Methods - such as newReportDescriptor() are only called after handleStart() - has returned true. A subclass that overrides this method should - begin its implementation by calling the version in super, and - then check the return value. - @param provider The provider argument passed to start(). - @result True on success, or false otherwise. Returning false will - cause start() to fail and return false. */ - - virtual bool handleStart( IOService * provider ); - -/*! @function handleStop - @abstract Quiesce the hardware and stop the driver. - @discussion IOHIDDevice will call this method from stop() to - signal that the hardware should be quiesced and the driver stopped. - A subclass that overrides this method should end its implementation - by calling the version in super. - @param provider The provider argument passed to stop(). */ - - virtual void handleStop( IOService * provider ); - -/*! @function newUserClient - @abstract Handle a request to create a connection for a non kernel - client. - @discussion Create a new IOUserClient, or a subclass of IOUserClient, - to service a connection to a non kernel client. This implementation - will simply call the implementation in IOService to handle the call. - @param owningTask The mach task requesting the connection. - @param security_id A token representing the access level for the task. - @param type A constant specifying the type of connection to be created. - @param properties A dictionary of additional properties for the connection. - @param handler The IOUserClient object returned. - @result The return from IOService::newUserClient() is returned. */ - - virtual IOReturn newUserClient( task_t owningTask, - void * security_id, - UInt32 type, - OSDictionary * properties, - IOUserClient ** handler ) APPLE_KEXT_OVERRIDE; - IOReturn newUserClientInternal(task_t owningTask, - void * security_id, - OSDictionary * properties, - IOUserClient ** handler ); - -/*! @function publishProperties - @abstract Publish HID properties to the I/O Kit registry. - @discussion Called by the start() method to fetch and publish all - HID properties to the I/O Kit registry. These properties will allow - the HID Manager to identify all HID device(s) in the system, by - iterating through objects that are subclasses of IOHIDDevice, and - then fetch their published property values. The implementation in - IOHIDDevice will call methods to get each individual HID property, - and subclasses will not normally need to override this method. - @param provider The provider argument passed to start(). - @result True to indicate that all properties were discovered and - published to the registry, false otherwise. Returning false will - cause start() to fail and return false. */ - - virtual bool publishProperties( IOService * provider ); - -public: - -/*! @function init - @abstract Initialize an IOHIDDevice object. - @discussion Prime the IOHIDDevice object and prepare it to support - a probe() or a start() call. This implementation will simply call - super::init(). - @param dictionary A dictionary associated with this IOHIDDevice - instance. - @result True on sucess, or false otherwise. */ - - virtual bool init( OSDictionary * dictionary = 0 ) APPLE_KEXT_OVERRIDE; - -/*! @function start - @abstract Start up the driver using the given provider. - @discussion IOHIDDevice will allocate resources, then call handleStart() - before fetching the report descriptor through newReportDescriptor(), and - publishing HID properties to the registry. Before returning true to - indicate success, registerService() is called to trigger client matching. - Subclasses are recommended to override handleStart(). - @param provider The provider that the driver was matched to, and selected - to run with. - @result True on success, or false otherwise. */ - - virtual bool start( IOService * provider ) APPLE_KEXT_OVERRIDE; - -/*! @function stop - @abstract Called by a provider (during its termination) before detaching - all its clients. - @discussion IOHIDDevice will call handleStop(), then release allocated - resources. Subclasses are recommended to override handleStop(). - @param provider The provider that the driver was started on. */ - - virtual void stop( IOService * provider ) APPLE_KEXT_OVERRIDE; - -/*! @function matchPropertyTable - @abstract Called by the provider during a match - @discussion Compare the properties in the supplied table to this - object's properties. - @param table The property table that this device will match against -*/ - - virtual bool matchPropertyTable(OSDictionary * table, SInt32 * score) APPLE_KEXT_OVERRIDE; - -/*! @function message - @abstract Receives messages delivered from an attached provider. - @discussion Handles the kIOMessageDeviceSignaledWakeup message - from a provider identifying the IOHIDDevice as the wakeup source. - @param type A type defined in IOMessage.h. - @param provider The provider from which the message originates. - @param argument An argument defined by the message type. - @result An IOReturn code defined by the message type. -*/ - - virtual IOReturn message( UInt32 type, IOService * provider, void * argument = 0 ) APPLE_KEXT_OVERRIDE; - -/*! @function newTransportString - @abstract Returns a string object that describes the transport - layer used by the HID device. - @result A string object. The caller must decrement the retain count - on the object returned. */ - - virtual OSString * newTransportString() const; - -/*! @function newManufacturerString - @abstract Returns a string object that describes the manufacturer - of the HID device. - @result A string object. The caller must decrement the retain count - on the object returned. */ - - virtual OSString * newManufacturerString() const; - -/*! @function newProductString - @abstract Returns a string object that describes the product - of the HID device. - @result A string object. The caller must decrement the retain count - on the object returned. */ - - virtual OSString * newProductString() const; - -/*! @function newVendorIDNumber - @abstract Returns a number object that describes the vendor ID - of the HID device. - @result A number object. The caller must decrement the retain count - on the object returned. */ - - virtual OSNumber * newVendorIDNumber() const; - -/*! @function newProductIDNumber - @abstract Returns a number object that describes the product ID - of the HID device. - @result A number object. The caller must decrement the retain count - on the object returned. */ - - virtual OSNumber * newProductIDNumber() const; - -/*! @function newVersionNumber - @abstract Returns a number object that describes the version number - of the HID device. - @result A number object. The caller must decrement the retain count - on the object returned. */ - - virtual OSNumber * newVersionNumber() const; - -// *** THIS HAS BEEN DEPRECATED. PLEASE USE newSerialNumberString *** -/*! @function newSerialNumber - @abstract THIS HAS BEEN DEPRECATED. PLEASE USE newSerialNumberString. - @result A number object. The caller must decrement the retain count - on the object returned. */ - - virtual OSNumber * newSerialNumber() const; - -/*! @function newPrimaryUsageNumber - @abstract Returns a number object that describes the primary usage - of the HID device. - @result A number object. The caller must decrement the retain count - on the object returned. */ - - virtual OSNumber * newPrimaryUsageNumber() const; - -/*! @function newPrimaryUsagePageNumber - @abstract Returns a number object that describes the primary usage - page of the HID device. - @result A number object. The caller must decrement the retain count - on the object returned. */ - - virtual OSNumber * newPrimaryUsagePageNumber() const; - -/*! @function newReportDescriptor - @abstract Create and return a new memory descriptor that describes the - report descriptor for the HID device. - @discussion A subclass must override this pure virtual function, and - return a memory descriptor that describes the HID report descriptor as - defined by the USB Device Class Definition for Human Interface Devices - Version 1.1 specification. - @param descriptor Pointer to the memory descriptor returned. This - memory descriptor will be released by the caller. - @result kIOReturnSuccess on success, or an error return otherwise. */ - - virtual IOReturn newReportDescriptor( - IOMemoryDescriptor ** descriptor ) const = 0; - -/*! @function handleReport - @abstract Handle an asynchronous report received from the HID device. - @param report A memory descriptor that describes the report. - @param reportType The type of report. - @param options Options to specify the request. No options are - currently defined, and the default value is 0. - @result kIOReturnSuccess on success, or an error return otherwise. */ - - virtual IOReturn handleReport( - IOMemoryDescriptor * report, - IOHIDReportType reportType = kIOHIDReportTypeInput, - IOOptionBits options = 0 ); - -/*! @function getReport - @abstract Get a report from the HID device. - @discussion A completion parameter may be added in the future. - @param report A memory descriptor that describes the memory to store - the report read from the HID device. - @param reportType The report type. - @param options The lower 8 bits will represent the Report ID. The - other 24 bits are options to specify the request. - @result kIOReturnSuccess on success, or an error return otherwise. */ - - virtual IOReturn getReport( IOMemoryDescriptor * report, - IOHIDReportType reportType, - IOOptionBits options ); - -/*! @function setReport - @abstract Send a report to the HID device. - @discussion A completion parameter may be added in the future. - @param report A memory descriptor that describes the report to send - to the HID device. - @param reportType The report type. - @param options The lower 8 bits will represent the Report ID. The - other 24 bits are options to specify the request. - @result kIOReturnSuccess on success, or an error return otherwise. */ - - virtual IOReturn setReport( IOMemoryDescriptor * report, - IOHIDReportType reportType, - IOOptionBits options = 0 ); - -/*! @function getMemoryWithCurrentElementValues - @abstract Get a reference to a memory descriptor that describes the - memory block containing the current HID element values. - @discussion Each HID element that can contribute to an input, output, - or feature report, is assigned an area of memory from a common memory - block allocated by IOHIDDevice. Each element will use its assigned - memory area to store its current value, defined by an IOHIDElementValue - structure. The memory described by the memory descriptor may be mapped - to user space to allow the HID Manager to poll the current element - value without the cost of a user-kernel transition. Subclasses should - not override this method. - @result A reference to a memory descriptor that describes the current - element values, or 0 to indicate a resource shortage. */ - - virtual IOMemoryDescriptor * getMemoryWithCurrentElementValues() const; - -/*! @function registerElement - @abstract A registration function called by a HID element to register - itself, and also to obtain an unique cookie identifier - (unique per device, not unique system-wide). - @discussion An internal data type, an IOHIDElementPrivate, is created to - represent each HID element discovered by parsing the HID report - descriptor. Each element created will call this method to register - itself with its owner (IOHIDDevice), and also to obtain an element - cookie that is used by HID Manager to specify and identify the element. - Subclasses should not override this method. - @param element The element that is requesting registration with its - owner. - @param cookie Pointer to the returned cookie assigned to this element. - @result True on success, or false otherwise. */ - - virtual bool registerElement( IOHIDElementPrivate * element, - IOHIDElementCookie * cookie ); - -/*! @function startEventDelivery - @abstract Start delivering events from a HID element to the event - queue specified. - @discussion Clients of IOHIDDevice may create an IOHIDEventQueue, and - then call this method to register for delivery of events generated by - one or more HID elements to that event queue. Subclasses should not - override this method. - @param queue The event queue that is interested in receiving events - generated by the HID element specified. The retain count on the queue - will be incremented by one. - @param cookie The cookie for a HID element published by the HID device. - @param options Options to specify the request. No options are currently - defined, and the default value is zero. - @result kIOReturnSuccess on success, or kIOReturnBadArgument if the - queue or the cookie argument specified is invalid, or kIOReturnNoMemory - if a resource shortage was encountered. */ - - virtual IOReturn startEventDelivery( IOHIDEventQueue * queue, - IOHIDElementCookie cookie, - IOOptionBits options = 0 ); - -/*! @function stopEventDelivery - @abstract Stop delivering events from one or more HID elements to the - event queue specified. - @discussion Clients that called startEventDelivery() must eventually - call this method to stop event delivery to its queue from one or more - HID elements. - @param queue The event queue that no longer wishes to receive events - generated by the HID element specified. - @param cookie The cookie for a HID element published by the HID device. - The default value of zero indicates that the queue should be removed from - the event dispatch list of all HID elements published by the HID device. - Subclasses should not override this method. - @result kIOReturnSuccess if the queue was removed from the event dispatch - list for one or more HID elements, or kIOReturnBadArgument if the queue - or the cookie argument specified is invalid, or kIOReturnNotFound if the - queue was not found. */ - - virtual IOReturn stopEventDelivery( IOHIDEventQueue * queue, - IOHIDElementCookie cookie = 0 ); - -/*! @function checkEventDelivery - @abstract Check whether events from a HID element will be delivered to - the event queue specified. - @param queue The event queue. - @param cookie The cookie for a HID element published by the HID device. - @param isActive Pointer to the return value that is set to true if events - generated by the HID element will be delivered to the queue, or false - otherwise. This return value is set only if kIOReturnSuccess is - returned. - @result kIOReturnSuccess on success, or kIOReturnBadArgument if one or - more of the arguments provided are invalid. */ - - virtual IOReturn checkEventDelivery( IOHIDEventQueue * queue, - IOHIDElementCookie cookie, - bool * isActive ); - -/*! @function updateElementValues - @abstract Updates element values from a HID device via getReport. - @discussion A completion parameter may be added in the future. - @param cookies A list of element cookies who's values need to be - set on the device. - @param cookieCount The number of element cookies. - @result kIOReturnSuccess on success, or an error return otherwise. */ - OSMetaClassDeclareReservedUsed(IOHIDDevice, 0); - virtual IOReturn updateElementValues(IOHIDElementCookie * cookies, UInt32 cookieCount = 1); - -/*! @function postElementValues - @abstract Posts element values to a HID device via setReport. - @discussion A completion parameter may be added in the future. - @param cookies A list of element cookies who's values need to be - set on the device. - @param cookieCount The number of element cookies. - @result kIOReturnSuccess on success, or an error return otherwise. */ - OSMetaClassDeclareReservedUsed(IOHIDDevice, 1); - virtual IOReturn postElementValues(IOHIDElementCookie * cookies, UInt32 cookieCount = 1); - -/*! @function newSerialNumberString - @abstract Returns a string object that describes the serial number - of the HID device. - @result A number object. The caller must decrement the retain count - on the object returned. */ - OSMetaClassDeclareReservedUsed(IOHIDDevice, 2); - virtual OSString * newSerialNumberString() const; - -/*! @function newLocationIDNumber - @abstract Returns a number object that describes the location ID - of the HID device. - @result A number object. The caller must decrement the retain count - on the object returned. */ - OSMetaClassDeclareReservedUsed(IOHIDDevice, 3); - virtual OSNumber * newLocationIDNumber() const; - -/*! @function getReport - @abstract Get a report from the HID device. - @discussion A completion parameter may be added in the future. - @param report A memory descriptor that describes the memory to store - the report read from the HID device. - @param reportType The report type. - @param options The lower 8 bits will represent the Report ID. The - other 24 bits are options to specify the request. - @param completionTimeout Specifies an amount of time (in ms) after which - the command will be aborted if the entire command has not been completed. - @param completion Function to call when request completes. If omitted then - getReport() executes synchronously, blocking until the request is complete. - @result kIOReturnSuccess on success, or an error return otherwise. */ - - OSMetaClassDeclareReservedUsed(IOHIDDevice, 4); - virtual IOReturn getReport( IOMemoryDescriptor * report, - IOHIDReportType reportType, - IOOptionBits options, - UInt32 completionTimeout, - IOHIDCompletion * completion = 0); - -/*! @function setReport - @abstract Send a report to the HID device. - @discussion A completion parameter may be added in the future. - @param report A memory descriptor that describes the report to send - to the HID device. - @param reportType The report type. - @param options The lower 8 bits will represent the Report ID. The - other 24 bits are options to specify the request. - @param completionTimeout Specifies an amount of time (in ms) after which - the command will be aborted if the entire command has not been completed. - @param completion Function to call when request completes. If omitted then - setReport() executes synchronously, blocking until the request is complete. - @result kIOReturnSuccess on success, or an error return otherwise. */ - - OSMetaClassDeclareReservedUsed(IOHIDDevice, 5); - virtual IOReturn setReport( IOMemoryDescriptor * report, - IOHIDReportType reportType, - IOOptionBits options, - UInt32 completionTimeout, - IOHIDCompletion * completion = 0); - -/*! @function newVendorIDSourceNumber - @abstract Returns a number object that describes the vendor ID - source of the HID device. - @result A number object. The caller must decrement the retain count - on the object returned. */ - OSMetaClassDeclareReservedUsed(IOHIDDevice, 6); - virtual OSNumber * newVendorIDSourceNumber() const; - -/*! @function newCountryCodeNumber - @abstract Returns a number object that describes the country code - of the HID device. - @result A number object. The caller must decrement the retain count - on the object returned. */ - OSMetaClassDeclareReservedUsed(IOHIDDevice, 7); - virtual OSNumber * newCountryCodeNumber() const; - - -/*! @function handleReportWithTime - @abstract Handle an asynchronous report received from the HID device. - @param timeStamp The timestamp of report. - @param report A memory descriptor that describes the report. - @param reportType The type of report. Currently, only - kIOHIDReportTypeInput report type is handled. - @param options Options to specify the request. No options are - currently defined, and the default value is 0. - @result kIOReturnSuccess on success, or an error return otherwise. */ - - OSMetaClassDeclareReservedUsed(IOHIDDevice, 8); - virtual IOReturn handleReportWithTime( - AbsoluteTime timeStamp, - IOMemoryDescriptor * report, - IOHIDReportType reportType = kIOHIDReportTypeInput, - IOOptionBits options = 0); - -/*! @function newReportInterval - @abstract Returns a number object that describes the actual polling - interval of the HID device in microseconds. - @result A number object. The caller must decrement the retain count - on the object returned. */ - OSMetaClassDeclareReservedUsed(IOHIDDevice, 9); - virtual OSNumber * newReportIntervalNumber() const; - - OSMetaClassDeclareReservedUsed(IOHIDDevice, 10); - virtual IOReturn handleReportWithTimeAsync( - AbsoluteTime timeStamp, - IOMemoryDescriptor * report, - IOHIDReportType reportType, - IOOptionBits options, - UInt32 completionTimeout, - IOHIDCompletion * completion); - -/*! @function newDeviceUsagePairs - @abstract Returns an array of usage dictionaries. IOHIDDevice creates - create this from the actual report descriptor, and that should be the base - for any subclass override. - @result A number object. The caller must decrement the retain count - on the object returned. */ - OSMetaClassDeclareReservedUsed(IOHIDDevice, 11); - virtual OSArray * newDeviceUsagePairs(); - -protected: - /*! @function createInterface - @abstract Creates an IOHIDInterface nub for the device to attach to. - @discussion Will create multiple interfaces, if applicable and support is - enabled. - @result true on success, false otherwise. */ - OSMetaClassDeclareReservedUnused(IOHIDDevice, 12); - OSMetaClassDeclareReservedUnused(IOHIDDevice, 13); - OSMetaClassDeclareReservedUnused(IOHIDDevice, 14); - OSMetaClassDeclareReservedUnused(IOHIDDevice, 15); - OSMetaClassDeclareReservedUnused(IOHIDDevice, 16); - OSMetaClassDeclareReservedUnused(IOHIDDevice, 17); - OSMetaClassDeclareReservedUnused(IOHIDDevice, 18); - OSMetaClassDeclareReservedUnused(IOHIDDevice, 19); - OSMetaClassDeclareReservedUnused(IOHIDDevice, 20); - OSMetaClassDeclareReservedUnused(IOHIDDevice, 21); - OSMetaClassDeclareReservedUnused(IOHIDDevice, 22); - OSMetaClassDeclareReservedUnused(IOHIDDevice, 23); - OSMetaClassDeclareReservedUnused(IOHIDDevice, 24); - OSMetaClassDeclareReservedUnused(IOHIDDevice, 25); - OSMetaClassDeclareReservedUnused(IOHIDDevice, 26); - OSMetaClassDeclareReservedUnused(IOHIDDevice, 27); - OSMetaClassDeclareReservedUnused(IOHIDDevice, 28); - OSMetaClassDeclareReservedUnused(IOHIDDevice, 29); - OSMetaClassDeclareReservedUnused(IOHIDDevice, 30); - OSMetaClassDeclareReservedUnused(IOHIDDevice, 31); - OSMetaClassDeclareReservedUnused(IOHIDDevice, 32); - OSMetaClassDeclareReservedUnused(IOHIDDevice, 33); - OSMetaClassDeclareReservedUnused(IOHIDDevice, 34); - OSMetaClassDeclareReservedUnused(IOHIDDevice, 35); - OSMetaClassDeclareReservedUnused(IOHIDDevice, 36); - OSMetaClassDeclareReservedUnused(IOHIDDevice, 37); - OSMetaClassDeclareReservedUnused(IOHIDDevice, 38); - OSMetaClassDeclareReservedUnused(IOHIDDevice, 39); - OSMetaClassDeclareReservedUnused(IOHIDDevice, 40); - -}; - -#endif /* !_IOKIT_HID_IOHIDDEVICE_H */ diff --git a/Library/LegacyIOHIKeyboard.h b/Library/LegacyIOHIKeyboard.h deleted file mode 100644 index 9e40c47d..00000000 --- a/Library/LegacyIOHIKeyboard.h +++ /dev/null @@ -1,278 +0,0 @@ -/* - * @APPLE_LICENSE_HEADER_START@ - * - * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved. - * - * This file contains Original Code and/or Modifications of Original Code - * as defined in and that are subject to the Apple Public Source License - * Version 2.0 (the 'License'). You may not use this file except in - * compliance with the License. Please obtain a copy of the License at - * http://www.opensource.apple.com/apsl/ and read it before using this - * file. - * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. - * Please see the License for the specific language governing rights and - * limitations under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ -/* Copyright (c) 1992 NeXT Computer, Inc. All rights reserved. - * - * EventSrcPCKeyboard.h - PC Keyboard EventSrc subclass definition - * - * HISTORY - * 28 Aug 1992 Joe Pasqua - * Created. - */ - -#ifndef _IOHIKEYBOARD_H -#define _IOHIKEYBOARD_H - -#include "LegacyIOService.h" - -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Winconsistent-missing-override" -#include -#include -#pragma clang diagnostic pop - -/* Start Action Definitions */ - -/* - * HISTORICAL NOTE: - * The following entry points were part of the IOHIKeyboardEvents - * protocol. - */ - -typedef void (*KeyboardEventAction)( OSObject * target, - /* eventFlags */ unsigned eventType, - /* flags */ unsigned flags, - /* keyCode */ unsigned key, - /* charCode */ unsigned charCode, - /* charSet */ unsigned charSet, - /* originalCharCode */ unsigned origCharCode, - /* originalCharSet */ unsigned origCharSet, - /* keyboardType */ unsigned keyboardType, - /* repeat */ bool repeat, - /* atTime */ AbsoluteTime ts); - -typedef void (*KeyboardSpecialEventAction)(OSObject * target, - /* eventType */ unsigned eventType, - /* flags */ unsigned flags, - /* keyCode */ unsigned key, - /* specialty */ unsigned flavor, - /* source id */ UInt64 guid, - /* repeat */ bool repeat, - /* atTime */ AbsoluteTime ts); - -typedef void (*UpdateEventFlagsAction)( OSObject * target, - /* flags */ unsigned flags); - -/* Event Callback Definitions */ - -typedef void (*KeyboardEventCallback)( - /* target */ OSObject * target, - /* eventFlags */ unsigned eventType, - /* flags */ unsigned flags, - /* keyCode */ unsigned key, - /* charCode */ unsigned charCode, - /* charSet */ unsigned charSet, - /* originalCharCode */ unsigned origCharCode, - /* originalCharSet */ unsigned origCharSet, - /* keyboardType */ unsigned keyboardType, - /* repeat */ bool repeat, - /* atTime */ AbsoluteTime ts, - /* sender */ OSObject * sender, - /* refcon */ void * refcon); - -typedef void (*KeyboardSpecialEventCallback)( - /* target */ OSObject * target, - /* eventType */ unsigned eventType, - /* flags */ unsigned flags, - /* keyCode */ unsigned key, - /* specialty */ unsigned flavor, - /* source id */ UInt64 guid, - /* repeat */ bool repeat, - /* atTime */ AbsoluteTime ts, - /* sender */ OSObject * sender, - /* refcon */ void * refcon); - -typedef void (*UpdateEventFlagsCallback)( - /* target */ OSObject * target, - /* flags */ unsigned flags, - /* sender */ OSObject * sender, - /* refcon */ void * refcon); - -/* End Action Definitions */ - -/* Default key repeat parameters */ -#define EV_DEFAULTINITIALREPEAT 500000000ULL // 1/2 sec in nanoseconds -#define EV_DEFAULTKEYREPEAT 83333333ULL // 1/12 sec in nanoseconds -#define EV_MINKEYREPEAT 16700000ULL // 1/60 sec - -class IOHIKeyboard : public IOHIDevice -{ - OSDeclareDefaultStructors(IOHIKeyboard); - - friend class IOHIDKeyboardDevice; - friend class IOHIDKeyboardEventDevice; - friend class IOHIDKeyboard; - friend class IOHIDConsumer; - -protected: - IOLock * _deviceLock; // Lock for all device access - IOHIKeyboardMapper * _keyMap; // KeyMap instance - - // The following fields describe the kind of keyboard - UInt32 _interfaceType; - UInt32 _deviceType; - - // The following fields describe the state of the keyboard - UInt32 * _keyState; // kbdBitVector - IOByteCount _keyStateSize; // kbdBitVector allocated size - unsigned _eventFlags; // Current eventFlags - bool _alphaLock; // true means alpha lock is on - bool _numLock; // true means num lock is on - bool _charKeyActive; // true means char gen. key active - - // The following fields are used in performing key repeats - bool _isRepeat; // true means we're generating repeat - unsigned _codeToRepeat; // What we are repeating - bool _calloutPending; // true means we've sched. a callout - AbsoluteTime _lastEventTime; // Time last event was dispatched - AbsoluteTime _downRepeatTime; // Time when we should next repeat - AbsoluteTime _keyRepeat; // Delay between key repeats - AbsoluteTime _initialKeyRepeat; // Delay before initial key repeat - UInt64 _guid; - - OSObject * _keyboardEventTarget; - KeyboardEventAction _keyboardEventAction; - OSObject * _keyboardSpecialEventTarget; - KeyboardSpecialEventAction _keyboardSpecialEventAction; - OSObject * _updateEventFlagsTarget; - UpdateEventFlagsAction _updateEventFlagsAction; - - UInt16 _lastUsagePage; - UInt16 _lastUsage; - -protected: - virtual void dispatchKeyboardEvent(unsigned int keyCode, - /* direction */ bool goingDown, - /* timeStamp */ AbsoluteTime time); - void setLastPageAndUsage(UInt16 usagePage, UInt16 usage); - void getLastPageAndUsage(UInt16 &usagePage, UInt16 &usage); - void clearLastPageAndUsage(); - -public: - virtual bool init(OSDictionary * properties = 0) override; - virtual bool start(IOService * provider) override; - virtual void stop(IOService * provider) override; - virtual void free() override; - - virtual bool open(IOService * client, - IOOptionBits options, - KeyboardEventAction keAction, - KeyboardSpecialEventAction kseAction, - UpdateEventFlagsAction uefAction); - - bool open( IOService * client, - IOOptionBits options, - void *, - KeyboardEventCallback keCallback, - KeyboardSpecialEventCallback kseCallback, - UpdateEventFlagsCallback uefCallback); - - virtual void close(IOService * client, IOOptionBits ) override; - - virtual IOReturn message( UInt32 type, IOService * provider, - void * argument = 0 ) override; - - virtual IOHIDKind hidKind() override; - virtual bool updateProperties( void ) override; - virtual IOReturn setParamProperties(OSDictionary * dict) override; - virtual IOReturn setProperties( OSObject * properties ) override; - - inline bool isRepeat() {return _isRepeat;} - -protected: // for subclasses to implement - virtual const unsigned char * defaultKeymapOfLength(UInt32 * length); - virtual void setAlphaLockFeedback(bool val); - virtual void setNumLockFeedback(bool val); - virtual UInt32 maxKeyCodes(); - - -private: - virtual bool resetKeyboard(); - virtual void scheduleAutoRepeat(); - static void _autoRepeat(void * arg, void *); - virtual void autoRepeat(); - virtual void setRepeat(unsigned eventType, unsigned keyCode); - void setRepeatMode(bool repeat); - static void _createKeyboardNub(thread_call_param_t param0, thread_call_param_t param1); - -/* - * HISTORICAL NOTE: - * The following methods were part of the KeyMapDelegate protocol; - * the declarations have now been merged directly into this class. - */ - -public: - virtual void keyboardEvent(unsigned eventType, - /* flags */ unsigned flags, - /* keyCode */ unsigned keyCode, - /* charCode */ unsigned charCode, - /* charSet */ unsigned charSet, - /* originalCharCode */ unsigned origCharCode, - /* originalCharSet */ unsigned origCharSet); - - virtual void keyboardSpecialEvent(unsigned eventType, - /* flags */ unsigned flags, - /* keyCode */ unsigned keyCode, - /* specialty */ unsigned flavor); - - virtual void updateEventFlags(unsigned flags); // Does not generate events - - virtual unsigned eventFlags(); // Global event flags - virtual unsigned deviceFlags(); // per-device event flags - virtual void setDeviceFlags(unsigned flags); // Set device event flags - virtual bool alphaLock(); // current alpha-lock state - virtual void setAlphaLock(bool val); // Set current alpha-lock state - virtual bool numLock(); - virtual void setNumLock(bool val); - virtual bool charKeyActive(); // Is a character gen. key down? - virtual void setCharKeyActive(bool val); // Note that a char gen key is down. - virtual bool doesKeyLock(unsigned key); //does key lock physically - virtual unsigned getLEDStatus(); //check hardware for LED status - -private: - static void _keyboardEvent( IOHIKeyboard * self, - unsigned eventType, - /* flags */ unsigned flags, - /* keyCode */ unsigned key, - /* charCode */ unsigned charCode, - /* charSet */ unsigned charSet, - /* originalCharCode */ unsigned origCharCode, - /* originalCharSet */ unsigned origCharSet, - /* keyboardType */ unsigned keyboardType, - /* repeat */ bool repeat, - /* atTime */ AbsoluteTime ts); - static void _keyboardSpecialEvent( - IOHIKeyboard * self, - unsigned eventType, - /* flags */ unsigned flags, - /* keyCode */ unsigned key, - /* specialty */ unsigned flavor, - /* guid */ UInt64 guid, - /* repeat */ bool repeat, - /* atTime */ AbsoluteTime ts); - - static void _updateEventFlags( IOHIKeyboard * self, - unsigned flags); /* Does not generate events */ - -}; - -#endif /* !_IOHIKEYBOARD_H */ diff --git a/Library/LegacyIOHIPointing.h b/Library/LegacyIOHIPointing.h deleted file mode 100644 index 1435e528..00000000 --- a/Library/LegacyIOHIPointing.h +++ /dev/null @@ -1,259 +0,0 @@ -/* - * @APPLE_LICENSE_HEADER_START@ - * - * Copyright (c) 1999-2009 Apple Computer, Inc. All Rights Reserved. - * - * This file contains Original Code and/or Modifications of Original Code - * as defined in and that are subject to the Apple Public Source License - * Version 2.0 (the 'License'). You may not use this file except in - * compliance with the License. Please obtain a copy of the License at - * http://www.opensource.apple.com/apsl/ and read it before using this - * file. - * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. - * Please see the License for the specific language governing rights and - * limitations under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ -#ifndef _IOHIPOINTING_H -#define _IOHIPOINTING_H - -#include "LegacyIOService.h" -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Winconsistent-missing-override" -#include -#include -#pragma clang diagnostic pop - -/* Start Action Definitions */ - -/* - * HISTORICAL NOTE: - * The following entry points were part of the IOHIPointingEvents - * protocol. - */ -typedef void (*RelativePointerEventAction)(OSObject * target, - /* buttons */ int buttons, - /* deltaX */ int dx, - /* deltaY */ int dy, - /* atTime */ AbsoluteTime ts); - -typedef void (*AbsolutePointerEventAction)(OSObject * target, - /* buttons */ int buttons, - /* at */ IOGPoint * newLoc, - /* withBounds */ IOGBounds *bounds, - /* inProximity */ bool proximity, - /* withPressure */ int pressure, - /* withAngle */ int stylusAngle, - /* atTime */ AbsoluteTime ts); - -typedef void (*ScrollWheelEventAction)(OSObject * target, - short deltaAxis1, - short deltaAxis2, - short deltaAxis3, - AbsoluteTime ts); - -/* Event Callback Definitions */ - -typedef void (*RelativePointerEventCallback)( - /* target */ OSObject * target, - /* buttons */ int buttons, - /* deltaX */ int dx, - /* deltaY */ int dy, - /* atTime */ AbsoluteTime ts, - /* sender */ OSObject * sender, - /* refcon */ void * refcon); - -typedef void (*AbsolutePointerEventCallback)( - /* target */ OSObject * target, - /* buttons */ int buttons, - /* at */ IOGPoint * newLoc, - /* withBounds */ IOGBounds *bounds, - /* inProximity */ bool proximity, - /* withPressure */ int pressure, - /* withAngle */ int stylusAngle, - /* atTime */ AbsoluteTime ts, - /* sender */ OSObject * sender, - /* refcon */ void * refcon); - -typedef void (*ScrollWheelEventCallback)( - /* target */ OSObject * target, - /* delta1 */ short deltaAxis1, - /* delta2 */ short deltaAxis2, - /* delta3 */ short deltaAxis3, - /* fixedDelta1 */ IOFixed fixedDelta1, - /* fixedDelta2 */ IOFixed fixedDelta2, - /* fixedDelta3 */ IOFixed fixedDelta3, - /* pointDelta1 */ SInt32 pointDelta1, - /* pointDelta2 */ SInt32 pointDelta2, - /* pointDelta3 */ SInt32 pointDelta3, - /* reserved */ SInt32 options, - /* atTime */ AbsoluteTime ts, - /* sender */ OSObject * sender, - /* refcon */ void * refcon); - -/* End Action Definitions */ - -/* Default accel level parameters */ -#define EV_DEFAULTPOINTERACCELLEVEL 0x0000b000 -#define EV_DEFAULTSCROLLACCELLEVEL 0x00005000 - -class IOHIDPointingDevice; -struct ScrollAccelInfo; - -class IOHIPointing : public IOHIDevice -{ - OSDeclareDefaultStructors(IOHIPointing); - - friend class IOHITablet; - friend class IOHIDPointing; - -private: - IOLock * _deviceLock; // Lock for all device access - int _buttonMode; // The "handedness" of the pointer - IOFixed _acceleration; - bool _convertAbsoluteToRelative; - bool _contactToMove; - bool _hadContact; - IOGPoint _previousLocation; - UInt8 _pressureThresholdToClick; // A scale factor of 0 to 255 to determine how much pressure is necessary to generate a primary mouse click - a value of 255 means no click will be generated - void * _scaleSegments; - IOItemCount _scaleSegCount; - IOFixed _fractX; - IOFixed _fractY; - - OSObject * _relativePointerEventTarget; - RelativePointerEventAction _relativePointerEventAction; - OSObject * _absolutePointerEventTarget; - AbsolutePointerEventAction _absolutePointerEventAction; - OSObject * _scrollWheelEventTarget; - ScrollWheelEventAction _scrollWheelEventAction; - - struct ExpansionData; - - ExpansionData * _reserved; - - void setPointingMode(UInt32 accelerateMode); - UInt32 getPointingMode (); - void setScrollType(UInt32 scrollType); - UInt32 getScrollType(); - - void dispatchScrollWheelEventWithAccelInfo( - SInt32 deltaAxis1, - SInt32 deltaAxis2, - SInt32 deltaAxis3, - ScrollAccelInfo * info, - AbsoluteTime ts); - - -protected: - virtual void dispatchRelativePointerEvent(int dx, - int dy, - UInt32 buttonState, - AbsoluteTime ts); - - virtual void dispatchAbsolutePointerEvent(IOGPoint * newLoc, - IOGBounds * bounds, - UInt32 buttonState, - bool proximity, - int pressure, - int pressureMin, - int pressureMax, - int stylusAngle, - AbsoluteTime ts); - - virtual void dispatchScrollWheelEvent(short deltaAxis1, - short deltaAxis2, - short deltaAxis3, - AbsoluteTime ts); - -public: - virtual bool init(OSDictionary * properties = 0) override; - virtual bool start(IOService * provider) override; - virtual void free() override; - - virtual bool open(IOService * client, - IOOptionBits options, - RelativePointerEventAction rpeAction, - AbsolutePointerEventAction apeAction, - ScrollWheelEventAction sweAction); - - bool open( IOService * client, - IOOptionBits options, - void *, - RelativePointerEventCallback rpeCallback, - AbsolutePointerEventCallback apeCallback, - ScrollWheelEventCallback sweCallback); - - virtual void close(IOService * client, IOOptionBits ) override; - virtual IOReturn message( UInt32 type, IOService * provider, - void * argument = 0 ) override; - - virtual IOHIDKind hidKind() override; - virtual bool updateProperties( void ) override; - virtual IOReturn setParamProperties( OSDictionary * dict ) override; - virtual IOReturn powerStateWillChangeTo( IOPMPowerFlags powerFlags, - unsigned long newState, IOService * device) override; - virtual IOReturn powerStateDidChangeTo( IOPMPowerFlags powerFlags, - unsigned long newState, IOService * device) override; - -protected: // for subclasses to implement - virtual OSData * copyAccelerationTable(); - virtual IOItemCount buttonCount(); - virtual IOFixed resolution(); - - // RY: Adding method to copy scroll wheel accel table. - // Unfortunately, we don't have any padding, so this - // is going to be non-virtual. - /*virtual*/ OSData * copyScrollAccelerationTable(); - -private: - virtual bool resetPointer(); - virtual void scalePointer(int * dxp, int * dyp); - virtual void setupForAcceleration(IOFixed accl); - - // RY: Adding methods to support scroll wheel accel. - // Unfortunately, we don't have any padding, so these - // are going to be non-virtual. - /*virtual*/ bool resetScroll(); - /*virtual*/ void setupScrollForAcceleration(IOFixed accl); - - // RY: We have to make sure that subclasses that will - // take advantage of this have their defined resolution - // in their property table. - /*virtual*/ IOFixed scrollResolutionForType(SInt32 type=-1); - /*virtual*/ IOFixed scrollReportRate(); - /*virtual*/ OSData * copyScrollAccelerationTableForType(SInt32 type=-1); - -private: - static void _relativePointerEvent( IOHIPointing * self, - int buttons, - /* deltaX */ int dx, - /* deltaY */ int dy, - /* atTime */ AbsoluteTime ts); - - /* Tablet event reporting */ - static void _absolutePointerEvent(IOHIPointing * self, - int buttons, - /* at */ IOGPoint * newLoc, - /* withBounds */ IOGBounds *bounds, - /* inProximity */ bool proximity, - /* withPressure */ int pressure, - /* withAngle */ int stylusAngle, - /* atTime */ AbsoluteTime ts); - - /* Mouse scroll wheel event reporting */ - static void _scrollWheelEvent(IOHIPointing *self, - short deltaAxis1, - short deltaAxis2, - short deltaAxis3, - AbsoluteTime ts); - -}; - -#endif /* !_IOHIPOINTING_H */ diff --git a/Library/LegacyIOService.h b/Library/LegacyIOService.h deleted file mode 100644 index fc378bd4..00000000 --- a/Library/LegacyIOService.h +++ /dev/null @@ -1,1721 +0,0 @@ -/* - * Copyright (c) 1998-2011 Apple Computer, Inc. All rights reserved. - * - * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ - * - * This file contains Original Code and/or Modifications of Original Code - * as defined in and that are subject to the Apple Public Source License - * Version 2.0 (the 'License'). You may not use this file except in - * compliance with the License. The rights granted to you under the License - * may not be used to create, or enable the creation or redistribution of, - * unlawful or unlicensed copies of an Apple operating system, or to - * circumvent, violate, or enable the circumvention or violation of, any - * terms of an Apple operating system software license agreement. - * - * Please obtain a copy of the License at - * http://www.opensource.apple.com/apsl/ and read it before using this file. - * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. - * Please see the License for the specific language governing rights and - * limitations under the License. - * - * @APPLE_OSREFERENCE_LICENSE_HEADER_END@ - */ -/* - * Copyright (c) 1998,1999 Apple Computer, Inc. All rights reserved. - * - * HISTORY - * - */ -/*! - @header - This header contains the definition of the IOService class. IOService is the sole direct subclass of IORegistryEntry and is the base class of almost all I/O Kit family superclasses. IOService defines methods that support the life cycle of I/O Kit drivers. For more information on IOService, see {@linkdoc //apple_ref/doc/uid/TP0000011 I/O Kit Fundamentals}. - - @seealso //apple_ref/doc/header/IORegistryEntry.h IORegistryEntry -*/ - -#ifndef _IOKIT_IOSERVICE_H -#define _IOKIT_IOSERVICE_H - -#include -#include -#include -#include -#include - -#include -#include -#include - -#include -#include - -extern "C" { -#include -} - -#include "LegacyLibkernMacros.h" - -#ifndef UINT64_MAX -#define UINT64_MAX 18446744073709551615ULL -#endif - -enum { - kIODefaultProbeScore = 0 -}; - -// masks for getState() -enum { - kIOServiceInactiveState = 0x00000001, - kIOServiceRegisteredState = 0x00000002, - kIOServiceMatchedState = 0x00000004, - kIOServiceFirstPublishState = 0x00000008, - kIOServiceFirstMatchState = 0x00000010 -}; - -enum { - // options for registerService() - kIOServiceExclusive = 0x00000001, - - // options for terminate() - kIOServiceRequired = 0x00000001, - kIOServiceTerminate = 0x00000004, - - // options for registerService() & terminate() - kIOServiceSynchronous = 0x00000002, - // options for registerService() - kIOServiceAsynchronous = 0x00000008 -}; - -// options for open() -enum { - kIOServiceSeize = 0x00000001, - kIOServiceFamilyOpenOptions = 0xffff0000 -}; - -// options for close() -enum { - kIOServiceFamilyCloseOptions = 0xffff0000 -}; - -typedef void * IONotificationRef; - -extern const IORegistryPlane * gIOServicePlane; -extern const IORegistryPlane * gIOPowerPlane; - -extern const OSSymbol * gIOResourcesKey; -extern const OSSymbol * gIOResourceMatchKey; -extern const OSSymbol * gIOProviderClassKey; -extern const OSSymbol * gIONameMatchKey; -extern const OSSymbol * gIONameMatchedKey; -extern const OSSymbol * gIOPropertyMatchKey; -extern const OSSymbol * gIOLocationMatchKey; -extern const OSSymbol * gIOParentMatchKey; -extern const OSSymbol * gIOPathMatchKey; -extern const OSSymbol * gIOMatchCategoryKey; -extern const OSSymbol * gIODefaultMatchCategoryKey; -extern const OSSymbol * gIOMatchedServiceCountKey; - -extern const OSSymbol * gIOUserClientClassKey; -extern const OSSymbol * gIOKitDebugKey; -extern const OSSymbol * gIOServiceKey; - -extern const OSSymbol * gIOCommandPoolSizeKey; - -extern const OSSymbol * gIOPublishNotification; -extern const OSSymbol * gIOFirstPublishNotification; -extern const OSSymbol * gIOMatchedNotification; -extern const OSSymbol * gIOFirstMatchNotification; -extern const OSSymbol * gIOTerminatedNotification; - -extern const OSSymbol * gIOGeneralInterest; -extern const OSSymbol * gIOBusyInterest; -extern const OSSymbol * gIOOpenInterest; -extern const OSSymbol * gIOAppPowerStateInterest; -extern const OSSymbol * gIOPriorityPowerStateInterest; -extern const OSSymbol * gIOConsoleSecurityInterest; - -extern const OSSymbol * gIODeviceMemoryKey; -extern const OSSymbol * gIOInterruptControllersKey; -extern const OSSymbol * gIOInterruptSpecifiersKey; - -extern SInt32 IOServiceOrdering( const OSMetaClassBase * inObj1, const OSMetaClassBase * inObj2, void * ref ); - -typedef void (*IOInterruptAction)( OSObject * target, void * refCon, - IOService * nub, int source ); - -/*! @typedef IOServiceNotificationHandler - @param target Reference supplied when the notification was registered. - @param refCon Reference constant supplied when the notification was registered. - @param newService The IOService object the notification is delivering. It is retained for the duration of the handler's invocation and doesn't need to be released by the handler. */ - -typedef bool (*IOServiceNotificationHandler)( void * target, void * refCon, - IOService * newService ); - -typedef bool (*IOServiceMatchingNotificationHandler)( void * target, void * refCon, - IOService * newService, - IONotifier * notifier ); - -/*! @typedef IOServiceInterestHandler - @param target Reference supplied when the notification was registered. - @param refCon Reference constant supplied when the notification was registered. - @param messageType Type of the message - IOKit defined in IOKit/IOMessage.h or family specific. - @param provider The IOService object who is delivering the notification. It is retained for the duration of the handler's invocation and doesn't need to be released by the handler. - @param messageArgument An argument for message, dependent on its type. - @param argSize Non zero if the argument represents a struct of that size, used when delivering messages outside the kernel. */ - -typedef IOReturn (*IOServiceInterestHandler)( void * target, void * refCon, - UInt32 messageType, IOService * provider, - void * messageArgument, vm_size_t argSize ); - -typedef void (*IOServiceApplierFunction)(IOService * service, void * context); -typedef void (*OSObjectApplierFunction)(OSObject * object, void * context); - -class IOUserClient; -class IOPlatformExpert; - -/*! @class IOService - @abstract The base class for most I/O Kit families, devices, and drivers. - @discussion The IOService base class defines APIs used to publish services, instantiate other services based on the existance of a providing service (ie. driver stacking), destroy a service and its dependent stack, notify interested parties of service state changes, and general utility functions useful across all families. - -Types of service are specified with a matching dictionary that describes properties of the service. For example, a matching dictionary might describe any IOUSBDevice (or subclass), an IOUSBDevice with a certain class code, or a IOPCIDevice with a set of matching names or device & vendor IDs. Since the matching dictionary is interpreted by the family which created the service, as well as generically by IOService, the list of properties considered for matching depends on the familiy. - -Matching dictionaries are associated with IOService classes by the catalogue, as driver property tables, and also supplied by clients of the notification APIs. - -IOService provides matching based on C++ class (via OSMetaClass dynamic casting), registry entry name, a registry path to the service (which includes device tree paths), a name assigned by BSD, or by its location (its point of attachment). - -

Driver Instantiation by IOService

- -Drivers are subclasses of IOService, and their availability is managed through the catalogue. They are instantiated based on the publication of an IOService they use (for example, an IOPCIDevice or IOUSBDevice), or when they are added to the catalogue and the IOService(s) they use are already available. - -When an IOService (the "provider") is published with the @link registerService registerService@/link method, the matching and probing process begins, which is always single threaded per provider. A list of matching dictionaries from the catalog and installed publish notification requests, that successfully match the IOService, is constructed, with ordering supplied by kIOProbeScoreKey ("IOProbeScore") property in the dictionary, or supplied with the notification. - -Each entry in the list is then processed in order - for notifications, the notification is delivered, for driver property tables a lot more happens. - -The driver class is instantiated and init() called with its property table. The new driver instance is then attached to the provider, and has its @link probe probe@/link method called with the provider as an argument. The default probe method does nothing but return success, but a driver may implement this method to interrogate the provider to make sure it can work with it. It may also modify its probe score at this time. After probe, the driver is detached and the next in the list is considered (ie. attached, probed, and detached). - -When the probing phase is complete, the list consists of successfully probed drivers, in order of their probe score (after adjustment during the @link probe probe@/link call). The list is then divided into categories based on the kIOMatchCategoryKey property ("IOMatchCategory"); drivers without a match category are all considered in one default category. Match categories allow multiple clients of a provider to be attached and started, though the provider may also enforce open/close semantics to gain active access to it. - -For each category, the highest scoring driver in that category is attached to the provider, and its @link start start@/link method called. If start is successful, the rest of the drivers in the same match category are discarded, otherwise the next highest scoring driver is started, and so on. - -The driver should only consider itself in action when the start method is called, meaning it has been selected for use on the provider, and consuming that particular match category. It should also be prepared to be allocated, probed and freed even if the probe was successful. - -After the drivers have all synchronously been started, the installed "matched" notifications that match the registered IOService are delivered. - -

Properties used by IOService

- - kIOClassKey, extern const OSSymbol * gIOClassKey, "IOClass" -
-
-Class of the driver to instantiate on matching providers. -
-
- kIOProviderClassKey, extern const OSSymbol * gIOProviderClassKey, "IOProviderClass" -
-
-Class of the provider(s) to be considered for matching, checked with OSDynamicCast so subclasses will also match. -
-
- kIOProbeScoreKey, extern const OSSymbol * gIOProbeScoreKey, "IOProbeScore" -
-
-The probe score initially used to order multiple matching drivers. -
-
- kIOMatchCategoryKey, extern const OSSymbol * gIOMatchCategoryKey, "IOMatchCategory" -
-
-A string defining the driver category for matching purposes. All drivers with no IOMatchCategory property are considered to be in the same default category. Only one driver in a category can be started on each provider. -
-
- kIONameMatchKey, extern const OSSymbol * gIONameMatchKey, "IONameMatch" -
-A string or collection of strings that match the provider's name. The comparison is implemented with the @link //apple_ref/cpp/instm/IORegistryEntry/compareNames/virtualbool/(OSObject*,OSString**) IORegistryEntry::compareNames@/link method, which supports a single string, or any collection (OSArray, OSSet, OSDictionary etc.) of strings. IOService objects with device tree properties (eg. IOPCIDevice) will also be matched based on that standard's "compatible", "name", "device_type" properties. The matching name will be left in the driver's property table in the kIONameMatchedKey property. -
-Examples -
-@textblock
-	IONameMatch
-	pci106b,7
-@/textblock
-
- -For a list of possible matching names, a serialized array of strings should used, eg. -
-@textblock
-	IONameMatch
-	
-		APPL,happy16
-		pci106b,7
-	
-@/textblock
-
- -
- kIONameMatchedKey, extern const OSSymbol * gIONameMatchedKey, "IONameMatched" -
-The name successfully matched name from the kIONameMatchKey property will be left in the driver's property table as the kIONameMatchedKey property. -
-
- kIOPropertyMatchKey, extern const OSSymbol * gIOPropertyMatchKey, "IOPropertyMatch" -
-A dictionary of properties that each must exist in the matching IOService and compare successfully with the isEqualTo method. - -
-@textblock
-	IOPropertyMatch
-	
-		APPL,happy16
-		APPL,meek8
-	
-@/textblock
-
- -
- kIOUserClientClassKey, extern const OSSymbol * gIOUserClientClassKey, "IOUserClientClass" -
-The class name that the service will attempt to allocate when a user client connection is requested. First the device nub is queried, then the nub's provider is queried by default. -
-
- kIOKitDebugKey, extern const OSSymbol * gIOKitDebugKey, "IOKitDebug" -
-Set some debug flags for logging the driver loading process. Flags are defined in IOKit/IOKitDebug.h, but 65535 works well.*/ - -class IOService : public IORegistryEntry -{ - OSDeclareDefaultStructors(IOService) - -protected: -/*! @struct ExpansionData - @discussion This structure will be used to expand the capablilties of this class in the future. - */ - struct ExpansionData { }; - -/*! @var reserved - Reserved for future use. (Internal use only) */ - ExpansionData * reserved; - -private: - IOService * __provider; - SInt32 __providerGeneration; - IOService * __owner; - IOOptionBits __state[2]; - uint64_t __timeBusy; - uint64_t __accumBusy; - IOServicePM * pwrMgt; - -protected: - // TRUE once PMinit has been called - bool initialized; - -public: - // DEPRECATED - void * pm_vars; - -public: - /* methods available in Mac OS X 10.1 or later */ -/*! @function requestTerminate - @abstract Passes a termination up the stack. - @discussion When an IOService is made inactive the default behavior is to also make any of its clients that have it as their only provider also inactive, in this way recursing the termination up the driver stack. This method allows an IOService object to override this behavior. Returning true from this method when passed a just terminated provider will cause the client to also be terminated. - @param provider The terminated provider of this object. - @param options Options originally passed to terminate, plus kIOServiceRecursing. - @result true if this object should be terminated now that its provider has been. */ - - virtual bool requestTerminate( IOService * provider, IOOptionBits options ); - -/*! @function willTerminate - @abstract Passes a termination up the stack. - @discussion Notification that a provider has been terminated, sent before recursing up the stack, in root-to-leaf order. - @param provider The terminated provider of this object. - @param options Options originally passed to terminate. - @result true. */ - - virtual bool willTerminate( IOService * provider, IOOptionBits options ); - -/*! @function didTerminate - @abstract Passes a termination up the stack. - @discussion Notification that a provider has been terminated, sent after recursing up the stack, in leaf-to-root order. - @param provider The terminated provider of this object. - @param options Options originally passed to terminate. - @param defer If there is pending I/O that requires this object to persist, and the provider is not opened by this object set defer to true and call the IOService::didTerminate() implementation when the I/O completes. Otherwise, leave defer set to its default value of false. - @result true. */ - - virtual bool didTerminate( IOService * provider, IOOptionBits options, bool * defer ); - -/*! @function nextIdleTimeout - @availability Mac OS X v10.4 and later - @abstract Allows subclasses to customize idle power management behavior. - @discussion Returns the next time that the device should idle into its next lower power state. Subclasses may override for custom idle behavior. - - A power managed driver might override this method to provide a more sophisticated idle power off algorithm than the one defined by power management. - @param currentTime The current time - @param lastActivity The time of last activity on this device - @param powerState The device's current power state. - @result Returns the next time the device should idle off (in seconds, relative to the current time). */ - - virtual SInt32 nextIdleTimeout(AbsoluteTime currentTime, - AbsoluteTime lastActivity, unsigned int powerState); - -/*! @function systemWillShutdown - @availability Mac OS X v10.5 and later - @abstract Notifies members of the power plane of system shutdown and restart. - @discussion This function is called for all members of the power plane in leaf-to-root order. If a subclass needs to wait for a pending I/O, then the call to systemWillShutdown should be postponed until the I/O completes. - - Any power managed driver (which has called @link joinPMtree joinPMtree@/link to join the power plane) interested in taking action at system shutdown or restart should override this method. - @param specifier kIOMessageSystemWillPowerOff or kIOMessageSystemWillRestart. */ - - virtual void systemWillShutdown( IOOptionBits specifier ); - -/*! @function copyClientWithCategory - @availability Mac OS X v10.6 and later - @param category An OSSymbol corresponding to an IOMatchCategory matching property. - @result Returns a reference to the IOService child with the given category. The result should be released by the caller. -*/ - - virtual IOService * copyClientWithCategory( const OSSymbol * category ); - -public: -/*! @function configureReport - * @abstract configure IOReporting channels - * @availability SPI on OS X v10.9 / iOS 7 and later - * - * @param channels - channels to configure - * @param action - enable/disable/size, etc - * @param result - action-specific returned value - * @param destination - action-specific default destination - */ - virtual IOReturn configureReport(IOReportChannelList *channels, - IOReportConfigureAction action, - void *result, - void *destination); - -/*! @function updateReport - * @abstract request current data for the specified channels - * @availability SPI on OS X 10.9 / iOS 7 and later - * - * @param channels - channels to be updated - * @param action - type/style of update - * @param result - returned details about what was updated - * @param destination - destination for this update (action-specific) - */ - virtual IOReturn updateReport(IOReportChannelList *channels, - IOReportUpdateAction action, - void *result, - void *destination); - -private: -#if __LP64__ - OSMetaClassDeclareReservedUsed(IOService, 0); - OSMetaClassDeclareReservedUsed(IOService, 1); - OSMetaClassDeclareReservedUnused(IOService, 2); - OSMetaClassDeclareReservedUnused(IOService, 3); - OSMetaClassDeclareReservedUnused(IOService, 4); - OSMetaClassDeclareReservedUnused(IOService, 5); -#else - OSMetaClassDeclareReservedUsed(IOService, 0); - OSMetaClassDeclareReservedUsed(IOService, 1); - OSMetaClassDeclareReservedUsed(IOService, 2); - OSMetaClassDeclareReservedUsed(IOService, 3); - OSMetaClassDeclareReservedUsed(IOService, 4); - OSMetaClassDeclareReservedUsed(IOService, 5); -#endif - - OSMetaClassDeclareReservedUnused(IOService, 6); - OSMetaClassDeclareReservedUnused(IOService, 7); - OSMetaClassDeclareReservedUnused(IOService, 8); - OSMetaClassDeclareReservedUnused(IOService, 9); - OSMetaClassDeclareReservedUnused(IOService, 10); - OSMetaClassDeclareReservedUnused(IOService, 11); - OSMetaClassDeclareReservedUnused(IOService, 12); - OSMetaClassDeclareReservedUnused(IOService, 13); - OSMetaClassDeclareReservedUnused(IOService, 14); - OSMetaClassDeclareReservedUnused(IOService, 15); - OSMetaClassDeclareReservedUnused(IOService, 16); - OSMetaClassDeclareReservedUnused(IOService, 17); - OSMetaClassDeclareReservedUnused(IOService, 18); - OSMetaClassDeclareReservedUnused(IOService, 19); - OSMetaClassDeclareReservedUnused(IOService, 20); - OSMetaClassDeclareReservedUnused(IOService, 21); - OSMetaClassDeclareReservedUnused(IOService, 22); - OSMetaClassDeclareReservedUnused(IOService, 23); - OSMetaClassDeclareReservedUnused(IOService, 24); - OSMetaClassDeclareReservedUnused(IOService, 25); - OSMetaClassDeclareReservedUnused(IOService, 26); - OSMetaClassDeclareReservedUnused(IOService, 27); - OSMetaClassDeclareReservedUnused(IOService, 28); - OSMetaClassDeclareReservedUnused(IOService, 29); - OSMetaClassDeclareReservedUnused(IOService, 30); - OSMetaClassDeclareReservedUnused(IOService, 31); - OSMetaClassDeclareReservedUnused(IOService, 32); - OSMetaClassDeclareReservedUnused(IOService, 33); - OSMetaClassDeclareReservedUnused(IOService, 34); - OSMetaClassDeclareReservedUnused(IOService, 35); - OSMetaClassDeclareReservedUnused(IOService, 36); - OSMetaClassDeclareReservedUnused(IOService, 37); - OSMetaClassDeclareReservedUnused(IOService, 38); - OSMetaClassDeclareReservedUnused(IOService, 39); - OSMetaClassDeclareReservedUnused(IOService, 40); - OSMetaClassDeclareReservedUnused(IOService, 41); - OSMetaClassDeclareReservedUnused(IOService, 42); - OSMetaClassDeclareReservedUnused(IOService, 43); - OSMetaClassDeclareReservedUnused(IOService, 44); - OSMetaClassDeclareReservedUnused(IOService, 45); - OSMetaClassDeclareReservedUnused(IOService, 46); - OSMetaClassDeclareReservedUnused(IOService, 47); - -public: -/*! @function getState - @abstract Accessor for IOService state bits, not normally needed or used outside IOService. - @result State bits for the IOService, eg. kIOServiceInactiveState, kIOServiceRegisteredState. */ - - virtual IOOptionBits getState( void ) const; - -/*! @function isInactive - @abstract Checks if the IOService object has been terminated, and is in the process of being destroyed. - @discussion When an IOService object is successfully terminated, it is immediately made inactive, which blocks further attach()es, matching or notifications occuring on the object. It remains inactive until the last client closes, and is then finalized and destroyed. - @result true if the IOService object has been terminated. */ - - bool isInactive( void ) const; - - /* Stack creation */ - -/*! @function registerService - @abstract Starts the registration process for a newly discovered IOService object. - @discussion This function allows an IOService subclass to be published and made available to possible clients, by starting the registration process and delivering notifications to registered clients. The object should be completely setup and ready to field requests from clients before registerService is called. - @param options The default zero options mask is recommended and should be used in most cases. The registration process is usually asynchronous, with possible driver probing and notification occurring some time later. kIOServiceSynchronous may be passed to carry out the matching and notification process for currently registered clients before returning to the caller. */ - - virtual void registerService( IOOptionBits options = 0 ); - -/*! @function probe - @abstract During an IOService object's instantiation, probes a matched service to see if it can be used. - @discussion The registration process for an IOService object (the provider) includes instantiating possible driver clients. The probe method is called in the client instance to check the matched service can be used before the driver is considered to be started. Since matching screens many possible providers, in many cases the probe method can be left unimplemented by IOService subclasses. The client is already attached to the provider when probe is called. - @param provider The registered IOService object that matches a driver personality's matching dictionary. - @param score Pointer to the current driver's probe score, which is used to order multiple matching drivers in the same match category. It defaults to the value of the IOProbeScore property in the drivers property table, or kIODefaultProbeScore if none is specified. The probe method may alter the score to affect start order. - @result An IOService instance or zero when the probe is unsuccessful. In almost all cases the value of this is returned on success. If another IOService object is returned, the probed instance is detached and freed, and the returned instance is used in its stead for start. */ - - virtual LIBKERN_RETURNS_NOT_RETAINED IOService * probe( IOService * provider, - SInt32 * score ); - -/*! @function start - @abstract During an IOService object's instantiation, starts the IOService object that has been selected to run on the provider. - @discussion The start method of an IOService instance is called by its provider when it has been selected (due to its probe score and match category) as the winning client. The client is already attached to the provider when start is called.
Implementations of start must call start on their superclass at an appropriate point. If an implementation of start has already called super::start but subsequently determines that it will fail, it must call super::stop to balance the prior call to super::start and prevent reference leaks. - @result true if the start was successful; false otherwise (which will cause the instance to be detached and usually freed). */ - - virtual bool start( IOService * provider ); - -/*! @function stop - @abstract During an IOService termination, the stop method is called in its clients before they are detached & it is destroyed. - @discussion The termination process for an IOService (the provider) will call stop in each of its clients, after they have closed the provider if they had it open, or immediately on termination. */ - - virtual void stop( IOService * provider ); - - /* Open / Close */ - -/*! @function open - @abstract Requests active access to a provider. - @discussion IOService provides generic open and close semantics to track clients of a provider that have established an active datapath. The use of open and @link close close@/link, and rules regarding ownership are family defined, and defined by the @link handleOpen handleOpen@/link and @link handleClose handleClose@/link methods in the provider. Some families will limit access to a provider based on its open state. - @param forClient Designates the client of the provider requesting the open. - @param options Options for the open. The provider family may implement options for open; IOService defines only kIOServiceSeize to request the device be withdrawn from its current owner. - @result true if the open was successful; false otherwise. */ - - virtual bool open( IOService * forClient, - IOOptionBits options = 0, - void * arg = 0 ); - -/*! @function close - @abstract Releases active access to a provider. - @discussion IOService provides generic open and close semantics to track clients of a provider that have established an active datapath. The use of @link open open@/link and close, and rules regarding ownership are family defined, and defined by the @link handleOpen handleOpen@/link and @link handleClose handleClose@/link methods in the provider. - @param forClient Designates the client of the provider requesting the close. - @param options Options available for the close. The provider family may implement options for close; IOService defines none. */ - - virtual void close( IOService * forClient, - IOOptionBits options = 0 ); - -/*! @function isOpen - @abstract Determines whether a specific, or any, client has an IOService object open. - @discussion Returns the open state of an IOService object with respect to the specified client, or when it is open by any client. - @param forClient If non-zero, isOpenisOpentrueopen. The object is locked via @link lockForArbitration lockForArbitration@/link before handleOpen is called. - @param forClient Designates the client of the provider requesting the open. - @param options Options for the open, may be interpreted by the implementor of handleOpen. - @result trueif the open was successful; false otherwise. */ - - virtual bool handleOpen( IOService * forClient, - IOOptionBits options, - void * arg ); - -/*! @function handleClose - @abstract Controls the open / close behavior of an IOService object (overrideable by subclasses). - @discussion IOService calls this method in its subclasses in response to the @link close close@/link method, so the subclass may implement the request. The default implementation provides single owner access to an IOService object via @link open open@/link. The object is locked via @link lockForArbitration lockForArbitration@/link before handleClose is called. - @param forClient Designates the client of the provider requesting the close. - @param options Options for the close, may be interpreted by the implementor of @link handleOpen handleOpen@/link. */ - - virtual void handleClose( IOService * forClient, - IOOptionBits options ); - -/*! @function handleIsOpen - @abstract Controls the open / close behavior of an IOService object (overrideable by subclasses). - @discussion IOService calls this method in its subclasses in response to the @link open open@/link method, so the subclass may implement the request. The default implementation provides single owner access to an IOService object via @link open open@/link. The object is locked via @link lockForArbitration lockForArbitration@/link before handleIsOpen is called. - @param forClient If non-zero, isOpen returns the open state for that client. If zero is passed, isOpen returns the open state for all clients. - @result true if the specific, or any, client has the IOService object open. */ - - virtual bool handleIsOpen( const IOService * forClient ) const; - - /* Stacking change */ - -/*! @function terminate - @abstract Makes an IOService object inactive and begins its destruction. - @discussion Registering an IOService object informs possible clients of its existance and instantiates drivers that may be used with it; terminate involves the opposite process of informing clients that an IOService object is no longer able to be used and will be destroyed. By default, if any client has the service open, terminate fails. If the kIOServiceRequired flag is passed however, terminate will be successful though further progress in the destruction of the IOService object will not proceed until the last client has closed it. The service will be made inactive immediately upon successful termination, and all its clients will be notified via their @link message message@/link method with a message of type kIOMessageServiceIsTerminated. Both these actions take place on the caller's thread. After the IOService object is made inactive, further matching or attach calls will fail on it. Each client has its @link stop stop@/link method called upon their close of an inactive IOService object , or on its termination if they do not have it open. After stop, @link detach detach@/link is called in each client. When all clients have been detached, the @link finalize finalize@/link method is called in the inactive service. The termination process is inherently asynchronous because it will be deferred until all clients have chosen to close. - @param options In most cases no options are needed. kIOServiceSynchronous may be passed to cause terminate to not return until the service is finalized. */ - - virtual bool terminate( IOOptionBits options = 0 ); - -/*! @function finalize - @abstract Finalizes the destruction of an IOService object. - @discussion The finalize method is called in an inactive (ie. terminated) IOService object after the last client has detached. IOService's implementation will call @link stop stop@/link, @link close close@/link, and @link detach detach@/link on each provider. When finalize returns, the object's retain count will have no references generated by IOService's registration process. - @param options The options passed to the @link terminate terminate@/link method of the IOService object are passed on to finalize. - @result true. */ - - virtual bool finalize( IOOptionBits options ); - -/*! @function free - @abstract Frees data structures that were allocated when power management was initialized on this service. */ - - virtual void free( void ) override; - -/*! @function lockForArbitration - @abstract Locks an IOService object against changes in state or ownership. - @discussion The registration, termination and open / close functions of IOService use lockForArbtration to single-thread access to an IOService object. lockForArbitration grants recursive access to the same thread. - @param isSuccessRequired If a request for access to an IOService object should be denied if it is terminated, pass false, otherwise pass true. */ - - virtual bool lockForArbitration( bool isSuccessRequired = true ); - -/*! @function unlockForArbitration - @abstract Unlocks an IOService obkect after a successful @link lockForArbitration lockForArbitration@/link. - @discussion A thread granted exclusive access to an IOService object should release it with unlockForArbitration. */ - - virtual void unlockForArbitration( void ); - -/*! @function terminateClient - @abstract Passes a termination up the stack. - @discussion When an IOService object is made inactive the default behavior is to also make any of its clients that have it as their only provider inactive, in this way recursing the termination up the driver stack. This method allows a terminated IOService object to override this behavior. Note the client may also override this behavior by overriding its @link terminate terminate@/link method. - @param client The client of the terminated provider. - @param options Options originally passed to @link terminate terminate@/link, plus kIOServiceRecursing. - @result result of the terminate request on the client. */ - - virtual bool terminateClient( IOService * client, IOOptionBits options ); - - /* Busy state indicates discovery, matching or termination is in progress */ - -/*! @function getBusyState - @abstract Returns the busyState of an IOService object. - @discussion Many activities in IOService are asynchronous. When registration, matching, or termination is in progress on an IOService object, its busyState is increased by one. Change in busyState to or from zero also changes the IOService object's provider's busyState by one, which means that an IOService object is marked busy when any of the above activities is ocurring on it or any of its clients. - @result The busyState value. */ - - virtual UInt32 getBusyState( void ); - -/*! @function adjustBusy - @abstract Adjusts the busyState of an IOService object. - @discussion Applies a delta to an IOService object's busyState. A change in the busyState to or from zero will change the IOService object's provider's busyState by one (in the same direction). - @param delta The delta to be applied to the IOService object's busyState. */ - - virtual void adjustBusy( SInt32 delta ); - - APPLE_KEXT_COMPATIBILITY_VIRTUAL - IOReturn waitQuiet(mach_timespec_t * timeout) - APPLE_KEXT_DEPRECATED; - -/*! @function waitQuiet - @abstract Waits for an IOService object's busyState to be zero. - @discussion Blocks the caller until an IOService object is non busy. - @param timeout The maximum time to wait in nanoseconds. Default is to wait forever. - @result Returns an error code if Mach synchronization primitives fail, kIOReturnTimeout, or kIOReturnSuccess. */ - - IOReturn waitQuiet(uint64_t timeout = UINT64_MAX); - - /* Matching */ - -/*! @function matchPropertyTable - @abstract Allows a registered IOService object to implement family specific matching. - @discussion All matching on an IOService object will call this method to allow a family writer to implement matching in addition to the generic methods provided by IOService. The implementer should examine the matching dictionary passed to see if it contains properties the family understands for matching, and use them to match with the IOService object if so. Note that since matching is also carried out by other parts of the I/O Kit, the matching dictionary may contain properties the family does not understand - these should not be considered matching failures. - @param table The dictionary of properties to be matched against. - @param score Pointer to the current driver's probe score, which is used to order multiple matching drivers in the same match category. It defaults to the value of the IOProbeScore property in the drivers property table, or kIODefaultProbeScore if none is specified. - @result false if the family considers the matching dictionary does not match in properties it understands; true otherwise. */ - - virtual bool matchPropertyTable( OSDictionary * table, - SInt32 * score ); - - virtual bool matchPropertyTable( OSDictionary * table ); - -/*! @function matchLocation - @abstract Allows a registered IOService object to direct location matching. - @discussion By default, a location matching property will be applied to an IOService object's provider. This method allows that behavior to be overridden by families. - @param client The IOService object at which matching is taking place. - @result Returns the IOService instance to be used for location matching. */ - - virtual LIBKERN_RETURNS_NOT_RETAINED IOService * matchLocation( IOService * client ); - - /* Resource service */ - -/*! @function publishResource - @abstract Uses the resource service to publish a property. - @discussion The resource service uses IOService's matching and notification to allow objects to be published and found by any I/O Kit client by a global name. publishResource makes an object available to anyone waiting for it or looking for it in the future. - @param key An OSSymbol key that globally identifies the object. - @param value The object to be published. */ - - static void publishResource( const OSSymbol * key, OSObject * value = 0 ); - -/*! @function publishResource - @abstract Uses the resource service to publish a property. - @discussion The resource service uses IOService object's matching and notification to allow objects to be published and found by any I/O Kit client by a global name. publishResource makes an object available to anyone waiting for it or looking for it in the future. - @param key A C string key that globally identifies the object. - @param value The object to be published. */ - - static void publishResource( const char * key, OSObject * value = 0 ); - virtual bool addNeededResource( const char * key ); - - /* Notifications */ - -/*! @function addNotification - @abstract Deprecated use addMatchingNotification(). Adds a persistant notification handler to be notified of IOService events. - @discussion IOService will deliver notifications of changes in state of an IOService object to registered clients. The type of notification is specified by a symbol, for example gIOMatchedNotification or gIOTerminatedNotification, and notifications will only include IOService objects that match the supplied matching dictionary. Notifications are ordered by a priority set with addNotification. When the notification is installed, its handler will be called with each of any currently existing IOService objects that are in the correct state (eg. registered) and match the supplied matching dictionary, avoiding races between finding preexisting and new IOService events. The notification request is identified by an instance of an IONotifier object, through which it can be enabled, disabled, or removed. addNotification consumes a retain count on the matching dictionary when the notification is removed. - @param type An OSSymbol identifying the type of notification and IOService state: -
gIOPublishNotification Delivered when an IOService object is registered. -
gIOFirstPublishNotification Delivered when an IOService object is registered, but only once per IOService instance. Some IOService objects may be reregistered when their state is changed. -
gIOMatchedNotification Delivered when an IOService object has been matched with all client drivers, and they have been probed and started. -
gIOFirstMatchNotification Delivered when an IOService object has been matched with all client drivers, but only once per IOService instance. Some IOService objects may be reregistered when their state is changed. -
gIOTerminatedNotification Delivered after an IOService object has been terminated, during its finalize stage. - @param matching A matching dictionary to restrict notifications to only matching IOService objects. The dictionary will be released when the notification is removed, consuming the passed-in reference. - @param handler A C function callback to deliver notifications. - @param target An instance reference for the callback's use. - @param ref A reference constant for the callback's use. - @param priority A constant ordering all notifications of a each type. - @result An instance of an IONotifier object that can be used to control or destroy the notification request. */ - - static IONotifier * addNotification( - const OSSymbol * type, OSDictionary * matching, - IOServiceNotificationHandler handler, - void * target, void * ref = 0, - SInt32 priority = 0 ) - APPLE_KEXT_DEPRECATED; - -/*! @function addMatchingNotification - @abstract Adds a persistant notification handler to be notified of IOService events. - @discussion IOService will deliver notifications of changes in state of an IOService object to registered clients. The type of notification is specified by a symbol, for example gIOMatchedNotification or gIOTerminatedNotification, and notifications will only include IOService objects that match the supplied matching dictionary. Notifications are ordered by a priority set with addNotification. When the notification is installed, its handler will be called with each of any currently existing IOService objects that are in the correct state (eg. registered) and match the supplied matching dictionary, avoiding races between finding preexisting and new IOService events. The notification request is identified by an instance of an IONotifier object, through which it can be enabled, disabled, or removed. addMatchingNotification does not consume a reference on the matching dictionary when the notification is removed, unlike addNotification. - @param type An OSSymbol identifying the type of notification and IOService state: -
gIOPublishNotification Delivered when an IOService object is registered. -
gIOFirstPublishNotification Delivered when an IOService object is registered, but only once per IOService instance. Some IOService objects may be reregistered when their state is changed. -
gIOMatchedNotification Delivered when an IOService object has been matched with all client drivers, and they have been probed and started. -
gIOFirstMatchNotification Delivered when an IOService object has been matched with all client drivers, but only once per IOService instance. Some IOService objects may be reregistered when their state is changed. -
gIOTerminatedNotification Delivered after an IOService object has been terminated, during its finalize stage. - @param matching A matching dictionary to restrict notifications to only matching IOService objects. The dictionary is retained while the notification is installed. (Differs from addNotification). - @param handler A C function callback to deliver notifications. - @param target An instance reference for the callback's use. - @param ref A reference constant for the callback's use. - @param priority A constant ordering all notifications of a each type. - @result An instance of an IONotifier object that can be used to control or destroy the notification request. */ - - static IONotifier * addMatchingNotification( - const OSSymbol * type, OSDictionary * matching, - IOServiceMatchingNotificationHandler handler, - void * target, void * ref = 0, - SInt32 priority = 0 ); - -/*! @function waitForService - @abstract Deprecated use waitForMatchingService(). Waits for a matching to service to be published. - @discussion Provides a method of waiting for an IOService object matching the supplied matching dictionary to be registered and fully matched. - @param matching The matching dictionary describing the desired IOService object. waitForService consumes one reference of the matching dictionary. - @param timeout The maximum time to wait. - @result A published IOService object matching the supplied dictionary. */ - - static LIBKERN_RETURNS_NOT_RETAINED IOService * waitForService( LIBKERN_CONSUMED OSDictionary * matching, - mach_timespec_t * timeout = 0); - -/*! @function waitForMatchingService - @abstract Waits for a matching to service to be published. - @discussion Provides a method of waiting for an IOService object matching the supplied matching dictionary to be registered and fully matched. - @param matching The matching dictionary describing the desired IOService object. (Does not consume a reference of the matching dictionary - differs from waitForService() which does consume a reference on the matching dictionary.) - @param timeout The maximum time to wait in nanoseconds. Default is to wait forever. - @result A published IOService object matching the supplied dictionary. waitForMatchingService returns a reference to the IOService which should be released by the caller. (Differs from waitForService() which does not retain the returned object.) */ - - static IOService * waitForMatchingService( OSDictionary * matching, - uint64_t timeout = UINT64_MAX); - -/*! @function getMatchingServices - @abstract Finds the set of current published IOService objects matching a matching dictionary. - @discussion Provides a method of finding the current set of published IOService objects matching the supplied matching dictionary. - @param matching The matching dictionary describing the desired IOService objects. - @result An instance of an iterator over a set of IOService objects. To be released by the caller. */ - - static OSIterator * getMatchingServices( OSDictionary * matching ); - -/*! @function copyMatchingService - @abstract Finds one of the current published IOService objects matching a matching dictionary. - @discussion Provides a method to find one member of the set of published IOService objects matching the supplied matching dictionary. - @param matching The matching dictionary describing the desired IOService object. - @result The IOService object or NULL. To be released by the caller. */ - - static IOService * copyMatchingService( OSDictionary * matching ); - -public: - /* Helpers to make matching dictionaries for simple cases, - * they add keys to an existing dictionary, or create one. */ - -/*! @function serviceMatching - @abstract Creates a matching dictionary, or adds matching properties to an existing dictionary, that specify an IOService class match. - @discussion A very common matching criteria for IOService object is based on its class. serviceMatching creates a matching dictionary that specifies any IOService object of a class, or its subclasses. The class is specified by name, and an existing dictionary may be passed in, in which case the matching properties will be added to that dictionary rather than creating a new one. - @param className The class name, as a const C string. Class matching is successful on IOService objects of this class or any subclass. - @param table If zero, serviceMatching creates a matching dictionary and returns a reference to it, otherwise the matching properties are added to the specified dictionary. - @result The matching dictionary created, or passed in, is returned on success, or zero on failure. */ - - static OSDictionary * serviceMatching( const char * className, - OSDictionary * table = 0 ); - -/*! @function serviceMatching - @abstract Creates a matching dictionary, or adds matching properties to an existing dictionary, that specify an IOService class match. - @discussion A very common matching criteria for IOService object is based on its class. serviceMatching creates a matching dictionary that specifies any IOService of a class, or its subclasses. The class is specified by name, and an existing dictionary may be passed in, in which case the matching properties will be added to that dictionary rather than creating a new one. - @param className The class name, as an OSString (which includes OSSymbol). Class matching is successful on IOService objects of this class or any subclass. - @param table If zero, serviceMatching creates a matching dictionary and returns a reference to it, otherwise the matching properties are added to the specified dictionary. - @result The matching dictionary created, or passed in, is returned on success, or zero on failure. */ - - static OSDictionary * serviceMatching( const OSString * className, - OSDictionary * table = 0 ); - -/*! @function nameMatching - @abstract Creates a matching dictionary, or adds matching properties to an existing dictionary, that specify an IOService name match. - @discussion A very common matching criteria for IOService object is based on its name. nameMatching creates a matching dictionary that specifies any IOService object which responds successfully to the @link //apple_ref/cpp/instm/IORegistryEntry/compareName/virtualbool/(OSString*,OSString**) IORegistryEntry::compareName@/link method. An existing dictionary may be passed in, in which case the matching properties will be added to that dictionary rather than creating a new one. - @param name The service's name, as a const C string. Name matching is successful on IOService objects that respond successfully to the IORegistryEntry::compareName method. - @param table If zero, nameMatching creates a matching dictionary and returns a reference to it, otherwise the matching properties are added to the specified dictionary. - @result The matching dictionary created, or passed in, is returned on success, or zero on failure. */ - - static OSDictionary * nameMatching( const char * name, - OSDictionary * table = 0 ); - -/*! @function nameMatching - @abstract Creates a matching dictionary, or adds matching properties to an existing dictionary, that specify an IOService name match. - @discussion A very common matching criteria for IOService object is based on its name. nameMatching creates a matching dictionary that specifies any IOService object which responds successfully to the @link //apple_ref/cpp/instm/IORegistryEntry/compareName/virtualbool/(OSString*,OSString**) IORegistryEntry::compareName@/link method. An existing dictionary may be passed in, in which case the matching properties will be added to that dictionary rather than creating a new one. - @param name The service's name, as an OSString (which includes OSSymbol). Name matching is successful on IOService objects that respond successfully to the IORegistryEntry::compareName method. - @param table If zero, nameMatching creates a matching dictionary and returns a reference to it, otherwise the matching properties are added to the specified dictionary. - @result The matching dictionary created, or passed in, is returned on success, or zero on failure. */ - - static OSDictionary * nameMatching( const OSString* name, - OSDictionary * table = 0 ); - -/*! @function resourceMatching - @abstract Creates a matching dictionary, or adds matching properties to an existing dictionary, that specify a resource service match. - @discussion IOService maintains a resource service IOResources that allows objects to be published and found globally in the I/O Kit based on a name, using the standard IOService matching and notification calls. - @param name The resource name, as a const C string. Resource matching is successful when an object by that name has been published with the publishResource method. - @param table If zero, resourceMatching creates a matching dictionary and returns a reference to it, otherwise the matching properties are added to the specified dictionary. - @result The matching dictionary created, or passed in, is returned on success, or zero on failure. */ - - static OSDictionary * resourceMatching( const char * name, - OSDictionary * table = 0 ); - -/*! @function resourceMatching - @abstract Creates a matching dictionary, or adds matching properties to an existing dictionary, that specify a resource service match. - @discussion IOService maintains a resource service IOResources that allows objects to be published and found globally in the I/O Kit based on a name, using the standard IOService matching and notification calls. - @param name The resource name, as an OSString (which includes OSSymbol). Resource matching is successful when an object by that name has been published with the publishResource method. - @param table If zero, resourceMatching creates a matching dictionary and returns a reference to it, otherwise the matching properties are added to the specified dictionary. - @result The matching dictionary created, or passed in, is returned on success, or zero on failure. */ - - static OSDictionary * resourceMatching( const OSString * name, - OSDictionary * table = 0 ); - - -/*! @function propertyMatching - @abstract Creates a matching dictionary, or adds matching properties to an existing dictionary, that specify an IOService phandle match. - @discussion TODO A very common matching criteria for IOService is based on its name. nameMatching will create a matching dictionary that specifies any IOService which respond successfully to the IORegistryEntry method compareName. An existing dictionary may be passed in, in which case the matching properties will be added to that dictionary rather than creating a new one. - @param key The service's phandle, as a const UInt32. PHandle matching is successful on IOService objects that respond successfully to the IORegistryEntry method compareName. - @param value The service's phandle, as a const UInt32. PHandle matching is successful on IOService's which respond successfully to the IORegistryEntry method compareName. - @param table If zero, nameMatching will create a matching dictionary and return a reference to it, otherwise the matching properties are added to the specified dictionary. - @result The matching dictionary created, or passed in, is returned on success, or zero on failure. */ - - static OSDictionary * propertyMatching( const OSSymbol * key, const OSObject * value, - OSDictionary * table = 0 ); - -/*! @function registryEntryIDMatching - @abstract Creates a matching dictionary, or adds matching properties to an existing dictionary, that specify a IORegistryEntryID match. - @discussion registryEntryIDMatching creates a matching dictionary that specifies the IOService object with the assigned registry entry ID (returned by IORegistryEntry::getRegistryEntryID()). An existing dictionary may be passed in, in which case the matching properties will be added to that dictionary rather than creating a new one. - @param entryID The service's ID. Matching is successful on the IOService object that return that ID from the IORegistryEntry::getRegistryEntryID() method. - @param table If zero, registryEntryIDMatching creates a matching dictionary and returns a reference to it, otherwise the matching properties are added to the specified dictionary. - @result The matching dictionary created, or passed in, is returned on success, or zero on failure. */ - - static OSDictionary * registryEntryIDMatching( uint64_t entryID, - OSDictionary * table = 0 ); - - -/*! @function addLocation - @abstract Adds a location matching property to an existing dictionary. - @discussion This function creates matching properties that specify the location of a IOService object, as an embedded matching dictionary. This matching will be successful on an IOService object that attached to an IOService object which matches this location matching dictionary. - @param table The matching properties are added to the specified dictionary, which must be non-zero. - @result The location matching dictionary created is returned on success, or zero on failure. */ - - static OSDictionary * addLocation( OSDictionary * table ); - - /* Helpers for matching dictionaries. */ - -/*! @function compareProperty - @abstract Compares a property in a matching dictionary with an IOService object's property table. - @discussion This is a helper function to aid in implementing @link matchPropertyTable matchPropertyTable@/link. If the property specified by key exists in the matching dictionary, it is compared with a property of the same name in the IOService object's property table. The comparison is performed with the isEqualTo method. If the property does not exist in the matching table, success is returned. If the property exists in the matching dictionary but not the IOService property table, failure is returned. - @param matching The matching dictionary, which must be non-zero. - @param key The dictionary key specifying the property to be compared, as a C string. - @result true if the property does not exist in the matching table. If the property exists in the matching dictionary but not the IOService property table, failure is returned. Otherwise the result of calling the property from the matching dictionary's isEqualTo method with the IOService property as an argument is returned. */ - - virtual bool compareProperty( OSDictionary * matching, - const char * key ); -/*! @function compareProperty - @abstract Compares a property in a matching dictionary with an IOService object's property table. - @discussion This is a helper function to aid in implementing @link matchPropertyTable matchPropertyTable@/link. If the property specified by key exists in the matching dictionary, it is compared with a property of the same name in the IOService object's property table. The comparison is performed with the isEqualTo method. If the property does not exist in the matching table, success is returned. If the property exists in the matching dictionary but not the IOService property table, failure is returned. - @param matching The matching dictionary, which must be non-zero. - @param key The dictionary key specifying the property to be compared, as an OSString (which includes OSSymbol). - @result true if the property does not exist in the matching table. If the property exists in the matching dictionary but not the IOService property table, failure is returned. Otherwise the result of calling the property from the matching dictionary's isEqualTo method with the IOService property as an argument is returned. */ - - virtual bool compareProperty( OSDictionary * matching, - const OSString * key ); - -/*! @function compareProperties - @abstract Compares a set of properties in a matching dictionary with an IOService object's property table. - @discussion This is a helper function to aid in implementing @link matchPropertyTable matchPropertyTable@/link. A collection of dictionary keys specifies properties in a matching dictionary to be compared, with compareProperty, with an IOService object's property table, if compareProperty returns true for each key, success is returned; otherwise failure. - @param matching The matching dictionary, which must be non-zero. - @param keys A collection (eg. OSSet, OSArray, OSDictionary) which should contain OSStrings (or OSSymbols) that specify the property keys to be compared. - @result Success if compareProperty returns true for each key in the collection; otherwise failure. */ - - virtual bool compareProperties( OSDictionary * matching, - OSCollection * keys ); - - /* Client / provider accessors */ - -/*! @function attach - @abstract Attaches an IOService client to a provider in the I/O Registry. - @discussion This function called in an IOService client enters the client into the I/O Registry as a child of the provider in the service plane. The provider must be active or the attach will fail. Multiple attach calls to the same provider are no-ops and return success. A client may be attached to multiple providers. Entering an object into the I/O Registry retains both the client and provider until they are detached. - @param provider The IOService object which will serve as this object's provider. - @result false if the provider is inactive or on a resource failure; otherwise true. */ - - virtual bool attach( IOService * provider ); - -/*! @function detach - @abstract Detaches an IOService client from a provider in the I/O Registry. - @discussion This function called in an IOService client removes the client as a child of the provider in the service plane of the I/O Registry. If the provider is not a parent of the client this is a no-op, otherwise the I/O Registry releases both the client and provider. - @param provider The IOService object to detach from. */ - - virtual void detach( IOService * provider ); - -/*! @function getProvider - @abstract Returns an IOService object's primary provider. - @discussion This function called in an IOService client will return the provider to which it was first attached. Because the majority of IOService objects have only one provider, this is a useful simplification and also supports caching of the provider when the I/O Registry is unchanged. - @result The first provider of the client, or zero if the IOService object is not attached into the I/O Registry. The provider is retained while the client is attached, and should not be released by the caller. */ - - virtual IOService * getProvider( void ) const; - -/*! @function getWorkLoop - @abstract Returns the current work loop or provider->getWorkLoop. - @discussion This function returns a valid work loop that a client can use to add an IOCommandGate to. The intention is that an IOService client has data that needs to be protected but doesn't want to pay the cost of a dedicated thread. This data has to be accessed from a provider's call-out context as well. So to achieve both of these goals the client creates an IOCommandGate to lock access to his data but he registers it with the provider's work loop, i.e. the work loop which will make the completion call-outs. This avoids a potential deadlock because the work loop gate uses a recursive lock, which allows the same lock to be held multiple times by a single thread. - @result A work loop, either the current work loop or it walks up the @link getProvider getProvider@/link chain calling getWorkLoop. Eventually it will reach a valid work loop-based driver or the root of the I/O tree, where it will return a system-wide work loop. Returns 0 if it fails to find (or create) a work loop.*/ - - virtual IOWorkLoop * getWorkLoop() const; - -/*! @function getProviderIterator - @abstract Returns an iterator over an IOService object's providers. - @discussion For those few IOService objects that obtain service from multiple providers, this method supplies an iterator over a client's providers. - @result An iterator over the providers of the client, or zero if there is a resource failure. The iterator must be released when the iteration is finished. All objects returned by the iteration are retained while the iterator is valid, though they may no longer be attached during the iteration. */ - - virtual OSIterator * getProviderIterator( void ) const; - -/*! @function getOpenProviderIterator - @abstract Returns an iterator over an client's providers that are currently opened by the client. - @discussion For those few IOService objects that obtain service from multiple providers, this method supplies an iterator over a client's providers, locking each in turn with @link lockForArbitration lockForArbitration@/link and returning those that have been opened by the client. - @result An iterator over the providers the client has open, or zero if there is a resource failure. The iterator must be released when the iteration is finished. All objects returned by the iteration are retained while the iterator is valid, and the current entry in the iteration is locked with lockForArbitration, protecting it from state changes. */ - - virtual OSIterator * getOpenProviderIterator( void ) const; - -/*! @function getClient - @abstract Returns an IOService object's primary client. - @discussion This function called in an IOService provider will return the first client to attach to it. For IOService objects which have only only one client, this may be a useful simplification. - @result The first client of the provider, or zero if the IOService object is not attached into the I/O Registry. The client is retained while it is attached, and should not be released by the caller. */ - - virtual IOService * getClient( void ) const; - -/*! @function getClientIterator - @abstract Returns an iterator over an IOService object's clients. - @discussion For IOService objects that may have multiple clients, this method supplies an iterator over a provider's clients. - @result An iterator over the clients of the provider, or zero if there is a resource failure. The iterator must be released when the iteration is finished. All objects returned by the iteration are retained while the iterator is valid, though they may no longer be attached during the iteration. */ - - virtual OSIterator * getClientIterator( void ) const; - -/*! @function getOpenClientIterator - @abstract Returns an iterator over a provider's clients that currently have opened the provider. - @discussion For IOService objects that may have multiple clients, this method supplies an iterator over a provider's clients, locking each in turn with @link lockForArbitration lockForArbitration@/link and returning those that have opened the provider. - @result An iterator over the clients that have opened the provider, or zero if there is a resource failure. The iterator must be released when the iteration is finished. All objects returned by the iteration are retained while the iterator is valid, and the current entry in the iteration is locked with lockForArbitration, protecting it from state changes. */ - - virtual OSIterator * getOpenClientIterator( void ) const; - -/*! @function callPlatformFunction - @abstract Calls the platform function with the given name. - @discussion The platform expert or other drivers may implement various functions to control hardware features. callPlatformFunction allows any IOService object to access these functions. Normally callPlatformFunction is called on a service's provider. The provider services the request or passes it to its provider. The system's IOPlatformExpert subclass catches functions it knows about and redirects them into other parts of the service plane. If the IOPlatformExpert subclass cannot execute the function, the base class is called. The IOPlatformExpert base class attempts to find a service to execute the function by looking up the function name in an IOResources name space. A service may publish a service using publishResource(functionName, this). If no service can be found to execute the function an error is returned. - @param functionName Name of the function to be called. When functionName is a C string, callPlatformFunction converts the C string to an OSSymbol and calls the OSSymbol version of callPlatformFunction. This process can block and should not be used from an interrupt context. - @param waitForFunction If true, callPlatformFunction will not return until the function has been called. - @result An IOReturn code; kIOReturnSuccess if the function was successfully executed, kIOReturnUnsupported if a service to execute the function could not be found. Other return codes may be returned by the function.*/ - - virtual IOReturn callPlatformFunction( const OSSymbol * functionName, - bool waitForFunction, - void *param1, void *param2, - void *param3, void *param4 ); - - virtual IOReturn callPlatformFunction( const char * functionName, - bool waitForFunction, - void *param1, void *param2, - void *param3, void *param4 ); - - - /* Some accessors */ - -/*! @function getPlatform - @abstract Returns a pointer to the platform expert instance for the computer. - @discussion This method provides an accessor to the platform expert instance for the computer. - @result A pointer to the IOPlatformExport instance. It should not be released by the caller. */ - - static IOPlatformExpert * getPlatform( void ); - -/*! @function getPMRootDomain - @abstract Returns a pointer to the power management root domain instance for the computer. - @discussion This method provides an accessor to the power management root domain instance for the computer. - @result A pointer to the power management root domain instance. It should not be released by the caller. */ - - static class IOPMrootDomain * getPMRootDomain( void ); - -/*! @function getServiceRoot - @abstract Returns a pointer to the root of the service plane. - @discussion This method provides an accessor to the root of the service plane for the computer. - @result A pointer to the IOService instance at the root of the service plane. It should not be released by the caller. */ - - static IOService * getServiceRoot( void ); - -/*! @function getResourceService - @abstract Returns a pointer to the IOResources service. - @discussion IOService maintains a resource service IOResources that allows objects to be published and found globally in the I/O Kit based on a name, using the standard IOService matching and notification calls. - @result A pointer to the IOResources instance. It should not be released by the caller. */ - - static IOService * getResourceService( void ); - - /* Allocate resources for a matched service */ - -/*! @function getResources - @abstract Allocates any needed resources for a published IOService object before clients attach. - @discussion This method is called during the registration process for an IOService object if there are successful driver matches, before any clients attach. It allows for lazy allocation of resources to an IOService object when a matching driver is found. - @result An IOReturn code; kIOReturnSuccess is necessary for the IOService object to be successfully used, otherwise the registration process for the object is halted. */ - - virtual IOReturn getResources( void ); - - /* Device memory accessors */ - -/*! @function getDeviceMemoryCount - @abstract Returns a count of the physical memory ranges available for a device. - @discussion This method returns the count of physical memory ranges, each represented by an IODeviceMemory instance, that have been allocated for a memory mapped device. - @result An integer count of the number of ranges available. */ - - virtual IOItemCount getDeviceMemoryCount( void ); - -/*! @function getDeviceMemoryWithIndex - @abstract Returns an instance of IODeviceMemory representing one of a device's memory mapped ranges. - @discussion This method returns a pointer to an instance of IODeviceMemory for the physical memory range at the given index for a memory mapped device. - @param index An index into the array of ranges assigned to the device. - @result A pointer to an instance of IODeviceMemory, or zero if the index is beyond the count available. The IODeviceMemory is retained by the provider, so is valid while attached, or while any mappings to it exist. It should not be released by the caller. See also @link mapDeviceMemoryWithIndex mapDeviceMemoryWithIndex@/link, which creates a device memory mapping. */ - - virtual IODeviceMemory * getDeviceMemoryWithIndex( unsigned int index ); - -/*! @function mapDeviceMemoryWithIndex - @abstract Maps a physical range of a device. - @discussion This method creates a mapping for the IODeviceMemory at the given index, with IODeviceMemory::map(options). The mapping is represented by the returned instance of IOMemoryMap, which should not be released until the mapping is no longer required. - @param index An index into the array of ranges assigned to the device. - @result An instance of IOMemoryMap, or zero if the index is beyond the count available. The mapping should be released only when access to it is no longer required. */ - - virtual IOMemoryMap * mapDeviceMemoryWithIndex( unsigned int index, - IOOptionBits options = 0 ); - -/*! @function getDeviceMemory - @abstract Returns the array of IODeviceMemory objects representing a device's memory mapped ranges. - @discussion This method returns an array of IODeviceMemory objects representing the physical memory ranges allocated to a memory mapped device. - @result An OSArray of IODeviceMemory objects, or zero if none are available. The array is retained by the provider, so is valid while attached. */ - - virtual OSArray * getDeviceMemory( void ); - -/*! @function setDeviceMemory - @abstract Sets the array of IODeviceMemory objects representing a device's memory mapped ranges. - @discussion This method sets an array of IODeviceMemory objects representing the physical memory ranges allocated to a memory mapped device. - @param array An OSArray of IODeviceMemory objects, or zero if none are available. The array will be retained by the object. */ - - virtual void setDeviceMemory( OSArray * array ); - - /* Interrupt accessors */ - -/*! @function registerInterrupt - @abstract Registers a C function interrupt handler for a device supplying interrupts. - @discussion This method installs a C function interrupt handler to be called at primary interrupt time for a device's interrupt. Only one handler may be installed per interrupt source. IOInterruptEventSource provides a work loop based abstraction for interrupt delivery that may be more appropriate for work loop based drivers. - @param source The index of the interrupt source in the device. - @param target An object instance to be passed to the interrupt handler. - @param handler The C function to be called at primary interrupt time when the interrupt occurs. The handler should process the interrupt by clearing the interrupt, or by disabling the source. - @param refCon A reference constant for the handler's use. - @result An IOReturn code.
kIOReturnNoInterrupt is returned if the source is not valid; kIOReturnNoResources is returned if the interrupt already has an installed handler. */ - - virtual IOReturn registerInterrupt(int source, OSObject *target, - IOInterruptAction handler, - void *refCon = 0); - -/*! @function unregisterInterrupt - @abstract Removes a C function interrupt handler for a device supplying hardware interrupts. - @discussion This method removes a C function interrupt handler previously installed with @link registerInterrupt registerInterrupt@/link. - @param source The index of the interrupt source in the device. - @result An IOReturn code (kIOReturnNoInterrupt is returned if the source is not valid). */ - - virtual IOReturn unregisterInterrupt(int source); - -/*! @function getInterruptType - @abstract Returns the type of interrupt used for a device supplying hardware interrupts. - @param source The index of the interrupt source in the device. - @param interruptType The interrupt type for the interrupt source will be stored here by getInterruptType.
kIOInterruptTypeEdge will be returned for edge-trigggered sources.
kIOInterruptTypeLevel will be returned for level-trigggered sources. - @result An IOReturn code (kIOReturnNoInterrupt is returned if the source is not valid). */ - - virtual IOReturn getInterruptType(int source, int *interruptType); - -/*! @function enableInterrupt - @abstract Enables a device interrupt. - @discussion It is the caller's responsiblity to keep track of the enable state of the interrupt source. - @param source The index of the interrupt source in the device. - @result An IOReturn code (kIOReturnNoInterrupt is returned if the source is not valid). */ - - virtual IOReturn enableInterrupt(int source); - -/*! @function disableInterrupt - @abstract Synchronously disables a device interrupt. - @discussion If the interrupt routine is running, the call will block until the routine completes. It is the caller's responsiblity to keep track of the enable state of the interrupt source. - @param source The index of the interrupt source in the device. - @result An IOReturn code (kIOReturnNoInterrupt is returned if the source is not valid). */ - - virtual IOReturn disableInterrupt(int source); - -/*! @function causeInterrupt - @abstract Causes a device interrupt to occur. - @discussion Emulates a hardware interrupt, to be called from task level. - @param source The index of the interrupt source in the device. - @result An IOReturn code (kIOReturnNoInterrupt is returned if the source is not valid). */ - - virtual IOReturn causeInterrupt(int source); - -/*! @function requestProbe - @abstract Requests that hardware be re-scanned for devices. - @discussion For bus families that do not usually detect device addition or removal, this method represents an external request (eg. from a utility application) to rescan and publish or remove found devices. - @param options Family defined options, not interpreted by IOService. - @result An IOReturn code. */ - - virtual IOReturn requestProbe( IOOptionBits options ); - - /* Generic API for non-data-path upstream calls */ - -/*! @function message - @abstract Receives a generic message delivered from an attached provider. - @discussion A provider may deliver messages via the message method to its clients informing them of state changes, such as kIOMessageServiceIsTerminated or kIOMessageServiceIsSuspended. Certain messages are defined by the I/O Kit in IOMessage.h while others may be family dependent. This method is implemented in the client to receive messages. - @param type A type defined in IOMessage.h or defined by the provider family. - @param provider The provider from which the message originates. - @param argument An argument defined by the provider family, not used by IOService. - @result An IOReturn code defined by the message type. */ - - virtual IOReturn message( UInt32 type, IOService * provider, - void * argument = 0 ); - -/*! @function messageClient - @abstract Sends a generic message to an attached client. - @discussion A provider may deliver messages via the @link message message@/link method to its clients informing them of state changes, such as kIOMessageServiceIsTerminated or kIOMessageServiceIsSuspended. Certain messages are defined by the I/O Kit in IOMessage.h while others may be family dependent. This method may be called in the provider to send a message to the specified client, which may be useful for overrides. - @param messageType A type defined in IOMessage.h or defined by the provider family. - @param client A client of the IOService to send the message. - @param messageArgument An argument defined by the provider family, not used by IOService. - @param argSize Specifies the size of messageArgument, in bytes. If argSize is non-zero, messageArgument is treated as a pointer to argSize bytes of data. If argSize is 0 (the default), messageArgument is treated as an ordinal and passed by value. - @result The return code from the client message call. */ - - virtual IOReturn messageClient( UInt32 messageType, OSObject * client, - void * messageArgument = 0, vm_size_t argSize = 0 ); - -/*! @function messageClients - @abstract Sends a generic message to all attached clients. - @discussion A provider may deliver messages via the @link message message@/link method to its clients informing them of state changes, such as kIOMessageServiceIsTerminated or kIOMessageServiceIsSuspended. Certain messages are defined by the I/O Kit in IOMessage.h while others may be family dependent. This method may be called in the provider to send a message to all the attached clients, via the @link messageClient messageClient@/link method. - @param type A type defined in IOMessage.h or defined by the provider family. - @param argument An argument defined by the provider family, not used by IOService. - @param argSize Specifies the size of argument, in bytes. If argSize is non-zero, argument is treated as a pointer to argSize bytes of data. If argSize is 0 (the default), argument is treated as an ordinal and passed by value. - @result Any non-kIOReturnSuccess return codes returned by the clients, or kIOReturnSuccess if all return kIOReturnSuccess. */ - - virtual IOReturn messageClients( UInt32 type, - void * argument = 0, vm_size_t argSize = 0 ); - - virtual IONotifier * registerInterest( const OSSymbol * typeOfInterest, - IOServiceInterestHandler handler, - void * target, void * ref = 0 ); - - virtual void applyToProviders( IOServiceApplierFunction applier, - void * context ); - - virtual void applyToClients( IOServiceApplierFunction applier, - void * context ); - - virtual void applyToInterested( const OSSymbol * typeOfInterest, - OSObjectApplierFunction applier, - void * context ); - - virtual IOReturn acknowledgeNotification( IONotificationRef notification, - IOOptionBits response ); - - /* User client create */ - -/*! @function newUserClient - @abstract Creates a connection for a non kernel client. - @discussion A non kernel client may request a connection be opened via the @link //apple_ref/c/func/IOServiceOpen IOServiceOpen@/link library function, which will call this method in an IOService object. The rules and capabilities of user level clients are family dependent, and use the functions of the IOUserClient class for support. IOService's implementation returns kIOReturnUnsupported, so any family supporting user clients must implement this method. - @param owningTask The Mach task of the client thread in the process of opening the user client. Note that in Mac OS X, each process is based on a Mach task and one or more Mach threads. For more information on the composition of a Mach task and its relationship with Mach threads, see {@linkdoc //apple_ref/doc/uid/TP30000905-CH209-TPXREF103 "Tasks and Threads"}. - @param securityID A token representing the access level for the task. - @param type A constant specifying the type of connection to be created, specified by the caller of @link //apple_ref/c/func/IOServiceOpen IOServiceOpen@/link and interpreted only by the family. - @param handler An instance of an IOUserClient object to represent the connection, which will be released when the connection is closed, or zero if the connection was not opened. - @param properties A dictionary of additional properties for the connection. - @result A return code to be passed back to the caller of IOServiceOpen. */ - - virtual IOReturn newUserClient( task_t owningTask, void * securityID, - UInt32 type, OSDictionary * properties, - LIBKERN_RETURNS_RETAINED IOUserClient ** handler ); - - virtual IOReturn newUserClient( task_t owningTask, void * securityID, - UInt32 type, LIBKERN_RETURNS_RETAINED IOUserClient ** handler ); - - /* Return code utilities */ - -/*! @function stringFromReturn - @abstract Supplies a programmer-friendly string from an IOReturn code. - @discussion Strings are available for the standard return codes in IOReturn.h in IOService, while subclasses may implement this method to interpret family dependent return codes. - @param rtn The IOReturn code. - @result A pointer to a constant string, or zero if the return code is unknown. */ - - virtual const char * stringFromReturn( IOReturn rtn ); - -/*! @function errnoFromReturn - @abstract Translates an IOReturn code to a BSD errno. - @discussion BSD defines its own return codes for its functions in sys/errno.h, and I/O Kit families may need to supply compliant results in BSD shims. Results are available for the standard return codes in IOReturn.h in IOService, while subclasses may implement this method to interpret family dependent return codes. - @param rtn The IOReturn code. - @result The BSD errno or EIO if unknown. */ - - virtual int errnoFromReturn( IOReturn rtn ); - - /* * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - /* * * * * * * * * * end of IOService API * * * * * * * */ - /* * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - - /* for IOInterruptController implementors */ - - int _numInterruptSources; - IOInterruptSource *_interruptSources; - - /* overrides */ - virtual bool serializeProperties( OSSerialize * s ) const override; - - void requireMaxBusStall(UInt32 ns); - void requireMaxInterruptDelay(uint32_t ns); - - /* * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - /* * * * * * * * * * * * Internals * * * * * * * * * * * */ - /* * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - - -private: - APPLE_KEXT_COMPATIBILITY_VIRTUAL - bool checkResources( void ); - APPLE_KEXT_COMPATIBILITY_VIRTUAL - bool checkResource( OSObject * matching ); - - APPLE_KEXT_COMPATIBILITY_VIRTUAL - void probeCandidates( OSOrderedSet * matches ); - APPLE_KEXT_COMPATIBILITY_VIRTUAL - bool startCandidate( IOService * candidate ); - -public: - APPLE_KEXT_COMPATIBILITY_VIRTUAL - IOService * getClientWithCategory( const OSSymbol * category ) - APPLE_KEXT_DEPRECATED; - // copyClientWithCategory is the public replacement - -private: - APPLE_KEXT_COMPATIBILITY_VIRTUAL - bool passiveMatch( OSDictionary * matching, bool changesOK = false); - APPLE_KEXT_COMPATIBILITY_VIRTUAL - void startMatching( IOOptionBits options = 0 ); - APPLE_KEXT_COMPATIBILITY_VIRTUAL - void doServiceMatch( IOOptionBits options ); - APPLE_KEXT_COMPATIBILITY_VIRTUAL - void doServiceTerminate( IOOptionBits options ); - -private: - - bool matchPassive(OSDictionary * table, uint32_t options); - bool matchInternal(OSDictionary * table, uint32_t options, unsigned int * did); - static bool instanceMatch(const OSObject * entry, void * context); - - static OSObject * copyExistingServices( OSDictionary * matching, - IOOptionBits inState, IOOptionBits options = 0 ); - - static IONotifier * setNotification( - const OSSymbol * type, OSDictionary * matching, - IOServiceMatchingNotificationHandler handler, - void * target, void * ref, - SInt32 priority = 0 ); - - static IONotifier * doInstallNotification( - const OSSymbol * type, OSDictionary * matching, - IOServiceMatchingNotificationHandler handler, - void * target, void * ref, - SInt32 priority, OSIterator ** existing ); - - static bool syncNotificationHandler( void * target, void * ref, - IOService * newService, IONotifier * notifier ); - - APPLE_KEXT_COMPATIBILITY_VIRTUAL - void deliverNotification( const OSSymbol * type, - IOOptionBits orNewState, IOOptionBits andNewState ); - - bool invokeNotifer( class _IOServiceNotifier * notify ); - - APPLE_KEXT_COMPATIBILITY_VIRTUAL - void unregisterAllInterest( void ); - - APPLE_KEXT_COMPATIBILITY_VIRTUAL - IOReturn waitForState( UInt32 mask, UInt32 value, - mach_timespec_t * timeout = 0 ); - - IOReturn waitForState( UInt32 mask, UInt32 value, uint64_t timeout ); - - UInt32 _adjustBusy( SInt32 delta ); - - bool terminatePhase1( IOOptionBits options = 0 ); - void scheduleTerminatePhase2( IOOptionBits options = 0 ); - void scheduleStop( IOService * provider ); - void scheduleFinalize( void ); - static void terminateThread( void * arg, wait_result_t unused ); - static void terminateWorker( IOOptionBits options ); - static void actionWillTerminate( IOService * victim, IOOptionBits options, - OSArray * doPhase2List, void*, void * ); - static void actionDidTerminate( IOService * victim, IOOptionBits options, - void *, void *, void *); - static void actionFinalize( IOService * victim, IOOptionBits options, - void *, void *, void *); - static void actionStop( IOService * client, IOService * provider, - void *, void *, void *); - - APPLE_KEXT_COMPATIBILITY_VIRTUAL - IOReturn resolveInterrupt(IOService *nub, int source); - APPLE_KEXT_COMPATIBILITY_VIRTUAL - IOReturn lookupInterrupt(int source, bool resolve, LIBKERN_RETURNS_NOT_RETAINED IOInterruptController **interruptController); - - - /* power management */ -public: - -/*! @function PMinit - @abstract Initializes power management for a driver. - @discussion PMinit allocates and initializes the power management instance variables, and it should be called before accessing those variables or calling the power management methods. This method should be called inside the driver's start routine and must be paired with a call to @link PMstop PMstop@/link. - Most calls to PMinit are followed by calls to @link joinPMtree joinPMtree@/link and @link registerPowerDriver registerPowerDriver@/link. */ - - virtual void PMinit( void ); - -/*! @function PMstop - @abstract Stop power managing the driver. - @discussion Removes the driver from the power plane and stop its power management. This method is synchronous against any power management method invocations (e.g. setPowerState or setAggressiveness), so when this method returns it is guaranteed those power management methods will not be entered. Driver should not call any power management methods after this call. - Calling PMstop cleans up for the three power management initialization calls: @link PMinit PMinit@/link, @link joinPMtree joinPMtree@/link, and @link registerPowerDriver registerPowerDriver@/link. */ - - virtual void PMstop( void ); - -/*! @function joinPMtree - @abstract Joins the driver into the power plane of the I/O Registry. - @discussion A driver uses this method to call its nub when initializing (usually in its start routine after calling @link PMinit PMinit@/link), to be attached into the power management hierarchy (i.e., the power plane). A driver usually calls this method on the driver for the device that provides it power (this is frequently the nub). - Before this call returns, the caller will probably be called at @link setPowerParent setPowerParent@/link and @link setAggressiveness setAggressiveness@/link and possibly at @link addPowerChild addPowerChild@/link as it is added to the hierarchy. This method may be overridden by a nub subclass. - @param driver The driver to be added to the power plane, usually this. */ - - virtual void joinPMtree( IOService * driver ); - -/*! @function registerPowerDriver - @abstract Registers a set of power states that the driver supports. - @discussion A driver defines its array of supported power states with power management in its power management initialization (its start routine). If successful, power management will call the driver to instruct it to change its power state through @link setPowerState setPowerState@/link. - Most drivers do not need to override registerPowerDriver. A nub may override registerPowerDriver if it needs to arrange its children in the power plane differently than the default placement, but this is uncommon. - @param controllingDriver A pointer to the calling driver, usually this. - @param powerStates A driver-defined array of power states that the driver and device support. Power states are defined in pwr_mgt/IOPMpowerState.h. - @param numberOfStates The number of power states in the array. - @result IOPMNoErr. All errors are logged via kprintf. */ - - virtual IOReturn registerPowerDriver( - IOService * controllingDriver, - IOPMPowerState * powerStates, - unsigned long numberOfStates ); - -/*! @function registerInterestedDriver - @abstract Allows an IOService object to register interest in the changing power state of a power-managed IOService object. - @discussion Call registerInterestedDriver on the IOService object you are interested in receiving power state messages from, and pass a pointer to the interested driver (this) as an argument. - The interested driver is retained until the power interest is removed by calling deRegisterInterestedDriver. - The interested driver should override @link powerStateWillChangeTo powerStateWillChangeTo@/link and @link powerStateDidChangeTo powerStateDidChangeTo@/link to receive these power change messages. - Interested drivers must acknowledge power changes in powerStateWillChangeTo or powerStateDidChangeTo, either via return value or later calls to @link acknowledgePowerChange acknowledgePowerChange@/link. - @param theDriver The driver of interest adds this pointer to the list of interested drivers. It informs drivers on this list before and after the power change. - @result Flags describing the capability of the device in its current power state. If the current power state is not yet defined, zero is returned (this is the case when the driver is not yet in the power domain hierarchy or hasn't fully registered with power management yet). */ - - APPLE_KEXT_COMPATIBILITY_VIRTUAL - IOPMPowerFlags registerInterestedDriver( IOService * theDriver ); - -/*! @function deRegisterInterestedDriver - @abstract De-registers power state interest from a previous call to registerInterestedDriver. - @discussion The retain from registerInterestedDriver is released. This method is synchronous against any powerStateWillChangeTo or powerStateDidChangeTo call targeting the interested driver, so when this method returns it is guaranteed those interest handlers will not be entered. - Most drivers do not need to override deRegisterInterestedDriver. - @param theDriver The interested driver previously passed into @link registerInterestedDriver registerInterestedDriver@/link. - @result A return code that can be ignored by the caller. */ - - APPLE_KEXT_COMPATIBILITY_VIRTUAL - IOReturn deRegisterInterestedDriver( IOService * theDriver ); - -/*! @function acknowledgePowerChange - @abstract Acknowledges an in-progress power state change. - @discussion When power management informs an interested object (via @link powerStateWillChangeTo powerStateWillChangeTo@/link or @link powerStateDidChangeTo powerStateDidChangeTo@/link), the object can return an immediate acknowledgement via a return code, or it may return an indication that it will acknowledge later by calling acknowledgePowerChange. - Interested objects are those that have registered as interested drivers, as well as power plane children of the power changing driver. A driver that calls @link registerInterestedDriver registerInterestedDriver@/link must call acknowledgePowerChange, or use an immediate acknowledgement return from powerStateWillChangeTo or powerStateDidChangeTo. - @param whichDriver A pointer to the calling driver. The called object tracks all interested parties to ensure that all have acknowledged the power state change. - @result IOPMNoErr. */ - - APPLE_KEXT_COMPATIBILITY_VIRTUAL - IOReturn acknowledgePowerChange( IOService * whichDriver ); - -/*! @function acknowledgeSetPowerState - @abstract Acknowledges the belated completion of a driver's setPowerState power state change. - @discussion After power management instructs a driver to change its state via @link setPowerState setPowerState@/link, that driver must acknowledge the change when its device has completed its transition. The acknowledgement may be immediate, via a return code from setPowerState, or delayed, via this call to acknowledgeSetPowerState. - Any driver that does not return kIOPMAckImplied from its setPowerState implementation must later call acknowledgeSetPowerState. - @result IOPMNoErr. */ - - APPLE_KEXT_COMPATIBILITY_VIRTUAL - IOReturn acknowledgeSetPowerState( void ); - -/*! @function requestPowerDomainState - @abstract Tells a driver to adjust its power state. - @discussion This call is handled internally by power management. It is not intended to be overridden or called by drivers. */ - - virtual IOReturn requestPowerDomainState( - IOPMPowerFlags desiredState, - IOPowerConnection * whichChild, - unsigned long specificationFlags ); - -/*! @function makeUsable - @abstract Requests that a device become usable. - @discussion This method is called when some client of a device (or the device's own driver) is asking for the device to become usable. Power management responds by telling the object upon which this method is called to change to its highest power state. - makeUsable is implemented using @link changePowerStateToPriv changePowerStateToPriv@/link. Subsequent requests for lower power, such as from changePowerStateToPriv, will pre-empt this request. - @result A return code that can be ignored by the caller. */ - - APPLE_KEXT_COMPATIBILITY_VIRTUAL - IOReturn makeUsable( void ); - -/*! @function temporaryPowerClampOn - @abstract A driver calls this method to hold itself in the highest power state until it has children. - @discussion Use temporaryPowerClampOn to hold your driver in its highest power state while waiting for child devices to attach. After children have attached, the clamp is released and the device's power state is controlled by the children's requirements. - @result A return code that can be ignored by the caller. */ - - APPLE_KEXT_COMPATIBILITY_VIRTUAL - IOReturn temporaryPowerClampOn( void ); - -/*! @function changePowerStateTo - @abstract Sets a driver's power state. - @discussion This function is one of several that are used to set a driver's power state. In most circumstances, however, you should call @link changePowerStateToPriv changePowerStateToPriv@/link instead. - Calls to changePowerStateTo, changePowerStateToPriv, and a driver's power children all affect the power state of a driver. For legacy design reasons, they have overlapping functionality. Although you should call changePowerStateToPriv to change your device's power state, you might need to call changePowerStateTo in the following circumstances: -
  • If a driver will be using changePowerStateToPriv to change its power state, it should call changePowerStateTo(0) in its start routine to eliminate the influence changePowerStateTo has on power state calculations. -
  • Call changePowerStateTo in conjunction with @link setIdleTimerPeriod setIdleTimerPeriod@/link and @link activityTickle activityTickle@/link to idle a driver into a low power state. For a driver with 3 power states, for example, changePowerStateTo(1) sets a minimum level of power state 1, such that the idle timer period may not set your device's power any lower than state 1.
- @param ordinal The number of the desired power state in the power state array. - @result A return code that can be ignored by the caller. */ - - APPLE_KEXT_COMPATIBILITY_VIRTUAL - IOReturn changePowerStateTo( unsigned long ordinal ); - -/*! @function currentCapability - @abstract Finds out the capability of a device's current power state. - @result A copy of the capabilityFlags field for the current power state in the power state array. */ - - APPLE_KEXT_COMPATIBILITY_VIRTUAL - IOPMPowerFlags currentCapability( void ); - -/*! @function currentPowerConsumption - @abstract Finds out the current power consumption of a device. - @discussion Most Mac OS X power managed drivers do not report their power consumption via the staticPower field. Thus this call will not accurately reflect power consumption for most drivers. - @result A copy of the staticPower field for the current power state in the power state array. */ - - APPLE_KEXT_COMPATIBILITY_VIRTUAL - unsigned long currentPowerConsumption( void ); - -/*! @function activityTickle - @abstract Informs power management when a power-managed device is in use, so that power management can track when it is idle and adjust its power state accordingly. - @discussion The activityTickle method is provided for objects in the system (or for the driver itself) to tell a driver that its device is being used. - The IOService superclass can manage idleness determination with a simple idle timer mechanism and this activityTickle call. To start this up, the driver calls its superclass's setIdleTimerPeriod. This starts a timer for the time interval specified in the call. When the timer expires, the superclass checks to see if there has been any activity since the last timer expiration. (It checks to see if activityTickle has been called). If there has been activity, it restarts the timer, and this process continues. When the timer expires, and there has been no device activity, the superclass lowers the device power state to the next lower state. This can continue until the device is in state zero. - After the device has been powered down by at least one power state, a subsequent call to activityTickle causes the device to be switched to a higher state required for the activity. - If the driver is managing the idleness determination totally on its own, the value of the type parameter should be kIOPMSubclassPolicy, and the driver should override the activityTickle method. The superclass IOService implementation of activityTickle does nothing with the kIOPMSubclassPolicy argument. - @param type When type is kIOPMSubclassPolicy, activityTickle is not handled in IOService and should be intercepted by the subclass. When type is kIOPMSuperclassPolicy1, an activity flag is set and the device state is checked. If the device has been powered down, it is powered up again. - @param stateNumber When type is kIOPMSuperclassPolicy1, stateNumber contains the desired power state ordinal for the activity. If the device is in a lower state, the superclass will switch it to this state. This is for devices that can handle some accesses in lower power states; the device is powered up only as far as it needs to be for the activity. - @result When type is kIOPMSuperclassPolicy1, the superclass returns true if the device is currently in the state specified by stateNumber. If the device is in a lower state and must be powered up, the superclass returns false; in this case the superclass will initiate a power change to power the device up. */ - - virtual bool activityTickle( - unsigned long type, - unsigned long stateNumber = 0 ); - -/*! @function setAggressiveness - @abstract Broadcasts an aggressiveness factor from the parent of a driver to the driver. - @discussion Implement setAggressiveness to receive a notification when an "aggressiveness Aggressiveness factors are a loose set of power management variables that contain values for system sleep timeout, display sleep timeout, whether the system is on battery or AC, and other power management features. There are several aggressiveness factors that can be broadcast and a driver may take action on whichever factors apply to it. - A driver that has joined the power plane via @link joinPMtree joinPMtree@/link will receive setAgressiveness calls when aggressiveness factors change. - A driver may override this call if it needs to do something with the new factor (such as change its idle timeout). If overridden, the driver must call its superclass's setAgressiveness method in its own setAgressiveness implementation. - Most drivers do not need to implement setAgressiveness. - @param type The aggressiveness factor type, such as kPMMinutesToDim, kPMMinutesToSpinDown, kPMMinutesToSleep, and kPMPowerSource. (Aggressiveness factors are defined in pwr_mgt/IOPM.h.) - @param newLevel The aggressiveness factor's new value. - @result IOPMNoErr. */ - - virtual IOReturn setAggressiveness( - unsigned long type, - unsigned long newLevel ); - -/*! @function getAggressiveness - @abstract Returns the current aggressiveness value for the given type. - @param type The aggressiveness factor to query. - @param currentLevel Upon successful return, contains the value of aggressiveness factor type. - @result kIOReturnSuccess upon success; an I/O Kit error code otherwise. */ - - virtual IOReturn getAggressiveness( - unsigned long type, - unsigned long * currentLevel ); - -#ifndef __LP64__ -/*! @function systemWake - @abstract Tells every driver in the power plane that the system is waking up. - @discussion This call is handled internally by power management. It is not intended to be overridden or called by drivers. */ - - virtual IOReturn systemWake( void ) - APPLE_KEXT_DEPRECATED; - -/*! @function temperatureCriticalForZone - @abstract Alerts a driver to a critical temperature in some thermal zone. - @discussion This call is unused by power management. It is not intended to be called or overridden. */ - - virtual IOReturn temperatureCriticalForZone( IOService * whichZone ) - APPLE_KEXT_DEPRECATED; - -/*! @function youAreRoot - @abstract Informs power management which IOService object is the power plane root. - @discussion This call is handled internally by power management. It is not intended to be overridden or called by drivers. */ - - virtual IOReturn youAreRoot( void ) - APPLE_KEXT_DEPRECATED; - -/*! @function setPowerParent - @abstract This call is handled internally by power management. It is not intended to be overridden or called by drivers. */ - - virtual IOReturn setPowerParent( - IOPowerConnection * parent, - bool stateKnown, - IOPMPowerFlags currentState ) - APPLE_KEXT_DEPRECATED; -#endif /* !__LP64__ */ - -/*! @function addPowerChild - @abstract Informs a driver that it has a new child. - @discussion The Platform Expert uses this method to call a driver and introduce it to a new child. This call is handled internally by power management. It is not intended to be overridden or called by drivers. - @param theChild A pointer to the child IOService object. */ - - virtual IOReturn addPowerChild( IOService * theChild ); - -/*! @function removePowerChild - @abstract Informs a power managed driver that one of its power plane childen is disappearing. - @discussion This call is handled internally by power management. It is not intended to be overridden or called by drivers. */ - - virtual IOReturn removePowerChild( IOPowerConnection * theChild ); - -#ifndef __LP64__ -/*! @function command_received - @discussion This call is handled internally by power management. It is not intended to be overridden or called by drivers. */ - - virtual void command_received( void *, void * , void * , void * ); -#endif - -/*! @function start_PM_idle_timer - @discussion This call is handled internally by power management. It is not intended to be overridden or called by drivers. */ - - APPLE_KEXT_COMPATIBILITY_VIRTUAL - void start_PM_idle_timer( void ); - -#ifndef __LP64__ -/*! @function PM_idle_timer_expiration - @discussion This call is handled internally by power management. It is not intended to be overridden or called by drivers. */ - - virtual void PM_idle_timer_expiration( void ) - APPLE_KEXT_DEPRECATED; - -/*! @function PM_Clamp_Timer_Expired - @discussion This call is handled internally by power management. It is not intended to be overridden or called by drivers. */ - - virtual void PM_Clamp_Timer_Expired( void ) - APPLE_KEXT_DEPRECATED; -#endif - -/*! @function setIdleTimerPeriod - @abstract Sets or changes the idle timer period. - @discussion A driver using the idleness determination provided by IOService calls its superclass with this method to set or change the idle timer period. See @link activityTickle activityTickle@/link for a description of this type of idleness determination. - @param period The desired idle timer period in seconds. - @result kIOReturnSuccess upon success; an I/O Kit error code otherwise. */ - - virtual IOReturn setIdleTimerPeriod( unsigned long period ); - -#ifndef __LP64__ -/*! @function getPMworkloop - @abstract Returns a pointer to the system-wide power management work loop. - @availability Deprecated in Mac OS X version 10.6. - @discussion Most drivers should create their own work loops to synchronize their code; drivers should not run arbitrary code on the power management work loop. */ - - virtual IOWorkLoop * getPMworkloop( void ) - APPLE_KEXT_DEPRECATED; -#endif - -/*! @function getPowerState - @abstract Determines a device's power state. - @discussion A device's "current power state" is updated at the end of each power state transition (e.g. transition from state 1 to state 0, or state 0 to state 2). This transition includes the time spent powering on or off any power plane children. Thus, if a child calls getPowerState on its power parent during system wake from sleep, the call will return the index to the device's off state rather than its on state. - @result The current power state's index into the device's power state array. */ - - UInt32 getPowerState( void ); - -/*! @function setPowerState - @abstract Requests a power managed driver to change the power state of its device. - @discussion A power managed driver must override setPowerState to take part in system power management. After a driver is registered with power management, the system uses setPowerState to power the device off and on for system sleep and wake. - Calls to @link PMinit PMinit@/link and @link registerPowerDriver registerPowerDriver@/link enable power management to change a device's power state using setPowerState. setPowerState is called in a clean and separate thread context. - @param powerStateOrdinal The number in the power state array of the state the driver is being instructed to switch to. - @param whatDevice A pointer to the power management object which registered to manage power for this device. In most cases, whatDevice will be equal to your driver's own this pointer. - @result The driver must return IOPMAckImplied if it has complied with the request when it returns. Otherwise if it has started the process of changing power state but not finished it, the driver should return a number of microseconds which is an upper limit of the time it will need to finish. Then, when it has completed the power switch, it should call @link acknowledgeSetPowerState acknowledgeSetPowerState@/link. */ - - virtual IOReturn setPowerState( - unsigned long powerStateOrdinal, - IOService * whatDevice ); - -#ifndef __LP64__ -/*! @function clampPowerOn - @abstract Deprecated. Do not use. */ - - virtual void clampPowerOn( unsigned long duration ); -#endif - -/*! @function maxCapabilityForDomainState - @abstract Determines a driver's highest power state possible for a given power domain state. - @discussion This happens when the power domain is changing state and power management needs to determine which state the device is capable of in the new domain state. - Most drivers do not need to implement this method, and can rely upon the default IOService implementation. The IOService implementation scans the power state array looking for the highest state whose inputPowerRequirement field exactly matches the value of the domainState parameter. If more intelligent determination is required, the driver itself should implement the method and override the superclass's implementation. - @param domainState Flags that describe the character of "domain power"; they represent the outputPowerCharacter field of a state in the power domain's power state array. - @result A state number. */ - - virtual unsigned long maxCapabilityForDomainState( IOPMPowerFlags domainState ); - -/*! @function initialPowerStateForDomainState - @abstract Determines which power state a device is in, given the current power domain state. - @discussion Power management calls this method once, when the driver is initializing power management. - Most drivers do not need to implement this method, and can rely upon the default IOService implementation. The IOService implementation scans the power state array looking for the highest state whose inputPowerRequirement field exactly matches the value of the domainState parameter. If more intelligent determination is required, the power managed driver should implement the method and override the superclass's implementation. - @param domainState Flags that describe the character of "domain power"; they represent the outputPowerCharacter field of a state in the power domain's power state array. - @result A state number. */ - - virtual unsigned long initialPowerStateForDomainState( IOPMPowerFlags domainState ); - -/*! @function powerStateForDomainState - @abstract Determines what power state the device would be in for a given power domain state. - @discussion Power management calls a driver with this method to find out what power state the device would be in for a given power domain state. This happens when the power domain is changing state and power management needs to determine the effect of the change. - Most drivers do not need to implement this method, and can rely upon the default IOService implementation. The IOService implementation scans the power state array looking for the highest state whose inputPowerRequirement field exactly matches the value of the domainState parameter. If more intelligent determination is required, the power managed driver should implement the method and override the superclass's implementation. - @param domainState Flags that describe the character of "domain power"; they represent the outputPowerCharacter field of a state in the power domain's power state array. - @result A state number. */ - - virtual unsigned long powerStateForDomainState( IOPMPowerFlags domainState ); - -/*! @function powerStateWillChangeTo - @abstract Informs interested parties that a device is about to change its power state. - @discussion Power management informs interested parties that a device is about to change to a different power state. Interested parties are those that have registered for this notification via @link registerInterestedDriver registerInterestedDriver@/link. If you have called registerInterestedDriver on a power managed driver, you must implement powerStateWillChangeTo and @link powerStateDidChangeTo powerStateDidChangeTo@/link to receive the notifications. - powerStateWillChangeTo is called in a clean and separate thread context. powerStateWillChangeTo is called before a power state transition takes place; powerStateDidChangeTo is called after the transition has completed. - @param capabilities Flags that describe the capability of the device in the new power state (they come from the capabilityFlags field of the new state in the power state array). - @param stateNumber The number of the state in the state array that the device is switching to. - @param whatDevice A pointer to the driver that is changing. It can be used by a driver that is receiving power state change notifications for multiple devices to distinguish between them. - @result The driver returns IOPMAckImplied if it has prepared for the power change when it returns. If it has started preparing but not finished, it should return a number of microseconds which is an upper limit of the time it will need to finish preparing. Then, when it has completed its preparations, it should call @link acknowledgePowerChange acknowledgePowerChange@/link. */ - - virtual IOReturn powerStateWillChangeTo( - IOPMPowerFlags capabilities, - unsigned long stateNumber, - IOService * whatDevice ); - -/*! @function powerStateDidChangeTo - @abstract Informs interested parties that a device has changed to a different power state. - @discussion Power management informs interested parties that a device has changed to a different power state. Interested parties are those that have registered for this notification via @link registerInterestedDriver registerInterestedDriver@/link. If you have called registerInterestedDriver on a power managed driver, you must implemnt @link powerStateWillChangeTo powerStateWillChangeTo@/link and powerStateDidChangeTo to receive the notifications. - powerStateDidChangeTo is called in a clean and separate thread context. powerStateWillChangeTo is called before a power state transition takes place; powerStateDidChangeTo is called after the transition has completed. - @param capabilities Flags that describe the capability of the device in the new power state (they come from the capabilityFlags field of the new state in the power state array). - @param stateNumber The number of the state in the state array that the device is switching to. - @param whatDevice A pointer to the driver that is changing. It can be used by a driver that is receiving power state change notifications for multiple devices to distinguish between them. - @result The driver returns IOPMAckImplied if it has prepared for the power change when it returns. If it has started preparing but not finished, it should return a number of microseconds which is an upper limit of the time it will need to finish preparing. Then, when it has completed its preparations, it should call @link acknowledgePowerChange acknowledgePowerChange@/link. */ - - virtual IOReturn powerStateDidChangeTo( - IOPMPowerFlags capabilities, - unsigned long stateNumber, - IOService * whatDevice ); - -#ifndef __LP64__ -/*! @function didYouWakeSystem - @abstract Asks a driver if its device is the one that just woke the system from sleep. - @availability Deprecated in Mac OS X version 10.6. - @discussion Power management calls a power managed driver with this method to ask if its device is the one that just woke the system from sleep. If a device is capable of waking the system from sleep, its driver should implement didYouWakeSystem and return true if its device was responsible for waking the system. - @result true if the driver's device woke the system and false otherwise. */ - - virtual bool didYouWakeSystem( void ) - APPLE_KEXT_DEPRECATED; - -/*! @function newTemperature - @abstract Tells a power managed driver that the temperature in the thermal zone has changed. - @discussion This call is unused by power management. It is not intended to be called or overridden. */ - - virtual IOReturn newTemperature( long currentTemp, IOService * whichZone ) - APPLE_KEXT_DEPRECATED; -#endif - - virtual bool askChangeDown( unsigned long ); - virtual bool tellChangeDown( unsigned long ); - virtual void tellNoChangeDown ( unsigned long ); - virtual void tellChangeUp( unsigned long ); - virtual IOReturn allowPowerChange( unsigned long refcon ); - virtual IOReturn cancelPowerChange( unsigned long refcon ); - -protected: -/*! @function changePowerStateToPriv - @abstract Tells a driver's superclass to change the power state of its device. - @discussion A driver uses this method to tell its superclass to change the power state of the device. This is the recommended way to change the power state of a device. - Three things affect driver power state: @link changePowerStateTo changePowerStateTo@/link, changePowerStateToPriv, and the desires of the driver's power plane children. Power management puts the device into the maximum state governed by those three entities. - Drivers may eliminate the influence of the changePowerStateTo method on power state one of two ways. See @link powerOverrideOnPriv powerOverrideOnPriv@/link to ignore the method's influence, or call changePowerStateTo(0) in the driver's start routine to remove the changePowerStateTo method's power request. - @param ordinal The number of the desired power state in the power state array. - @result A return code that can be ignored by the caller. */ - - IOReturn changePowerStateToPriv( unsigned long ordinal ); - -/*! @function powerOverrideOnPriv - @abstract Allows a driver to ignore its children's power management requests and only use changePowerStateToPriv to define its own power state. - @discussion Power management normally keeps a device at the highest state required by its requests via @link changePowerStateTo changePowerStateTo@/link, @link changePowerStateToPriv changePowerStateToPriv@/link, and its children. However, a driver may ensure a lower power state than otherwise required by itself and its children using powerOverrideOnPriv. When the override is on, power management keeps the device's power state in the state specified by changePowerStateToPriv. Turning on the override will initiate a power change if the driver's changePowerStateToPriv desired power state is different from the maximum of the changePowerStateTo desired power state and the children's desires. - @result A return code that can be ignored by the caller. */ - - IOReturn powerOverrideOnPriv( void ); - -/*! @function powerOverrideOffPriv - @abstract Allows a driver to disable a power override. - @discussion When a driver has enabled an override via @link powerOverrideOnPriv powerOverrideOnPriv@/link, it can disable it again by calling this method in its superclass. Disabling the override reverts to the default algorithm for determining a device's power state. The superclass will now keep the device at the highest state required by changePowerStateTo, changePowerStateToPriv, and its children. Turning off the override will initiate a power change if the driver's desired power state is different from the maximum of the power managed driver's desire and the children's desires. - @result A return code that can be ignored by the caller. */ - - IOReturn powerOverrideOffPriv( void ); - -/*! @function powerChangeDone - @abstract Tells a driver when a power state change is complete. - @discussion Power management uses this method to inform a driver when a power change is completely done, when all interested parties have acknowledged the @link powerStateDidChangeTo powerStateDidChangeTo@/link call. The default implementation of this method is null; the method is meant to be overridden by subclassed power managed drivers. A driver should use this method to find out if a power change it initiated is complete. - @param stateNumber The number of the state in the state array that the device has switched from. */ - - virtual void powerChangeDone( unsigned long stateNumber ); -}; - -#endif /* ! _IOKIT_IOSERVICE_H */ diff --git a/Library/LegacyLibkernMacros.h b/Library/LegacyLibkernMacros.h deleted file mode 100644 index d685ee06..00000000 --- a/Library/LegacyLibkernMacros.h +++ /dev/null @@ -1,58 +0,0 @@ -// -// LegacyLibkernMacros.h -// Lilu -// -// Copyright © 2019 vit9696. All rights reserved. -// - -#ifndef LegacyLibkernMacros_h -#define LegacyLibkernMacros_h - -// This is a compatibility header to let Lilu build with different Xcode -// versions and be able to use legacy headers and clang analyzer. - -#include - -#if !defined(LIBKERN_RETURNS_NOT_RETAINED) -#define LIBKERN_RETURNS_NOT_RETAINED -#elif defined(__clang_major__) && __clang_major__ < 11 -#undef LIBKERN_RETURNS_NOT_RETAINED -#define LIBKERN_RETURNS_NOT_RETAINED -#endif - -#if !defined(LIBKERN_RETURNS_RETAINED) -#define LIBKERN_RETURNS_RETAINED -#elif defined(__clang_major__) && __clang_major__ < 11 -#undef LIBKERN_RETURNS_RETAINED -#define LIBKERN_RETURNS_RETAINED -#endif - -#if !defined(LIBKERN_CONSUMED) -#define LIBKERN_CONSUMED -#elif defined(__clang_major__) && __clang_major__ < 11 -#undef LIBKERN_CONSUMED -#define LIBKERN_CONSUMED -#endif - -#if !defined(LIBKERN_CONSUMES_THIS) -#define LIBKERN_CONSUMES_THIS -#elif defined(__clang_major__) && __clang_major__ < 11 -#undef LIBKERN_CONSUMES_THIS -#define LIBKERN_CONSUMES_THIS -#endif - -#if !defined(LIBKERN_RETURNS_RETAINED_ON_ZERO) -#define LIBKERN_RETURNS_RETAINED_ON_ZERO -#elif defined(__clang_major__) && __clang_major__ < 11 -#undef LIBKERN_RETURNS_RETAINED_ON_ZERO -#define LIBKERN_RETURNS_RETAINED_ON_ZERO -#endif - -#if !defined(LIBKERN_RETURNS_RETAINED_ON_NONZERO) -#define LIBKERN_RETURNS_RETAINED_ON_NONZERO -#elif defined(__clang_major__) && __clang_major__ < 11 -#undef LIBKERN_RETURNS_RETAINED_ON_NONZERO -#define LIBKERN_RETURNS_RETAINED_ON_NONZERO -#endif - -#endif /* LegacyLibkernMacros_h */ diff --git a/Library/compat.cpp b/Library/compat.cpp deleted file mode 100644 index 687b6260..00000000 --- a/Library/compat.cpp +++ /dev/null @@ -1,37 +0,0 @@ -// -// compat.cpp -// VoodooPS2Controller -// -// Created by user on 24/07/2019. -// Copyright © 2019 vit9696. All rights reserved. -// - -#include - -#ifdef __MAC_10_15 - -/** - * Ensure the symbol is not exported - */ -#define PRIVATE __attribute__((visibility("hidden"))) - -/** - * For private fallback symbol definition - */ -#define WEAKFUNC __attribute__((weak)) - -// macOS 10.15 adds Dispatch function to all OSObject instances and basically -// every header is now incompatible with 10.14 and earlier. -// Here we add a stub to permit older macOS versions to link. -// Note, this is done in both kern_util and plugin_start as plugins will not link -// to Lilu weak exports from vtable. - -kern_return_t WEAKFUNC PRIVATE OSObject::Dispatch(const IORPC rpc) { - (panic)("OSObject::Dispatch plugin stub called"); -} - -kern_return_t WEAKFUNC PRIVATE OSMetaClassBase::Dispatch(const IORPC rpc) { - (panic)("OSMetaClassBase::Dispatch plugin stub called"); -} - -#endif diff --git a/Library/libkmod.a b/Library/libkmod.a deleted file mode 100755 index 4bf84bb80e9bdffb6fc0f9c98f6536268c534b20..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1408 zcmbtUO-ma=7#=^Wc3Vmg9#n*`w1q-JcSF>JMuZqmX^PUUQpGS?l8r9vu53o|&_kj0 zQ1SNoZly~X?t4*Ztr)sB$KB~HYd$!*C1m(*aqu?^}|x+m@r@z_EmZ}4@H%>Xbqra^kifzjXek) z56y_dxs!iS2iXR_UibTe2J}xDJ|?F=N06e#kipm!gZ084ft_If0Qe`EKKBT=21|na zk%L+|a_}mhG<=@}zR{1Ph`P53aC)Tbdnv0LiXE`)Mr)*mBgkm~3 z{9pDV_$l@=1}1F5D4v%QV{tHhJQGkcRH|du8X@lDplIpy!+rRfTOT9^78bfdrAs#tAAb5y4ck#4I9k4$q(8v`4 diff --git a/VoodooPS2Controller.xcodeproj/project.pbxproj b/VoodooPS2Controller.xcodeproj/project.pbxproj index e7feb1a5..8af39b19 100644 --- a/VoodooPS2Controller.xcodeproj/project.pbxproj +++ b/VoodooPS2Controller.xcodeproj/project.pbxproj @@ -32,30 +32,10 @@ 84DD197C162D496E0044D061 /* AppleACPIPS2Nub.h in Headers */ = {isa = PBXBuildFile; fileRef = 84DD197A162D496E0044D061 /* AppleACPIPS2Nub.h */; }; 84EB0AE316F0AD9300016108 /* ApplePS2KeyboardDevice.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 84833F9E161B627D00845294 /* ApplePS2KeyboardDevice.cpp */; }; 84EB0AE516F0AD9600016108 /* ApplePS2MouseDevice.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 84833FA0161B627D00845294 /* ApplePS2MouseDevice.cpp */; }; - CE7F451A22E8AC61003F7971 /* libkmod.a in Frameworks */ = {isa = PBXBuildFile; fileRef = CE7F451822E8AC59003F7971 /* libkmod.a */; }; - CE7F451B22E8AC65003F7971 /* libkmod.a in Frameworks */ = {isa = PBXBuildFile; fileRef = CE7F451822E8AC59003F7971 /* libkmod.a */; }; - CE7F451C22E8AC69003F7971 /* libkmod.a in Frameworks */ = {isa = PBXBuildFile; fileRef = CE7F451822E8AC59003F7971 /* libkmod.a */; }; - CE7F451D22E8AC6F003F7971 /* libkmod.a in Frameworks */ = {isa = PBXBuildFile; fileRef = CE7F451822E8AC59003F7971 /* libkmod.a */; }; - CE86CCF122E8B0F800B32BE3 /* compat.cpp in Sources */ = {isa = PBXBuildFile; fileRef = CE86CCF022E8B0F800B32BE3 /* compat.cpp */; }; - CE86CCF222E8B0F800B32BE3 /* compat.cpp in Sources */ = {isa = PBXBuildFile; fileRef = CE86CCF022E8B0F800B32BE3 /* compat.cpp */; }; - CE86CCF322E8B0F800B32BE3 /* compat.cpp in Sources */ = {isa = PBXBuildFile; fileRef = CE86CCF022E8B0F800B32BE3 /* compat.cpp */; }; - CE86CCF422E8B0F800B32BE3 /* compat.cpp in Sources */ = {isa = PBXBuildFile; fileRef = CE86CCF022E8B0F800B32BE3 /* compat.cpp */; }; - CE86CCF622E8BC9800B32BE3 /* LegacyIOService.h in Headers */ = {isa = PBXBuildFile; fileRef = CE86CCF522E8BC9800B32BE3 /* LegacyIOService.h */; }; - CE86CCF722E8BC9800B32BE3 /* LegacyIOService.h in Headers */ = {isa = PBXBuildFile; fileRef = CE86CCF522E8BC9800B32BE3 /* LegacyIOService.h */; }; - CE86CCF822E8BC9800B32BE3 /* LegacyIOService.h in Headers */ = {isa = PBXBuildFile; fileRef = CE86CCF522E8BC9800B32BE3 /* LegacyIOService.h */; }; - CE86CCF922E8BC9800B32BE3 /* LegacyIOService.h in Headers */ = {isa = PBXBuildFile; fileRef = CE86CCF522E8BC9800B32BE3 /* LegacyIOService.h */; }; - CE86CCFB22E8BCEE00B32BE3 /* LegacyLibkernMacros.h in Headers */ = {isa = PBXBuildFile; fileRef = CE86CCFA22E8BCEE00B32BE3 /* LegacyLibkernMacros.h */; }; - CE86CCFC22E8BCEE00B32BE3 /* LegacyLibkernMacros.h in Headers */ = {isa = PBXBuildFile; fileRef = CE86CCFA22E8BCEE00B32BE3 /* LegacyLibkernMacros.h */; }; - CE86CCFD22E8BCEE00B32BE3 /* LegacyLibkernMacros.h in Headers */ = {isa = PBXBuildFile; fileRef = CE86CCFA22E8BCEE00B32BE3 /* LegacyLibkernMacros.h */; }; - CE86CCFE22E8BCEE00B32BE3 /* LegacyLibkernMacros.h in Headers */ = {isa = PBXBuildFile; fileRef = CE86CCFA22E8BCEE00B32BE3 /* LegacyLibkernMacros.h */; }; - CE86CD0122E8BDE000B32BE3 /* LegacyIOHIKeyboard.h in Headers */ = {isa = PBXBuildFile; fileRef = CE86CCFF22E8BDE000B32BE3 /* LegacyIOHIKeyboard.h */; }; - CE86CD0222E8BDE000B32BE3 /* LegacyIOHIKeyboard.h in Headers */ = {isa = PBXBuildFile; fileRef = CE86CCFF22E8BDE000B32BE3 /* LegacyIOHIKeyboard.h */; }; - CE86CD0322E8BDE000B32BE3 /* LegacyIOHIKeyboard.h in Headers */ = {isa = PBXBuildFile; fileRef = CE86CCFF22E8BDE000B32BE3 /* LegacyIOHIKeyboard.h */; }; - CE86CD0422E8BDE000B32BE3 /* LegacyIOHIKeyboard.h in Headers */ = {isa = PBXBuildFile; fileRef = CE86CCFF22E8BDE000B32BE3 /* LegacyIOHIKeyboard.h */; }; - CE86CD0522E8BDE000B32BE3 /* LegacyIOHIPointing.h in Headers */ = {isa = PBXBuildFile; fileRef = CE86CD0022E8BDE000B32BE3 /* LegacyIOHIPointing.h */; }; - CE86CD0622E8BDE000B32BE3 /* LegacyIOHIPointing.h in Headers */ = {isa = PBXBuildFile; fileRef = CE86CD0022E8BDE000B32BE3 /* LegacyIOHIPointing.h */; }; - CE86CD0722E8BDE000B32BE3 /* LegacyIOHIPointing.h in Headers */ = {isa = PBXBuildFile; fileRef = CE86CD0022E8BDE000B32BE3 /* LegacyIOHIPointing.h */; }; - CE86CD0822E8BDE000B32BE3 /* LegacyIOHIPointing.h in Headers */ = {isa = PBXBuildFile; fileRef = CE86CD0022E8BDE000B32BE3 /* LegacyIOHIPointing.h */; }; + CE8DA1C5251839B3008C44E8 /* libkmod.a in Frameworks */ = {isa = PBXBuildFile; fileRef = CE8DA1C4251839B2008C44E8 /* libkmod.a */; }; + CE8DA1C6251839B7008C44E8 /* libkmod.a in Frameworks */ = {isa = PBXBuildFile; fileRef = CE8DA1C4251839B2008C44E8 /* libkmod.a */; }; + CE8DA1C7251839B9008C44E8 /* libkmod.a in Frameworks */ = {isa = PBXBuildFile; fileRef = CE8DA1C4251839B2008C44E8 /* libkmod.a */; }; + CE8DA1CC251839BC008C44E8 /* libkmod.a in Frameworks */ = {isa = PBXBuildFile; fileRef = CE8DA1C4251839B2008C44E8 /* libkmod.a */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ @@ -131,13 +111,7 @@ CE7F451422E8A8F8003F7971 /* Changelog.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = Changelog.md; sourceTree = SOURCE_ROOT; }; CE7F451522E8A8FE003F7971 /* README.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = README.md; sourceTree = SOURCE_ROOT; }; CE7F451622E8A906003F7971 /* LICENSE.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = LICENSE.md; sourceTree = SOURCE_ROOT; }; - CE7F451822E8AC59003F7971 /* libkmod.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libkmod.a; sourceTree = ""; }; - CE86CCF022E8B0F800B32BE3 /* compat.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = compat.cpp; sourceTree = ""; }; - CE86CCF522E8BC9800B32BE3 /* LegacyIOService.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LegacyIOService.h; sourceTree = ""; }; - CE86CCFA22E8BCEE00B32BE3 /* LegacyLibkernMacros.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LegacyLibkernMacros.h; sourceTree = ""; }; - CE86CCFF22E8BDE000B32BE3 /* LegacyIOHIKeyboard.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LegacyIOHIKeyboard.h; sourceTree = ""; }; - CE86CD0022E8BDE000B32BE3 /* LegacyIOHIPointing.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LegacyIOHIPointing.h; sourceTree = ""; }; - CED643F022E8AF27006CDE9B /* LegacyIOHIDDevice.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = LegacyIOHIDDevice.h; sourceTree = ""; }; + CE8DA1C4251839B2008C44E8 /* libkmod.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libkmod.a; path = ../Lilu/MacKernelSDK/Library/x86_64/libkmod.a; sourceTree = ""; }; ED1C95C51F9B88EF00CAFCA3 /* SSDT-PrtSc-F13.dsl */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = "SSDT-PrtSc-F13.dsl"; sourceTree = ""; }; ED48777A207D94BC00D6B1E8 /* SSDT-AlternateSwipes.dsl */ = {isa = PBXFileReference; lastKnownFileType = text; path = "SSDT-AlternateSwipes.dsl"; sourceTree = ""; }; ED5759741D44FBA50069DF9F /* SSDT-KEY-DELL-WN09.dsl */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = "SSDT-KEY-DELL-WN09.dsl"; sourceTree = ""; }; @@ -156,7 +130,7 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - CE7F451A22E8AC61003F7971 /* libkmod.a in Frameworks */, + CE8DA1C5251839B3008C44E8 /* libkmod.a in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -164,7 +138,7 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - CE7F451B22E8AC65003F7971 /* libkmod.a in Frameworks */, + CE8DA1C6251839B7008C44E8 /* libkmod.a in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -172,7 +146,7 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - CE7F451C22E8AC69003F7971 /* libkmod.a in Frameworks */, + CE8DA1C7251839B9008C44E8 /* libkmod.a in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -180,7 +154,7 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - CE7F451D22E8AC6F003F7971 /* libkmod.a in Frameworks */, + CE8DA1CC251839BC008C44E8 /* libkmod.a in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -203,7 +177,6 @@ children = ( CE7F450F22E8A853003F7971 /* Docs */, 84833FC0161B636900845294 /* Common */, - CE7F451722E8AC45003F7971 /* Library */, CE39B4E122D0CCC200D344F3 /* Changelog.md */, 84AE0F6C1BE4479200AF814A /* README.md */, 84167818161B55B2002C60E6 /* VoodooPS2Controller */, @@ -211,6 +184,7 @@ 84167842161B56A2002C60E6 /* VoodooPS2Mouse */, 84167856161B56C4002C60E6 /* VoodooPS2Trackpad */, 84167814161B55B2002C60E6 /* Products */, + CE8DA1C3251839B2008C44E8 /* Frameworks */, ); sourceTree = ""; usesTabs = 0; @@ -359,18 +333,12 @@ path = Docs; sourceTree = ""; }; - CE7F451722E8AC45003F7971 /* Library */ = { + CE8DA1C3251839B2008C44E8 /* Frameworks */ = { isa = PBXGroup; children = ( - CE7F451822E8AC59003F7971 /* libkmod.a */, - CED643F022E8AF27006CDE9B /* LegacyIOHIDDevice.h */, - CE86CCFF22E8BDE000B32BE3 /* LegacyIOHIKeyboard.h */, - CE86CD0022E8BDE000B32BE3 /* LegacyIOHIPointing.h */, - CE86CCF522E8BC9800B32BE3 /* LegacyIOService.h */, - CE86CCFA22E8BCEE00B32BE3 /* LegacyLibkernMacros.h */, - CE86CCF022E8B0F800B32BE3 /* compat.cpp */, - ); - path = Library; + CE8DA1C4251839B2008C44E8 /* libkmod.a */, + ); + name = Frameworks; sourceTree = ""; }; /* End PBXGroup section */ @@ -381,13 +349,9 @@ buildActionMask = 2147483647; files = ( 84833FA3161B627D00845294 /* ApplePS2Device.h in Headers */, - CE86CD0122E8BDE000B32BE3 /* LegacyIOHIKeyboard.h in Headers */, - CE86CCF622E8BC9800B32BE3 /* LegacyIOService.h in Headers */, 84833FA5161B627D00845294 /* ApplePS2KeyboardDevice.h in Headers */, - CE86CCFB22E8BCEE00B32BE3 /* LegacyLibkernMacros.h in Headers */, 84833FA7161B627D00845294 /* ApplePS2MouseDevice.h in Headers */, 84833FC3161B6A7E00845294 /* VoodooPS2Controller.h in Headers */, - CE86CD0522E8BDE000B32BE3 /* LegacyIOHIPointing.h in Headers */, 84DD197C162D496E0044D061 /* AppleACPIPS2Nub.h in Headers */, ); runOnlyForDeploymentPostprocessing = 0; @@ -396,11 +360,7 @@ isa = PBXHeadersBuildPhase; buildActionMask = 2147483647; files = ( - CE86CCFC22E8BCEE00B32BE3 /* LegacyLibkernMacros.h in Headers */, 84833FAA161B629500845294 /* ApplePS2ToADBMap.h in Headers */, - CE86CD0222E8BDE000B32BE3 /* LegacyIOHIKeyboard.h in Headers */, - CE86CCF722E8BC9800B32BE3 /* LegacyIOService.h in Headers */, - CE86CD0622E8BDE000B32BE3 /* LegacyIOHIPointing.h in Headers */, 84833FC2161B69C700845294 /* VoodooPS2Keyboard.h in Headers */, ); runOnlyForDeploymentPostprocessing = 0; @@ -410,10 +370,6 @@ buildActionMask = 2147483647; files = ( 84833FC1161B69B800845294 /* VoodooPS2Mouse.h in Headers */, - CE86CD0322E8BDE000B32BE3 /* LegacyIOHIKeyboard.h in Headers */, - CE86CCFD22E8BCEE00B32BE3 /* LegacyLibkernMacros.h in Headers */, - CE86CCF822E8BC9800B32BE3 /* LegacyIOService.h in Headers */, - CE86CD0722E8BDE000B32BE3 /* LegacyIOHIPointing.h in Headers */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -421,12 +377,8 @@ isa = PBXHeadersBuildPhase; buildActionMask = 2147483647; files = ( - CE86CD0422E8BDE000B32BE3 /* LegacyIOHIKeyboard.h in Headers */, 356B896323007F4F0042F30F /* VoodooInputEvent.h in Headers */, 356B896223007F4F0042F30F /* VoodooInputMessages.h in Headers */, - CE86CCF922E8BC9800B32BE3 /* LegacyIOService.h in Headers */, - CE86CD0822E8BDE000B32BE3 /* LegacyIOHIPointing.h in Headers */, - CE86CCFE22E8BCEE00B32BE3 /* LegacyLibkernMacros.h in Headers */, 356B896423007F4F0042F30F /* VoodooInputTransducer.h in Headers */, 84833FB2161B62A900845294 /* VoodooPS2ALPSGlidePoint.h in Headers */, 356B896523007F4F0042F30F /* MultitouchHelpers.h in Headers */, @@ -660,7 +612,6 @@ 840F104A16EFE42600E8C116 /* ApplePS2Device.cpp in Sources */, 84EB0AE316F0AD9300016108 /* ApplePS2KeyboardDevice.cpp in Sources */, 84EB0AE516F0AD9600016108 /* ApplePS2MouseDevice.cpp in Sources */, - CE86CCF122E8B0F800B32BE3 /* compat.cpp in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -669,7 +620,6 @@ buildActionMask = 2147483647; files = ( 84167836161B5613002C60E6 /* VoodooPS2Keyboard.cpp in Sources */, - CE86CCF222E8B0F800B32BE3 /* compat.cpp in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -678,7 +628,6 @@ buildActionMask = 2147483647; files = ( 8416784A161B56A2002C60E6 /* VoodooPS2Mouse.cpp in Sources */, - CE86CCF322E8B0F800B32BE3 /* compat.cpp in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -687,7 +636,6 @@ buildActionMask = 2147483647; files = ( 84833FB1161B62A900845294 /* VoodooPS2ALPSGlidePoint.cpp in Sources */, - CE86CCF422E8B0F800B32BE3 /* compat.cpp in Sources */, 84833FB3161B62A900845294 /* VoodooPS2SentelicFSP.cpp in Sources */, 84833FB5161B62A900845294 /* VoodooPS2SynapticsTouchPad.cpp in Sources */, ); @@ -797,9 +745,11 @@ GCC_WARN_UNUSED_LABEL = YES; GCC_WARN_UNUSED_PARAMETER = NO; GCC_WARN_UNUSED_VARIABLE = YES; + KERNEL_EXTENSION_HEADER_SEARCH_PATHS = "$(PROJECT_DIR)/MacKernelSDK/Headers"; + KERNEL_FRAMEWORK_HEADERS = "$(PROJECT_DIR)/MacKernelSDK/Headers"; "LLVM_LTO[arch=x86_64]" = YES; MACOSX_DEPLOYMENT_TARGET = 10.11; - MODULE_VERSION = 2.1.7; + MODULE_VERSION = 2.1.8; ONLY_ACTIVE_ARCH = YES; "OTHER_LDFLAGS[arch=x86_64]" = "-dead_strip"; PRODUCT_NAME = VoodooPS2Controller; @@ -850,9 +800,11 @@ GCC_WARN_UNUSED_LABEL = YES; GCC_WARN_UNUSED_PARAMETER = NO; GCC_WARN_UNUSED_VARIABLE = YES; + KERNEL_EXTENSION_HEADER_SEARCH_PATHS = "$(PROJECT_DIR)/MacKernelSDK/Headers"; + KERNEL_FRAMEWORK_HEADERS = "$(PROJECT_DIR)/MacKernelSDK/Headers"; "LLVM_LTO[arch=x86_64]" = YES; MACOSX_DEPLOYMENT_TARGET = 10.11; - MODULE_VERSION = 2.1.7; + MODULE_VERSION = 2.1.8; "OTHER_LDFLAGS[arch=x86_64]" = "-dead_strip"; PRODUCT_NAME = VoodooPS2Controller; SDKROOT = macosx; @@ -870,7 +822,7 @@ INFOPLIST_FILE = "VoodooPS2Controller/VoodooPS2Controller-Info.plist"; LIBRARY_SEARCH_PATHS = ( "$(inherited)", - "$(PROJECT_DIR)$(LOCAL_LIBRARY_DIR)", + "$(PROJECT_DIR)/MacKernelSDK/Library/x86_64", ); MODULE_NAME = as.acidanthera.driver.VoodooPS2Controller; OTHER_CFLAGS = "-fno-stack-protector"; @@ -890,7 +842,7 @@ INFOPLIST_FILE = "VoodooPS2Controller/VoodooPS2Controller-Info.plist"; LIBRARY_SEARCH_PATHS = ( "$(inherited)", - "$(PROJECT_DIR)$(LOCAL_LIBRARY_DIR)", + "$(PROJECT_DIR)/MacKernelSDK/Library/x86_64", ); MODULE_NAME = as.acidanthera.driver.VoodooPS2Controller; OTHER_CFLAGS = "-fno-stack-protector"; @@ -912,7 +864,7 @@ INFOPLIST_FILE = "VoodooPS2Keyboard/VoodooPS2Keyboard-Info.plist"; LIBRARY_SEARCH_PATHS = ( "$(inherited)", - "$(PROJECT_DIR)$(LOCAL_LIBRARY_DIR)", + "$(PROJECT_DIR)/MacKernelSDK/Library/x86_64", ); MODULE_NAME = as.acidanthera.driver.VoodooPS2Keyboard; OTHER_CFLAGS = "-fno-stack-protector"; @@ -934,7 +886,7 @@ INFOPLIST_FILE = "VoodooPS2Keyboard/VoodooPS2Keyboard-Info.plist"; LIBRARY_SEARCH_PATHS = ( "$(inherited)", - "$(PROJECT_DIR)$(LOCAL_LIBRARY_DIR)", + "$(PROJECT_DIR)/MacKernelSDK/Library/x86_64", ); MODULE_NAME = as.acidanthera.driver.VoodooPS2Keyboard; OTHER_CFLAGS = "-fno-stack-protector"; @@ -955,7 +907,7 @@ INFOPLIST_FILE = "VoodooPS2Mouse/VoodooPS2Mouse-Info.plist"; LIBRARY_SEARCH_PATHS = ( "$(inherited)", - "$(PROJECT_DIR)$(LOCAL_LIBRARY_DIR)", + "$(PROJECT_DIR)/MacKernelSDK/Library/x86_64", ); MODULE_NAME = as.acidanthera.driver.VoodooPS2Mouse; OTHER_CFLAGS = "-fno-stack-protector"; @@ -976,7 +928,7 @@ INFOPLIST_FILE = "VoodooPS2Mouse/VoodooPS2Mouse-Info.plist"; LIBRARY_SEARCH_PATHS = ( "$(inherited)", - "$(PROJECT_DIR)$(LOCAL_LIBRARY_DIR)", + "$(PROJECT_DIR)/MacKernelSDK/Library/x86_64", ); MODULE_NAME = as.acidanthera.driver.VoodooPS2Mouse; OTHER_CFLAGS = "-fno-stack-protector"; @@ -998,7 +950,7 @@ INFOPLIST_FILE = "VoodooPS2Trackpad/VoodooPS2Trackpad-Info.plist"; LIBRARY_SEARCH_PATHS = ( "$(inherited)", - "$(PROJECT_DIR)$(LOCAL_LIBRARY_DIR)", + "$(PROJECT_DIR)/MacKernelSDK/Library/x86_64", ); MODULE_NAME = as.acidanthera.driver.VoodooPS2Trackpad; OTHER_CFLAGS = "-fno-stack-protector"; @@ -1020,7 +972,7 @@ INFOPLIST_FILE = "VoodooPS2Trackpad/VoodooPS2Trackpad-Info.plist"; LIBRARY_SEARCH_PATHS = ( "$(inherited)", - "$(PROJECT_DIR)$(LOCAL_LIBRARY_DIR)", + "$(PROJECT_DIR)/MacKernelSDK/Library/x86_64", ); MODULE_NAME = as.acidanthera.driver.VoodooPS2Trackpad; OTHER_CFLAGS = "-fno-stack-protector"; diff --git a/VoodooPS2Controller/AppleACPIPS2Nub.h b/VoodooPS2Controller/AppleACPIPS2Nub.h index 339bad35..75b18be0 100644 --- a/VoodooPS2Controller/AppleACPIPS2Nub.h +++ b/VoodooPS2Controller/AppleACPIPS2Nub.h @@ -31,7 +31,7 @@ #ifndef __AppleACPIPS2Nub__ #define __AppleACPIPS2Nub__ -#include "LegacyIOService.h" +#include #include #include diff --git a/VoodooPS2Controller/ApplePS2Device.h b/VoodooPS2Controller/ApplePS2Device.h index 8f4bce08..f2031b07 100644 --- a/VoodooPS2Controller/ApplePS2Device.h +++ b/VoodooPS2Controller/ApplePS2Device.h @@ -25,7 +25,7 @@ #include #include -#include "LegacyIOService.h" +#include #include #include diff --git a/VoodooPS2Controller/VoodooPS2Controller.cpp b/VoodooPS2Controller/VoodooPS2Controller.cpp index 849eeab4..fb4a087e 100644 --- a/VoodooPS2Controller/VoodooPS2Controller.cpp +++ b/VoodooPS2Controller/VoodooPS2Controller.cpp @@ -23,15 +23,12 @@ #define DISABLE_CLOCKS_IRQS_BEFORE_SLEEP 1 #define FULL_INIT_AFTER_WAKE 1 -#include "LegacyIOService.h" +#include #include #include #include -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Winconsistent-missing-override" #include -#pragma clang diagnostic pop #include "ApplePS2KeyboardDevice.h" #include "ApplePS2MouseDevice.h" diff --git a/VoodooPS2Controller/VoodooPS2Controller.h b/VoodooPS2Controller/VoodooPS2Controller.h index b64aa066..a388135c 100644 --- a/VoodooPS2Controller/VoodooPS2Controller.h +++ b/VoodooPS2Controller/VoodooPS2Controller.h @@ -25,7 +25,7 @@ #include #include -#include "LegacyIOService.h" +#include #include #include "ApplePS2Device.h" diff --git a/VoodooPS2Keyboard/VoodooPS2Keyboard.cpp b/VoodooPS2Keyboard/VoodooPS2Keyboard.cpp index f96b3eee..a0e85f1b 100644 --- a/VoodooPS2Keyboard/VoodooPS2Keyboard.cpp +++ b/VoodooPS2Keyboard/VoodooPS2Keyboard.cpp @@ -26,16 +26,13 @@ #define DEBUG_LITE #endif -#include "LegacyIOService.h" +#include -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Winconsistent-missing-override" #include #include #include #include #include -#pragma clang diagnostic pop #include "ApplePS2ToADBMap.h" #include "VoodooPS2Controller.h" diff --git a/VoodooPS2Keyboard/VoodooPS2Keyboard.h b/VoodooPS2Keyboard/VoodooPS2Keyboard.h index 20b4adfa..5a701303 100644 --- a/VoodooPS2Keyboard/VoodooPS2Keyboard.h +++ b/VoodooPS2Keyboard/VoodooPS2Keyboard.h @@ -25,13 +25,10 @@ #include #include "../VoodooPS2Controller/ApplePS2KeyboardDevice.h" -#include "LegacyIOHIKeyboard.h" +#include -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Winconsistent-missing-override" #include #include -#pragma clang diagnostic pop #include diff --git a/VoodooPS2Mouse/VoodooPS2Mouse.cpp b/VoodooPS2Mouse/VoodooPS2Mouse.cpp index 0647c666..d5ff2e3c 100644 --- a/VoodooPS2Mouse/VoodooPS2Mouse.cpp +++ b/VoodooPS2Mouse/VoodooPS2Mouse.cpp @@ -20,16 +20,13 @@ * @APPLE_LICENSE_HEADER_END@ */ -#include "LegacyIOService.h" +#include -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Winconsistent-missing-override" #include #include #include #include #include -#pragma clang diagnostic pop #include "VoodooPS2Controller.h" #include "VoodooPS2Mouse.h" diff --git a/VoodooPS2Mouse/VoodooPS2Mouse.h b/VoodooPS2Mouse/VoodooPS2Mouse.h index ef685462..f9b3aa71 100644 --- a/VoodooPS2Mouse/VoodooPS2Mouse.h +++ b/VoodooPS2Mouse/VoodooPS2Mouse.h @@ -24,13 +24,10 @@ #define _APPLEPS2MOUSE_H #include "../VoodooPS2Controller/ApplePS2MouseDevice.h" -#include "LegacyIOHIPointing.h" +#include -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Winconsistent-missing-override" #include #include -#pragma clang diagnostic pop // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // Local Declarations diff --git a/VoodooPS2Trackpad/VoodooPS2ALPSGlidePoint.cpp b/VoodooPS2Trackpad/VoodooPS2ALPSGlidePoint.cpp index 0358e74c..7b964575 100644 --- a/VoodooPS2Trackpad/VoodooPS2ALPSGlidePoint.cpp +++ b/VoodooPS2Trackpad/VoodooPS2ALPSGlidePoint.cpp @@ -20,7 +20,7 @@ * @APPLE_LICENSE_HEADER_END@ */ -#include "LegacyIOService.h" +#include #include #include diff --git a/VoodooPS2Trackpad/VoodooPS2ALPSGlidePoint.h b/VoodooPS2Trackpad/VoodooPS2ALPSGlidePoint.h index 44c830c0..3897ceb0 100644 --- a/VoodooPS2Trackpad/VoodooPS2ALPSGlidePoint.h +++ b/VoodooPS2Trackpad/VoodooPS2ALPSGlidePoint.h @@ -24,7 +24,7 @@ #define _APPLEPS2SYNAPTICSTOUCHPAD_H #include "../VoodooPS2Controller/ApplePS2MouseDevice.h" -#include "LegacyIOHIPointing.h" +#include // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // ApplePS2ALPSGlidePoint Class Declaration diff --git a/VoodooPS2Trackpad/VoodooPS2SentelicFSP.cpp b/VoodooPS2Trackpad/VoodooPS2SentelicFSP.cpp index 4d1f05d9..3fbc4087 100644 --- a/VoodooPS2Trackpad/VoodooPS2SentelicFSP.cpp +++ b/VoodooPS2Trackpad/VoodooPS2SentelicFSP.cpp @@ -20,7 +20,7 @@ * @APPLE_LICENSE_HEADER_END@ */ -#include "LegacyIOService.h" +#include #include #include diff --git a/VoodooPS2Trackpad/VoodooPS2SentelicFSP.h b/VoodooPS2Trackpad/VoodooPS2SentelicFSP.h index 7c6a18eb..bcb56def 100644 --- a/VoodooPS2Trackpad/VoodooPS2SentelicFSP.h +++ b/VoodooPS2Trackpad/VoodooPS2SentelicFSP.h @@ -25,7 +25,7 @@ #include "../VoodooPS2Controller/ApplePS2MouseDevice.h" -#include "LegacyIOHIPointing.h" +#include #define kPacketLengthMax 4 #define kPacketLengthStandard 3 diff --git a/VoodooPS2Trackpad/VoodooPS2SynapticsTouchPad.cpp b/VoodooPS2Trackpad/VoodooPS2SynapticsTouchPad.cpp index 6e8ac526..409c6af2 100644 --- a/VoodooPS2Trackpad/VoodooPS2SynapticsTouchPad.cpp +++ b/VoodooPS2Trackpad/VoodooPS2SynapticsTouchPad.cpp @@ -37,7 +37,7 @@ #define kTPDN "TPDN" // Trackpad Disable Notification -#include "LegacyIOService.h" +#include #pragma clang diagnostic push #pragma clang diagnostic ignored "-Winconsistent-missing-override" diff --git a/VoodooPS2Trackpad/VoodooPS2SynapticsTouchPad.h b/VoodooPS2Trackpad/VoodooPS2SynapticsTouchPad.h index c550bab2..f322fceb 100644 --- a/VoodooPS2Trackpad/VoodooPS2SynapticsTouchPad.h +++ b/VoodooPS2Trackpad/VoodooPS2SynapticsTouchPad.h @@ -24,7 +24,7 @@ #define _APPLEPS2SYNAPTICSTOUCHPAD_H #include "../VoodooPS2Controller/ApplePS2MouseDevice.h" -#include "LegacyIOHIPointing.h" +#include #pragma clang diagnostic push #pragma clang diagnostic ignored "-Winconsistent-missing-override" From 1e2925d3c1f90b454b0d12a5e0ea1a0e57d62287 Mon Sep 17 00:00:00 2001 From: zhen-zen <66577170+zhen-zen@users.noreply.github.com> Date: Tue, 22 Sep 2020 10:15:07 -0700 Subject: [PATCH 012/101] Workaround for ICL/CML brightness keys (#23) --- VoodooPS2Controller/ApplePS2Device.h | 6 +++++- VoodooPS2Keyboard/VoodooPS2Keyboard.cpp | 22 +++++++++++++++++++--- 2 files changed, 24 insertions(+), 4 deletions(-) diff --git a/VoodooPS2Controller/ApplePS2Device.h b/VoodooPS2Controller/ApplePS2Device.h index f2031b07..b6e639cf 100644 --- a/VoodooPS2Controller/ApplePS2Device.h +++ b/VoodooPS2Controller/ApplePS2Device.h @@ -160,7 +160,7 @@ #define kSC_NumLock 0x45 // -// ACPI message for brightness keys. +// ACPI message and device type for brightness keys. // #define kIOACPIMessageBrightnessCycle 0x85 // Cycle Brightness @@ -168,6 +168,10 @@ #define kIOACPIMessageBrightnessDown 0x87 // Decrease Brightness #define kIOACPIMessageBrightnessZero 0x88 // Zero Brightness #define kIOACPIMessageBrightnessOff 0x89 // Display Device Off + +#define kIOACPICRTMonitor 0x0100 // For integrated graphics +#define kIOACPILCDDisplay 0x0400 // For integrated graphics +#define kIOACPILegacyPanel 0x0110 // For discrete graphics // name of drivers/services as registered diff --git a/VoodooPS2Keyboard/VoodooPS2Keyboard.cpp b/VoodooPS2Keyboard/VoodooPS2Keyboard.cpp index a0e85f1b..9c894b6f 100644 --- a/VoodooPS2Keyboard/VoodooPS2Keyboard.cpp +++ b/VoodooPS2Keyboard/VoodooPS2Keyboard.cpp @@ -388,12 +388,28 @@ IOACPIPlatformDevice* ApplePS2Keyboard::getBrightnessPanel() { }; if (info) { - if (info->videoBuiltin != nullptr) - panel = getAcpiDevice(getDevicebyAddress(info->videoBuiltin, 0x400)); + if (info->videoBuiltin != nullptr) { + panel = getAcpiDevice(getDevicebyAddress(info->videoBuiltin, kIOACPILCDDisplay)); + + // + // On some newer laptops, address of Display Output Device (DOD) + // may not export panel information. We can verify it by whether + // a DOD of CRT type present, which should present when types are + // initialized correctly. If not, use DD1F instead. + // + if (panel == nullptr) { + IORegistryEntry *defaultLCD; + if (!getDevicebyAddress(info->videoBuiltin, kIOACPICRTMonitor) && + (defaultLCD = info->videoBuiltin->childFromPath("DD1F", gIODTPlane))) { + panel = getAcpiDevice(defaultLCD); + defaultLCD->release(); + } + } + } if (panel == nullptr) for (size_t i = 0; panel == nullptr && i < info->videoExternal.size(); ++i) - panel = getAcpiDevice(getDevicebyAddress(info->videoExternal[i].video, 0x110)); + panel = getAcpiDevice(getDevicebyAddress(info->videoExternal[i].video, kIOACPILegacyPanel)); DeviceInfo::deleter(info); } From cc8f931a3be6de2fc1b8857521624daa0579fad3 Mon Sep 17 00:00:00 2001 From: vit9696 <4348897+vit9696@users.noreply.github.com> Date: Tue, 22 Sep 2020 20:15:45 +0300 Subject: [PATCH 013/101] Sync changelog --- Changelog.md | 1 + 1 file changed, 1 insertion(+) diff --git a/Changelog.md b/Changelog.md index 46214e84..cd2eb185 100644 --- a/Changelog.md +++ b/Changelog.md @@ -2,6 +2,7 @@ VoodooPS2 Changelog ============================ #### v2.1.8 - Initial MacKernelSDK and Xcode 12 compatibility +- Improved native brightness keys discovery on CML/ICL #### 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`. From bd827d3ec7069098cfda846b44635fbe65b79f9b Mon Sep 17 00:00:00 2001 From: Andrey1970AppleLife Date: Wed, 23 Sep 2020 02:12:34 +0300 Subject: [PATCH 014/101] Build: Added -jobs 1 --- .travis.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.travis.yml b/.travis.yml index 11ce98dd..e1811c54 100644 --- a/.travis.yml +++ b/.travis.yml @@ -4,15 +4,15 @@ matrix: include: - os: osx name: "Build" - osx_image: xcode10.2 + osx_image: xcode11.6 compiler: clang script: - git clone https://github.com/acidanthera/MacKernelSDK - 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 + - xcodebuild -jobs 1 -configuration Debug + - xcodebuild -jobs 1 -configuration Release deploy: provider: releases From 383e67203c5fded1484498b501413b3132434596 Mon Sep 17 00:00:00 2001 From: Hiep Bao Le Date: Sat, 26 Sep 2020 02:16:46 +0700 Subject: [PATCH 015/101] Fix typo in Changelog (#25) --- Changelog.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Changelog.md b/Changelog.md index cd2eb185..b244e0d1 100644 --- a/Changelog.md +++ b/Changelog.md @@ -5,7 +5,7 @@ VoodooPS2 Changelog - Improved native brightness keys discovery on CML/ICL #### 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 ability for native brightness keys discovery with `Lilu` API, please be aware of this new dependency and drop SSDT modification to corresponding `_QXX`. - Added constants for 11.0 support #### v2.1.6 From ac8c2bb4eb3efb0db19e4738586aeda082b15abd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bartosz=20Korczy=C5=84ski?= Date: Mon, 28 Sep 2020 11:25:52 +0200 Subject: [PATCH 016/101] Implement Elan PS/2 touchpad support (#24) --- README.md | 7 +- VoodooPS2Controller.xcodeproj/project.pbxproj | 12 + VoodooPS2Trackpad/VoodooPS2Elan.cpp | 2212 +++++++++++++++++ VoodooPS2Trackpad/VoodooPS2Elan.h | 354 +++ .../VoodooPS2SynapticsTouchPad.cpp | 23 +- .../VoodooPS2SynapticsTouchPad.h | 14 +- .../VoodooPS2Trackpad-Info.plist | 74 + VoodooPS2Trackpad/VoodooPS2TrackpadCommon.h | 20 + 8 files changed, 2680 insertions(+), 36 deletions(-) create mode 100644 VoodooPS2Trackpad/VoodooPS2Elan.cpp create mode 100644 VoodooPS2Trackpad/VoodooPS2Elan.h create mode 100644 VoodooPS2Trackpad/VoodooPS2TrackpadCommon.h diff --git a/README.md b/README.md index c5cae4c8..addd24e1 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. @@ -57,8 +59,11 @@ 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 touchpad driver – linux kernel contributors, @kprinssu, @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. diff --git a/VoodooPS2Controller.xcodeproj/project.pbxproj b/VoodooPS2Controller.xcodeproj/project.pbxproj index 8af39b19..a6e43abf 100644 --- a/VoodooPS2Controller.xcodeproj/project.pbxproj +++ b/VoodooPS2Controller.xcodeproj/project.pbxproj @@ -11,6 +11,7 @@ 356B896323007F4F0042F30F /* VoodooInputEvent.h in Headers */ = {isa = PBXBuildFile; fileRef = 356B895F23007F4F0042F30F /* VoodooInputEvent.h */; }; 356B896423007F4F0042F30F /* VoodooInputTransducer.h in Headers */ = {isa = PBXBuildFile; fileRef = 356B896023007F4F0042F30F /* VoodooInputTransducer.h */; }; 356B896523007F4F0042F30F /* MultitouchHelpers.h in Headers */ = {isa = PBXBuildFile; fileRef = 356B896123007F4F0042F30F /* MultitouchHelpers.h */; }; + 4CC27EB3251FBC7700824FE1 /* VoodooPS2TrackpadCommon.h in Headers */ = {isa = PBXBuildFile; fileRef = 4CC27EB2251FBC7700824FE1 /* VoodooPS2TrackpadCommon.h */; }; 840F104A16EFE42600E8C116 /* ApplePS2Device.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 840F104916EFE42600E8C116 /* ApplePS2Device.cpp */; }; 84167820161B55B2002C60E6 /* VoodooPS2Controller.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 8416781F161B55B2002C60E6 /* VoodooPS2Controller.cpp */; }; 84167836161B5613002C60E6 /* VoodooPS2Keyboard.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 84167835161B5613002C60E6 /* VoodooPS2Keyboard.cpp */; }; @@ -32,6 +33,8 @@ 84DD197C162D496E0044D061 /* AppleACPIPS2Nub.h in Headers */ = {isa = PBXBuildFile; fileRef = 84DD197A162D496E0044D061 /* AppleACPIPS2Nub.h */; }; 84EB0AE316F0AD9300016108 /* ApplePS2KeyboardDevice.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 84833F9E161B627D00845294 /* ApplePS2KeyboardDevice.cpp */; }; 84EB0AE516F0AD9600016108 /* ApplePS2MouseDevice.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 84833FA0161B627D00845294 /* ApplePS2MouseDevice.cpp */; }; + 9828A92F24A2B6C200550FAA /* VoodooPS2Elan.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9828A92D24A2B6C200550FAA /* VoodooPS2Elan.cpp */; }; + 9828A93024A2B6C200550FAA /* VoodooPS2Elan.h in Headers */ = {isa = PBXBuildFile; fileRef = 9828A92E24A2B6C200550FAA /* VoodooPS2Elan.h */; }; CE8DA1C5251839B3008C44E8 /* libkmod.a in Frameworks */ = {isa = PBXBuildFile; fileRef = CE8DA1C4251839B2008C44E8 /* libkmod.a */; }; CE8DA1C6251839B7008C44E8 /* libkmod.a in Frameworks */ = {isa = PBXBuildFile; fileRef = CE8DA1C4251839B2008C44E8 /* libkmod.a */; }; CE8DA1C7251839B9008C44E8 /* libkmod.a in Frameworks */ = {isa = PBXBuildFile; fileRef = CE8DA1C4251839B2008C44E8 /* libkmod.a */; }; @@ -67,6 +70,7 @@ 356B895F23007F4F0042F30F /* VoodooInputEvent.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = VoodooInputEvent.h; path = VoodooInput/Debug/VoodooInput.kext/Contents/Resources/VoodooInputMultitouch/VoodooInputEvent.h; sourceTree = SOURCE_ROOT; }; 356B896023007F4F0042F30F /* VoodooInputTransducer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = VoodooInputTransducer.h; path = VoodooInput/Debug/VoodooInput.kext/Contents/Resources/VoodooInputMultitouch/VoodooInputTransducer.h; sourceTree = SOURCE_ROOT; }; 356B896123007F4F0042F30F /* MultitouchHelpers.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = MultitouchHelpers.h; path = VoodooInput/Debug/VoodooInput.kext/Contents/Resources/VoodooInputMultitouch/MultitouchHelpers.h; sourceTree = SOURCE_ROOT; }; + 4CC27EB2251FBC7700824FE1 /* VoodooPS2TrackpadCommon.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = VoodooPS2TrackpadCommon.h; sourceTree = ""; }; 7B44762421D52A7100418B25 /* ApplePS2MouseDevice.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ApplePS2MouseDevice.h; sourceTree = ""; }; 8404565C161E3AAF00D74D7F /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = ""; }; 8404565F161E3AC300D74D7F /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = ""; }; @@ -104,6 +108,8 @@ 84AE0F6C1BE4479200AF814A /* README.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = README.md; sourceTree = ""; }; 84DD1979162D496E0044D061 /* AppleACPIPS2Nub.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = AppleACPIPS2Nub.cpp; sourceTree = ""; }; 84DD197A162D496E0044D061 /* AppleACPIPS2Nub.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AppleACPIPS2Nub.h; sourceTree = ""; }; + 9828A92D24A2B6C200550FAA /* VoodooPS2Elan.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = VoodooPS2Elan.cpp; sourceTree = ""; }; + 9828A92E24A2B6C200550FAA /* VoodooPS2Elan.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = VoodooPS2Elan.h; sourceTree = ""; }; CE39B4E122D0CCC200D344F3 /* Changelog.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = Changelog.md; sourceTree = ""; }; CE7F451122E8A8C4003F7971 /* SSDT-MouseAsTrackpad.dsl */ = {isa = PBXFileReference; lastKnownFileType = text; path = "SSDT-MouseAsTrackpad.dsl"; sourceTree = ""; }; CE7F451222E8A8ED003F7971 /* SynapticsRevB.pdf */ = {isa = PBXFileReference; lastKnownFileType = image.pdf; path = SynapticsRevB.pdf; sourceTree = ""; }; @@ -272,10 +278,13 @@ 356B895D23007F1A0042F30F /* VoodooInput Headers */, 84833FAC161B62A900845294 /* VoodooPS2ALPSGlidePoint.h */, 84833FAB161B62A900845294 /* VoodooPS2ALPSGlidePoint.cpp */, + 9828A92E24A2B6C200550FAA /* VoodooPS2Elan.h */, + 9828A92D24A2B6C200550FAA /* VoodooPS2Elan.cpp */, 84833FAE161B62A900845294 /* VoodooPS2SentelicFSP.h */, 84833FAD161B62A900845294 /* VoodooPS2SentelicFSP.cpp */, 84833FB0161B62A900845294 /* VoodooPS2SynapticsTouchPad.h */, 84833FAF161B62A900845294 /* VoodooPS2SynapticsTouchPad.cpp */, + 4CC27EB2251FBC7700824FE1 /* VoodooPS2TrackpadCommon.h */, 84167857161B56C4002C60E6 /* Supporting Files */, ); path = VoodooPS2Trackpad; @@ -378,11 +387,13 @@ buildActionMask = 2147483647; files = ( 356B896323007F4F0042F30F /* VoodooInputEvent.h in Headers */, + 9828A93024A2B6C200550FAA /* VoodooPS2Elan.h in Headers */, 356B896223007F4F0042F30F /* VoodooInputMessages.h in Headers */, 356B896423007F4F0042F30F /* VoodooInputTransducer.h in Headers */, 84833FB2161B62A900845294 /* VoodooPS2ALPSGlidePoint.h in Headers */, 356B896523007F4F0042F30F /* MultitouchHelpers.h in Headers */, 84833FB4161B62A900845294 /* VoodooPS2SentelicFSP.h in Headers */, + 4CC27EB3251FBC7700824FE1 /* VoodooPS2TrackpadCommon.h in Headers */, 84833FB6161B62A900845294 /* VoodooPS2SynapticsTouchPad.h in Headers */, ); runOnlyForDeploymentPostprocessing = 0; @@ -636,6 +647,7 @@ buildActionMask = 2147483647; files = ( 84833FB1161B62A900845294 /* VoodooPS2ALPSGlidePoint.cpp in Sources */, + 9828A92F24A2B6C200550FAA /* VoodooPS2Elan.cpp in Sources */, 84833FB3161B62A900845294 /* VoodooPS2SentelicFSP.cpp in Sources */, 84833FB5161B62A900845294 /* VoodooPS2SynapticsTouchPad.cpp in Sources */, ); diff --git a/VoodooPS2Trackpad/VoodooPS2Elan.cpp b/VoodooPS2Trackpad/VoodooPS2Elan.cpp new file mode 100644 index 00000000..c17cf876 --- /dev/null +++ b/VoodooPS2Trackpad/VoodooPS2Elan.cpp @@ -0,0 +1,2212 @@ +/* +* Elan PS2 touchpad integration +* +* Mostly contains code ported from Linux +* https://github.com/torvalds/linux/blob/master/drivers/input/mouse/elantech.c +* +* Created by Bartosz Korczyński (@bandysc), Hiep Bao Le (@hieplpvip) +* Special thanks to Kishor Prins (@kprinssu), EMlyDinEsHMG and whole VoodooInput team +*/ + +// generally one cannot IOLog from interrupt context, it eventually leads to kernel panic +// but it is useful sometimes +#if 0 +#define INTERRUPT_LOG(args...) do { IOLog(args); } while (0) +#else +#define INTERRUPT_LOG(args...) do { } while (0) +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include "VoodooPS2Controller.h" +#include "VoodooPS2Elan.h" +#include "VoodooInputMultitouch/VoodooInputTransducer.h" +#include "VoodooInputMultitouch/VoodooInputMessages.h" + +// ============================================================================= +// ApplePS2Elan Class Implementation +// + +OSDefineMetaClassAndStructors(ApplePS2Elan, IOHIPointing); + +UInt32 ApplePS2Elan::deviceType() +{ return NX_EVS_DEVICE_TYPE_MOUSE; }; + +UInt32 ApplePS2Elan::interfaceID() +{ return NX_EVS_DEVICE_INTERFACE_BUS_ACE; }; + +#define abs(x) ((x) < 0 ? -(x) : (x)) + +bool ApplePS2Elan::init(OSDictionary *dict) { + // Initialize this object's minimal state. This is invoked right after this + // object is instantiated. + + 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); + + return true; +} + +void ApplePS2Elan::injectVersionDependentProperties(OSDictionary *config) { + // inject properties specific to the version of Darwin that is runnning... + char buf[32]; + 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)))) { + break; + } + + // check for "Darwin major.x" + snprintf(buf, sizeof(buf), "Darwin %d.x", version_major); + 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+")))) { + break; + } + } while (0); + + if (dict) { + // found version specific properties above, inject... + 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)) { + setProperty(key, value); + } + } + iter->release(); + } + } +} + +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)) { + return 0; + } + + _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) { + // if DisableDevice is Yes, then do not load at all... + OSBoolean *disable = OSDynamicCast(OSBoolean, config->getObject(kDisableDevice)); + if (disable && disable->isTrue()) { + config->release(); + _device = 0; + return 0; + } +#ifdef DEBUG + // save configuration for later/diagnostics... + setProperty(kMergedConfiguration, config); +#endif + + // load settings specific to Platform Profile + setParamPropertiesGated(config); + injectVersionDependentProperties(config); + OSSafeReleaseNULL(config); + } + + resetMouse(); + + DEBUG_LOG("VoodooPS2Elan: send magic knock to the device.\n"); + // send magic knock to the device + if (elantechDetect()) { + DEBUG_LOG("VoodooPS2Elan: elan touchpad not detected\n"); + return NULL; + } + + resetMouse(); + + if (elantechQueryInfo()) { + DEBUG_LOG("VoodooPS2Elan: query info failed\n"); + return NULL; + } + + DEBUG_LOG("VoodooPS2Elan: capabilities: %x %x %x\n", info.capabilities[0], info.capabilities[1], info.capabilities[2]); + DEBUG_LOG("VoodooPS2Elan: samples: %x %x %x\n", info.capabilities[0], info.capabilities[1], info.capabilities[2]); + DEBUG_LOG("VoodooPS2Elan: hw_version: %x\n", info.hw_version); + DEBUG_LOG("VoodooPS2Elan: fw_version: %x\n", info.fw_version); + DEBUG_LOG("VoodooPS2Elan: x_min: %d\n", info.x_min); + DEBUG_LOG("VoodooPS2Elan: y_min: %d\n", info.y_min); + DEBUG_LOG("VoodooPS2Elan: x_max: %d\n", info.x_max); + DEBUG_LOG("VoodooPS2Elan: y_max: %d\n", info.y_max); + DEBUG_LOG("VoodooPS2Elan: x_res: %d\n", info.x_res); + DEBUG_LOG("VoodooPS2Elan: y_res: %d\n", info.y_res); + DEBUG_LOG("VoodooPS2Elan: x_traces: %d\n", info.x_traces); + DEBUG_LOG("VoodooPS2Elan: y_traces: %d\n", info.y_traces); + DEBUG_LOG("VoodooPS2Elan: width: %d\n", info.width); + DEBUG_LOG("VoodooPS2Elan: bus: %d\n", info.bus); + DEBUG_LOG("VoodooPS2Elan: paritycheck: %d\n", info.paritycheck); + DEBUG_LOG("VoodooPS2Elan: jumpy_cursor: %d\n", info.jumpy_cursor); + DEBUG_LOG("VoodooPS2Elan: reports_pressure: %d\n", info.reports_pressure); + DEBUG_LOG("VoodooPS2Elan: crc_enabled: %d\n", info.crc_enabled); + DEBUG_LOG("VoodooPS2Elan: set_hw_resolution: %d\n", info.set_hw_resolution); + DEBUG_LOG("VoodooPS2Elan: has_trackpoint: %d\n", info.has_trackpoint); + DEBUG_LOG("VoodooPS2Elan: has_middle_button: %d\n", info.has_middle_button); + + DEBUG_LOG("VoodooPS2Elan: elan touchpad detected. Probing finished.\n"); + + _device = nullptr; + + return this; +} + +bool ApplePS2Elan::handleOpen(IOService *forClient, IOOptionBits options, void *arg) { + if (forClient && forClient->getProperty(VOODOO_INPUT_IDENTIFIER)) { + voodooInputInstance = forClient; + voodooInputInstance->retain(); + + return true; + } + + return super::handleOpen(forClient, options, arg); +} + +void ApplePS2Elan::handleClose(IOService *forClient, IOOptionBits options) { + OSSafeReleaseNULL(voodooInputInstance); + super::handleClose(forClient, options); +} + +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)) { + return false; + } + + // Maintain a pointer to and retain the provider object. + _device = (ApplePS2MouseDevice *)provider; + _device->retain(); + + // 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); + +#ifdef DEBUG + if (info.bus == ETP_BUS_PS2_ONLY) { + setProperty("Bus", "ETP_BUS_PS2_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) { + setProperty("Bus", "ETP_BUS_SMB_HST_NTFY_ONLY"); + } 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) { + 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)) { + 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) { + setProperty("SMBus NOTE", "It looks like your touchpad does not support SMBus protocol."); + } +#endif + + // 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) + setProperty("HIDScrollResolutionX", _scrollresolution << 16, 32); + setProperty("HIDScrollResolutionY", _scrollresolution << 16, 32); + + // Setup workloop with command gate for thread syncronization... + IOWorkLoop *pWorkLoop = getWorkLoop(); + _cmdGate = IOCommandGate::commandGate(this); + 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 it is safe to allow other threads + _device->unlock(); + + // 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); + + return true; +} + +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 + // 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 touchpad + setTouchPadEnable(false); + + // Release command gate + IOWorkLoop *pWorkLoop = getWorkLoop(); + if (pWorkLoop) { + if (_cmdGate) { + pWorkLoop->removeEventSource(_cmdGate); + OSSafeReleaseNULL(_cmdGate); + } + } + + // Uninstall the interrupt handler + if (_interruptHandlerInstalled) { + _device->uninstallInterruptAction(); + _interruptHandlerInstalled = false; + } + + // Uninstall the power control handler + if (_powerControlHandlerInstalled) { + _device->uninstallPowerControlAction(); + _powerControlHandlerInstalled = false; + } + + // Release the pointer to the provider object. + OSSafeReleaseNULL(_device); + + 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}, + {"ForceTouchMode", (int*)&_forceTouchMode}, + }; + + 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}, + }; + + const struct {const char *name; bool *var;} lowbitvars[] = { + {"USBMouseStopsTrackpad", &usb_mouse_stops_trackpad}, + }; + + OSBoolean *bl; + OSNumber *num; + + // highrate? + if ((bl = OSDynamicCast(OSBoolean, config->getObject("UseHighRate")))) { + 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)))) { + *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)))) { + *boolvars[i].var = bl->isTrue(); + setProperty(boolvars[i].name, *boolvars[i].var ? kOSBooleanTrue : kOSBooleanFalse); + } + } + + // 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; + 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? + *lowbitvars[i].var = bl->isTrue(); + setProperty(lowbitvars[i].name, *lowbitvars[i].var ? kOSBooleanTrue : kOSBooleanFalse); + } + } + + // disable trackpad when USB mouse is plugged in and this functionality is requested + if (attachedHIDPointerDevices && attachedHIDPointerDevices->getCount() > 0) { + ignoreall = usb_mouse_stops_trackpad; + } +} + +IOReturn ApplePS2Elan::setParamProperties(OSDictionary *dict) { + if (_cmdGate) { + // syncronize through workloop... + //_cmdGate->runAction(OSMemberFunctionCast(IOCommandGate::Action, this, &ApplePS2Elan::setParamPropertiesGated), dict); + setParamPropertiesGated(dict); + } + + return super::setParamProperties(dict); +} + +IOReturn ApplePS2Elan::setProperties(OSObject *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); +} + +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; + DEBUG_LOG("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: + // 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 + IOSleep(wakedelay); + + // 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() { + 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"); + + 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"); + 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); + OSSafeReleaseNULL(matchingDictionary); + } +} + +void ApplePS2Elan::unregisterHIDPointerNotifications() { + // Free device matching notifiers + // remove() releases them + + if (usb_hid_publish_notify) { + usb_hid_publish_notify->remove(); + } + + if (usb_hid_terminate_notify) { + usb_hid_terminate_notify->remove(); + } + + if (bluetooth_hid_publish_notify) { + bluetooth_hid_publish_notify->remove(); + } + + if (bluetooth_hid_terminate_notify) { + bluetooth_hid_terminate_notify->remove(); + } + + attachedHIDPointerDevices->flushCollection(); +} + +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")); + + if (propDeviceClass != NULL) { + UInt32 classOfDevice = propDeviceClass->unsigned32BitValue(); + + UInt32 deviceClassMajor = (classOfDevice & 0x1F00) >> 8; + UInt32 deviceClassMinor = (classOfDevice & 0xFF) >> 2; + + if (deviceClassMajor == kBluetoothDeviceClassMajorPeripheral) { // Bluetooth peripheral devices + UInt32 deviceClassMinor1 = (deviceClassMinor) & 0x30; + UInt32 deviceClassMinor2 = (deviceClassMinor) & 0x0F; + + if (deviceClassMinor1 == kBluetoothDeviceClassMinorPeripheral1Pointing || // Seperate pointing device + deviceClassMinor1 == kBluetoothDeviceClassMinorPeripheral1Combo) // Combo bluetooth keyboard/touchpad + { + if (deviceClassMinor2 == kBluetoothDeviceClassMinorPeripheral2Unclassified || // Mouse + 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()); + } + } + } + } + } + + 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 + ignoreall = false; + } + } +} + +bool ApplePS2Elan::notificationHIDAttachedHandler(void *refCon, IOService *newService, IONotifier *notifier) { + if (_cmdGate) { + _cmdGate->runAction(OSMemberFunctionCast(IOCommandGate::Action, this, &ApplePS2Elan::notificationHIDAttachedHandlerGated), newService, notifier); + } + + return true; +} + +// elantech.c port + +template +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++) { + 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++) { + params[i] = request.commands[i + 1].inOrOut; + } + + return request.commandsCount != 1 + I; +} + +/* + * A retrying version of ps2_command + */ +template +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) { + break; + } + tries--; + DEBUG_LOG("VoodooPS2Elan: retrying ps2 command 0x%02x (%d).\n", command, tries); + IOSleep(ETP_PS2_COMMAND_DELAY); + } while (tries > 0); + + if (rc) { + DEBUG_LOG("VoodooPS2Elan: ps2 command 0x%02x failed.\n", command); + } + + return rc; +} + +/* + * ps2_sliced_command() sends an extended PS/2 command to the mouse + * using sliced syntax, understood by advanced devices, such as Logitech + * or Synaptics touchpads. The command is encoded as: + * 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 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; +} + +/* + * 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)) { + DEBUG_LOG("VoodooPS2Elan: query 0x%02x failed.\n", c); + return -1; + } + + return 0; +} + +/* + * V3 and later support this fast command + */ +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)) { + DEBUG_LOG("VoodooPS2Elan: query 0x%02x failed.\n", c); + return -1; + } + + 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); + } +} + +bool ApplePS2Elan::elantech_is_signature_valid(const unsigned char *param) { + static const unsigned char rates[] = { 200, 100, 80, 60, 40, 20, 10 }; + + if (param[0] == 0) { + return false; + } + + 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) { + return true; + } + + for (int i = 0; i < sizeof(rates) / sizeof(*rates); i++) { + if (param[2] == rates[i]) { + return false; + } + } + + return true; +} + +/* + * (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) { + return (val * 10 + 790) * 10 / 254; +} + +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)) { + return -1; + } + + *x_res = elantech_convert_res(param[1] & 0x0f); + *y_res = elantech_convert_res((param[1] & 0xf0) >> 4); + *bus = param[2]; + + return 0; +} + +/* + * Use magic knock to detect Elantech touchpad + */ +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<3>(param, kDP_GetMouseInformation)) { + DEBUG_LOG("VoodooPS2Elan: sending Elantech magic knock failed.\n"); + 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)) { + DEBUG_LOG("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. + if (synaptics_send_cmd<3>(ETP_FW_VERSION_QUERY, param)) { + DEBUG_LOG("VoodooPS2Elan: failed to query firmware version.\n"); + return -1; + } + + DEBUG_LOG("VoodooPS2Elan: Elantech version query result 0x%02x, 0x%02x, 0x%02x.\n", param[0], param[1], param[2]); + + if (!elantech_is_signature_valid(param)) { + DEBUG_LOG("VoodooPS2Elan: Probably not a real Elantech touchpad. Aborting.\n"); + return -1; + } + + return 0; +} + +int ApplePS2Elan::elantechQueryInfo() { + unsigned char param[3]; + unsigned char traces; + + // Do the version query again so we can store the result + if (synaptics_send_cmd<3>(ETP_FW_VERSION_QUERY, param)) { + DEBUG_LOG("VoodooPS2Elan: failed to query firmware version.\n"); + return -1; + } + + info.fw_version = (param[0] << 16) | (param[1] << 8) | param[2]; + + if (elantechSetProperties()) { + DEBUG_LOG("VoodooPS2Elan: unknown hardware version, aborting...\n"); + return -1; + } + + DEBUG_LOG("VoodooPS2Elan assuming hardware version %d (with firmware version 0x%02x%02x%02x)\n", + info.hw_version, param[0], param[1], param[2]); + + if (send_cmd<3>(ETP_CAPABILITIES_QUERY, info.capabilities)) { + DEBUG_LOG("VoodooPS2Elan: failed to query capabilities.\n"); + return -1; + } + + DEBUG_LOG("VoodooPS2Elan: Elan capabilities query result 0x%02x, 0x%02x, 0x%02x.\n", + info.capabilities[0], info.capabilities[1], + info.capabilities[2]); + + if (info.hw_version != 1) { + if (send_cmd<3>(ETP_SAMPLE_QUERY, info.samples)) { + DEBUG_LOG("VoodooPS2Elan: failed to query sample data\n"); + return -1; + } + DEBUG_LOG("VoodooPS2Elan: Elan sample query result %02x, %02x, %02x\n", + info.samples[0], + info.samples[1], + info.samples[2]); + } + + 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. + DEBUG_LOG("VoodooPS2Elan: absolute mode broken, forcing standard PS/2 protocol\n"); + return -1; + } + + // 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)) { + DEBUG_LOG("VoodooPS2Elan: failed to query resolution data.\n"); + } + } + + // query range information + switch (info.hw_version) { + 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; + + case 2: + if (info.fw_version == 0x020800 || + info.fw_version == 0x020b00 || + info.fw_version == 0x020030) { + info.x_min = ETP_XMIN_V2; + info.y_min = ETP_YMIN_V2; + info.x_max = ETP_XMAX_V2; + info.y_max = ETP_YMAX_V2; + } else { + if (send_cmd<3>(ETP_FW_ID_QUERY, param)) { + return -1; + } + + 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)) { + 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; + + case 3: + 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)) { + 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; + } + + info.width = info.x_max / (traces - 1); + + // column number of traces + info.x_traces = traces; + + // row number of traces + traces = info.capabilities[2]; + if ((traces >= 2) && (traces <= info.y_max)) { + info.y_traces = traces; + } + + 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) && !info.is_buttonpad; + + 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; + + // Set packet length (4 for v1, 6 for v2 and newer) + _packetLength = (info.hw_version == 1) ? 4 : 6; + + return 0; +} + +/* + * 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(VOODOO_INPUT_TRANSFORM_KEY, 0ull, 32); + setProperty("VoodooInputSupported", kOSBooleanTrue); + registerService(); + + return 0; +} + +/* + * Put the touchpad into absolute mode + */ +int ApplePS2Elan::elantechSetAbsoluteMode() { + unsigned char val; + int tries = ETP_READ_BACK_TRIES; + int rc = 0; + + switch (info.hw_version) { + case 1: + etd.reg_10 = 0x16; + etd.reg_11 = 0x8f; + if (elantechWriteReg(0x10, etd.reg_10) || + elantechWriteReg(0x11, etd.reg_11)) { + rc = -1; + } + break; + + case 2: + // Windows driver values + etd.reg_10 = 0x54; + 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)) { + rc = -1; + } + break; + + case 3: + if (info.set_hw_resolution) { + etd.reg_10 = 0x0b; + } else { + etd.reg_10 = 0x01; + } + + if (elantechWriteReg(0x10, etd.reg_10)) { + rc = -1; + } + + break; + + case 4: + etd.reg_07 = 0x01; + if (elantechWriteReg(0x07, etd.reg_07)) { + rc = -1; + } + + 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. + do { + rc = elantechReadReg(0x10, &val); + if (rc == 0) { + break; + } + tries--; + DEBUG_LOG("VoodooPS2Elan: retrying read (%d).\n", tries); + IOSleep(ETP_READ_BACK_DELAY); + } while (tries > 0); + + if (rc) { + DEBUG_LOG("VoodooPS2Elan: failed to read back register 0x10.\n"); + } else if (info.hw_version == 1 && !(val & ETP_R10_ABSOLUTE_MODE)) { + DEBUG_LOG("VoodooPS2Elan: touchpad refuses to switch to absolute mode.\n"); + rc = -1; + } + } + +skip_readback_reg_10: + if (rc) { + DEBUG_LOG("VoodooPS2Elan: failed to initialise registers.\n"); + } + + return rc; +} + +/* + * Initialize the touchpad + */ +int ApplePS2Elan::elantechSetupPS2() { + etd.parity[0] = 1; + for (int i = 1; i < 256; i++) + etd.parity[i] = etd.parity[i & (i - 1)] ^ 1; + + if (elantechSetAbsoluteMode()) { + DEBUG_LOG("VoodooPS2: failed to put touchpad into absolute mode.\n"); + return -1; + } + + /* + if (info.fw_version == 0x381f17) { + etd.original_set_rate = psmouse->set_rate; + psmouse->set_rate = elantech_set_rate_restore_reg_07; + } + */ + + if (elantechSetInputParams()) { + DEBUG_LOG("VoodooPS2: failed to query touchpad range.\n"); + return -1; + } + + // set resolution and dpi + TPS2Request<> request; + request.commands[0].command = kPS2C_SendMouseCommandAndCompareAck; + request.commands[0].inOrOut = kDP_SetDefaultsAndDisable; // 0xF5, Disable data reporting + request.commands[1].command = kPS2C_SendMouseCommandAndCompareAck; + request.commands[1].inOrOut = kDP_SetMouseSampleRate; // 0xF3 + request.commands[2].command = kPS2C_SendMouseCommandAndCompareAck; + 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 = 8 counts/mm + request.commands[5].command = kPS2C_SendMouseCommandAndCompareAck; + request.commands[5].inOrOut = kDP_SetMouseScaling1To1; // 0xE6 + request.commands[6].command = kPS2C_SendMouseCommandAndCompareAck; + request.commands[6].inOrOut = kDP_Enable; // 0xF4, Enable Data Reporting + request.commandsCount = 7; + _device->submitRequestAndBlock(&request); + + return 0; +} + +/* + * 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] = {0, 0, 0}; + 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; + } + + if (rc) { + DEBUG_LOG("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) { + DEBUG_LOG("VoodooPS2Elan: failed to write register 0x%02x with value 0x%02x.\n", reg, 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::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(); + + // 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 + }; + + 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))) { + return PACKET_DEBOUNCE; + } + + // If the hardware flag 'crc_enabled' is set the packets have different signatures. + if (info.crc_enabled) { + if ((packet[3] & 0x09) == 0x08) { + return PACKET_V3_HEAD; + } + + if ((packet[3] & 0x09) == 0x09) { + return PACKET_V3_TAIL; + } + } else { + if ((packet[0] & 0x0c) == 0x04 && (packet[3] & 0xcf) == 0x02) { + return PACKET_V3_HEAD; + } + + if ((packet[0] & 0x0c) == 0x0c && (packet[3] & 0xce) == 0x0c) { + return PACKET_V3_TAIL; + } + + if ((packet[3] & 0x0f) == 0x06) { + return PACKET_TRACKPOINT; + } + } + + 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::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; + + // 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]); + + // pressure: (packet[1] & 0xf0) | ((packet[4] & 0xf0) >> 4); + // finger 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); + 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; + + 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; + + // 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]); + 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 + 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; + } + + // pressure: (packet[1] & 0xf0) | ((packet[4] & 0xf0) >> 4); + // finger width: ((packet[0] & 0x30) >> 2) | ((packet[3] & 0x30) >> 4); + + 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; + + 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::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; + } +} + +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; + 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); + + // 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 { + dispatchRelativePointerEvent(dx, dy, trackpointRightButton | trackpointLeftButton | trackpointMiddleButton, timestamp); + } +} + +void ApplePS2Elan::processPacketStatusV4() { + unsigned char *packet = _ringBuffer.tail(); + unsigned fingers; + leftButton = packet[0] & 0x1; + rightButton = packet[0] & 0x2; + + // notify finger state change + fingers = packet[1] & 0x1f; + int count = 0; + for (int i = 0; i < ETP_MAX_FINGERS; i++) { + if ((fingers & (1 << i)) == 0) { + // 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 { + 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) { + sendTouchData(); + } +} + +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; + } + + AbsoluteTime timestamp; + clock_get_uptime(×tamp); + + int x = ((packet[1] & 0x0f) << 8) | packet[2]; + int y = info.y_max - (((packet[4] & 0x0f) << 8) | packet[5]); + + 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] & 0x3); + virtualFinger[id].prev = virtualFinger[id].now; + virtualFinger[id].pressure = pres; + virtualFinger[id].width = traces; + + virtualFinger[id].now.x = x; + virtualFinger[id].now.y = y; + + if (headPacketsCount == heldFingers) { + headPacketsCount = 0; + sendTouchData(); + } +} + +void ApplePS2Elan::processPacketMotionV4() { + unsigned char *packet = _ringBuffer.tail(); + int weight, delta_x1 = 0, delta_y1 = 0, delta_x2 = 0, delta_y2 = 0; + int id, sid; + + 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. + 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] & 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] & 0x3); + virtualFinger[sid].prev = virtualFinger[sid].now; + virtualFinger[sid].now.x += delta_x2 * weight; + virtualFinger[sid].now.y -= delta_y2 * weight; + } + + sendTouchData(); +} + +MT2FingerType ApplePS2Elan::GetBestFingerType(int i) { + switch (i) { + case 0: return kMT2FingerTypeIndexFinger; + case 1: return kMT2FingerTypeMiddleFinger; + case 2: return kMT2FingerTypeRingFinger; + case 3: return kMT2FingerTypeThumb; + case 4: return kMT2FingerTypeLittleFinger; + + default: + break; + } + return kMT2FingerTypeIndexFinger; +} + +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/trackpoint usage + if (timestamp_ns - keytime < maxaftertyping) { + return; + } + + static_assert(VOODOO_INPUT_MAX_TRANSDUCERS >= ETP_MAX_FINGERS, "Trackpad supports too many fingers"); + + int transducers_count = 0; + for (int i = 0; i < ETP_MAX_FINGERS; i++) { + const auto &state = virtualFinger[i]; + if (!state.touch) { + continue; + } + + auto &transducer = inputEvent.transducers[transducers_count]; + + transducer.currentCoordinates = state.now; + transducer.previousCoordinates = state.prev; + transducer.timestamp = timestamp; + + transducer.isValid = true; + transducer.isPhysicalButtonDown = info.is_buttonpad && state.button; + transducer.isTransducerActive = true; + + transducer.secondaryId = i; + transducer.fingerType = GetBestFingerType(transducers_count); + transducer.type = FINGER; + + // 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 (_forceTouchMode == FORCE_TOUCH_BUTTON && transducer.isPhysicalButtonDown) { + transducer.supportsPressure = true; + transducer.isPhysicalButtonDown = false; + transducer.currentCoordinates.pressure = 255; + transducer.currentCoordinates.width = 10; + } + + transducers_count++; + } + + // 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 + // 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 > maxY) { + maxY = inputEvent.transducers[i].currentCoordinates.y; + newThumbIndex = i; + } + if (inputEvent.transducers[i].fingerType == kMT2FingerTypeThumb) { + currentThumbIndex = i; + } + } + inputEvent.transducers[currentThumbIndex].fingerType = inputEvent.transducers[newThumbIndex].fingerType; + inputEvent.transducers[newThumbIndex].fingerType = kMT2FingerTypeThumb; + } + + 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 = transducers_count; + inputEvent.timestamp = timestamp; + + if (voodooInputInstance) { + super::messageClient(kIOMessageVoodooInputMessage, voodooInputInstance, &inputEvent, sizeof(VoodooInputEvent)); + } + + 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; + } +} + +PS2InterruptResult ApplePS2Elan::interruptOccurred(UInt8 data) { + UInt8 *packet = _ringBuffer.head(); + packet[_packetByteCount++] = data; + + if (_packetByteCount == _packetLength) { + _ringBuffer.advanceHead(_packetLength); + _packetByteCount = 0; + return kPS2IR_packetReady; + } + + return kPS2IR_packetBuffering; +} + +void ApplePS2Elan::packetReady() { + INTERRUPT_LOG("VoodooPS2Elan: packet ready occurred\n"); + // empty the ring buffer, dispatching each packet... + while (_ringBuffer.count() >= _packetLength) { + if (ignoreall) { + _ringBuffer.advanceTail(_packetLength); + continue; + } + + int packetType; + switch (info.hw_version) { + case 1: + 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: + 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); + + switch (packetType) { + case PACKET_UNKNOWN: + INTERRUPT_LOG("VoodooPS2Elan: invalid packet received\n"); + break; + + case PACKET_DEBOUNCE: + // ignore debounce + break; + + case PACKET_TRACKPOINT: + INTERRUPT_LOG("VoodooPS2Elan: Handling trackpoint packet\n"); + elantechReportTrackpoint(); + break; + + default: + INTERRUPT_LOG("VoodooPS2Elan: Handling absolute mode\n"); + elantechReportAbsoluteV3(packetType); + break; + } + break; + + case 4: + packetType = elantechPacketCheckV4(); + INTERRUPT_LOG("VoodooPS2Elan: Packet Type %d\n", packetType); + + switch (packetType) { + case PACKET_UNKNOWN: + INTERRUPT_LOG("VoodooPS2Elan: invalid packet received\n"); + break; + + case PACKET_TRACKPOINT: + INTERRUPT_LOG("VoodooPS2Elan: Handling trackpoint packet\n"); + elantechReportTrackpoint(); + break; + + default: + INTERRUPT_LOG("VoodooPS2Elan: Handling absolute mode\n"); + elantechReportAbsoluteV4(packetType); + break; + } + break; + + default: + INTERRUPT_LOG("VoodooPS2Elan: invalid packet received\n"); + } + + _ringBuffer.advanceTail(_packetLength); + } +} + +void ApplePS2Elan::resetMouse() { + UInt8 params[2]; + ps2_command<2>(params, kDP_Reset); + + if (params[0] != 0xaa && params[1] != 0x00) { + DEBUG_LOG("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 new file mode 100644 index 00000000..363ab5e0 --- /dev/null +++ b/VoodooPS2Trackpad/VoodooPS2Elan.h @@ -0,0 +1,354 @@ +/* + * Elan PS2 touchpad integration + * + * Mostly contains code ported from Linux + * https://github.com/torvalds/linux/blob/master/drivers/input/mouse/elantech.c + * + * Created by Bartosz Korczyński (@bandysc), Hiep Bao Le (@hieplpvip) + * Special thanks to Kishor Prins (@kprinssu), EMlyDinEsHMG and whole VoodooInput team + */ + +#ifndef _APPLEPS2ELAN_H +#define _APPLEPS2ELAN_H + +#include "../VoodooPS2Controller/ApplePS2MouseDevice.h" +#include +#include +#include + +#include "VoodooInputMultitouch/VoodooInputEvent.h" +#include "VoodooPS2TrackpadCommon.h" + +struct virtual_finger_state { + TouchCoordinates prev; + TouchCoordinates now; + uint8_t pressure; + uint8_t width; + bool touch; + bool button; + MT2FingerType fingerType; +}; + +#define kPacketLengthMax 6 + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +// +// FROM LINUX ELANTECH.C + +/* + * Command values for Synaptics style queries + */ +#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 + +/* + * Command values for register reading or writing + */ +#define ETP_REGISTER_READ 0x10 +#define ETP_REGISTER_WRITE 0x11 +#define ETP_REGISTER_READWRITE 0x00 + +/* + * Hardware version 2 custom PS/2 command value + */ +#define ETP_PS2_CUSTOM_COMMAND 0xf8 + +/* + * Times to retry a ps2_command and millisecond delay between tries + */ +#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 + +/* + * Register bitmasks for hardware version 1 + */ +#define ETP_R10_ABSOLUTE_MODE 0x04 +#define ETP_R11_4_BYTE_MODE 0x02 + +/* + * Capability bitmasks + */ +#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_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 + +// Preasure min-max +#define ETP_PMIN_V2 0 +#define ETP_PMAX_V2 255 + +// Width min-max +#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 + +/* + * track up to 5 fingers for v4 hardware + */ +#define ETP_MAX_FINGERS 5 + +/* + * weight value for v4 hardware + */ +#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_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 + +/* + * New ICs are either using SMBus Host Notify or just plain PS2. + * + * ETP_FW_VERSION_QUERY is: + * Byte 1: + * - bit 0..3: IC BODY + * Byte 2: + * - bit 4: HiddenButton + * - bit 5: PS2_SMBUS_NOTIFY + * - bit 6: PS2CRCCheck + */ +#define ETP_NEW_IC_SMBUS_HOST_NOTIFY(fw_version) \ + ((((fw_version) & 0x0f2000) == 0x0f2000) && \ + ((fw_version) & 0x0000ff) > 0) + +/* + * The base position for one finger, v4 hardware + */ +struct finger_pos { + unsigned int x; + unsigned int y; +}; + +struct elantech_device_info { + unsigned char capabilities[3]; + unsigned char samples[3]; + unsigned char debug; + unsigned char hw_version; + unsigned int fw_version; + unsigned int x_min; + unsigned int y_min; + unsigned int x_max; + unsigned int y_max; + unsigned int x_res; + unsigned int y_res; + unsigned int x_traces; + unsigned int y_traces; + unsigned int width; + unsigned int bus; + bool paritycheck; + bool jumpy_cursor; + bool reports_pressure; + bool crc_enabled; + bool set_hw_resolution; + bool is_buttonpad; + bool has_trackpoint; + bool has_middle_button; +}; + +struct elantech_data { + unsigned char reg_07; + unsigned char reg_10; + unsigned char reg_11; + unsigned char reg_20; + unsigned char reg_21; + unsigned char reg_22; + unsigned char reg_23; + unsigned char reg_24; + unsigned char reg_25; + unsigned char reg_26; + unsigned int single_finger_reports; + struct finger_pos mt[ETP_MAX_FINGERS]; + unsigned char parity[256]; +}; + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +// ApplePS2Elan Class Declaration +// + +class EXPORT ApplePS2Elan : public IOHIPointing { + typedef IOHIPointing super; + OSDeclareDefaultStructors(ApplePS2Elan); + +private: + IOService* voodooInputInstance {nullptr}; + ApplePS2MouseDevice* _device {nullptr}; + bool _interruptHandlerInstalled {false}; + bool _powerControlHandlerInstalled {false}; + UInt32 _packetByteCount {0}; + UInt32 _packetLength {0}; + RingBuffer _ringBuffer {}; + + IOCommandGate* _cmdGate {nullptr}; + + VoodooInputEvent inputEvent {}; + + // 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; + UInt32 lastFingers = 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"); + + ForceTouchMode _forceTouchMode {FORCE_TOUCH_BUTTON}; + + int _scrollresolution {2300}; + int wakedelay {1000}; + int _trackpointMultiplierX {120}; + int _trackpointMultiplierY {120}; + int _trackpointDividerX {120}; + int _trackpointDividerY {120}; + + int _mouseResolution {0x3}; + int _mouseSampleRate {200}; + + bool _set_hw_resolution {false}; + + bool ignoreall {false}; + bool usb_mouse_stops_trackpad {true}; + + bool _processusbmouse {true}; + bool _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 + 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 registerHIDPointerNotifications(); + void unregisterHIDPointerNotifications(); + + void notificationHIDAttachedHandlerGated(IOService *newService, IONotifier *notifier); + bool notificationHIDAttachedHandler(void *refCon, IOService *newService, IONotifier *notifier); + + elantech_data etd {}; + elantech_device_info info {}; + int elantechDetect(); + int elantechQueryInfo(); + int elantechSetProperties(); + int elantechSetAbsoluteMode(); + int elantechSetInputParams(); + int elantechSetupPS2(); + 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); + void elantechReportTrackpoint(); + void processPacketStatusV4(); + void processPacketHeadV4(); + void processPacketMotionV4(); + void sendTouchData(); + void resetMouse(); + void setTouchPadEnable(bool enable); + + static MT2FingerType GetBestFingerType(int i); + + template + int ps2_command(UInt8* params, unsigned int command); + template + int elantech_ps2_command(unsigned char *param, int command); + int ps2_sliced_command(UInt8 command); + template + 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); + +public: + 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; +}; + +#endif /* _ApplePS2Elan_H */ diff --git a/VoodooPS2Trackpad/VoodooPS2SynapticsTouchPad.cpp b/VoodooPS2Trackpad/VoodooPS2SynapticsTouchPad.cpp index 409c6af2..aad50287 100644 --- a/VoodooPS2Trackpad/VoodooPS2SynapticsTouchPad.cpp +++ b/VoodooPS2Trackpad/VoodooPS2SynapticsTouchPad.cpp @@ -38,9 +38,6 @@ #define kTPDN "TPDN" // Trackpad Disable Notification #include - -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Winconsistent-missing-override" #include #include #include @@ -48,29 +45,11 @@ #include #include #include -#pragma clang diagnostic pop #include "VoodooPS2Controller.h" #include "VoodooPS2SynapticsTouchPad.h" #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 -}; - // ============================================================================= // ApplePS2SynapticsTouchPad Class Implementation // @@ -462,7 +441,7 @@ void ApplePS2SynapticsTouchPad::queryCapabilities() setProperty(VOODOO_INPUT_PHYSICAL_MAX_X_KEY, physical_max_x, 32); setProperty(VOODOO_INPUT_PHYSICAL_MAX_Y_KEY, physical_max_y, 32); - setProperty(kIOFBTransformKey, 0ull, 32); + setProperty(VOODOO_INPUT_TRANSFORM_KEY, 0ull, 32); setProperty("VoodooInputSupported", kOSBooleanTrue); registerService(); diff --git a/VoodooPS2Trackpad/VoodooPS2SynapticsTouchPad.h b/VoodooPS2Trackpad/VoodooPS2SynapticsTouchPad.h index f322fceb..a88d040a 100644 --- a/VoodooPS2Trackpad/VoodooPS2SynapticsTouchPad.h +++ b/VoodooPS2Trackpad/VoodooPS2SynapticsTouchPad.h @@ -25,14 +25,10 @@ #include "../VoodooPS2Controller/ApplePS2MouseDevice.h" #include - -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Winconsistent-missing-override" #include #include -#pragma clang diagnostic pop - #include "VoodooInputMultitouch/VoodooInputEvent.h" +#include "VoodooPS2TrackpadCommon.h" // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // SimpleAverage Class Declaration @@ -184,14 +180,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 SYNAPTICS_MAX_FINGERS 5 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/VoodooPS2Trackpad/VoodooPS2Trackpad-Info.plist b/VoodooPS2Trackpad/VoodooPS2Trackpad-Info.plist index 883e74f6..93906e63 100644 --- a/VoodooPS2Trackpad/VoodooPS2Trackpad-Info.plist +++ b/VoodooPS2Trackpad/VoodooPS2Trackpad-Info.plist @@ -85,6 +85,80 @@ + Elantech TouchPad + + IOProbeScore + 7000 + IOProviderClass + ApplePS2MouseDevice + IOClass + ApplePS2Elan + CFBundleIdentifier + as.acidanthera.voodoo.driver.PS2Trackpad + Platform Profile + + Default + + ButtonCount + 3 + Darwin 16+ + + ApplePreferenceCapability + + ApplePreferenceIdentifier + com.apple.AppleMultitouchTrackpad + MT Built-in + + MTHIDDevice + + SupportsGestureScrolling + + TrackpadEmbedded + + TrackpadFourFingerGestures + + TrackpadSecondaryClickCorners + + TrackpadThreeFingerDrag + + + DisableDevice + + ForceTouchMode + 1 + MouseResolution + 3 + MouseSampleRate + 200 + ProcessBluetoothMouseStopsTrackpad + + ProcessUSBMouseStopsTrackpad + + QuietTimeAfterTyping + 500000000 + ScrollResolution + 400 + SetHwResolution + + TrackpointDividerX + 120 + TrackpointDividerY + 120 + TrackpointMultiplierX + 120 + TrackpointMultiplierY + 120 + USBMouseStopsTrackpad + 0 + UseHighRate + + WakeDelay + 1000 + + + RM,deliverNotifications + + Native Multitouch Engine CFBundleIdentifier diff --git a/VoodooPS2Trackpad/VoodooPS2TrackpadCommon.h b/VoodooPS2Trackpad/VoodooPS2TrackpadCommon.h new file mode 100644 index 00000000..d38d1957 --- /dev/null +++ b/VoodooPS2Trackpad/VoodooPS2TrackpadCommon.h @@ -0,0 +1,20 @@ +// +// VoodooPS2TrackpadCommon.h +// VoodooPS2Trackpad +// +// Created by Le Bao Hiep on 27/09/2020. +// Copyright © 2020 Acidanthera. All rights reserved. +// + +#ifndef VoodooPS2TrackpadCommon_h +#define VoodooPS2TrackpadCommon_h + +typedef enum { + FORCE_TOUCH_DISABLED = 0, + FORCE_TOUCH_BUTTON = 1, + FORCE_TOUCH_THRESHOLD = 2, + FORCE_TOUCH_VALUE = 3, + FORCE_TOUCH_CUSTOM = 4 +} ForceTouchMode; + +#endif /* VoodooPS2TrackpadCommon_h */ From 86d8fb2a47dbed569145341ac40a4c5681bc66ce Mon Sep 17 00:00:00 2001 From: zhen-zen <66577170+zhen-zen@users.noreply.github.com> Date: Mon, 28 Sep 2020 02:26:37 -0700 Subject: [PATCH 017/101] Workaround for buggy vendor backlight implements (#26) --- VoodooPS2Controller/ApplePS2Device.h | 10 +- VoodooPS2Keyboard/VoodooPS2Keyboard.cpp | 116 ++++++++++++++++-------- VoodooPS2Keyboard/VoodooPS2Keyboard.h | 8 +- 3 files changed, 90 insertions(+), 44 deletions(-) diff --git a/VoodooPS2Controller/ApplePS2Device.h b/VoodooPS2Controller/ApplePS2Device.h index b6e639cf..af89e832 100644 --- a/VoodooPS2Controller/ApplePS2Device.h +++ b/VoodooPS2Controller/ApplePS2Device.h @@ -161,6 +161,7 @@ // // ACPI message and device type for brightness keys. +// See ACPI Specification, Appendix B: Video Extensions for details // #define kIOACPIMessageBrightnessCycle 0x85 // Cycle Brightness @@ -169,9 +170,12 @@ #define kIOACPIMessageBrightnessZero 0x88 // Zero Brightness #define kIOACPIMessageBrightnessOff 0x89 // Display Device Off -#define kIOACPICRTMonitor 0x0100 // For integrated graphics -#define kIOACPILCDDisplay 0x0400 // For integrated graphics -#define kIOACPILegacyPanel 0x0110 // For discrete graphics +#define kIOACPIDisplayTypeMask 0x0F00 + +#define kIOACPICRTMonitor 0x0100 // VGA* CRT or VESA* Compatible Analog Monitor +#define kIOACPILCDPanel 0x0400 // Internal/Integrated Digital Flat Panel + +#define kIOACPILegacyPanel 0x0110 // Integrated LCD Panel #1 using a common, backwards compatible ID // name of drivers/services as registered diff --git a/VoodooPS2Keyboard/VoodooPS2Keyboard.cpp b/VoodooPS2Keyboard/VoodooPS2Keyboard.cpp index 9c894b6f..97b34c1f 100644 --- a/VoodooPS2Keyboard/VoodooPS2Keyboard.cpp +++ b/VoodooPS2Keyboard/VoodooPS2Keyboard.cpp @@ -65,7 +65,7 @@ // Constants for brightness keys -#define kBrightnessDevice "BrightnessDevice" +#define kBrightnessPanel "BrightnessPanel" #define kBrightnessKey "BrightnessKey" // Definitions for Macro Inversion data format @@ -181,9 +181,13 @@ bool ApplePS2Keyboard::init(OSDictionary * dict) // initialize ACPI support for brightness key _panel = 0; + _panelFallback = 0; + _panelDiscrete = 0; _panelNotified = false; _panelPrompt = false; _panelNotifiers = 0; + _panelNotifiersFallback = 0; + _panelNotifiersDiscrete = 0; // initialize ACPI support for keyboard backlight/screen brightness _provider = 0; @@ -345,7 +349,7 @@ ApplePS2Keyboard* ApplePS2Keyboard::probe(IOService * provider, SInt32 * score) // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -IORegistryEntry* ApplePS2Keyboard::getDevicebyAddress(IORegistryEntry *parent, int address) { +IORegistryEntry* ApplePS2Keyboard::getDevicebyAddress(IORegistryEntry *parent, int address, int mask) { IORegistryEntry* child = NULL; auto iter = parent->getChildIterator(gIODTPlane); if (iter) { @@ -356,7 +360,8 @@ IORegistryEntry* ApplePS2Keyboard::getDevicebyAddress(IORegistryEntry *parent, i // 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) { + sscanf(dev->getLocation(), "%x", &addr) == 1 && + (addr & mask) == address) { child = dev; break; } @@ -368,9 +373,7 @@ IORegistryEntry* ApplePS2Keyboard::getDevicebyAddress(IORegistryEntry *parent, i // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -IOACPIPlatformDevice* ApplePS2Keyboard::getBrightnessPanel() { - IOACPIPlatformDevice *panel = nullptr; - +void ApplePS2Keyboard::getBrightnessPanel() { auto info = DeviceInfo::create(); auto getAcpiDevice = [](IORegistryEntry *dev) -> IOACPIPlatformDevice * { @@ -387,34 +390,53 @@ IOACPIPlatformDevice* ApplePS2Keyboard::getBrightnessPanel() { return nullptr; }; - if (info) { - if (info->videoBuiltin != nullptr) { - panel = getAcpiDevice(getDevicebyAddress(info->videoBuiltin, kIOACPILCDDisplay)); + if (!info) + return; - // - // On some newer laptops, address of Display Output Device (DOD) - // may not export panel information. We can verify it by whether - // a DOD of CRT type present, which should present when types are - // initialized correctly. If not, use DD1F instead. - // - if (panel == nullptr) { - IORegistryEntry *defaultLCD; - if (!getDevicebyAddress(info->videoBuiltin, kIOACPICRTMonitor) && - (defaultLCD = info->videoBuiltin->childFromPath("DD1F", gIODTPlane))) { - panel = getAcpiDevice(defaultLCD); - defaultLCD->release(); - } + if (info->videoBuiltin != nullptr) { + // + // ACPI Spec B.5.1 _ADR (Return the Unique ID for this Device) + // + // This method returns a unique ID representing the display + // output device. All output devices must have a unique hardware + // ID. This method is required for all The IDs returned by this + // method will appear in the list of hardware IDs returned by the + // _DOD method. + // + _panel = getAcpiDevice(getDevicebyAddress(info->videoBuiltin, kIOACPILCDPanel, kIOACPIDisplayTypeMask)); + + // + // On some newer laptops, address of Display Output Device (DOD) + // may not export panel information. We can verify it by whether + // a DOD of CRT type present, which should present when types are + // initialized correctly. If not, use DD1F instead. + // + if (_panel == nullptr && !getDevicebyAddress(info->videoBuiltin, kIOACPICRTMonitor)) { + auto defaultPanel = info->videoBuiltin->childFromPath("DD1F", gIODTPlane); + if (defaultPanel != nullptr) { + _panel = getAcpiDevice(defaultPanel); + defaultPanel->release(); } } - if (panel == nullptr) - for (size_t i = 0; panel == nullptr && i < info->videoExternal.size(); ++i) - panel = getAcpiDevice(getDevicebyAddress(info->videoExternal[i].video, kIOACPILegacyPanel)); - - DeviceInfo::deleter(info); + // + // Some vendors just won't follow the specs and update their code + // + if (strncmp(_panel->getName(), "DD02", strlen("DD02"))) { + auto fallbackPanel = info->videoBuiltin->childFromPath("DD02", gIODTPlane); + if (fallbackPanel != nullptr) { + _panelFallback = getAcpiDevice(fallbackPanel); + fallbackPanel->release(); + } + } } - return panel; + for (size_t i = 0; i < info->videoExternal.size(); ++i) + if ((_panelDiscrete = getAcpiDevice(getDevicebyAddress(info->videoExternal[i].video, kIOACPILCDPanel, kIOACPIDisplayTypeMask))) || + (_panelDiscrete = getAcpiDevice(getDevicebyAddress(info->videoExternal[i].video, kIOACPILegacyPanel)))) + break; + + DeviceInfo::deleter(info); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -463,13 +485,19 @@ bool ApplePS2Keyboard::start(IOService * provider) } // 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"); - } + getBrightnessPanel(); + + if (_panel != NULL) + _panelNotifiers = _panel->registerInterest(gIOGeneralInterest, _panelNotification, this); + + if (_panelFallback != NULL) + _panelNotifiersFallback = _panelFallback->registerInterest(gIOGeneralInterest, _panelNotification, this); + + if (_panelDiscrete != NULL) + _panelNotifiersDiscrete = _panelDiscrete->registerInterest(gIOGeneralInterest, _panelNotification, this); + + if (_panelNotifiers == NULL && _panelNotifiersFallback == NULL && _panelNotifiersDiscrete == NULL) + IOLog("ps2br: unable to register any interests for GFX notifications\n"); // get IOACPIPlatformDevice for Device (PS2K) //REVIEW: should really look at the parent chain for IOACPIPlatformDevice instead. @@ -1046,7 +1074,16 @@ void ApplePS2Keyboard::stop(IOService * provider) // if (_panel && _panelNotifiers) _panelNotifiers->remove(); + + if (_panelFallback && _panelNotifiersFallback) + _panelNotifiersFallback->remove(); + + if (_panelDiscrete && _panelNotifiersDiscrete) + _panelNotifiersDiscrete->remove(); + OSSafeReleaseNULL(_panel); + OSSafeReleaseNULL(_panelFallback); + OSSafeReleaseNULL(_panelDiscrete); OSSafeReleaseNULL(_provider); // @@ -2050,7 +2087,7 @@ IOReturn ApplePS2Keyboard::_panelNotification(void *target, void *refCon, UInt32 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()); + DEBUG_LOG("%s %s ACPI brightness up\n", self->getName(), provider->getName()); break; case kIOACPIMessageBrightnessDown: @@ -2058,22 +2095,23 @@ IOReturn ApplePS2Keyboard::_panelNotification(void *target, void *refCon, UInt32 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()); + DEBUG_LOG("%s %s ACPI brightness down\n", self->getName(), provider->getName()); break; case kIOACPIMessageBrightnessCycle: case kIOACPIMessageBrightnessZero: case kIOACPIMessageBrightnessOff: - DEBUG_LOG("%s ACPI brightness operation 0x%02x not implemented\n", self->getName(), *((UInt32 *) messageArgument)); + DEBUG_LOG("%s %s ACPI brightness operation 0x%02x not implemented\n", self->getName(), provider->getName(), *((UInt32 *) messageArgument)); return kIOReturnSuccess; default: - DEBUG_LOG("%s unknown ACPI notification 0x%04x\n", self->getName(), *((UInt32 *) messageArgument)); + DEBUG_LOG("%s %s unknown ACPI notification 0x%04x\n", self->getName(), provider->getName(), *((UInt32 *) messageArgument)); return kIOReturnSuccess; } if (!self->_panelNotified) { self->_panelNotified = true; self->setProperty(kBrightnessKey, "ACPI"); + self->setProperty(kBrightnessPanel, provider->getName()); } } else { DEBUG_LOG("%s %s received unknown kIOACPIMessageDeviceNotification\n", self->getName(), provider->getName()); diff --git a/VoodooPS2Keyboard/VoodooPS2Keyboard.h b/VoodooPS2Keyboard/VoodooPS2Keyboard.h index 5a701303..4c30cae0 100644 --- a/VoodooPS2Keyboard/VoodooPS2Keyboard.h +++ b/VoodooPS2Keyboard/VoodooPS2Keyboard.h @@ -106,9 +106,13 @@ class EXPORT ApplePS2Keyboard : public IOHIKeyboard // ACPI support for panel brightness IOACPIPlatformDevice * _panel; + IOACPIPlatformDevice * _panelFallback; + IOACPIPlatformDevice * _panelDiscrete; bool _panelNotified; bool _panelPrompt; IONotifier * _panelNotifiers; + IONotifier * _panelNotifiersFallback; + IONotifier * _panelNotifiersDiscrete; IOACPIPlatformDevice * _provider; int * _brightnessLevels; @@ -141,8 +145,8 @@ 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(); + IORegistryEntry* getDevicebyAddress(IORegistryEntry *parent, int address, int mask = 0xFFFFFFFF); + void 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); From bd1a11c897cf08ac8009e944b2b234fd7d028ab4 Mon Sep 17 00:00:00 2001 From: vit9696 <4348897+vit9696@users.noreply.github.com> Date: Mon, 28 Sep 2020 13:51:30 +0300 Subject: [PATCH 018/101] Sync changelog --- Changelog.md | 1 + 1 file changed, 1 insertion(+) diff --git a/Changelog.md b/Changelog.md index b244e0d1..b58c6042 100644 --- a/Changelog.md +++ b/Changelog.md @@ -3,6 +3,7 @@ VoodooPS2 Changelog #### v2.1.8 - Initial MacKernelSDK and Xcode 12 compatibility - Improved native brightness keys discovery on CML/ICL +- Added support for select ELAN touchpads by BAndysc and hieplpvip #### v2.1.7 - Added ability for native brightness keys discovery with `Lilu` API, please be aware of this new dependency and drop SSDT modification to corresponding `_QXX`. From 4f4ad8e0796e888b3dc8e8e25acc94c46edd4bef Mon Sep 17 00:00:00 2001 From: Michael Belyaev Date: Mon, 28 Sep 2020 19:54:22 +0300 Subject: [PATCH 019/101] Revert "Workaround for buggy vendor backlight implements (#26)" This reverts commit 86d8fb2a47dbed569145341ac40a4c5681bc66ce. Revert "Fix typo in Changelog (#25)" This reverts commit 383e67203c5fded1484498b501413b3132434596. Revert "Workaround for ICL/CML brightness keys (#23)" This reverts commit 1e2925d3c1f90b454b0d12a5e0ea1a0e57d62287. Revert "Get ACPI notification for brightness keys from GFX0.DD1F/DD02 (#22)" This reverts commit d5f05415ac087ed4411b51ce73ac19c021bbaf48. --- .gitignore | 1 - .travis.yml | 3 - Changelog.md | 2 - 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 | 18 -- VoodooPS2Controller/VoodooPS2Controller.cpp | 4 +- .../VoodooPS2Keyboard-Info.plist | 4 - VoodooPS2Keyboard/VoodooPS2Keyboard.cpp | 209 +----------------- VoodooPS2Keyboard/VoodooPS2Keyboard.h | 15 +- 14 files changed, 9 insertions(+), 264 deletions(-) diff --git a/.gitignore b/.gitignore index 9a4e5a50..6de4bdb1 100644 --- a/.gitignore +++ b/.gitignore @@ -7,5 +7,4 @@ xcuserdata xcshareddata project.xcworkspace VoodooInput -Lilu.kext /MacKernelSDK diff --git a/.travis.yml b/.travis.yml index e1811c54..dd3729f8 100644 --- a/.travis.yml +++ b/.travis.yml @@ -9,7 +9,6 @@ matrix: script: - git clone https://github.com/acidanthera/MacKernelSDK - - 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 -jobs 1 -configuration Debug - xcodebuild -jobs 1 -configuration Release @@ -30,8 +29,6 @@ matrix: compiler: clang script: - - git clone https://github.com/acidanthera/MacKernelSDK - - 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 b58c6042..a75ca659 100644 --- a/Changelog.md +++ b/Changelog.md @@ -2,11 +2,9 @@ VoodooPS2 Changelog ============================ #### v2.1.8 - Initial MacKernelSDK and Xcode 12 compatibility -- Improved native brightness keys discovery on CML/ICL - Added support for select ELAN touchpads by BAndysc and hieplpvip #### v2.1.7 -- Added ability for native brightness keys discovery with `Lilu` API, please be aware of this new dependency and drop SSDT modification to corresponding `_QXX`. - Added constants for 11.0 support #### v2.1.6 diff --git a/README.md b/README.md index addd24e1..db7b4221 100644 --- a/README.md +++ b/README.md @@ -36,8 +36,6 @@ 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. - 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 a6e43abf..789bbf52 100644 --- a/VoodooPS2Controller.xcodeproj/project.pbxproj +++ b/VoodooPS2Controller.xcodeproj/project.pbxproj @@ -193,7 +193,6 @@ CE8DA1C3251839B2008C44E8 /* Frameworks */, ); sourceTree = ""; - usesTabs = 0; }; 84167814161B55B2002C60E6 /* Products */ = { isa = PBXGroup; @@ -488,7 +487,7 @@ 84167808161B55B2002C60E6 /* Project object */ = { isa = PBXProject; attributes = { - LastUpgradeCheck = 1200; + LastUpgradeCheck = 1140; ORGANIZATIONNAME = Acidanthera; }; buildConfigurationList = 8416780B161B55B2002C60E6 /* Build configuration list for PBXProject "VoodooPS2Controller" */; @@ -713,7 +712,6 @@ 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; @@ -775,7 +773,6 @@ 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; @@ -872,7 +869,6 @@ 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)", @@ -894,7 +890,6 @@ 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 53cfca6d..d9cf0273 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 @@ -585,8 +583,6 @@ 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 97b34c1f..1ac73cd4 100644 --- a/VoodooPS2Keyboard/VoodooPS2Keyboard.cpp +++ b/VoodooPS2Keyboard/VoodooPS2Keyboard.cpp @@ -40,7 +40,6 @@ #include "ApplePS2ToADBMap.h" #include "AppleACPIPS2Nub.h" #include -#include // Constants for Info.plist settings @@ -63,11 +62,6 @@ #define kMacroTranslation "Macro Translation" #define kMaxMacroTime "MaximumMacroTime" -// Constants for brightness keys - -#define kBrightnessPanel "BrightnessPanel" -#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) @@ -179,16 +173,6 @@ bool ApplePS2Keyboard::init(OSDictionary * dict) _keysSpecial = 0; _f12ejectdelay = 250; // default is 250 ms - // initialize ACPI support for brightness key - _panel = 0; - _panelFallback = 0; - _panelDiscrete = 0; - _panelNotified = false; - _panelPrompt = false; - _panelNotifiers = 0; - _panelNotifiersFallback = 0; - _panelNotifiersDiscrete = 0; - // initialize ACPI support for keyboard backlight/screen brightness _provider = 0; _brightnessLevels = 0; @@ -349,98 +333,6 @@ ApplePS2Keyboard* ApplePS2Keyboard::probe(IOService * provider, SInt32 * score) // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -IORegistryEntry* ApplePS2Keyboard::getDevicebyAddress(IORegistryEntry *parent, int address, int mask) { - 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 & mask) == address) { - child = dev; - break; - } - } - } - OSSafeRelease(iter); - return child; -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void ApplePS2Keyboard::getBrightnessPanel() { - 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) - return; - - if (info->videoBuiltin != nullptr) { - // - // ACPI Spec B.5.1 _ADR (Return the Unique ID for this Device) - // - // This method returns a unique ID representing the display - // output device. All output devices must have a unique hardware - // ID. This method is required for all The IDs returned by this - // method will appear in the list of hardware IDs returned by the - // _DOD method. - // - _panel = getAcpiDevice(getDevicebyAddress(info->videoBuiltin, kIOACPILCDPanel, kIOACPIDisplayTypeMask)); - - // - // On some newer laptops, address of Display Output Device (DOD) - // may not export panel information. We can verify it by whether - // a DOD of CRT type present, which should present when types are - // initialized correctly. If not, use DD1F instead. - // - if (_panel == nullptr && !getDevicebyAddress(info->videoBuiltin, kIOACPICRTMonitor)) { - auto defaultPanel = info->videoBuiltin->childFromPath("DD1F", gIODTPlane); - if (defaultPanel != nullptr) { - _panel = getAcpiDevice(defaultPanel); - defaultPanel->release(); - } - } - - // - // Some vendors just won't follow the specs and update their code - // - if (strncmp(_panel->getName(), "DD02", strlen("DD02"))) { - auto fallbackPanel = info->videoBuiltin->childFromPath("DD02", gIODTPlane); - if (fallbackPanel != nullptr) { - _panelFallback = getAcpiDevice(fallbackPanel); - fallbackPanel->release(); - } - } - } - - for (size_t i = 0; i < info->videoExternal.size(); ++i) - if ((_panelDiscrete = getAcpiDevice(getDevicebyAddress(info->videoExternal[i].video, kIOACPILCDPanel, kIOACPIDisplayTypeMask))) || - (_panelDiscrete = getAcpiDevice(getDevicebyAddress(info->videoExternal[i].video, kIOACPILegacyPanel)))) - break; - - DeviceInfo::deleter(info); -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool ApplePS2Keyboard::start(IOService * provider) { DEBUG_LOG("ApplePS2Keyboard::start entered...\n"); @@ -484,21 +376,6 @@ bool ApplePS2Keyboard::start(IOService * provider) return false; } - // get IOACPIPlatformDevice for built-in panel - getBrightnessPanel(); - - if (_panel != NULL) - _panelNotifiers = _panel->registerInterest(gIOGeneralInterest, _panelNotification, this); - - if (_panelFallback != NULL) - _panelNotifiersFallback = _panelFallback->registerInterest(gIOGeneralInterest, _panelNotification, this); - - if (_panelDiscrete != NULL) - _panelNotifiersDiscrete = _panelDiscrete->registerInterest(gIOGeneralInterest, _panelNotification, this); - - if (_panelNotifiers == NULL && _panelNotifiersFallback == NULL && _panelNotifiersDiscrete == NULL) - IOLog("ps2br: unable to register any interests 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"); @@ -1070,20 +947,8 @@ void ApplePS2Keyboard::stop(IOService * provider) OSSafeReleaseNULL(_device); // - // Release ACPI provider for panel and PS2K ACPI device + // Release ACPI provider for PS2K ACPI device // - if (_panel && _panelNotifiers) - _panelNotifiers->remove(); - - if (_panelFallback && _panelNotifiersFallback) - _panelNotifiersFallback->remove(); - - if (_panelDiscrete && _panelNotifiersDiscrete) - _panelNotifiersDiscrete->remove(); - - OSSafeReleaseNULL(_panel); - OSSafeReleaseNULL(_panelFallback); - OSSafeReleaseNULL(_panelDiscrete); OSSafeReleaseNULL(_provider); // @@ -1941,19 +1806,6 @@ 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) @@ -2065,65 +1917,6 @@ 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 %s ACPI brightness up\n", self->getName(), provider->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 %s ACPI brightness down\n", self->getName(), provider->getName()); - break; - - case kIOACPIMessageBrightnessCycle: - case kIOACPIMessageBrightnessZero: - case kIOACPIMessageBrightnessOff: - DEBUG_LOG("%s %s ACPI brightness operation 0x%02x not implemented\n", self->getName(), provider->getName(), *((UInt32 *) messageArgument)); - return kIOReturnSuccess; - - default: - DEBUG_LOG("%s %s unknown ACPI notification 0x%04x\n", self->getName(), provider->getName(), *((UInt32 *) messageArgument)); - return kIOReturnSuccess; - } - if (!self->_panelNotified) { - self->_panelNotified = true; - self->setProperty(kBrightnessKey, "ACPI"); - self->setProperty(kBrightnessPanel, provider->getName()); - } - } 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 4c30cae0..4f885718 100644 --- a/VoodooPS2Keyboard/VoodooPS2Keyboard.h +++ b/VoodooPS2Keyboard/VoodooPS2Keyboard.h @@ -28,7 +28,6 @@ #include #include -#include #include @@ -104,16 +103,7 @@ class EXPORT ApplePS2Keyboard : public IOHIKeyboard IOTimerEventSource* _sleepEjectTimer; UInt32 _maxsleeppresstime; - // ACPI support for panel brightness - IOACPIPlatformDevice * _panel; - IOACPIPlatformDevice * _panelFallback; - IOACPIPlatformDevice * _panelDiscrete; - bool _panelNotified; - bool _panelPrompt; - IONotifier * _panelNotifiers; - IONotifier * _panelNotifiersFallback; - IONotifier * _panelNotifiersDiscrete; - + // ACPI support for screen brightness IOACPIPlatformDevice * _provider; int * _brightnessLevels; int _brightnessCount; @@ -145,9 +135,6 @@ class EXPORT ApplePS2Keyboard : public IOHIKeyboard virtual void setKeyboardEnable(bool enable); virtual void initKeyboard(); virtual void setDevicePowerState(UInt32 whatToDo); - IORegistryEntry* getDevicebyAddress(IORegistryEntry *parent, int address, int mask = 0xFFFFFFFF); - void 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 153bd805fdc1c87c64cd93a6c5523eebeb40d482 Mon Sep 17 00:00:00 2001 From: Michael Belyaev Date: Mon, 28 Sep 2020 20:28:52 +0300 Subject: [PATCH 020/101] Fix version and code analysis --- .travis.yml | 1 + Changelog.md | 5 ++--- VoodooPS2Controller.xcodeproj/project.pbxproj | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/.travis.yml b/.travis.yml index dd3729f8..f8fdc47e 100644 --- a/.travis.yml +++ b/.travis.yml @@ -29,6 +29,7 @@ matrix: compiler: clang script: + - git clone https://github.com/acidanthera/MacKernelSDK - 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 a75ca659..d1b398c5 100644 --- a/Changelog.md +++ b/Changelog.md @@ -1,10 +1,9 @@ VoodooPS2 Changelog ============================ -#### v2.1.8 -- Initial MacKernelSDK and Xcode 12 compatibility -- Added support for select ELAN touchpads by BAndysc and hieplpvip #### v2.1.7 +- Initial MacKernelSDK and Xcode 12 compatibility +- Added support for select ELAN touchpads by BAndysc and hieplpvip - Added constants for 11.0 support #### v2.1.6 diff --git a/VoodooPS2Controller.xcodeproj/project.pbxproj b/VoodooPS2Controller.xcodeproj/project.pbxproj index 789bbf52..3c215345 100644 --- a/VoodooPS2Controller.xcodeproj/project.pbxproj +++ b/VoodooPS2Controller.xcodeproj/project.pbxproj @@ -759,7 +759,7 @@ KERNEL_FRAMEWORK_HEADERS = "$(PROJECT_DIR)/MacKernelSDK/Headers"; "LLVM_LTO[arch=x86_64]" = YES; MACOSX_DEPLOYMENT_TARGET = 10.11; - MODULE_VERSION = 2.1.8; + MODULE_VERSION = 2.1.7; ONLY_ACTIVE_ARCH = YES; "OTHER_LDFLAGS[arch=x86_64]" = "-dead_strip"; PRODUCT_NAME = VoodooPS2Controller; @@ -813,7 +813,7 @@ KERNEL_FRAMEWORK_HEADERS = "$(PROJECT_DIR)/MacKernelSDK/Headers"; "LLVM_LTO[arch=x86_64]" = YES; MACOSX_DEPLOYMENT_TARGET = 10.11; - MODULE_VERSION = 2.1.8; + MODULE_VERSION = 2.1.7; "OTHER_LDFLAGS[arch=x86_64]" = "-dead_strip"; PRODUCT_NAME = VoodooPS2Controller; SDKROOT = macosx; From 6d3b230ad57cddf2a49e71773abd94b0265bbb1d Mon Sep 17 00:00:00 2001 From: zhen-zen <66577170+zhen-zen@users.noreply.github.com> Date: Wed, 30 Sep 2020 16:21:51 -0700 Subject: [PATCH 021/101] Remove obsolete ACPI brightness control (#28) --- VoodooPS2Keyboard/VoodooPS2Keyboard.cpp | 136 +----------------------- VoodooPS2Keyboard/VoodooPS2Keyboard.h | 6 +- 2 files changed, 5 insertions(+), 137 deletions(-) diff --git a/VoodooPS2Keyboard/VoodooPS2Keyboard.cpp b/VoodooPS2Keyboard/VoodooPS2Keyboard.cpp index 1ac73cd4..8b24adbf 100644 --- a/VoodooPS2Keyboard/VoodooPS2Keyboard.cpp +++ b/VoodooPS2Keyboard/VoodooPS2Keyboard.cpp @@ -173,9 +173,8 @@ bool ApplePS2Keyboard::init(OSDictionary * dict) _keysSpecial = 0; _f12ejectdelay = 250; // default is 250 ms - // initialize ACPI support for keyboard backlight/screen brightness + // initialize ACPI support for keyboard backlight _provider = 0; - _brightnessLevels = 0; _backlightLevels = 0; _logscancodes = 0; @@ -380,64 +379,11 @@ bool ApplePS2Keyboard::start(IOService * provider) //REVIEW: should really look at the parent chain for IOACPIPlatformDevice instead. _provider = (IOACPIPlatformDevice*)IORegistryEntry::fromPath("IOService:/AppleACPIPlatformExpert/PS2K"); - // - // get brightness levels for ACPI based brightness keys - // - - OSObject* result = 0; - if (_provider) do - { - // check for brightness methods - if (kIOReturnSuccess != _provider->validateObject("KBCL") || kIOReturnSuccess != _provider->validateObject("KBCM") || kIOReturnSuccess != _provider->validateObject("KBQC")) - { - break; - } - // methods are there, so now try to collect brightness levels - if (kIOReturnSuccess != _provider->evaluateObject("KBCL", &result)) - { - DEBUG_LOG("ps2br: KBCL returned error\n"); - break; - } - OSArray* array = OSDynamicCast(OSArray, result); - if (!array) - { - DEBUG_LOG("ps2br: KBCL returned non-array package\n"); - break; - } - int count = array->getCount(); - if (count < 4) - { - DEBUG_LOG("ps2br: KBCL returned invalid package\n"); - break; - } - _brightnessCount = count; - _brightnessLevels = new int[_brightnessCount]; - if (!_brightnessLevels) - { - DEBUG_LOG("ps2br: _brightnessLevels new int[] failed\n"); - break; - } - for (int i = 0; i < _brightnessCount; i++) - { - OSNumber* num = OSDynamicCast(OSNumber, array->getObject(i)); - int brightness = num ? num->unsigned32BitValue() : 0; - _brightnessLevels[i] = brightness; - } -#ifdef DEBUG_VERBOSE - DEBUG_LOG("ps2br: Brightness levels: { "); - for (int i = 0; i < _brightnessCount; i++) - DEBUG_LOG("%d, ", _brightnessLevels[i]); - DEBUG_LOG("}\n"); -#endif - break; - } while (false); - - OSSafeReleaseNULL(result); - // // get keyboard backlight levels for ACPI based backlight keys // + OSObject* result = 0; if (_provider) do { // check for brightness methods @@ -950,18 +896,9 @@ void ApplePS2Keyboard::stop(IOService * provider) // Release ACPI provider for PS2K ACPI device // OSSafeReleaseNULL(_provider); - - // - // Release data related to screen brightness - // - if (_brightnessLevels) - { - delete[] _brightnessLevels; - _brightnessLevels = 0; - } - + // - // Release data related to screen brightness + // Release data related to keyboard backlight // if (_backlightLevels) { @@ -1336,63 +1273,6 @@ void ApplePS2Keyboard::dispatchInvertBuffer() // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -// -// Note: attempted brightness through ACPI methods, but it didn't work. -// -// I think because Probook 4530s does some funny in things in its -// ACPI brightness methods. -// -// Just keeping it here in case someone wants to try with theirs. - -void ApplePS2Keyboard::modifyScreenBrightness(int adbKeyCode, bool goingDown) -{ - assert(_provider); - assert(_brightnessLevels); - - // get current brightness level - UInt32 result; - if (kIOReturnSuccess != _provider->evaluateInteger("KBQC", &result)) - { - DEBUG_LOG("ps2br: KBQC returned error\n"); - return; - } - int current = result; -#ifdef DEBUG_VERBOSE - if (goingDown) - DEBUG_LOG("ps2br: Current brightness: %d\n", current); -#endif - // calculate new brightness level, find current in table >= entry in table - // note first two entries in table are ac-power/battery - int index = 2; - while (index < _brightnessCount) - { - if (_brightnessLevels[index] >= current) - break; - ++index; - } - // move to next or previous - index += (adbKeyCode == 0x90 ? +1 : -1); - if (index >= _brightnessCount) - index = _brightnessCount - 1; - if (index < 2) - index = 2; -#ifdef DEBUG_VERBOSE - if (goingDown) - DEBUG_LOG("ps2br: setting brightness %d\n", _brightnessLevels[index]); -#endif - OSNumber* num = OSNumber::withNumber(_brightnessLevels[index], 32); - if (!num) - { - DEBUG_LOG("ps2br: OSNumber::withNumber failed\n"); - return; - } - if (goingDown && kIOReturnSuccess != _provider->evaluateObject("KBCM", NULL, (OSObject**)&num, 1)) - { - DEBUG_LOG("ps2br: KBCM returned error\n"); - } - num->release(); -} - // // Note: trying for ACPI backlight control for ASUS notebooks // @@ -1806,14 +1686,6 @@ bool ApplePS2Keyboard::dispatchKeyboardEventWithPacket(const UInt8* packet) // special cases switch (adbKeyCode) { - case 0x90: - case 0x91: - if (_brightnessLevels) - { - modifyScreenBrightness(adbKeyCode, goingDown); - adbKeyCode = DEADKEY; - } - break; case 0x92: // eject if (0 == _PS2modifierState) { diff --git a/VoodooPS2Keyboard/VoodooPS2Keyboard.h b/VoodooPS2Keyboard/VoodooPS2Keyboard.h index 4f885718..1c8a0f62 100644 --- a/VoodooPS2Keyboard/VoodooPS2Keyboard.h +++ b/VoodooPS2Keyboard/VoodooPS2Keyboard.h @@ -103,12 +103,8 @@ class EXPORT ApplePS2Keyboard : public IOHIKeyboard IOTimerEventSource* _sleepEjectTimer; UInt32 _maxsleeppresstime; - // ACPI support for screen brightness - IOACPIPlatformDevice * _provider; - int * _brightnessLevels; - int _brightnessCount; - // ACPI support for keyboard backlight + IOACPIPlatformDevice * _provider; int * _backlightLevels; int _backlightCount; From f0797cec2192287d6d0199d74d154b673f80b37e Mon Sep 17 00:00:00 2001 From: Le Bao Hiep Date: Thu, 1 Oct 2020 12:56:12 +0700 Subject: [PATCH 022/101] Remove dead code in VoodooPS2Elan --- VoodooPS2Trackpad/VoodooPS2Elan.cpp | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/VoodooPS2Trackpad/VoodooPS2Elan.cpp b/VoodooPS2Trackpad/VoodooPS2Elan.cpp index c17cf876..f1867bbb 100644 --- a/VoodooPS2Trackpad/VoodooPS2Elan.cpp +++ b/VoodooPS2Trackpad/VoodooPS2Elan.cpp @@ -41,8 +41,6 @@ UInt32 ApplePS2Elan::deviceType() UInt32 ApplePS2Elan::interfaceID() { return NX_EVS_DEVICE_INTERFACE_BUS_ACE; }; -#define abs(x) ((x) < 0 ? -(x) : (x)) - bool ApplePS2Elan::init(OSDictionary *dict) { // Initialize this object's minimal state. This is invoked right after this // object is instantiated. @@ -1767,11 +1765,6 @@ void ApplePS2Elan::elantechReportAbsoluteV3(int packetType) { } 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"); @@ -1906,9 +1899,6 @@ void ApplePS2Elan::processPacketHeadV4() { return; } - AbsoluteTime timestamp; - clock_get_uptime(×tamp); - int x = ((packet[1] & 0x0f) << 8) | packet[2]; int y = info.y_max - (((packet[4] & 0x0f) << 8) | packet[5]); From bcc187d4017e04605884c5ec86c1bbbfbe81b5ff Mon Sep 17 00:00:00 2001 From: Hiep Bao Le Date: Thu, 1 Oct 2020 22:38:24 +0700 Subject: [PATCH 023/101] Improve key time dispatch (#30) --- VoodooPS2Controller/VoodooPS2Controller.cpp | 2 +- VoodooPS2Mouse/VoodooPS2Mouse.cpp | 20 ++------------------ VoodooPS2Trackpad/VoodooPS2Elan.cpp | 5 ++--- 3 files changed, 5 insertions(+), 22 deletions(-) diff --git a/VoodooPS2Controller/VoodooPS2Controller.cpp b/VoodooPS2Controller/VoodooPS2Controller.cpp index 5add312d..63ab1359 100644 --- a/VoodooPS2Controller/VoodooPS2Controller.cpp +++ b/VoodooPS2Controller/VoodooPS2Controller.cpp @@ -2012,7 +2012,7 @@ void ApplePS2Controller::dispatchMessageGated(int* message, void* data) switch (pInfo->adbKeyCode) { - // Do not trigger on modifier key presses (for example multi-click select) + // Do not trigger on modifier key presses (for example multi-click select) case 0x38: // left shift case 0x3c: // right shift case 0x3b: // left control diff --git a/VoodooPS2Mouse/VoodooPS2Mouse.cpp b/VoodooPS2Mouse/VoodooPS2Mouse.cpp index d5ff2e3c..a2bdb9a6 100644 --- a/VoodooPS2Mouse/VoodooPS2Mouse.cpp +++ b/VoodooPS2Mouse/VoodooPS2Mouse.cpp @@ -1263,27 +1263,11 @@ IOReturn ApplePS2Mouse::message(UInt32 type, IOService* provider, void* argument break; } - case kPS2M_notifyKeyPressed: + case kPS2M_notifyKeyTime: { // just remember last time key pressed... this can be used in // interrupt handler to detect unintended input while typing - PS2KeyInfo* pInfo = (PS2KeyInfo*)argument; - switch (pInfo->adbKeyCode) - { - // don't store key time for modifier keys going down - case 0x38: // left shift - case 0x3c: // right shift - case 0x3b: // left control - case 0x3e: // right control - case 0x3a: // left alt (command) - case 0x3d: // right alt - case 0x37: // left windows (option) - case 0x36: // right windows - if (pInfo->goingDown) - break; - default: - keytime = pInfo->time; - } + keytime = *((uint64_t*)argument); break; } } diff --git a/VoodooPS2Trackpad/VoodooPS2Elan.cpp b/VoodooPS2Trackpad/VoodooPS2Elan.cpp index f1867bbb..993b0586 100644 --- a/VoodooPS2Trackpad/VoodooPS2Elan.cpp +++ b/VoodooPS2Trackpad/VoodooPS2Elan.cpp @@ -468,12 +468,11 @@ IOReturn ApplePS2Elan::message(UInt32 type, IOService* provider, void* argument) break; } - case kPS2M_notifyKeyPressed: + case kPS2M_notifyKeyTime: { // 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; + keytime = *((uint64_t*)argument); break; } } From a5d2997e2be9449ad3322ff1ae4bd0391fab537a Mon Sep 17 00:00:00 2001 From: vandroiy2013 Date: Mon, 5 Oct 2020 20:01:58 +0300 Subject: [PATCH 024/101] 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 3c215345..789bbf52 100644 --- a/VoodooPS2Controller.xcodeproj/project.pbxproj +++ b/VoodooPS2Controller.xcodeproj/project.pbxproj @@ -759,7 +759,7 @@ KERNEL_FRAMEWORK_HEADERS = "$(PROJECT_DIR)/MacKernelSDK/Headers"; "LLVM_LTO[arch=x86_64]" = YES; MACOSX_DEPLOYMENT_TARGET = 10.11; - MODULE_VERSION = 2.1.7; + MODULE_VERSION = 2.1.8; ONLY_ACTIVE_ARCH = YES; "OTHER_LDFLAGS[arch=x86_64]" = "-dead_strip"; PRODUCT_NAME = VoodooPS2Controller; @@ -813,7 +813,7 @@ KERNEL_FRAMEWORK_HEADERS = "$(PROJECT_DIR)/MacKernelSDK/Headers"; "LLVM_LTO[arch=x86_64]" = YES; MACOSX_DEPLOYMENT_TARGET = 10.11; - MODULE_VERSION = 2.1.7; + MODULE_VERSION = 2.1.8; "OTHER_LDFLAGS[arch=x86_64]" = "-dead_strip"; PRODUCT_NAME = VoodooPS2Controller; SDKROOT = macosx; From f579efa977508611ce53ff972a3f74b7750c9444 Mon Sep 17 00:00:00 2001 From: zhen-zen <66577170+zhen-zen@users.noreply.github.com> Date: Mon, 12 Oct 2020 10:55:09 -0700 Subject: [PATCH 025/101] Fix timestamp type for PS2KeyInfo; receiving PS2KeyInfo from other kext (#31) --- VoodooPS2Controller/ApplePS2Device.h | 5 ++++- VoodooPS2Keyboard/VoodooPS2Keyboard.cpp | 13 +++++++++++++ 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/VoodooPS2Controller/ApplePS2Device.h b/VoodooPS2Controller/ApplePS2Device.h index b9ad98f9..3a986906 100644 --- a/VoodooPS2Controller/ApplePS2Device.h +++ b/VoodooPS2Controller/ApplePS2Device.h @@ -532,11 +532,14 @@ enum // from sensor (such as yoga mode indicator) to keyboard kPS2K_setKeyboardStatus = iokit_vendor_specific_msg(200), // set disable/enable keyboard (data is bool*) kPS2K_getKeyboardStatus = iokit_vendor_specific_msg(201), // get disable/enable keyboard (data is bool*) + + // from OEM ACPI (WMI) events to keyboard + kPS2K_notifyKeystroke = iokit_vendor_specific_msg(202), // notify of key press (data is PS2KeyInfo*), in the opposite direction of kPS2M_notifyKeyPressed }; typedef struct PS2KeyInfo { - int64_t time; + uint64_t time; UInt16 adbKeyCode; bool goingDown; bool eatKey; diff --git a/VoodooPS2Keyboard/VoodooPS2Keyboard.cpp b/VoodooPS2Keyboard/VoodooPS2Keyboard.cpp index 8b24adbf..dda2e254 100644 --- a/VoodooPS2Keyboard/VoodooPS2Keyboard.cpp +++ b/VoodooPS2Keyboard/VoodooPS2Keyboard.cpp @@ -1004,6 +1004,19 @@ IOReturn ApplePS2Keyboard::message(UInt32 type, IOService* provider, void* argum } break; } + + case kPS2K_notifyKeystroke: + { + if (argument) { + PS2KeyInfo *keystroke = (PS2KeyInfo*)argument; + if (!keystroke->eatKey) { + // the key is consumed + keystroke->eatKey = true; + dispatchKeyboardEventX(keystroke->adbKeyCode, keystroke->goingDown, keystroke->time); + } + } + break; + } } return kIOReturnSuccess; } From d367cade30119dbf7d115a653d5f64e02b40ad89 Mon Sep 17 00:00:00 2001 From: Vitaly Cheptsov <4348897+vit9696@users.noreply.github.com> Date: Mon, 12 Oct 2020 20:55:52 +0300 Subject: [PATCH 026/101] Sync changelog --- Changelog.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Changelog.md b/Changelog.md index d1b398c5..f0640754 100644 --- a/Changelog.md +++ b/Changelog.md @@ -1,6 +1,9 @@ VoodooPS2 Changelog ============================ +#### v2.1.8 +- Added support for receiving input form other kexts + #### v2.1.7 - Initial MacKernelSDK and Xcode 12 compatibility - Added support for select ELAN touchpads by BAndysc and hieplpvip From 7512e01c6cc5a144b779aed248a810d8796fceda Mon Sep 17 00:00:00 2001 From: vit9696 Date: Sun, 11 Oct 2020 15:05:30 +0300 Subject: [PATCH 027/101] Fixed dynamic coordinate refresh for ELAN v3 touchpads --- Changelog.md | 1 + VoodooPS2Controller.xcodeproj/project.pbxproj | 3 +- .../xcschemes/VoodooPS2Controller.xcscheme | 4 +- .../xcschemes/VoodooPS2Keyboard.xcscheme | 2 +- .../xcschemes/VoodooPS2Mouse.xcscheme | 2 +- .../xcschemes/VoodooPS2Trackpad.xcscheme | 2 +- VoodooPS2Controller/VoodooPS2Controller.cpp | 4 +- VoodooPS2Trackpad/VoodooPS2Elan.cpp | 48 +++++++++++++++++-- VoodooPS2Trackpad/VoodooPS2Elan.h | 1 + 9 files changed, 55 insertions(+), 12 deletions(-) diff --git a/Changelog.md b/Changelog.md index f0640754..48d9223a 100644 --- a/Changelog.md +++ b/Changelog.md @@ -3,6 +3,7 @@ VoodooPS2 Changelog #### v2.1.8 - Added support for receiving input form other kexts +- Fixed dynamic coordinate refresh for ELAN v3 touchpads #### v2.1.7 - Initial MacKernelSDK and Xcode 12 compatibility diff --git a/VoodooPS2Controller.xcodeproj/project.pbxproj b/VoodooPS2Controller.xcodeproj/project.pbxproj index 789bbf52..2bd39ce1 100644 --- a/VoodooPS2Controller.xcodeproj/project.pbxproj +++ b/VoodooPS2Controller.xcodeproj/project.pbxproj @@ -193,6 +193,7 @@ CE8DA1C3251839B2008C44E8 /* Frameworks */, ); sourceTree = ""; + usesTabs = 0; }; 84167814161B55B2002C60E6 /* Products */ = { isa = PBXGroup; @@ -487,7 +488,7 @@ 84167808161B55B2002C60E6 /* Project object */ = { isa = PBXProject; attributes = { - LastUpgradeCheck = 1140; + LastUpgradeCheck = 1200; ORGANIZATIONNAME = Acidanthera; }; buildConfigurationList = 8416780B161B55B2002C60E6 /* Build configuration list for PBXProject "VoodooPS2Controller" */; diff --git a/VoodooPS2Controller.xcodeproj/xcshareddata/xcschemes/VoodooPS2Controller.xcscheme b/VoodooPS2Controller.xcodeproj/xcshareddata/xcschemes/VoodooPS2Controller.xcscheme index d9cf0273..07d93519 100644 --- a/VoodooPS2Controller.xcodeproj/xcshareddata/xcschemes/VoodooPS2Controller.xcscheme +++ b/VoodooPS2Controller.xcodeproj/xcshareddata/xcschemes/VoodooPS2Controller.xcscheme @@ -1,6 +1,6 @@ info.x_max) { + info.x_max = x; + needs_update = true; + } + + if (y > info.y_max) { + info.y_max = y; + needs_update = true; + } + + if (needs_update) { + 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 - info.x_min + 1) * 100 / info.x_res, 32); + setProperty(VOODOO_INPUT_PHYSICAL_MAX_Y_KEY, (info.y_max - info.y_min + 1) * 100 / info.y_res, 32); + + if (voodooInputInstance) { + VoodooInputDimensions dims = { + static_cast(info.x_min), static_cast(info.x_max), + static_cast(info.y_min), static_cast(info.y_max) + }; + + super::messageClient(kIOMessageVoodooInputUpdateDimensionsMessage, voodooInputInstance, &dims, sizeof(dims)); + } + } +} + void ApplePS2Elan::elantechReportAbsoluteV1() { unsigned char *packet = _ringBuffer.tail(); unsigned int fingers = 0, x = 0, y = 0; @@ -1666,6 +1697,11 @@ void ApplePS2Elan::elantechReportAbsoluteV3(int packetType) { // byte 0: n1 n0 . . . . R L fingers = (packet[0] & 0xc0) >> 6; + INTERRUPT_LOG("report abs v3 type %d finger %u x %d y %d btn %d (%02x %02x %02x %02x %02x %02x)\n", packetType, fingers, + ((packet[1] & 0x0f) << 8) | packet[2], + (((packet[4] & 0x0f) << 8) | packet[5]), + packet[0] & 0x03, packet[0], packet[1], packet[2], packet[3], packet[4], packet[5]); + switch (fingers) { case 3: case 1: @@ -1675,7 +1711,9 @@ void ApplePS2Elan::elantechReportAbsoluteV3(int packetType) { // 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]); + y1 = (((packet[4] & 0x0f) << 8) | packet[5]); + elantechRescale(x1, y1); + y1 = info.y_max - y1; break; case 2: @@ -1696,7 +1734,9 @@ void ApplePS2Elan::elantechReportAbsoluteV3(int packetType) { 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]); + y2 = (((packet[4] & 0x0f) << 8) | packet[5]); + elantechRescale(x2, y2); + y2 = info.y_max - y2; break; } diff --git a/VoodooPS2Trackpad/VoodooPS2Elan.h b/VoodooPS2Trackpad/VoodooPS2Elan.h index 363ab5e0..332cea0f 100644 --- a/VoodooPS2Trackpad/VoodooPS2Elan.h +++ b/VoodooPS2Trackpad/VoodooPS2Elan.h @@ -306,6 +306,7 @@ class EXPORT ApplePS2Elan : public IOHIPointing { int elantechPacketCheckV2(); int elantechPacketCheckV3(); int elantechPacketCheckV4(); + void elantechRescale(unsigned int x, unsigned int y); void elantechReportAbsoluteV1(); void elantechReportAbsoluteV2(); void elantechReportAbsoluteV3(int packetType); From 650b5698688aed2155b72901240dd0225304fd66 Mon Sep 17 00:00:00 2001 From: vandroiy2013 Date: Mon, 2 Nov 2020 21:29:05 +0200 Subject: [PATCH 028/101] 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 2bd39ce1..ede05238 100644 --- a/VoodooPS2Controller.xcodeproj/project.pbxproj +++ b/VoodooPS2Controller.xcodeproj/project.pbxproj @@ -760,7 +760,7 @@ KERNEL_FRAMEWORK_HEADERS = "$(PROJECT_DIR)/MacKernelSDK/Headers"; "LLVM_LTO[arch=x86_64]" = YES; MACOSX_DEPLOYMENT_TARGET = 10.11; - MODULE_VERSION = 2.1.8; + MODULE_VERSION = 2.1.9; ONLY_ACTIVE_ARCH = YES; "OTHER_LDFLAGS[arch=x86_64]" = "-dead_strip"; PRODUCT_NAME = VoodooPS2Controller; @@ -814,7 +814,7 @@ KERNEL_FRAMEWORK_HEADERS = "$(PROJECT_DIR)/MacKernelSDK/Headers"; "LLVM_LTO[arch=x86_64]" = YES; MACOSX_DEPLOYMENT_TARGET = 10.11; - MODULE_VERSION = 2.1.8; + MODULE_VERSION = 2.1.9; "OTHER_LDFLAGS[arch=x86_64]" = "-dead_strip"; PRODUCT_NAME = VoodooPS2Controller; SDKROOT = macosx; From 428b31077160cb76791806ff505363c5020c4375 Mon Sep 17 00:00:00 2001 From: vit9696 Date: Mon, 23 Nov 2020 15:01:41 +0300 Subject: [PATCH 029/101] Disable building for arm64 --- VoodooPS2Controller.xcodeproj/project.pbxproj | 4 +++- .../xcshareddata/xcschemes/VoodooPS2Controller.xcscheme | 2 +- .../xcshareddata/xcschemes/VoodooPS2Keyboard.xcscheme | 2 +- .../xcshareddata/xcschemes/VoodooPS2Mouse.xcscheme | 2 +- .../xcshareddata/xcschemes/VoodooPS2Trackpad.xcscheme | 2 +- 5 files changed, 7 insertions(+), 5 deletions(-) diff --git a/VoodooPS2Controller.xcodeproj/project.pbxproj b/VoodooPS2Controller.xcodeproj/project.pbxproj index ede05238..ab3e6d36 100644 --- a/VoodooPS2Controller.xcodeproj/project.pbxproj +++ b/VoodooPS2Controller.xcodeproj/project.pbxproj @@ -488,7 +488,7 @@ 84167808161B55B2002C60E6 /* Project object */ = { isa = PBXProject; attributes = { - LastUpgradeCheck = 1200; + LastUpgradeCheck = 1220; ORGANIZATIONNAME = Acidanthera; }; buildConfigurationList = 8416780B161B55B2002C60E6 /* Build configuration list for PBXProject "VoodooPS2Controller" */; @@ -713,6 +713,7 @@ isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; + ARCHS = x86_64; CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; CLANG_CXX_LANGUAGE_STANDARD = "c++1y"; CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; @@ -774,6 +775,7 @@ isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; + ARCHS = x86_64; CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; CLANG_CXX_LANGUAGE_STANDARD = "c++1y"; CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; diff --git a/VoodooPS2Controller.xcodeproj/xcshareddata/xcschemes/VoodooPS2Controller.xcscheme b/VoodooPS2Controller.xcodeproj/xcshareddata/xcschemes/VoodooPS2Controller.xcscheme index 07d93519..bf3d8d13 100644 --- a/VoodooPS2Controller.xcodeproj/xcshareddata/xcschemes/VoodooPS2Controller.xcscheme +++ b/VoodooPS2Controller.xcodeproj/xcshareddata/xcschemes/VoodooPS2Controller.xcscheme @@ -1,6 +1,6 @@ Date: Wed, 2 Dec 2020 15:25:37 -0800 Subject: [PATCH 030/101] Switch to GitHub Actions (#34) --- .github/workflows/main.yml | 68 ++++++++++++++++++++++++++++++++++++++ .travis.yml | 36 -------------------- README.md | 2 +- 3 files changed, 69 insertions(+), 37 deletions(-) create mode 100644 .github/workflows/main.yml delete mode 100644 .travis.yml diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml new file mode 100644 index 00000000..dc91bddb --- /dev/null +++ b/.github/workflows/main.yml @@ -0,0 +1,68 @@ +name: CI + +on: + push: + pull_request: + workflow_dispatch: + release: + types: [published] + +env: + PROJECT_TYPE: KEXT + +jobs: + build: + name: Build + runs-on: macos-latest + env: + JOB_TYPE: BUILD + steps: + - uses: actions/checkout@v2 + - uses: actions/checkout@v2 + with: + repository: acidanthera/MacKernelSDK + path: MacKernelSDK + - name: CI Bootstrap + run: | + src=$(/usr/bin/curl -Lfs https://raw.githubusercontent.com/acidanthera/ocbuild/master/ci-bootstrap.sh) && eval "$src" || exit 1 + - name: VoodooInput Bootstrap + run: | + src=$(/usr/bin/curl -Lfs https://raw.githubusercontent.com/acidanthera/VoodooInput/master/VoodooInput/Scripts/bootstrap.sh) && eval "$src" || exit 1 + + - run: xcodebuild -jobs 1 -configuration Debug + - run: xcodebuild -jobs 1 -configuration Release + + - name: Upload to Artifacts + uses: actions/upload-artifact@v2 + with: + name: Artifacts + path: build/*/*/*.zip + - name: Upload to Release + if: github.event_name == 'release' + uses: svenstaro/upload-release-action@e74ff71f7d8a4c4745b560a485cc5fdb9b5b999d + with: + repo_token: ${{ secrets.GITHUB_TOKEN }} + file: build/*/*/*.zip + tag: ${{ github.ref }} + file_glob: true + + analyze-clang: + name: Analyze Clang + runs-on: macos-latest + env: + JOB_TYPE: ANALYZE + steps: + - uses: actions/checkout@v2 + - uses: actions/checkout@v2 + with: + repository: acidanthera/MacKernelSDK + path: MacKernelSDK + - name: CI Bootstrap + run: | + src=$(/usr/bin/curl -Lfs https://raw.githubusercontent.com/acidanthera/ocbuild/master/ci-bootstrap.sh) && eval "$src" || exit 1 + - name: VoodooInput Bootstrap + run: | + src=$(/usr/bin/curl -Lfs https://raw.githubusercontent.com/acidanthera/VoodooInput/master/VoodooInput/Scripts/bootstrap.sh) && eval "$src" || exit 1 + + - run: xcodebuild analyze -quiet -scheme VoodooPS2Controller -configuration Debug CLANG_ANALYZER_OUTPUT=plist-html CLANG_ANALYZER_OUTPUT_DIR="$(pwd)/clang-analyze" && [ "$(find clang-analyze -name "*.html")" = "" ] + - run: 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/.travis.yml b/.travis.yml deleted file mode 100644 index f8fdc47e..00000000 --- a/.travis.yml +++ /dev/null @@ -1,36 +0,0 @@ -language: cpp - -matrix: - include: - - os: osx - name: "Build" - osx_image: xcode11.6 - compiler: clang - - script: - - git clone https://github.com/acidanthera/MacKernelSDK - - src=$(/usr/bin/curl -Lfs https://raw.githubusercontent.com/acidanthera/VoodooInput/master/VoodooInput/Scripts/bootstrap.sh) && eval "$src" || exit 1 - - xcodebuild -jobs 1 -configuration Debug - - xcodebuild -jobs 1 -configuration Release - - deploy: - provider: releases - skip_cleanup: true - file: "build/*/*/*.zip" - file_glob: true - api_key: - secure: Kyxtp5f9lb+38SZBhfHuQsZB95UQ3TaSGprfCfr3enjZSQ+EHAjGj0Fek7hde6iaMG1CfdJrLItGycNPlrOafAX7ylC5WwJw2CApWXnsuJxDPju5f49P6aEmWHWitS0dYVcHp/IWBYpjacxBKNxDD9lBI9TfCd6mLvZiv15WngNyfKWz90YdY4YlgEPB3VM+XcRoYtILL1eg1Q++hlxn4fE1TEyK4pGJxrFfq0Fqvy8rQ5zYm1idk0aasC1GsS3U7L5zlZjlYs3RRnKOzSKiexLvhhcOPFsdAuQaW+IL/eofzaSEm9Slc9pCXUUlmyU5O0+hS36YPCh9cVSYv0HVVMQp+DotcbD/nKhJE5V+x+8xYRP2oIFLd15ujhJDBHWVn5QMAUu6YiGwtbLFRIUe4P8T0JkBDpUlznqZI2XzusHmpQDeDT/IzLwU1srELLqHjlS5qQQYvXrocTEgdvvUE9yMWUp7v52gk/rEm8jCH3cwYaXBwjfYC8Iy/GgoEoCYG1x6dF7BLYsv0+DYde16oEOB38Oilf++JFEK7AJb5adWjDJOwYEEIeWBhMtOKEJ5TaBiaYmlNsClM0r4CKD712cHSgHD/EDqRzVp3873R+pfSUfEfjth4vi+lVvnyqj38YCy0kTT0meVVg6M/V9c39eyTd53DiIjLowB3J3YJEk= - on: - tags: true - - - os: osx - name: "Analyze Clang" - osx_image: xcode11 - compiler: clang - - script: - - git clone https://github.com/acidanthera/MacKernelSDK - - 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/README.md b/README.md index db7b4221..68ccfd52 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ VoodooPS2 ========= -[![Build Status](https://travis-ci.com/acidanthera/VoodooPS2.svg?branch=master)](https://travis-ci.com/acidanthera/VoodooPS2) +[![Build Status](https://github.com/acidanthera/VoodooPS2/workflows/CI/badge.svg?branch=master)](https://github.com/acidanthera/VoodooPS2/actions) New **VoodooPS2Trackpad** uses VoodooInput's Magic Trackpad II emulation in order to use macOS native driver instead of handling all gestures itself. This enables the use of any from one to four finger gestures defined by Apple including: * Look up & data detectors From 346dc1f6615618ef390218f893a819fff86ed52b Mon Sep 17 00:00:00 2001 From: Vitaly Cheptsov <4348897+vit9696@users.noreply.github.com> Date: Thu, 3 Dec 2020 02:35:44 +0300 Subject: [PATCH 031/101] Add Coverity analysis --- .github/workflows/main.yml | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index dc91bddb..30238f79 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -66,3 +66,26 @@ jobs: - run: xcodebuild analyze -quiet -scheme VoodooPS2Controller -configuration Debug CLANG_ANALYZER_OUTPUT=plist-html CLANG_ANALYZER_OUTPUT_DIR="$(pwd)/clang-analyze" && [ "$(find clang-analyze -name "*.html")" = "" ] - run: xcodebuild analyze -quiet -scheme VoodooPS2Controller -configuration Release CLANG_ANALYZER_OUTPUT=plist-html CLANG_ANALYZER_OUTPUT_DIR="$(pwd)/clang-analyze" && [ "$(find clang-analyze -name "*.html")" = "" ] + + analyze-coverity: + name: Analyze Coverity + runs-on: macos-latest + env: + JOB_TYPE: COVERITY + if: github.repository_owner == 'acidanthera' && github.event_name != 'pull_request' + steps: + - uses: actions/checkout@v2 + - uses: actions/checkout@v2 + with: + repository: acidanthera/MacKernelSDK + path: MacKernelSDK + - name: CI Bootstrap + run: | + src=$(/usr/bin/curl -Lfs https://raw.githubusercontent.com/acidanthera/ocbuild/master/ci-bootstrap.sh) && eval "$src" || exit 1 + - name: Run Coverity + run: | + src=$(/usr/bin/curl -Lfs https://raw.githubusercontent.com/acidanthera/ocbuild/master/coverity/covstrap.sh) && eval "$src" || exit 1 + env: + COVERITY_SCAN_TOKEN: ${{ secrets.COVERITY_SCAN_TOKEN }} + COVERITY_SCAN_EMAIL: ${{ secrets.COVERITY_SCAN_EMAIL }} + COVERITY_BUILD_COMMAND: xcodebuild -configuration Release From 3355926c12a27a7e3ec209103b368e662cf0486a Mon Sep 17 00:00:00 2001 From: Vitaly Cheptsov <4348897+vit9696@users.noreply.github.com> Date: Thu, 3 Dec 2020 02:38:36 +0300 Subject: [PATCH 032/101] Add Coverity shield --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 68ccfd52..ef3bec9e 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ VoodooPS2 ========= -[![Build Status](https://github.com/acidanthera/VoodooPS2/workflows/CI/badge.svg?branch=master)](https://github.com/acidanthera/VoodooPS2/actions) +[![Build Status](https://github.com/acidanthera/VoodooPS2/workflows/CI/badge.svg?branch=master)](https://github.com/acidanthera/VoodooPS2/actions) [![Scan Status](https://scan.coverity.com/projects/22190/badge.svg?flat=1)](https://scan.coverity.com/projects/22190) New **VoodooPS2Trackpad** uses VoodooInput's Magic Trackpad II emulation in order to use macOS native driver instead of handling all gestures itself. This enables the use of any from one to four finger gestures defined by Apple including: * Look up & data detectors From 096f654c986d8d135c0e422eb89e582136cf5736 Mon Sep 17 00:00:00 2001 From: zhen-zen <66577170+zhen-zen@users.noreply.github.com> Date: Wed, 2 Dec 2020 15:44:30 -0800 Subject: [PATCH 033/101] Disable PrntScr remap by default (#33) --- Changelog.md | 3 +++ Docs/ACPI/SSDT-PrtSc-F13.dsl | 20 ------------------ Docs/ACPI/SSDT-PrtSc-Remap.dsl | 21 +++++++++++++++++++ VoodooPS2Controller.xcodeproj/project.pbxproj | 6 +++--- VoodooPS2Keyboard/VoodooPS2Keyboard.cpp | 16 +++++++++++++- VoodooPS2Keyboard/VoodooPS2Keyboard.h | 1 + 6 files changed, 43 insertions(+), 24 deletions(-) delete mode 100755 Docs/ACPI/SSDT-PrtSc-F13.dsl create mode 100755 Docs/ACPI/SSDT-PrtSc-Remap.dsl diff --git a/Changelog.md b/Changelog.md index 48d9223a..73a39344 100644 --- a/Changelog.md +++ b/Changelog.md @@ -1,6 +1,9 @@ VoodooPS2 Changelog ============================ +#### v2.1.9 +- Disabled PrntScr remap by default, see `SSDT-PrtSc-Remap.dsl` for example to re-enable it + #### v2.1.8 - Added support for receiving input form other kexts - Fixed dynamic coordinate refresh for ELAN v3 touchpads diff --git a/Docs/ACPI/SSDT-PrtSc-F13.dsl b/Docs/ACPI/SSDT-PrtSc-F13.dsl deleted file mode 100755 index 0b0cef0e..00000000 --- a/Docs/ACPI/SSDT-PrtSc-F13.dsl +++ /dev/null @@ -1,20 +0,0 @@ -// This sample shows how to remap the PrtSc key to F13 -// F13, for example, could then be mapped to one of the image capture functions -// via SysPrefs->Keyboard->Shortcuts -DefinitionBlock ("", "SSDT", 2, "ACDT", "ps2", 0) -{ - External (_SB_.PCI0.LPCB.PS2K, DeviceObj) - - Name(_SB.PCI0.LPCB.PS2K.RMCF, Package() - { - "Keyboard", Package() - { - "Custom PS2 Map", Package() - { - Package(){}, - "e037=64", // PrtSc=F13 - }, - }, - }) -} -//EOF diff --git a/Docs/ACPI/SSDT-PrtSc-Remap.dsl b/Docs/ACPI/SSDT-PrtSc-Remap.dsl new file mode 100755 index 00000000..3365625a --- /dev/null +++ b/Docs/ACPI/SSDT-PrtSc-Remap.dsl @@ -0,0 +1,21 @@ +// Remap PrntScr to disable touchpad/keyboard +// Supported Voodoo PrntScr Key combinations: + +// PrntScr Enable/Disable touchpad +// Windows+PrntScr Enable/Disable touchpad+keyboard +// Ctrl+Alt+PrntScr Reset and enable touchpad +// Shift+PrntScr Send SysRq scancode to the kernel + +DefinitionBlock ("", "SSDT", 2, "ACDT", "ps2", 0) +{ + External (_SB_.PCI0.LPCB.PS2K, DeviceObj) + + Name(_SB.PCI0.LPCB.PS2K.RMCF, Package() + { + "Keyboard", Package() + { + "RemapPrntScr", ">y", + }, + }) +} +//EOF diff --git a/VoodooPS2Controller.xcodeproj/project.pbxproj b/VoodooPS2Controller.xcodeproj/project.pbxproj index ab3e6d36..4263df54 100644 --- a/VoodooPS2Controller.xcodeproj/project.pbxproj +++ b/VoodooPS2Controller.xcodeproj/project.pbxproj @@ -117,8 +117,8 @@ CE7F451422E8A8F8003F7971 /* Changelog.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = Changelog.md; sourceTree = SOURCE_ROOT; }; CE7F451522E8A8FE003F7971 /* README.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = README.md; sourceTree = SOURCE_ROOT; }; CE7F451622E8A906003F7971 /* LICENSE.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = LICENSE.md; sourceTree = SOURCE_ROOT; }; - CE8DA1C4251839B2008C44E8 /* libkmod.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libkmod.a; path = ../Lilu/MacKernelSDK/Library/x86_64/libkmod.a; sourceTree = ""; }; - ED1C95C51F9B88EF00CAFCA3 /* SSDT-PrtSc-F13.dsl */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = "SSDT-PrtSc-F13.dsl"; sourceTree = ""; }; + CE8DA1C4251839B2008C44E8 /* libkmod.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libkmod.a; path = MacKernelSDK/Library/x86_64/libkmod.a; sourceTree = ""; }; + ED1C95C51F9B88EF00CAFCA3 /* SSDT-PrtSc-Remap.dsl */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = "SSDT-PrtSc-Remap.dsl"; sourceTree = ""; }; ED48777A207D94BC00D6B1E8 /* SSDT-AlternateSwipes.dsl */ = {isa = PBXFileReference; lastKnownFileType = text; path = "SSDT-AlternateSwipes.dsl"; sourceTree = ""; }; ED5759741D44FBA50069DF9F /* SSDT-KEY-DELL-WN09.dsl */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = "SSDT-KEY-DELL-WN09.dsl"; sourceTree = ""; }; ED6BB589209E4EE8007AC3A4 /* SSDT-DisableTrackpadProbe.dsl */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = "SSDT-DisableTrackpadProbe.dsl"; sourceTree = ""; }; @@ -320,7 +320,7 @@ ED7E45DF1CFB35EE00ED2FB8 /* SSDT-Enable_DynamicEWMode.dsl */, EDD970FD1FD0B826004CCFFD /* SSDT-HP-FixLidSleep.dsl */, ED5759741D44FBA50069DF9F /* SSDT-KEY-DELL-WN09.dsl */, - ED1C95C51F9B88EF00CAFCA3 /* SSDT-PrtSc-F13.dsl */, + ED1C95C51F9B88EF00CAFCA3 /* SSDT-PrtSc-Remap.dsl */, EDB891282041BB12004DB536 /* SSDT-Swap-LeftControlCapsLock.dsl */, EDAD29471FE8772400A93537 /* SSDT-Swap-LeftControlCommand.dsl */, EDD95559208E2B640031D99E /* SSDT-Thinkpad_Clickpad.dsl */, diff --git a/VoodooPS2Keyboard/VoodooPS2Keyboard.cpp b/VoodooPS2Keyboard/VoodooPS2Keyboard.cpp index dda2e254..103456a8 100644 --- a/VoodooPS2Keyboard/VoodooPS2Keyboard.cpp +++ b/VoodooPS2Keyboard/VoodooPS2Keyboard.cpp @@ -49,6 +49,7 @@ #define kHIDF12EjectDelay "HIDF12EjectDelay" #define kFunctionKeysStandard "Function Keys Standard" #define kFunctionKeysSpecial "Function Keys Special" +#define kRemapPrntScr "RemapPrntScr" #define kSwapCapsLockLeftControl "Swap capslock and left control" #define kSwapCommandOption "Swap command and option" #define kMakeApplicationKeyRightWindows "Make Application key into right windows" @@ -163,6 +164,7 @@ bool ApplePS2Keyboard::init(OSDictionary * dict) _ledState = 0; _lastdata = 0; + _remapPrntScr = false; _swapcommandoption = false; _sleepEjectTimer = 0; _cmdGate = 0; @@ -738,6 +740,12 @@ void ApplePS2Keyboard::setParamPropertiesGated(OSDictionary * dict) _brightnessHack = true; } + if ((xml = OSDynamicCast(OSBoolean, dict->getObject(kRemapPrntScr)))) + { + _remapPrntScr = xml->getValue(); + setProperty(kRemapPrntScr, _remapPrntScr); + } + // these two options are mutually exclusive // kMakeApplicationKeyAppleFN is ignored if kMakeApplicationKeyRightWindows is set bool temp = false; @@ -1523,9 +1531,12 @@ bool ApplePS2Keyboard::dispatchKeyboardEventWithPacket(const UInt8* packet) break; //REVIEW: this is getting a bit ugly - case 0x0128: // alternate that cannot fnkeys toggle (discrete trackpad toggle) case 0x0054: // SysRq (PrntScr when combined with Alt modifier -left or right-) + if (!_remapPrntScr) + break; + case 0x0128: // alternate that cannot fnkeys toggle (discrete trackpad toggle) { + // PrntScr is handled specially by some keyboard devices. // See: 5.19 on https://www.win.tue.nl/~aeb/linux/kbd/scancodes-5.html#mtek #ifdef DEBUG @@ -1544,6 +1555,9 @@ bool ApplePS2Keyboard::dispatchKeyboardEventWithPacket(const UInt8* packet) } case 0x0137: // prt sc/sys rq { + if (!_remapPrntScr) + break; + /* Supported Voodoo PrntScr Key combinations: PrntScr Enable/Disable touchpad Windows+PrntScr Enable/Disable touchpad+keyboard diff --git a/VoodooPS2Keyboard/VoodooPS2Keyboard.h b/VoodooPS2Keyboard/VoodooPS2Keyboard.h index 1c8a0f62..b7f68ab8 100644 --- a/VoodooPS2Keyboard/VoodooPS2Keyboard.h +++ b/VoodooPS2Keyboard/VoodooPS2Keyboard.h @@ -98,6 +98,7 @@ class EXPORT ApplePS2Keyboard : public IOHIKeyboard int _logscancodes; UInt32 _f12ejectdelay; enum { kTimerSleep, kTimerEject } _timerFunc; + bool _remapPrntScr; // dealing with sleep key delay IOTimerEventSource* _sleepEjectTimer; From 1052e19ffb0855a3c71ec3c1343826b6c786e700 Mon Sep 17 00:00:00 2001 From: vit9696 Date: Sun, 6 Dec 2020 04:43:16 +0300 Subject: [PATCH 034/101] Disable Command and Option swap by default closes #35 --- Changelog.md | 1 + Docs/ACPI/SSDT-Swap-CommandOption.dsl | 14 ++++++++++++++ Docs/ACPI/SSDT-Swap-LeftControlCommand.dsl | 2 +- Docs/ACPI/SSDT-Thinkpad_Trackpad.dsl | 2 +- VoodooPS2Controller.xcodeproj/project.pbxproj | 2 ++ .../VoodooPS2Keyboard-Breakless-Info.plist | 2 +- VoodooPS2Keyboard/VoodooPS2Keyboard-Info.plist | 2 +- .../VoodooPS2Keyboard-RemapFN-Info.plist | 2 +- 8 files changed, 22 insertions(+), 5 deletions(-) create mode 100755 Docs/ACPI/SSDT-Swap-CommandOption.dsl diff --git a/Changelog.md b/Changelog.md index 73a39344..aed515af 100644 --- a/Changelog.md +++ b/Changelog.md @@ -3,6 +3,7 @@ VoodooPS2 Changelog #### v2.1.9 - Disabled PrntScr remap by default, see `SSDT-PrtSc-Remap.dsl` for example to re-enable it +- Disabled Command and Option remap by default, see `SSDT-Swap-CommandOption.dsl` for example to re-enable it #### v2.1.8 - Added support for receiving input form other kexts diff --git a/Docs/ACPI/SSDT-Swap-CommandOption.dsl b/Docs/ACPI/SSDT-Swap-CommandOption.dsl new file mode 100755 index 00000000..e0fb1ced --- /dev/null +++ b/Docs/ACPI/SSDT-Swap-CommandOption.dsl @@ -0,0 +1,14 @@ +// This sample shows how to remap the Command and Option. +DefinitionBlock ("", "SSDT", 2, "ACDT", "ps2", 0) +{ + External (_SB_.PCI0.LPCB.PS2K, DeviceObj) + + Name(_SB.PCI0.LPCB.PS2K.RMCF, Package() + { + "Keyboard", Package() + { + "Swap command and option", ">y", + } + }) +} +//EOF diff --git a/Docs/ACPI/SSDT-Swap-LeftControlCommand.dsl b/Docs/ACPI/SSDT-Swap-LeftControlCommand.dsl index d523721b..560c5bec 100755 --- a/Docs/ACPI/SSDT-Swap-LeftControlCommand.dsl +++ b/Docs/ACPI/SSDT-Swap-LeftControlCommand.dsl @@ -17,4 +17,4 @@ DefinitionBlock ("", "SSDT", 2, "ACDT", "ps2", 0) }, }) } -//EOF \ No newline at end of file +//EOF diff --git a/Docs/ACPI/SSDT-Thinkpad_Trackpad.dsl b/Docs/ACPI/SSDT-Thinkpad_Trackpad.dsl index 278ef104..8f33d66e 100644 --- a/Docs/ACPI/SSDT-Thinkpad_Trackpad.dsl +++ b/Docs/ACPI/SSDT-Thinkpad_Trackpad.dsl @@ -55,4 +55,4 @@ DefinitionBlock ("", "SSDT", 2, "ACDT", "ps2", 0) }) } } -//EOF \ No newline at end of file +//EOF diff --git a/VoodooPS2Controller.xcodeproj/project.pbxproj b/VoodooPS2Controller.xcodeproj/project.pbxproj index 4263df54..b4b005b1 100644 --- a/VoodooPS2Controller.xcodeproj/project.pbxproj +++ b/VoodooPS2Controller.xcodeproj/project.pbxproj @@ -118,6 +118,7 @@ CE7F451522E8A8FE003F7971 /* README.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = README.md; sourceTree = SOURCE_ROOT; }; CE7F451622E8A906003F7971 /* LICENSE.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = LICENSE.md; sourceTree = SOURCE_ROOT; }; CE8DA1C4251839B2008C44E8 /* libkmod.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libkmod.a; path = MacKernelSDK/Library/x86_64/libkmod.a; sourceTree = ""; }; + CEA35504257C6E3500E17556 /* SSDT-Swap-CommandOption.dsl */ = {isa = PBXFileReference; lastKnownFileType = text; path = "SSDT-Swap-CommandOption.dsl"; sourceTree = ""; }; ED1C95C51F9B88EF00CAFCA3 /* SSDT-PrtSc-Remap.dsl */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = "SSDT-PrtSc-Remap.dsl"; sourceTree = ""; }; ED48777A207D94BC00D6B1E8 /* SSDT-AlternateSwipes.dsl */ = {isa = PBXFileReference; lastKnownFileType = text; path = "SSDT-AlternateSwipes.dsl"; sourceTree = ""; }; ED5759741D44FBA50069DF9F /* SSDT-KEY-DELL-WN09.dsl */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = "SSDT-KEY-DELL-WN09.dsl"; sourceTree = ""; }; @@ -321,6 +322,7 @@ EDD970FD1FD0B826004CCFFD /* SSDT-HP-FixLidSleep.dsl */, ED5759741D44FBA50069DF9F /* SSDT-KEY-DELL-WN09.dsl */, ED1C95C51F9B88EF00CAFCA3 /* SSDT-PrtSc-Remap.dsl */, + CEA35504257C6E3500E17556 /* SSDT-Swap-CommandOption.dsl */, EDB891282041BB12004DB536 /* SSDT-Swap-LeftControlCapsLock.dsl */, EDAD29471FE8772400A93537 /* SSDT-Swap-LeftControlCommand.dsl */, EDD95559208E2B640031D99E /* SSDT-Thinkpad_Clickpad.dsl */, diff --git a/VoodooPS2Keyboard/VoodooPS2Keyboard-Breakless-Info.plist b/VoodooPS2Keyboard/VoodooPS2Keyboard-Breakless-Info.plist index 3c32f874..9e6aaba2 100644 --- a/VoodooPS2Keyboard/VoodooPS2Keyboard-Breakless-Info.plist +++ b/VoodooPS2Keyboard/VoodooPS2Keyboard-Breakless-Info.plist @@ -43,7 +43,7 @@ Swap capslock and left control Swap command and option - + Use ISO layout keyboard alt_handler_id diff --git a/VoodooPS2Keyboard/VoodooPS2Keyboard-Info.plist b/VoodooPS2Keyboard/VoodooPS2Keyboard-Info.plist index 767b08ae..7e224756 100644 --- a/VoodooPS2Keyboard/VoodooPS2Keyboard-Info.plist +++ b/VoodooPS2Keyboard/VoodooPS2Keyboard-Info.plist @@ -278,7 +278,7 @@ Swap capslock and left control Swap command and option - + Use ISO layout keyboard alt_handler_id diff --git a/VoodooPS2Keyboard/VoodooPS2Keyboard-RemapFN-Info.plist b/VoodooPS2Keyboard/VoodooPS2Keyboard-RemapFN-Info.plist index 401a44b9..eb4a48d1 100644 --- a/VoodooPS2Keyboard/VoodooPS2Keyboard-RemapFN-Info.plist +++ b/VoodooPS2Keyboard/VoodooPS2Keyboard-RemapFN-Info.plist @@ -43,7 +43,7 @@ Swap capslock and left control Swap command and option - + Use ISO layout keyboard alt_handler_id From 6765507448327ade2c648de7e2eeb087d2d571cb Mon Sep 17 00:00:00 2001 From: vandroiy2013 Date: Mon, 7 Dec 2020 19:53:43 +0200 Subject: [PATCH 035/101] 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 b4b005b1..7e5bb67d 100644 --- a/VoodooPS2Controller.xcodeproj/project.pbxproj +++ b/VoodooPS2Controller.xcodeproj/project.pbxproj @@ -763,7 +763,7 @@ KERNEL_FRAMEWORK_HEADERS = "$(PROJECT_DIR)/MacKernelSDK/Headers"; "LLVM_LTO[arch=x86_64]" = YES; MACOSX_DEPLOYMENT_TARGET = 10.11; - MODULE_VERSION = 2.1.9; + MODULE_VERSION = 2.2.0; ONLY_ACTIVE_ARCH = YES; "OTHER_LDFLAGS[arch=x86_64]" = "-dead_strip"; PRODUCT_NAME = VoodooPS2Controller; @@ -818,7 +818,7 @@ KERNEL_FRAMEWORK_HEADERS = "$(PROJECT_DIR)/MacKernelSDK/Headers"; "LLVM_LTO[arch=x86_64]" = YES; MACOSX_DEPLOYMENT_TARGET = 10.11; - MODULE_VERSION = 2.1.9; + MODULE_VERSION = 2.2.0; "OTHER_LDFLAGS[arch=x86_64]" = "-dead_strip"; PRODUCT_NAME = VoodooPS2Controller; SDKROOT = macosx; From 163a76f153c34451164f16e6ee0a95647eb1d1ba Mon Sep 17 00:00:00 2001 From: Avery Black Date: Thu, 24 Dec 2020 00:08:43 -0800 Subject: [PATCH 036/101] Add interaction with SMBus driver (#36) --- VoodooPS2Controller/ApplePS2Device.h | 5 +- .../VoodooPS2SynapticsTouchPad.cpp | 51 ++++++++++++++++--- .../VoodooPS2SynapticsTouchPad.h | 5 ++ 3 files changed, 54 insertions(+), 7 deletions(-) diff --git a/VoodooPS2Controller/ApplePS2Device.h b/VoodooPS2Controller/ApplePS2Device.h index 3a986906..78c31fdf 100644 --- a/VoodooPS2Controller/ApplePS2Device.h +++ b/VoodooPS2Controller/ApplePS2Device.h @@ -528,7 +528,10 @@ enum kPS2M_notifyKeyTime = iokit_vendor_specific_msg(110), // notify of timestamp a non-modifier key was pressed (data is uint64_t*) kPS2M_resetTouchpad = iokit_vendor_specific_msg(151), // Force touchpad reset (data is int*) - + + // from trackpad on I2C/SMBus + kPS2M_SMBusStart = iokit_vendor_specific_msg(152), // Reset, disable PS2 comms to not interfere with SMBus comms + // from sensor (such as yoga mode indicator) to keyboard kPS2K_setKeyboardStatus = iokit_vendor_specific_msg(200), // set disable/enable keyboard (data is bool*) kPS2K_getKeyboardStatus = iokit_vendor_specific_msg(201), // get disable/enable keyboard (data is bool*) diff --git a/VoodooPS2Trackpad/VoodooPS2SynapticsTouchPad.cpp b/VoodooPS2Trackpad/VoodooPS2SynapticsTouchPad.cpp index aad50287..a4133cc9 100644 --- a/VoodooPS2Trackpad/VoodooPS2SynapticsTouchPad.cpp +++ b/VoodooPS2Trackpad/VoodooPS2SynapticsTouchPad.cpp @@ -334,7 +334,18 @@ void ApplePS2SynapticsTouchPad::queryCapabilities() if (getTouchPadData(0x1, buf3)) { INFO_LOG("VoodooPS2Trackpad: Mode/model($01) bytes = { 0x%x, 0x%x, 0x%x }\n", buf3[0], buf3[1], buf3[2]); + + if (_touchPadVersion >= 0x705) { + _boardID = ((buf3[0] & 0xfc) << 6) | buf3[1]; + setProperty("Board ID", _boardID, 32); + + // Check if more extended capabilities exist before querying at 0x10 + if ((buf3[0] & 0x2) && getTouchPadData(0x10, buf3)) { + trackstickButtons = buf3[0] & 0x1; + } + } } +#ifdef DEBUG_MSG if (getTouchPadData(0x2, buf3)) { INFO_LOG("VoodooPS2Trackpad: Capabilities($02) bytes = { 0x%x, 0x%x, 0x%x }\n", buf3[0], buf3[1], buf3[2]); @@ -359,7 +370,7 @@ void ApplePS2SynapticsTouchPad::queryCapabilities() { INFO_LOG("VoodooPS2Trackpad: Extended Model($09) bytes = { 0x%x, 0x%x, 0x%x }\n", buf3[0], buf3[1], buf3[2]); } - +#endif bool reportsMax = false; bool reportsMin = false; bool deluxeLeds = false; @@ -388,6 +399,12 @@ void ApplePS2SynapticsTouchPad::queryCapabilities() reportsMax = (bool)(buf3[0] & (1 << 1)); reportsMin = (bool)(buf3[1] & (1 << 5)); deluxeLeds = (bool)(buf3[1] & (1 << 1)); + + if (buf3[1] & 0x40) + { + IOLog("VoodooPS2Trackpad: Trackpad supports SMBus operation"); + setProperty("Intertouch Support", kOSBooleanTrue); + } } if (reportsMax && getTouchPadData(0xd, buf3)) { @@ -444,8 +461,14 @@ void ApplePS2SynapticsTouchPad::queryCapabilities() setProperty(VOODOO_INPUT_TRANSFORM_KEY, 0ull, 32); setProperty("VoodooInputSupported", kOSBooleanTrue); - registerService(); - + // Helpful information for SMBus drivers + OSDictionary *dictionary = OSDictionary::withCapacity(2); + dictionary->setObject("TrackstickButtons", trackstickButtons ? kOSBooleanTrue : kOSBooleanFalse); + dictionary->setObject("Clickpad", (clickpadtype & 0x1) ? kOSBooleanTrue : kOSBooleanFalse); + setProperty("GPIO Data", dictionary); + + OSSafeReleaseNULL(dictionary); + INFO_LOG("VoodooPS2Trackpad: logical %dx%d-%dx%d physical_max %dx%d upmm %dx%d", logical_min_x, logical_min_y, logical_max_x, logical_max_y, @@ -608,7 +631,7 @@ bool ApplePS2SynapticsTouchPad::start( IOService * provider ) // Update LED -- it could have been disabled then computer was restarted // updateTouchpadLED(); - + registerService(); return true; } @@ -2310,6 +2333,11 @@ IOReturn ApplePS2SynapticsTouchPad::setProperties(OSObject *props) void ApplePS2SynapticsTouchPad::setDevicePowerState( UInt32 whatToDo ) { + if (otherBusInUse) { + // SMBus/I2C is handling power management + return; + } + switch ( whatToDo ) { case kPS2C_DisableDevice: @@ -2370,7 +2398,7 @@ IOReturn ApplePS2SynapticsTouchPad::message(UInt32 type, IOService* provider, vo { bool enable = *((bool*)argument); // ignoreall is true when trackpad has been disabled - if (enable == ignoreall) + if (enable == ignoreall && !otherBusInUse) { // save state, and update LED ignoreall = !enable; @@ -2383,7 +2411,7 @@ IOReturn ApplePS2SynapticsTouchPad::message(UInt32 type, IOService* provider, vo { int* reqCode = (int*)argument; IOLog("VoodooPS2SynapticsTouchPad::kPS2M_resetTouchpad reqCode: %d\n", *reqCode); - if (*reqCode == 1) + if (*reqCode == 1 && !otherBusInUse) { ignoreall = false; initTouchPad(); @@ -2473,6 +2501,17 @@ IOReturn ApplePS2SynapticsTouchPad::message(UInt32 type, IOService* provider, vo keycode = pInfo->adbKeyCode; break; } + case kPS2M_SMBusStart: { + // Trackpad is being taken over by another driver + + // Queries/standing up before this point needs to be reset + // Fixes issues with CSM/Fast Boot on HP laptops + doHardwareReset(); + + // Prevent any PS2 transactions, otherwise the trackpad can completely lock up from PS2 commands + // This is called after ::start (specifically registerService()), so only prevent power management/reset msgs + otherBusInUse = true; + } } return kIOReturnSuccess; diff --git a/VoodooPS2Trackpad/VoodooPS2SynapticsTouchPad.h b/VoodooPS2Trackpad/VoodooPS2SynapticsTouchPad.h index a88d040a..0e156f2e 100644 --- a/VoodooPS2Trackpad/VoodooPS2SynapticsTouchPad.h +++ b/VoodooPS2Trackpad/VoodooPS2SynapticsTouchPad.h @@ -216,6 +216,7 @@ class EXPORT ApplePS2SynapticsTouchPad : public IOHIPointing UInt32 _packetByteCount {0}; UInt8 _lastdata {0}; UInt16 _touchPadVersion {0}; + UInt32 _boardID {0}; UInt8 _touchPadType {0}; // from identify: either 0x46 or 0x47 UInt8 _touchPadModeByte {0x80}; //default: absolute, low-rate, no w-mode @@ -300,12 +301,16 @@ class EXPORT ApplePS2SynapticsTouchPad : public IOHIPointing bool tracksecondary {false}; bool _extendedwmode {false}, _extendedwmodeSupported {false}; + // Capabilities for SMBus + bool trackstickButtons {false}; + // normal state UInt32 passbuttons {0}; UInt32 lastbuttons {0}; uint64_t keytime {0}; UInt16 keycode {0}; bool ignoreall {false}; + bool otherBusInUse {false}; // Trackpad being used over SMBus/I2C #ifdef SIMULATE_PASSTHRU UInt32 trackbuttons {0}; #endif From 6763f75bdc7f43a14903864cacb04e1a9bfc9aa5 Mon Sep 17 00:00:00 2001 From: Vitaly Cheptsov <4348897+vit9696@users.noreply.github.com> Date: Thu, 24 Dec 2020 11:12:49 +0300 Subject: [PATCH 037/101] Sync changelog --- Changelog.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Changelog.md b/Changelog.md index aed515af..e0de332a 100644 --- a/Changelog.md +++ b/Changelog.md @@ -1,6 +1,9 @@ VoodooPS2 Changelog ============================ +#### 2.2.0 +- Added VoodooRmi compatibility to allow external touchpad resets + #### v2.1.9 - Disabled PrntScr remap by default, see `SSDT-PrtSc-Remap.dsl` for example to re-enable it - Disabled Command and Option remap by default, see `SSDT-Swap-CommandOption.dsl` for example to re-enable it From 1afec6e1460397694a2f36f393ed560fd2f4a53a Mon Sep 17 00:00:00 2001 From: vit9696 Date: Sat, 2 Jan 2021 04:55:52 +0300 Subject: [PATCH 038/101] Provide docs for ELAN wake issues --- Docs/ACPI/SSDT-DisableElanWakeDelay.dsl | 16 ++++++++++++++++ Docs/ACPI/SSDT-Disable_DynamicEWMode.dsl | 13 ------------- Docs/ACPI/SSDT-Enable_DynamicEWMode.dsl | 13 ------------- Docs/ACPI/SSDT-Thinkpad_Clickpad.dsl | 1 - Docs/ACPI/SSDT-Thinkpad_Trackpad.dsl | 1 - VoodooPS2Controller.xcodeproj/project.pbxproj | 6 ++---- 6 files changed, 18 insertions(+), 32 deletions(-) create mode 100644 Docs/ACPI/SSDT-DisableElanWakeDelay.dsl delete mode 100644 Docs/ACPI/SSDT-Disable_DynamicEWMode.dsl delete mode 100644 Docs/ACPI/SSDT-Enable_DynamicEWMode.dsl diff --git a/Docs/ACPI/SSDT-DisableElanWakeDelay.dsl b/Docs/ACPI/SSDT-DisableElanWakeDelay.dsl new file mode 100644 index 00000000..9d5b948c --- /dev/null +++ b/Docs/ACPI/SSDT-DisableElanWakeDelay.dsl @@ -0,0 +1,16 @@ +// For some computers wake delay needs to be shorter +// for ELAN touchpad to work after wakeup. + +DefinitionBlock("", "SSDT", 2, "ACDT", "ps2", 0) +{ + External (_SB_.PCI0.LPCB.PS2K, DeviceObj) + + Name(_SB.PCI0.LPCB.PS2K.RMCF, Package() + { + "Elantech TouchPad", Package() + { + "WakeDelay", 0, + }, + }) +} +//EOF diff --git a/Docs/ACPI/SSDT-Disable_DynamicEWMode.dsl b/Docs/ACPI/SSDT-Disable_DynamicEWMode.dsl deleted file mode 100644 index bac74c44..00000000 --- a/Docs/ACPI/SSDT-Disable_DynamicEWMode.dsl +++ /dev/null @@ -1,13 +0,0 @@ -DefinitionBlock ("", "SSDT", 2, "ACDT", "ps2", 0) -{ - External (_SB_.PCI0.LPCB.PS2K, DeviceObj) - - Name(_SB.PCI0.LPCB.PS2K.RMCF, Package() - { - "Synaptics TouchPad", Package() - { - "DynamicEWMode", ">n", - }, - }) -} -//EOF diff --git a/Docs/ACPI/SSDT-Enable_DynamicEWMode.dsl b/Docs/ACPI/SSDT-Enable_DynamicEWMode.dsl deleted file mode 100644 index 4566d29a..00000000 --- a/Docs/ACPI/SSDT-Enable_DynamicEWMode.dsl +++ /dev/null @@ -1,13 +0,0 @@ -DefinitionBlock ("", "SSDT", 2, "ACDT", "ps2", 0) -{ - External (_SB_.PCI0.LPCB.PS2K, DeviceObj) - - Name(_SB.PCI0.LPCB.PS2K.RMCF, Package() - { - "Synaptics TouchPad", Package() - { - "DynamicEWMode", ">y", - }, - }) -} -//EOF diff --git a/Docs/ACPI/SSDT-Thinkpad_Clickpad.dsl b/Docs/ACPI/SSDT-Thinkpad_Clickpad.dsl index 32d26cfd..f0db949c 100644 --- a/Docs/ACPI/SSDT-Thinkpad_Clickpad.dsl +++ b/Docs/ACPI/SSDT-Thinkpad_Clickpad.dsl @@ -24,7 +24,6 @@ DefinitionBlock ("", "SSDT", 2, "ACDT", "ps2", 0) "BogusDeltaThreshY", 800, "Clicking", ">y", "DragLockTempMask", 0x40004, - "DynamicEWMode", ">n", "FakeMiddleButton", ">n", "HWResetOnStart", ">y", //"ForcePassThrough", ">y", diff --git a/Docs/ACPI/SSDT-Thinkpad_Trackpad.dsl b/Docs/ACPI/SSDT-Thinkpad_Trackpad.dsl index 8f33d66e..ab19ee76 100644 --- a/Docs/ACPI/SSDT-Thinkpad_Trackpad.dsl +++ b/Docs/ACPI/SSDT-Thinkpad_Trackpad.dsl @@ -25,7 +25,6 @@ DefinitionBlock ("", "SSDT", 2, "ACDT", "ps2", 0) "BogusDeltaThreshY", 100, "Clicking", ">y", "DragLockTempMask", 0x40004, - "DynamicEWMode", ">n", "FakeMiddleButton", ">n", "HWResetOnStart", ">y", //"ForcePassThrough", ">y", diff --git a/VoodooPS2Controller.xcodeproj/project.pbxproj b/VoodooPS2Controller.xcodeproj/project.pbxproj index 7e5bb67d..6d89aec1 100644 --- a/VoodooPS2Controller.xcodeproj/project.pbxproj +++ b/VoodooPS2Controller.xcodeproj/project.pbxproj @@ -119,12 +119,11 @@ CE7F451622E8A906003F7971 /* LICENSE.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = LICENSE.md; sourceTree = SOURCE_ROOT; }; CE8DA1C4251839B2008C44E8 /* libkmod.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libkmod.a; path = MacKernelSDK/Library/x86_64/libkmod.a; sourceTree = ""; }; CEA35504257C6E3500E17556 /* SSDT-Swap-CommandOption.dsl */ = {isa = PBXFileReference; lastKnownFileType = text; path = "SSDT-Swap-CommandOption.dsl"; sourceTree = ""; }; + CEAFF570259F8AE700693DEC /* SSDT-DisableElanWakeDelay.dsl */ = {isa = PBXFileReference; lastKnownFileType = text; path = "SSDT-DisableElanWakeDelay.dsl"; sourceTree = ""; }; ED1C95C51F9B88EF00CAFCA3 /* SSDT-PrtSc-Remap.dsl */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = "SSDT-PrtSc-Remap.dsl"; sourceTree = ""; }; ED48777A207D94BC00D6B1E8 /* SSDT-AlternateSwipes.dsl */ = {isa = PBXFileReference; lastKnownFileType = text; path = "SSDT-AlternateSwipes.dsl"; sourceTree = ""; }; ED5759741D44FBA50069DF9F /* SSDT-KEY-DELL-WN09.dsl */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = "SSDT-KEY-DELL-WN09.dsl"; sourceTree = ""; }; ED6BB589209E4EE8007AC3A4 /* SSDT-DisableTrackpadProbe.dsl */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = "SSDT-DisableTrackpadProbe.dsl"; sourceTree = ""; }; - ED7E45DF1CFB35EE00ED2FB8 /* SSDT-Enable_DynamicEWMode.dsl */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = "SSDT-Enable_DynamicEWMode.dsl"; sourceTree = ""; }; - ED7E45E01CFB35EE00ED2FB8 /* SSDT-Disable_DynamicEWMode.dsl */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = "SSDT-Disable_DynamicEWMode.dsl"; sourceTree = ""; }; EDAD29471FE8772400A93537 /* SSDT-Swap-LeftControlCommand.dsl */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = "SSDT-Swap-LeftControlCommand.dsl"; sourceTree = ""; }; EDB891282041BB12004DB536 /* SSDT-Swap-LeftControlCapsLock.dsl */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = "SSDT-Swap-LeftControlCapsLock.dsl"; sourceTree = ""; }; EDD95559208E2B640031D99E /* SSDT-Thinkpad_Clickpad.dsl */ = {isa = PBXFileReference; lastKnownFileType = text; path = "SSDT-Thinkpad_Clickpad.dsl"; sourceTree = ""; }; @@ -316,9 +315,8 @@ children = ( CE7F451122E8A8C4003F7971 /* SSDT-MouseAsTrackpad.dsl */, ED48777A207D94BC00D6B1E8 /* SSDT-AlternateSwipes.dsl */, - ED7E45E01CFB35EE00ED2FB8 /* SSDT-Disable_DynamicEWMode.dsl */, + CEAFF570259F8AE700693DEC /* SSDT-DisableElanWakeDelay.dsl */, ED6BB589209E4EE8007AC3A4 /* SSDT-DisableTrackpadProbe.dsl */, - ED7E45DF1CFB35EE00ED2FB8 /* SSDT-Enable_DynamicEWMode.dsl */, EDD970FD1FD0B826004CCFFD /* SSDT-HP-FixLidSleep.dsl */, ED5759741D44FBA50069DF9F /* SSDT-KEY-DELL-WN09.dsl */, ED1C95C51F9B88EF00CAFCA3 /* SSDT-PrtSc-Remap.dsl */, From fbd15f02c1408c5d592c5a2b14ebbbbe7c4d417c Mon Sep 17 00:00:00 2001 From: vandroiy2013 Date: Wed, 6 Jan 2021 15:19:14 +0200 Subject: [PATCH 039/101] 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 6d89aec1..db863d64 100644 --- a/VoodooPS2Controller.xcodeproj/project.pbxproj +++ b/VoodooPS2Controller.xcodeproj/project.pbxproj @@ -761,7 +761,7 @@ KERNEL_FRAMEWORK_HEADERS = "$(PROJECT_DIR)/MacKernelSDK/Headers"; "LLVM_LTO[arch=x86_64]" = YES; MACOSX_DEPLOYMENT_TARGET = 10.11; - MODULE_VERSION = 2.2.0; + MODULE_VERSION = 2.2.1; ONLY_ACTIVE_ARCH = YES; "OTHER_LDFLAGS[arch=x86_64]" = "-dead_strip"; PRODUCT_NAME = VoodooPS2Controller; @@ -816,7 +816,7 @@ KERNEL_FRAMEWORK_HEADERS = "$(PROJECT_DIR)/MacKernelSDK/Headers"; "LLVM_LTO[arch=x86_64]" = YES; MACOSX_DEPLOYMENT_TARGET = 10.11; - MODULE_VERSION = 2.2.0; + MODULE_VERSION = 2.2.1; "OTHER_LDFLAGS[arch=x86_64]" = "-dead_strip"; PRODUCT_NAME = VoodooPS2Controller; SDKROOT = macosx; From dc3571249f59d3aa0bfd867596bb7121373c8ee9 Mon Sep 17 00:00:00 2001 From: lvs1974 Date: Fri, 8 Jan 2021 12:26:26 +0100 Subject: [PATCH 040/101] fix issue with registering of services matched by property name "RM,deliverNotifications" - #1415 --- Changelog.md | 2 ++ VoodooPS2Controller/VoodooPS2Controller.cpp | 38 +++++++++++++-------- VoodooPS2Controller/VoodooPS2Controller.h | 7 ++-- 3 files changed, 30 insertions(+), 17 deletions(-) diff --git a/Changelog.md b/Changelog.md index e0de332a..e3c05d8d 100644 --- a/Changelog.md +++ b/Changelog.md @@ -1,5 +1,7 @@ VoodooPS2 Changelog ============================ +#### 2.2.1 +- Fix issue with registering of services matched by property name "RM,deliverNotifications". It solves issue with broadcasting timestamp for the last pressed key and handling of QuietTimeAfterTyping [see bug #1415](https://github.com/acidanthera/bugtracker/issues/1415) #### 2.2.0 - Added VoodooRmi compatibility to allow external touchpad resets diff --git a/VoodooPS2Controller/VoodooPS2Controller.cpp b/VoodooPS2Controller/VoodooPS2Controller.cpp index edaf3657..5a2dc300 100644 --- a/VoodooPS2Controller/VoodooPS2Controller.cpp +++ b/VoodooPS2Controller/VoodooPS2Controller.cpp @@ -603,20 +603,22 @@ bool ApplePS2Controller::start(IOService * provider) propertyMatch = propertyMatching(_deliverNotification, kOSBooleanTrue); if (propertyMatch != NULL) { - IOServiceMatchingNotificationHandler notificationHandler = OSMemberFunctionCast(IOServiceMatchingNotificationHandler, this, &ApplePS2Controller::notificationHandler); + IOServiceMatchingNotificationHandler notificationHandlerPublish = OSMemberFunctionCast(IOServiceMatchingNotificationHandler, this, &ApplePS2Controller::notificationHandlerPublish); // // Register notifications for availability of any IOService objects wanting to consume our message events // _publishNotify = addMatchingNotification(gIOFirstPublishNotification, propertyMatch, - notificationHandler, + notificationHandlerPublish, this, 0, 10000); + IOServiceMatchingNotificationHandler notificationHandlerTerminate = OSMemberFunctionCast(IOServiceMatchingNotificationHandler, this, &ApplePS2Controller::notificationHandlerTerminate); + _terminateNotify = addMatchingNotification(gIOTerminatedNotification, propertyMatch, - notificationHandler, + notificationHandlerTerminate, this, 0, 10000); @@ -1972,23 +1974,29 @@ void ApplePS2Controller::uninstallPowerControlAction( PS2DeviceType deviceType ) // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void ApplePS2Controller::notificationHandlerGated(IOService * newService, IONotifier * notifier) +void ApplePS2Controller::notificationHandlerPublishGated(IOService * newService, IONotifier * notifier) { - if (notifier == _publishNotify) { - IOLog("%s: Notification consumer published: %s\n", getName(), newService->getName()); - _notificationServices->setObject(newService); - } - - if (notifier == _terminateNotify) { - IOLog("%s: Notification consumer terminated: %s\n", getName(), newService->getName()); - _notificationServices->removeObject(newService); - } + IOLog("%s: Notification consumer published: %s\n", getName(), newService->getName()); + _notificationServices->setObject(newService); } -bool ApplePS2Controller::notificationHandler(void * refCon, IOService * newService, IONotifier * notifier) +bool ApplePS2Controller::notificationHandlerPublish(void * refCon, IOService * newService, IONotifier * notifier) { assert(_cmdGate != nullptr); - _cmdGate->runAction(OSMemberFunctionCast(IOCommandGate::Action, this, &ApplePS2Controller::notificationHandlerGated), newService, notifier); + _cmdGate->runAction(OSMemberFunctionCast(IOCommandGate::Action, this, &ApplePS2Controller::notificationHandlerPublishGated), newService, notifier); + return true; +} + +void ApplePS2Controller::notificationHandlerTerminateGated(IOService * newService, IONotifier * notifier) +{ + IOLog("%s: Notification consumer terminated: %s\n", getName(), newService->getName()); + _notificationServices->removeObject(newService); +} + +bool ApplePS2Controller::notificationHandlerTerminate(void * refCon, IOService * newService, IONotifier * notifier) +{ + assert(_cmdGate != nullptr); + _cmdGate->runAction(OSMemberFunctionCast(IOCommandGate::Action, this, &ApplePS2Controller::notificationHandlerTerminateGated), newService, notifier); return true; } diff --git a/VoodooPS2Controller/VoodooPS2Controller.h b/VoodooPS2Controller/VoodooPS2Controller.h index a388135c..90ef1fd4 100644 --- a/VoodooPS2Controller/VoodooPS2Controller.h +++ b/VoodooPS2Controller/VoodooPS2Controller.h @@ -292,8 +292,11 @@ class EXPORT ApplePS2Controller : public IOService static void interruptHandlerMouse(OSObject*, void* refCon, IOService*, int); static void interruptHandlerKeyboard(OSObject*, void* refCon, IOService*, int); - void notificationHandlerGated(IOService * newService, IONotifier * notifier); - bool notificationHandler(void * refCon, IOService * newService, IONotifier * notifier); + void notificationHandlerPublishGated(IOService * newService, IONotifier * notifier); + bool notificationHandlerPublish(void * refCon, IOService * newService, IONotifier * notifier); + + void notificationHandlerTerminateGated(IOService * newService, IONotifier * notifier); + bool notificationHandlerTerminate(void * refCon, IOService * newService, IONotifier * notifier); void dispatchMessageGated(int* message, void* data); From 552bb9b802bad7168830147320eb7cdc8da90c4e Mon Sep 17 00:00:00 2001 From: chilledHamza Date: Sun, 21 Feb 2021 00:33:06 +0500 Subject: [PATCH 041/101] Added NumLockSupport & NumLockOnAtBoot --- Docs/ACPI/SSDT-NumLockOnAtBoot.dsl | 15 +++++++++ Docs/ACPI/SSDT-NumLockSupport.dsl | 18 ++++++++++ VoodooPS2Controller.xcodeproj/project.pbxproj | 4 +++ VoodooPS2Keyboard/VoodooPS2Keyboard.cpp | 33 +++++++++++++++++++ VoodooPS2Keyboard/VoodooPS2Keyboard.h | 2 ++ 5 files changed, 72 insertions(+) create mode 100755 Docs/ACPI/SSDT-NumLockOnAtBoot.dsl create mode 100755 Docs/ACPI/SSDT-NumLockSupport.dsl diff --git a/Docs/ACPI/SSDT-NumLockOnAtBoot.dsl b/Docs/ACPI/SSDT-NumLockOnAtBoot.dsl new file mode 100755 index 00000000..d9778525 --- /dev/null +++ b/Docs/ACPI/SSDT-NumLockOnAtBoot.dsl @@ -0,0 +1,15 @@ +// Set NumLock state to ON at Bootup + +DefinitionBlock ("", "SSDT", 2, "ACDT", "ps2", 0) +{ + External (_SB_.PCI0.LPCB.PS2K, DeviceObj) + + Name(_SB.PCI0.LPCB.PS2K.RMCF, Package() + { + "Keyboard", Package() + { + "NumLockOnAtBoot", ">y", + }, + }) +} +//EOF diff --git a/Docs/ACPI/SSDT-NumLockSupport.dsl b/Docs/ACPI/SSDT-NumLockSupport.dsl new file mode 100755 index 00000000..b6cba0b5 --- /dev/null +++ b/Docs/ACPI/SSDT-NumLockSupport.dsl @@ -0,0 +1,18 @@ +// Add Support for Num Lock key +// By Default Voodoo maps Num Lock to Clear key because of the following +// 1) On USB keyboards Num Lock is translated to the Clear key +// 2) On Apple keyboards there is no Num Lock key + +DefinitionBlock ("", "SSDT", 2, "ACDT", "ps2", 0) +{ + External (_SB_.PCI0.LPCB.PS2K, DeviceObj) + + Name(_SB.PCI0.LPCB.PS2K.RMCF, Package() + { + "Keyboard", Package() + { + "NumLockSupport", ">y", + }, + }) +} +//EOF diff --git a/VoodooPS2Controller.xcodeproj/project.pbxproj b/VoodooPS2Controller.xcodeproj/project.pbxproj index db863d64..3a96e9b7 100644 --- a/VoodooPS2Controller.xcodeproj/project.pbxproj +++ b/VoodooPS2Controller.xcodeproj/project.pbxproj @@ -71,6 +71,8 @@ 356B896023007F4F0042F30F /* VoodooInputTransducer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = VoodooInputTransducer.h; path = VoodooInput/Debug/VoodooInput.kext/Contents/Resources/VoodooInputMultitouch/VoodooInputTransducer.h; sourceTree = SOURCE_ROOT; }; 356B896123007F4F0042F30F /* MultitouchHelpers.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = MultitouchHelpers.h; path = VoodooInput/Debug/VoodooInput.kext/Contents/Resources/VoodooInputMultitouch/MultitouchHelpers.h; sourceTree = SOURCE_ROOT; }; 4CC27EB2251FBC7700824FE1 /* VoodooPS2TrackpadCommon.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = VoodooPS2TrackpadCommon.h; sourceTree = ""; }; + 73119AB725E1961D0017311C /* SSDT-NumLockOnAtBoot.dsl */ = {isa = PBXFileReference; lastKnownFileType = text; path = "SSDT-NumLockOnAtBoot.dsl"; sourceTree = ""; }; + 73119AB825E1961D0017311C /* SSDT-NumLockSupport.dsl */ = {isa = PBXFileReference; lastKnownFileType = text; path = "SSDT-NumLockSupport.dsl"; sourceTree = ""; }; 7B44762421D52A7100418B25 /* ApplePS2MouseDevice.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ApplePS2MouseDevice.h; sourceTree = ""; }; 8404565C161E3AAF00D74D7F /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = ""; }; 8404565F161E3AC300D74D7F /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = ""; }; @@ -313,6 +315,8 @@ CE7F450E22E8A842003F7971 /* ACPI */ = { isa = PBXGroup; children = ( + 73119AB725E1961D0017311C /* SSDT-NumLockOnAtBoot.dsl */, + 73119AB825E1961D0017311C /* SSDT-NumLockSupport.dsl */, CE7F451122E8A8C4003F7971 /* SSDT-MouseAsTrackpad.dsl */, ED48777A207D94BC00D6B1E8 /* SSDT-AlternateSwipes.dsl */, CEAFF570259F8AE700693DEC /* SSDT-DisableElanWakeDelay.dsl */, diff --git a/VoodooPS2Keyboard/VoodooPS2Keyboard.cpp b/VoodooPS2Keyboard/VoodooPS2Keyboard.cpp index 103456a8..5847e2b4 100644 --- a/VoodooPS2Keyboard/VoodooPS2Keyboard.cpp +++ b/VoodooPS2Keyboard/VoodooPS2Keyboard.cpp @@ -50,6 +50,8 @@ #define kFunctionKeysStandard "Function Keys Standard" #define kFunctionKeysSpecial "Function Keys Special" #define kRemapPrntScr "RemapPrntScr" +#define kNumLockSupport "NumLockSupport" +#define kNumLockOnAtBoot "NumLockOnAtBoot" #define kSwapCapsLockLeftControl "Swap capslock and left control" #define kSwapCommandOption "Swap command and option" #define kMakeApplicationKeyRightWindows "Make Application key into right windows" @@ -165,6 +167,8 @@ bool ApplePS2Keyboard::init(OSDictionary * dict) _lastdata = 0; _remapPrntScr = false; + _numLockSupport = false; + _numLockOnAtBoot = false; _swapcommandoption = false; _sleepEjectTimer = 0; _cmdGate = 0; @@ -448,6 +452,13 @@ bool ApplePS2Keyboard::start(IOService * provider) // initKeyboard(); + + // + // Set NumLock State to On (if specified). + // + + if (_numLockOnAtBoot) + setNumLock(true); pWorkLoop->addEventSource(_sleepEjectTimer); pWorkLoop->addEventSource(_cmdGate); @@ -745,6 +756,18 @@ void ApplePS2Keyboard::setParamPropertiesGated(OSDictionary * dict) _remapPrntScr = xml->getValue(); setProperty(kRemapPrntScr, _remapPrntScr); } + + if ((xml = OSDynamicCast(OSBoolean, dict->getObject(kNumLockSupport)))) + { + _numLockSupport = xml->getValue(); + setProperty(kNumLockSupport, _numLockSupport); + } + + if ((xml = OSDynamicCast(OSBoolean, dict->getObject(kNumLockOnAtBoot)))) + { + _numLockOnAtBoot = xml->getValue(); + setProperty(kNumLockOnAtBoot, _numLockOnAtBoot); + } // these two options are mutually exclusive // kMakeApplicationKeyAppleFN is ignored if kMakeApplicationKeyRightWindows is set @@ -1469,6 +1492,16 @@ bool ApplePS2Keyboard::dispatchKeyboardEventWithPacket(const UInt8* packet) // handle special cases switch (keyCode) { + case 0x45: // NumLock + if (_numLockSupport && (scanCode == 0xc5)) // NumLock -> Up + { + setNumLock(!numLock()); + return true; + } + else if (_numLockSupport && (scanCode == 0x45)) // NumLock -> Down + return false; + break; + case 0x4e: // Numpad+ case 0x4a: // Numpad- if (_backlightLevels && checkModifierState(kMaskLeftControl|kMaskLeftAlt)) diff --git a/VoodooPS2Keyboard/VoodooPS2Keyboard.h b/VoodooPS2Keyboard/VoodooPS2Keyboard.h index b7f68ab8..4e8e6142 100644 --- a/VoodooPS2Keyboard/VoodooPS2Keyboard.h +++ b/VoodooPS2Keyboard/VoodooPS2Keyboard.h @@ -99,6 +99,8 @@ class EXPORT ApplePS2Keyboard : public IOHIKeyboard UInt32 _f12ejectdelay; enum { kTimerSleep, kTimerEject } _timerFunc; bool _remapPrntScr; + bool _numLockSupport; + bool _numLockOnAtBoot; // dealing with sleep key delay IOTimerEventSource* _sleepEjectTimer; From 7c5cf7b38bf00bdb704f4785cad78a274b5c1e4e Mon Sep 17 00:00:00 2001 From: Andrey1970AppleLife Date: Thu, 25 Feb 2021 15:12:42 +0300 Subject: [PATCH 042/101] Bump version --- Changelog.md | 3 +++ VoodooPS2Controller.xcodeproj/project.pbxproj | 4 ++-- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/Changelog.md b/Changelog.md index e3c05d8d..cc4ab256 100644 --- a/Changelog.md +++ b/Changelog.md @@ -1,5 +1,8 @@ VoodooPS2 Changelog ============================ +#### 2.2.2 +- Added NumLockSupport & NumLockOnAtBoot + #### 2.2.1 - Fix issue with registering of services matched by property name "RM,deliverNotifications". It solves issue with broadcasting timestamp for the last pressed key and handling of QuietTimeAfterTyping [see bug #1415](https://github.com/acidanthera/bugtracker/issues/1415) diff --git a/VoodooPS2Controller.xcodeproj/project.pbxproj b/VoodooPS2Controller.xcodeproj/project.pbxproj index 3a96e9b7..80edfae6 100644 --- a/VoodooPS2Controller.xcodeproj/project.pbxproj +++ b/VoodooPS2Controller.xcodeproj/project.pbxproj @@ -765,7 +765,7 @@ KERNEL_FRAMEWORK_HEADERS = "$(PROJECT_DIR)/MacKernelSDK/Headers"; "LLVM_LTO[arch=x86_64]" = YES; MACOSX_DEPLOYMENT_TARGET = 10.11; - MODULE_VERSION = 2.2.1; + MODULE_VERSION = 2.2.2; ONLY_ACTIVE_ARCH = YES; "OTHER_LDFLAGS[arch=x86_64]" = "-dead_strip"; PRODUCT_NAME = VoodooPS2Controller; @@ -820,7 +820,7 @@ KERNEL_FRAMEWORK_HEADERS = "$(PROJECT_DIR)/MacKernelSDK/Headers"; "LLVM_LTO[arch=x86_64]" = YES; MACOSX_DEPLOYMENT_TARGET = 10.11; - MODULE_VERSION = 2.2.1; + MODULE_VERSION = 2.2.2; "OTHER_LDFLAGS[arch=x86_64]" = "-dead_strip"; PRODUCT_NAME = VoodooPS2Controller; SDKROOT = macosx; From ab49b27d22b0de72677bdb44bd0e304d6495afde Mon Sep 17 00:00:00 2001 From: Andrey1970AppleLife Date: Tue, 2 Mar 2021 17:44:28 +0300 Subject: [PATCH 043/101] 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 80edfae6..e274926e 100644 --- a/VoodooPS2Controller.xcodeproj/project.pbxproj +++ b/VoodooPS2Controller.xcodeproj/project.pbxproj @@ -765,7 +765,7 @@ KERNEL_FRAMEWORK_HEADERS = "$(PROJECT_DIR)/MacKernelSDK/Headers"; "LLVM_LTO[arch=x86_64]" = YES; MACOSX_DEPLOYMENT_TARGET = 10.11; - MODULE_VERSION = 2.2.2; + MODULE_VERSION = 2.2.3; ONLY_ACTIVE_ARCH = YES; "OTHER_LDFLAGS[arch=x86_64]" = "-dead_strip"; PRODUCT_NAME = VoodooPS2Controller; @@ -820,7 +820,7 @@ KERNEL_FRAMEWORK_HEADERS = "$(PROJECT_DIR)/MacKernelSDK/Headers"; "LLVM_LTO[arch=x86_64]" = YES; MACOSX_DEPLOYMENT_TARGET = 10.11; - MODULE_VERSION = 2.2.2; + MODULE_VERSION = 2.2.3; "OTHER_LDFLAGS[arch=x86_64]" = "-dead_strip"; PRODUCT_NAME = VoodooPS2Controller; SDKROOT = macosx; From 69c29bcf19f629df30a345bc5117c552c3b7f3ed Mon Sep 17 00:00:00 2001 From: vit9696 Date: Thu, 22 Apr 2021 15:57:20 +0300 Subject: [PATCH 044/101] Added `DisableDeepSleep` to workaround ACPI S3 wakes on some Synaptics touchpads closes acidanthera/bugtracker#1610 --- Changelog.md | 9 ++++++--- Docs/ACPI/SSDT-DisableDeepSleep.dsl | 17 +++++++++++++++++ VoodooPS2Controller.xcodeproj/project.pbxproj | 4 +++- .../xcschemes/VoodooPS2Controller.xcscheme | 2 +- .../xcschemes/VoodooPS2Keyboard.xcscheme | 2 +- .../xcschemes/VoodooPS2Mouse.xcscheme | 2 +- .../xcschemes/VoodooPS2Trackpad.xcscheme | 2 +- .../VoodooPS2SynapticsTouchPad.cpp | 16 +++++++++++----- VoodooPS2Trackpad/VoodooPS2SynapticsTouchPad.h | 10 ++++++---- 9 files changed, 47 insertions(+), 17 deletions(-) create mode 100644 Docs/ACPI/SSDT-DisableDeepSleep.dsl diff --git a/Changelog.md b/Changelog.md index cc4ab256..35290a92 100644 --- a/Changelog.md +++ b/Changelog.md @@ -1,12 +1,15 @@ VoodooPS2 Changelog ============================ -#### 2.2.2 +#### v2.2.3 +- Added `DisableDeepSleep` to workaround ACPI S3 wakes on some Synaptics touchpads + +#### v2.2.2 - Added NumLockSupport & NumLockOnAtBoot -#### 2.2.1 +#### v2.2.1 - Fix issue with registering of services matched by property name "RM,deliverNotifications". It solves issue with broadcasting timestamp for the last pressed key and handling of QuietTimeAfterTyping [see bug #1415](https://github.com/acidanthera/bugtracker/issues/1415) -#### 2.2.0 +#### v2.2.0 - Added VoodooRmi compatibility to allow external touchpad resets #### v2.1.9 diff --git a/Docs/ACPI/SSDT-DisableDeepSleep.dsl b/Docs/ACPI/SSDT-DisableDeepSleep.dsl new file mode 100644 index 00000000..f61dbe63 --- /dev/null +++ b/Docs/ACPI/SSDT-DisableDeepSleep.dsl @@ -0,0 +1,17 @@ +// For computers with Synaptics touchpad that wake immediately after +// going to sleep deeper touchpad sleep can be disabled. +// +// This will cause the touchpad to consume more power in ACPI S3. +DefinitionBlock("", "SSDT", 2, "ACDT", "ps2", 0) +{ + External (_SB_.PCI0.LPCB.PS2K, DeviceObj) + + Name(_SB.PCI0.LPCB.PS2K.RMCF, Package() + { + "Synaptics TouchPad", Package() + { + "DisableDeepSleep", ">y", + } + }) +} +//EOF diff --git a/VoodooPS2Controller.xcodeproj/project.pbxproj b/VoodooPS2Controller.xcodeproj/project.pbxproj index e274926e..66cc5112 100644 --- a/VoodooPS2Controller.xcodeproj/project.pbxproj +++ b/VoodooPS2Controller.xcodeproj/project.pbxproj @@ -122,6 +122,7 @@ CE8DA1C4251839B2008C44E8 /* libkmod.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libkmod.a; path = MacKernelSDK/Library/x86_64/libkmod.a; sourceTree = ""; }; CEA35504257C6E3500E17556 /* SSDT-Swap-CommandOption.dsl */ = {isa = PBXFileReference; lastKnownFileType = text; path = "SSDT-Swap-CommandOption.dsl"; sourceTree = ""; }; CEAFF570259F8AE700693DEC /* SSDT-DisableElanWakeDelay.dsl */ = {isa = PBXFileReference; lastKnownFileType = text; path = "SSDT-DisableElanWakeDelay.dsl"; sourceTree = ""; }; + CEF251412631A92B00A20C9A /* SSDT-DisableDeepSleep.dsl */ = {isa = PBXFileReference; lastKnownFileType = text; path = "SSDT-DisableDeepSleep.dsl"; sourceTree = ""; }; ED1C95C51F9B88EF00CAFCA3 /* SSDT-PrtSc-Remap.dsl */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = "SSDT-PrtSc-Remap.dsl"; sourceTree = ""; }; ED48777A207D94BC00D6B1E8 /* SSDT-AlternateSwipes.dsl */ = {isa = PBXFileReference; lastKnownFileType = text; path = "SSDT-AlternateSwipes.dsl"; sourceTree = ""; }; ED5759741D44FBA50069DF9F /* SSDT-KEY-DELL-WN09.dsl */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = "SSDT-KEY-DELL-WN09.dsl"; sourceTree = ""; }; @@ -319,6 +320,7 @@ 73119AB825E1961D0017311C /* SSDT-NumLockSupport.dsl */, CE7F451122E8A8C4003F7971 /* SSDT-MouseAsTrackpad.dsl */, ED48777A207D94BC00D6B1E8 /* SSDT-AlternateSwipes.dsl */, + CEF251412631A92B00A20C9A /* SSDT-DisableDeepSleep.dsl */, CEAFF570259F8AE700693DEC /* SSDT-DisableElanWakeDelay.dsl */, ED6BB589209E4EE8007AC3A4 /* SSDT-DisableTrackpadProbe.dsl */, EDD970FD1FD0B826004CCFFD /* SSDT-HP-FixLidSleep.dsl */, @@ -492,7 +494,7 @@ 84167808161B55B2002C60E6 /* Project object */ = { isa = PBXProject; attributes = { - LastUpgradeCheck = 1220; + LastUpgradeCheck = 1240; ORGANIZATIONNAME = Acidanthera; }; buildConfigurationList = 8416780B161B55B2002C60E6 /* Build configuration list for PBXProject "VoodooPS2Controller" */; diff --git a/VoodooPS2Controller.xcodeproj/xcshareddata/xcschemes/VoodooPS2Controller.xcscheme b/VoodooPS2Controller.xcodeproj/xcshareddata/xcschemes/VoodooPS2Controller.xcscheme index bf3d8d13..860a7f87 100644 --- a/VoodooPS2Controller.xcodeproj/xcshareddata/xcschemes/VoodooPS2Controller.xcscheme +++ b/VoodooPS2Controller.xcodeproj/xcshareddata/xcschemes/VoodooPS2Controller.xcscheme @@ -1,6 +1,6 @@ Date: Mon, 3 May 2021 22:09:06 +0300 Subject: [PATCH 045/101] 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 66cc5112..9449a1f5 100644 --- a/VoodooPS2Controller.xcodeproj/project.pbxproj +++ b/VoodooPS2Controller.xcodeproj/project.pbxproj @@ -767,7 +767,7 @@ KERNEL_FRAMEWORK_HEADERS = "$(PROJECT_DIR)/MacKernelSDK/Headers"; "LLVM_LTO[arch=x86_64]" = YES; MACOSX_DEPLOYMENT_TARGET = 10.11; - MODULE_VERSION = 2.2.3; + MODULE_VERSION = 2.2.4; ONLY_ACTIVE_ARCH = YES; "OTHER_LDFLAGS[arch=x86_64]" = "-dead_strip"; PRODUCT_NAME = VoodooPS2Controller; @@ -822,7 +822,7 @@ KERNEL_FRAMEWORK_HEADERS = "$(PROJECT_DIR)/MacKernelSDK/Headers"; "LLVM_LTO[arch=x86_64]" = YES; MACOSX_DEPLOYMENT_TARGET = 10.11; - MODULE_VERSION = 2.2.3; + MODULE_VERSION = 2.2.4; "OTHER_LDFLAGS[arch=x86_64]" = "-dead_strip"; PRODUCT_NAME = VoodooPS2Controller; SDKROOT = macosx; From f0c7fda3fec51150f77f3cbd9a1e452118a8e8d9 Mon Sep 17 00:00:00 2001 From: Goldfish64 Date: Mon, 14 Jun 2021 17:12:09 -0500 Subject: [PATCH 046/101] Fix incorrect command gate init in VoodooPS2Trackpad --- Changelog.md | 3 +++ VoodooPS2Trackpad/VoodooPS2SynapticsTouchPad.cpp | 4 ++-- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/Changelog.md b/Changelog.md index 35290a92..4f0c6bfb 100644 --- a/Changelog.md +++ b/Changelog.md @@ -1,5 +1,8 @@ VoodooPS2 Changelog ============================ +#### v2.2.4 +- Fixed incorrect command gate initialization causing panics + #### v2.2.3 - Added `DisableDeepSleep` to workaround ACPI S3 wakes on some Synaptics touchpads diff --git a/VoodooPS2Trackpad/VoodooPS2SynapticsTouchPad.cpp b/VoodooPS2Trackpad/VoodooPS2SynapticsTouchPad.cpp index 064e065c..685a16b6 100644 --- a/VoodooPS2Trackpad/VoodooPS2SynapticsTouchPad.cpp +++ b/VoodooPS2Trackpad/VoodooPS2SynapticsTouchPad.cpp @@ -545,6 +545,8 @@ bool ApplePS2SynapticsTouchPad::start( IOService * provider ) _device = nullptr; return false; } + + pWorkLoop->addEventSource(_cmdGate); // // Lock the controller during initialization @@ -579,8 +581,6 @@ bool ApplePS2SynapticsTouchPad::start( IOService * provider ) pWorkLoop->addEventSource(_buttonTimer); } - pWorkLoop->addEventSource(_cmdGate); - // // Query the touchpad for the capabilities we need to know. // From b5bb1a0fca9de819bdd79710726ae83a37571d55 Mon Sep 17 00:00:00 2001 From: Andrey1970AppleLife Date: Tue, 6 Jul 2021 00:58:29 +0300 Subject: [PATCH 047/101] 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 9449a1f5..191679c4 100644 --- a/VoodooPS2Controller.xcodeproj/project.pbxproj +++ b/VoodooPS2Controller.xcodeproj/project.pbxproj @@ -767,7 +767,7 @@ KERNEL_FRAMEWORK_HEADERS = "$(PROJECT_DIR)/MacKernelSDK/Headers"; "LLVM_LTO[arch=x86_64]" = YES; MACOSX_DEPLOYMENT_TARGET = 10.11; - MODULE_VERSION = 2.2.4; + MODULE_VERSION = 2.2.5; ONLY_ACTIVE_ARCH = YES; "OTHER_LDFLAGS[arch=x86_64]" = "-dead_strip"; PRODUCT_NAME = VoodooPS2Controller; @@ -822,7 +822,7 @@ KERNEL_FRAMEWORK_HEADERS = "$(PROJECT_DIR)/MacKernelSDK/Headers"; "LLVM_LTO[arch=x86_64]" = YES; MACOSX_DEPLOYMENT_TARGET = 10.11; - MODULE_VERSION = 2.2.4; + MODULE_VERSION = 2.2.5; "OTHER_LDFLAGS[arch=x86_64]" = "-dead_strip"; PRODUCT_NAME = VoodooPS2Controller; SDKROOT = macosx; From a41ad20864f21937762e59db7098a52ac2daa5a1 Mon Sep 17 00:00:00 2001 From: Avery Black Date: Thu, 19 Aug 2021 23:27:08 -0700 Subject: [PATCH 048/101] Add multiplexing support (#38) --- VoodooPS2Controller.xcodeproj/project.pbxproj | 4 +- VoodooPS2Controller/AppleACPIPS2Nub.cpp | 6 + VoodooPS2Controller/AppleACPIPS2Nub.h | 1 + VoodooPS2Controller/ApplePS2Device.cpp | 102 ++- VoodooPS2Controller/ApplePS2Device.h | 43 +- .../ApplePS2KeyboardDevice.cpp | 10 - VoodooPS2Controller/ApplePS2KeyboardDevice.h | 3 - VoodooPS2Controller/ApplePS2MouseDevice.cpp | 10 - VoodooPS2Controller/ApplePS2MouseDevice.h | 3 - VoodooPS2Controller/VoodooPS2Controller.cpp | 690 +++++++++--------- VoodooPS2Controller/VoodooPS2Controller.h | 95 +-- VoodooPS2Mouse/VoodooPS2Mouse.cpp | 216 +++--- VoodooPS2Mouse/VoodooPS2Mouse.h | 10 +- VoodooPS2Trackpad/VoodooPS2ALPSGlidePoint.cpp | 76 +- VoodooPS2Trackpad/VoodooPS2Elan.cpp | 22 +- VoodooPS2Trackpad/VoodooPS2SentelicFSP.cpp | 76 +- .../VoodooPS2SynapticsTouchPad.cpp | 63 +- 17 files changed, 730 insertions(+), 700 deletions(-) diff --git a/VoodooPS2Controller.xcodeproj/project.pbxproj b/VoodooPS2Controller.xcodeproj/project.pbxproj index 191679c4..ad5d1890 100644 --- a/VoodooPS2Controller.xcodeproj/project.pbxproj +++ b/VoodooPS2Controller.xcodeproj/project.pbxproj @@ -81,8 +81,8 @@ 840F104916EFE42600E8C116 /* ApplePS2Device.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ApplePS2Device.cpp; sourceTree = ""; }; 84167813161B55B2002C60E6 /* VoodooPS2Controller.kext */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = VoodooPS2Controller.kext; sourceTree = BUILT_PRODUCTS_DIR; }; 8416781A161B55B2002C60E6 /* VoodooPS2Controller-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "VoodooPS2Controller-Info.plist"; sourceTree = ""; }; - 8416781E161B55B2002C60E6 /* VoodooPS2Controller.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; lineEnding = 0; path = VoodooPS2Controller.h; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.objcpp; }; - 8416781F161B55B2002C60E6 /* VoodooPS2Controller.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; lineEnding = 0; path = VoodooPS2Controller.cpp; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.cpp; }; + 8416781E161B55B2002C60E6 /* VoodooPS2Controller.h */ = {isa = PBXFileReference; indentWidth = 2; lastKnownFileType = sourcecode.c.h; lineEnding = 0; path = VoodooPS2Controller.h; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.objcpp; }; + 8416781F161B55B2002C60E6 /* VoodooPS2Controller.cpp */ = {isa = PBXFileReference; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; lineEnding = 0; path = VoodooPS2Controller.cpp; sourceTree = ""; tabWidth = 4; xcLanguageSpecificationIdentifier = xcode.lang.cpp; }; 8416782D161B5613002C60E6 /* VoodooPS2Keyboard.kext */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = VoodooPS2Keyboard.kext; sourceTree = BUILT_PRODUCTS_DIR; }; 84167830161B5613002C60E6 /* VoodooPS2Keyboard-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "VoodooPS2Keyboard-Info.plist"; sourceTree = ""; }; 84167834161B5613002C60E6 /* VoodooPS2Keyboard.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = VoodooPS2Keyboard.h; sourceTree = ""; }; diff --git a/VoodooPS2Controller/AppleACPIPS2Nub.cpp b/VoodooPS2Controller/AppleACPIPS2Nub.cpp index 8aef97b4..a6e345c3 100644 --- a/VoodooPS2Controller/AppleACPIPS2Nub.cpp +++ b/VoodooPS2Controller/AppleACPIPS2Nub.cpp @@ -106,6 +106,12 @@ bool AppleACPIPS2Nub::start(IOService *provider) return true; } +void AppleACPIPS2Nub::stop(IOService *provider) +{ + PMstop(); + return super::stop(provider); +} + IOService *AppleACPIPS2Nub::findMouseDevice() { OSObject *prop = getProperty("MouseNameMatch"); diff --git a/VoodooPS2Controller/AppleACPIPS2Nub.h b/VoodooPS2Controller/AppleACPIPS2Nub.h index 75b18be0..53d96609 100644 --- a/VoodooPS2Controller/AppleACPIPS2Nub.h +++ b/VoodooPS2Controller/AppleACPIPS2Nub.h @@ -86,6 +86,7 @@ class EXPORT AppleACPIPS2Nub: public IOPlatformDevice public: bool start(IOService *provider) override; + void stop(IOService *provider) override; /*! @method findMouseDevice @abstract Locates the mouse nub in the IORegistry diff --git a/VoodooPS2Controller/ApplePS2Device.cpp b/VoodooPS2Controller/ApplePS2Device.cpp index 775b44ef..9f935d63 100644 --- a/VoodooPS2Controller/ApplePS2Device.cpp +++ b/VoodooPS2Controller/ApplePS2Device.cpp @@ -29,11 +29,37 @@ OSDefineMetaClassAndStructors(ApplePS2Device, IOService); // ApplePS2Device Class Implementation // +bool ApplePS2Device::init(size_t port) +{ + _port = port; + return super::init(); +} + bool ApplePS2Device::attach(IOService * provider) { if (!super::attach(provider)) return false; + _workloop = IOWorkLoop::workLoop(); + _interruptSource = IOInterruptEventSource::interruptEventSource(this, + OSMemberFunctionCast(IOInterruptEventAction, this, &ApplePS2Device::packetAction)); + + if (!_interruptSource || !_workloop) + { + OSSafeReleaseNULL(_workloop); + OSSafeReleaseNULL(_interruptSource); + return false; + } + + if (_workloop->addEventSource(_interruptSource) != kIOReturnSuccess) + { + OSSafeReleaseNULL(_workloop); + OSSafeReleaseNULL(_interruptSource); + return false; + } + + setProperty(kPortKey, _port, 8); + assert(_controller == 0); _controller = (ApplePS2Controller*)provider; _controller->retain(); @@ -49,6 +75,14 @@ void ApplePS2Device::detach( IOService * provider ) _controller->release(); _controller = 0; + if (_interruptSource && _workloop) + { + _workloop->removeEventSource(_interruptSource); + } + + OSSafeReleaseNULL(_interruptSource); + OSSafeReleaseNULL(_workloop); + super::detach(provider); } @@ -70,6 +104,7 @@ void ApplePS2Device::freeRequest(PS2Request * request) bool ApplePS2Device::submitRequest(PS2Request * request) { + request->port = _port; return _controller->submitRequest(request); } @@ -77,6 +112,7 @@ bool ApplePS2Device::submitRequest(PS2Request * request) void ApplePS2Device::submitRequestAndBlock(PS2Request * request) { + request->port = _port; _controller->submitRequestAndBlock(request); } @@ -102,33 +138,38 @@ void ApplePS2Device::unlock() // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void ApplePS2Device::installInterruptAction(OSObject * target, - PS2InterruptAction interruptAction, - PS2PacketAction packetAction) + PS2InterruptAction interruptAction, + PS2PacketAction packetAction) { - _controller->installInterruptAction(_deviceType, target, interruptAction, packetAction); + _client = target; + _controller->installInterruptAction(_port); + _interrupt_action = interruptAction; + _packet_action = packetAction; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void ApplePS2Device::uninstallInterruptAction() { - _controller->uninstallInterruptAction(_deviceType); + _controller->uninstallInterruptAction(_port); + _interrupt_action = nullptr; + _packet_action = nullptr; + _client = nullptr; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void ApplePS2Device::installPowerControlAction( - OSObject * target, - PS2PowerControlAction action) +void ApplePS2Device::installPowerControlAction(OSObject * target, + PS2PowerControlAction action) { - _controller->installPowerControlAction(_deviceType, target, action); + _power_action = action; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void ApplePS2Device::uninstallPowerControlAction() { - _controller->uninstallPowerControlAction(_deviceType); + _power_action = nullptr; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -144,3 +185,46 @@ ApplePS2Controller* ApplePS2Device::getController() { return _controller; } + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + +PS2InterruptResult ApplePS2Device::interruptAction(UInt8 data) +{ + if (_client == nullptr || _interrupt_action == nullptr) + { + return kPS2IR_packetBuffering; + } + + return (*_interrupt_action)(_client, data); +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + +void ApplePS2Device::packetActionInterrupt() +{ + _interruptSource->interruptOccurred(0, 0, 0); +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + +void ApplePS2Device::powerAction(UInt32 whatToDo) +{ + if (_client == nullptr || _power_action == nullptr) + { + return; + } + + (*_power_action)(_client, whatToDo); +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + +void ApplePS2Device::packetAction(IOInterruptEventSource *, int) +{ + if (_client == nullptr || _packet_action == nullptr) + { + return; + } + + (*_packet_action)(_client); +} diff --git a/VoodooPS2Controller/ApplePS2Device.h b/VoodooPS2Controller/ApplePS2Device.h index 78c31fdf..607847ee 100644 --- a/VoodooPS2Controller/ApplePS2Device.h +++ b/VoodooPS2Controller/ApplePS2Device.h @@ -27,6 +27,7 @@ #include #include #include +#include #include #ifdef DEBUG_MSG @@ -81,6 +82,7 @@ #define kCP_ReadControllerRAMBase 0x21 // #define kCP_SetCommandByte 0x60 // (keyboard+mouse) #define kCP_WriteControllerRAMBase 0x61 // +#define kCP_TransmitToMuxedMouse 0x90 // (muxed mouse) #define kCP_TestPassword 0xA4 // #define kCP_GetPassword 0xA5 // #define kCP_VerifyPassword 0xA6 // @@ -266,20 +268,13 @@ class RingBuffer // o Description: Writes the byte in the In Field to the data port (60h). // o In Field: Holds byte that should be written. // -// o kPS2C_WriteCommandPort: -// o Description: Writes the byte in the In Field to the command port (64h). -// o In Field: Holds byte that should be written. -// enum PS2CommandEnum { kPS2C_ReadDataPort, kPS2C_ReadDataPortAndCompare, kPS2C_WriteDataPort, - kPS2C_WriteCommandPort, - kPS2C_SendMouseCommandAndCompareAck, - kPS2C_ReadMouseDataPort, - kPS2C_ReadMouseDataPortAndCompare, + kPS2C_SendCommandAndCompareAck, kPS2C_FlushDataPort, kPS2C_SleepMS, kPS2C_ModifyCommandByte, @@ -411,6 +406,7 @@ struct PS2Request { ::operator delete(p); } public: + size_t port; UInt8 commandsCount; void * completionTarget; PS2CompletionAction completionAction; @@ -516,6 +512,9 @@ typedef void (*PS2PowerControlAction)(void * target, UInt32 whatToDo); // Published property for devices to express interest in receiving messages #define kDeliverNotifications "RM,deliverNotifications" +// Published property for device nub port location +#define kPortKey "Port Num" + typedef void (*PS2MessageAction)(void* target, int message, void* data); enum @@ -559,17 +558,6 @@ enum kPS2C_EnableDevice }; -// PS/2 device types. - -typedef enum -{ - kDT_Keyboard, - kDT_Mouse, -#if WATCHDOG_TIMER - kDT_Watchdog, -#endif -} PS2DeviceType; - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // ApplePS2Device Class Declaration // @@ -583,9 +571,10 @@ class EXPORT ApplePS2Device : public IOService protected: ApplePS2Controller* _controller; - PS2DeviceType _deviceType; + size_t _port; public: + bool init(size_t port); bool attach(IOService * provider) override; void detach(IOService * provider) override; @@ -606,6 +595,11 @@ class EXPORT ApplePS2Device : public IOService virtual void installPowerControlAction(OSObject *, PS2PowerControlAction); virtual void uninstallPowerControlAction(); + + virtual PS2InterruptResult interruptAction(UInt8); + virtual void packetActionInterrupt(); + void packetAction(IOInterruptEventSource *, int); + virtual void powerAction(UInt32); // Messaging virtual void dispatchMessage(int message, void *data); @@ -617,6 +611,15 @@ class EXPORT ApplePS2Device : public IOService // Controller access virtual ApplePS2Controller* getController(); +private: + PS2InterruptAction _interrupt_action {nullptr}; + PS2PacketAction _packet_action {nullptr}; + PS2PowerControlAction _power_action {nullptr}; + + IOWorkLoop * _workloop {nullptr}; + IOInterruptEventSource * _interruptSource {nullptr}; + + OSObject* _client {nullptr}; }; #if 0 // Note: Now using architecture/i386/pio.h (see above) diff --git a/VoodooPS2Controller/ApplePS2KeyboardDevice.cpp b/VoodooPS2Controller/ApplePS2KeyboardDevice.cpp index 6ea687b1..f6eba164 100644 --- a/VoodooPS2Controller/ApplePS2KeyboardDevice.cpp +++ b/VoodooPS2Controller/ApplePS2KeyboardDevice.cpp @@ -28,13 +28,3 @@ // OSDefineMetaClassAndStructors(ApplePS2KeyboardDevice, ApplePS2Device); - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -bool ApplePS2KeyboardDevice::init() -{ - bool result = super::init(); - _deviceType = kDT_Keyboard; - return result; -} - diff --git a/VoodooPS2Controller/ApplePS2KeyboardDevice.h b/VoodooPS2Controller/ApplePS2KeyboardDevice.h index 9f9435f8..6f206218 100644 --- a/VoodooPS2Controller/ApplePS2KeyboardDevice.h +++ b/VoodooPS2Controller/ApplePS2KeyboardDevice.h @@ -31,9 +31,6 @@ class EXPORT ApplePS2KeyboardDevice : public ApplePS2Device { typedef ApplePS2Device super; OSDeclareDefaultStructors(ApplePS2KeyboardDevice); - -public: - bool init() override; }; #endif /* !_APPLEPS2KEYBOARDDEVICE_H */ diff --git a/VoodooPS2Controller/ApplePS2MouseDevice.cpp b/VoodooPS2Controller/ApplePS2MouseDevice.cpp index b9fb5f28..3892629b 100644 --- a/VoodooPS2Controller/ApplePS2MouseDevice.cpp +++ b/VoodooPS2Controller/ApplePS2MouseDevice.cpp @@ -28,13 +28,3 @@ // OSDefineMetaClassAndStructors(ApplePS2MouseDevice, ApplePS2Device); - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -bool ApplePS2MouseDevice::init() -{ - bool result = super::init(); - _deviceType = kDT_Mouse; - return result; -} - diff --git a/VoodooPS2Controller/ApplePS2MouseDevice.h b/VoodooPS2Controller/ApplePS2MouseDevice.h index 0af67d37..4594e8bd 100644 --- a/VoodooPS2Controller/ApplePS2MouseDevice.h +++ b/VoodooPS2Controller/ApplePS2MouseDevice.h @@ -31,9 +31,6 @@ class EXPORT ApplePS2MouseDevice : public ApplePS2Device { typedef ApplePS2Device super; OSDeclareDefaultStructors(ApplePS2MouseDevice); - -public: - bool init() override; }; #endif /* !_APPLEPS2MOUSEDEVICE_H */ diff --git a/VoodooPS2Controller/VoodooPS2Controller.cpp b/VoodooPS2Controller/VoodooPS2Controller.cpp index 5a2dc300..10490714 100644 --- a/VoodooPS2Controller/VoodooPS2Controller.cpp +++ b/VoodooPS2Controller/VoodooPS2Controller.cpp @@ -61,7 +61,7 @@ void ApplePS2Controller::interruptHandlerMouse(OSObject*, void* refCon, IOServic #if HANDLE_INTERRUPT_DATA_LATER me->_interruptSourceMouse->interruptOccurred(0, 0, 0); #else - me->handleInterrupt(kDT_Mouse); + me->handleInterrupt(); #endif } @@ -135,7 +135,7 @@ void ApplePS2Controller::interruptHandlerKeyboard(OSObject*, void* refCon, IOSer #if HANDLE_INTERRUPT_DATA_LATER me->_interruptSourceKeyboard->interruptOccurred(0, 0, 0); #else - me->handleInterrupt(kDT_Keyboard); + me->handleInterrupt(); #endif #endif //DEBUGGER_SUPPORT @@ -148,7 +148,7 @@ void ApplePS2Controller::interruptHandlerKeyboard(OSObject*, void* refCon, IOSer void ApplePS2Controller::onWatchdogTimer() { if (!_ignoreInterrupts) - handleInterrupt(kDT_Watchdog); + handleInterrupt(true); _watchdogTimer->setTimeoutMS(kWatchdogTimerInterval); } @@ -158,20 +158,19 @@ void ApplePS2Controller::onWatchdogTimer() #if !HANDLE_INTERRUPT_DATA_LATER -void ApplePS2Controller::handleInterrupt(PS2DeviceType deviceType) +void ApplePS2Controller::handleInterrupt(bool watchdog) { - ////IOLog("%s:handleInterrupt(%s)\n", getName(), deviceType == kDT_Keyboard ? "kDT_Keyboard" : deviceType == kDT_Watchdog ? "kDT_Watchdog" : "kDT_Mouse"); - // Loop only while there is data currently on the input stream. - - bool wakeMouse = false; - bool wakeKeyboard = false; + bool wakePort[kPS2MaxIdx] {}; + while (1) { // while getting status and reading the port, no interrupts... bool enable = ml_set_interrupts_enabled(false); + size_t port = kPS2KbdIdx; IODelay(kDataDelay); UInt8 status = inb(kCommandPort); + if (!(status & kOutputReady)) { // no data available, so break out and return @@ -181,13 +180,13 @@ void ApplePS2Controller::handleInterrupt(PS2DeviceType deviceType) #if WATCHDOG_TIMER // do not process mouse data in watchdog timer - if (deviceType == kDT_Watchdog && (status & kMouseData)) + if (watchdog && (status & kMouseData)) { ml_set_interrupts_enabled(enable); break; } #endif - + // read the data IODelay(kDataDelay); UInt8 data = inb(kDataPort); @@ -195,59 +194,59 @@ void ApplePS2Controller::handleInterrupt(PS2DeviceType deviceType) // now ok for interrupts, we have read status, and found data... // (it does not matter [too much] if keyboard data is delivered out of order) ml_set_interrupts_enabled(enable); - + #if WATCHDOG_TIMER //REVIEW: remove this debug eventually... - if (deviceType == kDT_Watchdog) - IOLog("%s:handleInterrupt(kDT_Watchdog): %s = %02x\n", getName(), status & kMouseData ? "mouse" : "keyboard", data); + if (watchdog) + IOLog("%s:handleInterrupt(kDT_Watchdog): %s = %02x\n", getName(), port > kPS2KbdIdx ? "mouse" : "keyboard", data); #endif - if (status & kMouseData) + + port = getPortFromStatus(status); + if (port >= kPS2MaxIdx || _devices[port] == nullptr) { - // Dispatch the data to the mouse driver. - if (kPS2IR_packetReady == _dispatchDriverInterrupt(kDT_Mouse, data)) - wakeMouse = true; + continue; } - else + + if (kPS2IR_packetReady == _dispatchDriverInterrupt(port, data)) { - // Dispatch the data to the keyboard driver. - if (kPS2IR_packetReady == _dispatchDriverInterrupt(kDT_Keyboard, data)) - wakeKeyboard = true; + wakePort[port] = true; } } // while (forever) // wake up workloop based mouse interrupt source if needed - if (wakeMouse) - _interruptSourceMouse->interruptOccurred(0, 0, 0); - // wake up workloop based keyboard interrupt source if needed - if (wakeKeyboard) - _interruptSourceKeyboard->interruptOccurred(0, 0, 0); + size_t max_idx = _mux_present ? kPS2MaxIdx : kPS2MuxIdx; + for (size_t i = kPS2KbdIdx; i < max_idx; i++) { + if (wakePort[i] && _devices[i] != nullptr) + { + _devices[i]->packetActionInterrupt(); + } + } } #else // HANDLE_INTERRUPT_DATA_LATER -void ApplePS2Controller::handleInterrupt(PS2DeviceType deviceType) +void ApplePS2Controller::handleInterrupt(bool watchdog) { - ////IOLog("%s:handleInterrupt(%s)\n", getName(), deviceType == kDT_Keyboard ? "kDT_Keyboard" : deviceType == kDT_Watchdog ? "kDT_Watchdog" : "kDT_Mouse"); - // Loop only while there is data currently on the input stream. UInt8 status; + size_t port; IODelay(kDataDelay); while ((status = inb(kCommandPort)) & kOutputReady) { #if WATCHDOG_TIMER - if (deviceType == kDT_Watchdog && (status & kMouseData)) + if (watchdog && (status & kMouseData)) break; #endif - IODelay(kDataDelay); UInt8 data = inb(kDataPort); + port = getPortFromStatus(status); #if WATCHDOG_TIMER //REVIEW: remove this debug eventually... - if (deviceType == kDT_Watchdog) - IOLog("%s:handleInterrupt(kDT_Watchdog): %s = %02x\n", getName(), status & kMouseData ? "mouse" : "keyboard", data); + if (watchdog) + IOLog("%s:handleInterrupt(kDT_Watchdog): %s = %02x\n", getName(), port > kPS2KbdIdx ? "mouse" : "keyboard", data); #endif - dispatchDriverInterrupt(status & kMouseData ? kDT_Mouse : kDT_Keyboard, data); + dispatchDriverInterrupt(port, data); IODelay(kDataDelay); } } @@ -395,18 +394,18 @@ void ApplePS2Controller::resetController(void) writeCommandPort(kCP_EnableKeyboardClock); // Read current command writeCommandPort(kCP_GetCommandByte); - commandByte = readDataPort(kDT_Keyboard); + commandByte = readDataPort(kPS2KbdIdx); DEBUG_LOG("%s: initial commandByte = %02x\n", getName(), commandByte); // Issue Test Controller to try to reset device writeCommandPort(kCP_TestController); - readDataPort(kDT_Keyboard); - readDataPort(kDT_Mouse); + readDataPort(kPS2KbdIdx); + readDataPort(kPS2AuxIdx); // Issue Test Keyboard Port to try to reset device writeCommandPort(kCP_TestKeyboardPort); - readDataPort(kDT_Keyboard); + readDataPort(kPS2KbdIdx); // Issue Test Mouse Port to try to reset device writeCommandPort(kCP_TestMousePort); - readDataPort(kDT_Mouse); + readDataPort(kPS2AuxIdx); _suppressTimeout = false; // @@ -417,18 +416,30 @@ void ApplePS2Controller::resetController(void) // port routines directly, since no other thread will conflict with us. // commandByte &= ~(kCB_EnableKeyboardIRQ | kCB_EnableMouseIRQ | kCB_DisableMouseClock | kCB_DisableMouseClock); - ////commandByte |= kCB_EnableKeyboardIRQ | kCB_EnableMouseIRQ; commandByte |= kCB_TranslateMode; writeCommandPort(kCP_SetCommandByte); writeDataPort(commandByte); DEBUG_LOG("%s: new commandByte = %02x\n", getName(), commandByte); writeDataPort(kDP_SetDefaultsAndDisable); - readDataPort(kDT_Keyboard); // (discard acknowledge; success irrelevant) + readDataPort(kPS2KbdIdx); // (discard acknowledge; success irrelevant) - writeCommandPort(kCP_TransmitToMouse); - writeDataPort(kDP_SetDefaultsAndDisable); - readDataPort(kDT_Mouse); // (discard acknowledge; success irrelevant) + if (hasMux()) + { + _mux_present = true; + for (size_t i = 0; i < PS2_MUX_PORTS; i++) + { + writeCommandPort(kCP_TransmitToMuxedMouse + i); + writeDataPort(kDP_SetDefaultsAndDisable); + readDataPort(kPS2MuxIdx + i); // (discard acknowledge; success irrelevant) + } + } + else + { + writeCommandPort(kCP_TransmitToMouse); + writeDataPort(kDP_SetDefaultsAndDisable); + readDataPort(kPS2AuxIdx); // (discard acknowledge; success irrelevant) + } // // Clear out garbage in the controller's input streams, before starting up @@ -445,6 +456,34 @@ void ApplePS2Controller::resetController(void) // -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +bool ApplePS2Controller::hasMux() +{ + writeCommandPort(kCP_WriteMouseOutputBuffer); + writeDataPort(kDP_EnableMuxCmd1); + if (readDataPort(kPS2AuxIdx) != kDP_EnableMuxCmd1) + return false; + writeCommandPort(kCP_WriteMouseOutputBuffer); + writeDataPort(kDP_EnableMuxCmd2); + if (readDataPort(kPS2AuxIdx) != kDP_EnableMuxCmd2) + return false; + writeCommandPort(kCP_WriteMouseOutputBuffer); + writeDataPort(kDP_GetMuxVersion); + UInt8 ver = readDataPort(kPS2AuxIdx); + if (ver == kDP_GetMuxVersion) + { + return false; + } + + // Only log first time + if (!_mux_present) + { + IOLog("ApplePS2Controller::hasMux = true - version: %x\n", ver); + } + return true; +} + +// -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + bool ApplePS2Controller::start(IOService * provider) { DEBUG_LOG("ApplePS2Controller::start entered...\n"); @@ -471,16 +510,6 @@ bool ApplePS2Controller::start(IOService * provider) queue_enter(&_keyboardQueueUnused, &_keyboardQueueAlloc[index], KeyboardQueueElement *, chain); #endif //DEBUGGER_SUPPORT - // Note: I don't think this newIRQLayout thing is used at all - // -- our provider is PS2Nub and the PS2 nub we use does not set this flag - // -- in addition it only supports the LEGACY interrupt specifiers - // #ifdef to eliminate for now... -#ifdef NEWIRQ - if (provider->getProperty("newIRQLayout")) { // turbo - IOLog("Using new IRQ layout 0,1\n"); - _newIRQLayout = true; - } -#endif // // Reset and clean the 8042 keyboard/mouse controller. @@ -502,44 +531,48 @@ bool ApplePS2Controller::start(IOService * provider) // Initialize our work loop, our command gate, and our interrupt event // sources. The work loop can accept requests after this step. // + - _workLoop = IOWorkLoop::workLoop(); + _workLoop = IOWorkLoop::workLoop(); + _cmdGate = IOCommandGate::commandGate(this); + _interruptSourceQueue = IOInterruptEventSource::interruptEventSource( this, + OSMemberFunctionCast(IOInterruptEventAction, this, &ApplePS2Controller::processRequestQueue)); + + + if ( !_workLoop || + !_interruptSourceQueue || + !_cmdGate) goto fail; + #if HANDLE_INTERRUPT_DATA_LATER _interruptSourceMouse = IOInterruptEventSource::interruptEventSource( this, - OSMemberFunctionCast(IOInterruptEventAction, this, &ApplePS2Controller::interruptOccurred)); - _interruptSourceKeyboard = IOInterruptEventSource::interruptEventSource( this, OSMemberFunctionCast(IOInterruptEventAction, this, &ApplePS2Controller::interruptOccurred)); -#else - _interruptSourceMouse = IOInterruptEventSource::interruptEventSource( this, - OSMemberFunctionCast(IOInterruptEventAction, this, &ApplePS2Controller::packetReadyMouse)); _interruptSourceKeyboard = IOInterruptEventSource::interruptEventSource( this, - OSMemberFunctionCast(IOInterruptEventAction, this, &ApplePS2Controller::packetReadyKeyboard)); -#endif - _interruptSourceQueue = IOInterruptEventSource::interruptEventSource( this, - OSMemberFunctionCast(IOInterruptEventAction, this, &ApplePS2Controller::processRequestQueue)); - _cmdGate = IOCommandGate::commandGate(this); -#if WATCHDOG_TIMER - _watchdogTimer = IOTimerEventSource::timerEventSource(this, OSMemberFunctionCast(IOTimerEventSource::Action, this, &ApplePS2Controller::onWatchdogTimer)); - if (!_watchdogTimer) + OSMemberFunctionCast(IOInterruptEventAction, this, &ApplePS2Controller::interruptOccurred)); + + if ( !_interruptSourceMouse || + !_interruptSourceKeyboard) goto fail; + + if ( _workLoop->addEventSource(_interruptSourceMouse) != kIOReturnSuccess ) + goto fail; + if ( _workLoop->addEventSource(_interruptSourceKeyboard) != kIOReturnSuccess ) goto fail; #endif - - if ( !_workLoop || - !_interruptSourceMouse || - !_interruptSourceKeyboard || - !_interruptSourceQueue || - !_cmdGate) goto fail; if ( _workLoop->addEventSource(_interruptSourceQueue) != kIOReturnSuccess ) goto fail; if ( _workLoop->addEventSource(_cmdGate) != kIOReturnSuccess ) goto fail; - + #if WATCHDOG_TIMER + _watchdogTimer = IOTimerEventSource::timerEventSource(this, OSMemberFunctionCast(IOTimerEventSource::Action, this, &ApplePS2Controller::onWatchdogTimer)); + if (!_watchdogTimer) + goto fail; + if ( _workLoop->addEventSource(_watchdogTimer) != kIOReturnSuccess ) goto fail; _watchdogTimer->setTimeoutMS(kWatchdogTimerInterval); #endif + _interruptSourceQueue->enable(); // @@ -575,30 +608,51 @@ bool ApplePS2Controller::start(IOService * provider) // will query these nubs to determine the existence of the keyboard or mouse, // and should they exist, will attach themselves to the nub as clients. // - - _keyboardDevice = OSTypeAlloc(ApplePS2KeyboardDevice); - if ( !_keyboardDevice || - !_keyboardDevice->init() || - !_keyboardDevice->attach(this) ) + + _devices[kPS2KbdIdx] = OSTypeAlloc(ApplePS2KeyboardDevice); + if ( !_devices[kPS2KbdIdx] || + !_devices[kPS2KbdIdx]->init(kPS2KbdIdx) || + !_devices[kPS2KbdIdx]->attach(this) ) { - OSSafeReleaseNULL(_keyboardDevice); - OSSafeReleaseNULL(_interruptSourceKeyboard); + OSSafeReleaseNULL(_devices[kPS2KbdIdx]); + goto fail; } - - _mouseDevice = OSTypeAlloc(ApplePS2MouseDevice); - if ( !_mouseDevice || - !_mouseDevice->init() || - !_mouseDevice->attach(this) ) + + + if (_mux_present) { - OSSafeReleaseNULL(_mouseDevice); - OSSafeReleaseNULL(_interruptSourceMouse); + for (size_t i = kPS2MuxIdx; i < kPS2MaxIdx; i++) + { + _devices[i] = OSTypeAlloc(ApplePS2MouseDevice); + if ( !_devices[i] || + !_devices[i]->init(i) || + !_devices[i]->attach(this) ) + { + OSSafeReleaseNULL(_devices[i]); + goto fail; + } + } } - - if (_keyboardDevice) - _keyboardDevice->registerService(); - if (_mouseDevice) - _mouseDevice->registerService(); - + else + { + _devices[kPS2AuxIdx] = OSTypeAlloc(ApplePS2MouseDevice); + if ( !_devices[kPS2AuxIdx] || + !_devices[kPS2AuxIdx]->init(kPS2AuxIdx) || + !_devices[kPS2AuxIdx]->attach(this) ) + { + OSSafeReleaseNULL(_devices[kPS2AuxIdx]); + goto fail; + } + } + + for (size_t i = kPS2KbdIdx; i < kPS2MaxIdx; i++) + { + if (_devices[i]) + { + _devices[i]->registerService(); + } + } + registerService(); propertyMatch = propertyMatching(_deliverNotification, kOSBooleanTrue); @@ -648,8 +702,6 @@ void ApplePS2Controller::stop(IOService * provider) // Ensure that the interrupt handlers have been uninstalled (ie. no clients). assert(!_interruptInstalledKeyboard); assert(!_interruptInstalledMouse); - assert(!_powerControlInstalledKeyboard); - assert(!_powerControlInstalledMouse); // Free device matching notifiers // remove() releases them @@ -660,18 +712,23 @@ void ApplePS2Controller::stop(IOService * provider) OSSafeReleaseNULL(_notificationServices); // Free the nubs we created. - OSSafeReleaseNULL(_keyboardDevice); - OSSafeReleaseNULL(_mouseDevice); + for (size_t i = 0; i < kPS2MaxIdx; i++) { + OSSafeReleaseNULL(_devices[i]); + } - // Free the event/interrupt sources. - OSSafeReleaseNULL(_interruptSourceKeyboard); - OSSafeReleaseNULL(_interruptSourceMouse); + // Free the event/interrupt sources OSSafeReleaseNULL(_interruptSourceQueue); OSSafeReleaseNULL(_cmdGate); + +#if HANDLE_INTERRUPT_DATA_LATER + OSSafeReleaseNULL(_interruptSourceMouse); + OSSafeReleaseNULL(_interruptSourceKeyboard); +#endif + #if WATCHDOG_TIMER - OSSafeReleaseNULL(_watchdogTimer); + OSSafeReleaseNULL(_watchdogTimer); #endif - + // Free the work loop. OSSafeReleaseNULL(_workLoop); @@ -719,10 +776,18 @@ IOWorkLoop * ApplePS2Controller::getWorkLoop() const // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void ApplePS2Controller::installInterruptAction(PS2DeviceType deviceType, - OSObject * target, - PS2InterruptAction interruptAction, - PS2PacketAction packetAction) +void ApplePS2Controller::enableMuxPorts() +{ + for (size_t i = 0; i < PS2_MUX_PORTS; i++) + { + writeCommandPort(kCP_TransmitToMuxedMouse + i); + writeCommandPort(kCP_EnableMouseClock); + } +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + +void ApplePS2Controller::installInterruptAction(size_t port) { // // Install the keyboard or mouse interrupt handler. @@ -734,58 +799,42 @@ void ApplePS2Controller::installInterruptAction(PS2DeviceType deviceType, // Is it the keyboard or the mouse interrupt handler that was requested? // We only install it if it is currently uninstalled. - - if (deviceType == kDT_Keyboard && !_interruptInstalledKeyboard && _interruptSourceKeyboard) + + if (port == kPS2KbdIdx && !_interruptInstalledKeyboard) { - target->retain(); - _interruptTargetKeyboard = target; - _interruptActionKeyboard = interruptAction; - _packetActionKeyboard = packetAction; - _workLoop->addEventSource(_interruptSourceKeyboard); DEBUG_LOG("%s: setCommandByte for keyboard interrupt install\n", getName()); setCommandByte(kCB_EnableKeyboardIRQ, 0); -#ifdef NEWIRQ - if (_newIRQLayout) - { // turbo - getProvider()->registerInterrupt(0,0, interruptHandlerKeyboard, this); - getProvider()->enableInterrupt(0); - } else -#endif - { - getProvider()->registerInterrupt(kIRQ_Keyboard,0, interruptHandlerKeyboard, this); - getProvider()->enableInterrupt(kIRQ_Keyboard); - } + + getProvider()->registerInterrupt(kIRQ_Keyboard,0, interruptHandlerKeyboard, this); + getProvider()->enableInterrupt(kIRQ_Keyboard); _interruptInstalledKeyboard = true; } - else if (deviceType == kDT_Mouse && !_interruptInstalledMouse && _interruptSourceMouse) + else if (port > kPS2KbdIdx) { - target->retain(); - _interruptTargetMouse = target; - _interruptActionMouse = interruptAction; - _packetActionMouse = packetAction; - _workLoop->addEventSource(_interruptSourceMouse); - DEBUG_LOG("%s: setCommandByte for mouse interrupt install\n", getName()); - setCommandByte(kCB_EnableMouseIRQ, 0); -#ifdef NEWIRQ - if (_newIRQLayout) - { // turbo - getProvider()->registerInterrupt(1, 0, interruptHandlerMouse, this); - getProvider()->enableInterrupt(1); - } else -#endif + // Only enable interrupts for the first mouse, as this interrupt is used for all of them + if (!_interruptInstalledMouse) { - getProvider()->registerInterrupt(kIRQ_Mouse, 0, interruptHandlerMouse, this); - getProvider()->enableInterrupt(kIRQ_Mouse); + DEBUG_LOG("%s: setCommandByte for mouse interrupt install\n", getName()); + if (_mux_present) + { + enableMuxPorts(); + } + + setCommandByte(kCB_EnableMouseIRQ, 0); + + getProvider()->registerInterrupt(kIRQ_Mouse, 0, interruptHandlerMouse, this); + getProvider()->enableInterrupt(kIRQ_Mouse); } - - _interruptInstalledMouse = true; + + // Record number of mouses with interrupts + _interruptInstalledMouse++; } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void ApplePS2Controller::uninstallInterruptAction(PS2DeviceType deviceType) +void ApplePS2Controller::uninstallInterruptAction(size_t port) { // // Uninstall the keyboard or mouse interrupt handler. @@ -798,40 +847,26 @@ void ApplePS2Controller::uninstallInterruptAction(PS2DeviceType deviceType) // Is it the keyboard or the mouse interrupt handler that was requested? // We only uninstall it if it is currently installed. - if (deviceType == kDT_Keyboard && _interruptInstalledKeyboard) + if (port == kPS2KbdIdx && _interruptInstalledKeyboard) { setCommandByte(0, kCB_EnableKeyboardIRQ); -#ifdef NEWIRQ - getProvider()->disableInterrupt(0); - getProvider()->unregisterInterrupt(0); -#else getProvider()->disableInterrupt(kIRQ_Keyboard); getProvider()->unregisterInterrupt(kIRQ_Keyboard); -#endif - _workLoop->removeEventSource(_interruptSourceKeyboard); _interruptInstalledKeyboard = false; - _interruptActionKeyboard = NULL; - _packetActionKeyboard = NULL; - _interruptTargetKeyboard->release(); - _interruptTargetKeyboard = 0; } - else if (deviceType == kDT_Mouse && _interruptInstalledMouse) + else if (port > kPS2KbdIdx) { - setCommandByte(0, kCB_EnableMouseIRQ); -#ifdef NEWIRQ - getProvider()->disableInterrupt(1); - getProvider()->unregisterInterrupt(1); -#else - getProvider()->disableInterrupt(kIRQ_Mouse); - getProvider()->unregisterInterrupt(kIRQ_Mouse); -#endif - _workLoop->removeEventSource(_interruptSourceMouse); - _interruptInstalledMouse = false; - _interruptActionMouse = NULL; - _packetActionMouse = NULL; - _interruptTargetMouse->release(); - _interruptTargetMouse = 0; + assert(_interruptInstalledMouse > 0); + _interruptInstalledMouse--; + + // Only uninstall interrupt once we have no mice installed + if (_interruptInstalledMouse == 0) { + setCommandByte(0, kCB_EnableMouseIRQ); + getProvider()->disableInterrupt(kIRQ_Mouse); + getProvider()->unregisterInterrupt(kIRQ_Mouse); + } + } } @@ -895,7 +930,7 @@ void ApplePS2Controller::setCommandByteGated(PS2Request* request) UInt8 clearBits = request->commands[0].clearBits; ++_ignoreInterrupts; writeCommandPort(kCP_GetCommandByte); - UInt8 oldCommandByte = readDataPort(kDT_Keyboard); + UInt8 oldCommandByte = readDataPort(kPS2KbdIdx); --_ignoreInterrupts; DEBUG_LOG("%s: oldCommandByte = %02x\n", getName(), oldCommandByte); UInt8 newCommandByte = (oldCommandByte | setBits) & ~clearBits; @@ -912,10 +947,18 @@ void ApplePS2Controller::setCommandByteGated(PS2Request* request) bool ApplePS2Controller::submitRequest(PS2Request * request) { + // Make sure that the request is in bounds + if (request->port >= kPS2MaxIdx || request->port < kPS2KbdIdx) + return false; + + // Check that we only read from ports which are active in mux mode + if ((_mux_present && request->port == kPS2AuxIdx) || + (!_mux_present && request->port > kPS2AuxIdx)) + return false; + // // Submit the request to the controller for processing, asynchronously. // - IOLockLock(_requestQueueLock); queue_enter(&_requestQueue, request, PS2Request *, chain); IOLockUnlock(_requestQueueLock); @@ -929,6 +972,15 @@ bool ApplePS2Controller::submitRequest(PS2Request * request) void ApplePS2Controller::submitRequestAndBlock(PS2Request * request) { + // Make sure that the request is in bounds + if (request->port >= kPS2MaxIdx || request->port < kPS2KbdIdx) + return; + + // Check that we only read from ports which are active in mux mode + if ((_mux_present && request->port == kPS2AuxIdx) || + (!_mux_present && request->port > kPS2AuxIdx)) + return; + _cmdGate->runAction(OSMemberFunctionCast(IOCommandGate::Action, this, &ApplePS2Controller::submitRequestAndBlockGated), request); } @@ -973,80 +1025,61 @@ void ApplePS2Controller::interruptOccurred(IOInterruptEventSource* source, int) if (dequeueKeyboardData(&status)) { unlockController(state); - dispatchDriverInterrupt(kDT_Keyboard, status); + dispatchDriverInterrupt(kPS2KbdIdx, status); lockController(&state); + continue; } // See if data is available on the mouse input stream (off real port). - else if ( (inb(kCommandPort) & (kOutputReady | kMouseData)) == - (kOutputReady | kMouseData)) + status = inb(kCommandPort); + if ( ( status & (kOutputReady | kMouseData)) != + (kOutputReady | kMouseData)) { - unlockController(state); - IODelay(kDataDelay); - dispatchDriverInterrupt(kDT_Mouse, inb(kDataPort)); - lockController(&state); + break; // out of loop } - else break; // out of loop + + unlockController(state); + IODelay(kDataDelay); + size_t port = getPortFromStatus(status); + dispatchDriverInterrupt(port, inb(kDataPort)); + lockController(&state); } unlockController(state); // (release interrupt lockout + access to queue) #else - handleInterrupt(source == _interruptSourceKeyboard ? kDT_Keyboard : kDT_Mouse); + handleInterrupt(); #endif // DEBUGGER_SUPPORT } #endif // HANDLE_INTERRUPT_DATA_LATER -#if !HANDLE_INTERRUPT_DATA_LATER -void ApplePS2Controller::packetReadyKeyboard(IOInterruptEventSource *, int) -{ - // a complete packet has arrived for the keyboard and has signaled the workloop - // -- dispatch it to the installed keyboard packet handler - if (_interruptInstalledKeyboard) - (*_packetActionKeyboard)(_interruptTargetKeyboard); -} - -void ApplePS2Controller::packetReadyMouse(IOInterruptEventSource *, int) -{ - // a complete packet has arrived for the mouse and has signaled the workloop - // -- dispatch it to the installed mouse packet handler - if (_interruptInstalledMouse) - (*_packetActionMouse)(_interruptTargetMouse); -} -#endif // !HANDLE_INTERRUPT_DATA_LATER - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -PS2InterruptResult ApplePS2Controller::_dispatchDriverInterrupt(PS2DeviceType deviceType, UInt8 data) +PS2InterruptResult ApplePS2Controller::_dispatchDriverInterrupt(size_t port, UInt8 data) { PS2InterruptResult result = kPS2IR_packetBuffering; - if (kDT_Mouse == deviceType && _interruptInstalledMouse) + + if (port >= kPS2AuxIdx && _interruptInstalledMouse) { // Dispatch the data to the mouse driver. - result = (*_interruptActionMouse)(_interruptTargetMouse, data); + result = _devices[port]->interruptAction(data); } - else if (kDT_Keyboard == deviceType && _interruptInstalledKeyboard) + else if (kPS2KbdIdx == port && _interruptInstalledKeyboard) { // Dispatch the data to the keyboard driver. - result = (*_interruptActionKeyboard)(_interruptTargetKeyboard, data); + result = _devices[kPS2KbdIdx]->interruptAction(data); } return result; } -void ApplePS2Controller::dispatchDriverInterrupt(PS2DeviceType deviceType, UInt8 data) +void ApplePS2Controller::dispatchDriverInterrupt(size_t port, UInt8 data) { - PS2InterruptResult result = _dispatchDriverInterrupt(deviceType, data); + PS2InterruptResult result = _dispatchDriverInterrupt(port, data); if (kPS2IR_packetReady == result) { #if HANDLE_INTERRUPT_DATA_LATER - if (kDT_Mouse == deviceType) - (*_packetActionMouse)(_interruptTargetMouse); - else if (kDT_Keyboard == deviceType) - (*_packetActionKeyboard)(_interruptTargetKeyboard); + _devices[port]->packetAction(nullptr, 0); #else - if (kDT_Mouse == deviceType) - _interruptSourceMouse->interruptOccurred(0, 0, 0); - else if (kDT_Keyboard == deviceType) - _interruptSourceKeyboard->interruptOccurred(0, 0, 0); + _devices[port]->packetActionInterrupt(); #endif } } @@ -1064,9 +1097,8 @@ void ApplePS2Controller::processRequest(PS2Request * request) // UInt8 byte; - PS2DeviceType deviceMode = kDT_Keyboard; + size_t devicePort = request->port; bool failed = false; - bool transmitToMouse = false; unsigned index; if (_hardwareOffline) @@ -1088,74 +1120,53 @@ void ApplePS2Controller::processRequest(PS2Request * request) switch (request->commands[index].command) { case kPS2C_ReadDataPort: - request->commands[index].inOrOut = readDataPort(deviceMode); + request->commands[index].inOrOut = readDataPort(devicePort); break; case kPS2C_ReadDataPortAndCompare: #if OUT_OF_ORDER_DATA_CORRECTION_FEATURE - byte = readDataPort(deviceMode, request->commands[index].inOrOut); + byte = readDataPort(devicePort, request->commands[index].inOrOut); #else - byte = readDataPort(deviceMode); + byte = readDataPort(devicePort); #endif failed = (byte != request->commands[index].inOrOut); request->commands[index].inOrOut = byte; break; case kPS2C_WriteDataPort: - writeDataPort(request->commands[index].inOrOut); - if (transmitToMouse) // next reads from mouse input stream - { - deviceMode = kDT_Mouse; - transmitToMouse = false; + if (devicePort == kPS2AuxIdx) { + writeCommandPort(kCP_TransmitToMouse); + } else if (devicePort > kPS2AuxIdx) { + writeCommandPort(kCP_TransmitToMuxedMouse + (devicePort - kPS2MuxIdx)); } - else - { - deviceMode = kDT_Keyboard; - } - break; - - case kPS2C_WriteCommandPort: - writeCommandPort(request->commands[index].inOrOut); - if (request->commands[index].inOrOut == kCP_TransmitToMouse) - transmitToMouse = true; // preparing to transmit data to mouse + + writeDataPort(request->commands[index].inOrOut); break; // // Send a composite mouse command that is equivalent to the following // (frequently used) command sequence: // - // 1. kPS2C_WriteCommandPort( kCP_TransmitToMouse ) - // 2. kPS2C_WriteDataPort( command ) - // 3. kPS2C_ReadDataPortAndCompare( kSC_Acknowledge ) + // 1. kPS2C_WriteDataPort( command ) + // 2. kPS2C_ReadDataPortAndCompare( kSC_Acknowledge ) // - case kPS2C_SendMouseCommandAndCompareAck: - writeCommandPort(kCP_TransmitToMouse); + case kPS2C_SendCommandAndCompareAck: + if (devicePort == kPS2AuxIdx) { + writeCommandPort(kCP_TransmitToMouse); + } else if (devicePort > kPS2AuxIdx) { + writeCommandPort(kCP_TransmitToMuxedMouse + (devicePort - kPS2MuxIdx)); + } + writeDataPort(request->commands[index].inOrOut); - deviceMode = kDT_Mouse; #if OUT_OF_ORDER_DATA_CORRECTION_FEATURE - byte = readDataPort(kDT_Mouse, kSC_Acknowledge); + byte = readDataPort(devicePort, kSC_Acknowledge); #else - byte = readDataPort(kDT_Mouse); + byte = readDataPort(devicePort); #endif failed = (byte != kSC_Acknowledge); break; - case kPS2C_ReadMouseDataPort: - deviceMode= kDT_Mouse; - request->commands[index].inOrOut = readDataPort(deviceMode); - break; - - case kPS2C_ReadMouseDataPortAndCompare: - deviceMode= kDT_Mouse; -#if OUT_OF_ORDER_DATA_CORRECTION_FEATURE - byte = readDataPort(deviceMode, request->commands[index].inOrOut); -#else - byte = readDataPort(deviceMode); -#endif - failed = (byte != request->commands[index].inOrOut); - break; - case kPS2C_FlushDataPort: request->commands[index].inOrOut32 = 0; while ( inb(kCommandPort) & kOutputReady ) @@ -1173,7 +1184,7 @@ void ApplePS2Controller::processRequest(PS2Request * request) case kPS2C_ModifyCommandByte: writeCommandPort(kCP_GetCommandByte); - UInt8 commandByte = readDataPort(kDT_Keyboard); + UInt8 commandByte = readDataPort(kPS2KbdIdx); writeCommandPort(kCP_SetCommandByte); writeDataPort((commandByte | request->commands[index].setBits) & ~request->commands[index].clearBits); request->commands[index].oldBits = commandByte; @@ -1239,7 +1250,22 @@ void ApplePS2Controller::processRequestQueue(IOInterruptEventSource *, int) // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -UInt8 ApplePS2Controller::readDataPort(PS2DeviceType deviceType) +size_t ApplePS2Controller::getPortFromStatus(UInt8 status) +{ + bool aux_port = status & kMouseData; + if (_mux_present && aux_port) + { + return kPS2MuxIdx + ((status >> 6) & 3); + } + else + { + return aux_port ? kPS2AuxIdx : kPS2KbdIdx; + } +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + +UInt8 ApplePS2Controller::readDataPort(size_t expectedPort) { // // Blocks until keyboard or mouse data is available from the controller @@ -1263,7 +1289,7 @@ UInt8 ApplePS2Controller::readDataPort(PS2DeviceType deviceType) #if DEBUGGER_SUPPORT int state; lockController(&state); // (lock out interrupt + access to queue) - if (deviceType == kDT_Keyboard && dequeueKeyboardData(&readByte)) + if (expectedPort == kPS2KbdIdx && dequeueKeyboardData(&readByte)) { unlockController(state); return readByte; @@ -1291,9 +1317,8 @@ UInt8 ApplePS2Controller::readDataPort(PS2DeviceType deviceType) #endif //DEBUGGER_SUPPORT if (!_suppressTimeout) - IOLog("%s: Timed out on %s input stream.\n", getName(), - (deviceType == kDT_Keyboard) ? "keyboard" : "mouse"); - return 0; + IOLog("%s: Timed out on input stream %ld.\n", getName(), expectedPort); + return 0; } // @@ -1318,22 +1343,15 @@ UInt8 ApplePS2Controller::readDataPort(PS2DeviceType deviceType) if (_suppressTimeout) // startup mode w/o interrupts return readByte; - if ( (status & kMouseData) ) - { - if (deviceType == kDT_Mouse) return readByte; - } - else - { - if (deviceType == kDT_Keyboard) return readByte; - } + size_t port = getPortFromStatus(status); + if (expectedPort == port) { return readByte; } // // The data we just received is for the other input stream, not the one // that was requested, so dispatch other device's interrupt handler. // - dispatchDriverInterrupt((deviceType==kDT_Keyboard)?kDT_Mouse:kDT_Keyboard, - readByte); + dispatchDriverInterrupt(port, readByte); } // while (forever) } @@ -1341,8 +1359,8 @@ UInt8 ApplePS2Controller::readDataPort(PS2DeviceType deviceType) #if OUT_OF_ORDER_DATA_CORRECTION_FEATURE -UInt8 ApplePS2Controller::readDataPort(PS2DeviceType deviceType, - UInt8 expectedByte) +UInt8 ApplePS2Controller::readDataPort(size_t expectedPort, + UInt8 expectedByte) { // // Blocks until keyboard or mouse data is available from the controller @@ -1375,6 +1393,7 @@ UInt8 ApplePS2Controller::readDataPort(PS2DeviceType deviceType, UInt8 firstByte = 0; bool firstByteHeld = false; + size_t port = kPS2KbdIdx; UInt8 readByte; bool requestedStream; UInt8 status = 0; @@ -1385,7 +1404,7 @@ UInt8 ApplePS2Controller::readDataPort(PS2DeviceType deviceType, #if DEBUGGER_SUPPORT int state; lockController(&state); // (lock out interrupt + access to queue) - if (deviceType == kDT_Keyboard && dequeueKeyboardData(&readByte)) + if (expectedPort == kPS2KbdIdx && dequeueKeyboardData(&readByte)) { requestedStream = true; goto skipForwardToY; @@ -1416,8 +1435,7 @@ UInt8 ApplePS2Controller::readDataPort(PS2DeviceType deviceType, if (firstByteHeld) return firstByte; - IOLog("%s: Timed out on %s input stream.\n", getName(), - (deviceType == kDT_Keyboard) ? "keyboard" : "mouse"); + IOLog("%s: Timed out on input stream %ld.\n", getName(), expectedPort); return 0; } @@ -1436,15 +1454,9 @@ UInt8 ApplePS2Controller::readDataPort(PS2DeviceType deviceType, readByte = inb(kDataPort); requestedStream = false; + port = getPortFromStatus(status); - if ( (status & kMouseData) ) - { - if (deviceType == kDT_Mouse) requestedStream = true; - } - else - { - if (deviceType == kDT_Keyboard) requestedStream = true; - } + if (expectedPort == port) { requestedStream = true; } #if DEBUGGER_SUPPORT skipForwardToY: @@ -1471,7 +1483,7 @@ UInt8 ApplePS2Controller::readDataPort(PS2DeviceType deviceType, // if (!_ignoreOutOfOrder) - dispatchDriverInterrupt(deviceType, firstByte); + dispatchDriverInterrupt(expectedPort, firstByte); return readByte; } } @@ -1495,7 +1507,7 @@ UInt8 ApplePS2Controller::readDataPort(PS2DeviceType deviceType, // if (!_ignoreOutOfOrder) - dispatchDriverInterrupt(deviceType, readByte); + dispatchDriverInterrupt(expectedPort, readByte); return firstByte; } } @@ -1508,7 +1520,7 @@ UInt8 ApplePS2Controller::readDataPort(PS2DeviceType deviceType, // if (!_ignoreOutOfOrder) - dispatchDriverInterrupt(deviceType == kDT_Keyboard ? kDT_Mouse : kDT_Keyboard, readByte); + dispatchDriverInterrupt(port, readByte); } } // while (forever) } @@ -1785,7 +1797,7 @@ IOReturn ApplePS2Controller::setPowerStateAction( OSObject * target, void * arg0, void * arg1, void * arg2, void * arg3 ) { - ApplePS2Controller * me = (ApplePS2Controller *) target; + ApplePS2Controller * me = (ApplePS2Controller *) target; #ifdef __LP64__ UInt32 powerState = (UInt32)(UInt64)arg0; @@ -1793,9 +1805,9 @@ IOReturn ApplePS2Controller::setPowerStateAction( OSObject * target, UInt32 powerState = (UInt32) arg0; #endif - me->setPowerStateGated( powerState ); + me->setPowerStateGated( powerState ); - return kIOReturnSuccess; + return kIOReturnSuccess; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -1820,8 +1832,8 @@ void ApplePS2Controller::setPowerStateGated( UInt32 powerState ) // synchronous requests thanks to the recursive lock. // First Mouse, then Keyboard. - dispatchDriverPowerControl( kPS2C_DisableDevice, kDT_Mouse ); - dispatchDriverPowerControl( kPS2C_DisableDevice, kDT_Keyboard ); + dispatchDriverPowerControl( kPS2C_DisableDevice, kPS2AuxIdx ); + dispatchDriverPowerControl( kPS2C_DisableDevice, kPS2KbdIdx ); // 3. Freeze the request queue and drop all data received over // the PS/2 port. @@ -1871,6 +1883,11 @@ void ApplePS2Controller::setPowerStateGated( UInt32 powerState ) // // 1. Enable the PS/2 port -- but just the clocks + + if (_mux_present) + { + enableMuxPorts(); + } DEBUG_LOG("%s: setCommandByte for wake 1\n", getName()); setCommandByte(0, kCB_DisableKeyboardClock | kCB_DisableMouseClock | kCB_EnableKeyboardIRQ | kCB_EnableMouseIRQ); @@ -1886,13 +1903,13 @@ void ApplePS2Controller::setPowerStateGated( UInt32 powerState ) if (!_mouseWakeFirst) { - dispatchDriverPowerControl( kPS2C_EnableDevice, kDT_Keyboard ); - dispatchDriverPowerControl( kPS2C_EnableDevice, kDT_Mouse ); + dispatchDriverPowerControl( kPS2C_EnableDevice, kPS2KbdIdx ); + dispatchDriverPowerControl( kPS2C_EnableDevice, kPS2AuxIdx ); } else { - dispatchDriverPowerControl( kPS2C_EnableDevice, kDT_Mouse ); - dispatchDriverPowerControl( kPS2C_EnableDevice, kDT_Keyboard ); + dispatchDriverPowerControl( kPS2C_EnableDevice, kPS2AuxIdx ); + dispatchDriverPowerControl( kPS2C_EnableDevice, kPS2KbdIdx ); } // 4. Now safe to enable the IRQs... @@ -1920,56 +1937,32 @@ void ApplePS2Controller::setPowerStateGated( UInt32 powerState ) // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void ApplePS2Controller::dispatchDriverPowerControl( UInt32 whatToDo, PS2DeviceType deviceType ) +void ApplePS2Controller::dispatchDriverPowerControl( UInt32 whatToDo, size_t port ) { - if (kDT_Mouse == deviceType && _powerControlInstalledMouse) - (*_powerControlActionMouse)(_powerControlTargetMouse, whatToDo); - - if (kDT_Keyboard == deviceType && _powerControlInstalledKeyboard) - (*_powerControlActionKeyboard)(_powerControlTargetKeyboard, whatToDo); -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void ApplePS2Controller::installPowerControlAction( - PS2DeviceType deviceType, - OSObject * target, - PS2PowerControlAction action ) -{ - if ( deviceType == kDT_Keyboard && _powerControlInstalledKeyboard == false ) - { - target->retain(); - _powerControlTargetKeyboard = target; - _powerControlActionKeyboard = action; - _powerControlInstalledKeyboard = true; - } - else if ( deviceType == kDT_Mouse && _powerControlInstalledMouse == false ) - { - target->retain(); - _powerControlTargetMouse = target; - _powerControlActionMouse = action; - _powerControlInstalledMouse = true; - } -} + // Should just be called with kPS2Aux or kPS2Kbd + // This will do power control on all mice if called with kPS2Aux + if (port > kPS2AuxIdx || _devices[port] == nullptr) + { + return; + } + + if (port == kPS2KbdIdx) + { + _devices[kPS2KbdIdx]->powerAction(whatToDo); + return; + } -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + if (!_mux_present) { + _devices[kPS2AuxIdx]->powerAction(whatToDo); + return; + } -void ApplePS2Controller::uninstallPowerControlAction( PS2DeviceType deviceType ) -{ - if ( deviceType == kDT_Keyboard && _powerControlInstalledKeyboard == true ) - { - _powerControlInstalledKeyboard = false; - _powerControlActionKeyboard = NULL; - _powerControlTargetKeyboard->release(); - _powerControlTargetKeyboard = 0; - } - else if ( deviceType == kDT_Mouse && _powerControlInstalledMouse == true ) - { - _powerControlInstalledMouse = false; - _powerControlActionMouse = NULL; - _powerControlTargetMouse->release(); - _powerControlTargetMouse = 0; - } + for (size_t i = kPS2MuxIdx; i < kPS2MaxIdx; i++) { + if (_devices[i]) + { + _devices[i]->powerAction(whatToDo); + } + } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -2032,6 +2025,7 @@ void ApplePS2Controller::dispatchMessageGated(int* message, void* data) case 0x3f: // osx fn (function) break; default: + int dispatchMessage = kPS2M_notifyKeyTime; dispatchMessageGated(&dispatchMessage, &(pInfo->time)); } diff --git a/VoodooPS2Controller/VoodooPS2Controller.h b/VoodooPS2Controller/VoodooPS2Controller.h index 90ef1fd4..6eb61f20 100644 --- a/VoodooPS2Controller/VoodooPS2Controller.h +++ b/VoodooPS2Controller/VoodooPS2Controller.h @@ -146,6 +146,14 @@ class ApplePS2MouseDevice; #define kWatchdogTimerInterval 100 +// Enable Mux commands +// Constants are from Linux +// https://github.com/torvalds/linux/blob/c2d7ed9d680fd14aa5486518bd0d0fa5963c6403/drivers/input/serio/i8042.c#L685-L693 + +#define kDP_EnableMuxCmd1 0xF0 +#define kDP_EnableMuxCmd2 0x56 +#define kDP_GetMuxVersion 0xA4 + #if DEBUGGER_SUPPORT // Definitions for our internal keyboard queue (holds keys processed by the // interrupt-time mini-monitor-key-sequence detection code). @@ -170,8 +178,8 @@ struct KeyboardQueueElement #endif // ps2rst flags -#define RESET_CONTROLLER_ON_BOOT 1 -#define RESET_CONTROLLER_ON_WAKEUP 2 +#define RESET_CONTROLLER_ON_BOOT 1 +#define RESET_CONTROLLER_ON_WAKEUP 2 class IOACPIPlatformDevice; @@ -182,6 +190,22 @@ enum { kPS2PowerStateCount }; +// i8042 Mux indexes +#define PS2_MUX_IDX 2 +#define PS2_MUX_PORTS 4 + +// Normally, the i8042 controller has 2 ports. With the mux active, +// there are 5 ports. 1 Keyboard port and 4 mux ports. All the muxed ports +// share the same IRQ. When the controller is in the multiplexer mode, the +// index for the aux port is skipped. + +enum { + kPS2KbdIdx = 0, + kPS2AuxIdx = 1, + kPS2MuxIdx = PS2_MUX_IDX, + kPS2MaxIdx = PS2_MUX_IDX + PS2_MUX_PORTS +}; + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // ApplePS2Controller Class Declaration // @@ -191,9 +215,12 @@ class EXPORT ApplePS2Controller : public IOService typedef IOService super; OSDeclareDefaultStructors(ApplePS2Controller); -public: // interrupt-time variables and functions - IOInterruptEventSource * _interruptSourceKeyboard {nullptr}; +public: + // interrupt-time variables and functions +#if HANDLE_INTERRUPT_DATA_LATER IOInterruptEventSource * _interruptSourceMouse {nullptr}; + IOInterruptEventSource * _interruptSourceKeyboard {nullptr}; +#endif IOInterruptEventSource * _interruptSourceQueue {nullptr}; #if DEBUGGER_SUPPORT @@ -213,27 +240,13 @@ class EXPORT ApplePS2Controller : public IOService IOLock* _requestQueueLock {nullptr}; IOLock* _cmdbyteLock {nullptr}; - OSObject * _interruptTargetKeyboard {nullptr}; - OSObject * _interruptTargetMouse {nullptr}; - PS2InterruptAction _interruptActionKeyboard {nullptr}; - PS2InterruptAction _interruptActionMouse {nullptr}; - PS2PacketAction _packetActionKeyboard {nullptr}; - PS2PacketAction _packetActionMouse {nullptr}; bool _interruptInstalledKeyboard {false}; - bool _interruptInstalledMouse {false}; - - OSObject * _powerControlTargetKeyboard {nullptr}; - OSObject * _powerControlTargetMouse {nullptr}; - PS2PowerControlAction _powerControlActionKeyboard {nullptr}; - PS2PowerControlAction _powerControlActionMouse {nullptr}; - bool _powerControlInstalledKeyboard {false}; - bool _powerControlInstalledMouse {false}; + int _interruptInstalledMouse {0}; int _ignoreInterrupts {0}; int _ignoreOutOfOrder {0}; - ApplePS2MouseDevice * _mouseDevice {nullptr}; // mouse nub - ApplePS2KeyboardDevice * _keyboardDevice {nullptr}; // keyboard nub + ApplePS2Device * _devices [kPS2MaxIdx] {nullptr}; IONotifier* _publishNotify {nullptr}; IONotifier* _terminateNotify {nullptr}; @@ -255,11 +268,9 @@ class EXPORT ApplePS2Controller : public IOService UInt32 _currentPowerState {kPS2PowerStateNormal}; bool _hardwareOffline {false}; bool _suppressTimeout {false}; -#ifdef NEWIRQ - bool _newIRQLayout {false}; -#endif int _wakedelay {10}; bool _mouseWakeFirst {false}; + bool _mux_present {false}; IOCommandGate* _cmdGate {nullptr}; #if WATCHDOG_TIMER IOTimerEventSource* _watchdogTimer {nullptr}; @@ -269,25 +280,27 @@ class EXPORT ApplePS2Controller : public IOService int _resetControllerFlag {RESET_CONTROLLER_ON_BOOT | RESET_CONTROLLER_ON_WAKEUP}; - virtual PS2InterruptResult _dispatchDriverInterrupt(PS2DeviceType deviceType, UInt8 data); - virtual void dispatchDriverInterrupt(PS2DeviceType deviceType, UInt8 data); + virtual PS2InterruptResult _dispatchDriverInterrupt(size_t port, UInt8 data); + virtual void dispatchDriverInterrupt(size_t port, UInt8 data); #if HANDLE_INTERRUPT_DATA_LATER virtual void interruptOccurred(IOInterruptEventSource *, int); -#else - void packetReadyMouse(IOInterruptEventSource*, int); - void packetReadyKeyboard(IOInterruptEventSource*, int); #endif - void handleInterrupt(PS2DeviceType deviceType); + void handleInterrupt(bool watchdog = false); #if WATCHDOG_TIMER void onWatchdogTimer(); #endif virtual void processRequest(PS2Request * request); virtual void processRequestQueue(IOInterruptEventSource *, int); - virtual UInt8 readDataPort(PS2DeviceType deviceType); +#if OUT_OF_ORDER_DATA_CORRECTION_FEATURE + virtual UInt8 readDataPort(size_t port, UInt8 expectedByte); +#endif + + virtual UInt8 readDataPort(size_t port); virtual void writeCommandPort(UInt8 byte); virtual void writeDataPort(UInt8 byte); void resetController(void); + bool hasMux(void); static void interruptHandlerMouse(OSObject*, void* refCon, IOService*, int); static void interruptHandlerKeyboard(OSObject*, void* refCon, IOService*, int); @@ -300,10 +313,6 @@ class EXPORT ApplePS2Controller : public IOService void dispatchMessageGated(int* message, void* data); -#if OUT_OF_ORDER_DATA_CORRECTION_FEATURE - virtual UInt8 readDataPort(PS2DeviceType deviceType, UInt8 expectedByte); -#endif - static void setPowerStateCallout(thread_call_param_t param0, thread_call_param_t param1); @@ -313,10 +322,12 @@ class EXPORT ApplePS2Controller : public IOService virtual void setPowerStateGated(UInt32 newPowerState); - virtual void dispatchDriverPowerControl(UInt32 whatToDo, PS2DeviceType deviceType); + virtual void dispatchDriverPowerControl(UInt32 whatToDo, size_t port); void free(void) override; IOReturn setPropertiesGated(OSObject* props); void submitRequestAndBlockGated(PS2Request* request); + + size_t getPortFromStatus(UInt8 status); public: bool init(OSDictionary * properties) override; @@ -326,11 +337,9 @@ class EXPORT ApplePS2Controller : public IOService IOWorkLoop * getWorkLoop() const override; - virtual void installInterruptAction(PS2DeviceType deviceType, - OSObject * target, - PS2InterruptAction interruptAction, - PS2PacketAction packetAction); - virtual void uninstallInterruptAction(PS2DeviceType deviceType); + void enableMuxPorts(); + virtual void installInterruptAction(size_t port); + virtual void uninstallInterruptAction(size_t port); virtual PS2Request* allocateRequest(int max = kMaxCommands); virtual void freeRequest(PS2Request * request); @@ -341,12 +350,6 @@ class EXPORT ApplePS2Controller : public IOService IOReturn setPowerState(unsigned long powerStateOrdinal, IOService * policyMaker) override; - - virtual void installPowerControlAction(PS2DeviceType deviceType, - OSObject * target, - PS2PowerControlAction action); - - virtual void uninstallPowerControlAction(PS2DeviceType deviceType); virtual void dispatchMessage(int message, void* data); diff --git a/VoodooPS2Mouse/VoodooPS2Mouse.cpp b/VoodooPS2Mouse/VoodooPS2Mouse.cpp index a2bdb9a6..b2dcb43f 100644 --- a/VoodooPS2Mouse/VoodooPS2Mouse.cpp +++ b/VoodooPS2Mouse/VoodooPS2Mouse.cpp @@ -305,25 +305,23 @@ ApplePS2Mouse* ApplePS2Mouse::probe(IOService * provider, SInt32 * score) // // (get information command) - TPS2Request<6> request; - request.commands[0].command = kPS2C_WriteCommandPort; - request.commands[0].inOrOut = kCP_TransmitToMouse; - request.commands[1].command = kPS2C_WriteDataPort; - request.commands[1].inOrOut = kDP_GetMouseInformation; - request.commands[2].command = kPS2C_ReadDataPortAndCompare; - request.commands[2].inOrOut = kSC_Acknowledge; + TPS2Request<5> request; + request.commands[0].command = kPS2C_WriteDataPort; + request.commands[0].inOrOut = kDP_GetMouseInformation; + request.commands[1].command = kPS2C_ReadDataPortAndCompare; + request.commands[1].inOrOut = kSC_Acknowledge; + request.commands[2].command = kPS2C_ReadDataPort; + request.commands[2].inOrOut = 0; request.commands[3].command = kPS2C_ReadDataPort; request.commands[3].inOrOut = 0; request.commands[4].command = kPS2C_ReadDataPort; request.commands[4].inOrOut = 0; - request.commands[5].command = kPS2C_ReadDataPort; - request.commands[5].inOrOut = 0; - request.commandsCount = 6; + request.commandsCount = 5; assert(request.commandsCount <= countof(request.commands)); device->submitRequestAndBlock(&request); DEBUG_LOG("ApplePS2Mouse::probe leaving.\n"); - return 6 == request.commandsCount ? this : 0; + return 5 == request.commandsCount ? this : 0; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -374,6 +372,10 @@ bool ApplePS2Mouse::start(IOService * provider) pWorkLoop->addEventSource(_cmdGate); attachedHIDPointerDevices = OSSet::withCapacity(1); + if (attachedHIDPointerDevices == nullptr) + { + return false; + } registerHIDPointerNotifications(); // @@ -495,27 +497,23 @@ void ApplePS2Mouse::resetMouse() // ... it is just going to time out... and then later show up in the // input stream unexpectedly. - TPS2Request<8> request; - request.commands[0].command = kPS2C_WriteCommandPort; - request.commands[0].inOrOut = kCP_TransmitToMouse; + TPS2Request<6> request; + request.commands[0].command = kPS2C_WriteDataPort; + request.commands[0].inOrOut = kDP_SetDefaults; request.commands[1].command = kPS2C_WriteDataPort; - request.commands[1].inOrOut = kDP_SetDefaults; - request.commands[2].command = kPS2C_WriteCommandPort; - request.commands[2].inOrOut = kCP_TransmitToMouse; - request.commands[3].command = kPS2C_WriteDataPort; - request.commands[3].inOrOut = kDP_GetMouseInformation; - request.commands[4].command = kPS2C_ReadDataPortAndCompare; - request.commands[4].inOrOut = kSC_Acknowledge; + request.commands[1].inOrOut = kDP_GetMouseInformation; + request.commands[2].command = kPS2C_ReadDataPortAndCompare; + request.commands[2].inOrOut = kSC_Acknowledge; + request.commands[3].command = kPS2C_ReadDataPort; + request.commands[3].inOrOut = 0; + request.commands[4].command = kPS2C_ReadDataPort; + request.commands[4].inOrOut = 0; request.commands[5].command = kPS2C_ReadDataPort; request.commands[5].inOrOut = 0; - request.commands[6].command = kPS2C_ReadDataPort; - request.commands[6].inOrOut = 0; - request.commands[7].command = kPS2C_ReadDataPort; - request.commands[7].inOrOut = 0; - request.commandsCount = 8; + request.commandsCount = 6; assert(request.commandsCount <= countof(request.commands)); _device->submitRequestAndBlock(&request); - if (8 != request.commandsCount) + if (6 != request.commandsCount) DEBUG_LOG("%s: reset mouse sequence failed: %d\n", getName(), request.commandsCount); // Now deal with Synaptics specifics (ActLikeTrackpad trick)... @@ -955,14 +953,12 @@ void ApplePS2Mouse::setMouseEnable(bool enable) // // (mouse enable/disable command) - TPS2Request<3> request; - request.commands[0].command = kPS2C_WriteCommandPort; - request.commands[0].inOrOut = kCP_TransmitToMouse; - request.commands[1].command = kPS2C_WriteDataPort; - request.commands[1].inOrOut = enable ? kDP_Enable : kDP_SetDefaultsAndDisable; - request.commands[2].command = kPS2C_ReadDataPortAndCompare; - request.commands[2].inOrOut = kSC_Acknowledge; - request.commandsCount = 3; + TPS2Request<2> request; + request.commands[0].command = kPS2C_WriteDataPort; + request.commands[0].inOrOut = enable ? kDP_Enable : kDP_SetDefaultsAndDisable; + request.commands[1].command = kPS2C_ReadDataPortAndCompare; + request.commands[1].inOrOut = kSC_Acknowledge; + request.commandsCount = 2; assert(request.commandsCount <= countof(request.commands)); _device->submitRequestAndBlock(&request); } @@ -981,20 +977,16 @@ void ApplePS2Mouse::setMouseSampleRate(UInt8 sampleRate) // // (set mouse sample rate command) - TPS2Request<6> request; - request.commands[0].command = kPS2C_WriteCommandPort; - request.commands[0].inOrOut = kCP_TransmitToMouse; - request.commands[1].command = kPS2C_WriteDataPort; - request.commands[1].inOrOut = kDP_SetMouseSampleRate; - request.commands[2].command = kPS2C_ReadDataPortAndCompare; - request.commands[2].inOrOut = kSC_Acknowledge; - request.commands[3].command = kPS2C_WriteCommandPort; - request.commands[3].inOrOut = kCP_TransmitToMouse; - request.commands[4].command = kPS2C_WriteDataPort; - request.commands[4].inOrOut = sampleRate; - request.commands[5].command = kPS2C_ReadDataPortAndCompare; - request.commands[5].inOrOut = kSC_Acknowledge; - request.commandsCount = 6; + TPS2Request<4> request; + request.commands[0].command = kPS2C_WriteDataPort; + request.commands[0].inOrOut = kDP_SetMouseSampleRate; + request.commands[1].command = kPS2C_ReadDataPortAndCompare; + request.commands[1].inOrOut = kSC_Acknowledge; + request.commands[2].command = kPS2C_WriteDataPort; + request.commands[2].inOrOut = sampleRate; + request.commands[3].command = kPS2C_ReadDataPortAndCompare; + request.commands[3].inOrOut = kSC_Acknowledge; + request.commandsCount = 4; assert(request.commandsCount <= countof(request.commands)); _device->submitRequestAndBlock(&request); } @@ -1018,20 +1010,16 @@ void ApplePS2Mouse::setMouseResolution(UInt8 resolution) DEBUG_LOG("%s::setMouseResolution(0x%x)\n", getName(), resolution); // (set mouse resolution command) - TPS2Request<6> request; - request.commands[0].command = kPS2C_WriteCommandPort; - request.commands[0].inOrOut = kCP_TransmitToMouse; - request.commands[1].command = kPS2C_WriteDataPort; - request.commands[1].inOrOut = kDP_SetMouseResolution; - request.commands[2].command = kPS2C_ReadDataPortAndCompare; - request.commands[2].inOrOut = kSC_Acknowledge; - request.commands[3].command = kPS2C_WriteCommandPort; - request.commands[3].inOrOut = kCP_TransmitToMouse; - request.commands[4].command = kPS2C_WriteDataPort; - request.commands[4].inOrOut = resolution; - request.commands[5].command = kPS2C_ReadDataPortAndCompare; - request.commands[5].inOrOut = kSC_Acknowledge; - request.commandsCount = 6; + TPS2Request<4> request; + request.commands[0].command = kPS2C_WriteDataPort; + request.commands[0].inOrOut = kDP_SetMouseResolution; + request.commands[1].command = kPS2C_ReadDataPortAndCompare; + request.commands[1].inOrOut = kSC_Acknowledge; + request.commands[2].command = kPS2C_WriteDataPort; + request.commands[2].inOrOut = resolution; + request.commands[3].command = kPS2C_ReadDataPortAndCompare; + request.commands[3].inOrOut = kSC_Acknowledge; + request.commandsCount = 4; assert(request.commandsCount <= countof(request.commands)); _device->submitRequestAndBlock(&request); } @@ -1136,28 +1124,26 @@ UInt32 ApplePS2Mouse::getMouseInformation() UInt32 returnValue = (UInt32)(-1); // (get information command) - TPS2Request<6> request; - request.commands[0].command = kPS2C_WriteCommandPort; - request.commands[0].inOrOut = kCP_TransmitToMouse; - request.commands[1].command = kPS2C_WriteDataPort; - request.commands[1].inOrOut = kDP_GetMouseInformation; - request.commands[2].command = kPS2C_ReadDataPortAndCompare; - request.commands[2].inOrOut = kSC_Acknowledge; + TPS2Request<5> request; + request.commands[0].command = kPS2C_WriteDataPort; + request.commands[0].inOrOut = kDP_GetMouseInformation; + request.commands[1].command = kPS2C_ReadDataPortAndCompare; + request.commands[1].inOrOut = kSC_Acknowledge; + request.commands[2].command = kPS2C_ReadDataPort; + request.commands[2].inOrOut = 0; request.commands[3].command = kPS2C_ReadDataPort; request.commands[3].inOrOut = 0; request.commands[4].command = kPS2C_ReadDataPort; request.commands[4].inOrOut = 0; - request.commands[5].command = kPS2C_ReadDataPort; - request.commands[5].inOrOut = 0; - request.commandsCount = 6; + request.commandsCount = 5; assert(request.commandsCount <= countof(request.commands)); _device->submitRequestAndBlock(&request); - if (request.commandsCount == 6) // success? + if (request.commandsCount == 5) // success? { - returnValue = ((UInt32)request.commands[3].inOrOut << 16) | - ((UInt32)request.commands[4].inOrOut << 8 ) | - ((UInt32)request.commands[5].inOrOut); + returnValue = ((UInt32)request.commands[2].inOrOut << 16) | + ((UInt32)request.commands[3].inOrOut << 8 ) | + ((UInt32)request.commands[4].inOrOut); } DEBUG_LOG("%s::getMouseInformation() returns 0x%x\n", getName(), returnValue); @@ -1181,21 +1167,19 @@ UInt8 ApplePS2Mouse::getMouseID() UInt8 returnValue = (UInt8)(-1); // (get information command) - TPS2Request<4> request; - request.commands[0].command = kPS2C_WriteCommandPort; - request.commands[0].inOrOut = kCP_TransmitToMouse; - request.commands[1].command = kPS2C_WriteDataPort; - request.commands[1].inOrOut = kDP_GetId; - request.commands[2].command = kPS2C_ReadDataPortAndCompare; - request.commands[2].inOrOut = kSC_Acknowledge; - request.commands[3].command = kPS2C_ReadDataPort; - request.commands[3].inOrOut = 0; - request.commandsCount = 4; + TPS2Request<3> request; + request.commands[0].command = kPS2C_WriteDataPort; + request.commands[0].inOrOut = kDP_GetId; + request.commands[1].command = kPS2C_ReadDataPortAndCompare; + request.commands[1].inOrOut = kSC_Acknowledge; + request.commands[2].command = kPS2C_ReadDataPort; + request.commands[2].inOrOut = 0; + request.commandsCount = 3; assert(request.commandsCount <= countof(request.commands)); _device->submitRequestAndBlock(&request); - if (request.commandsCount == 4) // success? - returnValue = request.commands[3].inOrOut; + if (request.commandsCount == 3) // success? + returnValue = request.commands[2].inOrOut; DEBUG_LOG("%s::getMouseID returns 0x%x\n", getName(), returnValue); return returnValue; @@ -1327,38 +1311,38 @@ bool ApplePS2Mouse::setTouchpadLED(UInt8 touchLED) TPS2Request<12> request; // send NOP before special command sequence - request.commands[0].command = kPS2C_SendMouseCommandAndCompareAck; + request.commands[0].command = kPS2C_SendCommandAndCompareAck; request.commands[0].inOrOut = kDP_SetMouseScaling1To1; // 4 set resolution commands, each encode 2 data bits of LED level - request.commands[1].command = kPS2C_SendMouseCommandAndCompareAck; + request.commands[1].command = kPS2C_SendCommandAndCompareAck; request.commands[1].inOrOut = kDP_SetMouseResolution; - request.commands[2].command = kPS2C_SendMouseCommandAndCompareAck; + request.commands[2].command = kPS2C_SendCommandAndCompareAck; request.commands[2].inOrOut = (touchLED >> 6) & 0x3; - request.commands[3].command = kPS2C_SendMouseCommandAndCompareAck; + request.commands[3].command = kPS2C_SendCommandAndCompareAck; request.commands[3].inOrOut = kDP_SetMouseResolution; - request.commands[4].command = kPS2C_SendMouseCommandAndCompareAck; + request.commands[4].command = kPS2C_SendCommandAndCompareAck; request.commands[4].inOrOut = (touchLED >> 4) & 0x3; - request.commands[5].command = kPS2C_SendMouseCommandAndCompareAck; + request.commands[5].command = kPS2C_SendCommandAndCompareAck; request.commands[5].inOrOut = kDP_SetMouseResolution; - request.commands[6].command = kPS2C_SendMouseCommandAndCompareAck; + request.commands[6].command = kPS2C_SendCommandAndCompareAck; request.commands[6].inOrOut = (touchLED >> 2) & 0x3; - request.commands[7].command = kPS2C_SendMouseCommandAndCompareAck; + request.commands[7].command = kPS2C_SendCommandAndCompareAck; request.commands[7].inOrOut = kDP_SetMouseResolution; - request.commands[8].command = kPS2C_SendMouseCommandAndCompareAck; + request.commands[8].command = kPS2C_SendCommandAndCompareAck; request.commands[8].inOrOut = (touchLED >> 0) & 0x3; // Set sample rate 10 (10 is command for setting LED) - request.commands[9].command = kPS2C_SendMouseCommandAndCompareAck; + request.commands[9].command = kPS2C_SendCommandAndCompareAck; request.commands[9].inOrOut = kDP_SetMouseSampleRate; - request.commands[10].command = kPS2C_SendMouseCommandAndCompareAck; + request.commands[10].command = kPS2C_SendCommandAndCompareAck; request.commands[10].inOrOut = 10; // 0x0A command for setting LED // finally send NOP command to end the special sequence - request.commands[11].command = kPS2C_SendMouseCommandAndCompareAck; + request.commands[11].command = kPS2C_SendCommandAndCompareAck; request.commands[11].inOrOut = kDP_SetMouseScaling1To1; request.commandsCount = 12; assert(request.commandsCount <= countof(request.commands)); @@ -1372,32 +1356,32 @@ bool ApplePS2Mouse::getTouchPadData(UInt8 dataSelector, UInt8 buf3[]) TPS2Request<14> request; // Disable stream mode before the command sequence. - request.commands[0].command = kPS2C_SendMouseCommandAndCompareAck; + request.commands[0].command = kPS2C_SendCommandAndCompareAck; request.commands[0].inOrOut = kDP_SetDefaultsAndDisable; // 4 set resolution commands, each encode 2 data bits. - request.commands[1].command = kPS2C_SendMouseCommandAndCompareAck; + request.commands[1].command = kPS2C_SendCommandAndCompareAck; request.commands[1].inOrOut = kDP_SetMouseResolution; - request.commands[2].command = kPS2C_SendMouseCommandAndCompareAck; + request.commands[2].command = kPS2C_SendCommandAndCompareAck; request.commands[2].inOrOut = (dataSelector >> 6) & 0x3; - request.commands[3].command = kPS2C_SendMouseCommandAndCompareAck; + request.commands[3].command = kPS2C_SendCommandAndCompareAck; request.commands[3].inOrOut = kDP_SetMouseResolution; - request.commands[4].command = kPS2C_SendMouseCommandAndCompareAck; + request.commands[4].command = kPS2C_SendCommandAndCompareAck; request.commands[4].inOrOut = (dataSelector >> 4) & 0x3; - request.commands[5].command = kPS2C_SendMouseCommandAndCompareAck; + request.commands[5].command = kPS2C_SendCommandAndCompareAck; request.commands[5].inOrOut = kDP_SetMouseResolution; - request.commands[6].command = kPS2C_SendMouseCommandAndCompareAck; + request.commands[6].command = kPS2C_SendCommandAndCompareAck; request.commands[6].inOrOut = (dataSelector >> 2) & 0x3; - request.commands[7].command = kPS2C_SendMouseCommandAndCompareAck; + request.commands[7].command = kPS2C_SendCommandAndCompareAck; request.commands[7].inOrOut = kDP_SetMouseResolution; - request.commands[8].command = kPS2C_SendMouseCommandAndCompareAck; + request.commands[8].command = kPS2C_SendCommandAndCompareAck; request.commands[8].inOrOut = (dataSelector >> 0) & 0x3; // Read response bytes. - request.commands[9].command = kPS2C_SendMouseCommandAndCompareAck; + request.commands[9].command = kPS2C_SendCommandAndCompareAck; request.commands[9].inOrOut = kDP_GetMouseInformation; request.commands[10].command = kPS2C_ReadDataPort; request.commands[10].inOrOut = 0; @@ -1405,7 +1389,7 @@ bool ApplePS2Mouse::getTouchPadData(UInt8 dataSelector, UInt8 buf3[]) request.commands[11].inOrOut = 0; request.commands[12].command = kPS2C_ReadDataPort; request.commands[12].inOrOut = 0; - request.commands[13].command = kPS2C_SendMouseCommandAndCompareAck; + request.commands[13].command = kPS2C_SendCommandAndCompareAck; request.commands[13].inOrOut = kDP_SetDefaultsAndDisable; request.commandsCount = 14; assert(request.commandsCount <= countof(request.commands)); @@ -1458,22 +1442,22 @@ void ApplePS2Mouse::unregisterHIDPointerNotifications() // Free device matching notifiers if (usb_hid_publish_notify) { usb_hid_publish_notify->remove(); - OSSafeReleaseNULL(usb_hid_publish_notify); + usb_hid_publish_notify = nullptr; } if (usb_hid_terminate_notify) { usb_hid_terminate_notify->remove(); - OSSafeReleaseNULL(usb_hid_terminate_notify); + usb_hid_terminate_notify = nullptr; } if (bluetooth_hid_publish_notify) { bluetooth_hid_publish_notify->remove(); - OSSafeReleaseNULL(bluetooth_hid_publish_notify); + bluetooth_hid_publish_notify = nullptr; } if (bluetooth_hid_terminate_notify) { bluetooth_hid_terminate_notify->remove(); - OSSafeReleaseNULL(bluetooth_hid_terminate_notify); + bluetooth_hid_terminate_notify = nullptr; } attachedHIDPointerDevices->flushCollection(); diff --git a/VoodooPS2Mouse/VoodooPS2Mouse.h b/VoodooPS2Mouse/VoodooPS2Mouse.h index f9b3aa71..a3786bc7 100644 --- a/VoodooPS2Mouse/VoodooPS2Mouse.h +++ b/VoodooPS2Mouse/VoodooPS2Mouse.h @@ -89,13 +89,13 @@ class EXPORT ApplePS2Mouse : public IOHIPointing int _processusbmouse; int _processbluetoothmouse; - OSSet* attachedHIDPointerDevices; + OSSet* attachedHIDPointerDevices { nullptr }; - IONotifier* usb_hid_publish_notify; // Notification when an USB mouse HID device is connected - IONotifier* usb_hid_terminate_notify; // 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; // Notification when a bluetooth HID device is connected - IONotifier* bluetooth_hid_terminate_notify; // 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 // for middle button simulation enum mbuttonstate diff --git a/VoodooPS2Trackpad/VoodooPS2ALPSGlidePoint.cpp b/VoodooPS2Trackpad/VoodooPS2ALPSGlidePoint.cpp index 7b964575..dfad1a47 100644 --- a/VoodooPS2Trackpad/VoodooPS2ALPSGlidePoint.cpp +++ b/VoodooPS2Trackpad/VoodooPS2ALPSGlidePoint.cpp @@ -541,8 +541,8 @@ void ApplePS2ALPSGlidePoint::setTapEnable( bool enable ) int cmd = enable ? kDP_SetMouseSampleRate : kDP_SetMouseResolution; int arg = enable ? 0x0A : 0x00; - TPS2Request<10> request; - request.commands[0].command = kPS2C_SendMouseCommandAndCompareAck; + TPS2Request<9> request; + request.commands[0].command = kPS2C_SendCommandAndCompareAck; request.commands[0].inOrOut = kDP_GetMouseInformation; //sync.. request.commands[1].command = kPS2C_ReadDataPort; request.commands[1].inOrOut = 0; @@ -550,19 +550,17 @@ void ApplePS2ALPSGlidePoint::setTapEnable( bool enable ) request.commands[2].inOrOut = 0; request.commands[3].command = kPS2C_ReadDataPort; request.commands[3].inOrOut = 0; - request.commands[4].command = kPS2C_SendMouseCommandAndCompareAck; + request.commands[4].command = kPS2C_SendCommandAndCompareAck; request.commands[4].inOrOut = kDP_SetDefaultsAndDisable; - request.commands[5].command = kPS2C_SendMouseCommandAndCompareAck; + request.commands[5].command = kPS2C_SendCommandAndCompareAck; request.commands[5].inOrOut = kDP_SetDefaultsAndDisable; - request.commands[6].command = kPS2C_SendMouseCommandAndCompareAck; + request.commands[6].command = kPS2C_SendCommandAndCompareAck; request.commands[6].inOrOut = cmd; - request.commands[7].command = kPS2C_WriteCommandPort; - request.commands[7].inOrOut = kCP_TransmitToMouse; - request.commands[8].command = kPS2C_WriteDataPort; - request.commands[8].inOrOut = arg; - request.commands[9].command = kPS2C_ReadDataPortAndCompare; - request.commands[9].inOrOut = kSC_Acknowledge; - request.commandsCount = 10; + request.commands[7].command = kPS2C_WriteDataPort; + request.commands[7].inOrOut = arg; + request.commands[8].command = kPS2C_ReadDataPortAndCompare; + request.commands[8].inOrOut = kSC_Acknowledge; + request.commandsCount = 9; assert(request.commandsCount <= countof(request.commands)); _device->submitRequestAndBlock(&request); @@ -580,17 +578,17 @@ void ApplePS2ALPSGlidePoint::setTouchPadEnable( bool enable ) // (mouse enable/disable command) TPS2Request<5> request; - request.commands[0].command = kPS2C_SendMouseCommandAndCompareAck; + request.commands[0].command = kPS2C_SendCommandAndCompareAck; request.commands[0].inOrOut = kDP_SetDefaultsAndDisable; - request.commands[1].command = kPS2C_SendMouseCommandAndCompareAck; + request.commands[1].command = kPS2C_SendCommandAndCompareAck; request.commands[1].inOrOut = kDP_SetDefaultsAndDisable; - request.commands[2].command = kPS2C_SendMouseCommandAndCompareAck; + request.commands[2].command = kPS2C_SendCommandAndCompareAck; request.commands[2].inOrOut = kDP_SetDefaultsAndDisable; - request.commands[3].command = kPS2C_SendMouseCommandAndCompareAck; + request.commands[3].command = kPS2C_SendCommandAndCompareAck; request.commands[3].inOrOut = kDP_SetDefaultsAndDisable; // (mouse or pad enable/disable command) - request.commands[4].command = kPS2C_SendMouseCommandAndCompareAck; + request.commands[4].command = kPS2C_SendCommandAndCompareAck; request.commands[4].inOrOut = enable ? kDP_Enable : kDP_SetDefaultsAndDisable; request.commandsCount = 5; assert(request.commandsCount <= countof(request.commands)); @@ -711,13 +709,13 @@ void ApplePS2ALPSGlidePoint::getStatus(ALPSStatus_t *status) { // (read command byte) TPS2Request<7> request; - request.commands[0].command = kPS2C_SendMouseCommandAndCompareAck; + request.commands[0].command = kPS2C_SendCommandAndCompareAck; request.commands[0].inOrOut = kDP_SetDefaultsAndDisable; - request.commands[1].command = kPS2C_SendMouseCommandAndCompareAck; + request.commands[1].command = kPS2C_SendCommandAndCompareAck; request.commands[1].inOrOut = kDP_SetDefaultsAndDisable; - request.commands[2].command = kPS2C_SendMouseCommandAndCompareAck; + request.commands[2].command = kPS2C_SendCommandAndCompareAck; request.commands[2].inOrOut = kDP_SetDefaultsAndDisable; - request.commands[3].command = kPS2C_SendMouseCommandAndCompareAck; + request.commands[3].command = kPS2C_SendCommandAndCompareAck; request.commands[3].inOrOut = kDP_GetMouseInformation; request.commands[4].command = kPS2C_ReadDataPort; request.commands[4].inOrOut = 0; @@ -740,19 +738,19 @@ void ApplePS2ALPSGlidePoint::getModel(ALPSStatus_t *E6,ALPSStatus_t *E7) { // "E6 report" TPS2Request<9> request; - request.commands[0].command = kPS2C_SendMouseCommandAndCompareAck; + request.commands[0].command = kPS2C_SendCommandAndCompareAck; request.commands[0].inOrOut = kDP_SetMouseResolution; - request.commands[1].command = kPS2C_SendMouseCommandAndCompareAck; + request.commands[1].command = kPS2C_SendCommandAndCompareAck; request.commands[1].inOrOut = 0; // 3X set mouse scaling 1 to 1 - request.commands[2].command = kPS2C_SendMouseCommandAndCompareAck; + request.commands[2].command = kPS2C_SendCommandAndCompareAck; request.commands[2].inOrOut = kDP_SetMouseScaling1To1; - request.commands[3].command = kPS2C_SendMouseCommandAndCompareAck; + request.commands[3].command = kPS2C_SendCommandAndCompareAck; request.commands[3].inOrOut = kDP_SetMouseScaling1To1; - request.commands[4].command = kPS2C_SendMouseCommandAndCompareAck; + request.commands[4].command = kPS2C_SendCommandAndCompareAck; request.commands[4].inOrOut = kDP_SetMouseScaling1To1; - request.commands[5].command = kPS2C_SendMouseCommandAndCompareAck; + request.commands[5].command = kPS2C_SendCommandAndCompareAck; request.commands[5].inOrOut = kDP_GetMouseInformation; request.commands[6].command = kPS2C_ReadDataPort; request.commands[6].inOrOut = 0; @@ -770,19 +768,19 @@ void ApplePS2ALPSGlidePoint::getModel(ALPSStatus_t *E6,ALPSStatus_t *E7) E6->byte2 = request.commands[8].inOrOut; // Now fetch "E7 report" - request.commands[0].command = kPS2C_SendMouseCommandAndCompareAck; + request.commands[0].command = kPS2C_SendCommandAndCompareAck; request.commands[0].inOrOut = kDP_SetMouseResolution; - request.commands[1].command = kPS2C_SendMouseCommandAndCompareAck; + request.commands[1].command = kPS2C_SendCommandAndCompareAck; request.commands[1].inOrOut = 0; // 3X set mouse scaling 2 to 1 - request.commands[2].command = kPS2C_SendMouseCommandAndCompareAck; + request.commands[2].command = kPS2C_SendCommandAndCompareAck; request.commands[2].inOrOut = kDP_SetMouseScaling2To1; - request.commands[3].command = kPS2C_SendMouseCommandAndCompareAck; + request.commands[3].command = kPS2C_SendCommandAndCompareAck; request.commands[3].inOrOut = kDP_SetMouseScaling2To1; - request.commands[4].command = kPS2C_SendMouseCommandAndCompareAck; + request.commands[4].command = kPS2C_SendCommandAndCompareAck; request.commands[4].inOrOut = kDP_SetMouseScaling2To1; - request.commands[5].command = kPS2C_SendMouseCommandAndCompareAck; + request.commands[5].command = kPS2C_SendCommandAndCompareAck; request.commands[5].inOrOut = kDP_GetMouseInformation; request.commands[6].command = kPS2C_ReadDataPort; request.commands[6].inOrOut = 0; @@ -804,17 +802,17 @@ void ApplePS2ALPSGlidePoint::setAbsoluteMode() { // (read command byte) TPS2Request<6> request; - request.commands[0].command = kPS2C_SendMouseCommandAndCompareAck; + request.commands[0].command = kPS2C_SendCommandAndCompareAck; request.commands[0].inOrOut = kDP_SetDefaultsAndDisable; - request.commands[1].command = kPS2C_SendMouseCommandAndCompareAck; + request.commands[1].command = kPS2C_SendCommandAndCompareAck; request.commands[1].inOrOut = kDP_SetDefaultsAndDisable; - request.commands[2].command = kPS2C_SendMouseCommandAndCompareAck; + request.commands[2].command = kPS2C_SendCommandAndCompareAck; request.commands[2].inOrOut = kDP_SetDefaultsAndDisable; - request.commands[3].command = kPS2C_SendMouseCommandAndCompareAck; + request.commands[3].command = kPS2C_SendCommandAndCompareAck; request.commands[3].inOrOut = kDP_SetDefaultsAndDisable; - request.commands[4].command = kPS2C_SendMouseCommandAndCompareAck; + request.commands[4].command = kPS2C_SendCommandAndCompareAck; request.commands[4].inOrOut = kDP_Enable; - request.commands[5].command = kPS2C_SendMouseCommandAndCompareAck; + request.commands[5].command = kPS2C_SendCommandAndCompareAck; request.commands[5].inOrOut = 0xF0; //Set poll ??! request.commandsCount = 6; assert(request.commandsCount <= countof(request.commands)); diff --git a/VoodooPS2Trackpad/VoodooPS2Elan.cpp b/VoodooPS2Trackpad/VoodooPS2Elan.cpp index 1f3f2fcf..fa98e20a 100644 --- a/VoodooPS2Trackpad/VoodooPS2Elan.cpp +++ b/VoodooPS2Trackpad/VoodooPS2Elan.cpp @@ -636,7 +636,7 @@ bool ApplePS2Elan::notificationHIDAttachedHandler(void *refCon, IOService *newSe template int ApplePS2Elan::ps2_command(UInt8 *params, unsigned int command) { TPS2Request<1 + I> request; - request.commands[0].command = kPS2C_SendMouseCommandAndCompareAck; + request.commands[0].command = kPS2C_SendCommandAndCompareAck; request.commands[0].inOrOut = command; for (int i = 0; i < I; i++) { request.commands[1 + i].command = kPS2C_ReadDataPort; @@ -689,15 +689,15 @@ int ApplePS2Elan::ps2_sliced_command(UInt8 command) { int j = 0; TPS2Request<> request; - request.commands[j].command = kPS2C_SendMouseCommandAndCompareAck; + request.commands[j].command = kPS2C_SendCommandAndCompareAck; 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].command = kPS2C_SendCommandAndCompareAck; request.commands[j++].inOrOut = kDP_SetMouseResolution; - request.commands[j].command = kPS2C_SendMouseCommandAndCompareAck; + request.commands[j].command = kPS2C_SendCommandAndCompareAck; request.commands[j++].inOrOut = d; } @@ -1164,19 +1164,19 @@ int ApplePS2Elan::elantechSetupPS2() { // set resolution and dpi TPS2Request<> request; - request.commands[0].command = kPS2C_SendMouseCommandAndCompareAck; + request.commands[0].command = kPS2C_SendCommandAndCompareAck; request.commands[0].inOrOut = kDP_SetDefaultsAndDisable; // 0xF5, Disable data reporting - request.commands[1].command = kPS2C_SendMouseCommandAndCompareAck; + request.commands[1].command = kPS2C_SendCommandAndCompareAck; request.commands[1].inOrOut = kDP_SetMouseSampleRate; // 0xF3 - request.commands[2].command = kPS2C_SendMouseCommandAndCompareAck; + request.commands[2].command = kPS2C_SendCommandAndCompareAck; request.commands[2].inOrOut = _mouseSampleRate; // 200 dpi - request.commands[3].command = kPS2C_SendMouseCommandAndCompareAck; + request.commands[3].command = kPS2C_SendCommandAndCompareAck; request.commands[3].inOrOut = kDP_SetMouseResolution; // 0xE8 - request.commands[4].command = kPS2C_SendMouseCommandAndCompareAck; + request.commands[4].command = kPS2C_SendCommandAndCompareAck; request.commands[4].inOrOut = _mouseResolution; // 0x03 = 8 counts/mm - request.commands[5].command = kPS2C_SendMouseCommandAndCompareAck; + request.commands[5].command = kPS2C_SendCommandAndCompareAck; request.commands[5].inOrOut = kDP_SetMouseScaling1To1; // 0xE6 - request.commands[6].command = kPS2C_SendMouseCommandAndCompareAck; + request.commands[6].command = kPS2C_SendCommandAndCompareAck; request.commands[6].inOrOut = kDP_Enable; // 0xF4, Enable Data Reporting request.commandsCount = 7; _device->submitRequestAndBlock(&request); diff --git a/VoodooPS2Trackpad/VoodooPS2SentelicFSP.cpp b/VoodooPS2Trackpad/VoodooPS2SentelicFSP.cpp index 3fbc4087..84e9eeaf 100644 --- a/VoodooPS2Trackpad/VoodooPS2SentelicFSP.cpp +++ b/VoodooPS2Trackpad/VoodooPS2SentelicFSP.cpp @@ -91,19 +91,17 @@ bool ApplePS2SentelicFSP::init(OSDictionary* dict) int fsp_ps2_command(ApplePS2MouseDevice * device, PS2Request * request, int cmd) { - request->commands[0].command = kPS2C_WriteCommandPort; - request->commands[0].inOrOut = kCP_TransmitToMouse; - request->commands[1].command = kPS2C_WriteDataPort; - request->commands[1].inOrOut = cmd; - request->commands[2].command = kPS2C_ReadDataPort; - request->commands[2].inOrOut = 0; + request->commands[0].command = kPS2C_WriteDataPort; + request->commands[0].inOrOut = cmd; + request->commands[1].command = kPS2C_ReadDataPort; + request->commands[1].inOrOut = 0; - request->commandsCount = 3; + request->commandsCount = 2; device->submitRequestAndBlock(request); //IOLog("ApplePS2Trackpad: Sentelic FSP: fsp_ps2_command(cmd = %0x) => %0x\n", cmd, request->commands[2].inOrOut); - return (request->commandsCount == 3) ? request->commands[2].inOrOut : -1; + return (request->commandsCount == 2) ? request->commands[1].inOrOut : -1; } unsigned int fsp_reg_read(ApplePS2MouseDevice * device, PS2Request * request, int reg) @@ -127,7 +125,7 @@ unsigned int fsp_reg_read(ApplePS2MouseDevice * device, PS2Request * request, in fsp_ps2_command(device, request, register_select); fsp_ps2_command(device, request, register_value); - request->commands[0].command = kPS2C_SendMouseCommandAndCompareAck; + request->commands[0].command = kPS2C_SendCommandAndCompareAck; request->commands[0].inOrOut = kDP_GetMouseInformation; request->commands[1].command = kPS2C_ReadDataPort; request->commands[1].inOrOut = 0; @@ -211,22 +209,22 @@ void fsp_opctag_enable(ApplePS2MouseDevice * device, PS2Request * request, int e int fsp_intellimouse_mode(ApplePS2MouseDevice * device, PS2Request * request) { - request->commands[0].command = kPS2C_SendMouseCommandAndCompareAck; + request->commands[0].command = kPS2C_SendCommandAndCompareAck; request->commands[0].inOrOut = kDP_SetMouseSampleRate; - request->commands[1].command = kPS2C_SendMouseCommandAndCompareAck; + request->commands[1].command = kPS2C_SendCommandAndCompareAck; request->commands[1].inOrOut = 200; - request->commands[2].command = kPS2C_SendMouseCommandAndCompareAck; + request->commands[2].command = kPS2C_SendCommandAndCompareAck; request->commands[2].inOrOut = kDP_SetMouseSampleRate; - request->commands[3].command = kPS2C_SendMouseCommandAndCompareAck; + request->commands[3].command = kPS2C_SendCommandAndCompareAck; request->commands[3].inOrOut = 200; - request->commands[4].command = kPS2C_SendMouseCommandAndCompareAck; + request->commands[4].command = kPS2C_SendCommandAndCompareAck; request->commands[4].inOrOut = kDP_SetMouseSampleRate; - request->commands[5].command = kPS2C_SendMouseCommandAndCompareAck; + request->commands[5].command = kPS2C_SendCommandAndCompareAck; request->commands[5].inOrOut = 80; - request->commands[6].command = kPS2C_SendMouseCommandAndCompareAck; + request->commands[6].command = kPS2C_SendCommandAndCompareAck; request->commands[6].inOrOut = kDP_GetId; request->commands[7].command = kPS2C_ReadDataPort; request->commands[7].inOrOut = 0; @@ -519,7 +517,7 @@ void ApplePS2SentelicFSP::setTouchPadEnable( bool enable ) // (mouse enable/disable command) TPS2Request<> request; - request.commands[0].command = kPS2C_SendMouseCommandAndCompareAck; + request.commands[0].command = kPS2C_SendCommandAndCompareAck; request.commands[0].inOrOut = enable ? kDP_Enable : kDP_SetDefaultsAndDisable; request.commandsCount = 1; assert(request.commandsCount <= countof(request.commands)); @@ -540,32 +538,32 @@ UInt32 ApplePS2SentelicFSP::getTouchPadData( UInt8 dataSelector ) TPS2Request<13> request; // Disable stream mode before the command sequence. - request.commands[0].command = kPS2C_SendMouseCommandAndCompareAck; + request.commands[0].command = kPS2C_SendCommandAndCompareAck; request.commands[0].inOrOut = kDP_SetDefaultsAndDisable; // 4 set resolution commands, each encode 2 data bits. - request.commands[1].command = kPS2C_SendMouseCommandAndCompareAck; + request.commands[1].command = kPS2C_SendCommandAndCompareAck; request.commands[1].inOrOut = kDP_SetMouseResolution; - request.commands[2].command = kPS2C_SendMouseCommandAndCompareAck; + request.commands[2].command = kPS2C_SendCommandAndCompareAck; request.commands[2].inOrOut = (dataSelector >> 6) & 0x3; - request.commands[3].command = kPS2C_SendMouseCommandAndCompareAck; + request.commands[3].command = kPS2C_SendCommandAndCompareAck; request.commands[3].inOrOut = kDP_SetMouseResolution; - request.commands[4].command = kPS2C_SendMouseCommandAndCompareAck; + request.commands[4].command = kPS2C_SendCommandAndCompareAck; request.commands[4].inOrOut = (dataSelector >> 4) & 0x3; - request.commands[5].command = kPS2C_SendMouseCommandAndCompareAck; + request.commands[5].command = kPS2C_SendCommandAndCompareAck; request.commands[5].inOrOut = kDP_SetMouseResolution; - request.commands[6].command = kPS2C_SendMouseCommandAndCompareAck; + request.commands[6].command = kPS2C_SendCommandAndCompareAck; request.commands[6].inOrOut = (dataSelector >> 2) & 0x3; - request.commands[7].command = kPS2C_SendMouseCommandAndCompareAck; + request.commands[7].command = kPS2C_SendCommandAndCompareAck; request.commands[7].inOrOut = kDP_SetMouseResolution; - request.commands[8].command = kPS2C_SendMouseCommandAndCompareAck; + request.commands[8].command = kPS2C_SendCommandAndCompareAck; request.commands[8].inOrOut = (dataSelector >> 0) & 0x3; // Read response bytes. - request.commands[9].command = kPS2C_SendMouseCommandAndCompareAck; + request.commands[9].command = kPS2C_SendCommandAndCompareAck; request.commands[9].inOrOut = kDP_GetMouseInformation; request.commands[10].command = kPS2C_ReadDataPort; request.commands[10].inOrOut = 0; @@ -663,38 +661,38 @@ bool ApplePS2SentelicFSP::setTouchPadModeByte(UInt8 modeByteValue, bool enableSt TPS2Request<12> request; // Disable stream mode before the command sequence. - request.commands[0].command = kPS2C_SendMouseCommandAndCompareAck; + request.commands[0].command = kPS2C_SendCommandAndCompareAck; request.commands[0].inOrOut = kDP_SetDefaultsAndDisable; // 4 set resolution commands, each encode 2 data bits. - request.commands[1].command = kPS2C_SendMouseCommandAndCompareAck; + request.commands[1].command = kPS2C_SendCommandAndCompareAck; request.commands[1].inOrOut = kDP_SetMouseResolution; - request.commands[2].command = kPS2C_SendMouseCommandAndCompareAck; + request.commands[2].command = kPS2C_SendCommandAndCompareAck; request.commands[2].inOrOut = (modeByteValue >> 6) & 0x3; - request.commands[3].command = kPS2C_SendMouseCommandAndCompareAck; + request.commands[3].command = kPS2C_SendCommandAndCompareAck; request.commands[3].inOrOut = kDP_SetMouseResolution; - request.commands[4].command = kPS2C_SendMouseCommandAndCompareAck; + request.commands[4].command = kPS2C_SendCommandAndCompareAck; request.commands[4].inOrOut = (modeByteValue >> 4) & 0x3; - request.commands[5].command = kPS2C_SendMouseCommandAndCompareAck; + request.commands[5].command = kPS2C_SendCommandAndCompareAck; request.commands[5].inOrOut = kDP_SetMouseResolution; - request.commands[6].command = kPS2C_SendMouseCommandAndCompareAck; + request.commands[6].command = kPS2C_SendCommandAndCompareAck; request.commands[6].inOrOut = (modeByteValue >> 2) & 0x3; - request.commands[7].command = kPS2C_SendMouseCommandAndCompareAck; + request.commands[7].command = kPS2C_SendCommandAndCompareAck; request.commands[7].inOrOut = kDP_SetMouseResolution; - request.commands[8].command = kPS2C_SendMouseCommandAndCompareAck; + request.commands[8].command = kPS2C_SendCommandAndCompareAck; request.commands[8].inOrOut = (modeByteValue >> 0) & 0x3; // Set sample rate 20 to set mode byte 2. Older pads have 4 mode // bytes (0,1,2,3), but only mode byte 2 remain in modern pads. - request.commands[9].command = kPS2C_SendMouseCommandAndCompareAck; + request.commands[9].command = kPS2C_SendCommandAndCompareAck; request.commands[9].inOrOut = kDP_SetMouseSampleRate; - request.commands[10].command = kPS2C_SendMouseCommandAndCompareAck; + request.commands[10].command = kPS2C_SendCommandAndCompareAck; request.commands[10].inOrOut = 20; - request.commands[11].command = kPS2C_SendMouseCommandAndCompareAck; + request.commands[11].command = kPS2C_SendCommandAndCompareAck; request.commands[11].inOrOut = enableStreamMode ? kDP_Enable : kDP_SetMouseScaling1To1; request.commandsCount = 12; assert(request.commandsCount <= countof(request.commands)); diff --git a/VoodooPS2Trackpad/VoodooPS2SynapticsTouchPad.cpp b/VoodooPS2Trackpad/VoodooPS2SynapticsTouchPad.cpp index 685a16b6..e48af335 100644 --- a/VoodooPS2Trackpad/VoodooPS2SynapticsTouchPad.cpp +++ b/VoodooPS2Trackpad/VoodooPS2SynapticsTouchPad.cpp @@ -190,7 +190,7 @@ ApplePS2SynapticsTouchPad* ApplePS2SynapticsTouchPad::probe(IOService * provider else { INFO_LOG("VoodooPS2Trackpad: Identify bytes = { 0x%x, 0x%x, 0x%x }\n", buf3[0], buf3[1], buf3[2]); - if (0x46 != buf3[1] && 0x47 != buf3[1]) + if (0x47 != buf3[1]) { IOLog("VoodooPS2Trackpad: Identify TouchPad command returned incorrect byte 2 (of 3): 0x%02x\n", buf3[1]); } @@ -199,9 +199,6 @@ ApplePS2SynapticsTouchPad* ApplePS2SynapticsTouchPad::probe(IOService * provider if (success) { - // some synaptics touchpads return 0x46 in byte2 and have a different numbering scheme - // this is all experimental for those touchpads - // most synaptics touchpads return 0x47, and we only support v4.0 or better // in the case of 0x46, we allow versions as low as v2.0 @@ -218,17 +215,7 @@ ApplePS2SynapticsTouchPad* ApplePS2SynapticsTouchPad::probe(IOService * provider // Only support 4.x or later touchpads. success = _touchPadVersion >= 0x400; } - if (0x46 == buf3[1]) - { - // for diagnostics... - if ( _touchPadVersion < 0x200) - { - IOLog("VoodooPS2Trackpad: TouchPad(0x46) v%d.%d is not supported\n", - (UInt8)(_touchPadVersion >> 8), (UInt8)(_touchPadVersion)); - } - // Only support 2.x or later touchpads. - success = _touchPadVersion >= 0x200; - } + if (forceSynaptics) { IOLog("VoodooPS2Trackpad: Forcing Synaptics detection due to ForceSynapticsDetect\n"); @@ -249,21 +236,19 @@ void ApplePS2SynapticsTouchPad::doHardwareReset() { TPS2Request<> request; int i = 0; - request.commands[i].command = kPS2C_SendMouseCommandAndCompareAck; + request.commands[i].command = kPS2C_SendCommandAndCompareAck; request.commands[i++].inOrOut = kDP_SetDefaultsAndDisable; // F5 - request.commands[i].command = kPS2C_SendMouseCommandAndCompareAck; + request.commands[i].command = kPS2C_SendCommandAndCompareAck; request.commands[i++].inOrOut = kDP_SetDefaultsAndDisable; // F5 - request.commands[i].command = kPS2C_WriteCommandPort; - request.commands[i++].inOrOut = kCP_TransmitToMouse; request.commands[i].command = kPS2C_WriteDataPort; request.commands[i++].inOrOut = kDP_Reset; // FF request.commands[i].command = kPS2C_ReadDataPortAndCompare; request.commands[i++].inOrOut = kSC_Acknowledge; request.commands[i].command = kPS2C_SleepMS; request.commands[i++].inOrOut32 = wakedelay*2; - request.commands[i].command = kPS2C_ReadMouseDataPortAndCompare; + request.commands[i].command = kPS2C_ReadDataPortAndCompare; request.commands[i++].inOrOut = 0xAA; - request.commands[i].command = kPS2C_ReadMouseDataPortAndCompare; + request.commands[i].command = kPS2C_ReadDataPortAndCompare; request.commands[i++].inOrOut = 0x00; request.commandsCount = i; DEBUG_LOG("VoodooPS2Trackpad: sending kDP_Reset $FF\n"); @@ -1847,7 +1832,7 @@ void ApplePS2SynapticsTouchPad::setTouchPadEnable( bool enable ) // (mouse enable/disable command) TPS2Request<1> request; - request.commands[0].command = kPS2C_SendMouseCommandAndCompareAck; + request.commands[0].command = kPS2C_SendCommandAndCompareAck; request.commands[0].inOrOut = enable ? kDP_Enable : kDP_SetDefaultsAndDisable; request.commandsCount = 1; assert(request.commandsCount <= countof(request.commands)); @@ -1859,9 +1844,9 @@ void ApplePS2SynapticsTouchPad::setTouchPadEnable( bool enable ) bool ApplePS2SynapticsTouchPad::getTouchPadStatus( UInt8 buf3[] ) { TPS2Request<6> request; - request.commands[0].command = kPS2C_SendMouseCommandAndCompareAck; + request.commands[0].command = kPS2C_SendCommandAndCompareAck; request.commands[0].inOrOut = kDP_SetDefaultsAndDisable; - request.commands[1].command = kPS2C_SendMouseCommandAndCompareAck; + request.commands[1].command = kPS2C_SendCommandAndCompareAck; request.commands[1].inOrOut = kDP_GetMouseInformation; request.commands[2].command = kPS2C_ReadDataPort; request.commands[2].inOrOut = 0; @@ -1869,7 +1854,7 @@ bool ApplePS2SynapticsTouchPad::getTouchPadStatus( UInt8 buf3[] ) request.commands[3].inOrOut = 0; request.commands[4].command = kPS2C_ReadDataPort; request.commands[4].inOrOut = 0; - request.commands[5].command = kPS2C_SendMouseCommandAndCompareAck; + request.commands[5].command = kPS2C_SendCommandAndCompareAck; request.commands[5].inOrOut = kDP_SetDefaultsAndDisable; request.commandsCount = 6; assert(request.commandsCount <= countof(request.commands)); @@ -1890,32 +1875,32 @@ bool ApplePS2SynapticsTouchPad::getTouchPadData(UInt8 dataSelector, UInt8 buf3[] TPS2Request<14> request; // Disable stream mode before the command sequence. - request.commands[0].command = kPS2C_SendMouseCommandAndCompareAck; + request.commands[0].command = kPS2C_SendCommandAndCompareAck; request.commands[0].inOrOut = kDP_SetDefaultsAndDisable; // 4 set resolution commands, each encode 2 data bits. - request.commands[1].command = kPS2C_SendMouseCommandAndCompareAck; + request.commands[1].command = kPS2C_SendCommandAndCompareAck; request.commands[1].inOrOut = kDP_SetMouseResolution; - request.commands[2].command = kPS2C_SendMouseCommandAndCompareAck; + request.commands[2].command = kPS2C_SendCommandAndCompareAck; request.commands[2].inOrOut = (dataSelector >> 6) & 0x3; - request.commands[3].command = kPS2C_SendMouseCommandAndCompareAck; + request.commands[3].command = kPS2C_SendCommandAndCompareAck; request.commands[3].inOrOut = kDP_SetMouseResolution; - request.commands[4].command = kPS2C_SendMouseCommandAndCompareAck; + request.commands[4].command = kPS2C_SendCommandAndCompareAck; request.commands[4].inOrOut = (dataSelector >> 4) & 0x3; - request.commands[5].command = kPS2C_SendMouseCommandAndCompareAck; + request.commands[5].command = kPS2C_SendCommandAndCompareAck; request.commands[5].inOrOut = kDP_SetMouseResolution; - request.commands[6].command = kPS2C_SendMouseCommandAndCompareAck; + request.commands[6].command = kPS2C_SendCommandAndCompareAck; request.commands[6].inOrOut = (dataSelector >> 2) & 0x3; - request.commands[7].command = kPS2C_SendMouseCommandAndCompareAck; + request.commands[7].command = kPS2C_SendCommandAndCompareAck; request.commands[7].inOrOut = kDP_SetMouseResolution; - request.commands[8].command = kPS2C_SendMouseCommandAndCompareAck; + request.commands[8].command = kPS2C_SendCommandAndCompareAck; request.commands[8].inOrOut = (dataSelector >> 0) & 0x3; // Read response bytes. - request.commands[9].command = kPS2C_SendMouseCommandAndCompareAck; + request.commands[9].command = kPS2C_SendCommandAndCompareAck; request.commands[9].inOrOut = kDP_GetMouseInformation; request.commands[10].command = kPS2C_ReadDataPort; request.commands[10].inOrOut = 0; @@ -1923,7 +1908,7 @@ bool ApplePS2SynapticsTouchPad::getTouchPadData(UInt8 dataSelector, UInt8 buf3[] request.commands[11].inOrOut = 0; request.commands[12].command = kPS2C_ReadDataPort; request.commands[12].inOrOut = 0; - request.commands[13].command = kPS2C_SendMouseCommandAndCompareAck; + request.commands[13].command = kPS2C_SendCommandAndCompareAck; request.commands[13].inOrOut = kDP_SetDefaultsAndDisable; request.commandsCount = 14; assert(request.commandsCount <= countof(request.commands)); @@ -2097,7 +2082,7 @@ bool ApplePS2SynapticsTouchPad::setTouchPadModeByte(UInt8 modeByteValue) // all these commands are "send mouse" and "compare ack" for (int x = 0; x < i; x++) - request.commands[x].command = kPS2C_SendMouseCommandAndCompareAck; + request.commands[x].command = kPS2C_SendCommandAndCompareAck; request.commandsCount = i; assert(request.commandsCount <= countof(request.commands)); _device->submitRequestAndBlock(&request); @@ -2166,7 +2151,7 @@ bool ApplePS2SynapticsTouchPad::setModeByte(UInt8 modeByteValue) // all these commands are "send mouse" and "compare ack" for (int x = 0; x < i; x++) - request.commands[x].command = kPS2C_SendMouseCommandAndCompareAck; + request.commands[x].command = kPS2C_SendCommandAndCompareAck; request.commandsCount = i; assert(request.commandsCount <= countof(request.commands)); _device->submitRequestAndBlock(&request); @@ -2606,7 +2591,7 @@ bool ApplePS2SynapticsTouchPad::setTouchpadLED(UInt8 touchLED) // all these commands are "send mouse" and "compare ack" for (int x = 0; x < request.commandsCount; x++) - request.commands[x].command = kPS2C_SendMouseCommandAndCompareAck; + request.commands[x].command = kPS2C_SendCommandAndCompareAck; _device->submitRequestAndBlock(&request); return 12 == request.commandsCount; From b4d9958f02c9b439b2fcdebce504c5271d1e17d4 Mon Sep 17 00:00:00 2001 From: Vitaly Cheptsov <4348897+vit9696@users.noreply.github.com> Date: Fri, 20 Aug 2021 09:28:38 +0300 Subject: [PATCH 049/101] Sync changelog --- Changelog.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Changelog.md b/Changelog.md index 4f0c6bfb..00b49200 100644 --- a/Changelog.md +++ b/Changelog.md @@ -1,5 +1,8 @@ VoodooPS2 Changelog ============================ +#### v2.2.5 +- Added support for touchpads with multiplexors + #### v2.2.4 - Fixed incorrect command gate initialization causing panics From dd91aaebe8449f7401edda308321b6de00b25be4 Mon Sep 17 00:00:00 2001 From: Avery Black Date: Sun, 22 Aug 2021 02:56:12 -0700 Subject: [PATCH 050/101] Remove less than 0 checks (#39) --- VoodooPS2Controller/VoodooPS2Controller.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/VoodooPS2Controller/VoodooPS2Controller.cpp b/VoodooPS2Controller/VoodooPS2Controller.cpp index 10490714..dc85fb36 100644 --- a/VoodooPS2Controller/VoodooPS2Controller.cpp +++ b/VoodooPS2Controller/VoodooPS2Controller.cpp @@ -948,7 +948,7 @@ void ApplePS2Controller::setCommandByteGated(PS2Request* request) bool ApplePS2Controller::submitRequest(PS2Request * request) { // Make sure that the request is in bounds - if (request->port >= kPS2MaxIdx || request->port < kPS2KbdIdx) + if (request->port >= kPS2MaxIdx) return false; // Check that we only read from ports which are active in mux mode @@ -973,7 +973,7 @@ bool ApplePS2Controller::submitRequest(PS2Request * request) void ApplePS2Controller::submitRequestAndBlock(PS2Request * request) { // Make sure that the request is in bounds - if (request->port >= kPS2MaxIdx || request->port < kPS2KbdIdx) + if (request->port >= kPS2MaxIdx) return; // Check that we only read from ports which are active in mux mode From d218f511cca544292cf5903cc41aba1104e1f6d3 Mon Sep 17 00:00:00 2001 From: Andrey1970AppleLife Date: Tue, 7 Sep 2021 22:18:28 +0300 Subject: [PATCH 051/101] 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 ad5d1890..a875f512 100644 --- a/VoodooPS2Controller.xcodeproj/project.pbxproj +++ b/VoodooPS2Controller.xcodeproj/project.pbxproj @@ -767,7 +767,7 @@ KERNEL_FRAMEWORK_HEADERS = "$(PROJECT_DIR)/MacKernelSDK/Headers"; "LLVM_LTO[arch=x86_64]" = YES; MACOSX_DEPLOYMENT_TARGET = 10.11; - MODULE_VERSION = 2.2.5; + MODULE_VERSION = 2.2.6; ONLY_ACTIVE_ARCH = YES; "OTHER_LDFLAGS[arch=x86_64]" = "-dead_strip"; PRODUCT_NAME = VoodooPS2Controller; @@ -822,7 +822,7 @@ KERNEL_FRAMEWORK_HEADERS = "$(PROJECT_DIR)/MacKernelSDK/Headers"; "LLVM_LTO[arch=x86_64]" = YES; MACOSX_DEPLOYMENT_TARGET = 10.11; - MODULE_VERSION = 2.2.5; + MODULE_VERSION = 2.2.6; "OTHER_LDFLAGS[arch=x86_64]" = "-dead_strip"; PRODUCT_NAME = VoodooPS2Controller; SDKROOT = macosx; From 4bdf2d430141f379178746d3f24c73001d7e2b22 Mon Sep 17 00:00:00 2001 From: Avery Black Date: Sat, 2 Oct 2021 15:38:35 -0700 Subject: [PATCH 052/101] Fix power actions in multiplexing mode (#40) --- VoodooPS2Controller/VoodooPS2Controller.cpp | 90 +++++++++---------- VoodooPS2Controller/VoodooPS2Controller.h | 10 ++- .../VoodooPS2SynapticsTouchPad.cpp | 2 +- 3 files changed, 47 insertions(+), 55 deletions(-) diff --git a/VoodooPS2Controller/VoodooPS2Controller.cpp b/VoodooPS2Controller/VoodooPS2Controller.cpp index dc85fb36..03724f3d 100644 --- a/VoodooPS2Controller/VoodooPS2Controller.cpp +++ b/VoodooPS2Controller/VoodooPS2Controller.cpp @@ -214,7 +214,7 @@ void ApplePS2Controller::handleInterrupt(bool watchdog) } // while (forever) // wake up workloop based mouse interrupt source if needed - size_t max_idx = _mux_present ? kPS2MaxIdx : kPS2MuxIdx; + size_t max_idx = _muxPresent ? kPS2MaxIdx : kPS2MuxIdx; for (size_t i = kPS2KbdIdx; i < max_idx; i++) { if (wakePort[i] && _devices[i] != nullptr) { @@ -423,10 +423,10 @@ void ApplePS2Controller::resetController(void) writeDataPort(kDP_SetDefaultsAndDisable); readDataPort(kPS2KbdIdx); // (discard acknowledge; success irrelevant) - - if (hasMux()) + + if (setMuxMode(true)) { - _mux_present = true; + _muxPresent = true; for (size_t i = 0; i < PS2_MUX_PORTS; i++) { writeCommandPort(kCP_TransmitToMuxedMouse + i); @@ -456,29 +456,39 @@ void ApplePS2Controller::resetController(void) // -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -bool ApplePS2Controller::hasMux() +bool ApplePS2Controller::setMuxMode(bool enable) { + UInt8 param = kDP_MuxCmd; + // getPortFromStatus will return kPS2MuxIdx when _muxPresent is true + size_t readPort = _muxPresent ? kPS2MuxIdx : kPS2AuxIdx; + writeCommandPort(kCP_WriteMouseOutputBuffer); - writeDataPort(kDP_EnableMuxCmd1); - if (readDataPort(kPS2AuxIdx) != kDP_EnableMuxCmd1) + writeDataPort(param); + if (readDataPort(readPort) != param) return false; + + param = enable ? kDP_EnableMuxCmd1 : kDP_DisableMuxCmd1; writeCommandPort(kCP_WriteMouseOutputBuffer); - writeDataPort(kDP_EnableMuxCmd2); - if (readDataPort(kPS2AuxIdx) != kDP_EnableMuxCmd2) + writeDataPort(param); + if (readDataPort(readPort) != param) return false; + + param = enable ? kDP_GetMuxVersion : kDP_DisableMuxCmd2; writeCommandPort(kCP_WriteMouseOutputBuffer); - writeDataPort(kDP_GetMuxVersion); - UInt8 ver = readDataPort(kPS2AuxIdx); - if (ver == kDP_GetMuxVersion) - { - return false; - } + writeDataPort(param); + UInt8 ver = readDataPort(readPort); + // We want the version on enable, and original command on disable + if ((enable && ver == param) || + (!enable && ver != param)) + return false; + // Only log first time - if (!_mux_present) + if (!_muxPresent) { - IOLog("ApplePS2Controller::hasMux = true - version: %x\n", ver); + IOLog("ApplePS2Controller::setMuxMode = true - version: %x\n", ver); } + return true; } @@ -619,7 +629,7 @@ bool ApplePS2Controller::start(IOService * provider) } - if (_mux_present) + if (_muxPresent) { for (size_t i = kPS2MuxIdx; i < kPS2MaxIdx; i++) { @@ -816,7 +826,7 @@ void ApplePS2Controller::installInterruptAction(size_t port) if (!_interruptInstalledMouse) { DEBUG_LOG("%s: setCommandByte for mouse interrupt install\n", getName()); - if (_mux_present) + if (_muxPresent) { enableMuxPorts(); } @@ -947,14 +957,7 @@ void ApplePS2Controller::setCommandByteGated(PS2Request* request) bool ApplePS2Controller::submitRequest(PS2Request * request) { - // Make sure that the request is in bounds - if (request->port >= kPS2MaxIdx) - return false; - - // Check that we only read from ports which are active in mux mode - if ((_mux_present && request->port == kPS2AuxIdx) || - (!_mux_present && request->port > kPS2AuxIdx)) - return false; + assert(request->port < kPS2MaxIdx); // // Submit the request to the controller for processing, asynchronously. @@ -972,14 +975,7 @@ bool ApplePS2Controller::submitRequest(PS2Request * request) void ApplePS2Controller::submitRequestAndBlock(PS2Request * request) { - // Make sure that the request is in bounds - if (request->port >= kPS2MaxIdx) - return; - - // Check that we only read from ports which are active in mux mode - if ((_mux_present && request->port == kPS2AuxIdx) || - (!_mux_present && request->port > kPS2AuxIdx)) - return; + assert(request->port < kPS2MaxIdx); _cmdGate->runAction(OSMemberFunctionCast(IOCommandGate::Action, this, &ApplePS2Controller::submitRequestAndBlockGated), request); } @@ -1252,14 +1248,14 @@ void ApplePS2Controller::processRequestQueue(IOInterruptEventSource *, int) size_t ApplePS2Controller::getPortFromStatus(UInt8 status) { - bool aux_port = status & kMouseData; - if (_mux_present && aux_port) + bool auxPort = status & kMouseData; + if (_muxPresent && auxPort) { return kPS2MuxIdx + ((status >> 6) & 3); } else { - return aux_port ? kPS2AuxIdx : kPS2KbdIdx; + return auxPort ? kPS2AuxIdx : kPS2KbdIdx; } } @@ -1884,7 +1880,7 @@ void ApplePS2Controller::setPowerStateGated( UInt32 powerState ) // 1. Enable the PS/2 port -- but just the clocks - if (_mux_present) + if (_muxPresent) { enableMuxPorts(); } @@ -1939,12 +1935,9 @@ void ApplePS2Controller::setPowerStateGated( UInt32 powerState ) void ApplePS2Controller::dispatchDriverPowerControl( UInt32 whatToDo, size_t port ) { - // Should just be called with kPS2Aux or kPS2Kbd - // This will do power control on all mice if called with kPS2Aux - if (port > kPS2AuxIdx || _devices[port] == nullptr) - { - return; - } + // Should be called with kPS2Aux or kPS2Kbd. + // "port" set to kPS2Aux will run the power action for all mux ports + assert (port < kPS2MuxIdx); if (port == kPS2KbdIdx) { @@ -1952,16 +1945,13 @@ void ApplePS2Controller::dispatchDriverPowerControl( UInt32 whatToDo, size_t por return; } - if (!_mux_present) { + if (!_muxPresent) { _devices[kPS2AuxIdx]->powerAction(whatToDo); return; } for (size_t i = kPS2MuxIdx; i < kPS2MaxIdx; i++) { - if (_devices[i]) - { - _devices[i]->powerAction(whatToDo); - } + _devices[i]->powerAction(whatToDo); } } diff --git a/VoodooPS2Controller/VoodooPS2Controller.h b/VoodooPS2Controller/VoodooPS2Controller.h index 6eb61f20..25d37583 100644 --- a/VoodooPS2Controller/VoodooPS2Controller.h +++ b/VoodooPS2Controller/VoodooPS2Controller.h @@ -150,9 +150,11 @@ class ApplePS2MouseDevice; // Constants are from Linux // https://github.com/torvalds/linux/blob/c2d7ed9d680fd14aa5486518bd0d0fa5963c6403/drivers/input/serio/i8042.c#L685-L693 -#define kDP_EnableMuxCmd1 0xF0 -#define kDP_EnableMuxCmd2 0x56 +#define kDP_MuxCmd 0xF0 +#define kDP_EnableMuxCmd1 0x56 #define kDP_GetMuxVersion 0xA4 +#define kDP_DisableMuxCmd1 0xF6 +#define kDP_DisableMuxCmd2 0xA5 #if DEBUGGER_SUPPORT // Definitions for our internal keyboard queue (holds keys processed by the @@ -270,7 +272,7 @@ class EXPORT ApplePS2Controller : public IOService bool _suppressTimeout {false}; int _wakedelay {10}; bool _mouseWakeFirst {false}; - bool _mux_present {false}; + bool _muxPresent {false}; IOCommandGate* _cmdGate {nullptr}; #if WATCHDOG_TIMER IOTimerEventSource* _watchdogTimer {nullptr}; @@ -300,7 +302,7 @@ class EXPORT ApplePS2Controller : public IOService virtual void writeCommandPort(UInt8 byte); virtual void writeDataPort(UInt8 byte); void resetController(void); - bool hasMux(void); + bool setMuxMode(bool); static void interruptHandlerMouse(OSObject*, void* refCon, IOService*, int); static void interruptHandlerKeyboard(OSObject*, void* refCon, IOService*, int); diff --git a/VoodooPS2Trackpad/VoodooPS2SynapticsTouchPad.cpp b/VoodooPS2Trackpad/VoodooPS2SynapticsTouchPad.cpp index e48af335..0abb0a6f 100644 --- a/VoodooPS2Trackpad/VoodooPS2SynapticsTouchPad.cpp +++ b/VoodooPS2Trackpad/VoodooPS2SynapticsTouchPad.cpp @@ -387,7 +387,7 @@ void ApplePS2SynapticsTouchPad::queryCapabilities() if (buf3[1] & 0x40) { - IOLog("VoodooPS2Trackpad: Trackpad supports SMBus operation"); + IOLog("VoodooPS2Trackpad: Trackpad supports Intertouch/SMBus operation\n"); setProperty("Intertouch Support", kOSBooleanTrue); } } From aee1b3a8ffcd6719b40fc2b98c7ad820a8e87f57 Mon Sep 17 00:00:00 2001 From: Vitaly Cheptsov <4348897+vit9696@users.noreply.github.com> Date: Sun, 3 Oct 2021 19:12:05 +0300 Subject: [PATCH 053/101] Sync changelog --- Changelog.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Changelog.md b/Changelog.md index 00b49200..7239ba5b 100644 --- a/Changelog.md +++ b/Changelog.md @@ -1,5 +1,8 @@ VoodooPS2 Changelog ============================ +#### v2.2.6 +- Fixed some touchpads not waking after S3 + #### v2.2.5 - Added support for touchpads with multiplexors From dd6cf33b1e06d852174bca8702c8fb2891044ad8 Mon Sep 17 00:00:00 2001 From: Andrey1970AppleLife Date: Mon, 4 Oct 2021 22:37:48 +0300 Subject: [PATCH 054/101] 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 a875f512..13612e8b 100644 --- a/VoodooPS2Controller.xcodeproj/project.pbxproj +++ b/VoodooPS2Controller.xcodeproj/project.pbxproj @@ -767,7 +767,7 @@ KERNEL_FRAMEWORK_HEADERS = "$(PROJECT_DIR)/MacKernelSDK/Headers"; "LLVM_LTO[arch=x86_64]" = YES; MACOSX_DEPLOYMENT_TARGET = 10.11; - MODULE_VERSION = 2.2.6; + MODULE_VERSION = 2.2.7; ONLY_ACTIVE_ARCH = YES; "OTHER_LDFLAGS[arch=x86_64]" = "-dead_strip"; PRODUCT_NAME = VoodooPS2Controller; @@ -822,7 +822,7 @@ KERNEL_FRAMEWORK_HEADERS = "$(PROJECT_DIR)/MacKernelSDK/Headers"; "LLVM_LTO[arch=x86_64]" = YES; MACOSX_DEPLOYMENT_TARGET = 10.11; - MODULE_VERSION = 2.2.6; + MODULE_VERSION = 2.2.7; "OTHER_LDFLAGS[arch=x86_64]" = "-dead_strip"; PRODUCT_NAME = VoodooPS2Controller; SDKROOT = macosx; From 89988217dd5f7923a31ae9db184279fec795b610 Mon Sep 17 00:00:00 2001 From: Avery Black Date: Sun, 10 Oct 2021 11:52:37 -0700 Subject: [PATCH 055/101] Only set _muxPresent on boot (#41) --- VoodooPS2Controller/VoodooPS2Controller.cpp | 84 ++++++++++++--------- VoodooPS2Controller/VoodooPS2Controller.h | 4 +- 2 files changed, 51 insertions(+), 37 deletions(-) diff --git a/VoodooPS2Controller/VoodooPS2Controller.cpp b/VoodooPS2Controller/VoodooPS2Controller.cpp index 03724f3d..350fa1d1 100644 --- a/VoodooPS2Controller/VoodooPS2Controller.cpp +++ b/VoodooPS2Controller/VoodooPS2Controller.cpp @@ -375,7 +375,7 @@ IOReturn ApplePS2Controller::setProperties(OSObject* props) // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void ApplePS2Controller::resetController(void) +void ApplePS2Controller::resetController(bool wakeup) { _suppressTimeout = true; UInt8 commandByte; @@ -383,13 +383,7 @@ void ApplePS2Controller::resetController(void) // Disable keyboard and mouse writeCommandPort(kCP_DisableKeyboardClock); writeCommandPort(kCP_DisableMouseClock); - // Flush any data - while ( inb(kCommandPort) & kOutputReady ) - { - IODelay(kDataDelay); - inb(kDataPort); - IODelay(kDataDelay); - } + flushDataPort(); writeCommandPort(kCP_EnableMouseClock); writeCommandPort(kCP_EnableKeyboardClock); // Read current command @@ -420,32 +414,56 @@ void ApplePS2Controller::resetController(void) writeCommandPort(kCP_SetCommandByte); writeDataPort(commandByte); DEBUG_LOG("%s: new commandByte = %02x\n", getName(), commandByte); - - writeDataPort(kDP_SetDefaultsAndDisable); - readDataPort(kPS2KbdIdx); // (discard acknowledge; success irrelevant) - - if (setMuxMode(true)) + + if (wakeup && _muxPresent) { - _muxPresent = true; - for (size_t i = 0; i < PS2_MUX_PORTS; i++) - { - writeCommandPort(kCP_TransmitToMuxedMouse + i); - writeDataPort(kDP_SetDefaultsAndDisable); - readDataPort(kPS2MuxIdx + i); // (discard acknowledge; success irrelevant) - } + setMuxMode(true); } - else + else if (!wakeup) { - writeCommandPort(kCP_TransmitToMouse); - writeDataPort(kDP_SetDefaultsAndDisable); - readDataPort(kPS2AuxIdx); // (discard acknowledge; success irrelevant) + _muxPresent = setMuxMode(true); } - + + resetDevices(); + // // Clear out garbage in the controller's input streams, before starting up // the work loop. // + + flushDataPort(); +} + +// -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + +void ApplePS2Controller::resetDevices() +{ + // Reset keyboard + writeDataPort(kDP_SetDefaultsAndDisable); + readDataPort(kPS2KbdIdx); // (discard acknowledge; success irrelevant) + + if (!_muxPresent) + { + // Reset aux device + writeCommandPort(kCP_TransmitToMouse); + writeDataPort(kDP_SetDefaultsAndDisable); + readDataPort(kPS2AuxIdx); // (discard acknowledge; success irrelevant) + return; + } + // Reset all muxed devices + for (size_t i = 0; i < PS2_MUX_PORTS; i++) + { + writeCommandPort(kCP_TransmitToMuxedMouse + i); + writeDataPort(kDP_SetDefaultsAndDisable); + readDataPort(kPS2MuxIdx + i); // (discard acknowledge; success irrelevant) + } +} + +// -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + +void ApplePS2Controller::flushDataPort() +{ while ( inb(kCommandPort) & kOutputReady ) { IODelay(kDataDelay); @@ -482,13 +500,7 @@ bool ApplePS2Controller::setMuxMode(bool enable) if ((enable && ver == param) || (!enable && ver != param)) return false; - - // Only log first time - if (!_muxPresent) - { - IOLog("ApplePS2Controller::setMuxMode = true - version: %x\n", ver); - } - + return true; } @@ -527,7 +539,7 @@ bool ApplePS2Controller::start(IOService * provider) PE_parse_boot_argn("ps2rst", &_resetControllerFlag, sizeof(_resetControllerFlag)); if (_resetControllerFlag & RESET_CONTROLLER_ON_BOOT) { - resetController(); + resetController(false); } // @@ -1868,11 +1880,11 @@ void ApplePS2Controller::setPowerStateGated( UInt32 powerState ) if (_resetControllerFlag & RESET_CONTROLLER_ON_WAKEUP) { - resetController(); + resetController(true); } - + #endif // FULL_INIT_AFTER_WAKE - + // // Transition from Sleep state to Working state in 4 stages. diff --git a/VoodooPS2Controller/VoodooPS2Controller.h b/VoodooPS2Controller/VoodooPS2Controller.h index 25d37583..aad23676 100644 --- a/VoodooPS2Controller/VoodooPS2Controller.h +++ b/VoodooPS2Controller/VoodooPS2Controller.h @@ -301,8 +301,10 @@ class EXPORT ApplePS2Controller : public IOService virtual UInt8 readDataPort(size_t port); virtual void writeCommandPort(UInt8 byte); virtual void writeDataPort(UInt8 byte); - void resetController(void); + void resetController(bool); bool setMuxMode(bool); + void flushDataPort(void); + void resetDevices(void); static void interruptHandlerMouse(OSObject*, void* refCon, IOService*, int); static void interruptHandlerKeyboard(OSObject*, void* refCon, IOService*, int); From 25335ff24971856e3f693470341d35cd7b6deb5d Mon Sep 17 00:00:00 2001 From: Vitaly Cheptsov <4348897+vit9696@users.noreply.github.com> Date: Mon, 11 Oct 2021 06:23:39 +0300 Subject: [PATCH 056/101] Sync changelog --- Changelog.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Changelog.md b/Changelog.md index 7239ba5b..b8ebb28f 100644 --- a/Changelog.md +++ b/Changelog.md @@ -1,5 +1,8 @@ VoodooPS2 Changelog ============================ +#### v2.2.7 +- Fixed kernel panic after S3 + #### v2.2.6 - Fixed some touchpads not waking after S3 From 6f9a2b1eeaca757f6ecb5d7ff31407177728afd5 Mon Sep 17 00:00:00 2001 From: Avery Black Date: Sun, 17 Oct 2021 13:16:04 -0700 Subject: [PATCH 057/101] Simplify mux logic (#42) --- VoodooPS2Controller/VoodooPS2Controller.cpp | 105 ++++++++------------ VoodooPS2Controller/VoodooPS2Controller.h | 15 +-- 2 files changed, 48 insertions(+), 72 deletions(-) diff --git a/VoodooPS2Controller/VoodooPS2Controller.cpp b/VoodooPS2Controller/VoodooPS2Controller.cpp index 350fa1d1..8c80c62f 100644 --- a/VoodooPS2Controller/VoodooPS2Controller.cpp +++ b/VoodooPS2Controller/VoodooPS2Controller.cpp @@ -161,7 +161,7 @@ void ApplePS2Controller::onWatchdogTimer() void ApplePS2Controller::handleInterrupt(bool watchdog) { // Loop only while there is data currently on the input stream. - bool wakePort[kPS2MaxIdx] {}; + bool wakePort[kPS2MuxMaxIdx] {}; while (1) { @@ -202,11 +202,6 @@ void ApplePS2Controller::handleInterrupt(bool watchdog) #endif port = getPortFromStatus(status); - if (port >= kPS2MaxIdx || _devices[port] == nullptr) - { - continue; - } - if (kPS2IR_packetReady == _dispatchDriverInterrupt(port, data)) { wakePort[port] = true; @@ -214,9 +209,8 @@ void ApplePS2Controller::handleInterrupt(bool watchdog) } // while (forever) // wake up workloop based mouse interrupt source if needed - size_t max_idx = _muxPresent ? kPS2MaxIdx : kPS2MuxIdx; - for (size_t i = kPS2KbdIdx; i < max_idx; i++) { - if (wakePort[i] && _devices[i] != nullptr) + for (size_t i = kPS2KbdIdx; i < _nubsCount; i++) { + if (wakePort[i]) { _devices[i]->packetActionInterrupt(); } @@ -422,6 +416,7 @@ void ApplePS2Controller::resetController(bool wakeup) else if (!wakeup) { _muxPresent = setMuxMode(true); + _nubsCount = _muxPresent ? kPS2MuxMaxIdx : kPS2AuxMaxIdx; } resetDevices(); @@ -456,7 +451,7 @@ void ApplePS2Controller::resetDevices() { writeCommandPort(kCP_TransmitToMuxedMouse + i); writeDataPort(kDP_SetDefaultsAndDisable); - readDataPort(kPS2MuxIdx + i); // (discard acknowledge; success irrelevant) + readDataPort(kPS2AuxIdx + i); // (discard acknowledge; success irrelevant) } } @@ -477,24 +472,22 @@ void ApplePS2Controller::flushDataPort() bool ApplePS2Controller::setMuxMode(bool enable) { UInt8 param = kDP_MuxCmd; - // getPortFromStatus will return kPS2MuxIdx when _muxPresent is true - size_t readPort = _muxPresent ? kPS2MuxIdx : kPS2AuxIdx; writeCommandPort(kCP_WriteMouseOutputBuffer); writeDataPort(param); - if (readDataPort(readPort) != param) + if (readDataPort(kPS2AuxIdx) != param) return false; param = enable ? kDP_EnableMuxCmd1 : kDP_DisableMuxCmd1; writeCommandPort(kCP_WriteMouseOutputBuffer); writeDataPort(param); - if (readDataPort(readPort) != param) + if (readDataPort(kPS2AuxIdx) != param) return false; param = enable ? kDP_GetMuxVersion : kDP_DisableMuxCmd2; writeCommandPort(kCP_WriteMouseOutputBuffer); writeDataPort(param); - UInt8 ver = readDataPort(readPort); + UInt8 ver = readDataPort(kPS2AuxIdx); // We want the version on enable, and original command on disable if ((enable && ver == param) || @@ -640,39 +633,21 @@ bool ApplePS2Controller::start(IOService * provider) goto fail; } - - if (_muxPresent) - { - for (size_t i = kPS2MuxIdx; i < kPS2MaxIdx; i++) - { - _devices[i] = OSTypeAlloc(ApplePS2MouseDevice); - if ( !_devices[i] || - !_devices[i]->init(i) || - !_devices[i]->attach(this) ) - { - OSSafeReleaseNULL(_devices[i]); - goto fail; - } - } - } - else + for (size_t i = kPS2AuxIdx; i < _nubsCount; i++) { - _devices[kPS2AuxIdx] = OSTypeAlloc(ApplePS2MouseDevice); - if ( !_devices[kPS2AuxIdx] || - !_devices[kPS2AuxIdx]->init(kPS2AuxIdx) || - !_devices[kPS2AuxIdx]->attach(this) ) + _devices[i] = OSTypeAlloc(ApplePS2MouseDevice); + if ( !_devices[i] || + !_devices[i]->init(i) || + !_devices[i]->attach(this) ) { - OSSafeReleaseNULL(_devices[kPS2AuxIdx]); + OSSafeReleaseNULL(_devices[i]); goto fail; } } - for (size_t i = kPS2KbdIdx; i < kPS2MaxIdx; i++) + for (size_t i = kPS2KbdIdx; i < _nubsCount; i++) { - if (_devices[i]) - { - _devices[i]->registerService(); - } + _devices[i]->registerService(); } registerService(); @@ -734,7 +709,7 @@ void ApplePS2Controller::stop(IOService * provider) OSSafeReleaseNULL(_notificationServices); // Free the nubs we created. - for (size_t i = 0; i < kPS2MaxIdx; i++) { + for (size_t i = 0; i < kPS2MuxMaxIdx; i++) { OSSafeReleaseNULL(_devices[i]); } @@ -969,7 +944,7 @@ void ApplePS2Controller::setCommandByteGated(PS2Request* request) bool ApplePS2Controller::submitRequest(PS2Request * request) { - assert(request->port < kPS2MaxIdx); + assert(request->port < kPS2MuxMaxIdx); // // Submit the request to the controller for processing, asynchronously. @@ -987,7 +962,7 @@ bool ApplePS2Controller::submitRequest(PS2Request * request) void ApplePS2Controller::submitRequestAndBlock(PS2Request * request) { - assert(request->port < kPS2MaxIdx); + assert(request->port < kPS2MuxMaxIdx); _cmdGate->runAction(OSMemberFunctionCast(IOCommandGate::Action, this, &ApplePS2Controller::submitRequestAndBlockGated), request); } @@ -1142,10 +1117,12 @@ void ApplePS2Controller::processRequest(PS2Request * request) break; case kPS2C_WriteDataPort: - if (devicePort == kPS2AuxIdx) { - writeCommandPort(kCP_TransmitToMouse); - } else if (devicePort > kPS2AuxIdx) { - writeCommandPort(kCP_TransmitToMuxedMouse + (devicePort - kPS2MuxIdx)); + if (devicePort >= kPS2AuxIdx) { + if (_muxPresent) { + writeCommandPort(kCP_TransmitToMuxedMouse + (devicePort - kPS2AuxIdx)); + } else { + writeCommandPort(kCP_TransmitToMouse); + } } writeDataPort(request->commands[index].inOrOut); @@ -1160,10 +1137,12 @@ void ApplePS2Controller::processRequest(PS2Request * request) // case kPS2C_SendCommandAndCompareAck: - if (devicePort == kPS2AuxIdx) { - writeCommandPort(kCP_TransmitToMouse); - } else if (devicePort > kPS2AuxIdx) { - writeCommandPort(kCP_TransmitToMuxedMouse + (devicePort - kPS2MuxIdx)); + if (devicePort >= kPS2AuxIdx) { + if (_muxPresent) { + writeCommandPort(kCP_TransmitToMuxedMouse + (devicePort - kPS2AuxIdx)); + } else { + writeCommandPort(kCP_TransmitToMouse); + } } writeDataPort(request->commands[index].inOrOut); @@ -1261,14 +1240,13 @@ void ApplePS2Controller::processRequestQueue(IOInterruptEventSource *, int) size_t ApplePS2Controller::getPortFromStatus(UInt8 status) { bool auxPort = status & kMouseData; - if (_muxPresent && auxPort) - { - return kPS2MuxIdx + ((status >> 6) & 3); - } - else - { - return auxPort ? kPS2AuxIdx : kPS2KbdIdx; + size_t port = auxPort ? kPS2AuxIdx : kPS2KbdIdx; + + if (_muxPresent && auxPort) { + port += (status >> PS2_STA_MUX_SHIFT) & PS2_STA_MUX_MASK; } + + return port; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -1949,7 +1927,7 @@ void ApplePS2Controller::dispatchDriverPowerControl( UInt32 whatToDo, size_t por { // Should be called with kPS2Aux or kPS2Kbd. // "port" set to kPS2Aux will run the power action for all mux ports - assert (port < kPS2MuxIdx); + assert (port < kPS2AuxMaxIdx); if (port == kPS2KbdIdx) { @@ -1957,12 +1935,7 @@ void ApplePS2Controller::dispatchDriverPowerControl( UInt32 whatToDo, size_t por return; } - if (!_muxPresent) { - _devices[kPS2AuxIdx]->powerAction(whatToDo); - return; - } - - for (size_t i = kPS2MuxIdx; i < kPS2MaxIdx; i++) { + for (size_t i = kPS2AuxIdx; i < _nubsCount; i++) { _devices[i]->powerAction(whatToDo); } } diff --git a/VoodooPS2Controller/VoodooPS2Controller.h b/VoodooPS2Controller/VoodooPS2Controller.h index aad23676..2503ff54 100644 --- a/VoodooPS2Controller/VoodooPS2Controller.h +++ b/VoodooPS2Controller/VoodooPS2Controller.h @@ -193,19 +193,21 @@ enum { }; // i8042 Mux indexes -#define PS2_MUX_IDX 2 #define PS2_MUX_PORTS 4 +#define PS2_STA_MUX_MASK 0x03 +#define PS2_STA_MUX_SHIFT 0x06 + // Normally, the i8042 controller has 2 ports. With the mux active, // there are 5 ports. 1 Keyboard port and 4 mux ports. All the muxed ports -// share the same IRQ. When the controller is in the multiplexer mode, the -// index for the aux port is skipped. +// share the same IRQ. When the controller is in a multiplexed mode, 3 +// additional ports are added. enum { kPS2KbdIdx = 0, kPS2AuxIdx = 1, - kPS2MuxIdx = PS2_MUX_IDX, - kPS2MaxIdx = PS2_MUX_IDX + PS2_MUX_PORTS + kPS2AuxMaxIdx = 2, + kPS2MuxMaxIdx = PS2_MUX_PORTS + 1 }; // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -248,7 +250,7 @@ class EXPORT ApplePS2Controller : public IOService int _ignoreInterrupts {0}; int _ignoreOutOfOrder {0}; - ApplePS2Device * _devices [kPS2MaxIdx] {nullptr}; + ApplePS2Device * _devices [kPS2MuxMaxIdx] {nullptr}; IONotifier* _publishNotify {nullptr}; IONotifier* _terminateNotify {nullptr}; @@ -273,6 +275,7 @@ class EXPORT ApplePS2Controller : public IOService int _wakedelay {10}; bool _mouseWakeFirst {false}; bool _muxPresent {false}; + size_t _nubsCount {0}; IOCommandGate* _cmdGate {nullptr}; #if WATCHDOG_TIMER IOTimerEventSource* _watchdogTimer {nullptr}; From 6e64b33e316ca9ffb980701704caac02a9bfa54b Mon Sep 17 00:00:00 2001 From: Andrey1970AppleLife Date: Tue, 2 Nov 2021 11:04:47 +0300 Subject: [PATCH 058/101] 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 13612e8b..5f5eb5a0 100644 --- a/VoodooPS2Controller.xcodeproj/project.pbxproj +++ b/VoodooPS2Controller.xcodeproj/project.pbxproj @@ -767,7 +767,7 @@ KERNEL_FRAMEWORK_HEADERS = "$(PROJECT_DIR)/MacKernelSDK/Headers"; "LLVM_LTO[arch=x86_64]" = YES; MACOSX_DEPLOYMENT_TARGET = 10.11; - MODULE_VERSION = 2.2.7; + MODULE_VERSION = 2.2.8; ONLY_ACTIVE_ARCH = YES; "OTHER_LDFLAGS[arch=x86_64]" = "-dead_strip"; PRODUCT_NAME = VoodooPS2Controller; @@ -822,7 +822,7 @@ KERNEL_FRAMEWORK_HEADERS = "$(PROJECT_DIR)/MacKernelSDK/Headers"; "LLVM_LTO[arch=x86_64]" = YES; MACOSX_DEPLOYMENT_TARGET = 10.11; - MODULE_VERSION = 2.2.7; + MODULE_VERSION = 2.2.8; "OTHER_LDFLAGS[arch=x86_64]" = "-dead_strip"; PRODUCT_NAME = VoodooPS2Controller; SDKROOT = macosx; From 46e4af8aefa244348fc9e8ec1febf9afc127cae2 Mon Sep 17 00:00:00 2001 From: SkyrilHD Date: Mon, 21 Feb 2022 17:55:53 +0100 Subject: [PATCH 059/101] Add ALPS touch support (#44) --- README.md | 2 + VoodooPS2Controller/ApplePS2Device.h | 4 + VoodooPS2Trackpad/VoodooPS2ALPSGlidePoint.cpp | 4695 ++++++++++++++--- VoodooPS2Trackpad/VoodooPS2ALPSGlidePoint.h | 739 ++- .../VoodooPS2Trackpad-Info.plist | 61 +- 5 files changed, 4835 insertions(+), 666 deletions(-) diff --git a/README.md b/README.md index ef3bec9e..0e450785 100644 --- a/README.md +++ b/README.md @@ -34,6 +34,8 @@ The parameters in the formula are configured using `ForceTouchCustomUpThreshold` For Elan touchpad, only mode 0 and mode 1 are supported. +For ALPS touchpads, V1, V2 and V6 do not support Force Touch. V3, V4 and V5 only support mode 0, 2, 3 and 4. V7 only supports mode 0 and 1. V8 supports all modes. + ## Installation and compilation For VoodooPS2Trackpad.kext to work multitouch interface engine, named VoodooInput.kext, is required. diff --git a/VoodooPS2Controller/ApplePS2Device.h b/VoodooPS2Controller/ApplePS2Device.h index 607847ee..35aefb10 100644 --- a/VoodooPS2Controller/ApplePS2Device.h +++ b/VoodooPS2Controller/ApplePS2Device.h @@ -55,9 +55,12 @@ #define kDP_SetMouseResolution 0xE8 // (mouse) #define kDP_GetMouseInformation 0xE9 // (mouse) #define kDP_SetMouseStreamMode 0xEA // (mouse) +#define kDP_MousePoll 0xEB // (mouse) caller sets number of bytes to receive +#define kDP_MouseResetWrap 0xEC // (mouse) #define kDP_SetKeyboardLEDs 0xED // (keyboard) #define kDP_TestKeyboardEcho 0xEE // (keyboard) #define kDP_GetSetKeyboardASCs 0xF0 // (keyboard) +#define kDP_MouseSetPoll 0xF0 // (mouse) #define kDP_GetId 0xF2 // (keyboard+mouse) #define kDP_SetKeyboardTypematic 0xF3 // (keyboard) #define kDP_SetMouseSampleRate 0xF3 // (mouse) @@ -142,6 +145,7 @@ #define kSC_Resend 0xFE // request to resend keybd cmd #define kSC_Reset 0xAA // the keyboard/mouse has reset #define kSC_UpBit 0x80 // OR'd in if key below is released +#define kSC_ID 0x00 // PSMOUSE_RET_ID // // Scan Codes for some modifier keys. diff --git a/VoodooPS2Trackpad/VoodooPS2ALPSGlidePoint.cpp b/VoodooPS2Trackpad/VoodooPS2ALPSGlidePoint.cpp index dfad1a47..b9817e1f 100644 --- a/VoodooPS2Trackpad/VoodooPS2ALPSGlidePoint.cpp +++ b/VoodooPS2Trackpad/VoodooPS2ALPSGlidePoint.cpp @@ -2,13 +2,13 @@ * Copyright (c) 2002 Apple Computer, Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ - * + * * The contents of this file constitute Original Code as defined in and * are subject to the Apple Public Source License Version 1.2 (the * "License"). You may not use this file except in compliance with the * License. Please obtain a copy of the License at * http://www.apple.com/publicsource and read it before using this file. - * + * * This Original Code and all software distributed under the License are * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, @@ -16,26 +16,157 @@ * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the * License for the specific language governing rights and limitations * under the License. - * + * * @APPLE_LICENSE_HEADER_END@ */ #include +#include "VoodooPS2ALPSGlidePoint.h" #include #include +#include +#include +#include +#include +#include #include "VoodooPS2Controller.h" -#include "VoodooPS2ALPSGlidePoint.h" +#include "VoodooInputMultitouch/VoodooInputTransducer.h" +#include "VoodooInputMultitouch/VoodooInputMessages.h" + +#undef NULL +#define NULL 0 enum { - // - // - kTapEnabled = 0x01 + kTapEnabled = 0x01 +}; + +#define ARRAY_SIZE(x) (sizeof(x)/sizeof(x[0])) +#define BIT(x) (1 << (x)) + + +/* ============================================================================================== */ +/* ===============================||\\ alps.c Definitions //||=================================== */ +/* ============================================================================================== */ + +/* + * Definitions for ALPS version 3 and 4 command mode protocol + */ +#define ALPS_CMD_NIBBLE_10 0x01f2 + +#define ALPS_REG_BASE_RUSHMORE 0xc2c0 +#define ALPS_REG_BASE_V7 0xc2c0 +#define ALPS_REG_BASE_PINNACLE 0x0000 + +static const struct alps_nibble_commands alps_v3_nibble_commands[] = { + { kDP_MouseSetPoll, 0x00 }, /* 0 no send/recv */ + { kDP_SetDefaults, 0x00 }, /* 1 no send/recv */ + { kDP_SetMouseScaling2To1, 0x00 }, /* 2 no send/recv */ + { kDP_SetMouseSampleRate | 0x1000, 0x0a }, /* 3 send=1 recv=0 */ + { kDP_SetMouseSampleRate | 0x1000, 0x14 }, /* 4 ..*/ + { kDP_SetMouseSampleRate | 0x1000, 0x28 }, /* 5 ..*/ + { kDP_SetMouseSampleRate | 0x1000, 0x3c }, /* 6 ..*/ + { kDP_SetMouseSampleRate | 0x1000, 0x50 }, /* 7 ..*/ + { kDP_SetMouseSampleRate | 0x1000, 0x64 }, /* 8 ..*/ + { kDP_SetMouseSampleRate | 0x1000, 0xc8 }, /* 9 ..*/ + { kDP_CommandNibble10 | 0x0100, 0x00 }, /* a send=0 recv=1 */ + { kDP_SetMouseResolution | 0x1000, 0x00 }, /* b send=1 recv=0 */ + { kDP_SetMouseResolution | 0x1000, 0x01 }, /* c ..*/ + { kDP_SetMouseResolution | 0x1000, 0x02 }, /* d ..*/ + { kDP_SetMouseResolution | 0x1000, 0x03 }, /* e ..*/ + { kDP_SetMouseScaling1To1, 0x00 }, /* f no send/recv */ +}; + +static const struct alps_nibble_commands alps_v4_nibble_commands[] = { + { kDP_Enable, 0x00 }, /* 0 no send/recv */ + { kDP_SetDefaults, 0x00 }, /* 1 no send/recv */ + { kDP_SetMouseScaling2To1, 0x00 }, /* 2 no send/recv */ + { kDP_SetMouseSampleRate | 0x1000, 0x0a }, /* 3 send=1 recv=0 */ + { kDP_SetMouseSampleRate | 0x1000, 0x14 }, /* 4 ..*/ + { kDP_SetMouseSampleRate | 0x1000, 0x28 }, /* 5 ..*/ + { kDP_SetMouseSampleRate | 0x1000, 0x3c }, /* 6 ..*/ + { kDP_SetMouseSampleRate | 0x1000, 0x50 }, /* 7 ..*/ + { kDP_SetMouseSampleRate | 0x1000, 0x64 }, /* 8 ..*/ + { kDP_SetMouseSampleRate | 0x1000, 0xc8 }, /* 9 ..*/ + { kDP_CommandNibble10 | 0x0100, 0x00 }, /* a send=0 recv=1 */ + { kDP_SetMouseResolution | 0x1000, 0x00 }, /* b send=1 recv=0 */ + { kDP_SetMouseResolution | 0x1000, 0x01 }, /* c ..*/ + { kDP_SetMouseResolution | 0x1000, 0x02 }, /* d ..*/ + { kDP_SetMouseResolution | 0x1000, 0x03 }, /* e ..*/ + { kDP_SetMouseScaling1To1, 0x00 }, /* f no send/recv */ +}; + +static const struct alps_nibble_commands alps_v6_nibble_commands[] = { + { kDP_Enable, 0x00 }, /* 0 */ + { kDP_SetMouseSampleRate, 0x0a }, /* 1 */ + { kDP_SetMouseSampleRate, 0x14 }, /* 2 */ + { kDP_SetMouseSampleRate, 0x28 }, /* 3 */ + { kDP_SetMouseSampleRate, 0x3c }, /* 4 */ + { kDP_SetMouseSampleRate, 0x50 }, /* 5 */ + { kDP_SetMouseSampleRate, 0x64 }, /* 6 */ + { kDP_SetMouseSampleRate, 0xc8 }, /* 7 */ + { kDP_GetId, 0x00 }, /* 8 */ + { kDP_GetMouseInformation, 0x00 }, /* 9 */ + { kDP_SetMouseResolution, 0x00 }, /* a */ + { kDP_SetMouseResolution, 0x01 }, /* b */ + { kDP_SetMouseResolution, 0x02 }, /* c */ + { kDP_SetMouseResolution, 0x03 }, /* d */ + { kDP_SetMouseScaling2To1, 0x00 }, /* e */ + { kDP_SetMouseScaling1To1, 0x00 }, /* f */ +}; + + +#define ALPS_DUALPOINT 0x02 /* touchpad has trackstick */ +#define ALPS_PASS 0x04 /* device has a pass-through port */ + +#define ALPS_WHEEL 0x08 /* hardware wheel present */ +#define ALPS_FW_BK_1 0x10 /* front & back buttons present */ +#define ALPS_FW_BK_2 0x20 /* front & back buttons present */ +#define ALPS_FOUR_BUTTONS 0x40 /* 4 direction button present */ +#define ALPS_PS2_INTERLEAVED 0x80 /* 3-byte PS/2 packet interleaved with 6-byte ALPS packet */ +#define ALPS_STICK_BITS 0x100 /* separate stick button bits */ +#define ALPS_BUTTONPAD 0x200 /* device is a clickpad */ +#define ALPS_DUALPOINT_WITH_PRESSURE 0x400 /* device can report trackpoint pressure */ + + +static const struct alps_model_info alps_model_data[] = { + /* + * XXX This entry is suspicious. First byte has zero lower nibble, + * which is what a normal mouse would report. Also, the value 0x0e + * isn't valid per PS/2 spec. + */ + { { 0x20, 0x02, 0x0e }, { ALPS_PROTO_V2, 0xf8, 0xf8, ALPS_PASS | ALPS_DUALPOINT } }, + + { { 0x22, 0x02, 0x0a }, { ALPS_PROTO_V2, 0xf8, 0xf8, ALPS_PASS | ALPS_DUALPOINT } }, + { { 0x22, 0x02, 0x14 }, { ALPS_PROTO_V2, 0xff, 0xff, ALPS_PASS | ALPS_DUALPOINT } }, /* Dell Latitude D600 */ + { { 0x32, 0x02, 0x14 }, { ALPS_PROTO_V2, 0xf8, 0xf8, ALPS_PASS | ALPS_DUALPOINT } }, /* Toshiba Salellite Pro M10 */ + { { 0x33, 0x02, 0x0a }, { ALPS_PROTO_V1, 0x88, 0xf8, 0 } }, /* UMAX-530T */ + { { 0x52, 0x01, 0x14 }, { ALPS_PROTO_V2, 0xff, 0xff, + ALPS_PASS | ALPS_DUALPOINT | ALPS_PS2_INTERLEAVED } }, /* Toshiba Tecra A11-11L */ + { { 0x53, 0x02, 0x0a }, { ALPS_PROTO_V2, 0xf8, 0xf8, 0 } }, + { { 0x53, 0x02, 0x14 }, { ALPS_PROTO_V2, 0xf8, 0xf8, 0 } }, + { { 0x60, 0x03, 0xc8 }, { ALPS_PROTO_V2, 0xf8, 0xf8, 0 } }, /* HP ze1115 */ + { { 0x62, 0x02, 0x14 }, { ALPS_PROTO_V2, 0xcf, 0xcf, + ALPS_PASS | ALPS_DUALPOINT | ALPS_PS2_INTERLEAVED } }, /* Dell Latitude E5500, E6400, E6500, Precision M4400 */ + { { 0x63, 0x02, 0x0a }, { ALPS_PROTO_V2, 0xf8, 0xf8, 0 } }, + { { 0x63, 0x02, 0x14 }, { ALPS_PROTO_V2, 0xf8, 0xf8, 0 } }, + { { 0x63, 0x02, 0x28 }, { ALPS_PROTO_V2, 0xf8, 0xf8, ALPS_FW_BK_2 } }, /* Fujitsu Siemens S6010 */ + { { 0x63, 0x02, 0x3c }, { ALPS_PROTO_V2, 0x8f, 0x8f, ALPS_WHEEL } }, /* Toshiba Satellite S2400-103 */ + { { 0x63, 0x02, 0x50 }, { ALPS_PROTO_V2, 0xef, 0xef, ALPS_FW_BK_1 } }, /* NEC Versa L320 */ + { { 0x63, 0x02, 0x64 }, { ALPS_PROTO_V2, 0xf8, 0xf8, 0 } }, + { { 0x63, 0x03, 0xc8 }, { ALPS_PROTO_V2, 0xf8, 0xf8, ALPS_PASS | ALPS_DUALPOINT } }, /* Dell Latitude D800 */ + { { 0x73, 0x00, 0x0a }, { ALPS_PROTO_V2, 0xf8, 0xf8, ALPS_DUALPOINT } }, /* ThinkPad R61 8918-5QG */ + { { 0x73, 0x00, 0x14 }, { ALPS_PROTO_V6, 0xff, 0xff, ALPS_DUALPOINT } }, /* Dell XT2 */ + { { 0x73, 0x02, 0x0a }, { ALPS_PROTO_V2, 0xf8, 0xf8, 0 } }, + { { 0x73, 0x02, 0x14 }, { ALPS_PROTO_V2, 0xf8, 0xf8, ALPS_FW_BK_2 } }, /* Ahtec Laptop */ + { { 0x73, 0x02, 0x50 }, { ALPS_PROTO_V2, 0xcf, 0xcf, ALPS_FOUR_BUTTONS } }, /* Dell Vostro 1400 */ }; +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + +// ============================================================================= +// ApplePS2ALPSGlidePoint Class Implementation //////////////////////////////// // ============================================================================= -// ApplePS2ALPSGlidePoint Class Implementation -// OSDefineMetaClassAndStructors(ApplePS2ALPSGlidePoint, IOHIPointing); @@ -45,47 +176,92 @@ UInt32 ApplePS2ALPSGlidePoint::deviceType() UInt32 ApplePS2ALPSGlidePoint::interfaceID() { return NX_EVS_DEVICE_INTERFACE_BUS_ACE; }; -IOItemCount ApplePS2ALPSGlidePoint::buttonCount() { return 2; }; -IOFixed ApplePS2ALPSGlidePoint::resolution() { return _resolution; }; -bool IsItALPS(ALPSStatus_t *E6,ALPSStatus_t *E7); +IOItemCount ApplePS2ALPSGlidePoint::buttonCount() { return _buttonCount; }; +IOFixed ApplePS2ALPSGlidePoint::resolution() { return _resolution << 16; }; // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -bool ApplePS2ALPSGlidePoint::init(OSDictionary * dict) -{ +bool ApplePS2ALPSGlidePoint::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; + } // initialize state... - _device = 0; - _interruptHandlerInstalled = false; - _packetByteCount = 0; - _resolution = (100) << 16; // (100 dpi, 4 counts/mm) - _touchPadModeByte = kTapEnabled; - _scrolling = SCROLL_NONE; - _zscrollpos = 0; - + for (int i = 0; i < MAX_TOUCHES; i++) + fingerStates[i].virtualFingerIndex = -1; + + memset(freeFingerTypes, true, kMT2FingerTypeCount); + freeFingerTypes[kMT2FingerTypeUndefined] = false; + + // announce version + extern kmod_info_t kmod_info; + DEBUG_LOG("ALPS: Version %s starting on OS X Darwin %d.%d.\n", kmod_info.version, version_major, version_minor); + + setProperty("Revision", 24, 32); + return true; } -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +void ApplePS2ALPSGlidePoint::injectVersionDependentProperties(OSDictionary *config) { + // inject properties specific to the version of Darwin that is runnning... + char buf[32]; + 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)))) + break; + // check for "Darwin major.x" + snprintf(buf, sizeof(buf), "Darwin %d.x", version_major); + 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+")))) + break; + } while (0); + + if (dict) + { + // found version specific properties above, inject... + 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)) + setProperty(key, value); + } + iter->release(); + } + } +} + +ApplePS2ALPSGlidePoint *ApplePS2ALPSGlidePoint::probe(IOService *provider, SInt32 *score) { + DEBUG_LOG("ALPS: 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). + // -ApplePS2ALPSGlidePoint* ApplePS2ALPSGlidePoint::probe( IOService * provider, SInt32 * score ) -{ - DEBUG_LOG("ApplePS2ALPSGlidePoint::probe entered...\n"); - if (!super::probe(provider, score)) return 0; + _device = (ApplePS2MouseDevice *) provider; + // find config specific to Platform Profile OSDictionary* list = OSDynamicCast(OSDictionary, getProperty(kPlatformProfile)); - ApplePS2Device* device = (ApplePS2Device*)provider; - OSDictionary* config = device->getController()->makeConfigurationNode(list, "ALPS GlidePoint"); + OSDictionary* config = _device->getController()->makeConfigurationNode(list, "ALPS GlidePoint"); if (config) { // if DisableDevice is Yes, then do not load at all... @@ -93,106 +269,74 @@ ApplePS2ALPSGlidePoint* ApplePS2ALPSGlidePoint::probe( IOService * provider, SIn if (disable && disable->isTrue()) { config->release(); + _device = 0; return 0; } #ifdef DEBUG // save configuration for later/diagnostics... setProperty(kMergedConfiguration, config); #endif + // load settings specific to Platform Profile + setParamPropertiesGated(config); + injectVersionDependentProperties(config); + OSSafeReleaseNULL(config); } - OSSafeReleaseNULL(config); - - ALPSStatus_t E6,E7; - // - // 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). - // - bool success = false; + _device->lock(); + resetMouse(); - _device = (ApplePS2MouseDevice *) provider; + bool success; + if (identify() != 0) { + success = false; + } else { + success = true; + IOLog("ALPS: TouchPad driver started...\n"); + } + _device->unlock(); - getModel(&E6, &E7); + _device = 0; - DEBUG_LOG("E7: { 0x%02x, 0x%02x, 0x%02x } E6: { 0x%02x, 0x%02x, 0x%02x }", - E7.byte0, E7.byte1, E7.byte2, E6.byte0, E6.byte1, E6.byte2); + return success ? this : 0; +} - success = IsItALPS(&E6,&E7); - DEBUG_LOG("ALPS Device? %s\n", (success ? "yes" : "no")); +bool ApplePS2ALPSGlidePoint::resetMouse() { + TPS2Request<3> request; - // override - //success = true; - _touchPadVersion = (E7.byte2 & 0x0f) << 8 | E7.byte0; - - _device = 0; + // Reset mouse + request.commands[0].command = kPS2C_SendCommandAndCompareAck; + request.commands[0].inOrOut = kDP_Reset; + request.commands[1].command = kPS2C_ReadDataPort; + request.commands[1].inOrOut = 0; + request.commands[2].command = kPS2C_ReadDataPort; + request.commands[2].inOrOut = 0; + request.commandsCount = 3; + assert(request.commandsCount <= countof(request.commands)); + _device->submitRequestAndBlock(&request); - DEBUG_LOG("ApplePS2ALPSGlidePoint::probe leaving.\n"); - - return (success) ? this : 0; + // Verify the result + if (request.commands[1].inOrOut != kSC_Reset && request.commands[2].inOrOut != kSC_ID) { + IOLog("ALPS: Failed to reset mouse, return values did not match. [0x%02x, 0x%02x]\n", request.commands[1].inOrOut, request.commands[2].inOrOut); + return false; + } + return true; } -bool IsItALPS(ALPSStatus_t *E6,ALPSStatus_t *E7) -{ - bool success = false; - short i; - - UInt8 byte0, byte1, byte2; - byte0 = E7->byte0; - byte1 = E7->byte1; - byte2 = E7->byte2; - - #define NUM_SINGLES 10 - static int singles[NUM_SINGLES * 3] ={ - 0x33,0x2,0x0a, - 0x53,0x2,0x0a, - 0x53,0x2,0x14, - 0x63,0x2,0xa, - 0x63,0x2,0x14, - 0x73,0x2,0x0a, // 3622947 - 0x63,0x2,0x28, - 0x63,0x2,0x3c, - 0x63,0x2,0x50, - 0x63,0x2,0x64}; - #define NUM_DUALS 3 - static int duals[NUM_DUALS * 3]={ - 0x20,0x2,0xe, - 0x22,0x2,0xa, - 0x22,0x2,0x14}; - - for (i = 0; i < NUM_SINGLES; i++) - { - if ((byte0 == singles[i * 3]) && (byte1 == singles[i * 3 + 1]) && - (byte2 == singles[i * 3 + 2])) - { - success = true; - break; - } - } - - if (!success) - { - for(i = 0;i < NUM_DUALS;i++) - { - if ((byte0 == duals[i * 3]) && (byte1 == duals[i * 3 + 1]) && - (byte2 == duals[i * 3 + 2])) - { - success = true; - break; - } - } - } - return success; -} +bool ApplePS2ALPSGlidePoint::handleOpen(IOService *forClient, IOOptionBits options, void *arg) { + if (forClient && forClient->getProperty(VOODOO_INPUT_IDENTIFIER)) { + voodooInputInstance = forClient; + voodooInputInstance->retain(); -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + return true; + } + return super::handleOpen(forClient, options, arg); +} -bool ApplePS2ALPSGlidePoint::start( IOService * provider ) -{ - UInt64 enabledProperty; +void ApplePS2ALPSGlidePoint::handleClose(IOService *forClient, IOOptionBits options) { + OSSafeReleaseNULL(voodooInputInstance); + super::handleClose(forClient, options); +} +bool ApplePS2ALPSGlidePoint::start( IOService * provider ) { // // The driver has been instructed to start. This is called after a // successful probe and match. @@ -209,25 +353,7 @@ bool ApplePS2ALPSGlidePoint::start( IOService * provider ) _device->retain(); // - // Announce hardware properties. - // - - IOLog("ApplePS2Trackpad: ALPS GlidePoint v%d.%d\n", - (UInt8)(_touchPadVersion >> 8), (UInt8)(_touchPadVersion)); - - // - // Advertise some supported features (tapping, edge scrolling). - // - - enabledProperty = 1; - - setProperty("Clicking", enabledProperty, - sizeof(enabledProperty) * 8); - setProperty("TrackpadScroll", enabledProperty, - sizeof(enabledProperty) * 8); - setProperty("TrackpadHorizScroll", enabledProperty, - sizeof(enabledProperty) * 8); - + // 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 @@ -235,57 +361,78 @@ bool ApplePS2ALPSGlidePoint::start( IOService * provider ) // setProperty(kIOHIDPointerAccelerationTypeKey, kIOHIDTrackpadAccelerationType); + setProperty(kIOHIDScrollAccelerationTypeKey, kIOHIDTrackpadScrollAccelerationKey); + setProperty(kIOHIDScrollResolutionKey, _scrollresolution << 16, 32); + // added for Sierra precise scrolling (credit usr-sse2) + setProperty("HIDScrollResolutionX", _scrollresolution << 16, 32); + setProperty("HIDScrollResolutionY", _scrollresolution << 16, 32); // - // Lock the controller during initialization + // Setup workloop with command gate for thread synchronization... // - - _device->lock(); - - // Enable tapping - setTapEnable( true ); - - // Enable Absolute Mode - setAbsoluteMode(); - + IOWorkLoop* pWorkLoop = getWorkLoop(); + _cmdGate = IOCommandGate::commandGate(this); + if (!pWorkLoop || !_cmdGate) + { + _device->release(); + _device = nullptr; + return false; + } + + pWorkLoop->addEventSource(_cmdGate); + // - // Finally, we enable the trackpad itself, so that it may start reporting - // asynchronous events. + // Lock the controller during initialization // - - setTouchPadEnable(true); - + + _device->lock(); + + attachedHIDPointerDevices = OSSet::withCapacity(1); + registerHIDPointerNotifications(); + // - // Enable the mouse clock (should already be so) and the mouse IRQ line. + // Perform any implementation specific device initialization // + if (!deviceSpecificInit()) { + _device->unlock(); + _device->release(); + return false; + } // // Install our driver's interrupt handler, for asynchronous data delivery. // - + _device->installInterruptAction(this, OSMemberFunctionCast(PS2InterruptAction, this, &ApplePS2ALPSGlidePoint::interruptOccurred), OSMemberFunctionCast(PS2PacketAction, this, &ApplePS2ALPSGlidePoint::packetReady)); _interruptHandlerInstalled = true; - + // now safe to allow other threads _device->unlock(); - + + // + // Install our power control handler. + // + + _device->installPowerControlAction( this, + OSMemberFunctionCast(PS2PowerControlAction, this, &ApplePS2ALPSGlidePoint::setDevicePowerState) ); + _powerControlHandlerInstalled = true; + + // + // Request message registration for keyboard to trackpad communication // - // Install our power control handler. - // - _device->installPowerControlAction( this, OSMemberFunctionCast(PS2PowerControlAction,this, - &ApplePS2ALPSGlidePoint::setDevicePowerState) ); - _powerControlHandlerInstalled = true; + //setProperty(kDeliverNotifications, true); return true; } -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void ApplePS2ALPSGlidePoint::stop( IOService * provider ) -{ +void ApplePS2ALPSGlidePoint::stop(IOService *provider) { + + DEBUG_LOG("%s: stop called\n", getName()); + // // The driver has been instructed to stop. Note that we must break all // connections to other service objects now (ie. no registered actions, @@ -294,527 +441,3895 @@ void ApplePS2ALPSGlidePoint::stop( IOService * provider ) assert(_device == provider); + unregisterHIDPointerNotifications(); + OSSafeReleaseNULL(attachedHIDPointerDevices); + + ignoreall = false; + // // Disable the mouse itself, so that it may stop reporting mouse events. // setTouchPadEnable(false); + // free up timer for scroll momentum + IOWorkLoop* pWorkLoop = getWorkLoop(); + if (pWorkLoop) + { + if (_cmdGate) + { + pWorkLoop->removeEventSource(_cmdGate); + _cmdGate->release(); + _cmdGate = 0; + } + } + // // Uninstall the interrupt handler. // - if ( _interruptHandlerInstalled ) _device->uninstallInterruptAction(); - _interruptHandlerInstalled = false; + if (_interruptHandlerInstalled) + { + _device->uninstallInterruptAction(); + _interruptHandlerInstalled = false; + } // // Uninstall the power control handler. // - if ( _powerControlHandlerInstalled ) _device->uninstallPowerControlAction(); - _powerControlHandlerInstalled = false; + if (_powerControlHandlerInstalled) + { + _device->uninstallPowerControlAction(); + _powerControlHandlerInstalled = false; + } // // Release the pointer to the provider object. // - + OSSafeReleaseNULL(_device); - - super::stop(provider); -} -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + super::stop(provider); +} -PS2InterruptResult ApplePS2ALPSGlidePoint::interruptOccurred(UInt8 data) -{ +PS2InterruptResult ApplePS2ALPSGlidePoint::interruptOccurred(UInt8 data) { // // This will be invoked automatically from our device when asynchronous // events need to be delivered. Process the trackpad data. Do NOT issue // any BLOCKING commands to our device in this context. // - // Ignore all bytes until we see the start of a packet, otherwise the - // packets may get out of sequence and things will get very confusing. - // - - if (0 == _packetByteCount && (data & 0xc8) != 0x08 && (data & 0xf8) != 0xf8) - { - DEBUG_LOG("%s: Unexpected byte0 data (%02x) from PS/2 controller\n", getName(), data); - return kPS2IR_packetBuffering; + + UInt8 *packet = _ringBuffer.head(); + + /* Save first packet */ + if (0 == _packetByteCount) { + packet[0] = data; } - if (_packetByteCount >= 1 && data == 0x80) - { - DEBUG_LOG("%s: Unexpected byte%d data (%02x) from PS/2 controller\n", getName(), _packetByteCount, data); - _packetByteCount = 0; + + /* Reset PSMOUSE_BAD_DATA flag */ + priv.PSMOUSE_BAD_DATA = false; + + /* + * Check if we are dealing with a bare PS/2 packet, presumably from + * a device connected to the external PS/2 port. Because bare PS/2 + * protocol does not have enough constant bits to self-synchronize + * properly we only do this if the device is fully synchronized. + * Can not distinguish V8's first byte from PS/2 packet's + */ + if (priv.proto_version != ALPS_PROTO_V8 && + (packet[0] & 0xc8) == 0x08) { + if (_packetByteCount == 3) { + DEBUG_LOG("ALPS: Dealing with bare PS/2 packet\n"); + //dispatchRelativePointerEventWithPacket(packet, kPacketLengthSmall); //Dr Hurt: allow this? + priv.PSMOUSE_BAD_DATA = true; + _ringBuffer.advanceHead(priv.pktsize); + return kPS2IR_packetReady; + } + packet[_packetByteCount++] = data; return kPS2IR_packetBuffering; } - UInt8* packet = _ringBuffer.head(); + /* Check for PS/2 packet stuffed in the middle of ALPS packet. */ + if ((priv.flags & ALPS_PS2_INTERLEAVED) && + _packetByteCount >= 4 && (packet[3] & 0x0f) == 0x0f) { + priv.PSMOUSE_BAD_DATA = true; + _ringBuffer.advanceHead(priv.pktsize); + return kPS2IR_packetReady; + } + + /* alps_is_valid_first_byte */ + if ((packet[0] & priv.mask0) != priv.byte0) { + priv.PSMOUSE_BAD_DATA = true; + _ringBuffer.advanceHead(priv.pktsize); + return kPS2IR_packetReady; + } + + /* Bytes 2 - pktsize should have 0 in the highest bit */ + if (priv.proto_version < ALPS_PROTO_V5 && + _packetByteCount >= 2 && _packetByteCount <= priv.pktsize && + (packet[_packetByteCount - 1] & 0x80)) { + priv.PSMOUSE_BAD_DATA = true; + _ringBuffer.advanceHead(priv.pktsize); + return kPS2IR_packetReady; + } + + /* alps_is_valid_package_v7 */ + if (priv.proto_version == ALPS_PROTO_V7 && + (((_packetByteCount == 3) && ((packet[2] & 0x40) != 0x40)) || + ((_packetByteCount == 4) && ((packet[3] & 0x48) != 0x48)) || + ((_packetByteCount == 6) && ((packet[5] & 0x40) != 0x0)))) { + priv.PSMOUSE_BAD_DATA = true; + _ringBuffer.advanceHead(priv.pktsize); + return kPS2IR_packetReady; + } + + /* alps_is_valid_package_ss4_v2 */ + if (priv.proto_version == ALPS_PROTO_V8 && + ((_packetByteCount == 4 && ((packet[3] & 0x08) != 0x08)) || + (_packetByteCount == 6 && ((packet[5] & 0x10) != 0x0)))) { + priv.PSMOUSE_BAD_DATA = true; + _ringBuffer.advanceHead(priv.pktsize); + return kPS2IR_packetReady; + } + packet[_packetByteCount++] = data; - if (kPacketLengthLarge == _packetByteCount || - (kPacketLengthSmall == _packetByteCount && (packet[0] & 0xc8) == 0x08)) + if (_packetByteCount == priv.pktsize) { - // complete 6 or 3-byte packet received... - _ringBuffer.advanceHead(kPacketLengthMax); - _packetByteCount = 0; + _ringBuffer.advanceHead(priv.pktsize); return kPS2IR_packetReady; } return kPS2IR_packetBuffering; } -void ApplePS2ALPSGlidePoint::packetReady() -{ +void ApplePS2ALPSGlidePoint::packetReady() { // empty the ring buffer, dispatching each packet... - while (_ringBuffer.count() >= kPacketLengthMax) - { - UInt8* packet = _ringBuffer.tail(); - // now we have complete packet, either 6-byte or 3-byte - if ((packet[0] & 0xf8) == 0xf8) - dispatchAbsolutePointerEventWithPacket(packet, kPacketLengthLarge); - else - dispatchRelativePointerEventWithPacket(packet, kPacketLengthSmall); - _ringBuffer.advanceTail(kPacketLengthMax); + while (_ringBuffer.count() >= priv.pktsize) { + UInt8 *packet = _ringBuffer.tail(); + if (priv.PSMOUSE_BAD_DATA == false) { + if (!ignoreall) + (this->*process_packet)(packet); + } else { + IOLog("ALPS: an invalid or bare packet has been dropped...\n"); + /* Might need to perform a full HW reset here if we keep receiving bad packets (consecutively) */ + } + _packetByteCount = 0; + _ringBuffer.advanceTail(priv.pktsize); } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void ApplePS2ALPSGlidePoint::dispatchAbsolutePointerEventWithPacket(UInt8* packet, UInt32 packetSize) -{ - UInt32 buttons = 0; - int left = 0, right = 0, middle = 0; - int xdiff, ydiff, scroll; - uint64_t now_abs; - bool wasNotScrolling, willScroll; - - int x = (packet[1] & 0x7f) | ((packet[2] & 0x78) << (7-3)); - int y = (packet[4] & 0x7f) | ((packet[3] & 0x70) << (7-4)); - int z = packet[5]; // touch pression - - clock_get_uptime(&now_abs); - - left |= (packet[2]) & 1; - left |= (packet[3]) & 1; - right |= (packet[3] >> 1) & 1; - - if (packet[0] != 0xff) - { - left |= (packet[0]) & 1; - right |= (packet[0] >> 1) & 1; - middle |= (packet[0] >> 2) & 1; - middle |= (packet[3] >> 2) & 1; - } +bool ApplePS2ALPSGlidePoint::deviceSpecificInit() { - buttons |= left ? 0x01 : 0; - buttons |= right ? 0x02 : 0; - buttons |= middle ? 0x04 : 0; + // Setup expected packet size + priv.pktsize = priv.proto_version == ALPS_PROTO_V4 ? 8 : 6; - /*DEBUG_LOG("Absolute packet: x: %d, y: %d, xpos: %d, ypos: %d, buttons: %x, " - "z: %d, zpos: %d\n", x, y, (int)_xpos, (int)_ypos, (int)buttons, - (int)z, (int)_zpos);*/ - - wasNotScrolling = _scrolling == SCROLL_NONE; - scroll = insideScrollArea(x, y); - - willScroll = ((scroll & SCROLL_VERT) && _edgevscroll) || - ((scroll & SCROLL_HORIZ) && _edgehscroll); - - // Make sure we are still relative - if (z == 0 || (_zpos >= 1 && z != 0 && !willScroll)) - { - _xpos = x; - _ypos = y; - } - - // Are we scrolling? - if (willScroll) - { - if (_zscrollpos <= 0 || wasNotScrolling) - { - _xscrollpos = x; - _yscrollpos = y; - } - - xdiff = x - _xscrollpos; - ydiff = y - _yscrollpos; - - ydiff = (scroll == SCROLL_VERT) ? -((int)((double)ydiff * _edgeaccellvalue)) : 0; - xdiff = (scroll == SCROLL_HORIZ) ? -((int)((double)xdiff * _edgeaccellvalue)) : 0; - - // Those "if" should provide angle tapping (simulate click on up/down - // buttons of a scrollbar), but i have to investigate more on the values, - // since currently they don't work... - if (ydiff == 0 && scroll == SCROLL_HORIZ) - ydiff = ((x >= 950 ? 25 : (x <= 100 ? -25 : 0)) / max(_edgeaccellvalue, 1)); - - if (xdiff == 0 && scroll == SCROLL_VERT) - xdiff = ((y >= 950 ? 25 : (y <= 100 ? -25 : 0)) / max(_edgeaccellvalue, 1)); - - dispatchScrollWheelEventX(ydiff, xdiff, 0, now_abs); - _zscrollpos = z; - return; + if (!(this->*hw_init)()) { + goto init_fail; } - _zpos = z == 0 ? _zpos + 1 : 0; - _scrolling = SCROLL_NONE; - - xdiff = x - _xpos; - ydiff = y - _ypos; - - _xpos = x; - _ypos = y; - - //DEBUG_LOG("Sending event: %d,%d,%d\n",xdiff,ydiff,(int)buttons); - dispatchRelativePointerEventX(xdiff, ydiff, buttons, now_abs); -} + return true; -int ApplePS2ALPSGlidePoint::insideScrollArea(int x, int y) -{ - int scroll = 0; - if (x > 900) scroll |= SCROLL_VERT; - if (y > 650) scroll |= SCROLL_HORIZ; - - if (x > 900 && y > 650) - { - if (_scrolling == SCROLL_VERT) - scroll = SCROLL_VERT; - else - scroll = SCROLL_HORIZ; - } - - _scrolling = scroll; - return scroll; +init_fail: + IOLog("ALPS: Hardware initialization failed. TouchPad probably won't work\n"); + resetMouse(); + return false; } -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +/* ============================================================================================== */ +/* ==============================||\\ alps.c Implementation //||================================= */ +/* ============================================================================================== */ -void ApplePS2ALPSGlidePoint:: - dispatchRelativePointerEventWithPacket( UInt8 * packet, - UInt32 packetSize ) -{ - // - // Process the three byte relative format packet that was retreived from the - // trackpad. The format of the bytes is as follows: - // - // 7 6 5 4 3 2 1 0 - // ----------------------- - // YO XO YS XS 1 M R L - // X7 X6 X5 X4 X3 X3 X1 X0 (X delta) - // Y7 Y6 Y5 Y4 Y3 Y2 Y1 Y0 (Y delta) - // - UInt32 buttons = 0; - SInt32 dx, dy; +void ApplePS2ALPSGlidePoint::alps_process_packet_v1_v2(UInt8 *packet) { - if ( (packet[0] & 0x1) ) buttons |= 0x1; // left button (bit 0 in packet) - if ( (packet[0] & 0x2) ) buttons |= 0x2; // right button (bit 1 in packet) - if ( (packet[0] & 0x4) ) buttons |= 0x4; // middle button (bit 2 in packet) - - dx = packet[1]; - if(packet[0] & 0x10) - dx = dx -256; - - dy = packet[2]; - if(packet[0] & 0x20) - dy = dy - 256; + // Check if input is disabled via ApplePS2Keyboard request + if (ignoreall) + return; + int x, y, z, fin, ges, left, right, middle, buttons = 0; + // Unused code + // int back = 0, forward = 0, fingers = 0; uint64_t now_abs; - clock_get_uptime(&now_abs); - dispatchRelativePointerEventX(dx, dy, buttons, now_abs); -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void ApplePS2ALPSGlidePoint::setTapEnable( bool enable ) -{ - // - // Instructs the trackpad to honor or ignore tapping - // - - ALPSStatus_t Status; - getStatus(&Status); - if (Status.byte0 & 0x04) - { - DEBUG_LOG("Tapping can only be toggled.\n"); - enable = false; - } + clock_get_uptime(&now_abs); - int cmd = enable ? kDP_SetMouseSampleRate : kDP_SetMouseResolution; - int arg = enable ? 0x0A : 0x00; + if (priv.proto_version == ALPS_PROTO_V1) { + left = packet[2] & 0x10; + right = packet[2] & 0x08; + middle = 0; + x = packet[1] | ((packet[0] & 0x07) << 7); + y = packet[4] | ((packet[3] & 0x07) << 7); + z = packet[5]; + } else { + left = packet[3] & 1; + right = packet[3] & 2; + middle = packet[3] & 4; + x = packet[1] | ((packet[2] & 0x78) << (7 - 3)); + y = packet[4] | ((packet[3] & 0x70) << (7 - 4)); + z = packet[5]; + } - TPS2Request<9> request; - request.commands[0].command = kPS2C_SendCommandAndCompareAck; - request.commands[0].inOrOut = kDP_GetMouseInformation; //sync.. - request.commands[1].command = kPS2C_ReadDataPort; - request.commands[1].inOrOut = 0; - request.commands[2].command = kPS2C_ReadDataPort; - request.commands[2].inOrOut = 0; - request.commands[3].command = kPS2C_ReadDataPort; - request.commands[3].inOrOut = 0; - request.commands[4].command = kPS2C_SendCommandAndCompareAck; - request.commands[4].inOrOut = kDP_SetDefaultsAndDisable; - request.commands[5].command = kPS2C_SendCommandAndCompareAck; - request.commands[5].inOrOut = kDP_SetDefaultsAndDisable; - request.commands[6].command = kPS2C_SendCommandAndCompareAck; - request.commands[6].inOrOut = cmd; - request.commands[7].command = kPS2C_WriteDataPort; - request.commands[7].inOrOut = arg; - request.commands[8].command = kPS2C_ReadDataPortAndCompare; - request.commands[8].inOrOut = kSC_Acknowledge; - request.commandsCount = 9; - assert(request.commandsCount <= countof(request.commands)); - _device->submitRequestAndBlock(&request); + // macOS does not support forward and back buttons + /* + if (priv.flags & ALPS_FW_BK_1) { + back = packet[0] & 0x10; + forward = packet[2] & 4; + } - getStatus(&Status); -} + if (priv.flags & ALPS_FW_BK_2) { + back = packet[3] & 4; + forward = packet[2] & 4; + if ((middle = forward && back)) { + forward = back = 0; + } + } + */ -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + ges = packet[2] & 1; + fin = packet[2] & 2; -void ApplePS2ALPSGlidePoint::setTouchPadEnable( bool enable ) -{ - // - // Instructs the trackpad to start or stop the reporting of data packets. - // It is safe to issue this request from the interrupt/completion context. - // + if ((priv.flags & ALPS_DUALPOINT) && z == 127) { + int dx, dy; + dx = x > 383 ? (x - 768) : x; + dy = -(y > 255 ? (y - 512) : y); - // (mouse enable/disable command) - TPS2Request<5> request; - request.commands[0].command = kPS2C_SendCommandAndCompareAck; - request.commands[0].inOrOut = kDP_SetDefaultsAndDisable; - request.commands[1].command = kPS2C_SendCommandAndCompareAck; - request.commands[1].inOrOut = kDP_SetDefaultsAndDisable; - request.commands[2].command = kPS2C_SendCommandAndCompareAck; - request.commands[2].inOrOut = kDP_SetDefaultsAndDisable; - request.commands[3].command = kPS2C_SendCommandAndCompareAck; - request.commands[3].inOrOut = kDP_SetDefaultsAndDisable; + dispatchRelativePointerEventX(dx, dy, buttons, now_abs); + return; + } - // (mouse or pad enable/disable command) - request.commands[4].command = kPS2C_SendCommandAndCompareAck; - request.commands[4].inOrOut = enable ? kDP_Enable : kDP_SetDefaultsAndDisable; - request.commandsCount = 5; - assert(request.commandsCount <= countof(request.commands)); - _device->submitRequestAndBlock(&request); -} + /* Some models have separate stick button bits */ + if (priv.flags & ALPS_STICK_BITS) { + left |= packet[0] & 1; + right |= packet[0] & 2; + middle |= packet[0] & 4; + } -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + /* To make button reporting compatible with rest of driver */ + buttons |= left ? 0x01 : 0; + buttons |= right ? 0x02 : 0; + buttons |= middle ? 0x04 : 0; -IOReturn ApplePS2ALPSGlidePoint::setParamProperties( OSDictionary * dict ) -{ - OSNumber * clicking = OSDynamicCast( OSNumber, dict->getObject("Clicking") ); - OSNumber * dragging = OSDynamicCast( OSNumber, dict->getObject("Dragging") ); - OSNumber * draglock = OSDynamicCast( OSNumber, dict->getObject("DragLock") ); - OSNumber * hscroll = OSDynamicCast( OSNumber, dict->getObject("TrackpadHorizScroll") ); - OSNumber * vscroll = OSDynamicCast( OSNumber, dict->getObject("TrackpadScroll") ); - OSNumber * eaccell = OSDynamicCast( OSNumber, dict->getObject("HIDTrackpadScrollAcceleration") ); - - OSCollectionIterator* iter = OSCollectionIterator::withCollection( dict ); - OSObject* obj; - - iter->reset(); - while ((obj = iter->getNextObject()) != NULL) - { - OSString* str = OSDynamicCast( OSString, obj ); - OSNumber* val = OSDynamicCast( OSNumber, dict->getObject( str ) ); - - if (val) - DEBUG_LOG("%s: Dictionary Object: %s Value: %d\n", getName(), - str->getCStringNoCopy(), val->unsigned32BitValue()); - else - DEBUG_LOG("%s: Dictionary Object: %s Value: ??\n", getName(), - str->getCStringNoCopy()); + /* Convert hardware tap to a reasonable Z value */ + if (ges && !fin) { + z = 40; } - OSSafeReleaseNULL(iter); - if ( clicking ) - { - UInt8 newModeByteValue = clicking->unsigned32BitValue() & 0x1 ? - kTapEnabled : - 0; - if (_touchPadModeByte != newModeByteValue) - { - _touchPadModeByte = newModeByteValue; - setTapEnable(_touchPadModeByte); - setProperty("Clicking", clicking); - setAbsoluteMode(); //restart the mouse... - } - } + // REVIEW: Check if this is correct + /* + * A "tap and drag" operation is reported by the hardware as a transition + * from (!fin && ges) to (fin && ges). This should be translated to the + * sequence Z>0, Z==0, Z>0, so the Z==0 event has to be generated manually. + */ + // if (ges && fin && !priv.prev_fin) { + // z = 0; + // fingers = 0; + // dispatchRelativePointerEventX(x, y, buttons, now_abs); + // } - if (dragging) - { - _dragging = dragging->unsigned32BitValue() & 0x1 ? true : false; - setProperty("Dragging", dragging); - } + priv.prev_fin = fin; - if (draglock) - { - _draglock = draglock->unsigned32BitValue() & 0x1 ? true : false; - setProperty("DragLock", draglock); - } + // fingers = z > 30 ? 1 : 0; - if (hscroll) - { - _edgehscroll = hscroll->unsigned32BitValue() & 0x1 ? true : false; - setProperty("TrackpadHorizScroll", hscroll); - } + if (z > 30) + dispatchRelativePointerEventX(x, y, buttons, now_abs); - if (vscroll) - { - _edgevscroll = vscroll->unsigned32BitValue() & 0x1 ? true : false; - setProperty("TrackpadScroll", vscroll); + if (priv.flags & ALPS_WHEEL) { + int scrollAmount = ((packet[2] << 1) & 0x08) - ((packet[0] >> 4) & 0x07); + if (scrollAmount) { + dispatchScrollWheelEventX(scrollAmount, 0, 0, now_abs); } - if (eaccell) - { - _edgeaccell = eaccell->unsigned32BitValue(); - _edgeaccellvalue = (((double)(_edgeaccell / 1966.08)) / 75.0); - _edgeaccellvalue = _edgeaccellvalue == 0 ? 0.01 : _edgeaccellvalue; - setProperty("HIDTrackpadScrollAcceleration", eaccell); } - - return super::setParamProperties(dict); } -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void ApplePS2ALPSGlidePoint::setDevicePowerState( UInt32 whatToDo ) +static void alps_get_bitmap_points(unsigned int map, + struct alps_bitmap_point *low, + struct alps_bitmap_point *high, + int *fingers) { - switch ( whatToDo ) - { - case kPS2C_DisableDevice: - - // - // Disable touchpad. - // + struct alps_bitmap_point *point; + int i, bit, prev_bit = 0; - setTouchPadEnable( false ); + point = low; + for (i = 0; map != 0; i++, map >>= 1) { + bit = map & 1; + if (bit) { + if (!prev_bit) { + point->start_bit = i; + point->num_bits = 0; + (*fingers)++; + } + point->num_bits++; + } else { + if (prev_bit) + point = high; + } + prev_bit = bit; + } +} + +/* + * Process bitmap data from semi-mt protocols. Returns the number of + * fingers detected. A return value of 0 means at least one of the + * bitmaps was empty. + * + * The bitmaps don't have enough data to track fingers, so this function + * only generates points representing a bounding box of all contacts. + * These points are returned in fields->mt when the return value + * is greater than 0. + */ +int ApplePS2ALPSGlidePoint::alps_process_bitmap(struct alps_data *priv, + struct alps_fields *fields) +{ + + int i, fingers_x = 0, fingers_y = 0, fingers, closest; + struct alps_bitmap_point x_low = {0,}, x_high = {0,}; + struct alps_bitmap_point y_low = {0,}, y_high = {0,}; + struct input_mt_pos corner[4]; + + + if (!fields->x_map || !fields->y_map) { + return 0; + } + + alps_get_bitmap_points(fields->x_map, &x_low, &x_high, &fingers_x); + alps_get_bitmap_points(fields->y_map, &y_low, &y_high, &fingers_y); + + /* + * Fingers can overlap, so we use the maximum count of fingers + * on either axis as the finger count. + */ + fingers = max(fingers_x, fingers_y); + + /* + * If an axis reports only a single contact, we have overlapping or + * adjacent fingers. Divide the single contact between the two points. + */ + if (fingers_x == 1) { + i = (x_low.num_bits - 1) / 2; + x_low.num_bits = x_low.num_bits - i; + x_high.start_bit = x_low.start_bit + i; + x_high.num_bits = max(i, 1); + } + + if (fingers_y == 1) { + i = (y_low.num_bits - 1) / 2; + y_low.num_bits = y_low.num_bits - i; + y_high.start_bit = y_low.start_bit + i; + y_high.num_bits = max(i, 1); + } + + /* top-left corner */ + corner[0].x = (priv->x_max * (2 * x_low.start_bit + x_low.num_bits - 1)) / + (2 * (priv->x_bits - 1)); + corner[0].y = (priv->y_max * (2 * y_low.start_bit + y_low.num_bits - 1)) / + (2 * (priv->y_bits - 1)); + + /* top-right corner */ + corner[1].x = (priv->x_max * (2 * x_high.start_bit + x_high.num_bits - 1)) / + (2 * (priv->x_bits - 1)); + corner[1].y = (priv->y_max * (2 * y_low.start_bit + y_low.num_bits - 1)) / + (2 * (priv->y_bits - 1)); + + /* bottom-right corner */ + corner[2].x = (priv->x_max * (2 * x_high.start_bit + x_high.num_bits - 1)) / + (2 * (priv->x_bits - 1)); + corner[2].y = (priv->y_max * (2 * y_high.start_bit + y_high.num_bits - 1)) / + (2 * (priv->y_bits - 1)); + + /* bottom-left corner */ + corner[3].x = (priv->x_max * (2 * x_low.start_bit + x_low.num_bits - 1)) / + (2 * (priv->x_bits - 1)); + corner[3].y = (priv->y_max * (2 * y_high.start_bit + y_high.num_bits - 1)) / + (2 * (priv->y_bits - 1)); + + /* x-bitmap order is reversed on v5 touchpads */ + if (priv->proto_version == ALPS_PROTO_V5) { + for (i = 0; i < 4; i++) + corner[i].x = priv->x_max - corner[i].x; + } + + /* y-bitmap order is reversed on v3 and v4 touchpads */ + if (priv->proto_version == ALPS_PROTO_V3 || priv->proto_version == ALPS_PROTO_V4) { + for (i = 0; i < 4; i++) + corner[i].y = priv->y_max - corner[i].y; + } + + /* + * We only select a corner for the second touch once per 2 finger + * touch sequence to avoid the chosen corner (and thus the coordinates) + * jumping around when the first touch is in the middle. + */ + if (priv->second_touch == -1) { + /* Find corner closest to our st coordinates */ + closest = 0x7fffffff; + for (i = 0; i < 4; i++) { + int dx = fields->st.x - corner[i].x; + int dy = fields->st.y - corner[i].y; + int distance = dx * dx + dy * dy; + + if (distance < closest) { + priv->second_touch = i; + closest = distance; + } + } + /* And select the opposite corner to use for the 2nd touch */ + priv->second_touch = (priv->second_touch + 2) % 4; + } + + fields->mt[0] = fields->st; + fields->mt[1] = corner[priv->second_touch]; + +#if DEBUG + IOLog("ALPS: BITMAP\n"); + + unsigned int ymap = fields->y_map; + + for (int i = 0; ymap != 0; i++, ymap >>= 1) { + unsigned int xmap = fields->x_map; + char bitLog[160]; + strlcpy(bitLog, "ALPS: ", sizeof(bitLog) + 1); + + for (int j = 0; xmap != 0; j++, xmap >>= 1) { + strlcat(bitLog, (ymap & 1 && xmap & 1) ? "1 " : "0 ", sizeof(bitLog) + 1); + } + + IOLog("ALPS: %s\n", bitLog); + } + + IOLog("ALPS: Process Bitmap, Corner=%d, Fingers=%d, x1=%d, x2=%d, y1=%d, y2=%d xmap=%d ymap=%d\n", priv->second_touch, fingers, fields->mt[0].x, fields->mt[1].x, fields->mt[0].y, fields->mt[1].y, fields->x_map, fields->y_map); +#endif // DEBUG + return fingers; +} + +void ApplePS2ALPSGlidePoint::alps_process_trackstick_packet_v3(UInt8 *packet) { + int x, y, left, right, middle; + // Unused code + // int z; + uint64_t now_abs; + UInt32 buttons = 0, raw_buttons = 0; + + /* It should be a DualPoint when received trackstick packet */ + if (!(priv.flags & ALPS_DUALPOINT)) { + DEBUG_LOG("ALPS: Rejected trackstick packet from non DualPoint device\n"); + return; + } + + /* Sanity check packet */ + if (!(packet[0] & 0x40)) { + DEBUG_LOG("ALPS: Bad trackstick packet, disregarding...\n"); + return; + } + + /* There is a special packet that seems to indicate the end + * of a stream of trackstick data. Filter these out + */ + if (packet[1] == 0x7f && packet[2] == 0x7f && packet[4] == 0x7f) { + return; + } + + x = (SInt8) (((packet[0] & 0x20) << 2) | (packet[1] & 0x7f)); + y = (SInt8) (((packet[0] & 0x10) << 3) | (packet[2] & 0x7f)); + // Unused code + // z = (packet[4] & 0x7f); + + /* + * The x and y values tend to be quite large, and when used + * alone the trackstick is difficult to use. Scale them down + * to compensate. + */ + x /= 8; + y /= 8; + + /* To get proper movement direction */ + y = -y; + + clock_get_uptime(&now_abs); + + /* + * Most ALPS models report the trackstick buttons in the touchpad + * packets, but a few report them here. No reliable way has been + * found to differentiate between the models upfront, so we enable + * the quirk in response to seeing a button press in the trackstick + * packet. + */ + left = packet[3] & 0x01; + right = packet[3] & 0x02; + middle = packet[3] & 0x04; + + if (!(priv.quirks & ALPS_QUIRK_TRACKSTICK_BUTTONS) && + (left || middle || right)) { + priv.quirks |= ALPS_QUIRK_TRACKSTICK_BUTTONS; + } + + if (priv.quirks & ALPS_QUIRK_TRACKSTICK_BUTTONS) { + raw_buttons |= left ? 0x01 : 0; + raw_buttons |= right ? 0x02 : 0; + raw_buttons |= middle ? 0x04 : 0; + } + + /* Button status can appear in normal packet */ + if (0 == raw_buttons) { + buttons = lastbuttons; + } else { + buttons = raw_buttons; + lastbuttons = buttons; + } + + /* If middle button is pressed, switch to scroll mode. Else, move pointer normally */ + if (0 == (buttons & 0x04)) { + dispatchRelativePointerEventX(x, y, buttons, now_abs); + } else { + dispatchScrollWheelEventX(-y, -x, 0, now_abs); + } +} + +bool ApplePS2ALPSGlidePoint::alps_decode_buttons_v3(struct alps_fields *f, unsigned char *p) { + f->left = !!(p[3] & 0x01); + f->right = !!(p[3] & 0x02); + f->middle = !!(p[3] & 0x04); + + f->ts_left = !!(p[3] & 0x10); + f->ts_right = !!(p[3] & 0x20); + f->ts_middle = !!(p[3] & 0x40); + return true; +} + +bool ApplePS2ALPSGlidePoint::alps_decode_pinnacle(struct alps_fields *f, UInt8 *p) { + f->first_mp = !!(p[4] & 0x40); + f->is_mp = !!(p[0] & 0x40); + + if (f->is_mp) { + f->fingers = (p[5] & 0x3) + 1; + f->x_map = ((p[4] & 0x7e) << 8) | + ((p[1] & 0x7f) << 2) | + ((p[0] & 0x30) >> 4); + f->y_map = ((p[3] & 0x70) << 4) | + ((p[2] & 0x7f) << 1) | + (p[4] & 0x01); + } else { + f->st.x = ((p[1] & 0x7f) << 4) | ((p[4] & 0x30) >> 2) | + ((p[0] & 0x30) >> 4); + f->st.y = ((p[2] & 0x7f) << 4) | (p[4] & 0x0f); + f->pressure = p[5] & 0x7f; + + alps_decode_buttons_v3(f, p); + } + return true; +} + +bool ApplePS2ALPSGlidePoint::alps_decode_rushmore(struct alps_fields *f, UInt8 *p) { + f->first_mp = !!(p[4] & 0x40); + f->is_mp = !!(p[5] & 0x40); + + if (f->is_mp) { + f->fingers = max((p[5] & 0x3), ((p[5] >> 2) & 0x3)) + 1; + f->x_map = ((p[5] & 0x10) << 11) | + ((p[4] & 0x7e) << 8) | + ((p[1] & 0x7f) << 2) | + ((p[0] & 0x30) >> 4); + f->y_map = ((p[5] & 0x20) << 6) | + ((p[3] & 0x70) << 4) | + ((p[2] & 0x7f) << 1) | + (p[4] & 0x01); + } else { + f->st.x = ((p[1] & 0x7f) << 4) | ((p[4] & 0x30) >> 2) | + ((p[0] & 0x30) >> 4); + f->st.y = ((p[2] & 0x7f) << 4) | (p[4] & 0x0f); + f->pressure = p[5] & 0x7f; + + alps_decode_buttons_v3(f, p); + } + return true; +} + +bool ApplePS2ALPSGlidePoint::alps_decode_dolphin(struct alps_fields *f, UInt8 *p) { + uint64_t palm_data = 0; + + f->first_mp = !!(p[0] & 0x02); + f->is_mp = !!(p[0] & 0x20); + + if (!f->is_mp) { + f->st.x = ((p[1] & 0x7f) | ((p[4] & 0x0f) << 7)); + f->st.y = ((p[2] & 0x7f) | ((p[4] & 0xf0) << 3)); + f->pressure = (p[0] & 4) ? 0 : p[5] & 0x7f; + alps_decode_buttons_v3(f, p); + } else { + f->fingers = ((p[0] & 0x6) >> 1 | + (p[0] & 0x10) >> 2); + + palm_data = (p[1] & 0x7f) | + ((p[2] & 0x7f) << 7) | + ((p[4] & 0x7f) << 14) | + ((p[5] & 0x7f) << 21) | + ((p[3] & 0x07) << 28) | + (((uint64_t)p[3] & 0x70) << 27) | + (((uint64_t)p[0] & 0x01) << 34); + + /* Y-profile is stored in P(0) to p(n-1), n = y_bits; */ + f->y_map = palm_data & (BIT(priv.y_bits) - 1); + + /* X-profile is stored in p(n) to p(n+m-1), m = x_bits; */ + f->x_map = (palm_data >> priv.y_bits) & (BIT(priv.x_bits) - 1); + } + return true; +} + +void ApplePS2ALPSGlidePoint::alps_process_touchpad_packet_v3_v5(UInt8 *packet) { + int fingers = 0; + struct alps_fields f; + + // Check if input is disabled via ApplePS2Keyboard request + if (ignoreall) + return; + + memset(&f, 0, sizeof(f)); + + (this->*decode_fields)(&f, packet); + /* + * There's no single feature of touchpad position and bitmap packets + * that can be used to distinguish between them. We rely on the fact + * that a bitmap packet should always follow a position packet with + * bit 6 of packet[4] set. + */ + if (priv.multi_packet) { + /* + * Sometimes a position packet will indicate a multi-packet + * sequence, but then what follows is another position + * packet. Check for this, and when it happens process the + * position packet as usual. + */ + if (f.is_mp) { + fingers = f.fingers; + /* + * Bitmap processing uses position packet's coordinate + * data, so we need to do decode it first. + */ + (this->*decode_fields)(&f, priv.multi_data); + if (alps_process_bitmap(&priv, &f) == 0) { + fingers = 0; /* Use st data */ + } + } else { + priv.multi_packet = 0; + } + } + + /* + * Bit 6 of byte 0 is not usually set in position packets. The only + * times it seems to be set is in situations where the data is + * suspect anyway, e.g. a palm resting flat on the touchpad. Given + * this combined with the fact that this bit is useful for filtering + * out misidentified bitmap packets, we reject anything with this + * bit set. + */ + if (f.is_mp) { + return; + } + + if (!priv.multi_packet && (f.first_mp)) { + priv.multi_packet = 1; + memcpy(priv.multi_data, packet, sizeof(priv.multi_data)); + return; + } + + priv.multi_packet = 0; + +#if 0 + /* + * Sometimes the hardware sends a single packet with z = 0 + * in the middle of a stream. Real releases generate packets + * with x, y, and z all zero, so these seem to be flukes. + * Ignore them. + */ + if (f.st.x && f.st.y && !f.pressure) { + //return; //Dr Hurt: This causes jitter + } +#endif + + /* Use st data when we don't have mt data */ + if (fingers < 2) { + f.mt[0].x = f.st.x; + f.mt[0].y = f.st.y; + fingers = f.pressure > 0 ? 1 : 0; + priv.second_touch = -1; + } + + /* Reverse y co-ordinates to have 0 at bottom for gestures to work */ + f.mt[0].y = priv.y_max - f.mt[0].y; + f.mt[1].y = priv.y_max - f.mt[1].y; + + /* Ignore 1 finger events after 2 finger scroll to prevent jitter */ + // if (last_fingers == 2 && fingers == 1 && scrolldebounce) + // fingers = 2; + + DEBUG_LOG("ALPS: Amount of finger(s) accessing alps_process_touchpad_packet_v3_v5: %d\n", fingers); + + if (fingers >= 2) { + fingerStates[1].x = f.mt[1].x; + fingerStates[1].y = f.mt[1].y; + fingerStates[1].z = f.pressure; + + if (fingerStates[1].x > X_MAX_POSITIVE) + fingerStates[1].x -= 1 << ABS_POS_BITS; + else if (fingerStates[1].x == X_MAX_POSITIVE) + fingerStates[1].x = XMAX; + + if (fingerStates[1].y > Y_MAX_POSITIVE) + fingerStates[1].y -= 1 << ABS_POS_BITS; + else if (fingerStates[1].y == Y_MAX_POSITIVE) + fingerStates[1].y = YMAX; + } + // normal "packet" + fingerStates[0].x = f.mt[0].x; + fingerStates[0].y = f.mt[0].y; + fingerStates[0].z = f.pressure; + + DEBUG_LOG("ALPS: fingerStates[0] report: x: %d, y: %d, z: %d\n", fingerStates[0].x, fingerStates[0].y, fingerStates[0].z); + + if (fingerStates[0].x > X_MAX_POSITIVE) + fingerStates[0].x -= 1 << ABS_POS_BITS; + else if (fingerStates[0].x == X_MAX_POSITIVE) + fingerStates[0].x = XMAX; + + if (fingerStates[0].y > Y_MAX_POSITIVE) + fingerStates[0].y -= 1 << ABS_POS_BITS; + else if (fingerStates[0].y == Y_MAX_POSITIVE) + fingerStates[0].y = YMAX; + + clampedFingerCount = fingers; + + if (clampedFingerCount > MAX_TOUCHES) + clampedFingerCount = MAX_TOUCHES; + + if (renumberFingers()) + sendTouchData(); + + alps_buttons(f); +} + +void ApplePS2ALPSGlidePoint::alps_process_packet_v3(UInt8 *packet) { + /* + * v3 protocol packets come in three types, two representing + * touchpad data and one representing trackstick data. + * Trackstick packets seem to be distinguished by always + * having 0x3f in the last byte. This value has never been + * observed in the last byte of either of the other types + * of packets. + */ + if (packet[5] == 0x3f) { + alps_process_trackstick_packet_v3(packet); + return; + } + + alps_process_touchpad_packet_v3_v5(packet); +} + +void ApplePS2ALPSGlidePoint::alps_process_packet_v6(UInt8 *packet) { + // Check if input is disabled via ApplePS2Keyboard request + if (ignoreall) + return; + + int x, y, z; + int buttons = 0; + + uint64_t now_abs; + clock_get_uptime(&now_abs); + + /* + * We can use Byte5 to distinguish if the packet is from Touchpad + * or Trackpoint. + * Touchpad: 0 - 0x7E + * Trackpoint: 0x7F + */ + if (packet[5] == 0x7F) { + /* It should be a DualPoint when received Trackpoint packet */ + if (!(priv.flags & ALPS_DUALPOINT)) { + DEBUG_LOG("ALPS: Rejected trackstick packet from non DualPoint device\n"); + return; + } + + /* Trackpoint packet */ + x = packet[1] | ((packet[3] & 0x20) << 2); + y = packet[2] | ((packet[3] & 0x40) << 1); + z = packet[4]; + + left = packet[3] & 0x01; + right = packet[3] & 0x02; + middle = packet[3] & 0x04; + + buttons |= left ? 0x01 : 0; + buttons |= right ? 0x02 : 0; + buttons |= middle ? 0x04 : 0; + + /* To prevent the cursor jump when finger lifted */ + // z is unused code + if (x == 0x7F && y == 0x7F && z == 0x7F) + x = y = 0; + + // Y is inverted + y = -y; + + /* Divide 4 since trackpoint's speed is too fast */ + dispatchRelativePointerEventX(x / 4, y / 4, buttons, now_abs); + return; + } + + /* Touchpad packet */ + struct alps_fields f; + + f.mt[0].x = packet[1] | ((packet[3] & 0x78) << 4); + f.mt[0].y = packet[2] | ((packet[4] & 0x78) << 4); + z = packet[5]; + f.pressure = z; + f.left = packet[3] & 0x01; + f.right = packet[3] & 0x02; + + f.fingers = z > 30 ? 1 : 0; + + buttons |= f.left ? 0x01 : 0; + buttons |= f.right ? 0x02 : 0; + + dispatchRelativePointerEventX(f.mt[0].x, f.mt[0].y, buttons, now_abs); +} + +void ApplePS2ALPSGlidePoint::alps_process_packet_v4(UInt8 *packet) { + // Check if input is disabled via ApplePS2Keyboard request + if (ignoreall) + return; + + SInt32 offset; + // UInt32 buttons = 0; + struct alps_fields f; + + f.fingers = 0; + + /* + * v4 has a 6-byte encoding for bitmap data, but this data is + * broken up between 3 normal packets. Use priv.multi_packet to + * track our position in the bitmap packet. + */ + if (packet[6] & 0x40) { + /* sync, reset position */ + priv.multi_packet = 0; + } + + if (priv.multi_packet > 2) { + return; + } + + offset = 2 * priv.multi_packet; + priv.multi_data[offset] = packet[6]; + priv.multi_data[offset + 1] = packet[7]; + + f.left = !!(packet[4] & 0x01); + f.right = !!(packet[4] & 0x02); + + f.st.x = ((packet[1] & 0x7f) << 4) | ((packet[3] & 0x30) >> 2) | + ((packet[0] & 0x30) >> 4); + f.st.y = ((packet[2] & 0x7f) << 4) | (packet[3] & 0x0f); + f.pressure = packet[5] & 0x7f; + + if (++priv.multi_packet > 2) { + priv.multi_packet = 0; + + f.x_map = ((priv.multi_data[2] & 0x1f) << 10) | + ((priv.multi_data[3] & 0x60) << 3) | + ((priv.multi_data[0] & 0x3f) << 2) | + ((priv.multi_data[1] & 0x60) >> 5); + f.y_map = ((priv.multi_data[5] & 0x01) << 10) | + ((priv.multi_data[3] & 0x1f) << 5) | + (priv.multi_data[1] & 0x1f); + + f.fingers = alps_process_bitmap(&priv, &f); + + } + + /* Use st data when we don't have mt data */ + if (f.fingers < 2) { + f.mt[0].x = f.st.x; + f.mt[0].y = f.st.y; + f.fingers = f.pressure > 0 ? 1 : 0; + priv.second_touch = -1; + } + + DEBUG_LOG("ALPS: There are currently %d finger(s) accessing alps_parse_hw_state\n", f.fingers); + + if (f.fingers >= 2) { + fingerStates[1].x = f.mt[1].x; + fingerStates[1].y = f.mt[1].y; + fingerStates[1].z = f.pressure; + + if (fingerStates[1].x > X_MAX_POSITIVE) + fingerStates[1].x -= 1 << ABS_POS_BITS; + else if (fingerStates[1].x == X_MAX_POSITIVE) + fingerStates[1].x = XMAX; + + if (fingerStates[1].y > Y_MAX_POSITIVE) + fingerStates[1].y -= 1 << ABS_POS_BITS; + else if (fingerStates[1].y == Y_MAX_POSITIVE) + fingerStates[1].y = YMAX; + } + // normal "packet" + fingerStates[0].x = f.mt[0].x; + fingerStates[0].y = f.mt[0].y; + fingerStates[0].z = f.pressure; + + DEBUG_LOG("ALPS: fingerStates[0] report: x: %d, y: %d, z: %d\n", fingerStates[0].x, fingerStates[0].y, fingerStates[0].z); + + if (fingerStates[0].x > X_MAX_POSITIVE) + fingerStates[0].x -= 1 << ABS_POS_BITS; + else if (fingerStates[0].x == X_MAX_POSITIVE) + fingerStates[0].x = XMAX; + + if (fingerStates[0].y > Y_MAX_POSITIVE) + fingerStates[0].y -= 1 << ABS_POS_BITS; + else if (fingerStates[0].y == Y_MAX_POSITIVE) + fingerStates[0].y = YMAX; + + clampedFingerCount = f.fingers; + + if (clampedFingerCount > MAX_TOUCHES) + clampedFingerCount = MAX_TOUCHES; + + if (renumberFingers()) + sendTouchData(); + + alps_buttons(f); +} + +unsigned char ApplePS2ALPSGlidePoint::alps_get_packet_id_v7(UInt8 *byte) { + unsigned char packet_id; + + if (byte[4] & 0x40) + packet_id = V7_PACKET_ID_TWO; + else if (byte[4] & 0x01) + packet_id = V7_PACKET_ID_MULTI; + else if ((byte[0] & 0x10) && !(byte[4] & 0x43)) + packet_id = V7_PACKET_ID_NEW; + else if (byte[1] == 0x00 && byte[4] == 0x00) + packet_id = V7_PACKET_ID_IDLE; + else + packet_id = V7_PACKET_ID_UNKNOWN; + + return packet_id; +} + +void ApplePS2ALPSGlidePoint::alps_get_finger_coordinate_v7(struct input_mt_pos *mt, + UInt8 *pkt, + UInt8 pkt_id) +{ + mt[0].x = ((pkt[2] & 0x80) << 4); + mt[0].x |= ((pkt[2] & 0x3F) << 5); + mt[0].x |= ((pkt[3] & 0x30) >> 1); + mt[0].x |= (pkt[3] & 0x07); + mt[0].y = (pkt[1] << 3) | (pkt[0] & 0x07); + + mt[1].x = ((pkt[3] & 0x80) << 4); + mt[1].x |= ((pkt[4] & 0x80) << 3); + mt[1].x |= ((pkt[4] & 0x3F) << 4); + mt[1].y = ((pkt[5] & 0x80) << 3); + mt[1].y |= ((pkt[5] & 0x3F) << 4); + + switch (pkt_id) { + case V7_PACKET_ID_TWO: + mt[1].x &= ~0x000F; + mt[1].y |= 0x000F; + /* Detect false-positive touches where x & y report max value */ + if (mt[1].y == 0x7ff && mt[1].x == 0xff0) + mt[1].x = 0; /* y gets set to 0 at the end of this function */ + break; + + case V7_PACKET_ID_MULTI: + mt[1].x &= ~0x003F; + mt[1].y &= ~0x0020; + mt[1].y |= ((pkt[4] & 0x02) << 4); + mt[1].y |= 0x001F; + break; + + case V7_PACKET_ID_NEW: + mt[1].x &= ~0x003F; + mt[1].x |= (pkt[0] & 0x20); + mt[1].y |= 0x000F; + break; + } + + mt[0].y = 0x7FF - mt[0].y; + mt[1].y = 0x7FF - mt[1].y; +} + +int ApplePS2ALPSGlidePoint::alps_get_mt_count(struct input_mt_pos *mt) { + int i, fingers = 0; + + for (i = 0; i < MAX_TOUCHES; i++) { + if (mt[i].x != 0 || mt[i].y != 0) + fingers++; + } + + return fingers; +} + +bool ApplePS2ALPSGlidePoint::alps_decode_packet_v7(struct alps_fields *f, UInt8 *p){ + //IOLog("ALPS: Decode V7 touchpad Packet... 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x\n", p[0], p[1], p[2], p[3], p[4], p[5]); + + unsigned char pkt_id; + + pkt_id = alps_get_packet_id_v7(p); + if (pkt_id == V7_PACKET_ID_IDLE) { + DEBUG_LOG("ALPS: V7_PACKET_ID_IDLE\n"); + return true; + } + if (pkt_id == V7_PACKET_ID_UNKNOWN) { + DEBUG_LOG("ALPS: V7_PACKET_ID_UNKNOWN\n"); + return false; + } + + /* + * NEW packets are send to indicate a discontinuity in the finger + * coordinate reporting. Specifically a finger may have moved from + * slot 0 to 1 or vice versa. INPUT_MT_TRACK takes care of this for + * us. + * + * NEW packets have 3 problems: + * 1) They do not contain middle / right button info (on non clickpads) + * this can be worked around by preserving the old button state + * 2) They do not contain an accurate fingercount, and they are + * typically send when the number of fingers changes. We cannot use + * the old finger count as that may mismatch with the amount of + * touch coordinates we've available in the NEW packet + * 3) Their x data for the second touch is inaccurate leading to + * a possible jump of the x coordinate by 16 units when the first + * non NEW packet comes in + * Since problems 2 & 3 cannot be worked around, just ignore them. + */ + if (pkt_id == V7_PACKET_ID_NEW) { + DEBUG_LOG("ALPS: V7_PACKET_ID_NEW\n"); + return true; + } + + alps_get_finger_coordinate_v7(f->mt, p, pkt_id); + + if (pkt_id == V7_PACKET_ID_TWO) { + DEBUG_LOG("ALPS: V7_PACKET_ID_TWO\n"); + f->fingers = alps_get_mt_count(f->mt); + } + else { /* pkt_id == V7_PACKET_ID_MULTI */ + DEBUG_LOG("ALPS: V7_PACKET_ID_MULTI\n"); + f->fingers = 3 + (p[5] & 0x03); + } + + f->left = (p[0] & 0x80) >> 7; + if (priv.flags & ALPS_BUTTONPAD) { + if (p[0] & 0x20) + f->fingers++; + if (p[0] & 0x10) + f->fingers++; + } else { + f->right = (p[0] & 0x20) >> 5; + f->middle = (p[0] & 0x10) >> 4; + } + + /* Sometimes a single touch is reported in mt[1] rather then mt[0] */ + if (f->fingers == 1 && f->mt[0].x == 0 && f->mt[0].y == 0) { + f->mt[0].x = f->mt[1].x; + f->mt[0].y = f->mt[1].y; + f->mt[1].x = 0; + f->mt[1].y = 0; + } + return true; +} + +void ApplePS2ALPSGlidePoint::alps_process_trackstick_packet_v7(UInt8 *packet) { + int x, y, left, right, middle; + // Disable unused code + // int z; + int buttons = 0; + + uint64_t now_abs; + clock_get_uptime(&now_abs); + + /* It should be a DualPoint when received trackstick packet */ + if (!(priv.flags & ALPS_DUALPOINT)) { + IOLog("ALPS: Rejected trackstick packet from non DualPoint device\n"); + return; + } + + x = (SInt8) ((packet[2] & 0xbf) | ((packet[3] & 0x10) << 2)); + y = (SInt8) ((packet[3] & 0x07) | (packet[4] & 0xb8) | ((packet[3] & 0x20) << 1)); +#if 0 + z = (packet[5] & 0x3f) | ((packet[3] & 0x80) >> 1); +#endif + + // Y is inverted + y = -y; + + left = (packet[1] & 0x01); + right = (packet[1] & 0x02) >> 1; + middle = (packet[1] & 0x04) >> 2; + + buttons |= left ? 0x01 : 0; + buttons |= right ? 0x02 : 0; + buttons |= middle ? 0x04 : 0; + + lastTrackStickButtons = buttons; + buttons |= lastTouchpadButtons; + + /* If middle button is pressed, switch to scroll mode. Else, move pointer normally */ + if (0 == (buttons & 0x04)) { + dispatchRelativePointerEventX(x, y, buttons, now_abs); + } else { + dispatchScrollWheelEventX(-y, -x, 0, now_abs); + } +} + +void ApplePS2ALPSGlidePoint::alps_process_touchpad_packet_v7(UInt8 *packet){ + struct alps_fields f; + + // Check if input is disabled via ApplePS2Keyboard request + if (ignoreall) + return; + + memset(&f, 0, sizeof(alps_fields)); + + (this->alps_decode_packet_v7)(&f, packet); + + /* Reverse y co-ordinates to have 0 at bottom for gestures to work */ + f.mt[0].y = priv.y_max - f.mt[0].y; + f.mt[1].y = priv.y_max - f.mt[1].y; + + DEBUG_LOG("ALPS: Amount of finger(s) accessing alps_process_touchpad_packet_v7: %d\n", f.fingers); + + if (f.fingers >= 2) { + fingerStates[1].x = f.mt[1].x; + fingerStates[1].y = f.mt[1].y; + fingerStates[1].z = f.pressure; + + if (fingerStates[1].x > X_MAX_POSITIVE) + fingerStates[1].x -= 1 << ABS_POS_BITS; + else if (fingerStates[1].x == X_MAX_POSITIVE) + fingerStates[1].x = XMAX; + + if (fingerStates[1].y > Y_MAX_POSITIVE) + fingerStates[1].y -= 1 << ABS_POS_BITS; + else if (fingerStates[1].y == Y_MAX_POSITIVE) + fingerStates[1].y = YMAX; + } + // normal "packet" + fingerStates[0].x = f.mt[0].x; + fingerStates[0].y = f.mt[0].y; + fingerStates[0].z = f.pressure; + + DEBUG_LOG("ALPS: fingerStates[0] report: x: %d, y: %d, z: %d\n", fingerStates[0].x, fingerStates[0].y, fingerStates[0].z); + + if (fingerStates[0].x > X_MAX_POSITIVE) + fingerStates[0].x -= 1 << ABS_POS_BITS; + else if (fingerStates[0].x == X_MAX_POSITIVE) + fingerStates[0].x = XMAX; + + if (fingerStates[0].y > Y_MAX_POSITIVE) + fingerStates[0].y -= 1 << ABS_POS_BITS; + else if (fingerStates[0].y == Y_MAX_POSITIVE) + fingerStates[0].y = YMAX; + + clampedFingerCount = f.fingers; + + if (clampedFingerCount > MAX_TOUCHES) + clampedFingerCount = MAX_TOUCHES; + + if (renumberFingers()) + sendTouchData(); + + alps_buttons(f); +} + +void ApplePS2ALPSGlidePoint::alps_process_packet_v7(UInt8 *packet){ + if (packet[0] == 0x48 && (packet[4] & 0x47) == 0x06) + alps_process_trackstick_packet_v7(packet); + else + alps_process_touchpad_packet_v7(packet); +} + +unsigned char ApplePS2ALPSGlidePoint::alps_get_pkt_id_ss4_v2(UInt8 *byte) { + unsigned char pkt_id = SS4_PACKET_ID_IDLE; + + switch (byte[3] & 0x30) { + case 0x00: + if (SS4_IS_IDLE_V2(byte)) { + pkt_id = SS4_PACKET_ID_IDLE; + } else { + pkt_id = SS4_PACKET_ID_ONE; + } + break; + case 0x10: + /* two-finger finger positions */ + pkt_id = SS4_PACKET_ID_TWO; + break; + case 0x20: + /* stick pointer */ + pkt_id = SS4_PACKET_ID_STICK; + break; + case 0x30: + /* third and fourth finger positions */ + pkt_id = SS4_PACKET_ID_MULTI; + break; + } + + return pkt_id; +} + +bool ApplePS2ALPSGlidePoint::alps_decode_ss4_v2(struct alps_fields *f, UInt8 *p){ + + //struct alps_data *priv; + unsigned char pkt_id; + unsigned int no_data_x, no_data_y; + uint64_t now_abs; + clock_get_uptime(&now_abs); + + pkt_id = alps_get_pkt_id_ss4_v2(p); + + /* Current packet is 1Finger coordinate packet */ + switch (pkt_id) { + case SS4_PACKET_ID_ONE: + DEBUG_LOG("ALPS: SS4_PACKET_ID_ONE\n"); + f->mt[0].x = SS4_1F_X_V2(p); + f->mt[0].y = SS4_1F_Y_V2(p); + DEBUG_LOG("ALPS: Coordinates for SS4_PACKET_ID_ONE: %dx%d\n", f->mt[0].x, f->mt[0].y); + f->pressure = ((SS4_1F_Z_V2(p)) * 2) & 0x7f; + /* + * When a button is held the device will give us events + * with x, y, and pressure of 0. This causes annoying jumps + * if a touch is released while the button is held. + * Handle this by claiming zero contacts. + */ + f->fingers = f->pressure > 0 ? 1 : 0; + f->first_mp = 0; + f->is_mp = 0; + break; + + case SS4_PACKET_ID_TWO: + DEBUG_LOG("ALPS: SS4_PACKET_ID_TWO\n"); + if (priv.flags & ALPS_BUTTONPAD) { + if (IS_SS4PLUS_DEV(priv.dev_id)) { + f->mt[0].x = SS4_PLUS_BTL_MF_X_V2(p, 0); + f->mt[1].x = SS4_PLUS_BTL_MF_X_V2(p, 1); + } else { + f->mt[0].x = SS4_BTL_MF_X_V2(p, 0); + f->mt[1].x = SS4_BTL_MF_X_V2(p, 1); + } + f->mt[0].y = SS4_BTL_MF_Y_V2(p, 0); + f->mt[1].y = SS4_BTL_MF_Y_V2(p, 1); + } else { + if (IS_SS4PLUS_DEV(priv.dev_id)) { + f->mt[0].x = SS4_PLUS_STD_MF_X_V2(p, 0); + f->mt[1].x = SS4_PLUS_STD_MF_X_V2(p, 1); + } else { + f->mt[0].x = SS4_STD_MF_X_V2(p, 0); + f->mt[1].x = SS4_STD_MF_X_V2(p, 1); + } + f->mt[0].y = SS4_STD_MF_Y_V2(p, 0); + f->mt[1].y = SS4_STD_MF_Y_V2(p, 1); + } + DEBUG_LOG("ALPS: Coordinates for SS4_PACKET_ID_TWO: [0]:%dx%d [1]:%dx%d\n", f->mt[0].x, f->mt[0].y, f->mt[1].x, f->mt[1].y); + f->pressure = SS4_MF_Z_V2(p, 0) ? 0x30 : 0; + + if (SS4_IS_MF_CONTINUE(p)) { + f->first_mp = 1; + } else { + f->fingers = 2; + f->first_mp = 0; + } + f->is_mp = 0; + + break; + + case SS4_PACKET_ID_MULTI: + DEBUG_LOG("ALPS: SS4_PACKET_ID_MULTI\n"); + if (priv.flags & ALPS_BUTTONPAD) { + if (IS_SS4PLUS_DEV(priv.dev_id)) { + f->mt[2].x = SS4_PLUS_BTL_MF_X_V2(p, 0); + f->mt[3].x = SS4_PLUS_BTL_MF_X_V2(p, 1); + no_data_x = SS4_PLUS_MFPACKET_NO_AX_BL; + } else { + f->mt[2].x = SS4_BTL_MF_X_V2(p, 0); + f->mt[3].x = SS4_BTL_MF_X_V2(p, 1); + no_data_x = SS4_MFPACKET_NO_AX_BL; + } + no_data_y = SS4_MFPACKET_NO_AY_BL; + + f->mt[2].y = SS4_BTL_MF_Y_V2(p, 0); + f->mt[3].y = SS4_BTL_MF_Y_V2(p, 1); + } else { + if (IS_SS4PLUS_DEV(priv.dev_id)) { + f->mt[2].x = SS4_PLUS_STD_MF_X_V2(p, 0); + f->mt[3].x = SS4_PLUS_STD_MF_X_V2(p, 1); + no_data_x = SS4_PLUS_MFPACKET_NO_AX; + } else { + f->mt[2].x = SS4_STD_MF_X_V2(p, 0); + f->mt[3].x = SS4_STD_MF_X_V2(p, 1); + no_data_x = SS4_MFPACKET_NO_AX; + } + no_data_y = SS4_MFPACKET_NO_AY; + + f->mt[2].y = SS4_STD_MF_Y_V2(p, 0); + f->mt[3].y = SS4_STD_MF_Y_V2(p, 1); + } + DEBUG_LOG("ALPS: Coordinates for SS4_PACKET_ID_MULTI: [2]:%dx%d [3]:%dx%d\n", f->mt[2].x, f->mt[2].y, f->mt[3].x, f->mt[3].y); + + f->first_mp = 0; + f->is_mp = 1; + + if (SS4_IS_5F_DETECTED(p)) { + f->fingers = 5; + } else if (f->mt[3].x == no_data_x && + f->mt[3].y == no_data_y) { + f->mt[3].x = 0; + f->mt[3].y = 0; + f->fingers = 3; + } else { + f->fingers = 4; + } + break; + + case SS4_PACKET_ID_STICK: + DEBUG_LOG("ALPS: SS4_PACKET_ID_STICK\n"); + /* + * x, y, and pressure are decoded in + * alps_process_packet_ss4_v2() + */ + f->first_mp = 0; + f->is_mp = 0; + break; + + case SS4_PACKET_ID_IDLE: + default: + memset(f, 0, sizeof(struct alps_fields)); + break; + } + + /* handle buttons */ + if (pkt_id == SS4_PACKET_ID_STICK) { + f->ts_left = !!(SS4_BTN_V2(p) & 0x01); + f->ts_right = !!(SS4_BTN_V2(p) & 0x02); + f->ts_middle = !!(SS4_BTN_V2(p) & 0x04); + } else { + f->left = !!(SS4_BTN_V2(p) & 0x01); + if (!(priv.flags & ALPS_BUTTONPAD)) { + f->right = !!(SS4_BTN_V2(p) & 0x02); + f->middle = !!(SS4_BTN_V2(p) & 0x04); + } + } + return true; +} + +void ApplePS2ALPSGlidePoint::alps_process_packet_ss4_v2(UInt8 *packet) { + // Check if input is disabled via ApplePS2Keyboard request + if (ignoreall) + return; + + int buttons = 0; + struct alps_fields f; + int x, y, pressure; + + uint64_t now_abs; + clock_get_uptime(&now_abs); + + memset(&f, 0, sizeof(struct alps_fields)); + (this->*decode_fields)(&f, packet); + if (priv.multi_packet) { + /* + * Sometimes the first packet will indicate a multi-packet + * sequence, but sometimes the next multi-packet would not + * come. Check for this, and when it happens process the + * position packet as usual. + */ + if (f.is_mp) { + /* Now process the 1st packet */ + (this->*decode_fields)(&f, priv.multi_data); + } else { + priv.multi_packet = 0; + } + } + + /* + * "f.is_mp" would always be '0' after merging the 1st and 2nd packet. + * When it is set, it means 2nd packet comes without 1st packet come. + */ + if (f.is_mp) { + return; + } + + /* Save the first packet */ + if (!priv.multi_packet && f.first_mp) { + priv.multi_packet = 1; + memcpy(priv.multi_data, packet, sizeof(priv.multi_data)); + return; + } + + priv.multi_packet = 0; + + /* Report trackstick */ + if (alps_get_pkt_id_ss4_v2(packet) == SS4_PACKET_ID_STICK) { + if (!(priv.flags & ALPS_DUALPOINT)) { + IOLog("ALPS: Rejected trackstick packet from non DualPoint device\n"); + return; + } + + x = (SInt8) (((packet[0] & 1) << 7) | (packet[1] & 0x7f)); + y = (SInt8) (((packet[3] & 1) << 7) | (packet[2] & 0x7f)); + pressure = (packet[4] & 0x7f); + + buttons |= f.ts_left ? 0x01 : 0; + buttons |= f.ts_right ? 0x02 : 0; + buttons |= f.ts_middle ? 0x04 : 0; + + if ((abs(x) >= 0x7f) || (abs(y) >= 0x7f)) { + return; + } + + // Y is inverted + y = -y; + + // Divide by 3 since trackpoint's speed is too fast + x /= 3; + y /= 3; + + DEBUG_LOG("ALPS: Trackstick report: X=%d, Y=%d, Z=%d\n", x, y, pressure); + /* If middle button is pressed, switch to scroll mode. Else, move pointer normally */ + if (0 == (buttons & 0x04)) { + dispatchRelativePointerEventX(x, y, buttons, now_abs); + } else { + dispatchScrollWheelEventX(-y, -x, 0, now_abs); + } + return; + } + + /* Reverse y co-ordinates to have 0 at bottom for gestures to work */ + f.mt[0].y = priv.y_max - f.mt[0].y; + f.mt[1].y = priv.y_max - f.mt[1].y; + + DEBUG_LOG("ALPS: There are currently %d fingers in alps_process_packet_ss4_v2\n", f.fingers); + + if (f.fingers >= 2) { + fingerStates[1].x = f.mt[1].x; + fingerStates[1].y = f.mt[1].y; + fingerStates[1].z = f.pressure; + + if (fingerStates[1].x > X_MAX_POSITIVE) + fingerStates[1].x -= 1 << ABS_POS_BITS; + else if (fingerStates[1].x == X_MAX_POSITIVE) + fingerStates[1].x = XMAX; + + if (fingerStates[1].y > Y_MAX_POSITIVE) + fingerStates[1].y -= 1 << ABS_POS_BITS; + else if (fingerStates[1].y == Y_MAX_POSITIVE) + fingerStates[1].y = YMAX; + + DEBUG_LOG("ALPS: fingerStates[1] report: x: %d, y: %d, z: %d\n", fingerStates[1].x, fingerStates[1].y, fingerStates[1].z); + } + // normal "packet" + fingerStates[0].x = f.mt[0].x; + fingerStates[0].y = f.mt[0].y; + fingerStates[0].z = f.pressure; + + DEBUG_LOG("ALPS: fingerStates[0] report: x: %d, y: %d, z: %d\n", fingerStates[0].x, fingerStates[0].y, fingerStates[0].z); + + if (fingerStates[0].x > X_MAX_POSITIVE) + fingerStates[0].x -= 1 << ABS_POS_BITS; + else if (fingerStates[0].x == X_MAX_POSITIVE) + fingerStates[0].x = XMAX; + + if (fingerStates[0].y > Y_MAX_POSITIVE) + fingerStates[0].y -= 1 << ABS_POS_BITS; + else if (fingerStates[0].y == Y_MAX_POSITIVE) + fingerStates[0].y = YMAX; + + clampedFingerCount = f.fingers; + + if (clampedFingerCount > MAX_TOUCHES) + clampedFingerCount = MAX_TOUCHES; + + if (renumberFingers()) + sendTouchData(); + + alps_buttons(f); +} + +bool ApplePS2ALPSGlidePoint::alps_command_mode_send_nibble(int nibble) { + SInt32 command; + // The largest amount of requests we will have is 2 right now + // 1 for the initial command, and 1 for sending data OR 1 for receiving data + // If the nibble commands at the top change then this will need to change as + // well. For now we will just validate that the request will not overload + // this object. + TPS2Request<2> request; + int cmdCount = 0, send = 0, receive = 0, i; + + if (nibble > 0xf) { + IOLog("%s::alps_command_mode_send_nibble ERROR: nibble value is greater than 0xf, command may fail\n", getName()); + } + + request.commands[cmdCount].command = kPS2C_SendCommandAndCompareAck; + command = priv.nibble_commands[nibble].command; + request.commands[cmdCount++].inOrOut = command & 0xff; + + send = (command >> 12 & 0xf); + receive = (command >> 8 & 0xf); + + if ((send > 1) || ((send + receive + 1) > 2)) { + return false; + } + + if (send > 0) { + request.commands[cmdCount].command = kPS2C_SendCommandAndCompareAck; + request.commands[cmdCount++].inOrOut = priv.nibble_commands[nibble].data; + } + + for (i = 0; i < receive; i++) { + request.commands[cmdCount].command = kPS2C_ReadDataPort; + request.commands[cmdCount++].inOrOut = 0; + } + + request.commandsCount = cmdCount; + assert(request.commandsCount <= countof(request.commands)); + + _device->submitRequestAndBlock(&request); + + return request.commandsCount == cmdCount; +} + +bool ApplePS2ALPSGlidePoint::alps_command_mode_set_addr(int addr) { + + TPS2Request<1> request; + int i, nibble; + + // DEBUG_LOG("ALPS: command mode set addr with addr command: 0x%02x\n", priv.addr_command); + request.commands[0].command = kPS2C_SendCommandAndCompareAck; + request.commands[0].inOrOut = priv.addr_command; + request.commandsCount = 1; + _device->submitRequestAndBlock(&request); + + if (request.commandsCount != 1) { + return false; + } + + for (i = 12; i >= 0; i -= 4) { + nibble = (addr >> i) & 0xf; + if (!alps_command_mode_send_nibble(nibble)) { + return false; + } + } + + return true; +} + +int ApplePS2ALPSGlidePoint::alps_command_mode_read_reg(int addr) { + TPS2Request<4> request; + ALPSStatus_t status; + + if (!alps_command_mode_set_addr(addr)) { + DEBUG_LOG("ALPS: Failed to set addr to read register\n"); + return -1; + } + + request.commands[0].command = kPS2C_SendCommandAndCompareAck; + request.commands[0].inOrOut = kDP_GetMouseInformation; //sync.. + request.commands[1].command = kPS2C_ReadDataPort; + request.commands[1].inOrOut = 0; + request.commands[2].command = kPS2C_ReadDataPort; + request.commands[2].inOrOut = 0; + request.commands[3].command = kPS2C_ReadDataPort; + request.commands[3].inOrOut = 0; + request.commandsCount = 4; + assert(request.commandsCount <= countof(request.commands)); + _device->submitRequestAndBlock(&request); + + if (request.commandsCount != 4) { + return -1; + } + + status.bytes[0] = request.commands[1].inOrOut; + status.bytes[1] = request.commands[2].inOrOut; + status.bytes[2] = request.commands[3].inOrOut; + + // IOLog("ALPS: read reg result: { 0x%02x, 0x%02x, 0x%02x }\n", status.bytes[0], status.bytes[1], status.bytes[2]); + + /* The address being read is returned in the first 2 bytes + * of the result. Check that the address matches the expected + * address. + */ + if (addr != ((status.bytes[0] << 8) | status.bytes[1])) { + DEBUG_LOG("ALPS: ERROR: read wrong registry value, expected: %x\n", addr); + return -1; + } + + return status.bytes[2]; +} + +bool ApplePS2ALPSGlidePoint::alps_command_mode_write_reg(int addr, UInt8 value) { + + if (!alps_command_mode_set_addr(addr)) { + return false; + } + + return alps_command_mode_write_reg(value); +} + +bool ApplePS2ALPSGlidePoint::alps_command_mode_write_reg(UInt8 value) { + if (!alps_command_mode_send_nibble((value >> 4) & 0xf)) { + return false; + } + if (!alps_command_mode_send_nibble(value & 0xf)) { + return false; + } + + return true; +} + +bool ApplePS2ALPSGlidePoint::alps_rpt_cmd(SInt32 init_command, SInt32 init_arg, SInt32 repeated_command, ALPSStatus_t *report) { + TPS2Request<9> request; + int byte0, cmd; + cmd = 0; + + if (init_command) { + request.commands[cmd].command = kPS2C_SendCommandAndCompareAck; + request.commands[cmd++].inOrOut = kDP_SetMouseResolution; + request.commands[cmd].command = kPS2C_SendCommandAndCompareAck; + request.commands[cmd++].inOrOut = init_arg; + } + + + // 3X run command + request.commands[cmd].command = kPS2C_SendCommandAndCompareAck; + request.commands[cmd++].inOrOut = repeated_command; + request.commands[cmd].command = kPS2C_SendCommandAndCompareAck; + request.commands[cmd++].inOrOut = repeated_command; + request.commands[cmd].command = kPS2C_SendCommandAndCompareAck; + request.commands[cmd++].inOrOut = repeated_command; + + // Get info/result + request.commands[cmd].command = kPS2C_SendCommandAndCompareAck; + request.commands[cmd++].inOrOut = kDP_GetMouseInformation; + byte0 = cmd; + request.commands[cmd].command = kPS2C_ReadDataPort; + request.commands[cmd++].inOrOut = 0; + request.commands[cmd].command = kPS2C_ReadDataPort; + request.commands[cmd++].inOrOut = 0; + request.commands[cmd].command = kPS2C_ReadDataPort; + request.commands[cmd++].inOrOut = 0; + request.commandsCount = cmd; + assert(request.commandsCount <= countof(request.commands)); + _device->submitRequestAndBlock(&request); + + report->bytes[0] = request.commands[byte0].inOrOut; + report->bytes[1] = request.commands[byte0+1].inOrOut; + report->bytes[2] = request.commands[byte0+2].inOrOut; + + DEBUG_LOG("ALPS: %02x report: [0x%02x 0x%02x 0x%02x]\n", + repeated_command, + report->bytes[0], + report->bytes[1], + report->bytes[2]); + + return request.commandsCount == cmd; +} + +bool ApplePS2ALPSGlidePoint::alps_enter_command_mode() { + DEBUG_LOG("ALPS: enter command mode\n"); + TPS2Request<4> request; + ALPSStatus_t status; + + if (!alps_rpt_cmd(NULL, NULL, kDP_MouseResetWrap, &status)) { + IOLog("ALPS: Failed to enter command mode!\n"); + return false; + } + return true; +} + +bool ApplePS2ALPSGlidePoint::alps_exit_command_mode() { + DEBUG_LOG("ALPS: exit command mode\n"); + TPS2Request<1> request; + + request.commands[0].command = kPS2C_SendCommandAndCompareAck; + request.commands[0].inOrOut = kDP_SetMouseStreamMode; + request.commandsCount = 1; + assert(request.commandsCount <= countof(request.commands)); + _device->submitRequestAndBlock(&request); + + return true; +} + +/* + * For DualPoint devices select the device that should respond to + * subsequent commands. It looks like glidepad is behind stickpointer, + * I'd thought it would be other way around... + */ +bool ApplePS2ALPSGlidePoint::alps_passthrough_mode_v2(bool enable) { + int cmd = enable ? kDP_SetMouseScaling2To1 : kDP_SetMouseScaling1To1; + TPS2Request<4> request; + + request.commands[0].command = kPS2C_SendCommandAndCompareAck; + request.commands[0].inOrOut = cmd; + request.commands[1].command = kPS2C_SendCommandAndCompareAck; + request.commands[1].inOrOut = cmd; + request.commands[2].command = kPS2C_SendCommandAndCompareAck; + request.commands[2].inOrOut = cmd; + request.commands[3].command = kPS2C_SendCommandAndCompareAck; + request.commands[3].inOrOut = kDP_SetDefaultsAndDisable; + request.commandsCount = 4; + assert(request.commandsCount <= countof(request.commands)); + _device->submitRequestAndBlock(&request); + + return request.commandsCount == 4; +} + +bool ApplePS2ALPSGlidePoint::alps_absolute_mode_v1_v2() { + + /* Try ALPS magic knock - 4 disable before enable */ + ps2_command_short(kDP_SetDefaultsAndDisable); + ps2_command_short(kDP_SetDefaultsAndDisable); + ps2_command_short(kDP_SetDefaultsAndDisable); + ps2_command_short(kDP_SetDefaultsAndDisable); + ps2_command_short(kDP_Enable); + + /* + * Switch mouse to poll (remote) mode so motion data will not + * get in our way + */ + ps2_command_short(kDP_MouseSetPoll); + + return true; +} + +int ApplePS2ALPSGlidePoint::alps_monitor_mode_send_word(int word) { + int i, nibble; + + /* + * b0-b11 are valid bits, send sequence is inverse. + * e.g. when word = 0x0123, nibble send sequence is 3, 2, 1 + */ + for (i = 0; i <= 8; i += 4) { + nibble = (word >> i) & 0xf; + alps_command_mode_send_nibble(nibble); + } + + return 0; +} + +int ApplePS2ALPSGlidePoint::alps_monitor_mode_write_reg(int addr, int value) { + ps2_command_short(kDP_Enable); + alps_monitor_mode_send_word(0x0A0); // 0x0A0 is the command to write the word + alps_monitor_mode_send_word(addr); + alps_monitor_mode_send_word(value); + ps2_command_short(kDP_SetDefaultsAndDisable); + + return 0; +} + +int ApplePS2ALPSGlidePoint::alps_monitor_mode(bool enable) { + TPS2Request<4> request; + int cmd = 0; + + if (enable) { + /* EC E9 F5 F5 E7 E6 E7 E9 to enter monitor mode */ + ps2_command_short(kDP_MouseResetWrap); + request.commands[cmd].command = kPS2C_SendCommandAndCompareAck; + request.commands[cmd++].inOrOut = kDP_GetMouseInformation; + request.commands[cmd].command = kPS2C_ReadDataPort; + request.commands[cmd++].inOrOut = 0; + request.commands[cmd].command = kPS2C_ReadDataPort; + request.commands[cmd++].inOrOut = 0; + request.commands[cmd].command = kPS2C_ReadDataPort; + request.commands[cmd++].inOrOut = 0; + request.commandsCount = cmd; + assert(request.commandsCount <= countof(request.commands)); + _device->submitRequestAndBlock(&request); + + ps2_command_short(kDP_SetDefaultsAndDisable); + ps2_command_short(kDP_SetDefaultsAndDisable); + ps2_command_short(kDP_SetMouseScaling2To1); + ps2_command_short(kDP_SetMouseScaling1To1); + ps2_command_short(kDP_SetMouseScaling2To1); + + /* Get Info */ + request.commands[cmd].command = kPS2C_SendCommandAndCompareAck; + request.commands[cmd++].inOrOut = kDP_GetMouseInformation; + request.commands[cmd].command = kPS2C_ReadDataPort; + request.commands[cmd++].inOrOut = 0; + request.commands[cmd].command = kPS2C_ReadDataPort; + request.commands[cmd++].inOrOut = 0; + request.commands[cmd].command = kPS2C_ReadDataPort; + request.commands[cmd++].inOrOut = 0; + request.commandsCount = cmd; + assert(request.commandsCount <= countof(request.commands)); + _device->submitRequestAndBlock(&request); + } else { + /* EC to exit monitor mode */ + ps2_command_short(kDP_MouseResetWrap); + } + + return 0; +} + +void ApplePS2ALPSGlidePoint::alps_absolute_mode_v6() { + // enter monitor mode, to write the register / + alps_monitor_mode(true); + alps_monitor_mode_write_reg(0x000, 0x181); + alps_monitor_mode(false); +} + +bool ApplePS2ALPSGlidePoint::alps_get_status(ALPSStatus_t *status) { + /* Get status: 0xF5 0xF5 0xF5 0xE9 */ + return alps_rpt_cmd(NULL, NULL, kDP_SetDefaultsAndDisable, status); +} + +/* + * Turn touchpad tapping on or off. The sequences are: + * 0xE9 0xF5 0xF5 0xF3 0x0A to enable, + * 0xE9 0xF5 0xF5 0xE8 0x00 to disable. + * My guess that 0xE9 (GetInfo) is here as a sync point. + * For models that also have stickpointer (DualPoints) its tapping + * is controlled separately (0xE6 0xE6 0xE6 0xF3 0x14|0x0A) but + * we don't fiddle with it. + */ +bool ApplePS2ALPSGlidePoint::alps_tap_mode(bool enable) { + int cmd = enable ? kDP_SetMouseSampleRate : kDP_SetMouseResolution; + UInt8 tapArg = enable ? 0x0A : 0x00; + TPS2Request<8> request; + ALPSStatus_t result; + + request.commands[0].command = kPS2C_SendCommandAndCompareAck; + request.commands[0].inOrOut = kDP_GetMouseInformation; + request.commands[1].command = kPS2C_ReadDataPort; + request.commands[1].inOrOut = 0; + request.commands[2].command = kPS2C_ReadDataPort; + request.commands[2].inOrOut = 0; + request.commands[3].command = kPS2C_ReadDataPort; + request.commands[3].inOrOut = 0; + request.commands[4].command = kPS2C_SendCommandAndCompareAck; + request.commands[4].inOrOut = kDP_SetDefaultsAndDisable; + request.commands[5].command = kPS2C_SendCommandAndCompareAck; + request.commands[5].inOrOut = kDP_SetDefaultsAndDisable; + request.commands[6].command = kPS2C_SendCommandAndCompareAck; + request.commands[6].inOrOut = cmd; + request.commands[7].command = kPS2C_SendCommandAndCompareAck; + request.commands[7].inOrOut = tapArg; + request.commandsCount = 8; + _device->submitRequestAndBlock(&request); + + if (request.commandsCount != 8) { + DEBUG_LOG("ALPS: Enabling tap mode failed before getStatus call, command count=%d\n", + request.commandsCount); + return false; + } + + return alps_get_status(&result); +} + + +bool ApplePS2ALPSGlidePoint::alps_hw_init_v1_v2() { + TPS2Request<1> request; + + if (priv.flags & ALPS_PASS) { + if (!alps_passthrough_mode_v2(true)) { + return false; + } + } + + if (!alps_tap_mode(true)) { + IOLog("ALPS: Failed to enable hardware tapping\n"); + return false; + } + + if (!alps_absolute_mode_v1_v2()) { + IOLog("ALPS: Failed to enable absolute mode\n"); + return false; + } + + if (priv.flags & ALPS_PASS) { + if (!alps_passthrough_mode_v2(false)) { + return false; + } + } + + /* ALPS needs stream mode, otherwise it won't report any data */ + ps2_command_short(kDP_SetMouseStreamMode); + + return true; +} + +bool ApplePS2ALPSGlidePoint::alps_hw_init_v6() { + /* Enter passthrough mode to let trackpoint enter 6byte raw mode */ + alps_passthrough_mode_v2(true); + + /* alps_trackstick_enter_extended_mode_v3_v6 */ + ps2_command_short(kDP_SetMouseScaling1To1); + ps2_command_short(kDP_SetMouseScaling1To1); + ps2_command_short(kDP_SetMouseScaling1To1); + ps2_command(0xC8, kDP_SetMouseSampleRate); + ps2_command(0x14, kDP_SetMouseSampleRate); + + alps_passthrough_mode_v2(false); + + alps_absolute_mode_v6(); + + return true; +} + +/* + * Enable or disable passthrough mode to the trackstick. + */ +bool ApplePS2ALPSGlidePoint::alps_passthrough_mode_v3(int regBase, bool enable) { + int regVal; + bool ret = false; + + DEBUG_LOG("ALPS: passthrough mode enable=%d\n", enable); + + if (!alps_enter_command_mode()) { + IOLog("ALPS: Failed to enter command mode while enabling passthrough mode\n"); + return false; + } + + regVal = alps_command_mode_read_reg(regBase + 0x0008); + if (regVal == -1) { + IOLog("ALPS: Failed to read register while setting up passthrough mode\n"); + goto error; + } + + if (enable) { + regVal |= 0x01; + } else { + regVal &= ~0x01; + } + + ret = alps_command_mode_write_reg(regVal); + +error: + if (!alps_exit_command_mode()) { + IOLog("ALPS: failed to exit command mode while enabling passthrough mode v3\n"); + return false; + } + + return ret; +} + +/* Must be in command mode when calling this function */ +bool ApplePS2ALPSGlidePoint::alps_absolute_mode_v3() { + + int regVal; + + regVal = alps_command_mode_read_reg(0x0004); + if (regVal == -1) { + return false; + } + + regVal |= 0x06; + if (!alps_command_mode_write_reg(regVal)) { + return false; + } + + return true; +} + +IOReturn ApplePS2ALPSGlidePoint::alps_probe_trackstick_v3_v7(int regBase) { + int ret = kIOReturnIOError, regVal; + + if (!alps_enter_command_mode()) { + goto error; + } + + regVal = alps_command_mode_read_reg(regBase + 0x08); + + if (regVal == -1) { + goto error; + } + + /* bit 7: trackstick is present */ + ret = regVal & 0x80 ? 0 : kIOReturnNoDevice; + +error: + alps_exit_command_mode(); + return ret; +} + +IOReturn ApplePS2ALPSGlidePoint::alps_setup_trackstick_v3(int regBase) { + IOReturn ret = 0; + ALPSStatus_t report; + TPS2Request<3> request; + + /* + * We need to configure trackstick to report data for touchpad in + * extended format. And also we need to tell touchpad to expect data + * from trackstick in extended format. Without this configuration + * trackstick packets sent from touchpad are in basic format which is + * different from what we expect. + */ + if (!alps_passthrough_mode_v3(regBase, true)) { + return kIOReturnIOError; + } + + /* + * E7 report for the trackstick + * + * There have been reports of failures to seem to trace back + * to the above trackstick check failing. When these occur + * this E7 report fails, so when that happens we continue + * with the assumption that there isn't a trackstick after + * all. + */ + if (!alps_rpt_cmd(NULL, NULL, kDP_SetMouseScaling2To1, &report)) { + IOLog("ALPS: Failed to initialize trackstick (E7 report failed)\n"); + ret = kIOReturnNoDevice; + } else { + /* + * Not sure what this does, but it is absolutely + * essential. Without it, the touchpad does not + * work at all and the trackstick just emits normal + * PS/2 packets. + */ + request.commands[0].command = kPS2C_SendCommandAndCompareAck; + request.commands[0].inOrOut = kDP_SetMouseScaling1To1; + request.commands[1].command = kPS2C_SendCommandAndCompareAck; + request.commands[1].inOrOut = kDP_SetMouseScaling1To1; + request.commands[2].command = kPS2C_SendCommandAndCompareAck; + request.commands[2].inOrOut = kDP_SetMouseScaling1To1; + request.commandsCount = 3; + assert(request.commandsCount <= countof(request.commands)); + _device->submitRequestAndBlock(&request); + if (request.commandsCount != 3) { + IOLog("ALPS: error sending magic E6 scaling sequence\n"); + ret = kIOReturnIOError; + goto error; + } + if (!(alps_command_mode_send_nibble(0x9) && alps_command_mode_send_nibble(0x4))) { + IOLog("ALPS: Error sending magic E6 nibble sequence\n"); + ret = kIOReturnIOError; + goto error; + } + DEBUG_LOG("ALPS: Sent magic E6 sequence\n"); + + /* + * This ensures the trackstick packets are in the format + * supported by this driver. If bit 1 isn't set the packet + * format is different. + */ + if (!(alps_enter_command_mode() && + alps_command_mode_write_reg(regBase + 0x0008, 0x82) && + alps_exit_command_mode())) { + ret = -kIOReturnIOError; + //goto error; + } + } +error: + if (!alps_passthrough_mode_v3(regBase, false)) { + ret = kIOReturnIOError; + } + + return ret; +} + +bool ApplePS2ALPSGlidePoint::alps_hw_init_v3() { + int regVal; + + if ((priv.flags & ALPS_DUALPOINT) && + alps_setup_trackstick_v3(ALPS_REG_BASE_PINNACLE) == kIOReturnIOError) + goto error; + + if (!(alps_enter_command_mode() && + alps_absolute_mode_v3())) { + IOLog("ALPS: Failed to enter absolute mode\n"); + goto error; + } + + regVal = alps_command_mode_read_reg(0x0006); + if (regVal == -1) + goto error; + if (!alps_command_mode_write_reg(regVal | 0x01)) + goto error; + + regVal = alps_command_mode_read_reg(0x0007); + if (regVal == -1) + goto error; + if (!alps_command_mode_write_reg(regVal | 0x01)) + goto error; + + if (alps_command_mode_read_reg(0x0144) == -1) + goto error; + if (!alps_command_mode_write_reg(0x04)) + goto error; + + if (alps_command_mode_read_reg(0x0159) == -1) + goto error; + if (!alps_command_mode_write_reg(0x03)) + goto error; + + if (alps_command_mode_read_reg(0x0163) == -1) + goto error; + if (!alps_command_mode_write_reg(0x0163, 0x03)) + goto error; + + if (alps_command_mode_read_reg(0x0162) == -1) + goto error; + if (!alps_command_mode_write_reg(0x0162, 0x04)) + goto error; + + alps_exit_command_mode(); + + /* Set rate and enable data reporting */ + /* param is set here to 0x28, in Linux code it is 0x64 + ref: https://github.com/torvalds/linux/blob/3593030761630e09200072a4bd06468892c27be3/drivers/input/mouse/alps.c#L2269 + */ + ps2_command(0x28, kDP_SetMouseSampleRate); + ps2_command_short(kDP_Enable); + + return true; + +error: + /* + * Leaving the touchpad in command mode will essentially render + * it unusable until the machine reboots, so exit it here just + * to be safe + */ + alps_exit_command_mode(); + return false; +} + +bool ApplePS2ALPSGlidePoint::alps_get_v3_v7_resolution(int reg_pitch) { + int reg, x_pitch, y_pitch, x_electrode, y_electrode, x_phys, y_phys; + + reg = alps_command_mode_read_reg(reg_pitch); + if (reg < 0) + return reg; + + x_pitch = (char)(reg << 4) >> 4; /* sign extend lower 4 bits */ + x_pitch = 50 + 2 * x_pitch; /* In 0.1 mm units */ + + y_pitch = (char)reg >> 4; /* sign extend upper 4 bits */ + y_pitch = 36 + 2 * y_pitch; /* In 0.1 mm units */ + + reg = alps_command_mode_read_reg(reg_pitch + 1); + if (reg < 0) + return reg; + + x_electrode = (char)(reg << 4) >> 4; /* sign extend lower 4 bits */ + x_electrode = 17 + x_electrode; + + y_electrode = (char)reg >> 4; /* sign extend upper 4 bits */ + y_electrode = 13 + y_electrode; + + x_phys = x_pitch * (x_electrode - 1); /* In 0.1 mm units */ + y_phys = y_pitch * (y_electrode - 1); /* In 0.1 mm units */ + + priv.x_res = priv.x_max * 10 / x_phys; /* units / mm */ + priv.y_res = priv.y_max * 10 / y_phys; /* units / mm */ + + /*IOLog("pitch %dx%d num-electrodes %dx%d physical size %dx%d mm res %dx%d\n", + x_pitch, y_pitch, x_electrode, y_electrode, + x_phys / 10, y_phys / 10, priv.x_res, priv.y_res);*/ + + return true; +} + +bool ApplePS2ALPSGlidePoint::alps_hw_init_rushmore_v3() { + int regVal; + + if (priv.flags & ALPS_DUALPOINT) { + regVal = alps_setup_trackstick_v3(ALPS_REG_BASE_RUSHMORE); + if (regVal == kIOReturnIOError) { + goto error; + } + } + + if (!alps_enter_command_mode() || + alps_command_mode_read_reg(0xc2d9) == -1 || + !alps_command_mode_write_reg(0xc2cb, 0x00)) { + goto error; + } + + if (!alps_get_v3_v7_resolution(0xc2da)) + goto error; + + regVal = alps_command_mode_read_reg(0xc2c6); + if (regVal == -1) + goto error; + if (!alps_command_mode_write_reg(regVal & 0xfd)) + goto error; + + if (!alps_command_mode_write_reg(0xc2c9, 0x64)) + goto error; + + /* enter absolute mode */ + regVal = alps_command_mode_read_reg(0xc2c4); + if (regVal == -1) + goto error; + if (!alps_command_mode_write_reg(regVal | 0x02)) + goto error; + + alps_exit_command_mode(); + + /* Enable data reporting */ + ps2_command_short(kDP_Enable); + + return true; + +error: + alps_exit_command_mode(); + return false; +} + +/* Must be in command mode when calling this function */ +bool ApplePS2ALPSGlidePoint::alps_absolute_mode_v4() { + int regVal; + + regVal = alps_command_mode_read_reg(0x0004); + if (regVal == -1) { + return false; + } + + regVal |= 0x02; + if (!alps_command_mode_write_reg(regVal)) { + return false; + } + + return true; +} + +bool ApplePS2ALPSGlidePoint::alps_hw_init_v4() { + + if (!alps_enter_command_mode()) + goto error; + + if (!alps_absolute_mode_v4()) { + IOLog("ALPS: Failed to enter absolute mode\n"); + goto error; + } + + if (!alps_command_mode_write_reg(0x0007, 0x8c)) + goto error; + + if (!alps_command_mode_write_reg(0x0149, 0x03)) + goto error; + + if (!alps_command_mode_write_reg(0x0160, 0x03)) + goto error; + + if (!alps_command_mode_write_reg(0x017f, 0x15)) + goto error; + + if (!alps_command_mode_write_reg(0x0151, 0x01)) + goto error; + + if (!alps_command_mode_write_reg(0x0168, 0x03)) + goto error; + + if (!alps_command_mode_write_reg(0x014a, 0x03)) + goto error; + + if (!alps_command_mode_write_reg(0x0161, 0x03)) + goto error; + + alps_exit_command_mode(); + + /* + * This sequence changes the output from a 9-byte to an + * 8-byte format. All the same data seems to be present, + * just in a more compact format. + */ + ps2_command(0xc8, kDP_SetMouseSampleRate); + ps2_command(0x64, kDP_SetMouseSampleRate); + ps2_command(0x50, kDP_SetMouseSampleRate); + ps2_command_short(kDP_GetId); + + /* Set rate and enable data reporting */ + ps2_command(0x64, kDP_SetMouseSampleRate); + ps2_command_short(kDP_Enable); + return true; + +error: + /* + * Leaving the touchpad in command mode will essentially render + * it unusable until the machine reboots, so exit it here just + * to be safe + */ + alps_exit_command_mode(); + return false; +} + +void ApplePS2ALPSGlidePoint::alps_get_otp_values_ss4_v2(unsigned char index, unsigned char otp[]) { + TPS2Request<4> request; + + switch (index) { + case 0: + ps2_command_short(kDP_SetMouseStreamMode); + ps2_command_short(kDP_SetMouseStreamMode); + + request.commands[0].command = kPS2C_SendCommandAndCompareAck; + request.commands[0].inOrOut = kDP_GetMouseInformation; + request.commands[1].command = kPS2C_ReadDataPort; + request.commands[1].inOrOut = 0; + request.commands[2].command = kPS2C_ReadDataPort; + request.commands[2].inOrOut = 0; + request.commands[3].command = kPS2C_ReadDataPort; + request.commands[3].inOrOut = 0; + request.commandsCount = 4; + assert(request.commandsCount <= countof(request.commands)); + _device->submitRequestAndBlock(&request); + + otp[0] = request.commands[1].inOrOut; + otp[1] = request.commands[2].inOrOut; + otp[2] = request.commands[3].inOrOut; + + break; + + case 1: + ps2_command_short(kDP_MouseSetPoll); + ps2_command_short(kDP_MouseSetPoll); + + request.commands[0].command = kPS2C_SendCommandAndCompareAck; + request.commands[0].inOrOut = kDP_GetMouseInformation; + request.commands[1].command = kPS2C_ReadDataPort; + request.commands[1].inOrOut = 0; + request.commands[2].command = kPS2C_ReadDataPort; + request.commands[2].inOrOut = 0; + request.commands[3].command = kPS2C_ReadDataPort; + request.commands[3].inOrOut = 0; + request.commandsCount = 4; + assert(request.commandsCount <= countof(request.commands)); + _device->submitRequestAndBlock(&request); + + otp[0] = request.commands[1].inOrOut; + otp[1] = request.commands[2].inOrOut; + otp[2] = request.commands[3].inOrOut; + + break; + } +} + +void ApplePS2ALPSGlidePoint::alps_update_device_area_ss4_v2(unsigned char otp[][4], struct alps_data *priv) { + int num_x_electrode; + int num_y_electrode; + int x_pitch, y_pitch, x_phys, y_phys; + + DEBUG_LOG("ALPS: Accessing 'Update Device Area'\n"); + + if (IS_SS4PLUS_DEV(priv->dev_id)) { + DEBUG_LOG("ALPS: Device is SS4_PLUS\n"); + num_x_electrode = SS4PLUS_NUMSENSOR_XOFFSET + (otp[0][2] & 0x0F); + num_y_electrode = SS4PLUS_NUMSENSOR_YOFFSET + ((otp[0][2] >> 4) & 0x0F); + + priv->x_max = (num_x_electrode - 1) * SS4PLUS_COUNT_PER_ELECTRODE; + priv->y_max = (num_y_electrode - 1) * SS4PLUS_COUNT_PER_ELECTRODE; + + x_pitch = (otp[0][1] & 0x0F) + SS4PLUS_MIN_PITCH_MM; + y_pitch = ((otp[0][1] >> 4) & 0x0F) + SS4PLUS_MIN_PITCH_MM; + + } else { + DEBUG_LOG("ALPS: Device is SS4\n"); + num_x_electrode = SS4_NUMSENSOR_XOFFSET + (otp[1][0] & 0x0F); + num_y_electrode = SS4_NUMSENSOR_YOFFSET + ((otp[1][0] >> 4) & 0x0F); + + priv->x_max = (num_x_electrode - 1) * SS4_COUNT_PER_ELECTRODE; + priv->y_max = (num_y_electrode - 1) * SS4_COUNT_PER_ELECTRODE; + + x_pitch = ((otp[1][2] >> 2) & 0x07) + SS4_MIN_PITCH_MM; + y_pitch = ((otp[1][2] >> 5) & 0x07) + SS4_MIN_PITCH_MM; + } + + x_phys = x_pitch * (num_x_electrode - 1); /* In 0.1 mm units */ + y_phys = y_pitch * (num_y_electrode - 1); /* In 0.1 mm units */ + + DEBUG_LOG("ALPS: Your dimensions are: %dx%d\n", x_phys, y_phys); + + priv->x_res = priv->x_max * 10 / x_phys; /* units / mm */ + priv->y_res = priv->y_max * 10 / y_phys; /* units / mm */ +} + +void ApplePS2ALPSGlidePoint::alps_update_btn_info_ss4_v2(unsigned char otp[][4], struct alps_data *priv) { + unsigned char is_btnless; + + if (IS_SS4PLUS_DEV(priv->dev_id)) + is_btnless = (otp[1][0] >> 1) & 0x01; + else + is_btnless = (otp[1][1] >> 3) & 0x01; + + if (is_btnless) + priv->flags |= ALPS_BUTTONPAD; + + is_btnless ? setProperty("Clickpad", kOSBooleanTrue) : setProperty("Clickpad", kOSBooleanFalse); +} + +void ApplePS2ALPSGlidePoint::alps_update_dual_info_ss4_v2(unsigned char otp[][4], struct alps_data *priv) { + bool is_dual = false; + int reg_val = 0; + + if (IS_SS4PLUS_DEV(priv->dev_id)) { + is_dual = (otp[0][0] >> 4) & 0x01; + + if (!is_dual) { + /* For support TrackStick of Thinkpad L/E series */ + if (alps_exit_command_mode()) + if (alps_enter_command_mode()) + reg_val = alps_command_mode_read_reg(0xD7); + alps_exit_command_mode(); + ps2_command_short(kDP_Enable); + + if (reg_val == 0x0C || reg_val == 0x1D) + is_dual = true; + } + } + + if (is_dual) + priv->flags |= ALPS_DUALPOINT | + ALPS_DUALPOINT_WITH_PRESSURE; + + is_dual ? setProperty("Trackpoint", kOSBooleanTrue) : setProperty("Trackpoint", kOSBooleanFalse); +} + +void ApplePS2ALPSGlidePoint::alps_set_defaults_ss4_v2(struct alps_data *priv) { + unsigned char otp[2][4]; + + memset(otp, 0, sizeof(otp)); + + alps_get_otp_values_ss4_v2(1, &otp[1][0]); + alps_get_otp_values_ss4_v2(0, &otp[0][0]); + + alps_update_device_area_ss4_v2(otp, priv); + + alps_update_btn_info_ss4_v2(otp, priv); + + alps_update_dual_info_ss4_v2(otp, priv); +} + +int ApplePS2ALPSGlidePoint::alps_dolphin_get_device_area(struct alps_data *priv) { + int num_x_electrode, num_y_electrode; + TPS2Request<4> request; + int cmd = 0; + ALPSStatus_t status; + + alps_enter_command_mode(); + + ps2_command_short(kDP_MouseResetWrap); + ps2_command_short(kDP_MouseSetPoll); + ps2_command_short(kDP_MouseSetPoll); + ps2_command(0x0a, kDP_SetMouseSampleRate); + ps2_command(0x0a, kDP_SetMouseSampleRate); + + request.commands[cmd].command = kPS2C_SendCommandAndCompareAck; + request.commands[cmd++].inOrOut = kDP_GetMouseInformation; + request.commands[cmd].command = kPS2C_ReadDataPort; + request.commands[cmd++].inOrOut = 0; + request.commands[cmd].command = kPS2C_ReadDataPort; + request.commands[cmd++].inOrOut = 0; + request.commands[cmd].command = kPS2C_ReadDataPort; + request.commands[cmd++].inOrOut = 0; + request.commandsCount = cmd; + assert(request.commandsCount <= countof(request.commands)); + _device->submitRequestAndBlock(&request); + + /* results */ + status.bytes[0] = request.commands[1].inOrOut; + status.bytes[1] = request.commands[2].inOrOut; + status.bytes[2] = request.commands[3].inOrOut; + + /* + * Dolphin's sensor line number is not fixed. It can be calculated + * by adding the device's register value with DOLPHIN_PROFILE_X/YOFFSET. + * Further more, we can get device's x_max and y_max by multiplying + * sensor line number with DOLPHIN_COUNT_PER_ELECTRODE. + * + * e.g. When we get register's sensor_x = 11 & sensor_y = 8, + * real sensor line number X = 11 + 8 = 19, and + * real sensor line number Y = 8 + 1 = 9. + * So, x_max = (19 - 1) * 64 = 1152, and + * y_max = (9 - 1) * 64 = 512. + */ + num_x_electrode = DOLPHIN_PROFILE_XOFFSET + (status.bytes[2] & 0x0F); + num_y_electrode = DOLPHIN_PROFILE_YOFFSET + ((status.bytes[2] >> 4) & 0x0F); + priv->x_bits = num_x_electrode; + priv->y_bits = num_y_electrode; + priv->x_max = (num_x_electrode - 1) * DOLPHIN_COUNT_PER_ELECTRODE; + priv->y_max = (num_y_electrode - 1) * DOLPHIN_COUNT_PER_ELECTRODE; + + alps_exit_command_mode(); + + return 0; +} + +bool ApplePS2ALPSGlidePoint::alps_hw_init_dolphin_v1() { + + ps2_command_short(kDP_SetMouseStreamMode); + ps2_command(0x64, kDP_SetMouseSampleRate); + ps2_command(0x28, kDP_SetMouseSampleRate); + ps2_command_short(kDP_Enable); + + return true; +} + +bool ApplePS2ALPSGlidePoint::alps_hw_init_v7(){ + int reg_val; + + if (!alps_enter_command_mode()) + goto error; + + if (alps_command_mode_read_reg(0xc2d9) == -1) + goto error; + + if (!alps_get_v3_v7_resolution(0xc397)) + goto error; + + if (!alps_command_mode_write_reg(0xc2c9, 0x64)) + goto error; + + reg_val = alps_command_mode_read_reg(0xc2c4); + if (reg_val == -1) + goto error; + + if (!alps_command_mode_write_reg(reg_val | 0x02)) + goto error; + + alps_exit_command_mode(); + + ps2_command(0x28, kDP_SetMouseSampleRate); + ps2_command_short(kDP_Enable); + + return true; + +error: + alps_exit_command_mode(); + return false; +} + +bool ApplePS2ALPSGlidePoint::alps_hw_init_ss4_v2() { + /* enter absolute mode */ + ps2_command_short(kDP_SetMouseStreamMode); + ps2_command_short(kDP_SetMouseStreamMode); + ps2_command(0x64, kDP_SetMouseSampleRate); + ps2_command(0x28, kDP_SetMouseSampleRate); + + /* T.B.D. Decread noise packet number, delete in the future */ + alps_exit_command_mode(); + alps_enter_command_mode(); + alps_command_mode_write_reg(0x001D, 0x20); + alps_exit_command_mode(); + + /* final init */ + ps2_command_short(kDP_Enable); + + return true; + +} + +void ApplePS2ALPSGlidePoint::set_protocol() { + setProperty("ALPS Version", priv.proto_version, 32); + + priv.byte0 = 0x8f; + priv.mask0 = 0x8f; + priv.flags = ALPS_DUALPOINT; + + priv.x_max = 2000; + priv.y_max = 1400; + priv.x_bits = 15; + priv.y_bits = 11; + + switch (priv.proto_version) { + case ALPS_PROTO_V1: + case ALPS_PROTO_V2: + hw_init = &ApplePS2ALPSGlidePoint::alps_hw_init_v1_v2; + process_packet = &ApplePS2ALPSGlidePoint::alps_process_packet_v1_v2; + //set_abs_params = alps_set_abs_params_st; + priv.x_max = 1023; + priv.y_max = 767; + break; + + case ALPS_PROTO_V3: + hw_init = &ApplePS2ALPSGlidePoint::alps_hw_init_v3; + process_packet = &ApplePS2ALPSGlidePoint::alps_process_packet_v3; + //set_abs_params = alps_set_abs_params_semi_mt; + decode_fields = &ApplePS2ALPSGlidePoint::alps_decode_pinnacle; + priv.nibble_commands = alps_v3_nibble_commands; + priv.addr_command = kDP_MouseResetWrap; + + if (alps_probe_trackstick_v3_v7(ALPS_REG_BASE_PINNACLE)) { + priv.flags &= ~ALPS_DUALPOINT; + } else { + IOLog("ALPS: TrackStick detected...\n"); + } + + break; + + case ALPS_PROTO_V3_RUSHMORE: + hw_init = &ApplePS2ALPSGlidePoint::alps_hw_init_rushmore_v3; + process_packet = &ApplePS2ALPSGlidePoint::alps_process_packet_v3; + //set_abs_params = alps_set_abs_params_semi_mt; + decode_fields = &ApplePS2ALPSGlidePoint::alps_decode_rushmore; + priv.nibble_commands = alps_v3_nibble_commands; + priv.addr_command = kDP_MouseResetWrap; + priv.x_bits = 16; + priv.y_bits = 12; + + if (alps_probe_trackstick_v3_v7(ALPS_REG_BASE_RUSHMORE)) { + priv.flags &= ~ALPS_DUALPOINT; + } else { + IOLog("ALPS: TrackStick detected...\n"); + } + + break; + + case ALPS_PROTO_V4: + hw_init = &ApplePS2ALPSGlidePoint::alps_hw_init_v4; + process_packet = &ApplePS2ALPSGlidePoint::alps_process_packet_v4; + //set_abs_params = alps_set_abs_params_semi_mt; + priv.nibble_commands = alps_v4_nibble_commands; + priv.addr_command = kDP_SetDefaultsAndDisable; + break; + + case ALPS_PROTO_V5: + hw_init = &ApplePS2ALPSGlidePoint::alps_hw_init_dolphin_v1; + process_packet = &ApplePS2ALPSGlidePoint::alps_process_touchpad_packet_v3_v5; + decode_fields = &ApplePS2ALPSGlidePoint::alps_decode_dolphin; + //set_abs_params = alps_set_abs_params_semi_mt; + priv.nibble_commands = alps_v3_nibble_commands; + priv.addr_command = kDP_MouseResetWrap; + priv.byte0 = 0xc8; + priv.mask0 = 0xc8; + priv.flags = 0; + //priv.x_max = 1360; + //priv.y_max = 660; + priv.x_bits = 23; + priv.y_bits = 12; + + alps_dolphin_get_device_area(&priv); + break; + + case ALPS_PROTO_V6: + hw_init = &ApplePS2ALPSGlidePoint::alps_hw_init_v6; + process_packet = &ApplePS2ALPSGlidePoint::alps_process_packet_v6; + //set_abs_params = alps_set_abs_params_st; + priv.nibble_commands = alps_v6_nibble_commands; + priv.addr_command = kDP_MouseResetWrap; + priv.byte0 = 0xc8; + priv.mask0 = 0xc8; + priv.flags = 0; + priv.x_max = 2047; + priv.y_max = 1535; + break; + + case ALPS_PROTO_V7: + hw_init = &ApplePS2ALPSGlidePoint::alps_hw_init_v7; + process_packet = &ApplePS2ALPSGlidePoint::alps_process_packet_v7; + decode_fields = &ApplePS2ALPSGlidePoint::alps_decode_packet_v7; + //set_abs_params = alps_set_abs_params_v7; + priv.nibble_commands = alps_v3_nibble_commands; + priv.addr_command = kDP_MouseResetWrap; + priv.byte0 = 0x48; + priv.mask0 = 0x48; + + priv.x_max = 0xfff; + priv.y_max = 0x7ff; + + if (priv.fw_ver[1] != 0xba){ + priv.flags |= ALPS_BUTTONPAD; + IOLog("ALPS: ButtonPad Detected...\n"); + } + + if (alps_probe_trackstick_v3_v7(ALPS_REG_BASE_V7)){ + priv.flags &= ~ALPS_DUALPOINT; + } else { + IOLog("ALPS: TrackStick detected...\n"); + } + + break; + + case ALPS_PROTO_V8: + hw_init = &ApplePS2ALPSGlidePoint::alps_hw_init_ss4_v2; + process_packet = &ApplePS2ALPSGlidePoint::alps_process_packet_ss4_v2; + decode_fields = &ApplePS2ALPSGlidePoint::alps_decode_ss4_v2; + //set_abs_params = alps_set_abs_params_ss4_v2; + priv.nibble_commands = alps_v3_nibble_commands; + priv.addr_command = kDP_MouseResetWrap; + priv.byte0 = 0x18; + priv.mask0 = 0x18; + priv.flags = 0; + + alps_set_defaults_ss4_v2(&priv); + break; + } + + if (priv.proto_version != ALPS_PROTO_V1 || + priv.proto_version != ALPS_PROTO_V2 || + priv.proto_version != ALPS_PROTO_V6) + set_resolution(); +} + +bool ApplePS2ALPSGlidePoint::matchTable(ALPSStatus_t *e7, ALPSStatus_t *ec) { + const struct alps_model_info *model; + int i; + + IOLog("ALPS: Touchpad with Signature { %d, %d, %d }\n", e7->bytes[0], e7->bytes[1], e7->bytes[2]); + + for (i = 0; i < ARRAY_SIZE(alps_model_data); i++) { + model = &alps_model_data[i]; + + if (!memcmp(e7->bytes, model->signature, sizeof(model->signature))) { + + priv.proto_version = model->protocol_info.version; + + // log model version: + if (priv.proto_version == ALPS_PROTO_V1) { + IOLog("ALPS: Found an ALPS V1 TouchPad\n"); + } else if (priv.proto_version == ALPS_PROTO_V2) { + IOLog("ALPS: Found an ALPS V2 TouchPad\n"); + } else if (priv.proto_version == ALPS_PROTO_V3_RUSHMORE) { + IOLog("ALPS: Found an ALPS V3 Rushmore TouchPad\n"); + } else if (priv.proto_version == ALPS_PROTO_V4) { + IOLog("ALPS: Found an ALPS V4 TouchPad\n"); + }else if (priv.proto_version == ALPS_PROTO_V6) { + IOLog("ALPS: Found an ALPS V6 TouchPad\n"); + } + + set_protocol(); + + priv.flags = model->protocol_info.flags; + priv.byte0 = model->protocol_info.byte0; + priv.mask0 = model->protocol_info.mask0; + + return true; + } + } + + return false; +} + +IOReturn ApplePS2ALPSGlidePoint::identify() { + ALPSStatus_t e6, e7, ec; + + /* + * First try "E6 report". + * ALPS should return 0,0,10 or 0,0,100 if no buttons are pressed. + * The bits 0-2 of the first byte will be 1s if some buttons are + * pressed. + */ + + if (!alps_rpt_cmd(kDP_SetMouseResolution, NULL, kDP_SetMouseScaling1To1, &e6)) { + IOLog("ALPS: identify: not an ALPS device. Error getting E6 report\n"); + //return kIOReturnIOError; + } + + if ((e6.bytes[0] & 0xf8) != 0 || e6.bytes[1] != 0 || (e6.bytes[2] != 10 && e6.bytes[2] != 100)) { + IOLog("ALPS: identify: not an ALPS device. Invalid E6 report\n"); + //return kIOReturnInvalid; + } + + /* + * Now get the "E7" and "EC" reports. These will uniquely identify + * most ALPS touchpads. + */ + if (!(alps_rpt_cmd(kDP_SetMouseResolution, NULL, kDP_SetMouseScaling2To1, &e7) && + alps_rpt_cmd(kDP_SetMouseResolution, NULL, kDP_MouseResetWrap, &ec) && + alps_exit_command_mode())) { + IOLog("ALPS: identify: not an ALPS device. Error getting E7/EC report\n"); + return kIOReturnIOError; + } + + if (matchTable(&e7, &ec)) { + return 0; + + } else if (e7.bytes[0] == 0x73 && e7.bytes[1] == 0x02 && e7.bytes[2] == 0x64 && + ec.bytes[2] == 0x8a) { + priv.proto_version = ALPS_PROTO_V4; + IOLog("ALPS: Found a V4 TouchPad with ID: E7=0x%02x 0x%02x 0x%02x, EC=0x%02x 0x%02x 0x%02x\n", e7.bytes[0], e7.bytes[1], e7.bytes[2], ec.bytes[0], ec.bytes[1], ec.bytes[2]); + } else if (e7.bytes[0] == 0x73 && e7.bytes[1] == 0x03 && e7.bytes[2] == 0x50 && + ec.bytes[0] == 0x73 && (ec.bytes[1] == 0x01 || ec.bytes[1] == 0x02)) { + priv.proto_version = ALPS_PROTO_V5; + IOLog("ALPS: Found a V5 Dolphin TouchPad with ID: E7=0x%02x 0x%02x 0x%02x, EC=0x%02x 0x%02x 0x%02x\n", e7.bytes[0], e7.bytes[1], e7.bytes[2], ec.bytes[0], ec.bytes[1], ec.bytes[2]); + + } else if (ec.bytes[0] == 0x88 && + ((ec.bytes[1] & 0xf0) == 0xb0 || (ec.bytes[1] & 0xf0) == 0xc0)) { + priv.proto_version = ALPS_PROTO_V7; + IOLog("ALPS: Found a V7 TouchPad with ID: E7=0x%02x 0x%02x 0x%02x, EC=0x%02x 0x%02x 0x%02x\n", e7.bytes[0], e7.bytes[1], e7.bytes[2], ec.bytes[0], ec.bytes[1], ec.bytes[2]); + + } else if (ec.bytes[0] == 0x88 && ec.bytes[1] == 0x08) { + priv.proto_version = ALPS_PROTO_V3_RUSHMORE; + IOLog("ALPS: Found a V3 Rushmore TouchPad with ID: E7=0x%02x 0x%02x 0x%02x, EC=0x%02x 0x%02x 0x%02x\n", e7.bytes[0], e7.bytes[1], e7.bytes[2], ec.bytes[0], ec.bytes[1], ec.bytes[2]); + + } else if (ec.bytes[0] == 0x88 && ec.bytes[1] == 0x07 && + ec.bytes[2] >= 0x90 && ec.bytes[2] <= 0x9d) { + priv.proto_version = ALPS_PROTO_V3; + IOLog("ALPS: Found a V3 Pinnacle TouchPad with ID: E7=0x%02x 0x%02x 0x%02x, EC=0x%02x 0x%02x 0x%02x\n", e7.bytes[0], e7.bytes[1], e7.bytes[2], ec.bytes[0], ec.bytes[1], ec.bytes[2]); + + } else if (e7.bytes[0] == 0x73 && e7.bytes[1] == 0x03 && + (e7.bytes[2] == 0x14 || e7.bytes[2] == 0x28)) { + priv.proto_version = ALPS_PROTO_V8; + IOLog("ALPS: Found a V8 TouchPad with ID: E7=0x%02x 0x%02x 0x%02x, EC=0x%02x 0x%02x 0x%02x\n", e7.bytes[0], e7.bytes[1], e7.bytes[2], ec.bytes[0], ec.bytes[1], ec.bytes[2]); + + } else if (e7.bytes[0] == 0x73 && e7.bytes[1] == 0x03 && e7.bytes[2] == 0xc8) { + priv.proto_version = ALPS_PROTO_V9; + IOLog("ALPS: Found a unsupported V9 TouchPad with ID: E7=0x%02x 0x%02x 0x%02x, EC=0x%02x 0x%02x 0x%02x\n", e7.bytes[0], e7.bytes[1], e7.bytes[2], ec.bytes[0], ec.bytes[1], ec.bytes[2]); + + } else { + IOLog("ALPS: Touchpad didn't match any known IDs: E7=0x%02x 0x%02x 0x%02x, EC=0x%02x 0x%02x 0x%02x ... driver will now exit\n", + e7.bytes[0], e7.bytes[1], e7.bytes[2], ec.bytes[0], ec.bytes[1], ec.bytes[2]); + return kIOReturnInvalid; + } + + /* Save Device ID and Firmware version */ + memcpy(priv.dev_id, e7.bytes, 3); + memcpy(priv.fw_ver, ec.bytes, 3); + set_protocol(); + return 0; +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + +void ApplePS2ALPSGlidePoint::setTouchPadEnable(bool enable) { + DEBUG_LOG("ALPS: setTouchpadEnable enter\n"); + // + // Instructs the trackpad to start or stop the reporting of data packets. + // It is safe to issue this request from the interrupt/completion context. + // + + if (enable) { + initTouchPad(); + } else { + // to disable just reset the mouse + resetMouse(); + } +} + +void ApplePS2ALPSGlidePoint::ps2_command(unsigned char value, UInt8 command) { + TPS2Request<2> request; + int cmdCount = 0; + + request.commands[cmdCount].command = kPS2C_SendCommandAndCompareAck; + request.commands[cmdCount++].inOrOut = command; + request.commands[cmdCount].command = kPS2C_SendCommandAndCompareAck; + request.commands[cmdCount++].inOrOut = value; + request.commandsCount = cmdCount; + assert(request.commandsCount <= countof(request.commands)); + _device->submitRequestAndBlock(&request); + + //return request.commandsCount = cmdCount; +} + +void ApplePS2ALPSGlidePoint::ps2_command_short(UInt8 command) { + TPS2Request<1> request; + int cmdCount = 0; + + request.commands[cmdCount].command = kPS2C_SendCommandAndCompareAck; + request.commands[cmdCount++].inOrOut = command; + request.commandsCount = cmdCount; + assert(request.commandsCount <= countof(request.commands)); + _device->submitRequestAndBlock(&request); + + //return request.commandsCount = cmdCount; +} + +int ApplePS2ALPSGlidePoint::abs(int x) { + return (x < 0 ? -(x) : x); +} + +/* ============================================================================================== */ +/* ===========================||\\PROCESS AND DISPATCH TO macOS//||============================== */ +/* ============================================================================================== */ + + +void ApplePS2ALPSGlidePoint::set_resolution() { + physical_max_x = priv.x_max * 4; // this number was determined experimentally + physical_max_y = priv.y_max * 4.5; // this number was determined experimentally + + logical_max_x = priv.x_max; + logical_max_y = priv.y_max; + + setProperty("X Max", priv.x_max, 32); + setProperty("Y Max", priv.y_max, 32); + + if (priv.proto_version == ALPS_PROTO_V7) { + margin_size_x = 3 * xupmm; + + if (maxXOverride != -1) + logical_max_x = maxXOverride; + } + + setProperty(VOODOO_INPUT_LOGICAL_MAX_X_KEY, logical_max_x - margin_size_x, 32); + setProperty(VOODOO_INPUT_LOGICAL_MAX_Y_KEY, logical_max_y, 32); + + setProperty(VOODOO_INPUT_PHYSICAL_MAX_X_KEY, physical_max_x, 32); + setProperty(VOODOO_INPUT_PHYSICAL_MAX_Y_KEY, physical_max_y, 32); + + setProperty(VOODOO_INPUT_TRANSFORM_KEY, 0ull, 32); + setProperty("VoodooInputSupported", kOSBooleanTrue); + + registerService(); + + DEBUG_LOG("VoodooPS2Trackpad: logical_max %dx%d physical_max %dx%d upmm %dx%d\n", + logical_max_x, logical_max_y, + physical_max_x, physical_max_y, + xupmm, yupmm); +} + +void ApplePS2ALPSGlidePoint::alps_buttons(struct alps_fields &f) { + bool prev_left = left; + bool prev_right = right; + bool prev_middle = middle; + bool prev_left_ts = left_ts; + + left = f.left; + right = f.right | f.ts_right; + middle = f.middle | f.ts_middle; + left_ts = f.ts_left; + + AbsoluteTime timestamp; + clock_get_uptime(×tamp); + // Physical left button (for non-Clickpads) + // Only used if trackpad is not a clickpad + if (!(priv.flags & ALPS_BUTTONPAD)) { + if (left && !prev_left) + dispatchRelativePointerEvent(0, 0, 0x01, timestamp); + else if (prev_left && !left) + dispatchRelativePointerEvent(0, 0, 0x00, timestamp); + } + // Physical right button + if (right && !prev_right) + dispatchRelativePointerEvent(0, 0, 0x02, timestamp); + else if (prev_right && !right) + dispatchRelativePointerEvent(0, 0, 0x00, timestamp); + // Physical middle button + if (middle && !prev_middle) + dispatchRelativePointerEvent(0, 0, 0x04, timestamp); + else if (prev_middle && !middle) + dispatchRelativePointerEvent(0, 0, 0x00, timestamp); + // Physical left button (Trackstick) + if (left_ts && !prev_left_ts) + dispatchRelativePointerEvent(0, 0, 0x01, timestamp); + else if (prev_left_ts && !left_ts) + dispatchRelativePointerEvent(0, 0, 0x00, timestamp); +} + +// port from VoodooPS2SynapticsTouchpad.cpp; huge credits to @usr-sse2 + +#define sqr(x) ((x) * (x)) +int ApplePS2ALPSGlidePoint::dist(int physicalFinger, int virtualFinger) { + const auto &phy = fingerStates[physicalFinger]; + const auto &virt = virtualFingerStates[virtualFinger]; + return sqr(phy.x - virt.x_avg.newest()) + sqr(phy.y - virt.y_avg.newest()); +} + +void ApplePS2ALPSGlidePoint::assignVirtualFinger(int physicalFinger) { + if (physicalFinger < 0 || physicalFinger >= MAX_TOUCHES) { + IOLog("alps_parse_hw_state: ALPS::assignVirtualFinger ERROR: invalid physical finger %d\n", physicalFinger); + return; + } + for (int j = 0; j < MAX_TOUCHES; j++) { + virtual_finger_state &vfj = virtualFingerStates[j]; + if (!vfj.touch) { + fingerStates[physicalFinger].virtualFingerIndex = j; + vfj.touch = true; + vfj.x_avg.reset(); + vfj.y_avg.reset(); + assignFingerType(vfj); + break; + } + } +} + +void ApplePS2ALPSGlidePoint::assignFingerType(virtual_finger_state &vf) { + vf.fingerType = kMT2FingerTypeUndefined; + for (MT2FingerType i = kMT2FingerTypeIndexFinger; i < kMT2FingerTypeCount; i = (MT2FingerType)(i + 1)) + if (freeFingerTypes[i]) { + freeFingerTypes[i] = false; + vf.fingerType = i; break; + } +} - case kPS2C_EnableDevice: - - setTapEnable( _touchPadModeByte ); +void ApplePS2ALPSGlidePoint::freeAndMarkVirtualFingers() { + memset(freeFingerTypes, true, kMT2FingerTypeCount); + freeFingerTypes[kMT2FingerTypeUndefined] = false; + + for (int i = 0; i < MAX_TOUCHES; i++) { // free up all virtual fingers + auto &vfi = virtualFingerStates[i]; + vfi.touch = false; + vfi.x_avg.reset(); // maybe it should be done only for unpressed fingers? + vfi.y_avg.reset(); + vfi.pressure = 0; + } + + for (int i = 0; i < clampedFingerCount; i++) { // mark virtual fingers as used + int j = fingerStates[i].virtualFingerIndex; + if (j == -1) { + IOLog("alps_parse_hw_state: WTF!? Finger %d has no virtual finger\n", i); + continue; + } + auto &vfj = virtualFingerStates[j]; + vfj.touch = true; + freeFingerTypes[vfj.fingerType] = false; + } + + for (int i = 0; i < MAX_TOUCHES; i++) { + auto &vfi = virtualFingerStates[i]; + if (!vfi.touch) + vfi.fingerType = kMT2FingerTypeUndefined; + } +} + +static void clone(alps_hw_state &dst, const alps_hw_state &src) { + dst.x = src.x; + dst.y = src.y; + dst.z = src.z; +} + +int ApplePS2ALPSGlidePoint::upperFingerIndex() const { + return fingerStates[0].y < fingerStates[1].y ? 1 : 0; +} + +const alps_hw_state& ApplePS2ALPSGlidePoint::upperFinger() const { + return fingerStates[upperFingerIndex()]; +} + +void ApplePS2ALPSGlidePoint::swapFingers(int dst, int src) { + int j = fingerStates[src].virtualFingerIndex; + const auto &vfj = virtualFingerStates[j]; + fingerStates[dst].x = vfj.x_avg.average(); + fingerStates[dst].y = vfj.y_avg.average(); + fingerStates[dst].virtualFingerIndex = j; + assignVirtualFinger(src); +} + +#define FINGER_DIST 1000000 + +bool ApplePS2ALPSGlidePoint::renumberFingers() { + const auto &f0 = fingerStates[0]; + const auto &f1 = fingerStates[1]; + auto &f2 = fingerStates[2]; + auto &f3 = fingerStates[3]; + auto &f4 = fingerStates[4]; + + if (clampedFingerCount == lastFingerCount && clampedFingerCount >= 3) { + // update imaginary finger states + if (f0.virtualFingerIndex != -1 && f1.virtualFingerIndex != -1) { + if (clampedFingerCount >= 4) { + const auto &fi = upperFinger(); + const auto &fiv = virtualFingerStates[fi.virtualFingerIndex]; + for (int j = 2; j < clampedFingerCount; j++) { + auto &fj = fingerStates[j]; + fj.x += fi.x - fiv.x_avg.newest(); + fj.y += fi.y - fiv.y_avg.newest(); + fj.z = fi.z; + } + } + else if (clampedFingerCount == 3) { + const auto &f0v = virtualFingerStates[f0.virtualFingerIndex]; + const auto &f1v = virtualFingerStates[f1.virtualFingerIndex]; + auto &f2 = fingerStates[2]; + f2.x += ((f0.x - f0v.x_avg.newest()) + (f1.x - f1v.x_avg.newest())) / 2; + f2.y += ((f0.y - f0v.y_avg.newest()) + (f1.y - f1v.y_avg.newest())) / 2; + f2.z = (f0.z + f1.z) / 2; + } + } + else + IOLog("alps_parse_hw_state: WTF - have %d fingers, but first 2 don't have virtual finger\n", clampedFingerCount); + } + + // We really need to send the "no touch" event + // multiple times, because if we don't do it and return, + // gestures like desktop switching or inertial scrolling + // got stuck midway until the next touch. + //if(!lastFingerCount && !clampedFingerCount) { + // return 0; + //} + + // Finger type detection: + // We think that fingers are added beginning with the index finger, + // then middle, ring and little. + // However, when the finger count reaches 4, the lowest finger becomes thumb, + // but other fingers don't change their types. + // All fingers preserve their types during the gesture. + // Though it would be nice to see what MT2 does. + + if (clampedFingerCount == lastFingerCount && clampedFingerCount == 1) { + int i = 0; + int j = fingerStates[i].virtualFingerIndex; + int d = dist(i, j); + if (d > FINGER_DIST) { // this number was determined experimentally + // Prevent jumps by unpressing finger. Other way could be leaving the old finger pressed. + DEBUG_LOG("alps_parse_hw_state: unpressing finger: dist is %d\n", d); + auto &vfj = virtualFingerStates[j]; + vfj.x_avg.reset(); + vfj.y_avg.reset(); + vfj.pressure = 0; + vfj.fingerType = kMT2FingerTypeUndefined; + clampedFingerCount = 0; + } + } + if (clampedFingerCount != lastFingerCount) { + if (clampedFingerCount > lastFingerCount && clampedFingerCount >= 3) { + // Skip sending touch data once because we need to wait for the next extended packet + if (wasSkipped) + wasSkipped = false; + else { + DEBUG_LOG("alps_parse_hw_state: Skip sending touch data\n"); + wasSkipped = true; + return false; + } + } + + if (lastFingerCount == 0) { + // Assign to identity mapping + for (int i = 0; i < clampedFingerCount; i++) { + auto &fi = fingerStates[i]; + fi.virtualFingerIndex = i; + auto &vfi = virtualFingerStates[i]; + vfi.touch = true; + assignFingerType(vfi); + vfi.x_avg.reset(); + vfi.y_avg.reset(); + if (i >= 2) // more than 3 fingers added simultaneously + clone(fi, upperFinger()); // Copy from the upper finger + } + } + else if (clampedFingerCount > lastFingerCount && !hadLiftFinger) { + // First finger already exists + // Can add 1, 2 or 3 fingers at once + // Newly added finger is always in secondary finger packet + switch (clampedFingerCount - lastFingerCount) { + case 1: + if (lastFingerCount >= 2) + swapFingers(lastFingerCount, 1); + else // lastFingerCount = 1 + assignVirtualFinger(1); + break; + case 2: + if (lastFingerCount == 1) { // added second and third + assignVirtualFinger(1); + clone(f2, upperFinger()); // We don't know better + assignVirtualFinger(2); + } + else { // added third and fourth + swapFingers(lastFingerCount, 1); + + // add fourth + clone(f3, upperFinger()); + assignVirtualFinger(3); + } + break; + case 3: + assignVirtualFinger(1); + clone(f2, upperFinger()); + assignVirtualFinger(2); + clone(f3, upperFinger()); + assignVirtualFinger(3); + break; + case 4: + assignVirtualFinger(1); + clone(f2, upperFinger()); + assignVirtualFinger(2); + clone(f3, upperFinger()); + assignVirtualFinger(3); + clone(f4, upperFinger()); + assignVirtualFinger(4); + break; + default: + IOLog("alps_parse_hw_state: WTF!? fc=%d lfc=%d\n", clampedFingerCount, lastFingerCount); + } + } + else if (clampedFingerCount > lastFingerCount && hadLiftFinger) { + for (int i = 0; i < MAX_TOUCHES; i++) // clean virtual finger numbers + fingerStates[i].virtualFingerIndex = -1; + + int maxMinDist = 0, maxMinDistIndex = -1; + int secondMaxMinDist = 0, secondMaxMinDistIndex = -1; + + // find new physical finger for each existing virtual finger + for (int j = 0; j < MAX_TOUCHES; j++) { + if (!virtualFingerStates[j].touch) + continue; // free + int minDist = INT_MAX, minIndex = -1; + for (int i = 0; i < lastFingerCount; i++) { + if (fingerStates[i].virtualFingerIndex != -1) + continue; // already taken + int d = dist(i, j); + if (d < minDist) { + minDist = d; + minIndex = i; + } + } + if (minIndex == -1) { + IOLog("alps_parse_hw_state: WTF!? minIndex is -1\n"); + continue; + } + if (minDist > maxMinDist) { + secondMaxMinDist = maxMinDist; + secondMaxMinDistIndex = maxMinDistIndex; + maxMinDist = minDist; + maxMinDistIndex = minIndex; + } + fingerStates[minIndex].virtualFingerIndex = j; + } + + // assign new virtual fingers for all new fingers + for (int i = 0; i < min(2, clampedFingerCount); i++) // third and fourth 'fingers' are handled separately + if (fingerStates[i].virtualFingerIndex == -1) + assignVirtualFinger(i); // here OK + + if (clampedFingerCount == 3) { + DEBUG_LOG("alps_parse_hw_state: adding third finger, maxMinDist=%d\n", maxMinDist); + f2.z = (f0.z + f1.z) / 2; + if (maxMinDist > FINGER_DIST && maxMinDistIndex >= 0) { + // i-th physical finger was replaced, save its old coordinates to the 3rd physical finger and map it to a new virtual finger. + // The third physical finger should now be mapped to the old fingerStates[i].virtualFingerIndex. + swapFingers(2, maxMinDistIndex); + DEBUG_LOG("alps_parse_hw_state: swapped, saving location\n"); + } + else { + // existing fingers didn't change or were swapped, so we don't know the location of the third finger + const auto &fj = upperFinger(); + + f2.x = fj.x; + f2.y = fj.y; + assignVirtualFinger(2); + DEBUG_LOG("alps_parse_hw_state: not swapped, taking upper finger position\n"); + } + } + else if (clampedFingerCount >= 4) { + // Is it possible that both 0 and 1 fingers were swapped with 2 and 3? + DEBUG_LOG("alps_parse_hw_state: adding third and fourth fingers, maxMinDist=%d, secondMaxMinDist=%d\n", maxMinDist, secondMaxMinDist); + f2.z = f3.z = (f0.z + f1.z) / 2; + + // Possible situations: + // 1. maxMinDist ≤ 1000000, lastFingerCount = 3 - no fingers swapped, just adding 4th finger + // 2. maxMinDist ≤ 1000000, lastFingerCount = 2 - no fingers swapped, just adding 3rd and 4th fingers + // 3. maxMinDist > 1000000, secondMaxMinDist ≤ 1000000, lastFingerCount = 3 - i'th finger was swapped with 4th, 3rd left in place (i∈{0,1}): + // 4th.xy = i'th.xy + // p2v[2] = j + // p2v[i] = next free + // 4. maxMinDist > 1000000, secondMaxMinDist > 1000000, lastFingerCount = 3 - i'th finger was swapped with 3rd and k'th finger was swapped with 4th (i,k∈{0,1}): + // is it possible that only imaginary finger was left in place?! + // 5. maxMinDist > 1000000, secondMaxMinDist ≤ 1000000, lastFingerCount = 2 - one finger swapped, one finger left in place. + + + if (maxMinDist > FINGER_DIST && maxMinDistIndex >= 0) { + if (lastFingerCount < 3) { + // i-th physical finger was replaced, save its old coordinates to the 3rd physical finger and map it to a new virtual finger. + // The third physical finger should now be mapped to the old fingerStates[i].virtualFingerIndex. + swapFingers(2, maxMinDistIndex); + if (secondMaxMinDist > FINGER_DIST && secondMaxMinDistIndex >= 0) { + // both fingers were swapped with new ones + // i-th physical finger was replaced, save its old coordinates to the 4th physical finger and map it to a new virtual finger. + // The fourth physical finger should now be mapped to the old fingerStates[i].virtualFingerIndex. + swapFingers(3, secondMaxMinDistIndex); + } + else { + // fourth finger is new + clone(f3, upperFinger()); + assignVirtualFinger(3); + } + } + else { + // i-th physical finger was replaced, save its old coordinates to the 4th physical finger and map it to a new virtual finger. + // The fourth physical finger should now be mapped to the old fingerStates[i].virtualFingerIndex. + swapFingers(3, maxMinDistIndex); + if (secondMaxMinDist > FINGER_DIST && secondMaxMinDistIndex >= 0) { + IOLog("alps_parse_hw_state: WTF, I thought it is impossible: fc=%d, lfc=%d, mdi=%d(%d), smdi=%d(%d)\n", clampedFingerCount, lastFingerCount, maxMinDist, maxMinDistIndex, secondMaxMinDist, secondMaxMinDistIndex); + } + } + DEBUG_LOG("alps_parse_hw_state: swapped, saving location\n"); + } + else { + // existing fingers didn't change or were swapped, so we don't know the location of the third and fourth fingers + const auto &fj = upperFinger(); + clone(f2, fj); + if (lastFingerCount < 3) + assignVirtualFinger(2); + clone(f3, fj); + assignVirtualFinger(3); + DEBUG_LOG("alps_parse_hw_state: not swapped, cloning existing fingers\n"); + } + if (clampedFingerCount >= 5) { + // Don't bother with 5th finger, always clone + clone(f4, upperFinger()); + assignVirtualFinger(4); + DEBUG_LOG("alps_parse_hw_state: cloning 5th finger\n"); + } + } + freeAndMarkVirtualFingers(); + } + else if (clampedFingerCount < lastFingerCount) { + // Set hadLiftFinger if lifted some fingers + // Reset hadLiftFinger if lifted all fingers + hadLiftFinger = clampedFingerCount > 0; + + // some fingers removed, need renumbering + bool used[MAX_TOUCHES]; + for (int i = 0; i < MAX_TOUCHES; i++) { // clean virtual finger numbers + fingerStates[i].virtualFingerIndex = -1; + used[i] = false; + } + for (int i = 0; i < clampedFingerCount; i++) { + // find new virtual finger number with nearest coordinates for this finger + int minDist = INT_MAX, minIndex = -1; + for (int j = 0; j < MAX_TOUCHES; j++) { + if (!virtualFingerStates[j].touch || used[j]) + continue; + int d = dist(i, j); + if (d < minDist) { + minDist = d; + minIndex = j; + } + } + fingerStates[i].virtualFingerIndex = minIndex; + if (minIndex == -1) { + IOLog("alps_parse_hw_state: WTF: renumbering failed, minIndex for %d is -1\n", i); + continue; + } + used[minIndex] = true; + } + freeAndMarkVirtualFingers(); + } + } + + for (int i = 0; i < clampedFingerCount; i++) { + const auto &fi = fingerStates[i]; + DEBUG_LOG("alps_parse_hw_state: finger %d -> virtual finger %d\n", i, fi.virtualFingerIndex); + if (fi.virtualFingerIndex < 0 || fi.virtualFingerIndex >= MAX_TOUCHES) { + IOLog("alps_parse_hw_state: ERROR: invalid physical finger %d\n", fi.virtualFingerIndex); + continue; + } + virtual_finger_state &fiv = virtualFingerStates[fi.virtualFingerIndex]; + fiv.x_avg.filter(fi.x); + fiv.y_avg.filter(fi.y); + fiv.pressure = fi.z; + // Only use this if trackpad is a clickpad + if (priv.flags & ALPS_BUTTONPAD) + fiv.button = left; + else + fiv.button = 0; + } + + // Thumb detection. Must happen after setting coordinates (filter) + if (clampedFingerCount > lastFingerCount && clampedFingerCount >= 4) { + // find the lowest finger + int lowestFingerIndex = -1; + int min_y = INT_MAX; + for (int i = 0; i < MAX_TOUCHES; i++) { + const auto &vfi = virtualFingerStates[i]; + DEBUG_LOG("alps_parse_hw_state: finger %d: touch %d, y %d\n", i, vfi.touch, vfi.y_avg.average()); + if (vfi.touch && vfi.y_avg.average() < min_y) { + lowestFingerIndex = i; + min_y = vfi.y_avg.average(); + } + } + DEBUG_LOG("alps_parse_hw_state: lowest finger: %d\n", lowestFingerIndex); + if (lowestFingerIndex == -1) + IOLog("alps_parse_hw_state: WTF?! lowest finger not found!\n"); + else { + auto &vf = virtualFingerStates[lowestFingerIndex]; + freeFingerTypes[vf.fingerType] = true; + vf.fingerType = kMT2FingerTypeThumb; + freeFingerTypes[kMT2FingerTypeThumb] = false; + } + } + + DEBUG_LOG("alps_parse_hw_state: lastFingerCount=%d clampedFingerCount=%d left=%d\n", lastFingerCount, clampedFingerCount, left); + return true; +} + +void ApplePS2ALPSGlidePoint::sendTouchData() { + // Ignore input for specified time after keyboard usage + AbsoluteTime timestamp; + clock_get_uptime(×tamp); + uint64_t timestamp_ns; + absolutetime_to_nanoseconds(timestamp, ×tamp_ns); + + if (timestamp_ns - keytime < maxaftertyping) + return; + + if (lastFingerCount != clampedFingerCount) { + lastFingerCount = clampedFingerCount; + return; // Skip while fingers are placed on the touchpad or removed + } + + static_assert(VOODOO_INPUT_MAX_TRANSDUCERS >= MAX_TOUCHES, "Trackpad supports too many fingers"); + + int transducers_count = 0; + for(int i = 0; i < MAX_TOUCHES; i++) { + const auto& state = virtualFingerStates[i]; + if (!state.touch) + continue; + + auto& transducer = inputEvent.transducers[transducers_count++]; + + transducer.type = FINGER; + transducer.isValid = true; + if (_forceTouchMode == FORCE_TOUCH_DISABLED || _forceTouchMode == FORCE_TOUCH_BUTTON) + transducer.supportsPressure = false; + else + transducer.supportsPressure = true; + + int posX = state.x_avg.average(); + int posY = state.y_avg.average(); + + posY = logical_max_y + 1 - posY; + + DEBUG_LOG("alps_parse_hw_state: finger[%d] x=%d y=%d raw_x=%d raw_y=%d\n", i, posX, posY, state.x_avg.average(), state.y_avg.average()); + + transducer.previousCoordinates = transducer.currentCoordinates; + + transducer.currentCoordinates.x = posX; + transducer.currentCoordinates.y = posY; + transducer.timestamp = timestamp; + + switch (_forceTouchMode) + { + case FORCE_TOUCH_BUTTON: // Physical button is translated into force touch instead of click + transducer.isPhysicalButtonDown = false; + transducer.currentCoordinates.pressure = state.button ? 255 : 0; + break; + + case FORCE_TOUCH_THRESHOLD: // Force touch is touch with pressure over threshold + transducer.isPhysicalButtonDown = state.button; + transducer.currentCoordinates.pressure = state.pressure > _forceTouchPressureThreshold ? 255 : 0; + break; + + case FORCE_TOUCH_VALUE: // Pressure is passed to system as is + transducer.isPhysicalButtonDown = state.button; + transducer.currentCoordinates.pressure = state.pressure; + break; + + case FORCE_TOUCH_CUSTOM: // Pressure is passed, but with locking + transducer.isPhysicalButtonDown = state.button; + + if (clampedFingerCount != 1) { + transducer.currentCoordinates.pressure = state.pressure > _forceTouchPressureThreshold ? 255 : 0; + break; + } + + double value; + if (state.pressure >= _forceTouchCustomDownThreshold) { + value = 1.0; + } else if (state.pressure <= _forceTouchCustomUpThreshold) { + value = 0.0; + } else { + double base = ((double) (state.pressure - _forceTouchCustomUpThreshold)) / ((double) (_forceTouchCustomDownThreshold - _forceTouchCustomUpThreshold)); + value = 1; + for (int i = 0; i < _forceTouchCustomPower; ++i) { + value *= base; + } + } + transducer.currentCoordinates.pressure = (int) (value * 255); + break; + + case FORCE_TOUCH_DISABLED: + default: + transducer.isPhysicalButtonDown = state.button; + transducer.currentCoordinates.pressure = 0; + break; + + } + + transducer.isTransducerActive = 1; + transducer.currentCoordinates.width = state.pressure / 2; + if (state.fingerType == kMT2FingerTypeUndefined) + IOLog("alps_parse_hw_state: WTF!? finger type is undefined\n"); + if (state.fingerType < kMT2FingerTypeUndefined || state.fingerType > kMT2FingerTypeLittleFinger) + IOLog("alps_parse_hw_state: WTF!? finger type is out of range\n"); + if (freeFingerTypes[state.fingerType]) + IOLog("alps_parse_hw_state: WTF!? finger type is marked free\n"); + transducer.fingerType = state.fingerType; + transducer.secondaryId = i; + } + + for (int i = 0; i < transducers_count; i++) + for (int j = i + 1; j < transducers_count; j++) + if (inputEvent.transducers[i].fingerType == inputEvent.transducers[j].fingerType) + IOLog("alps_parse_hw_state: WTF!? equal finger types\n"); + + if (transducers_count != clampedFingerCount) + IOLog("alps_parse_hw_state: WTF?! tducers_count %d clampedFingerCount %d\n", transducers_count, clampedFingerCount); + + // create new VoodooI2CMultitouchEvent + inputEvent.contact_count = transducers_count; + inputEvent.timestamp = timestamp; + + // send the event into the multitouch interface + // send the 0 finger message only once + if (inputEvent.contact_count != 0 || lastSentFingerCount != 0) { + super::messageClient(kIOMessageVoodooInputMessage, voodooInputInstance, &inputEvent, sizeof(VoodooInputEvent)); + } + lastFingerCount = clampedFingerCount; + lastSentFingerCount = inputEvent.contact_count; +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + +void ApplePS2ALPSGlidePoint::initTouchPad() { + // + // Clear packet buffer pointer to avoid issues caused by + // stale packet fragments. + // + + _packetByteCount = 0; + _ringBuffer.reset(); + + // clear state of control key cache + _modifierdown = 0; + + // initialize the touchpad + deviceSpecificInit(); +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + +void ApplePS2ALPSGlidePoint::setParamPropertiesGated(OSDictionary * config) { + if (NULL == config) + return; + + const struct {const char *name; int *var;} int32vars[]={ + {"FingerZ", &z_finger}, + {"WakeDelay", &wakedelay}, + {"Resolution", &_resolution}, + {"ScrollResolution", &_scrollresolution}, + {"UnitsPerMMX", &xupmm}, + {"UnitsPerMMY", &yupmm}, + {"MinLogicalXOverride", &minXOverride}, + {"MinLogicalYOverride", &minYOverride}, + {"MaxLogicalXOverride", &maxXOverride}, + {"MaxLogicalYOverride", &maxYOverride}, + {"ForceTouchMode", (int*)&_forceTouchMode}, // 0 - disable, 1 - left button, 2 - pressure threshold, 3 - pass pressure value + {"ForceTouchPressureThreshold", &_forceTouchPressureThreshold}, // used in mode 2 + {"ForceTouchCustomDownThreshold", &_forceTouchCustomDownThreshold}, // used in mode 4 + {"ForceTouchCustomUpThreshold", &_forceTouchCustomUpThreshold}, // used in mode 4 + {"ForceTouchCustomPower", &_forceTouchCustomPower}, // used in mode 4 + }; + + const struct {const char *name; int *var;} boolvars[]={ + {"ProcessUSBMouseStopsTrackpad", &_processusbmouse}, + {"ProcessBluetoothMouseStopsTrackpad", &_processbluetoothmouse}, + }; + + const struct {const char* name; bool* var;} lowbitvars[]={ + {"USBMouseStopsTrackpad", &usb_mouse_stops_trackpad}, + }; + const struct {const char* name; uint64_t* var; } int64vars[]={ + {"QuietTimeAfterTyping", &maxaftertyping}, + }; + + OSBoolean *bl; + OSNumber *num; + // 64-bit config items + 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)))) + { + *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)))) + { + *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; + 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)))) + { + *lowbitvars[i].var = bl->isTrue(); + setProperty(lowbitvars[i].name, *lowbitvars[i].var ? kOSBooleanTrue : kOSBooleanFalse); + } + } + + // disable trackpad when USB mouse is plugged in and this functionality is requested + if (attachedHIDPointerDevices && attachedHIDPointerDevices->getCount() > 0) { + ignoreall = usb_mouse_stops_trackpad; + } + + if (_forceTouchMode == FORCE_TOUCH_BUTTON) { + int val[16]; + if (PE_parse_boot_argn("rp0", val, sizeof(val)) || + PE_parse_boot_argn("rp", val, sizeof(val)) || + PE_parse_boot_argn("container-dmg", val, sizeof(val)) || + PE_parse_boot_argn("root-dmg", val, sizeof(val)) || + PE_parse_boot_argn("auth-root-dmg", val, sizeof(val))) + _forceTouchMode = FORCE_TOUCH_DISABLED; + } +} + +IOReturn ApplePS2ALPSGlidePoint::setParamProperties(OSDictionary* dict) { + ////IOReturn result = super::IOHIDevice::setParamProperties(dict); + if (_cmdGate) + { + // syncronize through workloop... + ////_cmdGate->runAction(OSMemberFunctionCast(IOCommandGate::Action, this, &VooodooPS2TouchPadBase::setParamPropertiesGated), dict); + setParamPropertiesGated(dict); + } + + return super::setParamProperties(dict); + ////return result; +} + +IOReturn ApplePS2ALPSGlidePoint::setProperties(OSObject *props) { + OSDictionary *dict = OSDynamicCast(OSDictionary, props); + if (dict && _cmdGate) + { + // syncronize through workloop... + _cmdGate->runAction(OSMemberFunctionCast(IOCommandGate::Action, this, &ApplePS2ALPSGlidePoint::setParamPropertiesGated), dict); + } + + return super::setProperties(props); +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + +void ApplePS2ALPSGlidePoint::setDevicePowerState( UInt32 whatToDo ) { + switch ( whatToDo ) + { + case kPS2C_DisableDevice: + // + // Disable touchpad (synchronous). + // + setTouchPadEnable( false ); + break; + + case kPS2C_EnableDevice: // - // Finally, we enable the trackpad itself, so that it may - // start reporting asynchronous events. + // Must not issue any commands before the device has + // completed its power-on self-test and calibration. // - setAbsoluteMode(); - - _ringBuffer.reset(); - _packetByteCount = 0; - - setTouchPadEnable( true ); + + IOSleep(wakedelay); + + // MARK: Find another way to fix trackpad breaking on V8 after sleep + // This workaround is very messy and unstable. + // A proper fix is needed. + // Reset and re-initialize touchpad + _device->lock(); + resetMouse(); + identify(); + initTouchPad(); + _device->unlock(); break; - } + } } -void ApplePS2ALPSGlidePoint::getStatus(ALPSStatus_t *status) -{ - // (read command byte) - TPS2Request<7> request; - request.commands[0].command = kPS2C_SendCommandAndCompareAck; - request.commands[0].inOrOut = kDP_SetDefaultsAndDisable; - request.commands[1].command = kPS2C_SendCommandAndCompareAck; - request.commands[1].inOrOut = kDP_SetDefaultsAndDisable; - request.commands[2].command = kPS2C_SendCommandAndCompareAck; - request.commands[2].inOrOut = kDP_SetDefaultsAndDisable; - request.commands[3].command = kPS2C_SendCommandAndCompareAck; - request.commands[3].inOrOut = kDP_GetMouseInformation; - request.commands[4].command = kPS2C_ReadDataPort; - request.commands[4].inOrOut = 0; - request.commands[5].command = kPS2C_ReadDataPort; - request.commands[5].inOrOut = 0; - request.commands[6].command = kPS2C_ReadDataPort; - request.commands[6].inOrOut = 0; - request.commandsCount = 7; - assert(request.commandsCount <= countof(request.commands)); - _device->submitRequestAndBlock(&request); - - status->byte0 = request.commands[4].inOrOut; - status->byte1 = request.commands[5].inOrOut; - status->byte2 = request.commands[6].inOrOut; - - DEBUG_LOG("getStatus(): [%02x %02x %02x]\n", status->byte0, status->byte1, status->byte2); +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + +IOReturn ApplePS2ALPSGlidePoint::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 is true when trackpad has been disabled + if (enable == ignoreall) + { + // save state, and update LED + ignoreall = !enable; + } + break; + } + + case kPS2M_resetTouchpad: + { + int *reqCode = (int *)argument; + DEBUG_LOG("ALPS::kPS2M_resetTouchpad reqCode: %d\n", *reqCode); + if (*reqCode == 1) { + ignoreall = false; + _device->lock(); + resetMouse(); + IOSleep(wakedelay); + identify(); + initTouchPad(); + _device->unlock(); + } + 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; + static const int masks[] = + { + 0x10, // 0x36 + 0x100000, // 0x37 + 0, // 0x38 + 0, // 0x39 + 0x080000, // 0x3a + 0x040000, // 0x3b + 0, // 0x3c + 0x08, // 0x3d + 0x04, // 0x3e + 0x200000, // 0x3f + }; + + switch (pInfo->adbKeyCode) + { + // don't store key time for modifier keys going down + // track modifiers for scrollzoom feature... + // (note: it turns out we didn't need to do this, but leaving this code in for now in case it is useful) + case 0x38: // left shift + case 0x3c: // right shift + case 0x3b: // left control + case 0x3e: // right control + case 0x3a: // left windows (option) + case 0x3d: // right windows + case 0x37: // left alt (command) + case 0x36: // right alt + case 0x3f: // osx fn (function) + if (pInfo->goingDown) + { + _modifierdown |= masks[pInfo->adbKeyCode-0x36]; + break; + } + _modifierdown &= ~masks[pInfo->adbKeyCode-0x36]; + keytime = pInfo->time; + break; + + default: + keytime = pInfo->time; + } + break; + } + } + + return kIOReturnSuccess; } -void ApplePS2ALPSGlidePoint::getModel(ALPSStatus_t *E6,ALPSStatus_t *E7) -{ - // "E6 report" - TPS2Request<9> request; - request.commands[0].command = kPS2C_SendCommandAndCompareAck; - request.commands[0].inOrOut = kDP_SetMouseResolution; - request.commands[1].command = kPS2C_SendCommandAndCompareAck; - request.commands[1].inOrOut = 0; - - // 3X set mouse scaling 1 to 1 - request.commands[2].command = kPS2C_SendCommandAndCompareAck; - request.commands[2].inOrOut = kDP_SetMouseScaling1To1; - request.commands[3].command = kPS2C_SendCommandAndCompareAck; - request.commands[3].inOrOut = kDP_SetMouseScaling1To1; - request.commands[4].command = kPS2C_SendCommandAndCompareAck; - request.commands[4].inOrOut = kDP_SetMouseScaling1To1; - request.commands[5].command = kPS2C_SendCommandAndCompareAck; - request.commands[5].inOrOut = kDP_GetMouseInformation; - request.commands[6].command = kPS2C_ReadDataPort; - request.commands[6].inOrOut = 0; - request.commands[7].command = kPS2C_ReadDataPort; - request.commands[7].inOrOut = 0; - request.commands[8].command = kPS2C_ReadDataPort; - request.commands[8].inOrOut = 0; - request.commandsCount = 9; - assert(request.commandsCount <= countof(request.commands)); - _device->submitRequestAndBlock(&request); - - // result is "E6 report" - E6->byte0 = request.commands[6].inOrOut; - E6->byte1 = request.commands[7].inOrOut; - E6->byte2 = request.commands[8].inOrOut; - - // Now fetch "E7 report" - request.commands[0].command = kPS2C_SendCommandAndCompareAck; - request.commands[0].inOrOut = kDP_SetMouseResolution; - request.commands[1].command = kPS2C_SendCommandAndCompareAck; - request.commands[1].inOrOut = 0; - - // 3X set mouse scaling 2 to 1 - request.commands[2].command = kPS2C_SendCommandAndCompareAck; - request.commands[2].inOrOut = kDP_SetMouseScaling2To1; - request.commands[3].command = kPS2C_SendCommandAndCompareAck; - request.commands[3].inOrOut = kDP_SetMouseScaling2To1; - request.commands[4].command = kPS2C_SendCommandAndCompareAck; - request.commands[4].inOrOut = kDP_SetMouseScaling2To1; - request.commands[5].command = kPS2C_SendCommandAndCompareAck; - request.commands[5].inOrOut = kDP_GetMouseInformation; - request.commands[6].command = kPS2C_ReadDataPort; - request.commands[6].inOrOut = 0; - request.commands[7].command = kPS2C_ReadDataPort; - request.commands[7].inOrOut = 0; - request.commands[8].command = kPS2C_ReadDataPort; - request.commands[8].inOrOut = 0; - request.commandsCount = 9; - assert(request.commandsCount <= countof(request.commands)); - _device->submitRequestAndBlock(&request); +void ApplePS2ALPSGlidePoint::registerHIDPointerNotifications() { + IOServiceMatchingNotificationHandler notificationHandler = OSMemberFunctionCast(IOServiceMatchingNotificationHandler, this, &ApplePS2ALPSGlidePoint::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"); + + 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"); + propertyMatching(OSSymbol::withCString(kIOHIDVirtualHIDevice), kOSBooleanFalse, matchingDictionary); - // result is "E7 report" - E7->byte0 = request.commands[6].inOrOut; - E7->byte1 = request.commands[7].inOrOut; - E7->byte2 = request.commands[8].inOrOut; + // 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); + OSSafeReleaseNULL(matchingDictionary); + } } -void ApplePS2ALPSGlidePoint::setAbsoluteMode() -{ - // (read command byte) - TPS2Request<6> request; - request.commands[0].command = kPS2C_SendCommandAndCompareAck; - request.commands[0].inOrOut = kDP_SetDefaultsAndDisable; - request.commands[1].command = kPS2C_SendCommandAndCompareAck; - request.commands[1].inOrOut = kDP_SetDefaultsAndDisable; - request.commands[2].command = kPS2C_SendCommandAndCompareAck; - request.commands[2].inOrOut = kDP_SetDefaultsAndDisable; - request.commands[3].command = kPS2C_SendCommandAndCompareAck; - request.commands[3].inOrOut = kDP_SetDefaultsAndDisable; - request.commands[4].command = kPS2C_SendCommandAndCompareAck; - request.commands[4].inOrOut = kDP_Enable; - request.commands[5].command = kPS2C_SendCommandAndCompareAck; - request.commands[5].inOrOut = 0xF0; //Set poll ??! - request.commandsCount = 6; - assert(request.commandsCount <= countof(request.commands)); - _device->submitRequestAndBlock(&request); +void ApplePS2ALPSGlidePoint::unregisterHIDPointerNotifications() { + // Free device matching notifiers + // remove() releases them + if (usb_hid_publish_notify) + usb_hid_publish_notify->remove(); + + if (usb_hid_terminate_notify) + usb_hid_terminate_notify->remove(); + + if (bluetooth_hid_publish_notify) + bluetooth_hid_publish_notify->remove(); + + if (bluetooth_hid_terminate_notify) + bluetooth_hid_terminate_notify->remove(); + + attachedHIDPointerDevices->flushCollection(); +} + +void ApplePS2ALPSGlidePoint::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")); + + 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 + { + if (deviceClassMinor2 == kBluetoothDeviceClassMinorPeripheral2Unclassified || // Mouse + 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()); + } + } + } + } + } + + 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 + ignoreall = false; + } + } +} + +bool ApplePS2ALPSGlidePoint::notificationHIDAttachedHandler(void * refCon, IOService * newService, IONotifier * notifier) { + if (_cmdGate) { // defensive + _cmdGate->runAction(OSMemberFunctionCast(IOCommandGate::Action, this, &ApplePS2ALPSGlidePoint::notificationHIDAttachedHandlerGated), newService, notifier); + } + + return true; } diff --git a/VoodooPS2Trackpad/VoodooPS2ALPSGlidePoint.h b/VoodooPS2Trackpad/VoodooPS2ALPSGlidePoint.h index 3897ceb0..891b96b8 100644 --- a/VoodooPS2Trackpad/VoodooPS2ALPSGlidePoint.h +++ b/VoodooPS2Trackpad/VoodooPS2ALPSGlidePoint.h @@ -2,13 +2,13 @@ * Copyright (c) 2002 Apple Computer, Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ - * + * * The contents of this file constitute Original Code as defined in and * are subject to the Apple Public Source License Version 1.2 (the * "License"). You may not use this file except in compliance with the * License. Please obtain a copy of the License at * http://www.apple.com/publicsource and read it before using this file. - * + * * This Original Code and all software distributed under the License are * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, @@ -16,104 +16,693 @@ * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the * License for the specific language governing rights and limitations * under the License. - * + * * @APPLE_LICENSE_HEADER_END@ */ -#ifndef _APPLEPS2SYNAPTICSTOUCHPAD_H -#define _APPLEPS2SYNAPTICSTOUCHPAD_H +#ifndef _APPLEPS2ALPSTOUCHPAD_H +#define _APPLEPS2ALPSTOUCHPAD_H -#include "../VoodooPS2Controller/ApplePS2MouseDevice.h" +#include "ApplePS2MouseDevice.h" +#include #include +#include +#include "VoodooInputMultitouch/VoodooInputEvent.h" +#include "VoodooPS2TrackpadCommon.h" + +#define ALPS_PROTO_V1 0x100 +#define ALPS_PROTO_V2 0x200 +#define ALPS_PROTO_V3 0x300 +#define ALPS_PROTO_V3_RUSHMORE 0x310 +#define ALPS_PROTO_V4 0x400 +#define ALPS_PROTO_V5 0x500 +#define ALPS_PROTO_V6 0x600 +#define ALPS_PROTO_V7 0x700 /* t3btl t4s */ +#define ALPS_PROTO_V8 0x800 /* SS4btl SS4s */ +#define ALPS_PROTO_V9 0x900 /* ss3btl */ + +#define MAX_TOUCHES 5 +#define DOLPHIN_COUNT_PER_ELECTRODE 64 +#define DOLPHIN_PROFILE_XOFFSET 8 /* x-electrode offset */ +#define DOLPHIN_PROFILE_YOFFSET 1 /* y-electrode offset */ + +// // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -// ApplePS2ALPSGlidePoint Class Declaration +// SimpleAverage Class Declaration // -typedef struct ALPSStatus +template +class SimpleAverage { - UInt8 byte0; - UInt8 byte1; - UInt8 byte2; -} ALPSStatus_t; +private: + T m_buffer[N]; + int m_count; + int m_sum; + int m_index; -#define SCROLL_NONE 0 -#define SCROLL_HORIZ 1 -#define SCROLL_VERT 2 +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; + } +}; -#define kPacketLengthSmall 3 -#define kPacketLengthLarge 6 -#define kPacketLengthMax 6 +// +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +// DecayingAverage Class Declaration +// -class EXPORT ApplePS2ALPSGlidePoint : public IOHIPointing +template +class DecayingAverage { - typedef IOHIPointing super; - OSDeclareDefaultStructors( ApplePS2ALPSGlidePoint ); +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: - ApplePS2MouseDevice * _device {nullptr}; - bool _interruptHandlerInstalled {false}; - bool _powerControlHandlerInstalled {false}; - RingBuffer _ringBuffer; - UInt32 _packetByteCount {0}; - IOFixed _resolution; - UInt16 _touchPadVersion; - UInt8 _touchPadModeByte; - - bool _dragging; - bool _edgehscroll; - bool _edgevscroll; - UInt32 _edgeaccell; - double _edgeaccellvalue; - bool _draglock; + 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 alps_hw_state { + int x; + int y; + int z; + int virtualFingerIndex; +}; + +struct virtual_finger_state { + SimpleAverage x_avg; + SimpleAverage y_avg; + uint8_t pressure; + bool touch; + bool button; + MT2FingerType fingerType; +}; + +/* + * enum SS4_PACKET_ID - defines the packet type for V8 + * SS4_PACKET_ID_IDLE: There's no finger and no button activity. + * SS4_PACKET_ID_ONE: There's one finger on touchpad + * or there's button activities. + * SS4_PACKET_ID_TWO: There's two or more fingers on touchpad + * SS4_PACKET_ID_MULTI: There's three or more fingers on touchpad + * SS4_PACKET_ID_STICK: A stick pointer packet + */ +enum SS4_PACKET_ID { + SS4_PACKET_ID_IDLE = 0, + SS4_PACKET_ID_ONE, + SS4_PACKET_ID_TWO, + SS4_PACKET_ID_MULTI, + SS4_PACKET_ID_STICK, +}; + +#define SS4_COUNT_PER_ELECTRODE 256 +#define SS4_NUMSENSOR_XOFFSET 7 +#define SS4_NUMSENSOR_YOFFSET 7 +#define SS4_MIN_PITCH_MM 50 + +#define SS4_MASK_NORMAL_BUTTONS 0x07 + +#define SS4PLUS_COUNT_PER_ELECTRODE 128 +#define SS4PLUS_NUMSENSOR_XOFFSET 16 +#define SS4PLUS_NUMSENSOR_YOFFSET 5 +#define SS4PLUS_MIN_PITCH_MM 37 + +#define IS_SS4PLUS_DEV(_b) (((_b[0]) == 0x73) && \ + ((_b[1]) == 0x03) && \ + ((_b[2]) == 0x28) \ + ) + +#define SS4_IS_IDLE_V2(_b) (((_b[0]) == 0x18) && \ + ((_b[1]) == 0x10) && \ + ((_b[2]) == 0x00) && \ + ((_b[3] & 0x88) == 0x08) && \ + ((_b[4]) == 0x10) && \ + ((_b[5]) == 0x00) \ + ) + +#define SS4_1F_X_V2(_b) (((_b[0]) & 0x0007) | \ + ((_b[1] << 3) & 0x0078) | \ + ((_b[1] << 2) & 0x0380) | \ + ((_b[2] << 5) & 0x1C00) \ + ) + +#define SS4_1F_Y_V2(_b) (((_b[2]) & 0x000F) | \ + ((_b[3] >> 2) & 0x0030) | \ + ((_b[4] << 6) & 0x03C0) | \ + ((_b[4] << 5) & 0x0C00) \ + ) + +#define SS4_1F_Z_V2(_b) (((_b[5]) & 0x0F) | \ + ((_b[5] >> 1) & 0x70) | \ + ((_b[4]) & 0x80) \ + ) + +#define SS4_1F_LFB_V2(_b) (((_b[2] >> 4) & 0x01) == 0x01) + +#define SS4_MF_LF_V2(_b, _i) ((_b[1 + (_i) * 3] & 0x0004) == 0x0004) + +#define SS4_BTN_V2(_b) ((_b[0] >> 5) & SS4_MASK_NORMAL_BUTTONS) + +#define SS4_STD_MF_X_V2(_b, _i) (((_b[0 + (_i) * 3] << 5) & 0x00E0) | \ + ((_b[1 + _i * 3] << 5) & 0x1F00) \ + ) + +#define SS4_PLUS_STD_MF_X_V2(_b, _i) (((_b[0 + (_i) * 3] << 4) & 0x0070) | \ + ((_b[1 + (_i) * 3] << 4) & 0x0F80) \ + ) + +#define SS4_STD_MF_Y_V2(_b, _i) (((_b[1 + (_i) * 3] << 3) & 0x0010) | \ + ((_b[2 + (_i) * 3] << 5) & 0x01E0) | \ + ((_b[2 + (_i) * 3] << 4) & 0x0E00) \ + ) + +#define SS4_BTL_MF_X_V2(_b, _i) (SS4_STD_MF_X_V2(_b, _i) | \ + ((_b[0 + (_i) * 3] >> 3) & 0x0010) \ + ) + +#define SS4_PLUS_BTL_MF_X_V2(_b, _i) (SS4_PLUS_STD_MF_X_V2(_b, _i) | \ + ((_b[0 + (_i) * 3] >> 4) & 0x0008) \ + ) + +#define SS4_BTL_MF_Y_V2(_b, _i) (SS4_STD_MF_Y_V2(_b, _i) | \ + ((_b[0 + (_i) * 3] >> 3) & 0x0008) \ + ) + +#define SS4_MF_Z_V2(_b, _i) (((_b[1 + (_i) * 3]) & 0x0001) | \ + ((_b[1 + (_i) * 3] >> 1) & 0x0002) \ + ) + +#define SS4_IS_MF_CONTINUE(_b) ((_b[2] & 0x10) == 0x10) +#define SS4_IS_5F_DETECTED(_b) ((_b[2] & 0x10) == 0x10) + +#define SS4_MFPACKET_NO_AX 8160 /* X-Coordinate value */ +#define SS4_MFPACKET_NO_AY 4080 /* Y-Coordinate value */ +#define SS4_MFPACKET_NO_AX_BL 8176 /* Buttonless X-Coord value */ +#define SS4_MFPACKET_NO_AY_BL 4088 /* Buttonless Y-Coord value */ +#define SS4_PLUS_MFPACKET_NO_AX 4080 /* SS4 PLUS, X */ +#define SS4_PLUS_MFPACKET_NO_AX_BL 4088 /* Buttonless SS4 PLUS, X */ + +/* + * enum V7_PACKET_ID - defines the packet type for V7 + * V7_PACKET_ID_IDLE: There's no finger and no button activity. + * V7_PACKET_ID_TWO: There's one or two non-resting fingers on touchpad + * or there's button activities. + * V7_PACKET_ID_MULTI: There are at least three non-resting fingers. + * V7_PACKET_ID_NEW: The finger position in slot is not continues from + * previous packet. + */ +enum V7_PACKET_ID { + V7_PACKET_ID_IDLE, + V7_PACKET_ID_TWO, + V7_PACKET_ID_MULTI, + V7_PACKET_ID_NEW, + V7_PACKET_ID_UNKNOWN, +}; + +/** + * struct alps_protocol_info - information about protocol used by a device + * @version: Indicates V1/V2/V3/... + * @byte0: Helps figure out whether a position report packet matches the + * known format for this model. The first byte of the report, ANDed with + * mask0, should match byte0. + * @mask0: The mask used to check the first byte of the report. + * @flags: Additional device capabilities (passthrough port, trackstick, etc.). + */ +struct alps_protocol_info { + UInt16 version; + UInt8 byte0, mask0; + unsigned int flags; +}; + +/** + * struct alps_model_info - touchpad ID table + * @signature: E7 response string to match. + * @protocol_info: information about protocol used by the device. + * + * Many (but not all) ALPS touchpads can be identified by looking at the + * values returned in the "E7 report" and/or the "EC report." This table + * lists a number of such touchpads. + */ +struct alps_model_info { + UInt8 signature[3]; + struct alps_protocol_info protocol_info; +}; + +/** + * struct alps_nibble_commands - encodings for register accesses + * @command: PS/2 command used for the nibble + * @data: Data supplied as an argument to the PS/2 command, if applicable + * + * The ALPS protocol uses magic sequences to transmit binary data to the + * touchpad, as it is generally not OK to send arbitrary bytes out the + * PS/2 port. Each of the sequences in this table sends one nibble of the + * register address or (write) data. Different versions of the ALPS protocol + * use slightly different encodings. + */ +struct alps_nibble_commands { + SInt32 command; + UInt8 data; +}; + +struct alps_bitmap_point { + int start_bit; + int num_bits; +}; + +struct input_mt_pos { + UInt32 x; + UInt32 y; +}; + +/** + * struct alps_fields - decoded version of the report packet + * @x_map: Bitmap of active X positions for MT. + * @y_map: Bitmap of active Y positions for MT. + * @fingers: Number of fingers for MT. + * @pressure: Pressure. + * @st: position for ST. + * @mt: position for MT. + * @first_mp: Packet is the first of a multi-packet report. + * @is_mp: Packet is part of a multi-packet report. + * @left: Left touchpad button is active. + * @right: Right touchpad button is active. + * @middle: Middle touchpad button is active. + * @ts_left: Left trackstick button is active. + * @ts_right: Right trackstick button is active. + * @ts_middle: Middle trackstick button is active. + */ +struct alps_fields { + unsigned int x_map; + unsigned int y_map; + unsigned int fingers; + + int pressure; + struct input_mt_pos st; + struct input_mt_pos mt[MAX_TOUCHES]; + + unsigned int first_mp:1; + unsigned int is_mp:1; + + unsigned int left:1; + unsigned int right:1; + unsigned int middle:1; + + unsigned int ts_left:1; + unsigned int ts_right:1; + unsigned int ts_middle:1; +}; + +class ApplePS2ALPSGlidePoint; + +/** + * struct alps_data - private data structure for the ALPS driver + * @nibble_commands: Command mapping used for touchpad register accesses. + * @addr_command: Command used to tell the touchpad that a register address + * follows. + * @proto_version: Indicates V1/V2/V3/... + * @byte0: Helps figure out whether a position report packet matches the + * known format for this model. The first byte of the report, ANDed with + * mask0, should match byte0. + * @mask0: The mask used to check the first byte of the report. + * @fw_ver: cached copy of firmware version (EC report) + * @flags: Additional device capabilities (passthrough port, trackstick, etc.). + * @x_max: Largest possible X position value. + * @y_max: Largest possible Y position value. + * @x_bits: Number of X bits in the MT bitmap. + * @y_bits: Number of Y bits in the MT bitmap. + * @prev_fin: Finger bit from previous packet. + * @multi_packet: Multi-packet data in progress. + * @multi_data: Saved multi-packet data. + * @f: Decoded packet data fields. + * @quirks: Bitmap of ALPS_QUIRK_*. + */ +struct alps_data { + /* these are autodetected when the device is identified */ + const struct alps_nibble_commands *nibble_commands; + SInt32 addr_command; + UInt16 proto_version; + UInt8 byte0, mask0; + UInt8 dev_id[3]; + UInt8 fw_ver[3]; + int flags; + SInt32 x_max; + SInt32 y_max; + SInt32 x_bits; + SInt32 y_bits; + unsigned int x_res; + unsigned int y_res; + + SInt32 prev_fin; + SInt32 multi_packet; + int second_touch; + UInt8 multi_data[6]; + struct alps_fields f; + UInt8 quirks; + bool PSMOUSE_BAD_DATA; + + int pktsize = 6; +}; + +// Pulled out of alps_data, now saved as vars on class +// makes invoking a little easier +typedef bool (ApplePS2ALPSGlidePoint::*hw_init)(); +typedef bool (ApplePS2ALPSGlidePoint::*decode_fields)(struct alps_fields *f, UInt8 *p); +typedef void (ApplePS2ALPSGlidePoint::*process_packet)(UInt8 *packet); +//typedef void (ALPS::*set_abs_params)(); + +#define ALPS_QUIRK_TRACKSTICK_BUTTONS 1 /* trakcstick buttons in trackstick packet */ + +// +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +// ApplePS2ALPSGlidePoint Class Declaration +// + +typedef struct ALPSStatus { + UInt8 bytes[3]; +} ALPSStatus_t; + +#define XMIN 0 +#define XMAX 6143 +#define YMIN 0 +#define YMAX 6143 +#define XMIN_NOMINAL 1472 +#define XMAX_NOMINAL 5472 +#define YMIN_NOMINAL 1408 +#define YMAX_NOMINAL 4448 + +#define ABS_POS_BITS 13 +#define X_MAX_POSITIVE 8176 +#define Y_MAX_POSITIVE 8176 + +#define kPacketLength 6 +#define kDP_CommandNibble10 0xf2 + +// predeclure stuff +struct alps_data; + +class EXPORT ApplePS2ALPSGlidePoint : public IOHIPointing { + typedef IOHIPointing super; + OSDeclareDefaultStructors( ApplePS2ALPSGlidePoint ); private: - SInt32 _xpos, _xscrollpos; - SInt32 _ypos, _yscrollpos; - SInt32 _zpos, _zscrollpos; - short _scrolling; - + IOService *voodooInputInstance {nullptr}; + ApplePS2MouseDevice * _device {nullptr}; + bool _interruptHandlerInstalled {false}; + bool _powerControlHandlerInstalled {false}; + RingBuffer _ringBuffer {}; + UInt32 _packetByteCount {0}; + + IOCommandGate* _cmdGate {nullptr}; + + VoodooInputEvent inputEvent {}; + + // buttons and scroll wheel + unsigned int left:1; + unsigned int right:1; + unsigned int middle:1; + + unsigned int left_ts:1; + + // VoodooInput + int margin_size_x {0}; + + uint32_t logical_max_x {0}; + uint32_t logical_max_y {0}; + + uint32_t physical_max_x {0}; + uint32_t physical_max_y {0}; + + alps_hw_state fingerStates[MAX_TOUCHES] {}; + virtual_finger_state virtualFingerStates[MAX_TOUCHES] {}; + bool freeFingerTypes[kMT2FingerTypeCount]; + + static_assert(MAX_TOUCHES <= kMT2FingerTypeLittleFinger, "Too many fingers for one hand"); + + int clampedFingerCount {0}; + bool wasSkipped {false}; + + int minXOverride {-1}, minYOverride {-1}, maxXOverride {-1}, maxYOverride {-1}; + + int lastFingerCount; + int lastSentFingerCount; + bool hadLiftFinger; + + ForceTouchMode _forceTouchMode {FORCE_TOUCH_DISABLED}; + int _forceTouchPressureThreshold {100}; + + int _forceTouchCustomDownThreshold {90}; + int _forceTouchCustomUpThreshold {20}; + int _forceTouchCustomPower {8}; + + // normal state + UInt32 lastbuttons {0}; + UInt32 lastTrackStickButtons, lastTouchpadButtons; + uint64_t keytime {0}; + bool ignoreall {false}; + int z_finger {45}; + uint64_t maxaftertyping {500000000}; + int wakedelay {1000}; + int _resolution {2300}; + int _scrollresolution {2300}; + int _buttonCount {2}; + + // HID Notification + 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 + + int _modifierdown {0}; // state of left+right control keys + + // for scaling x/y values + int xupmm {50}, yupmm {50}; // 50 is just arbitrary, but same + + alps_data priv; + hw_init hw_init; + decode_fields decode_fields; + process_packet process_packet; + // set_abs_params set_abs_params; + + void injectVersionDependentProperties(OSDictionary* dict); + bool resetMouse(); + bool handleOpen(IOService *forClient, IOOptionBits options, void *arg) override; + void handleClose(IOService *forClient, IOOptionBits options) override; + PS2InterruptResult interruptOccurred(UInt8 data); + void packetReady(); + virtual bool deviceSpecificInit(); + + void alps_process_packet_v1_v2(UInt8 *packet); + int alps_process_bitmap(struct alps_data *priv, struct alps_fields *f); + void alps_process_trackstick_packet_v3(UInt8 * packet); + bool alps_decode_buttons_v3(struct alps_fields *f, UInt8 *p); + bool alps_decode_pinnacle(struct alps_fields *f, UInt8 *p); + bool alps_decode_rushmore(struct alps_fields *f, UInt8 *p); + bool alps_decode_dolphin(struct alps_fields *f, UInt8 *p); + void alps_process_touchpad_packet_v3_v5(UInt8 * packet); + void alps_process_packet_v3(UInt8 *packet); + void alps_process_packet_v6(UInt8 *packet); + void alps_process_packet_v4(UInt8 *packet); + unsigned char alps_get_packet_id_v7(UInt8 *byte); + void alps_get_finger_coordinate_v7(struct input_mt_pos *mt, UInt8 *pkt, UInt8 pkt_id); + int alps_get_mt_count(struct input_mt_pos *mt); + bool alps_decode_packet_v7(struct alps_fields *f, UInt8 *p); + void alps_process_trackstick_packet_v7(UInt8 *packet); + void alps_process_touchpad_packet_v7(UInt8 *packet); + void alps_process_packet_v7(UInt8 *packet); + unsigned char alps_get_pkt_id_ss4_v2(UInt8 *byte); + bool alps_decode_ss4_v2(struct alps_fields *f, UInt8 *p); + void alps_process_packet_ss4_v2(UInt8 *packet); + bool alps_command_mode_send_nibble(int value); + bool alps_command_mode_set_addr(int addr); + int alps_command_mode_read_reg(int addr); + bool alps_command_mode_write_reg(int addr, UInt8 value); + bool alps_command_mode_write_reg(UInt8 value); + bool alps_rpt_cmd(SInt32 init_command, SInt32 init_arg, SInt32 repeated_command, ALPSStatus_t *report); + bool alps_enter_command_mode(); + bool alps_exit_command_mode(); + bool alps_passthrough_mode_v2(bool enable); + bool alps_absolute_mode_v1_v2(); + int alps_monitor_mode_send_word(int word); + int alps_monitor_mode_write_reg(int addr, int value); + int alps_monitor_mode(bool enable); + void alps_absolute_mode_v6(); + bool alps_get_status(ALPSStatus_t *status); + bool alps_tap_mode(bool enable); + bool alps_hw_init_v1_v2(); + bool alps_hw_init_v6(); + bool alps_passthrough_mode_v3(int regBase, bool enable); + bool alps_absolute_mode_v3(); + IOReturn alps_probe_trackstick_v3_v7(int regBase); + IOReturn alps_setup_trackstick_v3(int regBase); + bool alps_hw_init_v3(); + bool alps_get_v3_v7_resolution(int reg_pitch); + bool alps_hw_init_rushmore_v3(); + bool alps_absolute_mode_v4(); + bool alps_hw_init_v4(); + void alps_get_otp_values_ss4_v2(unsigned char index, unsigned char otp[]); + void alps_update_device_area_ss4_v2(unsigned char otp[][4], struct alps_data *priv); + void alps_update_btn_info_ss4_v2(unsigned char otp[][4], struct alps_data *priv); + void alps_update_dual_info_ss4_v2(unsigned char otp[][4], struct alps_data *priv); + void alps_set_defaults_ss4_v2(struct alps_data *priv); + int alps_dolphin_get_device_area(struct alps_data *priv); + bool alps_hw_init_dolphin_v1(); + bool alps_hw_init_v7(); + bool alps_hw_init_ss4_v2(); + void set_protocol(); + bool matchTable(ALPSStatus_t *e7, ALPSStatus_t *ec); + IOReturn identify(); + void setTouchPadEnable(bool enable); + void ps2_command(unsigned char value, UInt8 command); + void ps2_command_short(UInt8 command); + int abs(int x); + void set_resolution(); + void alps_buttons(struct alps_fields &f); + + int dist(int physicalFinger, int virtualFinger); + void assignVirtualFinger(int physicalFinger); + void assignFingerType(virtual_finger_state &vf); + void freeAndMarkVirtualFingers(); + int upperFingerIndex() const; + const alps_hw_state& upperFinger() const; + void swapFingers(int dst, int src); + /// Translates physical fingers into virtual fingers so that host software doesn't see 'jumps' and has coordinates for all fingers. + /// @return True if is ready to send finger state to host interface + bool renumberFingers(); + void sendTouchData(); + + virtual void initTouchPad(); + virtual void setParamPropertiesGated(OSDictionary* dict); + virtual void setDevicePowerState(UInt32 whatToDo); + + void registerHIDPointerNotifications(); + void unregisterHIDPointerNotifications(); + + void notificationHIDAttachedHandlerGated(IOService * newService, IONotifier * notifier); + bool notificationHIDAttachedHandler(void * refCon, IOService * newService, IONotifier * notifier); + protected: - virtual void dispatchRelativePointerEventWithPacket( UInt8 * packet, - UInt32 packetSize ); - virtual void dispatchAbsolutePointerEventWithPacket(UInt8 *packet,UInt32 packetSize); - virtual void getModel(ALPSStatus_t *e6,ALPSStatus_t *e7); - virtual void setAbsoluteMode(); - virtual void getStatus(ALPSStatus_t *status); - virtual int insideScrollArea(int x,int y); - - virtual void setTapEnable( bool enable ); - virtual void setTouchPadEnable( bool enable ); -#if _NO_TOUCHPAD_ENABLE_ - virtual UInt32 getTouchPadData( UInt8 dataSelector ); - virtual bool setTouchPadModeByte( UInt8 modeByteValue, - bool enableStreamMode = false ); -#endif - virtual PS2InterruptResult interruptOccurred(UInt8 data); - virtual void packetReady(); - virtual void setDevicePowerState(UInt32 whatToDo); - + IOItemCount buttonCount() override; + IOFixed resolution() override; inline void dispatchRelativePointerEventX(int dx, int dy, UInt32 buttonState, uint64_t now) - { dispatchRelativePointerEvent(dx, dy, buttonState, *(AbsoluteTime*)&now); } + { dispatchRelativePointerEvent(dx, dy, buttonState, *(AbsoluteTime*)&now); } inline void dispatchScrollWheelEventX(short deltaAxis1, short deltaAxis2, short deltaAxis3, uint64_t now) - { dispatchScrollWheelEvent(deltaAxis1, deltaAxis2, deltaAxis3, *(AbsoluteTime*)&now); } - -protected: - IOItemCount buttonCount() override; - IOFixed resolution() override; + { dispatchScrollWheelEvent(deltaAxis1, deltaAxis2, deltaAxis3, *(AbsoluteTime*)&now); } public: - bool init( OSDictionary * properties ) override; - ApplePS2ALPSGlidePoint * probe( IOService * provider, - SInt32 * score ) override; - - bool start( IOService * provider ) override; - void stop( IOService * provider ) override; - + bool init(OSDictionary * dict) override; + ApplePS2ALPSGlidePoint * 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 setParamProperties(OSDictionary * dict) override; + IOReturn setProperties(OSObject *props) override; + + IOReturn message(UInt32 type, IOService* provider, void* argument) override; }; -#endif /* _APPLEPS2SYNAPTICSTOUCHPAD_H */ +#endif /* _APPLEPS2ALPSTOUCHPAD_H */ diff --git a/VoodooPS2Trackpad/VoodooPS2Trackpad-Info.plist b/VoodooPS2Trackpad/VoodooPS2Trackpad-Info.plist index 93906e63..1248f964 100644 --- a/VoodooPS2Trackpad/VoodooPS2Trackpad-Info.plist +++ b/VoodooPS2Trackpad/VoodooPS2Trackpad-Info.plist @@ -29,15 +29,68 @@ IOClass ApplePS2ALPSGlidePoint IOProbeScore - 1500 + 6000 IOProviderClass ApplePS2MouseDevice Platform Profile Default + Darwin 16+ + + ApplePreferenceCapability + + ApplePreferenceIdentifier + com.apple.AppleMultitouchTrackpad + MT Built-in + + MTHIDDevice + + SupportsGestureScrolling + + TrackpadEmbedded + + TrackpadFourFingerGestures + + TrackpadSecondaryClickCorners + + TrackpadThreeFingerDrag + + DisableDevice + DragLockTempMask + 1048592 + FingerZ + 1 + ForceTouchCustomDownThreshold + 90 + ForceTouchCustomPower + 8 + ForceTouchCustomUpThreshold + 20 + ForceTouchMode + 0 + ForceTouchPressureThreshold + 100 + ProcessBluetoothMouseStopsTrackpad + + ProcessUSBMouseStopsTrackpad + + QuietTimeAfterTyping + 500000000 + Resolution + 400 + ScrollResolution + 400 + USBMouseStopsTrackpad + 0 + UnitsPerMMX + 50 + UnitsPerMMY + 50 + WakeDelay + 1000 HPQOEM @@ -84,6 +137,12 @@ ProBook + ProductID + 547 + RM,deliverNotifications + + VendorID + 1452 Elantech TouchPad From 8954e297622f1df03376c9f9778de5095abc82f2 Mon Sep 17 00:00:00 2001 From: Vitaly Cheptsov <4348897+vit9696@users.noreply.github.com> Date: Mon, 21 Feb 2022 19:56:21 +0300 Subject: [PATCH 060/101] Sync changelog --- Changelog.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Changelog.md b/Changelog.md index b8ebb28f..21c02d7a 100644 --- a/Changelog.md +++ b/Changelog.md @@ -1,5 +1,8 @@ VoodooPS2 Changelog ============================ +#### v2.2.8 +- Added ALPS touchpad support + #### v2.2.7 - Fixed kernel panic after S3 From f5e40698ec87d39c9c6f24ea76fe6932cec2659b Mon Sep 17 00:00:00 2001 From: SkyrilHD Date: Mon, 21 Feb 2022 18:34:29 +0100 Subject: [PATCH 061/101] Small fixes for ALPS (#46) --- VoodooPS2Trackpad/VoodooPS2ALPSGlidePoint.cpp | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/VoodooPS2Trackpad/VoodooPS2ALPSGlidePoint.cpp b/VoodooPS2Trackpad/VoodooPS2ALPSGlidePoint.cpp index b9817e1f..7a778c4f 100644 --- a/VoodooPS2Trackpad/VoodooPS2ALPSGlidePoint.cpp +++ b/VoodooPS2Trackpad/VoodooPS2ALPSGlidePoint.cpp @@ -1856,7 +1856,9 @@ void ApplePS2ALPSGlidePoint::alps_process_packet_ss4_v2(UInt8 *packet) { x = (SInt8) (((packet[0] & 1) << 7) | (packet[1] & 0x7f)); y = (SInt8) (((packet[3] & 1) << 7) | (packet[2] & 0x7f)); +#if DEBUG pressure = (packet[4] & 0x7f); +#endif buttons |= f.ts_left ? 0x01 : 0; buttons |= f.ts_right ? 0x02 : 0; @@ -3043,8 +3045,13 @@ void ApplePS2ALPSGlidePoint::set_protocol() { decode_fields = &ApplePS2ALPSGlidePoint::alps_decode_rushmore; priv.nibble_commands = alps_v3_nibble_commands; priv.addr_command = kDP_MouseResetWrap; - priv.x_bits = 16; - priv.y_bits = 12; + // This causes jumps in scrolling + //priv.x_bits = 16; + //priv.y_bits = 12; + + // Pinnacle dimensions + priv.x_max = 2047; + priv.y_max = 1535; if (alps_probe_trackstick_v3_v7(ALPS_REG_BASE_RUSHMORE)) { priv.flags &= ~ALPS_DUALPOINT; From d9159266a158fbbc29e4b850a908e1c07754a382 Mon Sep 17 00:00:00 2001 From: antoniomcr96 <63928525+antoniomcr96@users.noreply.github.com> Date: Mon, 7 Mar 2022 14:38:15 +0100 Subject: [PATCH 062/101] VoodooPS2Elan - Fixed trackpoint scrolling in the wrong direction (#47) As reported in this issue: https://github.com/acidanthera/bugtracker/issues/1226 trackpoint (when clicking the middle button) scrolls, but in the wrong direction. Inverting arguments provided to "dispatchScrollWheelEvent" function fixes the issue --- VoodooPS2Trackpad/VoodooPS2Elan.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VoodooPS2Trackpad/VoodooPS2Elan.cpp b/VoodooPS2Trackpad/VoodooPS2Elan.cpp index fa98e20a..09d4e842 100644 --- a/VoodooPS2Trackpad/VoodooPS2Elan.cpp +++ b/VoodooPS2Trackpad/VoodooPS2Elan.cpp @@ -1884,7 +1884,7 @@ void ApplePS2Elan::elantechReportTrackpoint() { keytime = timestamp_ns; if (trackpointScrolling) { - dispatchScrollWheelEvent(dx, dy, 0, timestamp); + dispatchScrollWheelEvent(dy, dx, 0, timestamp); } else { dispatchRelativePointerEvent(dx, dy, trackpointRightButton | trackpointLeftButton | trackpointMiddleButton, timestamp); } From 6b4a2dbe0c8e9fc0100bb08cb396f9127dd242d0 Mon Sep 17 00:00:00 2001 From: Vitaly Cheptsov <4348897+vit9696@users.noreply.github.com> Date: Mon, 7 Mar 2022 16:39:05 +0300 Subject: [PATCH 063/101] Sync changelog --- Changelog.md | 1 + 1 file changed, 1 insertion(+) diff --git a/Changelog.md b/Changelog.md index 21c02d7a..12e16b89 100644 --- a/Changelog.md +++ b/Changelog.md @@ -2,6 +2,7 @@ VoodooPS2 Changelog ============================ #### v2.2.8 - Added ALPS touchpad support +- Fixed ELAN trackpoint scrolling in the wrong direction #### v2.2.7 - Fixed kernel panic after S3 From 6e2666a56f81522d8772e5f5238ec7f7b47f5924 Mon Sep 17 00:00:00 2001 From: Andrey1970AppleLife Date: Tue, 8 Mar 2022 23:26:29 +0300 Subject: [PATCH 064/101] 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 5f5eb5a0..5c50f9a3 100644 --- a/VoodooPS2Controller.xcodeproj/project.pbxproj +++ b/VoodooPS2Controller.xcodeproj/project.pbxproj @@ -767,7 +767,7 @@ KERNEL_FRAMEWORK_HEADERS = "$(PROJECT_DIR)/MacKernelSDK/Headers"; "LLVM_LTO[arch=x86_64]" = YES; MACOSX_DEPLOYMENT_TARGET = 10.11; - MODULE_VERSION = 2.2.8; + MODULE_VERSION = 2.2.9; ONLY_ACTIVE_ARCH = YES; "OTHER_LDFLAGS[arch=x86_64]" = "-dead_strip"; PRODUCT_NAME = VoodooPS2Controller; @@ -822,7 +822,7 @@ KERNEL_FRAMEWORK_HEADERS = "$(PROJECT_DIR)/MacKernelSDK/Headers"; "LLVM_LTO[arch=x86_64]" = YES; MACOSX_DEPLOYMENT_TARGET = 10.11; - MODULE_VERSION = 2.2.8; + MODULE_VERSION = 2.2.9; "OTHER_LDFLAGS[arch=x86_64]" = "-dead_strip"; PRODUCT_NAME = VoodooPS2Controller; SDKROOT = macosx; From 9300207d2ff35a2fa93a6e21fe198923d9b94977 Mon Sep 17 00:00:00 2001 From: PMheart <17109513+PMheart@users.noreply.github.com> Date: Mon, 25 Apr 2022 12:24:34 +0200 Subject: [PATCH 065/101] Update to GitHub Actions v3 --- .github/workflows/main.yml | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 30238f79..960ef254 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -17,8 +17,8 @@ jobs: env: JOB_TYPE: BUILD steps: - - uses: actions/checkout@v2 - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 + - uses: actions/checkout@v3 with: repository: acidanthera/MacKernelSDK path: MacKernelSDK @@ -33,7 +33,7 @@ jobs: - run: xcodebuild -jobs 1 -configuration Release - name: Upload to Artifacts - uses: actions/upload-artifact@v2 + uses: actions/upload-artifact@v3 with: name: Artifacts path: build/*/*/*.zip @@ -52,8 +52,8 @@ jobs: env: JOB_TYPE: ANALYZE steps: - - uses: actions/checkout@v2 - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 + - uses: actions/checkout@v3 with: repository: acidanthera/MacKernelSDK path: MacKernelSDK @@ -74,8 +74,8 @@ jobs: JOB_TYPE: COVERITY if: github.repository_owner == 'acidanthera' && github.event_name != 'pull_request' steps: - - uses: actions/checkout@v2 - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 + - uses: actions/checkout@v3 with: repository: acidanthera/MacKernelSDK path: MacKernelSDK From 2e3bf7c4271a507cdabae556877e670720e46d95 Mon Sep 17 00:00:00 2001 From: PMheart <17109513+PMheart@users.noreply.github.com> Date: Mon, 25 Apr 2022 14:18:11 +0200 Subject: [PATCH 066/101] Fix bitmask calculation --- VoodooPS2Keyboard/VoodooPS2Keyboard.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/VoodooPS2Keyboard/VoodooPS2Keyboard.h b/VoodooPS2Keyboard/VoodooPS2Keyboard.h index 4e8e6142..797120f9 100644 --- a/VoodooPS2Keyboard/VoodooPS2Keyboard.h +++ b/VoodooPS2Keyboard/VoodooPS2Keyboard.h @@ -45,13 +45,13 @@ (KBV_BITS_PER_UNIT-1))/KBV_BITS_PER_UNIT) #define KBV_KEYDOWN(n) \ - (_keyBitVector)[((n)>>KBV_BITS_SHIFT)] |= (1 << ((n) & KBV_BITS_MASK)) + (_keyBitVector)[((n)>>KBV_BITS_SHIFT)] |= (1U << ((n) & KBV_BITS_MASK)) #define KBV_KEYUP(n) \ - (_keyBitVector)[((n)>>KBV_BITS_SHIFT)] &= ~(1 << ((n) & KBV_BITS_MASK)) + (_keyBitVector)[((n)>>KBV_BITS_SHIFT)] &= ~(1U << ((n) & KBV_BITS_MASK)) #define KBV_IS_KEYDOWN(n) \ - (((_keyBitVector)[((n)>>KBV_BITS_SHIFT)] & (1 << ((n) & KBV_BITS_MASK))) != 0) + (((_keyBitVector)[((n)>>KBV_BITS_SHIFT)] & (1U << ((n) & KBV_BITS_MASK))) != 0) #define KBV_NUM_SCANCODES 256 From b541fe37a5832880efaaa1398938cfa572feced8 Mon Sep 17 00:00:00 2001 From: PMheart <17109513+PMheart@users.noreply.github.com> Date: Tue, 24 May 2022 00:26:33 +0200 Subject: [PATCH 067/101] Fix build (#49) --- VoodooPS2Trackpad/VoodooPS2ALPSGlidePoint.cpp | 6 +++--- VoodooPS2Trackpad/VoodooPS2ALPSGlidePoint.h | 6 +++--- VoodooPS2Trackpad/VoodooPS2Elan.h | 4 ++-- VoodooPS2Trackpad/VoodooPS2SynapticsTouchPad.cpp | 6 +++--- VoodooPS2Trackpad/VoodooPS2SynapticsTouchPad.h | 6 +++--- 5 files changed, 14 insertions(+), 14 deletions(-) diff --git a/VoodooPS2Trackpad/VoodooPS2ALPSGlidePoint.cpp b/VoodooPS2Trackpad/VoodooPS2ALPSGlidePoint.cpp index 7a778c4f..c0a8e951 100644 --- a/VoodooPS2Trackpad/VoodooPS2ALPSGlidePoint.cpp +++ b/VoodooPS2Trackpad/VoodooPS2ALPSGlidePoint.cpp @@ -3406,7 +3406,7 @@ void ApplePS2ALPSGlidePoint::assignVirtualFinger(int physicalFinger) { return; } for (int j = 0; j < MAX_TOUCHES; j++) { - virtual_finger_state &vfj = virtualFingerStates[j]; + synaptics_virtual_finger_state &vfj = virtualFingerStates[j]; if (!vfj.touch) { fingerStates[physicalFinger].virtualFingerIndex = j; vfj.touch = true; @@ -3418,7 +3418,7 @@ void ApplePS2ALPSGlidePoint::assignVirtualFinger(int physicalFinger) { } } -void ApplePS2ALPSGlidePoint::assignFingerType(virtual_finger_state &vf) { +void ApplePS2ALPSGlidePoint::assignFingerType(synaptics_virtual_finger_state &vf) { vf.fingerType = kMT2FingerTypeUndefined; for (MT2FingerType i = kMT2FingerTypeIndexFinger; i < kMT2FingerTypeCount; i = (MT2FingerType)(i + 1)) if (freeFingerTypes[i]) { @@ -3780,7 +3780,7 @@ bool ApplePS2ALPSGlidePoint::renumberFingers() { IOLog("alps_parse_hw_state: ERROR: invalid physical finger %d\n", fi.virtualFingerIndex); continue; } - virtual_finger_state &fiv = virtualFingerStates[fi.virtualFingerIndex]; + synaptics_virtual_finger_state &fiv = virtualFingerStates[fi.virtualFingerIndex]; fiv.x_avg.filter(fi.x); fiv.y_avg.filter(fi.y); fiv.pressure = fi.z; diff --git a/VoodooPS2Trackpad/VoodooPS2ALPSGlidePoint.h b/VoodooPS2Trackpad/VoodooPS2ALPSGlidePoint.h index 891b96b8..bda48106 100644 --- a/VoodooPS2Trackpad/VoodooPS2ALPSGlidePoint.h +++ b/VoodooPS2Trackpad/VoodooPS2ALPSGlidePoint.h @@ -182,7 +182,7 @@ struct alps_hw_state { int virtualFingerIndex; }; -struct virtual_finger_state { +struct synaptics_virtual_finger_state { SimpleAverage x_avg; SimpleAverage y_avg; uint8_t pressure; @@ -526,7 +526,7 @@ class EXPORT ApplePS2ALPSGlidePoint : public IOHIPointing { uint32_t physical_max_y {0}; alps_hw_state fingerStates[MAX_TOUCHES] {}; - virtual_finger_state virtualFingerStates[MAX_TOUCHES] {}; + synaptics_virtual_finger_state virtualFingerStates[MAX_TOUCHES] {}; bool freeFingerTypes[kMT2FingerTypeCount]; static_assert(MAX_TOUCHES <= kMT2FingerTypeLittleFinger, "Too many fingers for one hand"); @@ -661,7 +661,7 @@ class EXPORT ApplePS2ALPSGlidePoint : public IOHIPointing { int dist(int physicalFinger, int virtualFinger); void assignVirtualFinger(int physicalFinger); - void assignFingerType(virtual_finger_state &vf); + void assignFingerType(synaptics_virtual_finger_state &vf); void freeAndMarkVirtualFingers(); int upperFingerIndex() const; const alps_hw_state& upperFinger() const; diff --git a/VoodooPS2Trackpad/VoodooPS2Elan.h b/VoodooPS2Trackpad/VoodooPS2Elan.h index 332cea0f..07dd6143 100644 --- a/VoodooPS2Trackpad/VoodooPS2Elan.h +++ b/VoodooPS2Trackpad/VoodooPS2Elan.h @@ -19,7 +19,7 @@ #include "VoodooInputMultitouch/VoodooInputEvent.h" #include "VoodooPS2TrackpadCommon.h" -struct virtual_finger_state { +struct elan_virtual_finger_state { TouchCoordinates prev; TouchCoordinates now; uint8_t pressure; @@ -240,7 +240,7 @@ class EXPORT ApplePS2Elan : public IOHIPointing { int heldFingers = 0; int headPacketsCount = 0; - virtual_finger_state virtualFinger[ETP_MAX_FINGERS] {}; + elan_virtual_finger_state virtualFinger[ETP_MAX_FINGERS] {}; static_assert(ETP_MAX_FINGERS <= kMT2FingerTypeLittleFinger, "Too many fingers for one hand"); diff --git a/VoodooPS2Trackpad/VoodooPS2SynapticsTouchPad.cpp b/VoodooPS2Trackpad/VoodooPS2SynapticsTouchPad.cpp index 0abb0a6f..c6fce205 100644 --- a/VoodooPS2Trackpad/VoodooPS2SynapticsTouchPad.cpp +++ b/VoodooPS2Trackpad/VoodooPS2SynapticsTouchPad.cpp @@ -807,7 +807,7 @@ void ApplePS2SynapticsTouchPad::assignVirtualFinger(int physicalFinger) { return; } for (int j = 0; j < SYNAPTICS_MAX_FINGERS; j++) { - virtual_finger_state &vfj = virtualFingerStates[j]; + synaptics_virtual_finger_state &vfj = virtualFingerStates[j]; if (!vfj.touch) { fingerStates[physicalFinger].virtualFingerIndex = j; vfj.touch = true; @@ -819,7 +819,7 @@ void ApplePS2SynapticsTouchPad::assignVirtualFinger(int physicalFinger) { } } -void ApplePS2SynapticsTouchPad::assignFingerType(virtual_finger_state &vf) { +void ApplePS2SynapticsTouchPad::assignFingerType(synaptics_virtual_finger_state &vf) { vf.fingerType = kMT2FingerTypeUndefined; for (MT2FingerType i = kMT2FingerTypeIndexFinger; i < kMT2FingerTypeCount; i = (MT2FingerType)(i + 1)) if (freeFingerTypes[i]) { @@ -1511,7 +1511,7 @@ bool ApplePS2SynapticsTouchPad::renumberFingers() { IOLog("synaptics_parse_hw_state: ERROR: invalid physical finger %d", fi.virtualFingerIndex); continue; } - virtual_finger_state &fiv = virtualFingerStates[fi.virtualFingerIndex]; + synaptics_virtual_finger_state &fiv = virtualFingerStates[fi.virtualFingerIndex]; fiv.x_avg.filter(fi.x); fiv.y_avg.filter(fi.y); fiv.width = fi.w; diff --git a/VoodooPS2Trackpad/VoodooPS2SynapticsTouchPad.h b/VoodooPS2Trackpad/VoodooPS2SynapticsTouchPad.h index 00fc296d..8f59be4f 100644 --- a/VoodooPS2Trackpad/VoodooPS2SynapticsTouchPad.h +++ b/VoodooPS2Trackpad/VoodooPS2SynapticsTouchPad.h @@ -170,7 +170,7 @@ struct synaptics_hw_state { transducers заполняются каждый раз с номером виртуального пальца столько, сколько надо. Будут ли при этом отжиматься отпущенные пальцы? */ -struct virtual_finger_state { +struct synaptics_virtual_finger_state { SimpleAverage x_avg; SimpleAverage y_avg; uint8_t pressure; @@ -239,7 +239,7 @@ class EXPORT ApplePS2SynapticsTouchPad : public IOHIPointing uint32_t physical_max_y {0}; synaptics_hw_state fingerStates[SYNAPTICS_MAX_FINGERS] {}; - virtual_finger_state virtualFingerStates[SYNAPTICS_MAX_FINGERS] {}; + synaptics_virtual_finger_state virtualFingerStates[SYNAPTICS_MAX_FINGERS] {}; bool freeFingerTypes[kMT2FingerTypeCount]; bool disableDeepSleep {false}; @@ -247,7 +247,7 @@ class EXPORT ApplePS2SynapticsTouchPad : public IOHIPointing static_assert(SYNAPTICS_MAX_FINGERS <= kMT2FingerTypeLittleFinger, "Too many fingers for one hand"); void assignVirtualFinger(int physicalFinger); - void assignFingerType(virtual_finger_state &vf); + void assignFingerType(synaptics_virtual_finger_state &vf); int lastFingerCount; int lastSentFingerCount; bool hadLiftFinger; From 2f7dac28602c490641c0cefd592bdf9e596e4538 Mon Sep 17 00:00:00 2001 From: SkyrilHD Date: Sat, 25 Jun 2022 08:34:03 +0200 Subject: [PATCH 068/101] Fix kernel panics on ALPS touchpads and more (#50) --- Changelog.md | 6 + VoodooPS2Trackpad/VoodooPS2ALPSGlidePoint.cpp | 1073 ++++------------- VoodooPS2Trackpad/VoodooPS2ALPSGlidePoint.h | 189 +-- .../VoodooPS2Trackpad-Info.plist | 6 +- 4 files changed, 281 insertions(+), 993 deletions(-) diff --git a/Changelog.md b/Changelog.md index 12e16b89..071c2371 100644 --- a/Changelog.md +++ b/Changelog.md @@ -1,5 +1,11 @@ VoodooPS2 Changelog ============================ +#### v2.2.9 +- Improved stability of ALPS touchpads +- V8 touchpads can pass all four fingers to VoodooInput natively +- Fixed unpressing during 3 fingers gesture on ALPS V7 +- Use VoodooTrackpoint for trackstick and non-MT ALPS touchpads + #### v2.2.8 - Added ALPS touchpad support - Fixed ELAN trackpoint scrolling in the wrong direction diff --git a/VoodooPS2Trackpad/VoodooPS2ALPSGlidePoint.cpp b/VoodooPS2Trackpad/VoodooPS2ALPSGlidePoint.cpp index c0a8e951..5b02ee68 100644 --- a/VoodooPS2Trackpad/VoodooPS2ALPSGlidePoint.cpp +++ b/VoodooPS2Trackpad/VoodooPS2ALPSGlidePoint.cpp @@ -168,16 +168,8 @@ static const struct alps_model_info alps_model_data[] = { // ApplePS2ALPSGlidePoint Class Implementation //////////////////////////////// // ============================================================================= -OSDefineMetaClassAndStructors(ApplePS2ALPSGlidePoint, IOHIPointing); - -UInt32 ApplePS2ALPSGlidePoint::deviceType() -{ return NX_EVS_DEVICE_TYPE_MOUSE; }; - -UInt32 ApplePS2ALPSGlidePoint::interfaceID() -{ return NX_EVS_DEVICE_INTERFACE_BUS_ACE; }; - -IOItemCount ApplePS2ALPSGlidePoint::buttonCount() { return _buttonCount; }; -IOFixed ApplePS2ALPSGlidePoint::resolution() { return _resolution << 16; }; +#define super IOService +OSDefineMetaClassAndStructors(ApplePS2ALPSGlidePoint, IOService); // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -192,16 +184,9 @@ bool ApplePS2ALPSGlidePoint::init(OSDictionary *dict) { return false; } - // initialize state... - for (int i = 0; i < MAX_TOUCHES; i++) - fingerStates[i].virtualFingerIndex = -1; - - memset(freeFingerTypes, true, kMT2FingerTypeCount); - freeFingerTypes[kMT2FingerTypeUndefined] = false; - // announce version extern kmod_info_t kmod_info; - DEBUG_LOG("ALPS: Version %s starting on OS X Darwin %d.%d.\n", kmod_info.version, version_major, version_minor); + DEBUG_LOG("%s: Version %s starting on OS X Darwin %d.%d.\n", getName() , kmod_info.version, version_major, version_minor); setProperty("Revision", 24, 32); @@ -244,7 +229,7 @@ void ApplePS2ALPSGlidePoint::injectVersionDependentProperties(OSDictionary *conf } ApplePS2ALPSGlidePoint *ApplePS2ALPSGlidePoint::probe(IOService *provider, SInt32 *score) { - DEBUG_LOG("ALPS: probe entered...\n"); + DEBUG_LOG("%s: probe entered...\n", getName()); // // The driver has been instructed to verify the presence of the actual @@ -290,7 +275,7 @@ ApplePS2ALPSGlidePoint *ApplePS2ALPSGlidePoint::probe(IOService *provider, SInt3 success = false; } else { success = true; - IOLog("ALPS: TouchPad driver started...\n"); + IOLog("%s: TouchPad driver started...\n", getName()); } _device->unlock(); @@ -315,7 +300,7 @@ bool ApplePS2ALPSGlidePoint::resetMouse() { // Verify the result if (request.commands[1].inOrOut != kSC_Reset && request.commands[2].inOrOut != kSC_ID) { - IOLog("ALPS: Failed to reset mouse, return values did not match. [0x%02x, 0x%02x]\n", request.commands[1].inOrOut, request.commands[2].inOrOut); + IOLog("%s: Failed to reset mouse, return values did not match. [0x%02x, 0x%02x]\n", getName(), request.commands[1].inOrOut, request.commands[2].inOrOut); return false; } return true; @@ -352,21 +337,6 @@ bool ApplePS2ALPSGlidePoint::start( IOService * provider ) { _device = (ApplePS2MouseDevice *) provider; _device->retain(); - // - // 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) - setProperty("HIDScrollResolutionX", _scrollresolution << 16, 32); - setProperty("HIDScrollResolutionY", _scrollresolution << 16, 32); - // // Setup workloop with command gate for thread synchronization... // @@ -425,6 +395,8 @@ bool ApplePS2ALPSGlidePoint::start( IOService * provider ) { //setProperty(kDeliverNotifications, true); + registerService(); + return true; } @@ -520,7 +492,7 @@ PS2InterruptResult ApplePS2ALPSGlidePoint::interruptOccurred(UInt8 data) { if (priv.proto_version != ALPS_PROTO_V8 && (packet[0] & 0xc8) == 0x08) { if (_packetByteCount == 3) { - DEBUG_LOG("ALPS: Dealing with bare PS/2 packet\n"); + DEBUG_LOG("%s: Dealing with bare PS/2 packet\n", getName()); //dispatchRelativePointerEventWithPacket(packet, kPacketLengthSmall); //Dr Hurt: allow this? priv.PSMOUSE_BAD_DATA = true; _ringBuffer.advanceHead(priv.pktsize); @@ -590,7 +562,7 @@ void ApplePS2ALPSGlidePoint::packetReady() { if (!ignoreall) (this->*process_packet)(packet); } else { - IOLog("ALPS: an invalid or bare packet has been dropped...\n"); + IOLog("%s: an invalid or bare packet has been dropped...\n", getName()); /* Might need to perform a full HW reset here if we keep receiving bad packets (consecutively) */ } _packetByteCount = 0; @@ -612,7 +584,7 @@ bool ApplePS2ALPSGlidePoint::deviceSpecificInit() { return true; init_fail: - IOLog("ALPS: Hardware initialization failed. TouchPad probably won't work\n"); + IOLog("%s: Hardware initialization failed. TouchPad probably won't work\n", getName()); resetMouse(); return false; } @@ -631,9 +603,6 @@ void ApplePS2ALPSGlidePoint::alps_process_packet_v1_v2(UInt8 *packet) { int x, y, z, fin, ges, left, right, middle, buttons = 0; // Unused code // int back = 0, forward = 0, fingers = 0; - uint64_t now_abs; - - clock_get_uptime(&now_abs); if (priv.proto_version == ALPS_PROTO_V1) { left = packet[2] & 0x10; @@ -675,7 +644,7 @@ void ApplePS2ALPSGlidePoint::alps_process_packet_v1_v2(UInt8 *packet) { dx = x > 383 ? (x - 768) : x; dy = -(y > 255 ? (y - 512) : y); - dispatchRelativePointerEventX(dx, dy, buttons, now_abs); + voodooTrackpoint(kIOMessageVoodooTrackpointRelativePointer, dx, dy, buttons); return; } @@ -705,7 +674,7 @@ void ApplePS2ALPSGlidePoint::alps_process_packet_v1_v2(UInt8 *packet) { // if (ges && fin && !priv.prev_fin) { // z = 0; // fingers = 0; - // dispatchRelativePointerEventX(x, y, buttons, now_abs); + // voodooTrackpoint(kIOMessageVoodooTrackpointRelativePointer, x, y, buttons); // } priv.prev_fin = fin; @@ -713,13 +682,12 @@ void ApplePS2ALPSGlidePoint::alps_process_packet_v1_v2(UInt8 *packet) { // fingers = z > 30 ? 1 : 0; if (z > 30) - dispatchRelativePointerEventX(x, y, buttons, now_abs); + voodooTrackpoint(kIOMessageVoodooTrackpointRelativePointer, x, y, buttons); if (priv.flags & ALPS_WHEEL) { int scrollAmount = ((packet[2] << 1) & 0x08) - ((packet[0] >> 4) & 0x07); - if (scrollAmount) { - dispatchScrollWheelEventX(scrollAmount, 0, 0, now_abs); - } + if (scrollAmount) + voodooTrackpoint(kIOMessageVoodooTrackpointScrollWheel, 0, -scrollAmount, buttons); } } @@ -862,23 +830,22 @@ int ApplePS2ALPSGlidePoint::alps_process_bitmap(struct alps_data *priv, fields->mt[1] = corner[priv->second_touch]; #if DEBUG - IOLog("ALPS: BITMAP\n"); + IOLog("%s: BITMAP\n", getName()); unsigned int ymap = fields->y_map; for (int i = 0; ymap != 0; i++, ymap >>= 1) { unsigned int xmap = fields->x_map; char bitLog[160]; - strlcpy(bitLog, "ALPS: ", sizeof(bitLog) + 1); for (int j = 0; xmap != 0; j++, xmap >>= 1) { strlcat(bitLog, (ymap & 1 && xmap & 1) ? "1 " : "0 ", sizeof(bitLog) + 1); } - IOLog("ALPS: %s\n", bitLog); + IOLog("%s: %s\n", getName(), bitLog); } - IOLog("ALPS: Process Bitmap, Corner=%d, Fingers=%d, x1=%d, x2=%d, y1=%d, y2=%d xmap=%d ymap=%d\n", priv->second_touch, fingers, fields->mt[0].x, fields->mt[1].x, fields->mt[0].y, fields->mt[1].y, fields->x_map, fields->y_map); + IOLog("%s: Process Bitmap, Corner=%d, Fingers=%d, x1=%d, x2=%d, y1=%d, y2=%d xmap=%d ymap=%d\n", getName(), priv->second_touch, fingers, fields->mt[0].x, fields->mt[1].x, fields->mt[0].y, fields->mt[1].y, fields->x_map, fields->y_map); #endif // DEBUG return fingers; } @@ -887,18 +854,17 @@ void ApplePS2ALPSGlidePoint::alps_process_trackstick_packet_v3(UInt8 *packet) { int x, y, left, right, middle; // Unused code // int z; - uint64_t now_abs; UInt32 buttons = 0, raw_buttons = 0; /* It should be a DualPoint when received trackstick packet */ if (!(priv.flags & ALPS_DUALPOINT)) { - DEBUG_LOG("ALPS: Rejected trackstick packet from non DualPoint device\n"); + DEBUG_LOG("%s: Rejected trackstick packet from non DualPoint device\n", getName()); return; } /* Sanity check packet */ if (!(packet[0] & 0x40)) { - DEBUG_LOG("ALPS: Bad trackstick packet, disregarding...\n"); + DEBUG_LOG("%s: Bad trackstick packet, disregarding...\n", getName()); return; } @@ -925,8 +891,6 @@ void ApplePS2ALPSGlidePoint::alps_process_trackstick_packet_v3(UInt8 *packet) { /* To get proper movement direction */ y = -y; - clock_get_uptime(&now_abs); - /* * Most ALPS models report the trackstick buttons in the touchpad * packets, but a few report them here. No reliable way has been @@ -959,9 +923,9 @@ void ApplePS2ALPSGlidePoint::alps_process_trackstick_packet_v3(UInt8 *packet) { /* If middle button is pressed, switch to scroll mode. Else, move pointer normally */ if (0 == (buttons & 0x04)) { - dispatchRelativePointerEventX(x, y, buttons, now_abs); + voodooTrackpoint(kIOMessageVoodooTrackpointRelativePointer, x, y, buttons); } else { - dispatchScrollWheelEventX(-y, -x, 0, now_abs); + voodooTrackpoint(kIOMessageVoodooTrackpointScrollWheel, x, y, buttons); } } @@ -1143,47 +1107,7 @@ void ApplePS2ALPSGlidePoint::alps_process_touchpad_packet_v3_v5(UInt8 *packet) { // if (last_fingers == 2 && fingers == 1 && scrolldebounce) // fingers = 2; - DEBUG_LOG("ALPS: Amount of finger(s) accessing alps_process_touchpad_packet_v3_v5: %d\n", fingers); - - if (fingers >= 2) { - fingerStates[1].x = f.mt[1].x; - fingerStates[1].y = f.mt[1].y; - fingerStates[1].z = f.pressure; - - if (fingerStates[1].x > X_MAX_POSITIVE) - fingerStates[1].x -= 1 << ABS_POS_BITS; - else if (fingerStates[1].x == X_MAX_POSITIVE) - fingerStates[1].x = XMAX; - - if (fingerStates[1].y > Y_MAX_POSITIVE) - fingerStates[1].y -= 1 << ABS_POS_BITS; - else if (fingerStates[1].y == Y_MAX_POSITIVE) - fingerStates[1].y = YMAX; - } - // normal "packet" - fingerStates[0].x = f.mt[0].x; - fingerStates[0].y = f.mt[0].y; - fingerStates[0].z = f.pressure; - - DEBUG_LOG("ALPS: fingerStates[0] report: x: %d, y: %d, z: %d\n", fingerStates[0].x, fingerStates[0].y, fingerStates[0].z); - - if (fingerStates[0].x > X_MAX_POSITIVE) - fingerStates[0].x -= 1 << ABS_POS_BITS; - else if (fingerStates[0].x == X_MAX_POSITIVE) - fingerStates[0].x = XMAX; - - if (fingerStates[0].y > Y_MAX_POSITIVE) - fingerStates[0].y -= 1 << ABS_POS_BITS; - else if (fingerStates[0].y == Y_MAX_POSITIVE) - fingerStates[0].y = YMAX; - - clampedFingerCount = fingers; - - if (clampedFingerCount > MAX_TOUCHES) - clampedFingerCount = MAX_TOUCHES; - - if (renumberFingers()) - sendTouchData(); + prepareVoodooInput(f, fingers); alps_buttons(f); } @@ -1213,9 +1137,6 @@ void ApplePS2ALPSGlidePoint::alps_process_packet_v6(UInt8 *packet) { int x, y, z; int buttons = 0; - uint64_t now_abs; - clock_get_uptime(&now_abs); - /* * We can use Byte5 to distinguish if the packet is from Touchpad * or Trackpoint. @@ -1225,7 +1146,7 @@ void ApplePS2ALPSGlidePoint::alps_process_packet_v6(UInt8 *packet) { if (packet[5] == 0x7F) { /* It should be a DualPoint when received Trackpoint packet */ if (!(priv.flags & ALPS_DUALPOINT)) { - DEBUG_LOG("ALPS: Rejected trackstick packet from non DualPoint device\n"); + DEBUG_LOG("%s: Rejected trackstick packet from non DualPoint device\n", getName()); return; } @@ -1251,7 +1172,7 @@ void ApplePS2ALPSGlidePoint::alps_process_packet_v6(UInt8 *packet) { y = -y; /* Divide 4 since trackpoint's speed is too fast */ - dispatchRelativePointerEventX(x / 4, y / 4, buttons, now_abs); + voodooTrackpoint(kIOMessageVoodooTrackpointRelativePointer, x/4, y/4, buttons); return; } @@ -1270,7 +1191,7 @@ void ApplePS2ALPSGlidePoint::alps_process_packet_v6(UInt8 *packet) { buttons |= f.left ? 0x01 : 0; buttons |= f.right ? 0x02 : 0; - dispatchRelativePointerEventX(f.mt[0].x, f.mt[0].y, buttons, now_abs); + voodooTrackpoint(kIOMessageVoodooTrackpointRelativePointer, f.mt[0].x, f.mt[0].y, buttons); } void ApplePS2ALPSGlidePoint::alps_process_packet_v4(UInt8 *packet) { @@ -1333,47 +1254,7 @@ void ApplePS2ALPSGlidePoint::alps_process_packet_v4(UInt8 *packet) { priv.second_touch = -1; } - DEBUG_LOG("ALPS: There are currently %d finger(s) accessing alps_parse_hw_state\n", f.fingers); - - if (f.fingers >= 2) { - fingerStates[1].x = f.mt[1].x; - fingerStates[1].y = f.mt[1].y; - fingerStates[1].z = f.pressure; - - if (fingerStates[1].x > X_MAX_POSITIVE) - fingerStates[1].x -= 1 << ABS_POS_BITS; - else if (fingerStates[1].x == X_MAX_POSITIVE) - fingerStates[1].x = XMAX; - - if (fingerStates[1].y > Y_MAX_POSITIVE) - fingerStates[1].y -= 1 << ABS_POS_BITS; - else if (fingerStates[1].y == Y_MAX_POSITIVE) - fingerStates[1].y = YMAX; - } - // normal "packet" - fingerStates[0].x = f.mt[0].x; - fingerStates[0].y = f.mt[0].y; - fingerStates[0].z = f.pressure; - - DEBUG_LOG("ALPS: fingerStates[0] report: x: %d, y: %d, z: %d\n", fingerStates[0].x, fingerStates[0].y, fingerStates[0].z); - - if (fingerStates[0].x > X_MAX_POSITIVE) - fingerStates[0].x -= 1 << ABS_POS_BITS; - else if (fingerStates[0].x == X_MAX_POSITIVE) - fingerStates[0].x = XMAX; - - if (fingerStates[0].y > Y_MAX_POSITIVE) - fingerStates[0].y -= 1 << ABS_POS_BITS; - else if (fingerStates[0].y == Y_MAX_POSITIVE) - fingerStates[0].y = YMAX; - - clampedFingerCount = f.fingers; - - if (clampedFingerCount > MAX_TOUCHES) - clampedFingerCount = MAX_TOUCHES; - - if (renumberFingers()) - sendTouchData(); + prepareVoodooInput(f, f.fingers); alps_buttons(f); } @@ -1450,17 +1331,17 @@ int ApplePS2ALPSGlidePoint::alps_get_mt_count(struct input_mt_pos *mt) { } bool ApplePS2ALPSGlidePoint::alps_decode_packet_v7(struct alps_fields *f, UInt8 *p){ - //IOLog("ALPS: Decode V7 touchpad Packet... 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x\n", p[0], p[1], p[2], p[3], p[4], p[5]); + //IOLog("%s: Decode V7 touchpad Packet... 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x\n", getName(), p[0], p[1], p[2], p[3], p[4], p[5]); unsigned char pkt_id; pkt_id = alps_get_packet_id_v7(p); if (pkt_id == V7_PACKET_ID_IDLE) { - DEBUG_LOG("ALPS: V7_PACKET_ID_IDLE\n"); + DEBUG_LOG("%s: V7_PACKET_ID_IDLE\n", getName()); return true; } if (pkt_id == V7_PACKET_ID_UNKNOWN) { - DEBUG_LOG("ALPS: V7_PACKET_ID_UNKNOWN\n"); + DEBUG_LOG("%s: V7_PACKET_ID_UNKNOWN\n", getName()); return false; } @@ -1483,18 +1364,18 @@ bool ApplePS2ALPSGlidePoint::alps_decode_packet_v7(struct alps_fields *f, UInt8 * Since problems 2 & 3 cannot be worked around, just ignore them. */ if (pkt_id == V7_PACKET_ID_NEW) { - DEBUG_LOG("ALPS: V7_PACKET_ID_NEW\n"); - return true; + DEBUG_LOG("%s: V7_PACKET_ID_NEW\n", getName()); + return false; } alps_get_finger_coordinate_v7(f->mt, p, pkt_id); if (pkt_id == V7_PACKET_ID_TWO) { - DEBUG_LOG("ALPS: V7_PACKET_ID_TWO\n"); + DEBUG_LOG("%s: V7_PACKET_ID_TWO\n", getName()); f->fingers = alps_get_mt_count(f->mt); } else { /* pkt_id == V7_PACKET_ID_MULTI */ - DEBUG_LOG("ALPS: V7_PACKET_ID_MULTI\n"); + DEBUG_LOG("%s: V7_PACKET_ID_MULTI\n", getName()); f->fingers = 3 + (p[5] & 0x03); } @@ -1525,12 +1406,9 @@ void ApplePS2ALPSGlidePoint::alps_process_trackstick_packet_v7(UInt8 *packet) { // int z; int buttons = 0; - uint64_t now_abs; - clock_get_uptime(&now_abs); - /* It should be a DualPoint when received trackstick packet */ if (!(priv.flags & ALPS_DUALPOINT)) { - IOLog("ALPS: Rejected trackstick packet from non DualPoint device\n"); + IOLog("%s: Rejected trackstick packet from non DualPoint device\n", getName()); return; } @@ -1556,9 +1434,9 @@ void ApplePS2ALPSGlidePoint::alps_process_trackstick_packet_v7(UInt8 *packet) { /* If middle button is pressed, switch to scroll mode. Else, move pointer normally */ if (0 == (buttons & 0x04)) { - dispatchRelativePointerEventX(x, y, buttons, now_abs); + voodooTrackpoint(kIOMessageVoodooTrackpointRelativePointer, x, y, buttons); } else { - dispatchScrollWheelEventX(-y, -x, 0, now_abs); + voodooTrackpoint(kIOMessageVoodooTrackpointScrollWheel, x, y, buttons); } } @@ -1571,53 +1449,17 @@ void ApplePS2ALPSGlidePoint::alps_process_touchpad_packet_v7(UInt8 *packet){ memset(&f, 0, sizeof(alps_fields)); - (this->alps_decode_packet_v7)(&f, packet); + if (!((this->*decode_fields)(&f, packet))) + return; /* Reverse y co-ordinates to have 0 at bottom for gestures to work */ f.mt[0].y = priv.y_max - f.mt[0].y; f.mt[1].y = priv.y_max - f.mt[1].y; - DEBUG_LOG("ALPS: Amount of finger(s) accessing alps_process_touchpad_packet_v7: %d\n", f.fingers); - - if (f.fingers >= 2) { - fingerStates[1].x = f.mt[1].x; - fingerStates[1].y = f.mt[1].y; - fingerStates[1].z = f.pressure; - - if (fingerStates[1].x > X_MAX_POSITIVE) - fingerStates[1].x -= 1 << ABS_POS_BITS; - else if (fingerStates[1].x == X_MAX_POSITIVE) - fingerStates[1].x = XMAX; - - if (fingerStates[1].y > Y_MAX_POSITIVE) - fingerStates[1].y -= 1 << ABS_POS_BITS; - else if (fingerStates[1].y == Y_MAX_POSITIVE) - fingerStates[1].y = YMAX; - } - // normal "packet" - fingerStates[0].x = f.mt[0].x; - fingerStates[0].y = f.mt[0].y; - fingerStates[0].z = f.pressure; - - DEBUG_LOG("ALPS: fingerStates[0] report: x: %d, y: %d, z: %d\n", fingerStates[0].x, fingerStates[0].y, fingerStates[0].z); + if (_forceTouchMode != 0) + f.pressure = z_finger; - if (fingerStates[0].x > X_MAX_POSITIVE) - fingerStates[0].x -= 1 << ABS_POS_BITS; - else if (fingerStates[0].x == X_MAX_POSITIVE) - fingerStates[0].x = XMAX; - - if (fingerStates[0].y > Y_MAX_POSITIVE) - fingerStates[0].y -= 1 << ABS_POS_BITS; - else if (fingerStates[0].y == Y_MAX_POSITIVE) - fingerStates[0].y = YMAX; - - clampedFingerCount = f.fingers; - - if (clampedFingerCount > MAX_TOUCHES) - clampedFingerCount = MAX_TOUCHES; - - if (renumberFingers()) - sendTouchData(); + prepareVoodooInput(f, f.fingers); alps_buttons(f); } @@ -1662,18 +1504,16 @@ bool ApplePS2ALPSGlidePoint::alps_decode_ss4_v2(struct alps_fields *f, UInt8 *p) //struct alps_data *priv; unsigned char pkt_id; unsigned int no_data_x, no_data_y; - uint64_t now_abs; - clock_get_uptime(&now_abs); pkt_id = alps_get_pkt_id_ss4_v2(p); /* Current packet is 1Finger coordinate packet */ switch (pkt_id) { case SS4_PACKET_ID_ONE: - DEBUG_LOG("ALPS: SS4_PACKET_ID_ONE\n"); + DEBUG_LOG("%s: SS4_PACKET_ID_ONE\n", getName()); f->mt[0].x = SS4_1F_X_V2(p); f->mt[0].y = SS4_1F_Y_V2(p); - DEBUG_LOG("ALPS: Coordinates for SS4_PACKET_ID_ONE: %dx%d\n", f->mt[0].x, f->mt[0].y); + DEBUG_LOG("%s: Coordinates for SS4_PACKET_ID_ONE: %dx%d\n", getName(), f->mt[0].x, f->mt[0].y); f->pressure = ((SS4_1F_Z_V2(p)) * 2) & 0x7f; /* * When a button is held the device will give us events @@ -1687,7 +1527,7 @@ bool ApplePS2ALPSGlidePoint::alps_decode_ss4_v2(struct alps_fields *f, UInt8 *p) break; case SS4_PACKET_ID_TWO: - DEBUG_LOG("ALPS: SS4_PACKET_ID_TWO\n"); + DEBUG_LOG("%s: SS4_PACKET_ID_TWO\n", getName()); if (priv.flags & ALPS_BUTTONPAD) { if (IS_SS4PLUS_DEV(priv.dev_id)) { f->mt[0].x = SS4_PLUS_BTL_MF_X_V2(p, 0); @@ -1709,7 +1549,7 @@ bool ApplePS2ALPSGlidePoint::alps_decode_ss4_v2(struct alps_fields *f, UInt8 *p) f->mt[0].y = SS4_STD_MF_Y_V2(p, 0); f->mt[1].y = SS4_STD_MF_Y_V2(p, 1); } - DEBUG_LOG("ALPS: Coordinates for SS4_PACKET_ID_TWO: [0]:%dx%d [1]:%dx%d\n", f->mt[0].x, f->mt[0].y, f->mt[1].x, f->mt[1].y); + DEBUG_LOG("%s: Coordinates for SS4_PACKET_ID_TWO: [0]:%dx%d [1]:%dx%d\n", getName(), f->mt[0].x, f->mt[0].y, f->mt[1].x, f->mt[1].y); f->pressure = SS4_MF_Z_V2(p, 0) ? 0x30 : 0; if (SS4_IS_MF_CONTINUE(p)) { @@ -1723,7 +1563,7 @@ bool ApplePS2ALPSGlidePoint::alps_decode_ss4_v2(struct alps_fields *f, UInt8 *p) break; case SS4_PACKET_ID_MULTI: - DEBUG_LOG("ALPS: SS4_PACKET_ID_MULTI\n"); + DEBUG_LOG("%s: SS4_PACKET_ID_MULTI\n", getName()); if (priv.flags & ALPS_BUTTONPAD) { if (IS_SS4PLUS_DEV(priv.dev_id)) { f->mt[2].x = SS4_PLUS_BTL_MF_X_V2(p, 0); @@ -1753,7 +1593,7 @@ bool ApplePS2ALPSGlidePoint::alps_decode_ss4_v2(struct alps_fields *f, UInt8 *p) f->mt[2].y = SS4_STD_MF_Y_V2(p, 0); f->mt[3].y = SS4_STD_MF_Y_V2(p, 1); } - DEBUG_LOG("ALPS: Coordinates for SS4_PACKET_ID_MULTI: [2]:%dx%d [3]:%dx%d\n", f->mt[2].x, f->mt[2].y, f->mt[3].x, f->mt[3].y); + DEBUG_LOG("%s: Coordinates for SS4_PACKET_ID_MULTI: [2]:%dx%d [3]:%dx%d\n", getName(), f->mt[2].x, f->mt[2].y, f->mt[3].x, f->mt[3].y); f->first_mp = 0; f->is_mp = 1; @@ -1771,7 +1611,7 @@ bool ApplePS2ALPSGlidePoint::alps_decode_ss4_v2(struct alps_fields *f, UInt8 *p) break; case SS4_PACKET_ID_STICK: - DEBUG_LOG("ALPS: SS4_PACKET_ID_STICK\n"); + DEBUG_LOG("%s: SS4_PACKET_ID_STICK\n", getName()); /* * x, y, and pressure are decoded in * alps_process_packet_ss4_v2() @@ -1810,9 +1650,6 @@ void ApplePS2ALPSGlidePoint::alps_process_packet_ss4_v2(UInt8 *packet) { struct alps_fields f; int x, y, pressure; - uint64_t now_abs; - clock_get_uptime(&now_abs); - memset(&f, 0, sizeof(struct alps_fields)); (this->*decode_fields)(&f, packet); if (priv.multi_packet) { @@ -1850,7 +1687,7 @@ void ApplePS2ALPSGlidePoint::alps_process_packet_ss4_v2(UInt8 *packet) { /* Report trackstick */ if (alps_get_pkt_id_ss4_v2(packet) == SS4_PACKET_ID_STICK) { if (!(priv.flags & ALPS_DUALPOINT)) { - IOLog("ALPS: Rejected trackstick packet from non DualPoint device\n"); + IOLog("%s: Rejected trackstick packet from non DualPoint device\n", getName()); return; } @@ -1875,12 +1712,12 @@ void ApplePS2ALPSGlidePoint::alps_process_packet_ss4_v2(UInt8 *packet) { x /= 3; y /= 3; - DEBUG_LOG("ALPS: Trackstick report: X=%d, Y=%d, Z=%d\n", x, y, pressure); + DEBUG_LOG("%s: Trackstick report: X=%d, Y=%d, Z=%d\n", getName(), x, y, pressure); /* If middle button is pressed, switch to scroll mode. Else, move pointer normally */ if (0 == (buttons & 0x04)) { - dispatchRelativePointerEventX(x, y, buttons, now_abs); + voodooTrackpoint(kIOMessageVoodooTrackpointRelativePointer, x, y, buttons); } else { - dispatchScrollWheelEventX(-y, -x, 0, now_abs); + voodooTrackpoint(kIOMessageVoodooTrackpointScrollWheel, x, y, buttons); } return; } @@ -1889,49 +1726,7 @@ void ApplePS2ALPSGlidePoint::alps_process_packet_ss4_v2(UInt8 *packet) { f.mt[0].y = priv.y_max - f.mt[0].y; f.mt[1].y = priv.y_max - f.mt[1].y; - DEBUG_LOG("ALPS: There are currently %d fingers in alps_process_packet_ss4_v2\n", f.fingers); - - if (f.fingers >= 2) { - fingerStates[1].x = f.mt[1].x; - fingerStates[1].y = f.mt[1].y; - fingerStates[1].z = f.pressure; - - if (fingerStates[1].x > X_MAX_POSITIVE) - fingerStates[1].x -= 1 << ABS_POS_BITS; - else if (fingerStates[1].x == X_MAX_POSITIVE) - fingerStates[1].x = XMAX; - - if (fingerStates[1].y > Y_MAX_POSITIVE) - fingerStates[1].y -= 1 << ABS_POS_BITS; - else if (fingerStates[1].y == Y_MAX_POSITIVE) - fingerStates[1].y = YMAX; - - DEBUG_LOG("ALPS: fingerStates[1] report: x: %d, y: %d, z: %d\n", fingerStates[1].x, fingerStates[1].y, fingerStates[1].z); - } - // normal "packet" - fingerStates[0].x = f.mt[0].x; - fingerStates[0].y = f.mt[0].y; - fingerStates[0].z = f.pressure; - - DEBUG_LOG("ALPS: fingerStates[0] report: x: %d, y: %d, z: %d\n", fingerStates[0].x, fingerStates[0].y, fingerStates[0].z); - - if (fingerStates[0].x > X_MAX_POSITIVE) - fingerStates[0].x -= 1 << ABS_POS_BITS; - else if (fingerStates[0].x == X_MAX_POSITIVE) - fingerStates[0].x = XMAX; - - if (fingerStates[0].y > Y_MAX_POSITIVE) - fingerStates[0].y -= 1 << ABS_POS_BITS; - else if (fingerStates[0].y == Y_MAX_POSITIVE) - fingerStates[0].y = YMAX; - - clampedFingerCount = f.fingers; - - if (clampedFingerCount > MAX_TOUCHES) - clampedFingerCount = MAX_TOUCHES; - - if (renumberFingers()) - sendTouchData(); + prepareVoodooInput(f, f.fingers); alps_buttons(f); } @@ -1984,7 +1779,7 @@ bool ApplePS2ALPSGlidePoint::alps_command_mode_set_addr(int addr) { TPS2Request<1> request; int i, nibble; - // DEBUG_LOG("ALPS: command mode set addr with addr command: 0x%02x\n", priv.addr_command); + // DEBUG_LOG("%s: command mode set addr with addr command: 0x%02x\n", getName(), priv.addr_command); request.commands[0].command = kPS2C_SendCommandAndCompareAck; request.commands[0].inOrOut = priv.addr_command; request.commandsCount = 1; @@ -2009,7 +1804,7 @@ int ApplePS2ALPSGlidePoint::alps_command_mode_read_reg(int addr) { ALPSStatus_t status; if (!alps_command_mode_set_addr(addr)) { - DEBUG_LOG("ALPS: Failed to set addr to read register\n"); + DEBUG_LOG("%s: Failed to set addr to read register\n", getName()); return -1; } @@ -2033,14 +1828,14 @@ int ApplePS2ALPSGlidePoint::alps_command_mode_read_reg(int addr) { status.bytes[1] = request.commands[2].inOrOut; status.bytes[2] = request.commands[3].inOrOut; - // IOLog("ALPS: read reg result: { 0x%02x, 0x%02x, 0x%02x }\n", status.bytes[0], status.bytes[1], status.bytes[2]); + // IOLog("%s: read reg result: { 0x%02x, 0x%02x, 0x%02x }\n", getName(), status.bytes[0], status.bytes[1], status.bytes[2]); /* The address being read is returned in the first 2 bytes * of the result. Check that the address matches the expected * address. */ if (addr != ((status.bytes[0] << 8) | status.bytes[1])) { - DEBUG_LOG("ALPS: ERROR: read wrong registry value, expected: %x\n", addr); + DEBUG_LOG("%s: ERROR: read wrong registry value, expected: %x\n", getName(), addr); return -1; } @@ -2106,7 +1901,8 @@ bool ApplePS2ALPSGlidePoint::alps_rpt_cmd(SInt32 init_command, SInt32 init_arg, report->bytes[1] = request.commands[byte0+1].inOrOut; report->bytes[2] = request.commands[byte0+2].inOrOut; - DEBUG_LOG("ALPS: %02x report: [0x%02x 0x%02x 0x%02x]\n", + DEBUG_LOG("%s: %02x report: [0x%02x 0x%02x 0x%02x]\n", + getName(), repeated_command, report->bytes[0], report->bytes[1], @@ -2116,19 +1912,19 @@ bool ApplePS2ALPSGlidePoint::alps_rpt_cmd(SInt32 init_command, SInt32 init_arg, } bool ApplePS2ALPSGlidePoint::alps_enter_command_mode() { - DEBUG_LOG("ALPS: enter command mode\n"); + DEBUG_LOG("%s: enter command mode\n", getName()); TPS2Request<4> request; ALPSStatus_t status; if (!alps_rpt_cmd(NULL, NULL, kDP_MouseResetWrap, &status)) { - IOLog("ALPS: Failed to enter command mode!\n"); + IOLog("%s: Failed to enter command mode!\n", getName()); return false; } return true; } bool ApplePS2ALPSGlidePoint::alps_exit_command_mode() { - DEBUG_LOG("ALPS: exit command mode\n"); + DEBUG_LOG("%s: exit command mode\n", getName()); TPS2Request<1> request; request.commands[0].command = kPS2C_SendCommandAndCompareAck; @@ -2299,8 +2095,7 @@ bool ApplePS2ALPSGlidePoint::alps_tap_mode(bool enable) { _device->submitRequestAndBlock(&request); if (request.commandsCount != 8) { - DEBUG_LOG("ALPS: Enabling tap mode failed before getStatus call, command count=%d\n", - request.commandsCount); + DEBUG_LOG("%s: Enabling tap mode failed before getStatus call, command count=%d\n", getName(), request.commandsCount); return false; } @@ -2318,12 +2113,12 @@ bool ApplePS2ALPSGlidePoint::alps_hw_init_v1_v2() { } if (!alps_tap_mode(true)) { - IOLog("ALPS: Failed to enable hardware tapping\n"); + IOLog("%s: Failed to enable hardware tapping\n", getName()); return false; } if (!alps_absolute_mode_v1_v2()) { - IOLog("ALPS: Failed to enable absolute mode\n"); + IOLog("%s: Failed to enable absolute mode\n", getName()); return false; } @@ -2364,16 +2159,16 @@ bool ApplePS2ALPSGlidePoint::alps_passthrough_mode_v3(int regBase, bool enable) int regVal; bool ret = false; - DEBUG_LOG("ALPS: passthrough mode enable=%d\n", enable); + DEBUG_LOG("%s: passthrough mode enable=%d\n", getName(), enable); if (!alps_enter_command_mode()) { - IOLog("ALPS: Failed to enter command mode while enabling passthrough mode\n"); + IOLog("%s: Failed to enter command mode while enabling passthrough mode\n", getName()); return false; } regVal = alps_command_mode_read_reg(regBase + 0x0008); if (regVal == -1) { - IOLog("ALPS: Failed to read register while setting up passthrough mode\n"); + IOLog("%s: Failed to read register while setting up passthrough mode\n", getName()); goto error; } @@ -2387,7 +2182,7 @@ bool ApplePS2ALPSGlidePoint::alps_passthrough_mode_v3(int regBase, bool enable) error: if (!alps_exit_command_mode()) { - IOLog("ALPS: failed to exit command mode while enabling passthrough mode v3\n"); + IOLog("%s: failed to exit command mode while enabling passthrough mode v3\n", getName()); return false; } @@ -2459,7 +2254,7 @@ IOReturn ApplePS2ALPSGlidePoint::alps_setup_trackstick_v3(int regBase) { * all. */ if (!alps_rpt_cmd(NULL, NULL, kDP_SetMouseScaling2To1, &report)) { - IOLog("ALPS: Failed to initialize trackstick (E7 report failed)\n"); + IOLog("%s: Failed to initialize trackstick (E7 report failed)\n", getName()); ret = kIOReturnNoDevice; } else { /* @@ -2478,16 +2273,16 @@ IOReturn ApplePS2ALPSGlidePoint::alps_setup_trackstick_v3(int regBase) { assert(request.commandsCount <= countof(request.commands)); _device->submitRequestAndBlock(&request); if (request.commandsCount != 3) { - IOLog("ALPS: error sending magic E6 scaling sequence\n"); + IOLog("%s: error sending magic E6 scaling sequence\n", getName()); ret = kIOReturnIOError; goto error; } if (!(alps_command_mode_send_nibble(0x9) && alps_command_mode_send_nibble(0x4))) { - IOLog("ALPS: Error sending magic E6 nibble sequence\n"); + IOLog("%s: Error sending magic E6 nibble sequence\n", getName()); ret = kIOReturnIOError; goto error; } - DEBUG_LOG("ALPS: Sent magic E6 sequence\n"); + DEBUG_LOG("%s: Sent magic E6 sequence\n", getName()); /* * This ensures the trackstick packets are in the format @@ -2518,7 +2313,7 @@ bool ApplePS2ALPSGlidePoint::alps_hw_init_v3() { if (!(alps_enter_command_mode() && alps_absolute_mode_v3())) { - IOLog("ALPS: Failed to enter absolute mode\n"); + IOLog("%s: Failed to enter absolute mode\n", getName()); goto error; } @@ -2681,7 +2476,7 @@ bool ApplePS2ALPSGlidePoint::alps_hw_init_v4() { goto error; if (!alps_absolute_mode_v4()) { - IOLog("ALPS: Failed to enter absolute mode\n"); + IOLog("%s: Failed to enter absolute mode\n", getName()); goto error; } @@ -2791,10 +2586,10 @@ void ApplePS2ALPSGlidePoint::alps_update_device_area_ss4_v2(unsigned char otp[][ int num_y_electrode; int x_pitch, y_pitch, x_phys, y_phys; - DEBUG_LOG("ALPS: Accessing 'Update Device Area'\n"); + DEBUG_LOG("%s: Accessing 'Update Device Area'\n", getName()); if (IS_SS4PLUS_DEV(priv->dev_id)) { - DEBUG_LOG("ALPS: Device is SS4_PLUS\n"); + DEBUG_LOG("%s: Device is SS4_PLUS\n", getName()); num_x_electrode = SS4PLUS_NUMSENSOR_XOFFSET + (otp[0][2] & 0x0F); num_y_electrode = SS4PLUS_NUMSENSOR_YOFFSET + ((otp[0][2] >> 4) & 0x0F); @@ -2805,7 +2600,7 @@ void ApplePS2ALPSGlidePoint::alps_update_device_area_ss4_v2(unsigned char otp[][ y_pitch = ((otp[0][1] >> 4) & 0x0F) + SS4PLUS_MIN_PITCH_MM; } else { - DEBUG_LOG("ALPS: Device is SS4\n"); + DEBUG_LOG("%s: Device is SS4\n", getName()); num_x_electrode = SS4_NUMSENSOR_XOFFSET + (otp[1][0] & 0x0F); num_y_electrode = SS4_NUMSENSOR_YOFFSET + ((otp[1][0] >> 4) & 0x0F); @@ -2819,7 +2614,7 @@ void ApplePS2ALPSGlidePoint::alps_update_device_area_ss4_v2(unsigned char otp[][ x_phys = x_pitch * (num_x_electrode - 1); /* In 0.1 mm units */ y_phys = y_pitch * (num_y_electrode - 1); /* In 0.1 mm units */ - DEBUG_LOG("ALPS: Your dimensions are: %dx%d\n", x_phys, y_phys); + DEBUG_LOG("%s: Your dimensions are: %dx%d\n", getName(), x_phys, y_phys); priv->x_res = priv->x_max * 10 / x_phys; /* units / mm */ priv->y_res = priv->y_max * 10 / y_phys; /* units / mm */ @@ -3033,7 +2828,7 @@ void ApplePS2ALPSGlidePoint::set_protocol() { if (alps_probe_trackstick_v3_v7(ALPS_REG_BASE_PINNACLE)) { priv.flags &= ~ALPS_DUALPOINT; } else { - IOLog("ALPS: TrackStick detected...\n"); + IOLog("%s: TrackStick detected...\n", getName()); } break; @@ -3056,7 +2851,7 @@ void ApplePS2ALPSGlidePoint::set_protocol() { if (alps_probe_trackstick_v3_v7(ALPS_REG_BASE_RUSHMORE)) { priv.flags &= ~ALPS_DUALPOINT; } else { - IOLog("ALPS: TrackStick detected...\n"); + IOLog("%s: TrackStick detected...\n", getName()); } break; @@ -3115,13 +2910,13 @@ void ApplePS2ALPSGlidePoint::set_protocol() { if (priv.fw_ver[1] != 0xba){ priv.flags |= ALPS_BUTTONPAD; - IOLog("ALPS: ButtonPad Detected...\n"); + IOLog("%s: ButtonPad Detected...\n", getName()); } if (alps_probe_trackstick_v3_v7(ALPS_REG_BASE_V7)){ priv.flags &= ~ALPS_DUALPOINT; } else { - IOLog("ALPS: TrackStick detected...\n"); + IOLog("%s: TrackStick detected...\n", getName()); } break; @@ -3145,13 +2940,16 @@ void ApplePS2ALPSGlidePoint::set_protocol() { priv.proto_version != ALPS_PROTO_V2 || priv.proto_version != ALPS_PROTO_V6) set_resolution(); + + setProperty(VOODOO_INPUT_TRANSFORM_KEY, 0ull, 32); + setProperty("VoodooInputSupported", kOSBooleanTrue); } bool ApplePS2ALPSGlidePoint::matchTable(ALPSStatus_t *e7, ALPSStatus_t *ec) { const struct alps_model_info *model; int i; - IOLog("ALPS: Touchpad with Signature { %d, %d, %d }\n", e7->bytes[0], e7->bytes[1], e7->bytes[2]); + IOLog("%s: Touchpad with Signature { %d, %d, %d }\n", getName(), e7->bytes[0], e7->bytes[1], e7->bytes[2]); for (i = 0; i < ARRAY_SIZE(alps_model_data); i++) { model = &alps_model_data[i]; @@ -3162,15 +2960,15 @@ bool ApplePS2ALPSGlidePoint::matchTable(ALPSStatus_t *e7, ALPSStatus_t *ec) { // log model version: if (priv.proto_version == ALPS_PROTO_V1) { - IOLog("ALPS: Found an ALPS V1 TouchPad\n"); + IOLog("%s: Found an ALPS V1 TouchPad\n", getName()); } else if (priv.proto_version == ALPS_PROTO_V2) { - IOLog("ALPS: Found an ALPS V2 TouchPad\n"); + IOLog("%s: Found an ALPS V2 TouchPad\n", getName()); } else if (priv.proto_version == ALPS_PROTO_V3_RUSHMORE) { - IOLog("ALPS: Found an ALPS V3 Rushmore TouchPad\n"); + IOLog("%s: Found an ALPS V3 Rushmore TouchPad\n", getName()); } else if (priv.proto_version == ALPS_PROTO_V4) { - IOLog("ALPS: Found an ALPS V4 TouchPad\n"); + IOLog("%s: Found an ALPS V4 TouchPad\n", getName()); }else if (priv.proto_version == ALPS_PROTO_V6) { - IOLog("ALPS: Found an ALPS V6 TouchPad\n"); + IOLog("%s: Found an ALPS V6 TouchPad\n", getName()); } set_protocol(); @@ -3197,12 +2995,12 @@ IOReturn ApplePS2ALPSGlidePoint::identify() { */ if (!alps_rpt_cmd(kDP_SetMouseResolution, NULL, kDP_SetMouseScaling1To1, &e6)) { - IOLog("ALPS: identify: not an ALPS device. Error getting E6 report\n"); + IOLog("%s: identify: not an ALPS device. Error getting E6 report\n", getName()); //return kIOReturnIOError; } if ((e6.bytes[0] & 0xf8) != 0 || e6.bytes[1] != 0 || (e6.bytes[2] != 10 && e6.bytes[2] != 100)) { - IOLog("ALPS: identify: not an ALPS device. Invalid E6 report\n"); + IOLog("%s: identify: not an ALPS device. Invalid E6 report\n", getName()); //return kIOReturnInvalid; } @@ -3213,7 +3011,7 @@ IOReturn ApplePS2ALPSGlidePoint::identify() { if (!(alps_rpt_cmd(kDP_SetMouseResolution, NULL, kDP_SetMouseScaling2To1, &e7) && alps_rpt_cmd(kDP_SetMouseResolution, NULL, kDP_MouseResetWrap, &ec) && alps_exit_command_mode())) { - IOLog("ALPS: identify: not an ALPS device. Error getting E7/EC report\n"); + IOLog("%s: identify: not an ALPS device. Error getting E7/EC report\n", getName()); return kIOReturnIOError; } @@ -3223,38 +3021,38 @@ IOReturn ApplePS2ALPSGlidePoint::identify() { } else if (e7.bytes[0] == 0x73 && e7.bytes[1] == 0x02 && e7.bytes[2] == 0x64 && ec.bytes[2] == 0x8a) { priv.proto_version = ALPS_PROTO_V4; - IOLog("ALPS: Found a V4 TouchPad with ID: E7=0x%02x 0x%02x 0x%02x, EC=0x%02x 0x%02x 0x%02x\n", e7.bytes[0], e7.bytes[1], e7.bytes[2], ec.bytes[0], ec.bytes[1], ec.bytes[2]); + IOLog("%s: Found a V4 TouchPad with ID: E7=0x%02x 0x%02x 0x%02x, EC=0x%02x 0x%02x 0x%02x\n", getName(), e7.bytes[0], e7.bytes[1], e7.bytes[2], ec.bytes[0], ec.bytes[1], ec.bytes[2]); } else if (e7.bytes[0] == 0x73 && e7.bytes[1] == 0x03 && e7.bytes[2] == 0x50 && ec.bytes[0] == 0x73 && (ec.bytes[1] == 0x01 || ec.bytes[1] == 0x02)) { priv.proto_version = ALPS_PROTO_V5; - IOLog("ALPS: Found a V5 Dolphin TouchPad with ID: E7=0x%02x 0x%02x 0x%02x, EC=0x%02x 0x%02x 0x%02x\n", e7.bytes[0], e7.bytes[1], e7.bytes[2], ec.bytes[0], ec.bytes[1], ec.bytes[2]); + IOLog("%s: Found a V5 Dolphin TouchPad with ID: E7=0x%02x 0x%02x 0x%02x, EC=0x%02x 0x%02x 0x%02x\n", getName(), e7.bytes[0], e7.bytes[1], e7.bytes[2], ec.bytes[0], ec.bytes[1], ec.bytes[2]); } else if (ec.bytes[0] == 0x88 && ((ec.bytes[1] & 0xf0) == 0xb0 || (ec.bytes[1] & 0xf0) == 0xc0)) { priv.proto_version = ALPS_PROTO_V7; - IOLog("ALPS: Found a V7 TouchPad with ID: E7=0x%02x 0x%02x 0x%02x, EC=0x%02x 0x%02x 0x%02x\n", e7.bytes[0], e7.bytes[1], e7.bytes[2], ec.bytes[0], ec.bytes[1], ec.bytes[2]); + IOLog("%s: Found a V7 TouchPad with ID: E7=0x%02x 0x%02x 0x%02x, EC=0x%02x 0x%02x 0x%02x\n", getName(), e7.bytes[0], e7.bytes[1], e7.bytes[2], ec.bytes[0], ec.bytes[1], ec.bytes[2]); } else if (ec.bytes[0] == 0x88 && ec.bytes[1] == 0x08) { priv.proto_version = ALPS_PROTO_V3_RUSHMORE; - IOLog("ALPS: Found a V3 Rushmore TouchPad with ID: E7=0x%02x 0x%02x 0x%02x, EC=0x%02x 0x%02x 0x%02x\n", e7.bytes[0], e7.bytes[1], e7.bytes[2], ec.bytes[0], ec.bytes[1], ec.bytes[2]); + IOLog("%s: Found a V3 Rushmore TouchPad with ID: E7=0x%02x 0x%02x 0x%02x, EC=0x%02x 0x%02x 0x%02x\n", getName(), e7.bytes[0], e7.bytes[1], e7.bytes[2], ec.bytes[0], ec.bytes[1], ec.bytes[2]); } else if (ec.bytes[0] == 0x88 && ec.bytes[1] == 0x07 && ec.bytes[2] >= 0x90 && ec.bytes[2] <= 0x9d) { priv.proto_version = ALPS_PROTO_V3; - IOLog("ALPS: Found a V3 Pinnacle TouchPad with ID: E7=0x%02x 0x%02x 0x%02x, EC=0x%02x 0x%02x 0x%02x\n", e7.bytes[0], e7.bytes[1], e7.bytes[2], ec.bytes[0], ec.bytes[1], ec.bytes[2]); + IOLog("%s: Found a V3 Pinnacle TouchPad with ID: E7=0x%02x 0x%02x 0x%02x, EC=0x%02x 0x%02x 0x%02x\n", getName(), e7.bytes[0], e7.bytes[1], e7.bytes[2], ec.bytes[0], ec.bytes[1], ec.bytes[2]); } else if (e7.bytes[0] == 0x73 && e7.bytes[1] == 0x03 && (e7.bytes[2] == 0x14 || e7.bytes[2] == 0x28)) { priv.proto_version = ALPS_PROTO_V8; - IOLog("ALPS: Found a V8 TouchPad with ID: E7=0x%02x 0x%02x 0x%02x, EC=0x%02x 0x%02x 0x%02x\n", e7.bytes[0], e7.bytes[1], e7.bytes[2], ec.bytes[0], ec.bytes[1], ec.bytes[2]); + IOLog("%s: Found a V8 TouchPad with ID: E7=0x%02x 0x%02x 0x%02x, EC=0x%02x 0x%02x 0x%02x\n", getName(), e7.bytes[0], e7.bytes[1], e7.bytes[2], ec.bytes[0], ec.bytes[1], ec.bytes[2]); } else if (e7.bytes[0] == 0x73 && e7.bytes[1] == 0x03 && e7.bytes[2] == 0xc8) { priv.proto_version = ALPS_PROTO_V9; - IOLog("ALPS: Found a unsupported V9 TouchPad with ID: E7=0x%02x 0x%02x 0x%02x, EC=0x%02x 0x%02x 0x%02x\n", e7.bytes[0], e7.bytes[1], e7.bytes[2], ec.bytes[0], ec.bytes[1], ec.bytes[2]); + IOLog("%s: Found a unsupported V9 TouchPad with ID: E7=0x%02x 0x%02x 0x%02x, EC=0x%02x 0x%02x 0x%02x\n", getName(), e7.bytes[0], e7.bytes[1], e7.bytes[2], ec.bytes[0], ec.bytes[1], ec.bytes[2]); } else { - IOLog("ALPS: Touchpad didn't match any known IDs: E7=0x%02x 0x%02x 0x%02x, EC=0x%02x 0x%02x 0x%02x ... driver will now exit\n", - e7.bytes[0], e7.bytes[1], e7.bytes[2], ec.bytes[0], ec.bytes[1], ec.bytes[2]); + IOLog("%s: Touchpad didn't match any known IDs: E7=0x%02x 0x%02x 0x%02x, EC=0x%02x 0x%02x 0x%02x ... driver will now exit\n", + getName(), e7.bytes[0], e7.bytes[1], e7.bytes[2], ec.bytes[0], ec.bytes[1], ec.bytes[2]); return kIOReturnInvalid; } @@ -3268,7 +3066,7 @@ IOReturn ApplePS2ALPSGlidePoint::identify() { // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void ApplePS2ALPSGlidePoint::setTouchPadEnable(bool enable) { - DEBUG_LOG("ALPS: setTouchpadEnable enter\n"); + DEBUG_LOG("%s: setTouchpadEnable enter\n", getName()); // // Instructs the trackpad to start or stop the reporting of data packets. // It is safe to issue this request from the interrupt/completion context. @@ -3342,22 +3140,42 @@ void ApplePS2ALPSGlidePoint::set_resolution() { setProperty(VOODOO_INPUT_PHYSICAL_MAX_X_KEY, physical_max_x, 32); setProperty(VOODOO_INPUT_PHYSICAL_MAX_Y_KEY, physical_max_y, 32); - setProperty(VOODOO_INPUT_TRANSFORM_KEY, 0ull, 32); - setProperty("VoodooInputSupported", kOSBooleanTrue); - - registerService(); - - DEBUG_LOG("VoodooPS2Trackpad: logical_max %dx%d physical_max %dx%d upmm %dx%d\n", - logical_max_x, logical_max_y, + DEBUG_LOG("%s: logical_max %dx%d physical_max %dx%d upmm %dx%d\n", + getName(), logical_max_x, logical_max_y, physical_max_x, physical_max_y, xupmm, yupmm); } +void ApplePS2ALPSGlidePoint::voodooTrackpoint(UInt32 type, SInt8 x, SInt8 y, int buttons) { + AbsoluteTime timestamp; + clock_get_uptime(×tamp); + + switch (type) { + case kIOMessageVoodooTrackpointRelativePointer: + RelativePointerEvent rpevent; + rpevent.dx = x; + rpevent.dy = y; + rpevent.buttons = buttons; + rpevent.timestamp = timestamp; + super::messageClient(kIOMessageVoodooTrackpointRelativePointer, voodooInputInstance, &rpevent, sizeof(rpevent)); + break; + case kIOMessageVoodooTrackpointScrollWheel: + ScrollWheelEvent swevent; + swevent.deltaAxis1 = -y; + swevent.deltaAxis2 = -x; + swevent.deltaAxis3 = 0; + swevent.timestamp = timestamp; + super::messageClient(kIOMessageVoodooTrackpointScrollWheel, voodooInputInstance, &swevent, sizeof(swevent)); + break; + } +} + void ApplePS2ALPSGlidePoint::alps_buttons(struct alps_fields &f) { bool prev_left = left; bool prev_right = right; bool prev_middle = middle; bool prev_left_ts = left_ts; + bool last_clicked = clicked; left = f.left; right = f.right | f.ts_right; @@ -3366,466 +3184,117 @@ void ApplePS2ALPSGlidePoint::alps_buttons(struct alps_fields &f) { AbsoluteTime timestamp; clock_get_uptime(×tamp); + RelativePointerEvent event; + event.dx = 0; + event.dy = 0; + event.timestamp = timestamp; + // Physical left button (for non-Clickpads) // Only used if trackpad is not a clickpad if (!(priv.flags & ALPS_BUTTONPAD)) { - if (left && !prev_left) - dispatchRelativePointerEvent(0, 0, 0x01, timestamp); - else if (prev_left && !left) - dispatchRelativePointerEvent(0, 0, 0x00, timestamp); + if (left && !prev_left) { + event.buttons = 0x01; + clicked = true; + } else if (prev_left && !left) { + event.buttons = 0x00; + clicked = false; + } } // Physical right button - if (right && !prev_right) - dispatchRelativePointerEvent(0, 0, 0x02, timestamp); - else if (prev_right && !right) - dispatchRelativePointerEvent(0, 0, 0x00, timestamp); + if (right && !prev_right) { + event.buttons = 0x02; + clicked = true; + } else if (prev_right && !right) { + event.buttons = 0x00; + clicked = false; + } // Physical middle button - if (middle && !prev_middle) - dispatchRelativePointerEvent(0, 0, 0x04, timestamp); - else if (prev_middle && !middle) - dispatchRelativePointerEvent(0, 0, 0x00, timestamp); - // Physical left button (Trackstick) - if (left_ts && !prev_left_ts) - dispatchRelativePointerEvent(0, 0, 0x01, timestamp); - else if (prev_left_ts && !left_ts) - dispatchRelativePointerEvent(0, 0, 0x00, timestamp); -} - -// port from VoodooPS2SynapticsTouchpad.cpp; huge credits to @usr-sse2 - -#define sqr(x) ((x) * (x)) -int ApplePS2ALPSGlidePoint::dist(int physicalFinger, int virtualFinger) { - const auto &phy = fingerStates[physicalFinger]; - const auto &virt = virtualFingerStates[virtualFinger]; - return sqr(phy.x - virt.x_avg.newest()) + sqr(phy.y - virt.y_avg.newest()); -} - -void ApplePS2ALPSGlidePoint::assignVirtualFinger(int physicalFinger) { - if (physicalFinger < 0 || physicalFinger >= MAX_TOUCHES) { - IOLog("alps_parse_hw_state: ALPS::assignVirtualFinger ERROR: invalid physical finger %d\n", physicalFinger); - return; + if (middle && !prev_middle) { + event.buttons = 0x04; + clicked = true; + } else if (prev_middle && !middle) { + event.buttons = 0x00; + clicked = false; } - for (int j = 0; j < MAX_TOUCHES; j++) { - synaptics_virtual_finger_state &vfj = virtualFingerStates[j]; - if (!vfj.touch) { - fingerStates[physicalFinger].virtualFingerIndex = j; - vfj.touch = true; - vfj.x_avg.reset(); - vfj.y_avg.reset(); - assignFingerType(vfj); - break; - } + // Physical left button (Trackstick) + if (left_ts && !prev_left_ts) { + event.buttons = 0x01; + clicked = true; + } else if (prev_left_ts && !left_ts) { + event.buttons = 0x00; + clicked = false; } -} -void ApplePS2ALPSGlidePoint::assignFingerType(synaptics_virtual_finger_state &vf) { - vf.fingerType = kMT2FingerTypeUndefined; - for (MT2FingerType i = kMT2FingerTypeIndexFinger; i < kMT2FingerTypeCount; i = (MT2FingerType)(i + 1)) - if (freeFingerTypes[i]) { - freeFingerTypes[i] = false; - vf.fingerType = i; - break; - } + if (last_clicked != clicked) + super::messageClient(kIOMessageVoodooTrackpointRelativePointer, voodooInputInstance, &event, sizeof(event)); } -void ApplePS2ALPSGlidePoint::freeAndMarkVirtualFingers() { - memset(freeFingerTypes, true, kMT2FingerTypeCount); - freeFingerTypes[kMT2FingerTypeUndefined] = false; +void ApplePS2ALPSGlidePoint::prepareVoodooInput(struct alps_fields &f, int fingers) { + for (int i = 0; i < MAX_TOUCHES; i++) // free up all virtual fingers + virtualFingerStates[i].touch = false; - for (int i = 0; i < MAX_TOUCHES; i++) { // free up all virtual fingers - auto &vfi = virtualFingerStates[i]; - vfi.touch = false; - vfi.x_avg.reset(); // maybe it should be done only for unpressed fingers? - vfi.y_avg.reset(); - vfi.pressure = 0; - } + DEBUG_LOG("%s: Amount of finger(s): %d\n", getName(), fingers); - for (int i = 0; i < clampedFingerCount; i++) { // mark virtual fingers as used - int j = fingerStates[i].virtualFingerIndex; - if (j == -1) { - IOLog("alps_parse_hw_state: WTF!? Finger %d has no virtual finger\n", i); - continue; + // limit to 4 fingers + for (int i = 0; i < min(4, fingers); i++) { + // V8 touchpads do not need workarounds for 3+ fingers + if (priv.proto_version == ALPS_PROTO_V8) { + virtualFingerStates[i].x = f.mt[i].x; + virtualFingerStates[i].y = f.mt[i].y; + } else { + if (i == 0 || i == 1) { + virtualFingerStates[i].x = f.mt[i].x; + virtualFingerStates[i].y = f.mt[i].y; + } else if (i == 2) { + virtualFingerStates[i].x = f.mt[0].x + 5; + virtualFingerStates[i].y = f.mt[0].y + 5; + } else if (i == 3) { + virtualFingerStates[i].x = f.mt[1].x - 5; + virtualFingerStates[i].y = f.mt[1].y + 5; + } } - auto &vfj = virtualFingerStates[j]; - vfj.touch = true; - freeFingerTypes[vfj.fingerType] = false; - } - - for (int i = 0; i < MAX_TOUCHES; i++) { - auto &vfi = virtualFingerStates[i]; - if (!vfi.touch) - vfi.fingerType = kMT2FingerTypeUndefined; - } -} - -static void clone(alps_hw_state &dst, const alps_hw_state &src) { - dst.x = src.x; - dst.y = src.y; - dst.z = src.z; -} -int ApplePS2ALPSGlidePoint::upperFingerIndex() const { - return fingerStates[0].y < fingerStates[1].y ? 1 : 0; -} + virtualFingerStates[i].pressure = f.pressure; + virtualFingerStates[i].touch = true; -const alps_hw_state& ApplePS2ALPSGlidePoint::upperFinger() const { - return fingerStates[upperFingerIndex()]; -} + // Only use this if trackpad is a clickpad + virtualFingerStates[0].button = priv.flags & ALPS_BUTTONPAD ? f.left : 0; -void ApplePS2ALPSGlidePoint::swapFingers(int dst, int src) { - int j = fingerStates[src].virtualFingerIndex; - const auto &vfj = virtualFingerStates[j]; - fingerStates[dst].x = vfj.x_avg.average(); - fingerStates[dst].y = vfj.y_avg.average(); - fingerStates[dst].virtualFingerIndex = j; - assignVirtualFinger(src); -} + if (virtualFingerStates[i].x > X_MAX_POSITIVE) + virtualFingerStates[i].x -= 1 << ABS_POS_BITS; + else if (virtualFingerStates[i].x == X_MAX_POSITIVE) + virtualFingerStates[i].x = XMAX; -#define FINGER_DIST 1000000 - -bool ApplePS2ALPSGlidePoint::renumberFingers() { - const auto &f0 = fingerStates[0]; - const auto &f1 = fingerStates[1]; - auto &f2 = fingerStates[2]; - auto &f3 = fingerStates[3]; - auto &f4 = fingerStates[4]; - - if (clampedFingerCount == lastFingerCount && clampedFingerCount >= 3) { - // update imaginary finger states - if (f0.virtualFingerIndex != -1 && f1.virtualFingerIndex != -1) { - if (clampedFingerCount >= 4) { - const auto &fi = upperFinger(); - const auto &fiv = virtualFingerStates[fi.virtualFingerIndex]; - for (int j = 2; j < clampedFingerCount; j++) { - auto &fj = fingerStates[j]; - fj.x += fi.x - fiv.x_avg.newest(); - fj.y += fi.y - fiv.y_avg.newest(); - fj.z = fi.z; - } - } - else if (clampedFingerCount == 3) { - const auto &f0v = virtualFingerStates[f0.virtualFingerIndex]; - const auto &f1v = virtualFingerStates[f1.virtualFingerIndex]; - auto &f2 = fingerStates[2]; - f2.x += ((f0.x - f0v.x_avg.newest()) + (f1.x - f1v.x_avg.newest())) / 2; - f2.y += ((f0.y - f0v.y_avg.newest()) + (f1.y - f1v.y_avg.newest())) / 2; - f2.z = (f0.z + f1.z) / 2; - } - } - else - IOLog("alps_parse_hw_state: WTF - have %d fingers, but first 2 don't have virtual finger\n", clampedFingerCount); - } - - // We really need to send the "no touch" event - // multiple times, because if we don't do it and return, - // gestures like desktop switching or inertial scrolling - // got stuck midway until the next touch. - //if(!lastFingerCount && !clampedFingerCount) { - // return 0; - //} - - // Finger type detection: - // We think that fingers are added beginning with the index finger, - // then middle, ring and little. - // However, when the finger count reaches 4, the lowest finger becomes thumb, - // but other fingers don't change their types. - // All fingers preserve their types during the gesture. - // Though it would be nice to see what MT2 does. - - if (clampedFingerCount == lastFingerCount && clampedFingerCount == 1) { - int i = 0; - int j = fingerStates[i].virtualFingerIndex; - int d = dist(i, j); - if (d > FINGER_DIST) { // this number was determined experimentally - // Prevent jumps by unpressing finger. Other way could be leaving the old finger pressed. - DEBUG_LOG("alps_parse_hw_state: unpressing finger: dist is %d\n", d); - auto &vfj = virtualFingerStates[j]; - vfj.x_avg.reset(); - vfj.y_avg.reset(); - vfj.pressure = 0; - vfj.fingerType = kMT2FingerTypeUndefined; - clampedFingerCount = 0; - } + if (virtualFingerStates[i].y > Y_MAX_POSITIVE) + virtualFingerStates[i].y -= 1 << ABS_POS_BITS; + else if (virtualFingerStates[i].y == Y_MAX_POSITIVE) + virtualFingerStates[i].y = YMAX; } - if (clampedFingerCount != lastFingerCount) { - if (clampedFingerCount > lastFingerCount && clampedFingerCount >= 3) { - // Skip sending touch data once because we need to wait for the next extended packet - if (wasSkipped) - wasSkipped = false; - else { - DEBUG_LOG("alps_parse_hw_state: Skip sending touch data\n"); - wasSkipped = true; - return false; - } - } - if (lastFingerCount == 0) { - // Assign to identity mapping - for (int i = 0; i < clampedFingerCount; i++) { - auto &fi = fingerStates[i]; - fi.virtualFingerIndex = i; - auto &vfi = virtualFingerStates[i]; - vfi.touch = true; - assignFingerType(vfi); - vfi.x_avg.reset(); - vfi.y_avg.reset(); - if (i >= 2) // more than 3 fingers added simultaneously - clone(fi, upperFinger()); // Copy from the upper finger - } - } - else if (clampedFingerCount > lastFingerCount && !hadLiftFinger) { - // First finger already exists - // Can add 1, 2 or 3 fingers at once - // Newly added finger is always in secondary finger packet - switch (clampedFingerCount - lastFingerCount) { - case 1: - if (lastFingerCount >= 2) - swapFingers(lastFingerCount, 1); - else // lastFingerCount = 1 - assignVirtualFinger(1); - break; - case 2: - if (lastFingerCount == 1) { // added second and third - assignVirtualFinger(1); - clone(f2, upperFinger()); // We don't know better - assignVirtualFinger(2); - } - else { // added third and fourth - swapFingers(lastFingerCount, 1); + DEBUG_LOG("%s: virtualFingerStates[0] report: x: %d, y: %d, z: %d\n", getName(), virtualFingerStates[0].x, virtualFingerStates[0].y, virtualFingerStates[0].pressure); - // add fourth - clone(f3, upperFinger()); - assignVirtualFinger(3); - } - break; - case 3: - assignVirtualFinger(1); - clone(f2, upperFinger()); - assignVirtualFinger(2); - clone(f3, upperFinger()); - assignVirtualFinger(3); - break; - case 4: - assignVirtualFinger(1); - clone(f2, upperFinger()); - assignVirtualFinger(2); - clone(f3, upperFinger()); - assignVirtualFinger(3); - clone(f4, upperFinger()); - assignVirtualFinger(4); - break; - default: - IOLog("alps_parse_hw_state: WTF!? fc=%d lfc=%d\n", clampedFingerCount, lastFingerCount); - } - } - else if (clampedFingerCount > lastFingerCount && hadLiftFinger) { - for (int i = 0; i < MAX_TOUCHES; i++) // clean virtual finger numbers - fingerStates[i].virtualFingerIndex = -1; - - int maxMinDist = 0, maxMinDistIndex = -1; - int secondMaxMinDist = 0, secondMaxMinDistIndex = -1; - - // find new physical finger for each existing virtual finger - for (int j = 0; j < MAX_TOUCHES; j++) { - if (!virtualFingerStates[j].touch) - continue; // free - int minDist = INT_MAX, minIndex = -1; - for (int i = 0; i < lastFingerCount; i++) { - if (fingerStates[i].virtualFingerIndex != -1) - continue; // already taken - int d = dist(i, j); - if (d < minDist) { - minDist = d; - minIndex = i; - } - } - if (minIndex == -1) { - IOLog("alps_parse_hw_state: WTF!? minIndex is -1\n"); - continue; - } - if (minDist > maxMinDist) { - secondMaxMinDist = maxMinDist; - secondMaxMinDistIndex = maxMinDistIndex; - maxMinDist = minDist; - maxMinDistIndex = minIndex; - } - fingerStates[minIndex].virtualFingerIndex = j; - } + clampedFingerCount = fingers; - // assign new virtual fingers for all new fingers - for (int i = 0; i < min(2, clampedFingerCount); i++) // third and fourth 'fingers' are handled separately - if (fingerStates[i].virtualFingerIndex == -1) - assignVirtualFinger(i); // here OK - - if (clampedFingerCount == 3) { - DEBUG_LOG("alps_parse_hw_state: adding third finger, maxMinDist=%d\n", maxMinDist); - f2.z = (f0.z + f1.z) / 2; - if (maxMinDist > FINGER_DIST && maxMinDistIndex >= 0) { - // i-th physical finger was replaced, save its old coordinates to the 3rd physical finger and map it to a new virtual finger. - // The third physical finger should now be mapped to the old fingerStates[i].virtualFingerIndex. - swapFingers(2, maxMinDistIndex); - DEBUG_LOG("alps_parse_hw_state: swapped, saving location\n"); - } - else { - // existing fingers didn't change or were swapped, so we don't know the location of the third finger - const auto &fj = upperFinger(); - - f2.x = fj.x; - f2.y = fj.y; - assignVirtualFinger(2); - DEBUG_LOG("alps_parse_hw_state: not swapped, taking upper finger position\n"); - } - } - else if (clampedFingerCount >= 4) { - // Is it possible that both 0 and 1 fingers were swapped with 2 and 3? - DEBUG_LOG("alps_parse_hw_state: adding third and fourth fingers, maxMinDist=%d, secondMaxMinDist=%d\n", maxMinDist, secondMaxMinDist); - f2.z = f3.z = (f0.z + f1.z) / 2; - - // Possible situations: - // 1. maxMinDist ≤ 1000000, lastFingerCount = 3 - no fingers swapped, just adding 4th finger - // 2. maxMinDist ≤ 1000000, lastFingerCount = 2 - no fingers swapped, just adding 3rd and 4th fingers - // 3. maxMinDist > 1000000, secondMaxMinDist ≤ 1000000, lastFingerCount = 3 - i'th finger was swapped with 4th, 3rd left in place (i∈{0,1}): - // 4th.xy = i'th.xy - // p2v[2] = j - // p2v[i] = next free - // 4. maxMinDist > 1000000, secondMaxMinDist > 1000000, lastFingerCount = 3 - i'th finger was swapped with 3rd and k'th finger was swapped with 4th (i,k∈{0,1}): - // is it possible that only imaginary finger was left in place?! - // 5. maxMinDist > 1000000, secondMaxMinDist ≤ 1000000, lastFingerCount = 2 - one finger swapped, one finger left in place. - - - if (maxMinDist > FINGER_DIST && maxMinDistIndex >= 0) { - if (lastFingerCount < 3) { - // i-th physical finger was replaced, save its old coordinates to the 3rd physical finger and map it to a new virtual finger. - // The third physical finger should now be mapped to the old fingerStates[i].virtualFingerIndex. - swapFingers(2, maxMinDistIndex); - if (secondMaxMinDist > FINGER_DIST && secondMaxMinDistIndex >= 0) { - // both fingers were swapped with new ones - // i-th physical finger was replaced, save its old coordinates to the 4th physical finger and map it to a new virtual finger. - // The fourth physical finger should now be mapped to the old fingerStates[i].virtualFingerIndex. - swapFingers(3, secondMaxMinDistIndex); - } - else { - // fourth finger is new - clone(f3, upperFinger()); - assignVirtualFinger(3); - } - } - else { - // i-th physical finger was replaced, save its old coordinates to the 4th physical finger and map it to a new virtual finger. - // The fourth physical finger should now be mapped to the old fingerStates[i].virtualFingerIndex. - swapFingers(3, maxMinDistIndex); - if (secondMaxMinDist > FINGER_DIST && secondMaxMinDistIndex >= 0) { - IOLog("alps_parse_hw_state: WTF, I thought it is impossible: fc=%d, lfc=%d, mdi=%d(%d), smdi=%d(%d)\n", clampedFingerCount, lastFingerCount, maxMinDist, maxMinDistIndex, secondMaxMinDist, secondMaxMinDistIndex); - } - } - DEBUG_LOG("alps_parse_hw_state: swapped, saving location\n"); - } - else { - // existing fingers didn't change or were swapped, so we don't know the location of the third and fourth fingers - const auto &fj = upperFinger(); - clone(f2, fj); - if (lastFingerCount < 3) - assignVirtualFinger(2); - clone(f3, fj); - assignVirtualFinger(3); - DEBUG_LOG("alps_parse_hw_state: not swapped, cloning existing fingers\n"); - } - if (clampedFingerCount >= 5) { - // Don't bother with 5th finger, always clone - clone(f4, upperFinger()); - assignVirtualFinger(4); - DEBUG_LOG("alps_parse_hw_state: cloning 5th finger\n"); - } - } - freeAndMarkVirtualFingers(); - } - else if (clampedFingerCount < lastFingerCount) { - // Set hadLiftFinger if lifted some fingers - // Reset hadLiftFinger if lifted all fingers - hadLiftFinger = clampedFingerCount > 0; - - // some fingers removed, need renumbering - bool used[MAX_TOUCHES]; - for (int i = 0; i < MAX_TOUCHES; i++) { // clean virtual finger numbers - fingerStates[i].virtualFingerIndex = -1; - used[i] = false; - } - for (int i = 0; i < clampedFingerCount; i++) { - // find new virtual finger number with nearest coordinates for this finger - int minDist = INT_MAX, minIndex = -1; - for (int j = 0; j < MAX_TOUCHES; j++) { - if (!virtualFingerStates[j].touch || used[j]) - continue; - int d = dist(i, j); - if (d < minDist) { - minDist = d; - minIndex = j; - } - } - fingerStates[i].virtualFingerIndex = minIndex; - if (minIndex == -1) { - IOLog("alps_parse_hw_state: WTF: renumbering failed, minIndex for %d is -1\n", i); - continue; - } - used[minIndex] = true; - } - freeAndMarkVirtualFingers(); - } - } + if (clampedFingerCount > MAX_TOUCHES) + clampedFingerCount = MAX_TOUCHES; - for (int i = 0; i < clampedFingerCount; i++) { - const auto &fi = fingerStates[i]; - DEBUG_LOG("alps_parse_hw_state: finger %d -> virtual finger %d\n", i, fi.virtualFingerIndex); - if (fi.virtualFingerIndex < 0 || fi.virtualFingerIndex >= MAX_TOUCHES) { - IOLog("alps_parse_hw_state: ERROR: invalid physical finger %d\n", fi.virtualFingerIndex); - continue; - } - synaptics_virtual_finger_state &fiv = virtualFingerStates[fi.virtualFingerIndex]; - fiv.x_avg.filter(fi.x); - fiv.y_avg.filter(fi.y); - fiv.pressure = fi.z; - // Only use this if trackpad is a clickpad - if (priv.flags & ALPS_BUTTONPAD) - fiv.button = left; - else - fiv.button = 0; - } - - // Thumb detection. Must happen after setting coordinates (filter) - if (clampedFingerCount > lastFingerCount && clampedFingerCount >= 4) { - // find the lowest finger - int lowestFingerIndex = -1; - int min_y = INT_MAX; - for (int i = 0; i < MAX_TOUCHES; i++) { - const auto &vfi = virtualFingerStates[i]; - DEBUG_LOG("alps_parse_hw_state: finger %d: touch %d, y %d\n", i, vfi.touch, vfi.y_avg.average()); - if (vfi.touch && vfi.y_avg.average() < min_y) { - lowestFingerIndex = i; - min_y = vfi.y_avg.average(); - } - } - DEBUG_LOG("alps_parse_hw_state: lowest finger: %d\n", lowestFingerIndex); - if (lowestFingerIndex == -1) - IOLog("alps_parse_hw_state: WTF?! lowest finger not found!\n"); - else { - auto &vf = virtualFingerStates[lowestFingerIndex]; - freeFingerTypes[vf.fingerType] = true; - vf.fingerType = kMT2FingerTypeThumb; - freeFingerTypes[kMT2FingerTypeThumb] = false; - } - } + if (fingers > 0) + reportVoodooInput = true; - DEBUG_LOG("alps_parse_hw_state: lastFingerCount=%d clampedFingerCount=%d left=%d\n", lastFingerCount, clampedFingerCount, left); - return true; + if (reportVoodooInput) { + if (fingers == 0 && lastFingerCount == 0) + reportVoodooInput = false; + sendTouchData(); + } } void ApplePS2ALPSGlidePoint::sendTouchData() { - // Ignore input for specified time after keyboard usage AbsoluteTime timestamp; clock_get_uptime(×tamp); uint64_t timestamp_ns; absolutetime_to_nanoseconds(timestamp, ×tamp_ns); + // Ignore input for specified time after keyboard/trackpoint usage if (timestamp_ns - keytime < maxaftertyping) return; @@ -3833,55 +3302,53 @@ void ApplePS2ALPSGlidePoint::sendTouchData() { lastFingerCount = clampedFingerCount; return; // Skip while fingers are placed on the touchpad or removed } - - static_assert(VOODOO_INPUT_MAX_TRANSDUCERS >= MAX_TOUCHES, "Trackpad supports too many fingers"); - + + static_assert(VOODOO_INPUT_MAX_TRANSDUCERS >= MAX_TOUCHES, "VoodooPS2ALPSGlidePoint: Trackpad supports too many fingers\n"); + int transducers_count = 0; - for(int i = 0; i < MAX_TOUCHES; i++) { - const auto& state = virtualFingerStates[i]; - if (!state.touch) + for (int i = 0; i < MAX_TOUCHES; i++) { + const auto &state = virtualFingerStates[i]; + if (!state.touch) { continue; + } - auto& transducer = inputEvent.transducers[transducers_count++]; - - transducer.type = FINGER; - transducer.isValid = true; - if (_forceTouchMode == FORCE_TOUCH_DISABLED || _forceTouchMode == FORCE_TOUCH_BUTTON) - transducer.supportsPressure = false; - else - transducer.supportsPressure = true; - - int posX = state.x_avg.average(); - int posY = state.y_avg.average(); - - posY = logical_max_y + 1 - posY; - - DEBUG_LOG("alps_parse_hw_state: finger[%d] x=%d y=%d raw_x=%d raw_y=%d\n", i, posX, posY, state.x_avg.average(), state.y_avg.average()); - + auto &transducer = inputEvent.transducers[transducers_count]; + transducer.previousCoordinates = transducer.currentCoordinates; - transducer.currentCoordinates.x = posX; - transducer.currentCoordinates.y = posY; + transducer.currentCoordinates.x = state.x; + transducer.currentCoordinates.y = logical_max_y + 1 - state.y; + transducer.timestamp = timestamp; - switch (_forceTouchMode) - { + transducer.isValid = true; + transducer.isTransducerActive = true; + + transducer.secondaryId = i; + transducer.fingerType = (MT2FingerType) (kMT2FingerTypeIndexFinger + (i % 4)); + transducer.type = FINGER; + + switch (_forceTouchMode) { case FORCE_TOUCH_BUTTON: // Physical button is translated into force touch instead of click + transducer.supportsPressure = true; transducer.isPhysicalButtonDown = false; transducer.currentCoordinates.pressure = state.button ? 255 : 0; break; case FORCE_TOUCH_THRESHOLD: // Force touch is touch with pressure over threshold + transducer.supportsPressure = true; transducer.isPhysicalButtonDown = state.button; transducer.currentCoordinates.pressure = state.pressure > _forceTouchPressureThreshold ? 255 : 0; break; case FORCE_TOUCH_VALUE: // Pressure is passed to system as is + transducer.supportsPressure = true; transducer.isPhysicalButtonDown = state.button; transducer.currentCoordinates.pressure = state.pressure; break; case FORCE_TOUCH_CUSTOM: // Pressure is passed, but with locking + transducer.supportsPressure = true; transducer.isPhysicalButtonDown = state.button; if (clampedFingerCount != 1) { @@ -3901,48 +3368,49 @@ void ApplePS2ALPSGlidePoint::sendTouchData() { value *= base; } } + transducer.currentCoordinates.pressure = (int) (value * 255); break; case FORCE_TOUCH_DISABLED: default: + transducer.supportsPressure = false; transducer.isPhysicalButtonDown = state.button; transducer.currentCoordinates.pressure = 0; break; - } - transducer.isTransducerActive = 1; - transducer.currentCoordinates.width = state.pressure / 2; - if (state.fingerType == kMT2FingerTypeUndefined) - IOLog("alps_parse_hw_state: WTF!? finger type is undefined\n"); - if (state.fingerType < kMT2FingerTypeUndefined || state.fingerType > kMT2FingerTypeLittleFinger) - IOLog("alps_parse_hw_state: WTF!? finger type is out of range\n"); - if (freeFingerTypes[state.fingerType]) - IOLog("alps_parse_hw_state: WTF!? finger type is marked free\n"); - transducer.fingerType = state.fingerType; - transducer.secondaryId = i; + transducers_count++; + } + + // 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 + // 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 > maxY) { + maxY = inputEvent.transducers[i].currentCoordinates.y; + newThumbIndex = i; + } + if (inputEvent.transducers[i].fingerType == kMT2FingerTypeThumb) { + currentThumbIndex = i; + } + } + inputEvent.transducers[currentThumbIndex].fingerType = inputEvent.transducers[newThumbIndex].fingerType; + inputEvent.transducers[newThumbIndex].fingerType = kMT2FingerTypeThumb; } - for (int i = 0; i < transducers_count; i++) - for (int j = i + 1; j < transducers_count; j++) - if (inputEvent.transducers[i].fingerType == inputEvent.transducers[j].fingerType) - IOLog("alps_parse_hw_state: WTF!? equal finger types\n"); - - if (transducers_count != clampedFingerCount) - IOLog("alps_parse_hw_state: WTF?! tducers_count %d clampedFingerCount %d\n", transducers_count, clampedFingerCount); - - // create new VoodooI2CMultitouchEvent inputEvent.contact_count = transducers_count; inputEvent.timestamp = timestamp; - // send the event into the multitouch interface - // send the 0 finger message only once - if (inputEvent.contact_count != 0 || lastSentFingerCount != 0) { + if (voodooInputInstance) { super::messageClient(kIOMessageVoodooInputMessage, voodooInputInstance, &inputEvent, sizeof(VoodooInputEvent)); } + lastFingerCount = clampedFingerCount; - lastSentFingerCount = inputEvent.contact_count; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -3972,8 +3440,6 @@ void ApplePS2ALPSGlidePoint::setParamPropertiesGated(OSDictionary * config) { const struct {const char *name; int *var;} int32vars[]={ {"FingerZ", &z_finger}, {"WakeDelay", &wakedelay}, - {"Resolution", &_resolution}, - {"ScrollResolution", &_scrollresolution}, {"UnitsPerMMX", &xupmm}, {"UnitsPerMMY", &yupmm}, {"MinLogicalXOverride", &minXOverride}, @@ -4054,19 +3520,6 @@ void ApplePS2ALPSGlidePoint::setParamPropertiesGated(OSDictionary * config) { } } -IOReturn ApplePS2ALPSGlidePoint::setParamProperties(OSDictionary* dict) { - ////IOReturn result = super::IOHIDevice::setParamProperties(dict); - if (_cmdGate) - { - // syncronize through workloop... - ////_cmdGate->runAction(OSMemberFunctionCast(IOCommandGate::Action, this, &VooodooPS2TouchPadBase::setParamPropertiesGated), dict); - setParamPropertiesGated(dict); - } - - return super::setParamProperties(dict); - ////return result; -} - IOReturn ApplePS2ALPSGlidePoint::setProperties(OSObject *props) { OSDictionary *dict = OSDynamicCast(OSDictionary, props); if (dict && _cmdGate) @@ -4150,7 +3603,7 @@ IOReturn ApplePS2ALPSGlidePoint::message(UInt32 type, IOService* provider, void* case kPS2M_resetTouchpad: { int *reqCode = (int *)argument; - DEBUG_LOG("ALPS::kPS2M_resetTouchpad reqCode: %d\n", *reqCode); + DEBUG_LOG("%s: kPS2M_resetTouchpad reqCode: %d\n", getName() , *reqCode); if (*reqCode == 1) { ignoreall = false; _device->lock(); diff --git a/VoodooPS2Trackpad/VoodooPS2ALPSGlidePoint.h b/VoodooPS2Trackpad/VoodooPS2ALPSGlidePoint.h index bda48106..bab4b59f 100644 --- a/VoodooPS2Trackpad/VoodooPS2ALPSGlidePoint.h +++ b/VoodooPS2Trackpad/VoodooPS2ALPSGlidePoint.h @@ -25,7 +25,6 @@ #include "ApplePS2MouseDevice.h" #include -#include #include #include "VoodooInputMultitouch/VoodooInputEvent.h" #include "VoodooPS2TrackpadCommon.h" @@ -47,144 +46,9 @@ #define DOLPHIN_PROFILE_XOFFSET 8 /* x-electrode offset */ #define DOLPHIN_PROFILE_YOFFSET 1 /* y-electrode offset */ -// -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -// 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 alps_hw_state { - int x; - int y; - int z; - int virtualFingerIndex; -}; - -struct synaptics_virtual_finger_state { - SimpleAverage x_avg; - SimpleAverage y_avg; +struct alps_virtual_finger_state { + UInt32 x; + UInt32 y; uint8_t pressure; bool touch; bool button; @@ -493,8 +357,7 @@ typedef struct ALPSStatus { // predeclure stuff struct alps_data; -class EXPORT ApplePS2ALPSGlidePoint : public IOHIPointing { - typedef IOHIPointing super; +class EXPORT ApplePS2ALPSGlidePoint : public IOService { OSDeclareDefaultStructors( ApplePS2ALPSGlidePoint ); private: @@ -510,6 +373,7 @@ class EXPORT ApplePS2ALPSGlidePoint : public IOHIPointing { VoodooInputEvent inputEvent {}; // buttons and scroll wheel + unsigned int clicked:1; unsigned int left:1; unsigned int right:1; unsigned int middle:1; @@ -525,21 +389,14 @@ class EXPORT ApplePS2ALPSGlidePoint : public IOHIPointing { uint32_t physical_max_x {0}; uint32_t physical_max_y {0}; - alps_hw_state fingerStates[MAX_TOUCHES] {}; - synaptics_virtual_finger_state virtualFingerStates[MAX_TOUCHES] {}; - bool freeFingerTypes[kMT2FingerTypeCount]; - - static_assert(MAX_TOUCHES <= kMT2FingerTypeLittleFinger, "Too many fingers for one hand"); + alps_virtual_finger_state virtualFingerStates[MAX_TOUCHES] {}; int clampedFingerCount {0}; - bool wasSkipped {false}; + int lastFingerCount; + bool reportVoodooInput; int minXOverride {-1}, minYOverride {-1}, maxXOverride {-1}, maxYOverride {-1}; - int lastFingerCount; - int lastSentFingerCount; - bool hadLiftFinger; - ForceTouchMode _forceTouchMode {FORCE_TOUCH_DISABLED}; int _forceTouchPressureThreshold {100}; @@ -553,12 +410,8 @@ class EXPORT ApplePS2ALPSGlidePoint : public IOHIPointing { uint64_t keytime {0}; bool ignoreall {false}; int z_finger {45}; - uint64_t maxaftertyping {500000000}; + uint64_t maxaftertyping {100000000}; int wakedelay {1000}; - int _resolution {2300}; - int _scrollresolution {2300}; - int _buttonCount {2}; - // HID Notification bool usb_mouse_stops_trackpad {true}; @@ -657,18 +510,10 @@ class EXPORT ApplePS2ALPSGlidePoint : public IOHIPointing { void ps2_command_short(UInt8 command); int abs(int x); void set_resolution(); + void voodooTrackpoint(UInt32 type, SInt8 x, SInt8 y, int buttons); void alps_buttons(struct alps_fields &f); - int dist(int physicalFinger, int virtualFinger); - void assignVirtualFinger(int physicalFinger); - void assignFingerType(synaptics_virtual_finger_state &vf); - void freeAndMarkVirtualFingers(); - int upperFingerIndex() const; - const alps_hw_state& upperFinger() const; - void swapFingers(int dst, int src); - /// Translates physical fingers into virtual fingers so that host software doesn't see 'jumps' and has coordinates for all fingers. - /// @return True if is ready to send finger state to host interface - bool renumberFingers(); + void prepareVoodooInput(struct alps_fields &f, int fingers); void sendTouchData(); virtual void initTouchPad(); @@ -681,14 +526,6 @@ class EXPORT ApplePS2ALPSGlidePoint : public IOHIPointing { void notificationHIDAttachedHandlerGated(IOService * newService, IONotifier * notifier); bool notificationHIDAttachedHandler(void * refCon, IOService * newService, IONotifier * notifier); -protected: - IOItemCount buttonCount() override; - IOFixed resolution() override; - inline void dispatchRelativePointerEventX(int dx, int dy, UInt32 buttonState, uint64_t now) - { dispatchRelativePointerEvent(dx, dy, buttonState, *(AbsoluteTime*)&now); } - inline void dispatchScrollWheelEventX(short deltaAxis1, short deltaAxis2, short deltaAxis3, uint64_t now) - { dispatchScrollWheelEvent(deltaAxis1, deltaAxis2, deltaAxis3, *(AbsoluteTime*)&now); } - public: bool init(OSDictionary * dict) override; ApplePS2ALPSGlidePoint * probe(IOService *provider, SInt32 *score) override; @@ -696,10 +533,6 @@ class EXPORT ApplePS2ALPSGlidePoint : public IOHIPointing { 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; diff --git a/VoodooPS2Trackpad/VoodooPS2Trackpad-Info.plist b/VoodooPS2Trackpad/VoodooPS2Trackpad-Info.plist index 1248f964..ea4f99b2 100644 --- a/VoodooPS2Trackpad/VoodooPS2Trackpad-Info.plist +++ b/VoodooPS2Trackpad/VoodooPS2Trackpad-Info.plist @@ -78,11 +78,7 @@ ProcessUSBMouseStopsTrackpad QuietTimeAfterTyping - 500000000 - Resolution - 400 - ScrollResolution - 400 + 100000000 USBMouseStopsTrackpad 0 UnitsPerMMX From 67cfa83b91c04e3207fc0b20d8be8eeb2010decf Mon Sep 17 00:00:00 2001 From: SkyrilHD Date: Mon, 4 Jul 2022 18:59:28 +0200 Subject: [PATCH 069/101] Set IOProbeScore to 1500 to fix newer ALPS touchpads (#51) --- 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 ea4f99b2..9667a434 100644 --- a/VoodooPS2Trackpad/VoodooPS2Trackpad-Info.plist +++ b/VoodooPS2Trackpad/VoodooPS2Trackpad-Info.plist @@ -29,7 +29,7 @@ IOClass ApplePS2ALPSGlidePoint IOProbeScore - 6000 + 1500 IOProviderClass ApplePS2MouseDevice Platform Profile From fdb8be58ac0b5c4c76b1bfe12f7c88b63fff1e10 Mon Sep 17 00:00:00 2001 From: PMheart <17109513+PMheart@users.noreply.github.com> Date: Mon, 1 Aug 2022 17:25:34 +0200 Subject: [PATCH 070/101] Fix variable shadowing (#52) closes https://github.com/acidanthera/bugtracker/issues/2028 closes https://github.com/acidanthera/bugtracker/issues/2025 closes https://github.com/acidanthera/bugtracker/issues/2027 --- VoodooPS2Controller/VoodooPS2Controller.cpp | 12 ++++---- VoodooPS2Keyboard/VoodooPS2Keyboard.cpp | 6 ++-- .../VoodooPS2SynapticsTouchPad.cpp | 30 +++++++++---------- 3 files changed, 24 insertions(+), 24 deletions(-) diff --git a/VoodooPS2Controller/VoodooPS2Controller.cpp b/VoodooPS2Controller/VoodooPS2Controller.cpp index 8c80c62f..a7f6e1ac 100644 --- a/VoodooPS2Controller/VoodooPS2Controller.cpp +++ b/VoodooPS2Controller/VoodooPS2Controller.cpp @@ -654,22 +654,22 @@ bool ApplePS2Controller::start(IOService * provider) propertyMatch = propertyMatching(_deliverNotification, kOSBooleanTrue); if (propertyMatch != NULL) { - IOServiceMatchingNotificationHandler notificationHandlerPublish = OSMemberFunctionCast(IOServiceMatchingNotificationHandler, this, &ApplePS2Controller::notificationHandlerPublish); + IOServiceMatchingNotificationHandler publishHandler = OSMemberFunctionCast(IOServiceMatchingNotificationHandler, this, &ApplePS2Controller::notificationHandlerPublish); // // Register notifications for availability of any IOService objects wanting to consume our message events // _publishNotify = addMatchingNotification(gIOFirstPublishNotification, propertyMatch, - notificationHandlerPublish, + publishHandler, this, 0, 10000); - IOServiceMatchingNotificationHandler notificationHandlerTerminate = OSMemberFunctionCast(IOServiceMatchingNotificationHandler, this, &ApplePS2Controller::notificationHandlerTerminate); + IOServiceMatchingNotificationHandler terminateHandler = OSMemberFunctionCast(IOServiceMatchingNotificationHandler, this, &ApplePS2Controller::notificationHandlerTerminate); _terminateNotify = addMatchingNotification(gIOTerminatedNotification, propertyMatch, - notificationHandlerTerminate, + terminateHandler, this, 0, 10000); @@ -2001,8 +2001,8 @@ void ApplePS2Controller::dispatchMessageGated(int* message, void* data) break; default: - int dispatchMessage = kPS2M_notifyKeyTime; - dispatchMessageGated(&dispatchMessage, &(pInfo->time)); + int dispatchMsg = kPS2M_notifyKeyTime; + dispatchMessageGated(&dispatchMsg, &(pInfo->time)); } } } diff --git a/VoodooPS2Keyboard/VoodooPS2Keyboard.cpp b/VoodooPS2Keyboard/VoodooPS2Keyboard.cpp index 5847e2b4..5ddb523f 100644 --- a/VoodooPS2Keyboard/VoodooPS2Keyboard.cpp +++ b/VoodooPS2Keyboard/VoodooPS2Keyboard.cpp @@ -1516,12 +1516,12 @@ bool ApplePS2Keyboard::dispatchKeyboardEventWithPacket(const UInt8* packet) // Fn+F2 generates e0 ab and so does Fn+F3 (we will null those out in ps2 map) static unsigned keys[] = { 0x2a, 0x1d }; // if Option key is down don't pull up on the Shift keys - int start = checkModifierState(kMaskLeftWindows) ? 1 : 0; - for (int i = start; i < countof(keys); i++) + int state = checkModifierState(kMaskLeftWindows) ? 1 : 0; + for (int i = state; i < countof(keys); i++) if (KBV_IS_KEYDOWN(keys[i])) dispatchKeyboardEventX(_PS2ToADBMap[keys[i]], false, now_abs); dispatchKeyboardEventX(keyCode == 0x4e ? 0x90 : 0x91, goingDown, now_abs); - for (int i = start; i < countof(keys); i++) + for (int i = state; i < countof(keys); i++) if (KBV_IS_KEYDOWN(keys[i])) dispatchKeyboardEventX(_PS2ToADBMap[keys[i]], true, now_abs); keyCode = 0; diff --git a/VoodooPS2Trackpad/VoodooPS2SynapticsTouchPad.cpp b/VoodooPS2Trackpad/VoodooPS2SynapticsTouchPad.cpp index c6fce205..af1a1695 100644 --- a/VoodooPS2Trackpad/VoodooPS2SynapticsTouchPad.cpp +++ b/VoodooPS2Trackpad/VoodooPS2SynapticsTouchPad.cpp @@ -964,22 +964,22 @@ void ApplePS2SynapticsTouchPad::synaptics_parse_hw_state(const UInt8 buf[]) - UInt32 buttonsraw = buf[0] & 0x03; // mask for just R L - UInt32 buttons = buttonsraw; + UInt32 btnsraw = buf[0] & 0x03; // mask for just R L + UInt32 btn = btnsraw; - UInt32 passbuttons = buf[1] & 0x7; // mask for just M R L + UInt32 passbtns = buf[1] & 0x7; // mask for just M R L // if there are buttons set in the last pass through packet, then be sure // they are set in any trackpad dispatches. // otherwise, you might see double clicks that aren't there - buttons |= passbuttons; - lastbuttons = buttons; + btn |= passbtns; + lastbuttons = btn; // New Lenovo clickpads do not have buttons, so LR in packet byte 1 is zero and thus // passbuttons is 0. Instead we need to check the trackpad buttons in byte 0 and byte 3 // However for clickpads that would miss right clicks, so use the last clickbuttons that // were saved. - UInt32 combinedButtons = buttons | ((buf[0] & 0x3) | (buf[3] & 0x3)) | _clickbuttons | thinkpadButtonState; + UInt32 combinedButtons = btn | ((buf[0] & 0x3) | (buf[3] & 0x3)) | _clickbuttons | thinkpadButtonState; SInt32 dx = ((buf[1] & 0x10) ? 0xffffff00 : 0 ) | buf[4]; SInt32 dy = ((buf[1] & 0x20) ? 0xffffff00 : 0 ) | buf[5]; @@ -1228,14 +1228,14 @@ bool ApplePS2SynapticsTouchPad::renumberFingers() { else if (clampedFingerCount == 3) { const auto &f0v = virtualFingerStates[f0.virtualFingerIndex]; const auto &f1v = virtualFingerStates[f1.virtualFingerIndex]; - auto &f2 = fingerStates[2]; - f2.x += ((f0.x - f0v.x_avg.newest()) + (f1.x - f1v.x_avg.newest())) / 2; - f2.y += ((f0.y - f0v.y_avg.newest()) + (f1.y - f1v.y_avg.newest())) / 2; - f2.z = (f0.z + f1.z) / 2; - f2.w = (f0.w + f1.w) / 2; - - clip_no_update_limits(f2.x, logical_min_x, logical_max_x, margin_size_x); - clip_no_update_limits(f2.y, logical_min_y, logical_max_y, margin_size_y); + auto &fs2 = fingerStates[2]; + fs2.x += ((f0.x - f0v.x_avg.newest()) + (f1.x - f1v.x_avg.newest())) / 2; + fs2.y += ((f0.y - f0v.y_avg.newest()) + (f1.y - f1v.y_avg.newest())) / 2; + fs2.z = (f0.z + f1.z) / 2; + fs2.w = (f0.w + f1.w) / 2; + + clip_no_update_limits(fs2.x, logical_min_x, logical_max_x, margin_size_x); + clip_no_update_limits(fs2.y, logical_min_y, logical_max_y, margin_size_y); } } else @@ -1630,7 +1630,7 @@ void ApplePS2SynapticsTouchPad::sendTouchData() { } else { double base = ((double) (state.pressure - _forceTouchCustomUpThreshold)) / ((double) (_forceTouchCustomDownThreshold - _forceTouchCustomUpThreshold)); value = 1; - for (int i = 0; i < _forceTouchCustomPower; ++i) { + for (int j = 0; j < _forceTouchCustomPower; ++j) { value *= base; } } From 4d8fd019b01d276e8c6acbcbb1e7c36d0890fcb1 Mon Sep 17 00:00:00 2001 From: Andrey1970AppleLife Date: Sat, 6 Aug 2022 17:09:45 +0300 Subject: [PATCH 071/101] Bump version --- Changelog.md | 3 +++ VoodooPS2Controller.xcodeproj/project.pbxproj | 4 ++-- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/Changelog.md b/Changelog.md index 071c2371..174366f4 100644 --- a/Changelog.md +++ b/Changelog.md @@ -1,5 +1,8 @@ VoodooPS2 Changelog ============================ +#### v2.3.0 +- Fixed variable shadowing + #### v2.2.9 - Improved stability of ALPS touchpads - V8 touchpads can pass all four fingers to VoodooInput natively diff --git a/VoodooPS2Controller.xcodeproj/project.pbxproj b/VoodooPS2Controller.xcodeproj/project.pbxproj index 5c50f9a3..98d9325f 100644 --- a/VoodooPS2Controller.xcodeproj/project.pbxproj +++ b/VoodooPS2Controller.xcodeproj/project.pbxproj @@ -767,7 +767,7 @@ KERNEL_FRAMEWORK_HEADERS = "$(PROJECT_DIR)/MacKernelSDK/Headers"; "LLVM_LTO[arch=x86_64]" = YES; MACOSX_DEPLOYMENT_TARGET = 10.11; - MODULE_VERSION = 2.2.9; + MODULE_VERSION = 2.3.0; ONLY_ACTIVE_ARCH = YES; "OTHER_LDFLAGS[arch=x86_64]" = "-dead_strip"; PRODUCT_NAME = VoodooPS2Controller; @@ -822,7 +822,7 @@ KERNEL_FRAMEWORK_HEADERS = "$(PROJECT_DIR)/MacKernelSDK/Headers"; "LLVM_LTO[arch=x86_64]" = YES; MACOSX_DEPLOYMENT_TARGET = 10.11; - MODULE_VERSION = 2.2.9; + MODULE_VERSION = 2.3.0; "OTHER_LDFLAGS[arch=x86_64]" = "-dead_strip"; PRODUCT_NAME = VoodooPS2Controller; SDKROOT = macosx; From 15fd4cd5cb97dd8dc2089913d3a01fe81cd50474 Mon Sep 17 00:00:00 2001 From: Andrey1970AppleLife Date: Mon, 5 Sep 2022 19:38:15 +0300 Subject: [PATCH 072/101] 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 98d9325f..70b4d681 100644 --- a/VoodooPS2Controller.xcodeproj/project.pbxproj +++ b/VoodooPS2Controller.xcodeproj/project.pbxproj @@ -767,7 +767,7 @@ KERNEL_FRAMEWORK_HEADERS = "$(PROJECT_DIR)/MacKernelSDK/Headers"; "LLVM_LTO[arch=x86_64]" = YES; MACOSX_DEPLOYMENT_TARGET = 10.11; - MODULE_VERSION = 2.3.0; + MODULE_VERSION = 2.3.1; ONLY_ACTIVE_ARCH = YES; "OTHER_LDFLAGS[arch=x86_64]" = "-dead_strip"; PRODUCT_NAME = VoodooPS2Controller; @@ -822,7 +822,7 @@ KERNEL_FRAMEWORK_HEADERS = "$(PROJECT_DIR)/MacKernelSDK/Headers"; "LLVM_LTO[arch=x86_64]" = YES; MACOSX_DEPLOYMENT_TARGET = 10.11; - MODULE_VERSION = 2.3.0; + MODULE_VERSION = 2.3.1; "OTHER_LDFLAGS[arch=x86_64]" = "-dead_strip"; PRODUCT_NAME = VoodooPS2Controller; SDKROOT = macosx; From 2f0d204cd1cda1a9925b722ae7f7126cdaab2fae Mon Sep 17 00:00:00 2001 From: Die Peter Pan Date: Thu, 29 Sep 2022 11:46:51 +0200 Subject: [PATCH 073/101] Replace kDP_SetDefaultsAndDisable with kDP_SetDefaults to fix keyboard disabled in some UEFI (#53) --- VoodooPS2Keyboard/VoodooPS2Keyboard.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VoodooPS2Keyboard/VoodooPS2Keyboard.cpp b/VoodooPS2Keyboard/VoodooPS2Keyboard.cpp index 5ddb523f..fe47247e 100644 --- a/VoodooPS2Keyboard/VoodooPS2Keyboard.cpp +++ b/VoodooPS2Keyboard/VoodooPS2Keyboard.cpp @@ -1923,7 +1923,7 @@ void ApplePS2Keyboard::setKeyboardEnable(bool enable) // (keyboard enable/disable command) TPS2Request<2> request; request.commands[0].command = kPS2C_WriteDataPort; - request.commands[0].inOrOut = enable ? kDP_Enable : kDP_SetDefaultsAndDisable; + request.commands[0].inOrOut = enable ? kDP_Enable : kDP_SetDefaults; request.commands[1].command = kPS2C_ReadDataPortAndCompare; request.commands[1].inOrOut = kSC_Acknowledge; request.commandsCount = 2; From fffa5fe3a2b1c66ce97f12ca3cabd2e8142dcc94 Mon Sep 17 00:00:00 2001 From: Vitaly Cheptsov <4348897+vit9696@users.noreply.github.com> Date: Thu, 29 Sep 2022 12:47:37 +0300 Subject: [PATCH 074/101] Sync changelog --- Changelog.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Changelog.md b/Changelog.md index 174366f4..f8591240 100644 --- a/Changelog.md +++ b/Changelog.md @@ -1,5 +1,8 @@ VoodooPS2 Changelog ============================ +#### v2.3.1 +- Fixed disabled keyboard after reboot + #### v2.3.0 - Fixed variable shadowing From 18853a1b634cff27e2a5b4075877490ee1fe9869 Mon Sep 17 00:00:00 2001 From: Andrey1970AppleLife Date: Wed, 5 Oct 2022 14:23:15 +0300 Subject: [PATCH 075/101] 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 70b4d681..a5807c86 100644 --- a/VoodooPS2Controller.xcodeproj/project.pbxproj +++ b/VoodooPS2Controller.xcodeproj/project.pbxproj @@ -767,7 +767,7 @@ KERNEL_FRAMEWORK_HEADERS = "$(PROJECT_DIR)/MacKernelSDK/Headers"; "LLVM_LTO[arch=x86_64]" = YES; MACOSX_DEPLOYMENT_TARGET = 10.11; - MODULE_VERSION = 2.3.1; + MODULE_VERSION = 2.3.2; ONLY_ACTIVE_ARCH = YES; "OTHER_LDFLAGS[arch=x86_64]" = "-dead_strip"; PRODUCT_NAME = VoodooPS2Controller; @@ -822,7 +822,7 @@ KERNEL_FRAMEWORK_HEADERS = "$(PROJECT_DIR)/MacKernelSDK/Headers"; "LLVM_LTO[arch=x86_64]" = YES; MACOSX_DEPLOYMENT_TARGET = 10.11; - MODULE_VERSION = 2.3.1; + MODULE_VERSION = 2.3.2; "OTHER_LDFLAGS[arch=x86_64]" = "-dead_strip"; PRODUCT_NAME = VoodooPS2Controller; SDKROOT = macosx; From ef5f50f5a022f30f61681e215f8d0404dc2cddc9 Mon Sep 17 00:00:00 2001 From: Katharine Chui Date: Mon, 5 Dec 2022 02:09:07 +0800 Subject: [PATCH 076/101] Add kernel parameter for kbd(port 0) only mode (#55) --- VoodooPS2Controller/VoodooPS2Controller.cpp | 53 +++++++++++++++------ VoodooPS2Controller/VoodooPS2Controller.h | 1 + 2 files changed, 39 insertions(+), 15 deletions(-) diff --git a/VoodooPS2Controller/VoodooPS2Controller.cpp b/VoodooPS2Controller/VoodooPS2Controller.cpp index a7f6e1ac..1f454485 100644 --- a/VoodooPS2Controller/VoodooPS2Controller.cpp +++ b/VoodooPS2Controller/VoodooPS2Controller.cpp @@ -378,7 +378,8 @@ void ApplePS2Controller::resetController(bool wakeup) writeCommandPort(kCP_DisableKeyboardClock); writeCommandPort(kCP_DisableMouseClock); flushDataPort(); - writeCommandPort(kCP_EnableMouseClock); + if (!_kbdOnly) + writeCommandPort(kCP_EnableMouseClock); writeCommandPort(kCP_EnableKeyboardClock); // Read current command writeCommandPort(kCP_GetCommandByte); @@ -387,13 +388,16 @@ void ApplePS2Controller::resetController(bool wakeup) // Issue Test Controller to try to reset device writeCommandPort(kCP_TestController); readDataPort(kPS2KbdIdx); - readDataPort(kPS2AuxIdx); + if (!_kbdOnly) + readDataPort(kPS2AuxIdx); // Issue Test Keyboard Port to try to reset device writeCommandPort(kCP_TestKeyboardPort); readDataPort(kPS2KbdIdx); // Issue Test Mouse Port to try to reset device - writeCommandPort(kCP_TestMousePort); - readDataPort(kPS2AuxIdx); + if (!_kbdOnly) { + writeCommandPort(kCP_TestMousePort); + readDataPort(kPS2AuxIdx); + } _suppressTimeout = false; // @@ -403,7 +407,10 @@ void ApplePS2Controller::resetController(bool wakeup) // asynchronous data arrival for key/mouse events). We call the read/write // port routines directly, since no other thread will conflict with us. // - commandByte &= ~(kCB_EnableKeyboardIRQ | kCB_EnableMouseIRQ | kCB_DisableMouseClock | kCB_DisableMouseClock); + if (!_kbdOnly) + commandByte &= ~(kCB_EnableKeyboardIRQ | kCB_EnableMouseIRQ | kCB_DisableMouseClock | kCB_DisableKeyboardClock); + else + commandByte &= ~(kCB_EnableKeyboardIRQ | kCB_EnableMouseIRQ | kCB_DisableKeyboardClock); commandByte |= kCB_TranslateMode; writeCommandPort(kCP_SetCommandByte); writeDataPort(commandByte); @@ -415,8 +422,13 @@ void ApplePS2Controller::resetController(bool wakeup) } else if (!wakeup) { - _muxPresent = setMuxMode(true); - _nubsCount = _muxPresent ? kPS2MuxMaxIdx : kPS2AuxMaxIdx; + if (!_kbdOnly){ + _muxPresent = setMuxMode(true); + _nubsCount = _muxPresent ? kPS2MuxMaxIdx : kPS2AuxMaxIdx; + }else{ + _muxPresent = false; + _nubsCount = 1; + } } resetDevices(); @@ -440,9 +452,11 @@ void ApplePS2Controller::resetDevices() if (!_muxPresent) { // Reset aux device - writeCommandPort(kCP_TransmitToMouse); - writeDataPort(kDP_SetDefaultsAndDisable); - readDataPort(kPS2AuxIdx); // (discard acknowledge; success irrelevant) + if(!_kbdOnly){ + writeCommandPort(kCP_TransmitToMouse); + writeDataPort(kDP_SetDefaultsAndDisable); + readDataPort(kPS2AuxIdx); // (discard acknowledge; success irrelevant) + } return; } @@ -525,7 +539,9 @@ bool ApplePS2Controller::start(IOService * provider) queue_enter(&_keyboardQueueUnused, &_keyboardQueueAlloc[index], KeyboardQueueElement *, chain); #endif //DEBUGGER_SUPPORT - + + PE_parse_boot_argn("ps2kbdonly", &_kbdOnly, sizeof(_kbdOnly)); + // // Reset and clean the 8042 keyboard/mouse controller. // @@ -632,7 +648,7 @@ bool ApplePS2Controller::start(IOService * provider) OSSafeReleaseNULL(_devices[kPS2KbdIdx]); goto fail; } - + for (size_t i = kPS2AuxIdx; i < _nubsCount; i++) { _devices[i] = OSTypeAlloc(ApplePS2MouseDevice); @@ -1641,7 +1657,8 @@ bool ApplePS2Controller::doEscape(UInt8 scancode) while (inb(kCommandPort) & kInputBusy) IODelay(kDataDelay); IODelay(kDataDelay); - outb(kCommandPort, kCP_EnableMouseClock); + if(!_kbdOnly) + outb(kCommandPort, kCP_EnableMouseClock); releaseModifiers = true; } @@ -1876,7 +1893,10 @@ void ApplePS2Controller::setPowerStateGated( UInt32 powerState ) } DEBUG_LOG("%s: setCommandByte for wake 1\n", getName()); - setCommandByte(0, kCB_DisableKeyboardClock | kCB_DisableMouseClock | kCB_EnableKeyboardIRQ | kCB_EnableMouseIRQ); + if (!_kbdOnly) + setCommandByte(0, kCB_DisableKeyboardClock | kCB_DisableMouseClock | kCB_EnableKeyboardIRQ | kCB_EnableMouseIRQ); + else + setCommandByte(0, kCB_DisableKeyboardClock | kCB_EnableKeyboardIRQ | kCB_EnableMouseIRQ); // 2. Unblock the request queue and wake up all driver threads // that were blocked by submitRequest(). @@ -1901,7 +1921,10 @@ void ApplePS2Controller::setPowerStateGated( UInt32 powerState ) // 4. Now safe to enable the IRQs... DEBUG_LOG("%s: setCommandByte for wake 2\n", getName()); - setCommandByte(kCB_EnableKeyboardIRQ | kCB_EnableMouseIRQ | kCB_SystemFlag, 0); + if (!_kbdOnly) + setCommandByte(kCB_EnableKeyboardIRQ | kCB_EnableMouseIRQ | kCB_SystemFlag, 0); + else + setCommandByte(kCB_EnableKeyboardIRQ | kCB_SystemFlag, 0); --_ignoreInterrupts; break; diff --git a/VoodooPS2Controller/VoodooPS2Controller.h b/VoodooPS2Controller/VoodooPS2Controller.h index 2503ff54..ea8d8ee6 100644 --- a/VoodooPS2Controller/VoodooPS2Controller.h +++ b/VoodooPS2Controller/VoodooPS2Controller.h @@ -284,6 +284,7 @@ class EXPORT ApplePS2Controller : public IOService const OSSymbol* _deliverNotification {nullptr}; int _resetControllerFlag {RESET_CONTROLLER_ON_BOOT | RESET_CONTROLLER_ON_WAKEUP}; + bool _kbdOnly {0}; virtual PS2InterruptResult _dispatchDriverInterrupt(size_t port, UInt8 data); virtual void dispatchDriverInterrupt(size_t port, UInt8 data); From c41396609ece845231de0071f34d75c8d479d3d0 Mon Sep 17 00:00:00 2001 From: Vitaly Cheptsov <4348897+vit9696@users.noreply.github.com> Date: Sun, 4 Dec 2022 21:10:36 +0300 Subject: [PATCH 077/101] Sync changelog --- Changelog.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Changelog.md b/Changelog.md index f8591240..aaf2210f 100644 --- a/Changelog.md +++ b/Changelog.md @@ -1,5 +1,8 @@ VoodooPS2 Changelog ============================ +#### v2.3.2 +- Added `ps2kbdonly=1` argument not to disable touchpad line on reboot, thx @Kethen + #### v2.3.1 - Fixed disabled keyboard after reboot From dec58cca5c1792e3f7c6fdee3d937e45d3e94429 Mon Sep 17 00:00:00 2001 From: Andrey1970AppleLife Date: Wed, 7 Dec 2022 01:28:27 +0300 Subject: [PATCH 078/101] 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 a5807c86..9981c159 100644 --- a/VoodooPS2Controller.xcodeproj/project.pbxproj +++ b/VoodooPS2Controller.xcodeproj/project.pbxproj @@ -767,7 +767,7 @@ KERNEL_FRAMEWORK_HEADERS = "$(PROJECT_DIR)/MacKernelSDK/Headers"; "LLVM_LTO[arch=x86_64]" = YES; MACOSX_DEPLOYMENT_TARGET = 10.11; - MODULE_VERSION = 2.3.2; + MODULE_VERSION = 2.3.3; ONLY_ACTIVE_ARCH = YES; "OTHER_LDFLAGS[arch=x86_64]" = "-dead_strip"; PRODUCT_NAME = VoodooPS2Controller; @@ -822,7 +822,7 @@ KERNEL_FRAMEWORK_HEADERS = "$(PROJECT_DIR)/MacKernelSDK/Headers"; "LLVM_LTO[arch=x86_64]" = YES; MACOSX_DEPLOYMENT_TARGET = 10.11; - MODULE_VERSION = 2.3.2; + MODULE_VERSION = 2.3.3; "OTHER_LDFLAGS[arch=x86_64]" = "-dead_strip"; PRODUCT_NAME = VoodooPS2Controller; SDKROOT = macosx; From f76cb96f8481fe43fa859539032e195898e01250 Mon Sep 17 00:00:00 2001 From: Avery Black Date: Tue, 27 Dec 2022 13:37:46 -0800 Subject: [PATCH 079/101] Refactor Synaptics driver (#54) --- Docs/ACPI/SSDT-Thinkpad_Clickpad.dsl | 27 +- Docs/ACPI/SSDT-Thinkpad_Trackpad.dsl | 32 +- VoodooPS2Controller.xcodeproj/project.pbxproj | 18 +- .../xcschemes/VoodooPS2Controller.xcscheme | 2 +- .../xcschemes/VoodooPS2Keyboard.xcscheme | 2 +- .../xcschemes/VoodooPS2Mouse.xcscheme | 2 +- .../xcschemes/VoodooPS2Trackpad.xcscheme | 2 +- .../VoodooPS2SynapticsTouchPad.cpp | 1165 ++++++----------- .../VoodooPS2SynapticsTouchPad.h | 373 +++--- .../VoodooPS2Trackpad-Info.plist | 67 +- VoodooPS2Trackpad/VoodooPS2TrackpadCommon.h | 132 ++ 11 files changed, 730 insertions(+), 1092 deletions(-) diff --git a/Docs/ACPI/SSDT-Thinkpad_Clickpad.dsl b/Docs/ACPI/SSDT-Thinkpad_Clickpad.dsl index f0db949c..500c8ffb 100644 --- a/Docs/ACPI/SSDT-Thinkpad_Clickpad.dsl +++ b/Docs/ACPI/SSDT-Thinkpad_Clickpad.dsl @@ -20,28 +20,19 @@ DefinitionBlock ("", "SSDT", 2, "ACDT", "ps2", 0) { "Synaptics TouchPad", Package() { - "BogusDeltaThreshX", 800, - "BogusDeltaThreshY", 800, - "Clicking", ">y", - "DragLockTempMask", 0x40004, - "FakeMiddleButton", ">n", "HWResetOnStart", ">y", - //"ForcePassThrough", ">y", - //"SkipPassThrough", ">y", - "PalmNoAction When Typing", ">y", - "ScrollResolution", 800, - "SmoothInput", ">y", - "UnsmoothInput", ">y", - "Thinkpad", ">y", - "EdgeBottom", 0, + "QuietTimeAfterTyping", 500000000, "FingerZ", 30, - "MaxTapTime", 100000000, "MouseMultiplierX", 2, "MouseMultiplierY", 2, - "MouseScrollMultiplierX", 2, - "MouseScrollMultiplierY", 2, - //"TrackpointScrollYMultiplier", 1, //Change this value to 0xFFFF in order to inverse the vertical scroll direction of the Trackpoint when holding the middle mouse button. - //"TrackpointScrollXMultiplier", 1, //Change this value to 0xFFFF in order to inverse the horizontal scroll direction of the Trackpoint when holding the middle mouse button. + "MouseDivisorX", 1, + "MouseDivisorY", 1, + // Change multipliers to 0xFFFE in order to inverse the scroll direction + // of the Trackpoint when holding the middle mouse button. + "TrackpointScrollXMultiplier", 2, + "TrackpointScrollYMultiplier", 2, + "TrackpointScrollXDivisor", 1, + "TrackpointScrollYDivisor", 1 }, }) } diff --git a/Docs/ACPI/SSDT-Thinkpad_Trackpad.dsl b/Docs/ACPI/SSDT-Thinkpad_Trackpad.dsl index ab19ee76..89dbfd25 100644 --- a/Docs/ACPI/SSDT-Thinkpad_Trackpad.dsl +++ b/Docs/ACPI/SSDT-Thinkpad_Trackpad.dsl @@ -21,35 +21,19 @@ DefinitionBlock ("", "SSDT", 2, "ACDT", "ps2", 0) { "Synaptics TouchPad", Package() { - "BogusDeltaThreshX", 100, - "BogusDeltaThreshY", 100, - "Clicking", ">y", - "DragLockTempMask", 0x40004, - "FakeMiddleButton", ">n", "HWResetOnStart", ">y", - //"ForcePassThrough", ">y", - //"SkipPassThrough", ">y", "PalmNoAction When Typing", ">y", - "ScrollResolution", 800, - "SmoothInput", ">y", - "UnsmoothInput", ">y", - "Thinkpad", ">y", - "DivisorX", 1, - "DivisorY", 1, "FingerZ", 47, - "MaxTapTime", 100000000, - "MomentumScrollThreshY", 16, "MouseMultiplierX", 8, "MouseMultiplierY", 8, - "MouseScrollMultiplierX", 2, - "MouseScrollMultiplierY", 2, - "MultiFingerHorizontalDivisor", 4, - "MultiFingerVerticalDivisor", 4, - "Resolution", 3200, - "ScrollDeltaThreshX", 10, - "ScrollDeltaThreshY", 10, - //"TrackpointScrollYMultiplier", 1, //Change this value to 0xFFFF in order to inverse the vertical scroll direction of the Trackpoint when holding the middle mouse button. - //"TrackpointScrollXMultiplier", 1, //Change this value to 0xFFFF in order to inverse the horizontal scroll direction of the Trackpoint when holding the middle mouse button. + "MouseDivisorX", 1, + "MouseDivisorY", 1, + // Change multipliers to 0xFFFE in order to inverse the scroll direction + // of the Trackpoint when holding the middle mouse button. + "TrackpointScrollXMultiplier", 2, + "TrackpointScrollYMultiplier", 2, + "TrackpointScrollXDivisor", 1, + "TrackpointScrollYDivisor", 1 }, }) } diff --git a/VoodooPS2Controller.xcodeproj/project.pbxproj b/VoodooPS2Controller.xcodeproj/project.pbxproj index 9981c159..5dbb466b 100644 --- a/VoodooPS2Controller.xcodeproj/project.pbxproj +++ b/VoodooPS2Controller.xcodeproj/project.pbxproj @@ -494,7 +494,7 @@ 84167808161B55B2002C60E6 /* Project object */ = { isa = PBXProject; attributes = { - LastUpgradeCheck = 1240; + LastUpgradeCheck = 1320; ORGANIZATIONNAME = Acidanthera; }; buildConfigurationList = 8416780B161B55B2002C60E6 /* Build configuration list for PBXProject "VoodooPS2Controller" */; @@ -834,6 +834,9 @@ 84167825161B55B2002C60E6 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { + CLANG_ANALYZER_DEADCODE_DEADSTORES = YES; + CLANG_ANALYZER_DIVIDE_BY_ZERO = YES; + CLANG_ANALYZER_NULL_DEREFERENCE = YES; CLANG_ENABLE_OBJC_WEAK = YES; COMBINE_HIDPI_IMAGES = YES; GCC_PRECOMPILE_PREFIX_HEADER = YES; @@ -846,6 +849,7 @@ OTHER_CFLAGS = "-fno-stack-protector"; PRODUCT_BUNDLE_IDENTIFIER = as.acidanthera.voodoo.driver.PS2Controller; PRODUCT_NAME = "$(TARGET_NAME)"; + RUN_CLANG_STATIC_ANALYZER = YES; STRIP_INSTALLED_PRODUCT = YES; STRIP_STYLE = "non-global"; }; @@ -874,6 +878,9 @@ 84167839161B5613002C60E6 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { + CLANG_ANALYZER_DEADCODE_DEADSTORES = YES; + CLANG_ANALYZER_DIVIDE_BY_ZERO = YES; + CLANG_ANALYZER_NULL_DEREFERENCE = YES; CLANG_ENABLE_OBJC_WEAK = YES; COMBINE_HIDPI_IMAGES = YES; CONFIGURATION_BUILD_DIR = "$(BUILD_DIR)/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)/VoodooPS2Controller.kext/Contents/PlugIns"; @@ -887,6 +894,7 @@ OTHER_CFLAGS = "-fno-stack-protector"; PRODUCT_BUNDLE_IDENTIFIER = as.acidanthera.voodoo.driver.PS2Keyboard; PRODUCT_NAME = "$(TARGET_NAME)"; + RUN_CLANG_STATIC_ANALYZER = YES; STRIP_INSTALLED_PRODUCT = YES; STRIP_STYLE = "non-global"; }; @@ -916,6 +924,9 @@ 8416784D161B56A2002C60E6 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { + CLANG_ANALYZER_DEADCODE_DEADSTORES = YES; + CLANG_ANALYZER_DIVIDE_BY_ZERO = YES; + CLANG_ANALYZER_NULL_DEREFERENCE = YES; CLANG_ENABLE_OBJC_WEAK = YES; COMBINE_HIDPI_IMAGES = YES; CONFIGURATION_BUILD_DIR = "$(BUILD_DIR)/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)/VoodooPS2Controller.kext/Contents/PlugIns"; @@ -929,6 +940,7 @@ OTHER_CFLAGS = "-fno-stack-protector"; PRODUCT_BUNDLE_IDENTIFIER = as.acidanthera.voodoo.driver.PS2Mouse; PRODUCT_NAME = "$(TARGET_NAME)"; + RUN_CLANG_STATIC_ANALYZER = YES; STRIP_INSTALLED_PRODUCT = YES; STRIP_STYLE = "non-global"; }; @@ -958,6 +970,9 @@ 84167861161B56C4002C60E6 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { + CLANG_ANALYZER_DEADCODE_DEADSTORES = YES; + CLANG_ANALYZER_DIVIDE_BY_ZERO = YES; + CLANG_ANALYZER_NULL_DEREFERENCE = YES; CLANG_ENABLE_OBJC_WEAK = YES; COMBINE_HIDPI_IMAGES = YES; CONFIGURATION_BUILD_DIR = "$(BUILD_DIR)/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)/VoodooPS2Controller.kext/Contents/PlugIns"; @@ -972,6 +987,7 @@ OTHER_CFLAGS = "-fno-stack-protector"; PRODUCT_BUNDLE_IDENTIFIER = as.acidanthera.voodoo.driver.PS2Trackpad; PRODUCT_NAME = "$(TARGET_NAME)"; + RUN_CLANG_STATIC_ANALYZER = YES; STRIP_INSTALLED_PRODUCT = YES; STRIP_STYLE = "non-global"; }; diff --git a/VoodooPS2Controller.xcodeproj/xcshareddata/xcschemes/VoodooPS2Controller.xcscheme b/VoodooPS2Controller.xcodeproj/xcshareddata/xcschemes/VoodooPS2Controller.xcscheme index 860a7f87..bc865335 100644 --- a/VoodooPS2Controller.xcodeproj/xcshareddata/xcschemes/VoodooPS2Controller.xcscheme +++ b/VoodooPS2Controller.xcodeproj/xcshareddata/xcschemes/VoodooPS2Controller.xcscheme @@ -1,6 +1,6 @@ #include -#include #include #include #include @@ -54,16 +53,7 @@ // ApplePS2SynapticsTouchPad Class Implementation // -OSDefineMetaClassAndStructors(ApplePS2SynapticsTouchPad, IOHIPointing); - -UInt32 ApplePS2SynapticsTouchPad::deviceType() -{ return NX_EVS_DEVICE_TYPE_MOUSE; }; - -UInt32 ApplePS2SynapticsTouchPad::interfaceID() -{ return NX_EVS_DEVICE_INTERFACE_BUS_ACE; }; - -IOItemCount ApplePS2SynapticsTouchPad::buttonCount() { return _buttonCount; }; -IOFixed ApplePS2SynapticsTouchPad::resolution() { return _resolution << 16; }; +OSDefineMetaClassAndStructors(ApplePS2SynapticsTouchPad, IOService); #define abs(x) ((x) < 0 ? -(x) : (x)) @@ -149,7 +139,6 @@ ApplePS2SynapticsTouchPad* ApplePS2SynapticsTouchPad::probe(IOService * provider return 0; _device = (ApplePS2MouseDevice*)provider; - bool forceSynaptics = false; // find config specific to Platform Profile OSDictionary* list = OSDynamicCast(OSDictionary, getProperty(kPlatformProfile)); @@ -164,70 +153,49 @@ ApplePS2SynapticsTouchPad* ApplePS2SynapticsTouchPad::probe(IOService * provider _device = 0; return 0; } - if (OSBoolean* force = OSDynamicCast(OSBoolean, config->getObject("ForceSynapticsDetect"))) - { - // "ForceSynapticsDetect" can be set to treat a trackpad as Synaptics which does not identify itself properly... - forceSynaptics = force->isTrue(); - } #ifdef DEBUG // save configuration for later/diagnostics... setProperty(kMergedConfiguration, config); #endif // load settings specific to Platform Profile - setParamPropertiesGated(config); + setPropertiesGated(config); injectVersionDependentProperties(config); OSSafeReleaseNULL(config); } - // for diagnostics... - UInt8 buf3[3]; - bool success = getTouchPadData(0x0, buf3); + bool success = getTouchPadData(SYNAPTICS_IDENTIFY_QUERY, reinterpret_cast(&_identity)); if (!success) { IOLog("VoodooPS2Trackpad: Identify TouchPad command failed\n"); + return 0; } - else + + INFO_LOG("VoodooPS2Trackpad: Identity = { 0x%x.%x, constant: %x }\n", + _identity.major_ver, _identity.minor_ver, _identity.synaptics_const); + + // 0x46 seemed to be returned on laptops with muxed PS/2 ports. Since muxing was added, + // I have not seen any devices return 0x46 ~ Avery + if (_identity.synaptics_const != 0x47) { - INFO_LOG("VoodooPS2Trackpad: Identify bytes = { 0x%x, 0x%x, 0x%x }\n", buf3[0], buf3[1], buf3[2]); - if (0x47 != buf3[1]) - { - IOLog("VoodooPS2Trackpad: Identify TouchPad command returned incorrect byte 2 (of 3): 0x%02x\n", buf3[1]); - } - _touchPadType = buf3[1]; + IOLog("VoodooPS2Trackpad: Identify TouchPad command returned incorrect byte 2 (of 3): 0x%02x\n", + _identity.synaptics_const); + return 0; } - if (success) + // Only support 4.x or later touchpads. + if (_identity.major_ver < 0x4) { - // most synaptics touchpads return 0x47, and we only support v4.0 or better - // in the case of 0x46, we allow versions as low as v2.0 - - success = false; - _touchPadVersion = (buf3[2] & 0x0f) << 8 | buf3[0]; - if (0x47 == buf3[1]) - { - // for diagnostics... - if ( _touchPadVersion < 0x400) - { - IOLog("VoodooPS2Trackpad: TouchPad(0x47) v%d.%d is not supported\n", - (UInt8)(_touchPadVersion >> 8), (UInt8)(_touchPadVersion)); - } - // Only support 4.x or later touchpads. - success = _touchPadVersion >= 0x400; - } - - if (forceSynaptics) - { - IOLog("VoodooPS2Trackpad: Forcing Synaptics detection due to ForceSynapticsDetect\n"); - success = true; - } + IOLog("VoodooPS2Trackpad: TouchPad(0x47) v%d.%d is not supported\n", + _identity.major_ver, _identity.minor_ver); + return 0; } _device = 0; DEBUG_LOG("ApplePS2SynapticsTouchPad::probe leaving.\n"); - return success ? this : 0; + return this; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -262,156 +230,105 @@ void ApplePS2SynapticsTouchPad::doHardwareReset() void ApplePS2SynapticsTouchPad::queryCapabilities() { + synaptics_logic_min_max logic_size; + synaptics_model model_data; + UInt8 *buf; + + bzero(&logic_size, sizeof(synaptics_logic_min_max)); + bzero(&model_data, sizeof(synaptics_model)); + // get TouchPad general capabilities - UInt8 buf3[3]; - if (!getTouchPadData(0x2, buf3) || !(buf3[0] & 0x80)) - buf3[0] = buf3[2] = 0; - int nExtendedQueries = (buf3[0] & 0x70) >> 4; - INFO_LOG("VoodooPS2Trackpad: nExtendedQueries=%d\n", nExtendedQueries); - UInt8 supportsEW = buf3[2] & (1<<5); - INFO_LOG("VoodooPS2Trackpad: supports EW=%d\n", supportsEW != 0); - - // deal with pass through capability - if (!skippassthru) - { - UInt8 passthru2 = buf3[2] >> 7; - // see if guest device for pass through is present - UInt8 passthru1 = 0; - if (getTouchPadData(0x1, buf3)) - { - // first byte, bit 0 indicates guest present - passthru1 = buf3[0] & 0x01; + buf = reinterpret_cast(&_capabilities); + if (!getTouchPadData(SYNA_CAPABILITIES_QUERY, buf)) { + bzero(&_capabilities, sizeof(_capabilities)); + } + + INFO_LOG("VoodooPS2Trackpad: nExtendedQueries=%d\n", _capabilities.extended_queries); + INFO_LOG("VoodooPS2Trackpad: supports EW=%d\n", _capabilities.extended_w_supported); + + buf = reinterpret_cast(&model_data); + if (getTouchPadData(SYNA_MODEL_QUERY, buf)) { + UInt16 combined_version = (_identity.major_ver << 8) | _identity.minor_ver; + if (combined_version >= 0x705) { + setProperty("Board ID", model_data.model_number, 32); } - // trackpad must have both guest present and pass through capability - passthru = passthru1 & passthru2; + } + #ifdef SIMULATE_PASSTHRU - passthru = true; + _capabilities.passthrough = 1; #endif - INFO_LOG("VoodooPS2Trackpad: passthru1=%d, passthru2=%d, passthru=%d\n", passthru1, passthru2, passthru); - } - if (forcepassthru) - { - passthru = true; - INFO_LOG("VoodooPS2Trackpad: Forcing Passthru\n"); - } + INFO_LOG("VoodooPS2Trackpad: Passthrough=%d, Guest Present=%d\n", + _capabilities.passthrough, model_data.guest_present); - // deal with LED capability - if (0x46 == _touchPadType) - { - ledpresent = true; - INFO_LOG("VoodooPS2Trackpad: ledpresent=%d (forced for type 0x46)\n", ledpresent); - } - else if (nExtendedQueries >= 1 && getTouchPadData(0x9, buf3)) - { - ledpresent = (buf3[0] >> 6) & 1; - INFO_LOG("VoodooPS2Trackpad: ledpresent=%d\n", ledpresent); - } - - // get resolution data for scaling x -> y or y -> x depending - if (getTouchPadData(0x8, buf3) && (buf3[1] & 0x80) && buf3[0] && buf3[2]) - { - xupmm = buf3[0]; - yupmm = buf3[2]; + // Get button data in case VoodooRMI needs it + if (model_data.more_extended_caps) { + buf = reinterpret_cast(&_securepad); + if (!getTouchPadData(SYNA_SECUREPAD_QUERY, buf)) { + bzero(&_securepad, sizeof(synaptics_securepad_id)); + } } - // now gather some more information about the touchpad - if (getTouchPadData(0x1, buf3)) - { - INFO_LOG("VoodooPS2Trackpad: Mode/model($01) bytes = { 0x%x, 0x%x, 0x%x }\n", buf3[0], buf3[1], buf3[2]); + buf = reinterpret_cast(&_extended_id); + if (_capabilities.extended_queries >= 1 && getTouchPadData(SYNA_EXTENDED_ID_QUERY, buf)) { + INFO_LOG("VoodooPS2Trackpad: ledpresent=%d\n", _extended_id.has_leds); - if (_touchPadVersion >= 0x705) { - _boardID = ((buf3[0] & 0xfc) << 6) | buf3[1]; - setProperty("Board ID", _boardID, 32); - - // Check if more extended capabilities exist before querying at 0x10 - if ((buf3[0] & 0x2) && getTouchPadData(0x10, buf3)) { - trackstickButtons = buf3[0] & 0x1; - } + if (_extended_id.extended_btns > SYNAPTICS_MAX_EXT_BTNS) { + INFO_LOG("VoodooPS2Trackpad: Too many external buttons!\n"); + _extended_id.extended_btns = 0; } } -#ifdef DEBUG_MSG - if (getTouchPadData(0x2, buf3)) - { - INFO_LOG("VoodooPS2Trackpad: Capabilities($02) bytes = { 0x%x, 0x%x, 0x%x }\n", buf3[0], buf3[1], buf3[2]); - } - if (getTouchPadData(0x3, buf3)) - { - INFO_LOG("VoodooPS2Trackpad: Model ID($03) bytes = { 0x%x, 0x%x, 0x%x }\n", buf3[0], buf3[1], buf3[2]); - } - if (getTouchPadData(0x6, buf3)) - { - INFO_LOG("VoodooPS2Trackpad: SN Prefix($06) bytes = { 0x%x, 0x%x, 0x%x }\n", buf3[0], buf3[1], buf3[2]); - } - if (getTouchPadData(0x7, buf3)) - { - INFO_LOG("VoodooPS2Trackpad: SN Suffix($07) bytes = { 0x%x, 0x%x, 0x%x }\n", buf3[0], buf3[1], buf3[2]); - } - if (getTouchPadData(0x8, buf3)) - { - INFO_LOG("VoodooPS2Trackpad: Resolutions($08) bytes = { 0x%x, 0x%x, 0x%x }\n", buf3[0], buf3[1], buf3[2]); - } - if (nExtendedQueries >= 1 && getTouchPadData(0x9, buf3)) - { - INFO_LOG("VoodooPS2Trackpad: Extended Model($09) bytes = { 0x%x, 0x%x, 0x%x }\n", buf3[0], buf3[1], buf3[2]); + + // get resolution data for scaling x -> y or y -> x depending + if (!getTouchPadData(SYNA_SCALE_QUERY, reinterpret_cast(&_scale)) || + _scale.xupmm == 0 || _scale.yupmm == 0) { + // "Typical" values from docs + _scale.xupmm = 85; + _scale.yupmm = 94; } -#endif - bool reportsMax = false; - bool reportsMin = false; - bool deluxeLeds = false; - if (nExtendedQueries >= 4 && getTouchPadData(0xc, buf3)) - { - setProperty("0xc Query", buf3, 3); - INFO_LOG("VoodooPS2Trackpad: Continued Capabilities($0C) bytes = { 0x%x, 0x%x, 0x%x }\n", buf3[0], buf3[1], buf3[2]); + bool reports_min = false; + bool reports_max = false; + + buf = reinterpret_cast(&_cont_caps); + if (_capabilities.extended_queries >= 4 && getTouchPadData(SYNA_CONT_CAPS_QUERY, buf)) { + INFO_LOG("VoodooPS2Trackpad: Continued Capabilities($0C) = { smbus_addr=0x%x }\n", _cont_caps.intertouch_addr); - clickpadtype = ((buf3[0] & 0x10) >> 4) | ((buf3[1] & 0x01) << 1); #ifdef SIMULATE_CLICKPAD - clickpadtype = 1; + _const_caps.one_btn_clickpad = 1; DEBUG_LOG("VoodooPS2Trackpad: clickpadtype=1 simulation set\n"); #endif - INFO_LOG("VoodooPS2Trackpad: clickpadtype=%d\n", clickpadtype); - _reportsv = (bool)(buf3[1] >> 3) & (1 << 3); - INFO_LOG("VoodooPS2Trackpad: _reportsv=%d\n", _reportsv); - - // automatically set extendedwmode if supported - if (supportsEW) - { - _extendedwmodeSupported = true; - INFO_LOG("VoodooPS2Trackpad: Trackpad supports extendedW mode\n"); - } - - reportsMax = (bool)(buf3[0] & (1 << 1)); - reportsMin = (bool)(buf3[1] & (1 << 5)); - deluxeLeds = (bool)(buf3[1] & (1 << 1)); - if (buf3[1] & 0x40) - { + reports_min = _cont_caps.reports_min; + reports_max = _cont_caps.reports_max; + INFO_LOG("VoodooPS2Trackpad: clickpadtype=%d\n", _cont_caps.one_btn_clickpad); + INFO_LOG("VoodooPS2Trackpad: _reportsv=%d\n", _cont_caps.reports_v); + + if (_cont_caps.intertouch) { IOLog("VoodooPS2Trackpad: Trackpad supports Intertouch/SMBus operation\n"); setProperty("Intertouch Support", kOSBooleanTrue); } } - if (reportsMax && getTouchPadData(0xd, buf3)) - { - logical_max_x = (buf3[0] << 5) | ((buf3[1] & 0x0f) << 1); - logical_max_y = (buf3[2] << 5) | ((buf3[1] & 0xf0) >> 3); - - INFO_LOG("VoodooPS2Trackpad: Maximum coords($0D) bytes = { 0x%x, 0x%x, 0x%x }\n", buf3[0], buf3[1], buf3[2]); - } - if (deluxeLeds && getTouchPadData(0xe, buf3)) + + buf = reinterpret_cast(&logic_size); + if (reports_max && getTouchPadData(SYNA_LOGIC_MAX_QUERY, buf)) { - INFO_LOG("VoodooPS2Trackpad: Deluxe LED bytes($0E) = { 0x%x, 0x%x, 0x%x }\n", buf3[0], buf3[1], buf3[2]); + logical_max_x = SYNA_LOGIC_X(logic_size); + logical_max_y = SYNA_LOGIC_Y(logic_size); + INFO_LOG("VoodooPS2Trackpad: Maximum coords($0D) = { 0x%x, 0x%x }\n", + logical_max_x, logical_max_y); } // 5 mm margins - margin_size_x = 5 * xupmm; - margin_size_y = 5 * yupmm; + margin_size_x = 5 * _scale.xupmm; + margin_size_y = 5 * _scale.yupmm; - if (reportsMin && getTouchPadData(0xf, buf3)) + if (reports_min && getTouchPadData(SYNA_LOGIC_MIN_QUERY, buf)) { - logical_min_x = (buf3[0] << 5) | ((buf3[1] & 0x0f) << 1); - logical_min_y = (buf3[2] << 5) | ((buf3[1] & 0xf0) >> 3); - DEBUG_LOG("VoodooPS2Trackpad: Minimum coords bytes($0F) = { 0x%x, 0x%x, 0x%x }\n", buf3[0], buf3[1], buf3[2]); + logical_min_x = SYNA_LOGIC_X(logic_size); + logical_min_y = SYNA_LOGIC_Y(logic_size); + DEBUG_LOG("VoodooPS2Trackpad: Minimum coords($0F) = { 0x%x, 0x%x }\n", + logical_min_x, logical_min_y); } else { logical_min_x = logical_max_x - 3 * margin_size_x; @@ -437,19 +354,24 @@ void ApplePS2SynapticsTouchPad::queryCapabilities() setProperty(VOODOO_INPUT_LOGICAL_MAX_Y_KEY, logical_max_y - logical_min_y, 32); // physical dimensions are specified in 0.01 mm units - physical_max_x = (logical_max_x + 1 - (reportsMin ? logical_min_x : 0)) * 100 / xupmm; - physical_max_y = (logical_max_y + 1 - (reportsMin ? logical_min_y : 0)) * 100 / yupmm; + physical_max_x = (logical_max_x + 1 - (reports_min ? logical_min_x : 0)) * 100 / _scale.xupmm; + physical_max_y = (logical_max_y + 1 - (reports_min ? logical_min_y : 0)) * 100 / _scale.yupmm; setProperty(VOODOO_INPUT_PHYSICAL_MAX_X_KEY, physical_max_x, 32); setProperty(VOODOO_INPUT_PHYSICAL_MAX_Y_KEY, physical_max_y, 32); setProperty(VOODOO_INPUT_TRANSFORM_KEY, 0ull, 32); + + setTrackpointProperties(); + setProperty("VoodooInputSupported", kOSBooleanTrue); // Helpful information for SMBus drivers OSDictionary *dictionary = OSDictionary::withCapacity(2); - dictionary->setObject("TrackstickButtons", trackstickButtons ? kOSBooleanTrue : kOSBooleanFalse); - dictionary->setObject("Clickpad", (clickpadtype & 0x1) ? kOSBooleanTrue : kOSBooleanFalse); + dictionary->setObject("TrackstickButtons", _securepad.trackstick_btns ? + kOSBooleanTrue : kOSBooleanFalse); + dictionary->setObject("Clickpad", _cont_caps.one_btn_clickpad ? + kOSBooleanTrue : kOSBooleanFalse); setProperty("GPIO Data", dictionary); OSSafeReleaseNULL(dictionary); @@ -458,7 +380,7 @@ void ApplePS2SynapticsTouchPad::queryCapabilities() logical_min_x, logical_min_y, logical_max_x, logical_max_y, physical_max_x, physical_max_y, - xupmm, yupmm); + _scale.xupmm, _scale.yupmm); } bool ApplePS2SynapticsTouchPad::handleOpen(IOService *forClient, IOOptionBits options, void *arg) { @@ -498,26 +420,12 @@ bool ApplePS2SynapticsTouchPad::start( IOService * provider ) // Announce hardware properties. // - IOLog("VoodooPS2Trackpad starting: Synaptics TouchPad reports type 0x%02x, version %d.%d\n", - _touchPadType, (UInt8)(_touchPadVersion >> 8), (UInt8)(_touchPadVersion)); + IOLog("VoodooPS2Trackpad starting: Synaptics TouchPad reports version %d.%d\n", + _identity.major_ver, _identity.minor_ver); char buf[128]; - snprintf(buf, sizeof(buf), "type 0x%02x, version %d.%d", _touchPadType, (UInt8)(_touchPadVersion >> 8), (UInt8)(_touchPadVersion)); + snprintf(buf, sizeof(buf), "type 0x%02x, version %d.%d", + 0x47, _identity.major_ver, _identity.minor_ver); setProperty("RM,TrackpadInfo", buf); - - // - // 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) - setProperty("HIDScrollResolutionX", _scrollresolution << 16, 32); - setProperty("HIDScrollResolutionY", _scrollresolution << 16, 32); // // Setup workloop with command gate for thread syncronization... @@ -549,22 +457,6 @@ bool ApplePS2SynapticsTouchPad::start( IOService * provider ) attachedHIDPointerDevices = OSSet::withCapacity(1); registerHIDPointerNotifications(); - - // - // Setup button timer event source - // - if (_buttonCount >= 3) - { - _buttonTimer = IOTimerEventSource::timerEventSource(this, OSMemberFunctionCast(IOTimerEventSource::Action, this, &ApplePS2SynapticsTouchPad::onButtonTimer)); - if (!_buttonTimer) - { - _device->unlock(); - _device->release(); - _device = nullptr; - return false; - } - pWorkLoop->addEventSource(_buttonTimer); - } // // Query the touchpad for the capabilities we need to know. @@ -576,7 +468,7 @@ bool ApplePS2SynapticsTouchPad::start( IOService * provider ) // Enable the mouse clock (should already be so) and the mouse IRQ line. // Enable the touchpad itself. // - setTouchpadModeByte(); + enterAdvancedGestureMode(); // // Install our driver's interrupt handler, for asynchronous data delivery. @@ -654,12 +546,6 @@ void ApplePS2SynapticsTouchPad::stop( IOService * provider ) IOWorkLoop* pWorkLoop = getWorkLoop(); if (pWorkLoop) { - if (_buttonTimer) - { - pWorkLoop->removeEventSource(_buttonTimer); - _buttonTimer->release(); - _buttonTimer = 0; - } if (_cmdGate) { pWorkLoop->removeEventSource(_cmdGate); @@ -830,9 +716,161 @@ void ApplePS2SynapticsTouchPad::assignFingerType(synaptics_virtual_finger_state } -void ApplePS2SynapticsTouchPad::synaptics_parse_hw_state(const UInt8 buf[]) -{ +void ApplePS2SynapticsTouchPad::synaptics_parse_normal_packet(const UInt8 buf[], const int w) { + DEBUG_LOG("synaptics_parse_hw_state: =============NORMAL PACKET============="); + + int x = buf[4] | + ((buf[1] & 0x0f) << 8) | + ((buf[3] & 0x10) << 8); + + int y = buf[5] | + ((buf[1] & 0xf0) << 4) | + ((buf[3] & 0x20) << 7); + + // normal "packet" + if (w >= 4) { // One finger + fingerStates[0].x = x; + fingerStates[0].y = y; + fingerStates[0].z = buf[2]; // pressure + fingerStates[0].w = w; // width + } + else { // Multiple fingers, read virtual V field + fingerStates[0].x = x; + fingerStates[0].y = y; + fingerStates[0].z = buf[2] & 0xfe; // pressure + fingerStates[0].w = 8 + ((buf[2] & 1) << 2 | (buf[5] & 2) | (buf[4] & 2 >> 1)); + } + DEBUG_LOG("synaptics_parse_hw_state: finger 0 pressure %d width %d\n", fingerStates[0].z, fingerStates[0].w); + + if (fingerStates[0].x > X_MAX_POSITIVE) + fingerStates[0].x -= 1 << ABS_POS_BITS; + else if (fingerStates[0].x == X_MAX_POSITIVE) + fingerStates[0].x = XMAX; + + if (fingerStates[0].y > Y_MAX_POSITIVE) + fingerStates[0].y -= 1 << ABS_POS_BITS; + else if (fingerStates[0].y == Y_MAX_POSITIVE) + fingerStates[0].y = YMAX; + + // count the number of fingers + // my port of synaptics_image_sensor_process from synaptics.c from Linux Kernel + int fingerCount = 0; + if(fingerStates[0].z < z_finger) { + fingerCount = 0; + agmFingerCount = 0; + fingerStates[0].w = 0; + } + else if(w >= 4) { + fingerCount = 1; + agmFingerCount = 0; + } else if(w == 0) + fingerCount = MAX(2, MIN(agmFingerCount, SYNAPTICS_MAX_FINGERS)); + else if(w == 1) + fingerCount = MAX(3, MIN(agmFingerCount, SYNAPTICS_MAX_FINGERS)); + + clampedFingerCount = fingerCount; + + if (clampedFingerCount > SYNAPTICS_MAX_FINGERS) + clampedFingerCount = SYNAPTICS_MAX_FINGERS; + + if (renumberFingers()) + sendTouchData(); +} + +// advanced gesture packet (half-resolution packets) +// my port of synaptics_parse_agm from synaptics.c from Linux Kernel +void ApplePS2SynapticsTouchPad::synaptics_parse_agm_packet(const UInt8 buf[]) { + int agmPacketType = (buf[5] & 0x30) >> 4; + + switch(agmPacketType) { + case 1: + DEBUG_LOG("synaptics_parse_hw_state: ===========EXTENDED PACKET==========="); + fingerStates[1].x = (((buf[4] & 0x0f) << 8) | buf[1]) << 1; + fingerStates[1].y = (((buf[4] & 0xf0) << 4) | buf[2]) << 1; + fingerStates[1].z = ((buf[3] & 0x30) | (buf[5] & 0x0f)) << 1; + fingerStates[1].w = 8 + ((buf[5] & 1) << 2 | (buf[2] & 1) << 1 | (buf[1] & 1)); + + DEBUG_LOG("synaptics_parse_hw_state: finger 1 pressure %d width %d\n", fingerStates[1].z, fingerStates[1].w); + + if (fingerStates[1].x > X_MAX_POSITIVE) + fingerStates[1].x -= 1 << ABS_POS_BITS; + else if (fingerStates[1].x == X_MAX_POSITIVE) + fingerStates[1].x = XMAX; + + if (fingerStates[1].y > Y_MAX_POSITIVE) + fingerStates[1].y -= 1 << ABS_POS_BITS; + else if (fingerStates[1].y == Y_MAX_POSITIVE) + fingerStates[1].y = YMAX; + + break; + case 2: + DEBUG_LOG("synaptics_parse_hw_state: ===========FINGER COUNT PACKET==========="); + agmFingerCount = buf[1] & 0x0f; + DEBUG_LOG("synaptics_parse_hw_state: %d fingers, prim_idx: %d, sec_idx: %d\n", + agmFingerCount, buf[2], buf[4]); + break; + default: + break; + } +} +void ApplePS2SynapticsTouchPad::synaptics_parse_passthru(const UInt8 buf[], UInt32 buttons) { + AbsoluteTime timestamp; + clock_get_uptime(×tamp); + + UInt32 passbuttons = buf[1] & 0x7; // mask for just M R L + + // if there are buttons set in the last pass through packet, then be sure + // they are set in any trackpad dispatches. + // otherwise, you might see double clicks that aren't there + _lastPassthruButtons = passbuttons; + + SInt32 dx = ((buf[1] & 0x10) ? 0xffffff00 : 0 ) | buf[4]; + SInt32 dy = ((buf[1] & 0x20) ? 0xffffff00 : 0 ) | buf[5]; + buttons |= passbuttons; + +#ifdef DEBUG_VERBOSE + static int count = 0; + IOLog("ps2: passthru packet dx=%d, dy=%d, buttons=%d (%d)\n", dx, dy, buttons, count++); +#endif + + trackpointReport.timestamp = timestamp; + trackpointReport.dx = dx; + trackpointReport.dy = -dy; + trackpointReport.buttons = buttons; + + super::messageClient(kIOMessageVoodooTrackpointMessage, voodooInputInstance, + &trackpointReport, sizeof(TrackpointReport)); +} + +int ApplePS2SynapticsTouchPad::synaptics_parse_ext_btns(const UInt8 buf[], const int w) { + UInt8 extBtnsChanged = (buf[0] ^ buf[3]) & 0x2; + + // The extended buttons override bits from x/y position, so are only part of the + // packet if their state changes and the packet isn't an Extended W packet. + if (extBtnsChanged == 0 || w == SYNA_W_EXTENDED) { + return _lastExtendedButtons; + } + + UInt8 btnBits = (_extended_id.extended_btns + 1) / 2; + int extendedBtns = 0; + + // Extended buttons have a pattern of: + // Byte 4 X7 X6 X5 X4 B6 B4 B2 B0 + // Byte 5 Y7 Y6 Y5 Y4 B7 B5 B3 B1 + // This needs to be converted to one value with up to 8 buttons in it + for (int i = 0; i < btnBits; i++) { + UInt8 mask = 1 << i; + extendedBtns |= (buf[4] & mask) << i; + extendedBtns |= (buf[5] & mask) << (i + 1); + } + + extendedBtns &= (1 << _extended_id.extended_btns) - 1; + _lastExtendedButtons = extendedBtns; + return _lastExtendedButtons; +} + +void ApplePS2SynapticsTouchPad::synaptics_parse_hw_state(const UInt8 buf[]) { // Check if input is disabled via ApplePS2Keyboard request if (ignoreall) return; @@ -840,287 +878,57 @@ void ApplePS2SynapticsTouchPad::synaptics_parse_hw_state(const UInt8 buf[]) int w = (((buf[0] & 0x30) >> 2) | ((buf[0] & 0x04) >> 1) | ((buf[3] & 0x04) >> 2)); - - - int x = buf[4]|((buf[1]&0x0f)<<8)|((buf[3]&0x10)<<8); - int y = buf[5]|((buf[1]&0xf0)<<4)|((buf[3]&0x20)<<7); DEBUG_LOG("VoodooPS2 w: %d\n", w); + // ------ Buttons ------ - //I'm just reimplement RehabMan old code here, maybe sounds like a hacky solution but hey at least it works! - - UInt32 buttonsraw = buf[0] & 0x03; // mask for just R L - UInt32 buttons = buttonsraw; - - if (passthru && 3 == w) - passbuttons = buf[1] & 0x7; // mask for just M R L + UInt32 buttons = buf[0] & 0x3; // R L + UInt32 xorBtns = buf[0] ^ buf[3]; // Useful for extended buttons below - buttons |= passbuttons; - lastbuttons = buttons; + if (_cont_caps.one_btn_clickpad) { + // Clickpad reports it's button in the middle mouse button position + _clickpad_pressed = xorBtns & 0x1; + } - if (clickpadtype) - { - // ClickPad puts its "button" presses in a different location - // And for single button ClickPad we have to provide a way to simulate right clicks - int clickbuttons = buf[3] & 0x3; - - //Let's quickly do some extra logic to see if we are pressing any of the physical buttons for the trackpoint - if (isthinkpad) - { - - DEBUG_LOG("IS THINKPAD"); - // parse packets for buttons - TrackPoint Buttons may not be passthru - int bp = buf[3] & 0x3; // 1 on clickpad or 2 for the 2 real buttons - int lb = buf[4] & 0x3; // 1 for left real button - int rb = buf[5] & 0x3; // 1 for right real button - - if (bp == 2) - { - if( lb == 1 ) - { // left click - clickbuttons = 0x1; - } - else if ( rb == 1 ) - { // right click - clickbuttons = 0x2; - } - else if ( lb == 2 ) - { // middle click - clickbuttons = 0x4; - } - else - { - clickbuttons = 0x0; - } - thinkpadButtonState = clickbuttons; - buttons=clickbuttons; - setClickButtons(clickbuttons); - } - else - { - clickbuttons = bp; - } - } - - // always clear _clickbutton state, when ClickPad is not clicked - if (!clickbuttons) - setClickButtons(0); - - //Remember the button state on thinkpads.. this is required so we can handle the middle click vs middle scrolling appropriately. - if (isthinkpad) - { - if (thinkpadButtonState) - _clickbuttons = thinkpadButtonState; - } - buttons |= _clickbuttons; - lastbuttons = buttons; - + if (_capabilities.middle_btn && (xorBtns & 0x1)) { + buttons |= 0x4; } + if (_extended_id.extended_btns > 0) { + buttons |= synaptics_parse_ext_btns(buf, w); + } + DEBUG_LOG("VoodooPS2 Buttons %d\n", buttons); - // advanced gesture packet (half-resolution packets) - // my port of synaptics_parse_agm from synaptics.c from Linux Kernel - DEBUG_LOG("buttons %d", buttons); + // ------ Motion Data ------ - if(w == 2) { - int agmPacketType = (buf[5] & 0x30) >> 4; - - switch(agmPacketType) { - case 1: - DEBUG_LOG("synaptics_parse_hw_state: ===========EXTENDED PACKET==========="); - fingerStates[1].x = (((buf[4] & 0x0f) << 8) | buf[1]) << 1; - fingerStates[1].y = (((buf[4] & 0xf0) << 4) | buf[2]) << 1; - fingerStates[1].z = ((buf[3] & 0x30) | (buf[5] & 0x0f)) << 1; - fingerStates[1].w = 8 + ((buf[5] & 1) << 2 | (buf[2] & 1) << 1 | (buf[1] & 1)); - - DEBUG_LOG("synaptics_parse_hw_state: finger 1 pressure %d width %d\n", fingerStates[1].z, fingerStates[1].w); - - if (fingerStates[1].x > X_MAX_POSITIVE) - fingerStates[1].x -= 1 << ABS_POS_BITS; - else if (fingerStates[1].x == X_MAX_POSITIVE) - fingerStates[1].x = XMAX; - - if (fingerStates[1].y > Y_MAX_POSITIVE) - fingerStates[1].y -= 1 << ABS_POS_BITS; - else if (fingerStates[1].y == Y_MAX_POSITIVE) - fingerStates[1].y = YMAX; - - break; - case 2: - DEBUG_LOG("synaptics_parse_hw_state: ===========FINGER COUNT PACKET==========="); - agmFingerCount = buf[1] & 0x0f; - DEBUG_LOG("synaptics_parse_hw_state: %d fingers\n", agmFingerCount); - break; - default: - break; - } - } - else if (w == 3 && passthru) { - AbsoluteTime timestamp; - clock_get_uptime(×tamp); - - - - - UInt32 btnsraw = buf[0] & 0x03; // mask for just R L - UInt32 btn = btnsraw; - - - UInt32 passbtns = buf[1] & 0x7; // mask for just M R L - // if there are buttons set in the last pass through packet, then be sure - // they are set in any trackpad dispatches. - // otherwise, you might see double clicks that aren't there - btn |= passbtns; - lastbuttons = btn; - - // New Lenovo clickpads do not have buttons, so LR in packet byte 1 is zero and thus - // passbuttons is 0. Instead we need to check the trackpad buttons in byte 0 and byte 3 - // However for clickpads that would miss right clicks, so use the last clickbuttons that - // were saved. - UInt32 combinedButtons = btn | ((buf[0] & 0x3) | (buf[3] & 0x3)) | _clickbuttons | thinkpadButtonState; - - SInt32 dx = ((buf[1] & 0x10) ? 0xffffff00 : 0 ) | buf[4]; - SInt32 dy = ((buf[1] & 0x20) ? 0xffffff00 : 0 ) | buf[5]; - if (/*mousemiddlescroll && */((buf[1] & 0x4) || thinkpadButtonState == 4)) // only for physical middle button - { - if (dx != 0 || dy != 0) - thinkpadMiddleScrolled = true; - // middle button treats deltas for scrolling - SInt32 scrollx = 0, scrolly = 0; - if (abs(dx) > abs(dy)) - scrollx = dx;// * mousescrollmultiplierx; - else - scrolly = dy;// * mousescrollmultipliery; - - if (isthinkpad && thinkpadMiddleButtonPressed) - { - scrolly = scrolly * thinkpadNubScrollYMultiplier; - scrollx = scrollx * thinkpadNubScrollXMultiplier; - } - - dispatchScrollWheelEvent(scrolly, -scrollx, 0, timestamp); - dx = dy = 0; - } - dx *= mousemultiplierx; - dy *= mousemultipliery; - //If this is a thinkpad, we do extra logic here to see if we're doing a middle click - if (isthinkpad) - { - if (/*mousemiddlescroll && */combinedButtons == 4) - { - thinkpadMiddleButtonPressed = true; - } - else - { - if (thinkpadMiddleButtonPressed && !thinkpadMiddleScrolled) - dispatchRelativePointerEvent(dx, -dy, 4, timestamp); - dispatchRelativePointerEvent(dx, -dy, combinedButtons, timestamp); - thinkpadMiddleButtonPressed = false; - thinkpadMiddleScrolled = false; - } - } - else - { - dispatchRelativePointerEvent(dx, -dy, combinedButtons, timestamp); - } -#ifdef DEBUG_VERBOSE - static int count = 0; - IOLog("ps2: passthru packet dx=%d, dy=%d, buttons=%d (%d)\n", dx, dy, combinedButtons, count++); -#endif - return; - - } - else { - DEBUG_LOG("synaptics_parse_hw_state: =============NORMAL PACKET============="); - - // normal "packet" - if (w >= 4) { // One finger - fingerStates[0].x = x; - fingerStates[0].y = y; - fingerStates[0].z = buf[2]; // pressure - fingerStates[0].w = w; // width - } - else { // Multiple fingers, read virtual V field - fingerStates[0].x = x; - fingerStates[0].y = y; - fingerStates[0].z = buf[2] & 0xfe; // pressure - fingerStates[0].w = 8 + ((buf[2] & 1) << 2 | (buf[5] & 2) | (buf[4] & 2 >> 1)); - } - DEBUG_LOG("synaptics_parse_hw_state: finger 0 pressure %d width %d\n", fingerStates[0].z, fingerStates[0].w); - - - bool prev_right = right; - // That's wrong according to the docs! - left = (buf[0] ^ buf[3]) & 1; - right = (buf[0] ^ buf[3]) & 2; - - if (fingerStates[0].x > X_MAX_POSITIVE) - fingerStates[0].x -= 1 << ABS_POS_BITS; - else if (fingerStates[0].x == X_MAX_POSITIVE) - fingerStates[0].x = XMAX; - - if (fingerStates[0].y > Y_MAX_POSITIVE) - fingerStates[0].y -= 1 << ABS_POS_BITS; - else if (fingerStates[0].y == Y_MAX_POSITIVE) - fingerStates[0].y = YMAX; - - // count the number of fingers - // my port of synaptics_image_sensor_process from synaptics.c from Linux Kernel - int fingerCount = 0; - if(fingerStates[0].z < z_finger) { - fingerCount = 0; - agmFingerCount = 0; - fingerStates[0].w = 0; - } - else if(w >= 4) { - fingerCount = 1; - agmFingerCount = 0; - } else if(w == 0) - fingerCount = MAX(2, MIN(agmFingerCount, SYNAPTICS_MAX_FINGERS)); - else if(w == 1) - fingerCount = MAX(3, MIN(agmFingerCount, SYNAPTICS_MAX_FINGERS)); - - clampedFingerCount = fingerCount; - - if (clampedFingerCount > SYNAPTICS_MAX_FINGERS) - clampedFingerCount = SYNAPTICS_MAX_FINGERS; - - if (renumberFingers()) - sendTouchData(); - - - AbsoluteTime timestamp; - clock_get_uptime(×tamp); - - - if (isthinkpad) - { - if (buttons == 4) - { - thinkpadMiddleButtonPressed = true; - } - else - { - if (thinkpadMiddleButtonPressed && !thinkpadMiddleScrolled) - dispatchRelativePointerEvent(0, 0, 4, timestamp); - dispatchRelativePointerEvent(0, 0, buttons, timestamp); - thinkpadMiddleButtonPressed = false; - thinkpadMiddleScrolled = false; - } - }else{//Deactivated this thingy because I was sending a right click after I pressed the left physical button on my thinkpad - if (right && !prev_right){ - dispatchRelativePointerEvent(0, 0, 0x02, timestamp); - } - else if (prev_right && !(right)){ - dispatchRelativePointerEvent(0, 0, 0x00, timestamp); - } - } - - + switch (w) { + case SYNA_W_EXTENDED: + buttons |= _lastPassthruButtons; + synaptics_parse_agm_packet(buf); + break; + case SYNA_W_PASSTHRU: + synaptics_parse_passthru(buf, buttons); + return; + default: + buttons |= _lastPassthruButtons; + synaptics_parse_normal_packet(buf, w); + break; } + // ------ Report buttons ------ + + AbsoluteTime timestamp; + clock_get_uptime(×tamp); + + trackpointReport.timestamp = timestamp; + trackpointReport.dx = 0; + trackpointReport.dy = 0; + trackpointReport.buttons = buttons; + + super::messageClient(kIOMessageVoodooTrackpointMessage, voodooInputInstance, + &trackpointReport, sizeof(TrackpointReport)); } template @@ -1516,7 +1324,7 @@ bool ApplePS2SynapticsTouchPad::renumberFingers() { fiv.y_avg.filter(fi.y); fiv.width = fi.w; fiv.pressure = fi.z; - fiv.button = left; + fiv.button = _clickpad_pressed; } // Thumb detection. Must happen after setting coordinates (filter) @@ -1543,7 +1351,8 @@ bool ApplePS2SynapticsTouchPad::renumberFingers() { } } - DEBUG_LOG("synaptics_parse_hw_state: lastFingerCount=%d clampedFingerCount=%d left=%d", lastFingerCount, clampedFingerCount, left); + DEBUG_LOG("synaptics_parse_hw_state: lastFingerCount=%d clampedFingerCount=%d clickpad=%d", + lastFingerCount, clampedFingerCount, _clickpad_pressed); return true; } @@ -1689,138 +1498,6 @@ void ApplePS2SynapticsTouchPad::sendTouchData() { lastSentFingerCount = inputEvent.contact_count; } - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void ApplePS2SynapticsTouchPad::onButtonTimer(void) -{ - uint64_t now_abs; - clock_get_uptime(&now_abs); - - middleButton(lastbuttons, now_abs, fromTimer); -} - -UInt32 ApplePS2SynapticsTouchPad::middleButton(UInt32 buttons, uint64_t now_abs, MBComingFrom from) -{ - if (!_fakemiddlebutton || _buttonCount <= 2 || (ignoreall && fromTrackpad == from)) - return buttons; - - // cancel timer if we see input before timeout has fired, but after expired - bool timeout = false; - uint64_t now_ns; - absolutetime_to_nanoseconds(now_abs, &now_ns); - if (fromTimer == from || fromCancel == from || now_ns - _buttontime > _maxmiddleclicktime) - timeout = true; - - // - // A state machine to simulate middle buttons with two buttons pressed - // together. - // - switch (_mbuttonstate) - { - // no buttons down, waiting for something to happen - case STATE_NOBUTTONS: - if (fromCancel != from) - { - if (buttons & 0x4) - _mbuttonstate = STATE_NOOP; - else if (0x3 == buttons) - _mbuttonstate = STATE_MIDDLE; - else if (0x0 != buttons) - { - // only single button, so delay this for a bit - _pendingbuttons = buttons; - _buttontime = now_ns; - setTimerTimeout(_buttonTimer, _maxmiddleclicktime); - _mbuttonstate = STATE_WAIT4TWO; - } - } - break; - - // waiting for second button to come down or timeout - case STATE_WAIT4TWO: - if (!timeout && 0x3 == buttons) - { - _pendingbuttons = 0; - cancelTimer(_buttonTimer); - _mbuttonstate = STATE_MIDDLE; - } - else if (timeout || buttons != _pendingbuttons) - { - if (fromTimer == from || !(buttons & _pendingbuttons)) - dispatchRelativePointerEventX(0, 0, buttons|_pendingbuttons, now_abs); - _pendingbuttons = 0; - cancelTimer(_buttonTimer); - if (0x0 == buttons) - _mbuttonstate = STATE_NOBUTTONS; - else - _mbuttonstate = STATE_NOOP; - } - break; - - // both buttons down and delivering middle button - case STATE_MIDDLE: - if (0x0 == buttons) - _mbuttonstate = STATE_NOBUTTONS; - else if (0x3 != (buttons & 0x3)) - { - // only single button, so delay to see if we get to none - _pendingbuttons = buttons; - _buttontime = now_ns; - setTimerTimeout(_buttonTimer, _maxmiddleclicktime); - _mbuttonstate = STATE_WAIT4NONE; - } - break; - - // was middle button, but one button now up, waiting for second to go up - case STATE_WAIT4NONE: - if (!timeout && 0x0 == buttons) - { - _pendingbuttons = 0; - cancelTimer(_buttonTimer); - _mbuttonstate = STATE_NOBUTTONS; - } - else if (timeout || buttons != _pendingbuttons) - { - if (fromTimer == from) - dispatchRelativePointerEventX(0, 0, buttons|_pendingbuttons, now_abs); - _pendingbuttons = 0; - cancelTimer(_buttonTimer); - if (0x0 == buttons) - _mbuttonstate = STATE_NOBUTTONS; - else - _mbuttonstate = STATE_NOOP; - } - break; - - case STATE_NOOP: - if (0x0 == buttons) - _mbuttonstate = STATE_NOBUTTONS; - break; - } - - // modify buttons after new state set - switch (_mbuttonstate) - { - case STATE_MIDDLE: - buttons = 0x4; - break; - - case STATE_WAIT4NONE: - case STATE_WAIT4TWO: - buttons &= ~0x3; - break; - - case STATE_NOBUTTONS: - case STATE_NOOP: - break; - } - - // return modified buttons - return buttons; -} - - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void ApplePS2SynapticsTouchPad::setTouchPadEnable( bool enable ) @@ -1935,7 +1612,9 @@ void ApplePS2SynapticsTouchPad::initTouchPad() _packetByteCount = 0; _ringBuffer.reset(); - _clickbuttons = 0; + _clickpad_pressed = 0; + _lastPassthruButtons = 0; + _lastExtendedButtons = 0; tracksecondary=false; // clear state of control key cache @@ -1947,7 +1626,7 @@ void ApplePS2SynapticsTouchPad::initTouchPad() // Also touchpad is enabled as side effect // - setTouchpadModeByte(); + enterAdvancedGestureMode(); // // Set LED state as it is lost after sleep @@ -1955,15 +1634,11 @@ void ApplePS2SynapticsTouchPad::initTouchPad() updateTouchpadLED(); } -bool ApplePS2SynapticsTouchPad::setTouchpadModeByte() -{ - _touchPadModeByte = _extendedwmodeSupported ? _touchPadModeByte | (1<<2) : _touchPadModeByte & ~(1<<2); - _extendedwmode = _extendedwmodeSupported; - return setTouchPadModeByte(_touchPadModeByte); -} - -bool ApplePS2SynapticsTouchPad::setTouchPadModeByte(UInt8 modeByteValue) +bool ApplePS2SynapticsTouchPad::enterAdvancedGestureMode() { + int i = 0; + TPS2Request<> request; + // make sure we are not early in the initialization... if (!_device) return false; @@ -2003,62 +1678,7 @@ bool ApplePS2SynapticsTouchPad::setTouchPadModeByte(UInt8 modeByteValue) // for a PS2Request is 30. So don't add any. Break it into multiple // requests! - int i; - TPS2Request<> request; - -#ifdef SET_STREAM_MODE - // This was another attempt to solve wake from sleep problems. Not needed. - i = 0; - request.commands[i++].inOrOut = kDP_SetMouseStreamMode; // EA - for (int x = 0; x < i; x++) - request.commands[x].command = kPS2C_SendMouseCommandAndCompareAck; - request.commandsCount = i; - assert(request.commandsCount <= countof(request.commands)); - DEBUG_LOG("VoodooPS2Trackpad: sending kDP_SetMouseStreamMode $EA\n"); - _device->submitRequestAndBlock(&request); - if (i != request.commandsCount) - DEBUG_LOG("VoodooPS2Trackpad: sending $EA failed: %d\n", request.commandsCount); -#endif - -#ifdef UNDOCUMENTED_INIT_SEQUENCE_PRE - // Also another attempt to solve wake from sleep problems. Probably not needed. - i = 0; - // From chiby's latest post... to take care of wakup issues? - request.commands[i++].inOrOut = kDP_SetMouseScaling2To1; // E7 - request.commands[i++].inOrOut = kDP_SetMouseScaling1To1; // E6 - request.commands[i++].inOrOut = kDP_Enable; // F4 - for (int x = 0; x < i; x++) - request.commands[x].command = kPS2C_SendMouseCommandAndCompareAck; - request.commandsCount = i; - DEBUG_LOG("VoodooPS2Trackpad: sending undoc pre\n"); - assert(request.commandsCount <= countof(request.commands)); - _device->submitRequestAndBlock(&request); - if (i != request.commandsCount) - DEBUG_LOG("VoodooPS2Trackpad: sending undoc pre failed: %d\n", request.commandsCount); -#endif - - // Disable stream mode before the command sequence. - i = 0; - request.commands[i++].inOrOut = kDP_SetDefaultsAndDisable; // F5 - request.commands[i++].inOrOut = kDP_SetDefaultsAndDisable; // F5 - request.commands[i++].inOrOut = kDP_SetMouseScaling1To1; // E6 - request.commands[i++].inOrOut = kDP_SetMouseScaling1To1; // E6 - - // 4 set resolution commands, each encode 2 data bits. - request.commands[i++].inOrOut = kDP_SetMouseResolution; // E8 - request.commands[i++].inOrOut = (modeByteValue >> 6) & 0x3; // 0x (depends on mode byte) - request.commands[i++].inOrOut = kDP_SetMouseResolution; // E8 - request.commands[i++].inOrOut = (modeByteValue >> 4) & 0x3; // 0x (depends on mode byte) - request.commands[i++].inOrOut = kDP_SetMouseResolution; // E8 - request.commands[i++].inOrOut = (modeByteValue >> 2) & 0x3; // 0x (depends on mode byte) - request.commands[i++].inOrOut = kDP_SetMouseResolution; // E8 - request.commands[i++].inOrOut = (modeByteValue >> 0) & 0x3; // 0x (depends on mode byte) - - // Set sample rate 20 to set mode byte 2. Older pads have 4 mode - // bytes (0,1,2,3), but only mode byte 2 remain in modern pads. - request.commands[i++].inOrOut = kDP_SetMouseSampleRate; // F3 - request.commands[i++].inOrOut = 20; // 14 - request.commands[i++].inOrOut = kDP_SetMouseScaling1To1; // E6 + setModeByte(false); #ifdef UNDOCUMENTED_INIT_SEQUENCE_POST // maybe this is commit? @@ -2092,33 +1712,22 @@ bool ApplePS2SynapticsTouchPad::setTouchPadModeByte(UInt8 modeByteValue) return i == request.commandsCount; } - -void ApplePS2SynapticsTouchPad::setClickButtons(UInt32 clickButtons) -{ - UInt32 oldClickButtons = _clickbuttons; - _clickbuttons = clickButtons; - - if (!!oldClickButtons != !!clickButtons) - setModeByte(); -} - -bool ApplePS2SynapticsTouchPad::setModeByte() -{ - if (!_extendedwmodeSupported) - return false; - - _touchPadModeByte = _clickbuttons ? _touchPadModeByte | (1<<2) : _touchPadModeByte & ~(1<<2); - _extendedwmode = _clickbuttons; - - return setModeByte(_touchPadModeByte); -} - // simplified setModeByte for switching between normal mode and EW mode -bool ApplePS2SynapticsTouchPad::setModeByte(UInt8 modeByteValue) +bool ApplePS2SynapticsTouchPad::setModeByte(bool sleep) { // make sure we are not early in the initialization... if (!_device) return false; + + uint8_t modeByte = SYNA_MODE_ABSOLUTE | SYNA_MODE_W_MODE | SYNA_MODE_HIGH_RATE; + + if (_capabilities.extended_w_supported || + // Linux checks these bits too + _cont_caps.advanced_gestures || _cont_caps.reports_v) + modeByte |= SYNA_MODE_EXT_W; + + if (sleep) + modeByte |= SYNA_MODE_SLEEP; int i; TPS2Request<> request; @@ -2132,13 +1741,13 @@ bool ApplePS2SynapticsTouchPad::setModeByte(UInt8 modeByteValue) // 4 set resolution commands, each encode 2 data bits. request.commands[i++].inOrOut = kDP_SetMouseResolution; // E8 - request.commands[i++].inOrOut = (modeByteValue >> 6) & 0x3; // 0x (depends on mode byte) + request.commands[i++].inOrOut = (modeByte >> 6) & 0x3; // 0x (depends on mode byte) request.commands[i++].inOrOut = kDP_SetMouseResolution; // E8 - request.commands[i++].inOrOut = (modeByteValue >> 4) & 0x3; // 0x (depends on mode byte) + request.commands[i++].inOrOut = (modeByte >> 4) & 0x3; // 0x mode_byte request.commands[i++].inOrOut = kDP_SetMouseResolution; // E8 - request.commands[i++].inOrOut = (modeByteValue >> 2) & 0x3; // 0x (depends on mode byte) + request.commands[i++].inOrOut = (modeByte >> 2) & 0x3; // 0x (depends on mode byte) request.commands[i++].inOrOut = kDP_SetMouseResolution; // E8 - request.commands[i++].inOrOut = (modeByteValue >> 0) & 0x3; // 0x (depends on mode byte) + request.commands[i++].inOrOut = (modeByte >> 0) & 0x3; // 0x (depends on mode byte) // Set sample rate 20 to set mode byte 2. Older pads have 4 mode // bytes (0,1,2,3), but only mode byte 2 remain in modern pads. @@ -2146,9 +1755,6 @@ bool ApplePS2SynapticsTouchPad::setModeByte(UInt8 modeByteValue) request.commands[i++].inOrOut = 20; // 14 request.commands[i++].inOrOut = kDP_SetMouseScaling1To1; // E6 - // enable trackpad - request.commands[i++].inOrOut = kDP_Enable; // F4 - // all these commands are "send mouse" and "compare ack" for (int x = 0; x < i; x++) request.commands[x].command = kPS2C_SendCommandAndCompareAck; @@ -2163,7 +1769,7 @@ bool ApplePS2SynapticsTouchPad::setModeByte(UInt8 modeByteValue) // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void ApplePS2SynapticsTouchPad::setParamPropertiesGated(OSDictionary * config) +void ApplePS2SynapticsTouchPad::setPropertiesGated(OSDictionary * config) { if (NULL == config) return; @@ -2171,17 +1777,19 @@ void ApplePS2SynapticsTouchPad::setParamPropertiesGated(OSDictionary * config) const struct {const char *name; int *var;} int32vars[]={ {"FingerZ", &z_finger}, {"WakeDelay", &wakedelay}, - {"Resolution", &_resolution}, - {"ScrollResolution", &_scrollresolution}, - {"ButtonCount", &_buttonCount}, {"MinLogicalXOverride", &minXOverride}, {"MinLogicalYOverride", &minYOverride}, {"MaxLogicalXOverride", &maxXOverride}, {"MaxLogicalYOverride", &maxYOverride}, - {"TrackpointScrollXMultiplier", &thinkpadNubScrollXMultiplier}, - {"TrackpointScrollYMultiplier", &thinkpadNubScrollYMultiplier}, - {"MouseMultiplierX", &mousemultiplierx}, - {"MouseMultiplierY", &mousemultipliery}, + {"TrackpointDeadzone", &_deadzone}, + {"TrackpointScrollXMultiplier", &_scrollMultiplierX}, + {"TrackpointScrollYMultiplier", &_scrollMultiplierY}, + {"TrackpointScrollXDivisor", &_scrollDivisorX}, + {"TrackpointScrollYDivisor", &_scrollDivisorY}, + {"MouseMultiplierX", &_mouseMultiplierX}, + {"MouseMultiplierY", &_mouseMultiplierY}, + {"MouseDivisorX", &_mouseDivisorX}, + {"MouseDivisorY", &_mouseDivisorY}, {"ForceTouchMode", (int*)&_forceTouchMode}, // 0 - disable, 1 - left button, 2 - pressure threshold, 3 - pass pressure value {"ForceTouchPressureThreshold", &_forceTouchPressureThreshold}, // used in mode 2 {"SpecialKeyForQuietTime", &specialKey}, @@ -2191,11 +1799,7 @@ void ApplePS2SynapticsTouchPad::setParamPropertiesGated(OSDictionary * config) }; const struct {const char *name; int *var;} boolvars[]={ {"DisableLEDUpdate", &noled}, - {"SkipPassThrough", &skippassthru}, - {"ForcePassThrough", &forcepassthru}, - {"Thinkpad", &isthinkpad}, {"HWResetOnStart", &hwresetonstart}, - {"FakeMiddleButton", &_fakemiddlebutton}, {"ProcessUSBMouseStopsTrackpad", &_processusbmouse}, {"ProcessBluetoothMouseStopsTrackpad", &_processbluetoothmouse}, }; @@ -2205,22 +1809,10 @@ void ApplePS2SynapticsTouchPad::setParamPropertiesGated(OSDictionary * config) }; const struct {const char* name; uint64_t* var; } int64vars[]={ {"QuietTimeAfterTyping", &maxaftertyping}, - {"QuietTimeAfterSpecialKey", &maxafterspecialtyping}, - {"MiddleClickTime", &_maxmiddleclicktime}, + {"QuietTimeAfterSpecialKey", &maxafterspecialtyping} }; - uint8_t oldmode = _touchPadModeByte; - - // highrate? OSBoolean *bl; - if ((bl=OSDynamicCast (OSBoolean, config->getObject ("UseHighRate")))) - { - if (bl->isTrue()) - _touchPadModeByte |= 1<<6; - else - _touchPadModeByte &= ~(1<<6); - setProperty("UseHighRate", bl->isTrue()); - } OSNumber *num; // 64-bit config items @@ -2260,18 +1852,6 @@ void ApplePS2SynapticsTouchPad::setParamPropertiesGated(OSDictionary * config) } } - // this driver assumes wmode is available (6-byte packets) - _touchPadModeByte |= 1<<0; - // extendedwmode is optional, used automatically - _touchPadModeByte = _extendedwmodeSupported ? _touchPadModeByte | (1<<2) : _touchPadModeByte & ~(1<<2); - // if changed, setup touchpad mode - if (_touchPadModeByte != oldmode) - { - setTouchpadModeByte(); - _packetByteCount=0; - _ringBuffer.reset(); - } - // disable trackpad when USB mouse is plugged in and this functionality is requested if (attachedHIDPointerDevices && attachedHIDPointerDevices->getCount() > 0) { ignoreall = usb_mouse_stops_trackpad; @@ -2287,20 +1867,12 @@ void ApplePS2SynapticsTouchPad::setParamPropertiesGated(OSDictionary * config) PE_parse_boot_argn("auth-root-dmg", val, sizeof(val))) _forceTouchMode = FORCE_TOUCH_DISABLED; } -} - -IOReturn ApplePS2SynapticsTouchPad::setParamProperties(OSDictionary* dict) -{ - ////IOReturn result = super::IOHIDevice::setParamProperties(dict); - if (_cmdGate) - { - // syncronize through workloop... - ////_cmdGate->runAction(OSMemberFunctionCast(IOCommandGate::Action, this, &ApplePS2SynapticsTouchPad::setParamPropertiesGated), dict); - setParamPropertiesGated(dict); - } - return super::setParamProperties(dict); - ////return result; + setTrackpointProperties(); + if (voodooInputInstance != nullptr) { + super::messageClient(kIOMessageVoodooTrackpointUpdatePropertiesNotification, + voodooInputInstance, 0, 0); + } } IOReturn ApplePS2SynapticsTouchPad::setProperties(OSObject *props) @@ -2309,7 +1881,7 @@ IOReturn ApplePS2SynapticsTouchPad::setProperties(OSObject *props) if (dict && _cmdGate) { // synchronize through workloop... - _cmdGate->runAction(OSMemberFunctionCast(IOCommandGate::Action, this, &ApplePS2SynapticsTouchPad::setParamPropertiesGated), dict); + _cmdGate->runAction(OSMemberFunctionCast(IOCommandGate::Action, this, &ApplePS2SynapticsTouchPad::setPropertiesGated), dict); } return super::setProperties(props); @@ -2317,6 +1889,51 @@ IOReturn ApplePS2SynapticsTouchPad::setProperties(OSObject *props) // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +void ApplePS2SynapticsTouchPad::setTrackpointProperties() +{ + // Trackpoint information for VoodooInput + OSDictionary *trackpoint = OSDictionary::withCapacity(5); + if (trackpoint == nullptr) + return; + + OSNumber *deadzone = OSNumber::withNumber(_deadzone, 32); + OSNumber *buttonCnt = OSNumber::withNumber(3, 32); + OSNumber *multX = OSNumber::withNumber(_mouseMultiplierX, 32); + OSNumber *multY = OSNumber::withNumber(_mouseMultiplierY, 32); + OSNumber *divX = OSNumber::withNumber(_mouseDivisorX, 32); + OSNumber *divY = OSNumber::withNumber(_mouseDivisorY, 32); + OSNumber *scrollMultX = OSNumber::withNumber(_scrollMultiplierX, 32); + OSNumber *scrollMultY = OSNumber::withNumber(_scrollMultiplierY, 32); + OSNumber *scrollDivX = OSNumber::withNumber(_scrollDivisorX, 32); + OSNumber *scrollDivY = OSNumber::withNumber(_scrollDivisorY, 32); + + trackpoint->setObject(VOODOO_TRACKPOINT_DEADZONE, deadzone); + trackpoint->setObject(VOODOO_TRACKPOINT_BTN_CNT, buttonCnt); + trackpoint->setObject(VOODOO_TRACKPOINT_MOUSE_MULT_X, multX); + trackpoint->setObject(VOODOO_TRACKPOINT_MOUSE_MULT_Y, multY); + trackpoint->setObject(VOODOO_TRACKPOINT_MOUSE_DIV_X, divX); + trackpoint->setObject(VOODOO_TRACKPOINT_MOUSE_DIV_Y, divY); + trackpoint->setObject(VOODOO_TRACKPOINT_SCROLL_MULT_X, scrollMultX); + trackpoint->setObject(VOODOO_TRACKPOINT_SCROLL_MULT_Y, scrollMultY); + trackpoint->setObject(VOODOO_TRACKPOINT_SCROLL_DIV_X, scrollDivX); + trackpoint->setObject(VOODOO_TRACKPOINT_SCROLL_DIV_Y, scrollDivY); + setProperty(VOODOO_TRACKPOINT_KEY, trackpoint); + + OSSafeReleaseNULL(deadzone); + OSSafeReleaseNULL(buttonCnt); + OSSafeReleaseNULL(multX); + OSSafeReleaseNULL(multY); + OSSafeReleaseNULL(divX); + OSSafeReleaseNULL(divY); + OSSafeReleaseNULL(scrollMultX); + OSSafeReleaseNULL(scrollMultY); + OSSafeReleaseNULL(scrollDivX); + OSSafeReleaseNULL(scrollDivY); + OSSafeReleaseNULL(trackpoint); +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + void ApplePS2SynapticsTouchPad::setDevicePowerState( UInt32 whatToDo ) { if (otherBusInUse) { @@ -2334,8 +1951,7 @@ void ApplePS2SynapticsTouchPad::setDevicePowerState( UInt32 whatToDo ) setTouchPadEnable( false ); // Disable stream mode if (!disableDeepSleep) { - _touchPadModeByte |= 1 << 3; - setModeByte(_touchPadModeByte); // Enable sleep + setModeByte(true); // Enable sleep } break; @@ -2347,8 +1963,7 @@ void ApplePS2SynapticsTouchPad::setDevicePowerState( UInt32 whatToDo ) if (!disableDeepSleep) { IOSleep(wakedelay); - _touchPadModeByte &= ~(1 << 3); // Wake from sleep - setModeByte(_touchPadModeByte); + setModeByte(false); } IOSleep(wakedelay); @@ -2548,7 +2163,7 @@ IOReturn ApplePS2SynapticsTouchPad::message(UInt32 type, IOService* provider, vo void ApplePS2SynapticsTouchPad::updateTouchpadLED() { - if (ledpresent && !noled) + if (_extended_id.has_leds && !noled) setTouchpadLED(ignoreall ? 0x88 : 0x10); // if PS2M implements "TPDN" then, we can notify it of changes to LED state diff --git a/VoodooPS2Trackpad/VoodooPS2SynapticsTouchPad.h b/VoodooPS2Trackpad/VoodooPS2SynapticsTouchPad.h index 8f59be4f..3f80df61 100644 --- a/VoodooPS2Trackpad/VoodooPS2SynapticsTouchPad.h +++ b/VoodooPS2Trackpad/VoodooPS2SynapticsTouchPad.h @@ -24,138 +24,11 @@ #define _APPLEPS2SYNAPTICSTOUCHPAD_H #include "../VoodooPS2Controller/ApplePS2MouseDevice.h" -#include #include #include #include "VoodooInputMultitouch/VoodooInputEvent.h" #include "VoodooPS2TrackpadCommon.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; @@ -180,6 +53,135 @@ struct synaptics_virtual_finger_state { MT2FingerType fingerType; }; +#pragma pack(push) +#pragma pack(1) + +#define SYNAPTICS_IDENTIFY_QUERY 0x00 +struct synaptics_identify_trackpad { + uint8_t minor_ver; + uint8_t synaptics_const; + uint8_t major_ver : 4; + uint8_t model_code : 4; // Unused field +}; +static_assert(sizeof(synaptics_identify_trackpad) == 3, "Invalid Identity packet size"); + +#define SYNA_MODEL_QUERY 0x01 +struct synaptics_model { + uint8_t guest_present: 1; + uint8_t more_extended_caps: 1; + uint16_t model_number: 14; + uint8_t mode_byte; +}; +static_assert(sizeof(synaptics_model) == 3, "Invalid Model packet size"); + +#define SYNA_CAPABILITIES_QUERY 0x02 +struct synaptics_capabilities { + // Byte 0 + uint8_t _reserved0: 2; + uint8_t middle_btn: 1; + uint8_t _reserved1: 1; + uint8_t extended_queries: 3; + uint8_t has_extended_queries: 1; + // Byte 1 + uint8_t model_sub_num; + // Byte 2 + uint8_t palm_detect: 1; + uint8_t multi_finger: 1; + uint8_t ballistics: 1; + uint8_t sleep: 1; + uint8_t four_buttons: 1; // Currently unsupported + uint8_t extended_w_supported: 1; + uint8_t low_power: 1; + uint8_t passthrough: 1; +}; +static_assert(sizeof(synaptics_capabilities) == 3, "Invalid Capabilities packet size"); + +#define SYNA_SCALE_QUERY 0x08 +struct synaptics_scale { + uint8_t xupmm; + uint8_t reserved; + uint8_t yupmm; +}; +static_assert(sizeof(synaptics_scale) == 3, "Invalid Scale packet size"); + +#define SYNA_EXTENDED_ID_QUERY 0x09 +struct synaptics_extended_id { + // Byte 0 + uint8_t vert_scroll_zone: 1; + uint8_t horiz_scroll_zone: 1; + uint8_t extended_w_supported: 1; + uint8_t vertical_wheel: 1; + uint8_t transparent_passthru: 1; + uint8_t peak_detection: 1; + uint8_t has_leds: 1; + uint8_t reserved0: 1; + // Byte 1 + uint8_t reserved1: 2; + uint8_t info_sensor: 2; + uint8_t extended_btns: 4; + // Byte 2 + uint8_t product_id; +}; +static_assert(sizeof(synaptics_extended_id) == 3, "Invalid Extended ID packet size"); + +#define SYNA_CONT_CAPS_QUERY 0x0C +struct synaptics_cont_capabilities { + // Byte 0 + uint8_t adj_button_threshold: 1; + uint8_t reports_max: 1; + uint8_t is_clearpad: 1; + uint8_t advanced_gestures: 1; + uint8_t one_btn_clickpad: 1; + uint8_t multifinger_mode: 2; + uint8_t covered_pad_gesture: 1; + // Byte 1 + uint8_t two_btn_clickpad: 1; + uint8_t deluxe_leds: 1; + uint8_t no_abs_pos_filter: 1; + uint8_t reports_v: 1; + uint8_t uniform_clickpad: 1; + uint8_t reports_min: 1; + uint8_t intertouch: 1; + uint8_t reserved: 1; + // Byte 2 + uint8_t intertouch_addr; +}; +static_assert(sizeof(synaptics_cont_capabilities) == 3, "Invalid continued capabilities packet size"); + +#define SYNA_LOGIC_MAX_QUERY 0x0D +#define SYNA_LOGIC_MIN_QUERY 0x0F +#define SYNA_LOGIC_X(x) ((x.x_high << 5) | (x.x_low << 1)) +#define SYNA_LOGIC_Y(x) (x.y << 1) +struct synaptics_logic_min_max { + uint8_t x_high; + uint8_t x_low: 4; + uint16_t y: 12; +}; +static_assert(sizeof(synaptics_logic_min_max) == 3, "Invalid logic packet size"); + +#define SYNA_SECUREPAD_QUERY 0x10 +struct synaptics_securepad_id { + uint8_t trackstick_btns: 1; + uint8_t is_securepad: 1; + uint8_t unused: 6; + uint8_t securepad_width; + uint8_t securepad_height; +}; +static_assert(sizeof(synaptics_securepad_id) == 3, "Invalid securepad packet size"); + +#define SYNA_MODE_ABSOLUTE 0x80 +#define SYNA_MODE_HIGH_RATE 0x40 +#define SYNA_MODE_SLEEP 0x08 +#define SYNA_MODE_EXT_W 0x04 +#define SYNA_MODE_W_MODE 0x01 + +// W Values for packet types +#define SYNA_W_EXTENDED 0x02 +#define SYNA_W_PASSTHRU 0x03 + +#pragma pack(pop) + +#define SYNAPTICS_MAX_EXT_BTNS 8 #define SYNAPTICS_MAX_FINGERS 5 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -202,9 +204,9 @@ struct synaptics_virtual_finger_state { #define kPacketLength 6 -class EXPORT ApplePS2SynapticsTouchPad : public IOHIPointing +class EXPORT ApplePS2SynapticsTouchPad : public IOService { - typedef IOHIPointing super; + typedef IOService super; OSDeclareDefaultStructors(ApplePS2SynapticsTouchPad); private: @@ -215,19 +217,22 @@ class EXPORT ApplePS2SynapticsTouchPad : public IOHIPointing RingBuffer _ringBuffer {}; UInt32 _packetByteCount {0}; UInt8 _lastdata {0}; - UInt16 _touchPadVersion {0}; - UInt32 _boardID {0}; - UInt8 _touchPadType {0}; // from identify: either 0x46 or 0x47 - UInt8 _touchPadModeByte {0x80}; //default: absolute, low-rate, no w-mode + + synaptics_identify_trackpad _identity {0}; + synaptics_capabilities _capabilities {0}; + synaptics_extended_id _extended_id {0}; + synaptics_securepad_id _securepad {0}; + synaptics_scale _scale {0}; + synaptics_cont_capabilities _cont_caps {0}; IOCommandGate* _cmdGate {nullptr}; IOACPIPlatformDevice*_provider {nullptr}; VoodooInputEvent inputEvent {}; + TrackpointReport trackpointReport {}; // buttons and scroll wheel - bool left {false}; - bool right {false}; + bool _clickpad_pressed { false }; int margin_size_x {0}, margin_size_y {0}; uint32_t logical_max_x {0}; @@ -254,6 +259,11 @@ class EXPORT ApplePS2SynapticsTouchPad : public IOHIPointing int upperFingerIndex() const; const synaptics_hw_state& upperFinger() const; void swapFingers(int dst, int src); + + void synaptics_parse_normal_packet(const UInt8 buf[], const int w); + void synaptics_parse_agm_packet(const UInt8 buf[]); + void synaptics_parse_passthru(const UInt8 buf[], const UInt32 buttons); + int synaptics_parse_ext_btns(const UInt8 buf[], const int w); void synaptics_parse_hw_state(const UInt8 buf[]); /// Translates physical fingers into virtual fingers so that host software doesn't see 'jumps' and has coordinates for all fingers. @@ -275,40 +285,33 @@ class EXPORT ApplePS2SynapticsTouchPad : public IOHIPointing bool wasSkipped {false}; int z_finger {45}; int zlimit {0}; - int noled {0}; + int noled {0}; uint64_t maxaftertyping {500000000}; uint64_t maxafterspecialtyping {0}; int specialKey {0x80}; int wakedelay {1000}; - int skippassthru {0}; - int forcepassthru {0}; int hwresetonstart {0}; int diszl {0}, diszr {0}, diszt {0}, diszb {0}; - int _resolution {2300}, _scrollresolution {2300}; - int _buttonCount {2}; int minXOverride {-1}, minYOverride {-1}, maxXOverride {-1}, maxYOverride {-1}; - //vars for clickpad and middleButton support (thanks jakibaki) - int isthinkpad {0}; - int thinkpadButtonState {0}; - int thinkpadNubScrollXMultiplier {1}; - int thinkpadNubScrollYMultiplier {1}; - bool thinkpadMiddleScrolled {false}; - bool thinkpadMiddleButtonPressed {false}; - int mousemultiplierx {1}; - int mousemultipliery {1}; - + int _lastExtendedButtons {0}; + int _lastPassthruButtons {0}; + + // Trackpoint information + int _scrollMultiplierX {1}; + int _scrollMultiplierY {1}; + int _scrollDivisorX {1}; + int _scrollDivisorY {1}; + int _mouseMultiplierX {1}; + int _mouseMultiplierY {1}; + int _mouseDivisorX {1}; + int _mouseDivisorY {1}; + int _deadzone {1}; // state related to secondary packets/extendedwmode bool tracksecondary {false}; - bool _extendedwmode {false}, _extendedwmodeSupported {false}; - - // Capabilities for SMBus - bool trackstickButtons {false}; // normal state - UInt32 passbuttons {0}; - UInt32 lastbuttons {0}; uint64_t keytime {0}; UInt16 keycode {0}; bool ignoreall {false}; @@ -316,11 +319,6 @@ class EXPORT ApplePS2SynapticsTouchPad : public IOHIPointing #ifdef SIMULATE_PASSTHRU UInt32 trackbuttons {0}; #endif - bool passthru {false}; - bool ledpresent {false}; - bool _reportsv {false}; - int clickpadtype {0}; //0=not, 1=1button, 2=2button, 3=reserved - UInt32 _clickbuttons {0}; //clickbuttons to merge into buttons bool usb_mouse_stops_trackpad {true}; int _processusbmouse {true}; @@ -336,27 +334,6 @@ class EXPORT ApplePS2SynapticsTouchPad : public IOHIPointing int _modifierdown {0}; // state of left+right control keys - // for scaling x/y values - int xupmm {50}, yupmm {50}; // 50 is just arbitrary, but same - - // for middle button simulation - enum mbuttonstate - { - STATE_NOBUTTONS, - STATE_MIDDLE, - STATE_WAIT4TWO, - STATE_WAIT4NONE, - STATE_NOOP, - } _mbuttonstate {STATE_NOBUTTONS}; - - UInt32 _pendingbuttons {0}; - uint64_t _buttontime {0}; - IOTimerEventSource* _buttonTimer {nullptr}; - uint64_t _maxmiddleclicktime {100000000}; - int _fakemiddlebutton {true}; - - void setClickButtons(UInt32 clickButtons); - inline bool isInDisableZone(int x, int y) { return x > diszl && x < diszr && y > diszb && y < diszt; } @@ -367,62 +344,42 @@ class EXPORT ApplePS2SynapticsTouchPad : public IOHIPointing virtual void setTouchPadEnable( bool enable ); virtual bool getTouchPadData( UInt8 dataSelector, UInt8 buf3[] ); virtual bool getTouchPadStatus( UInt8 buf3[] ); - virtual bool setTouchPadModeByte(UInt8 modeByteValue); virtual PS2InterruptResult interruptOccurred(UInt8 data); virtual void packetReady(); virtual void setDevicePowerState(UInt32 whatToDo); void updateTouchpadLED(); bool setTouchpadLED(UInt8 touchLED); - bool setTouchpadModeByte(); // set based on state void initTouchPad(); - bool setModeByte(UInt8 modeByteValue); - bool setModeByte(); // set based on state + bool enterAdvancedGestureMode(); + bool setModeByte(bool sleep); inline bool isFingerTouch(int z) { return z>z_finger && zsetTimeout(*(AbsoluteTime*)&time); } - inline void cancelTimer(IOTimerEventSource* timer) - { timer->cancelTimeout(); } - + public: bool init( OSDictionary * properties ) override; ApplePS2SynapticsTouchPad * 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; diff --git a/VoodooPS2Trackpad/VoodooPS2Trackpad-Info.plist b/VoodooPS2Trackpad/VoodooPS2Trackpad-Info.plist index 9667a434..ecf1cfe6 100644 --- a/VoodooPS2Trackpad/VoodooPS2Trackpad-Info.plist +++ b/VoodooPS2Trackpad/VoodooPS2Trackpad-Info.plist @@ -292,14 +292,6 @@ CFBundleIdentifier as.acidanthera.voodoo.driver.PS2Trackpad - HIDPointerAccelerationTable - AACAAFVTQioABwAAAAAAAgAEAAAABAAAABAAAAAQAAAAACAAAA0AAIAAAACAAAABQAAAAYAAAAIAAAAC4AAAAwAAAATgAAAEAAAAB0AAAAUAAAAKAAAABgAAAA1AAAAIAAAAFgAAAArAAAAjAAAADQAAAC8AAAAOwAAAOMAAABBAAABBAAAAEcAAAEjAAAAAUAAADwAAgAAAAIAAAAEAAAABQAAAAYAAAAJAAAACAAAAA4AAAAKAAAAE4AAAAwAAAAZgAAAEAAAACgAAAAUAAAAOQAAABgAAABNAAAAIAAAAHsAAAArAAAAuwAAADQAAADyAAAAOwAAARwAAABBAAABPwAAAEcAAAFiAAAAAgAAADwAAgAAAAIAAAAEAAAABYAAAAYAAAAKgAAACAAAABEAAAAKAAAAGAAAAAwAAAAgAAAAEAAAADQAAAAUAAAASwAAABgAAABkAAAAIAAAAKAAAAArAAAA7wAAADQAAAEuAAAAOwAAAV0AAABBAAABgQAAAEcAAAGkAAAAAsAAADwAAgAAAAIAAAAEAAAABoAAAAYAAAAMAAAACAAAABQAAAAKAAAAHQAAAAwAAAAnAAAAEAAAAEEAAAAUAAAAXgAAABgAAAB/AAAAIAAAAMgAAAArAAABKAAAADQAAAFyAAAAOwAAAaQAAABBAAABywAAAEcAAAHrAAAAA4AAADwAAgAAAAKAAAAEAAAABwAAAAYAAAANgAAACAAAABeAAAAKAAAAIoAAAAwAAAAvAAAAEAAAAE8AAAAUAAAAdQAAABgAAACfAAAAIAAAAPcAAAArAAABZAAAADQAAAG3AAAAOwAAAe0AAABBAAACFQAAAEcAAAIxAAAABAAAADwAAgAAAAMAAAAEAAAACAAAAAYAAAAPgAAACAAAABsAAAAKAAAAKQAAAAwAAAA5gAAAEAAAAGMAAAAUAAAAkwAAABgAAADLAAAAIAAAATUAAAArAAABugAAADQAAAIMAAAAOwAAAj0AAABBAAACXAAAAEcAAAJxAAA== - HIDPointerAccelerationType - HIDTrackpadAcceleration - HIDScrollAccelerationTable - AACAAFVTQioABwAAAAAAAQABAAAAAQAAAAAgAAAQAABxOwAATOMAAwAAAAdgAAAEwAAADoAAAAbxSgAX6V4ACVeCACMQWgALZ6EALBF7AA2N1AA03ToAD36aADvQuAASWKAARl01ABUAAABO2dgAF8AAAFXK7QAas+UAW2FQAB2QAABe0qoAIL75AGEgywAkLXsAYnXvACewAABjRl8AAIAAABMAAHE7AABWfwABAAAAAuAAAAIAAAAJYAAAAwAAABIAAAAEwAAAIMAAAAaAAAAwgAAACGp5AEH9tgAK7bUAV4ZuAA0B2ABrPTkADv1/AIEEcAAQy5gAkdRWABJouQCe3VAAE+c/AKikCgAXAucAtn2SABot3ADARE4AHVjQAMX4OgAg35IAytuYACQ4bgDO7mUAJ6CXANIwowAAsAAAFAAAcTsAAGFOAADAAAABwAAAAQAAAANgAAACAAAADCAAAAMAAAAW4AAABMAAACnAAAAGQAAAOsAAAAfOggBP7OcACgWAAGo8rgAL658AhMCkAA2RCwCfR+EADzjIALWDbwAQ/k8AxqbEABLNUQDUeCMAFepmAOTKxwAZoVYA8qFmAB1CvwD7fXwAIQuCAQFpdAAkS20BBVKIACegAAEIK4wAAOAAABQAAHE7AABtdwAAwAAAAeAAAAEAAAAD4AAAAgAAAA6AAAADAAAAHEAAAATAAAA0AAAABgAAAEdAAAAHN4wAXL7hAAkAAACAwAAACoAAAKGAAAALz7IAvU7UAA01yQDadikADvtPAPKF4gARLu4BCSWiABUlDwEfV8QAGT9oASzRKgAdChkBNQrGACDz5QE6cR4AJEARAT3XdgAnn1YBQMHWAABQAAATAABxOwAAS7AAAQAAAAJgAAACAAAABuAAAAMAAAAMYAAABMAAABcAAAAGwAAAJAAAAAkAAAAyAAAACz1uAEFngAANcE8AUMGhAA+sTQBgSTMAEagdAG5NTAATT9YAd9WQABTQfgB+26MAF3odAIbYXQAagocAjp+lAB2J6QCTvnkAIN/yAJdcWwAkO0IAmYu9ACegOACacdcAAQAAABUAAHE7AABWfwAAwAAAAiAAAAEAAAAEgAAAAYAAAAqAAAACAAAAEaAAAAMAAAAhgAAABMAAAD6AAAAFwAAAVEAAAAbAAABrAAAACAAAAIxAAAAJAAAAqYAAAApAAADKwAAAC8AAAPTAAAANwAABJAAAABAAAAFEn9IAFEAAAV49zAAZAAABbrsYABzQAAFz78AAIOAAAXhvwAAkIAABem/AACegAAF8JGg= - HIDScrollAccelerationType - HIDTrackpadScrollAcceleration IOClass ApplePS2SynapticsTouchPad IOProbeScore @@ -310,36 +302,11 @@ Default - ButtonCount - 3 - Darwin 16+ - - ApplePreferenceCapability - - ApplePreferenceIdentifier - com.apple.AppleMultitouchTrackpad - MT Built-in - - MTHIDDevice - - SupportsGestureScrolling - - TrackpadEmbedded - - TrackpadFourFingerGestures - - TrackpadSecondaryClickCorners - - TrackpadThreeFingerDrag - - DisableDevice DisableLEDUpdating - FakeMiddleButton - - ForceTouchMode + TrackpointDeadzone 1 ForceTouchPressureThreshold 100 @@ -349,26 +316,16 @@ 20 ForceTouchCustomPower 8 - MiddleClickTime - 100000000 - MouseMiddleScroll - ProcessBluetoothMouseStopsTrackpad ProcessUSBMouseStopsTrackpad QuietTimeAfterTyping 500000000 - Resolution - 400 - ScrollResolution - 400 SkipPassThrough USBMouseStopsTrackpad 0 - UseHighRate - WakeDelay 1000 @@ -426,39 +383,25 @@ Thinkpad_ClickPad Thinkpad_ClickPad - FakeMiddleButton - FingerZ 30 HWResetOnStart - MouseMultiplierX + TrackpointMultiplierX 2 - MouseMultiplierY + TrackpointMultiplierY 2 - MouseScrollMultiplierX + TrackpointScrollMultiplierX 2 - MouseScrollMultiplierY + TrackpointScrollMultiplierY 2 - ScrollResolution - 800 - Thinkpad - Thinkpad_TrackPad - FakeMiddleButton - FingerZ 47 HWResetOnStart - Resolution - 3200 - ScrollResolution - 800 - Thinkpad - X1CG3 Thinkpad_ClickPad diff --git a/VoodooPS2Trackpad/VoodooPS2TrackpadCommon.h b/VoodooPS2Trackpad/VoodooPS2TrackpadCommon.h index d38d1957..88cd681f 100644 --- a/VoodooPS2Trackpad/VoodooPS2TrackpadCommon.h +++ b/VoodooPS2Trackpad/VoodooPS2TrackpadCommon.h @@ -9,6 +9,138 @@ #ifndef VoodooPS2TrackpadCommon_h #define VoodooPS2TrackpadCommon_h +#define TEST_BIT(x, y) ((x >> y) & 0x1) + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +// 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; + } +}; + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +// Force Touch Modes +// + typedef enum { FORCE_TOUCH_DISABLED = 0, FORCE_TOUCH_BUTTON = 1, From dac4bb4c0f046653ecb719c1e9becdbb22601601 Mon Sep 17 00:00:00 2001 From: Vitaly Cheptsov <4348897+vit9696@users.noreply.github.com> Date: Wed, 28 Dec 2022 00:42:46 +0300 Subject: [PATCH 080/101] Sync changelog --- Changelog.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/Changelog.md b/Changelog.md index aaf2210f..9b727b8d 100644 --- a/Changelog.md +++ b/Changelog.md @@ -1,5 +1,10 @@ VoodooPS2 Changelog ============================ +#### v2.3.3 +- Fixed rapidly opening pages in browsers while scrolling with the trackpoint +- Fixed buttons on various trackpads (especially those without trackpoints attached) +- Fixed DynamicEWMode problem on Lenovo ThinkPad Laptops (acidanthera/bugtracker#890) + #### v2.3.2 - Added `ps2kbdonly=1` argument not to disable touchpad line on reboot, thx @Kethen From 3f7f910db0d69a6a1898544dd5b71b5a070bfb7d Mon Sep 17 00:00:00 2001 From: Andrey1970AppleLife Date: Mon, 2 Jan 2023 19:44:26 +0300 Subject: [PATCH 081/101] 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 5dbb466b..0a8b5122 100644 --- a/VoodooPS2Controller.xcodeproj/project.pbxproj +++ b/VoodooPS2Controller.xcodeproj/project.pbxproj @@ -767,7 +767,7 @@ KERNEL_FRAMEWORK_HEADERS = "$(PROJECT_DIR)/MacKernelSDK/Headers"; "LLVM_LTO[arch=x86_64]" = YES; MACOSX_DEPLOYMENT_TARGET = 10.11; - MODULE_VERSION = 2.3.3; + MODULE_VERSION = 2.3.4; ONLY_ACTIVE_ARCH = YES; "OTHER_LDFLAGS[arch=x86_64]" = "-dead_strip"; PRODUCT_NAME = VoodooPS2Controller; @@ -822,7 +822,7 @@ KERNEL_FRAMEWORK_HEADERS = "$(PROJECT_DIR)/MacKernelSDK/Headers"; "LLVM_LTO[arch=x86_64]" = YES; MACOSX_DEPLOYMENT_TARGET = 10.11; - MODULE_VERSION = 2.3.3; + MODULE_VERSION = 2.3.4; "OTHER_LDFLAGS[arch=x86_64]" = "-dead_strip"; PRODUCT_NAME = VoodooPS2Controller; SDKROOT = macosx; From f7735a237f848be31a4decfde69fbde22dfde52a Mon Sep 17 00:00:00 2001 From: Avery Black Date: Fri, 3 Mar 2023 17:41:38 -0800 Subject: [PATCH 082/101] Fixed device count detection when `ps2rst=0` is set (#57) --- Changelog.md | 3 + VoodooPS2Controller/VoodooPS2Controller.cpp | 66 ++++++++++++--------- VoodooPS2Controller/VoodooPS2Controller.h | 2 +- 3 files changed, 42 insertions(+), 29 deletions(-) diff --git a/Changelog.md b/Changelog.md index 9b727b8d..5f5221c1 100644 --- a/Changelog.md +++ b/Changelog.md @@ -1,5 +1,8 @@ VoodooPS2 Changelog ============================ +#### v2.3.4 +- Fixed device count detection when `ps2rst=0` is set. + #### v2.3.3 - Fixed rapidly opening pages in browsers while scrolling with the trackpoint - Fixed buttons on various trackpads (especially those without trackpoints attached) diff --git a/VoodooPS2Controller/VoodooPS2Controller.cpp b/VoodooPS2Controller/VoodooPS2Controller.cpp index 1f454485..497b47bc 100644 --- a/VoodooPS2Controller/VoodooPS2Controller.cpp +++ b/VoodooPS2Controller/VoodooPS2Controller.cpp @@ -369,7 +369,7 @@ IOReturn ApplePS2Controller::setProperties(OSObject* props) // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void ApplePS2Controller::resetController(bool wakeup) +void ApplePS2Controller::resetController() { _suppressTimeout = true; UInt8 commandByte; @@ -415,30 +415,6 @@ void ApplePS2Controller::resetController(bool wakeup) writeCommandPort(kCP_SetCommandByte); writeDataPort(commandByte); DEBUG_LOG("%s: new commandByte = %02x\n", getName(), commandByte); - - if (wakeup && _muxPresent) - { - setMuxMode(true); - } - else if (!wakeup) - { - if (!_kbdOnly){ - _muxPresent = setMuxMode(true); - _nubsCount = _muxPresent ? kPS2MuxMaxIdx : kPS2AuxMaxIdx; - }else{ - _muxPresent = false; - _nubsCount = 1; - } - } - - resetDevices(); - - // - // Clear out garbage in the controller's input streams, before starting up - // the work loop. - // - - flushDataPort(); } // -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -548,9 +524,32 @@ bool ApplePS2Controller::start(IOService * provider) PE_parse_boot_argn("ps2rst", &_resetControllerFlag, sizeof(_resetControllerFlag)); if (_resetControllerFlag & RESET_CONTROLLER_ON_BOOT) { - resetController(false); + resetController(); } + // + // Enable "Active PS/2 Multiplexing" if it exists. + // This creates 4 Aux ports which pointing devices may connect to. + // + + if (_kbdOnly) { + _muxPresent = false; + _nubsCount = 1; + } else { + _muxPresent = setMuxMode(true); + _nubsCount = _muxPresent ? kPS2MuxMaxIdx : kPS2AuxMaxIdx; + } + + // + // Reset attached devices and clear out garbage in the controller's input streams, + // before starting up the work loop. + // + + if (_resetControllerFlag & RESET_CONTROLLER_ON_BOOT) { + resetDevices(); + flushDataPort(); + } + // // Use a spin lock to protect the client async request queue. // @@ -1875,12 +1874,23 @@ void ApplePS2Controller::setPowerStateGated( UInt32 powerState ) if (_resetControllerFlag & RESET_CONTROLLER_ON_WAKEUP) { - resetController(true); + resetController(); } #endif // FULL_INIT_AFTER_WAKE - + if (_muxPresent) { + setMuxMode(true); + } + +#if FULL_INIT_AFTER_WAKE + if (_resetControllerFlag & RESET_CONTROLLER_ON_WAKEUP) + { + resetDevices(); + flushDataPort(); + } +#endif // FULL_INIT_AFTER_WAKE + // // Transition from Sleep state to Working state in 4 stages. // diff --git a/VoodooPS2Controller/VoodooPS2Controller.h b/VoodooPS2Controller/VoodooPS2Controller.h index ea8d8ee6..eb97fc56 100644 --- a/VoodooPS2Controller/VoodooPS2Controller.h +++ b/VoodooPS2Controller/VoodooPS2Controller.h @@ -305,7 +305,7 @@ class EXPORT ApplePS2Controller : public IOService virtual UInt8 readDataPort(size_t port); virtual void writeCommandPort(UInt8 byte); virtual void writeDataPort(UInt8 byte); - void resetController(bool); + void resetController(void); bool setMuxMode(bool); void flushDataPort(void); void resetDevices(void); From 6ff8271366ea498a8f7f3846b5127ca889d3d1da Mon Sep 17 00:00:00 2001 From: Avery Black Date: Fri, 3 Mar 2023 18:15:12 -0800 Subject: [PATCH 083/101] Fixed handleClose not being called by VoodooInput (#56) --- Changelog.md | 3 ++- VoodooPS2Trackpad/VoodooPS2ALPSGlidePoint.cpp | 15 ++++++++++++--- VoodooPS2Trackpad/VoodooPS2ALPSGlidePoint.h | 1 + VoodooPS2Trackpad/VoodooPS2Elan.cpp | 15 ++++++++++++--- VoodooPS2Trackpad/VoodooPS2Elan.h | 1 + VoodooPS2Trackpad/VoodooPS2SynapticsTouchPad.cpp | 15 ++++++++++++--- VoodooPS2Trackpad/VoodooPS2SynapticsTouchPad.h | 1 + 7 files changed, 41 insertions(+), 10 deletions(-) diff --git a/Changelog.md b/Changelog.md index 5f5221c1..babb898f 100644 --- a/Changelog.md +++ b/Changelog.md @@ -1,7 +1,8 @@ VoodooPS2 Changelog ============================ #### v2.3.4 -- Fixed device count detection when `ps2rst=0` is set. +- Fixed device count detection when `ps2rst=0` is set +- Fixed handleClose not being called by VoodooInput #### v2.3.3 - Fixed rapidly opening pages in browsers while scrolling with the trackpoint diff --git a/VoodooPS2Trackpad/VoodooPS2ALPSGlidePoint.cpp b/VoodooPS2Trackpad/VoodooPS2ALPSGlidePoint.cpp index 5b02ee68..85ae570a 100644 --- a/VoodooPS2Trackpad/VoodooPS2ALPSGlidePoint.cpp +++ b/VoodooPS2Trackpad/VoodooPS2ALPSGlidePoint.cpp @@ -313,12 +313,21 @@ bool ApplePS2ALPSGlidePoint::handleOpen(IOService *forClient, IOOptionBits optio return true; } - return super::handleOpen(forClient, options, arg); + return false; +} + +bool ApplePS2ALPSGlidePoint::handleIsOpen(const IOService *forClient) const { + if (forClient == nullptr) { + return voodooInputInstance != nullptr; + } else { + return voodooInputInstance == forClient; + } } void ApplePS2ALPSGlidePoint::handleClose(IOService *forClient, IOOptionBits options) { - OSSafeReleaseNULL(voodooInputInstance); - super::handleClose(forClient, options); + if (forClient == voodooInputInstance) { + OSSafeReleaseNULL(voodooInputInstance); + } } bool ApplePS2ALPSGlidePoint::start( IOService * provider ) { diff --git a/VoodooPS2Trackpad/VoodooPS2ALPSGlidePoint.h b/VoodooPS2Trackpad/VoodooPS2ALPSGlidePoint.h index bab4b59f..5f5804bf 100644 --- a/VoodooPS2Trackpad/VoodooPS2ALPSGlidePoint.h +++ b/VoodooPS2Trackpad/VoodooPS2ALPSGlidePoint.h @@ -441,6 +441,7 @@ class EXPORT ApplePS2ALPSGlidePoint : public IOService { bool resetMouse(); bool handleOpen(IOService *forClient, IOOptionBits options, void *arg) override; void handleClose(IOService *forClient, IOOptionBits options) override; + bool handleIsOpen(const IOService *forClient) const override; PS2InterruptResult interruptOccurred(UInt8 data); void packetReady(); virtual bool deviceSpecificInit(); diff --git a/VoodooPS2Trackpad/VoodooPS2Elan.cpp b/VoodooPS2Trackpad/VoodooPS2Elan.cpp index 09d4e842..cfa23539 100644 --- a/VoodooPS2Trackpad/VoodooPS2Elan.cpp +++ b/VoodooPS2Trackpad/VoodooPS2Elan.cpp @@ -183,12 +183,21 @@ bool ApplePS2Elan::handleOpen(IOService *forClient, IOOptionBits options, void * return true; } - return super::handleOpen(forClient, options, arg); + return false; +} + +bool ApplePS2Elan::handleIsOpen(const IOService *forClient) const { + if (forClient == nullptr) { + return voodooInputInstance != nullptr; + } else { + return voodooInputInstance == forClient; + } } void ApplePS2Elan::handleClose(IOService *forClient, IOOptionBits options) { - OSSafeReleaseNULL(voodooInputInstance); - super::handleClose(forClient, options); + if (forClient == voodooInputInstance) { + OSSafeReleaseNULL(voodooInputInstance); + } } bool ApplePS2Elan::start(IOService *provider) { diff --git a/VoodooPS2Trackpad/VoodooPS2Elan.h b/VoodooPS2Trackpad/VoodooPS2Elan.h index 07dd6143..7a2d0143 100644 --- a/VoodooPS2Trackpad/VoodooPS2Elan.h +++ b/VoodooPS2Trackpad/VoodooPS2Elan.h @@ -281,6 +281,7 @@ class EXPORT ApplePS2Elan : public IOHIPointing { bool handleOpen(IOService *forClient, IOOptionBits options, void *arg) override; void handleClose(IOService *forClient, IOOptionBits options) override; + bool handleIsOpen(const IOService *forClient) const override; void setParamPropertiesGated(OSDictionary *dict); void injectVersionDependentProperties(OSDictionary *dict); diff --git a/VoodooPS2Trackpad/VoodooPS2SynapticsTouchPad.cpp b/VoodooPS2Trackpad/VoodooPS2SynapticsTouchPad.cpp index 8c2301e9..88915ae9 100644 --- a/VoodooPS2Trackpad/VoodooPS2SynapticsTouchPad.cpp +++ b/VoodooPS2Trackpad/VoodooPS2SynapticsTouchPad.cpp @@ -391,12 +391,21 @@ bool ApplePS2SynapticsTouchPad::handleOpen(IOService *forClient, IOOptionBits op return true; } - return super::handleOpen(forClient, options, arg); + return false; +} + +bool ApplePS2SynapticsTouchPad::handleIsOpen(const IOService *forClient) const { + if (forClient == nullptr) { + return voodooInputInstance != nullptr; + } else { + return voodooInputInstance == forClient; + } } void ApplePS2SynapticsTouchPad::handleClose(IOService *forClient, IOOptionBits options) { - OSSafeReleaseNULL(voodooInputInstance); - super::handleClose(forClient, options); + if (forClient == voodooInputInstance) { + OSSafeReleaseNULL(voodooInputInstance); + } } bool ApplePS2SynapticsTouchPad::start( IOService * provider ) diff --git a/VoodooPS2Trackpad/VoodooPS2SynapticsTouchPad.h b/VoodooPS2Trackpad/VoodooPS2SynapticsTouchPad.h index 3f80df61..85c7a1dc 100644 --- a/VoodooPS2Trackpad/VoodooPS2SynapticsTouchPad.h +++ b/VoodooPS2Trackpad/VoodooPS2SynapticsTouchPad.h @@ -361,6 +361,7 @@ class EXPORT ApplePS2SynapticsTouchPad : public IOService bool handleOpen(IOService *forClient, IOOptionBits options, void *arg) override; void handleClose(IOService *forClient, IOOptionBits options) override; + bool handleIsOpen(const IOService *forClient) const override; void setPropertiesGated(OSDictionary* dict); void injectVersionDependentProperties(OSDictionary* dict); From 89ae5637f62f8a9179fb8932493bfa21e7e87fe9 Mon Sep 17 00:00:00 2001 From: Andrey1970AppleLife Date: Mon, 6 Mar 2023 22:17:50 +0300 Subject: [PATCH 084/101] 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 0a8b5122..214a98aa 100644 --- a/VoodooPS2Controller.xcodeproj/project.pbxproj +++ b/VoodooPS2Controller.xcodeproj/project.pbxproj @@ -767,7 +767,7 @@ KERNEL_FRAMEWORK_HEADERS = "$(PROJECT_DIR)/MacKernelSDK/Headers"; "LLVM_LTO[arch=x86_64]" = YES; MACOSX_DEPLOYMENT_TARGET = 10.11; - MODULE_VERSION = 2.3.4; + MODULE_VERSION = 2.3.5; ONLY_ACTIVE_ARCH = YES; "OTHER_LDFLAGS[arch=x86_64]" = "-dead_strip"; PRODUCT_NAME = VoodooPS2Controller; @@ -822,7 +822,7 @@ KERNEL_FRAMEWORK_HEADERS = "$(PROJECT_DIR)/MacKernelSDK/Headers"; "LLVM_LTO[arch=x86_64]" = YES; MACOSX_DEPLOYMENT_TARGET = 10.11; - MODULE_VERSION = 2.3.4; + MODULE_VERSION = 2.3.5; "OTHER_LDFLAGS[arch=x86_64]" = "-dead_strip"; PRODUCT_NAME = VoodooPS2Controller; SDKROOT = macosx; From a4a3f14a9d8e217ab7612ef0a5195f3a8fd2e1cb Mon Sep 17 00:00:00 2001 From: Avery Black Date: Sat, 1 Apr 2023 15:14:06 -0700 Subject: [PATCH 085/101] Remove actAsTrackpad and related logic (#58) --- Docs/ACPI/SSDT-MouseAsTrackpad.dsl | 16 - VoodooPS2Controller.xcodeproj/project.pbxproj | 2 - VoodooPS2Mouse/VoodooPS2Mouse-Info.plist | 91 ---- VoodooPS2Mouse/VoodooPS2Mouse.cpp | 487 +----------------- VoodooPS2Mouse/VoodooPS2Mouse.h | 35 +- 5 files changed, 12 insertions(+), 619 deletions(-) delete mode 100644 Docs/ACPI/SSDT-MouseAsTrackpad.dsl diff --git a/Docs/ACPI/SSDT-MouseAsTrackpad.dsl b/Docs/ACPI/SSDT-MouseAsTrackpad.dsl deleted file mode 100644 index 4994d843..00000000 --- a/Docs/ACPI/SSDT-MouseAsTrackpad.dsl +++ /dev/null @@ -1,16 +0,0 @@ -// VoodooPS2Mouse.kext has the ability to appear as a trackpad. -// Most "trackpad" related settings don't work with it, but it will -// enable a few extra features. -DefinitionBlock("", "SSDT", 2, "ACDT", "ps2", 0) -{ - External (_SB_.PCI0.LPCB.PS2K, DeviceObj) - - Name(_SB.PCI0.LPCB.PS2K.RMCF, Package() - { - "Mouse", Package() - { - "ActLikeTrackpad", ">y", - }, - }) -} -//EOF diff --git a/VoodooPS2Controller.xcodeproj/project.pbxproj b/VoodooPS2Controller.xcodeproj/project.pbxproj index 214a98aa..57950f22 100644 --- a/VoodooPS2Controller.xcodeproj/project.pbxproj +++ b/VoodooPS2Controller.xcodeproj/project.pbxproj @@ -113,7 +113,6 @@ 9828A92D24A2B6C200550FAA /* VoodooPS2Elan.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = VoodooPS2Elan.cpp; sourceTree = ""; }; 9828A92E24A2B6C200550FAA /* VoodooPS2Elan.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = VoodooPS2Elan.h; sourceTree = ""; }; CE39B4E122D0CCC200D344F3 /* Changelog.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = Changelog.md; sourceTree = ""; }; - CE7F451122E8A8C4003F7971 /* SSDT-MouseAsTrackpad.dsl */ = {isa = PBXFileReference; lastKnownFileType = text; path = "SSDT-MouseAsTrackpad.dsl"; sourceTree = ""; }; CE7F451222E8A8ED003F7971 /* SynapticsRevB.pdf */ = {isa = PBXFileReference; lastKnownFileType = image.pdf; path = SynapticsRevB.pdf; sourceTree = ""; }; CE7F451322E8A8ED003F7971 /* voodoops2ioio.sh */ = {isa = PBXFileReference; lastKnownFileType = text.script.sh; path = voodoops2ioio.sh; sourceTree = ""; }; CE7F451422E8A8F8003F7971 /* Changelog.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = Changelog.md; sourceTree = SOURCE_ROOT; }; @@ -318,7 +317,6 @@ children = ( 73119AB725E1961D0017311C /* SSDT-NumLockOnAtBoot.dsl */, 73119AB825E1961D0017311C /* SSDT-NumLockSupport.dsl */, - CE7F451122E8A8C4003F7971 /* SSDT-MouseAsTrackpad.dsl */, ED48777A207D94BC00D6B1E8 /* SSDT-AlternateSwipes.dsl */, CEF251412631A92B00A20C9A /* SSDT-DisableDeepSleep.dsl */, CEAFF570259F8AE700693DEC /* SSDT-DisableElanWakeDelay.dsl */, diff --git a/VoodooPS2Mouse/VoodooPS2Mouse-Info.plist b/VoodooPS2Mouse/VoodooPS2Mouse-Info.plist index 6de86ef2..1efb2d9f 100644 --- a/VoodooPS2Mouse/VoodooPS2Mouse-Info.plist +++ b/VoodooPS2Mouse/VoodooPS2Mouse-Info.plist @@ -26,10 +26,6 @@ CFBundleIdentifier as.acidanthera.voodoo.driver.PS2Mouse - HIDPointerAccelerationType - HIDTrackpadAcceleration - HIDScrollAccelerationType - HIDTrackpadScrollAcceleration IOClass ApplePS2Mouse IOProviderClass @@ -38,37 +34,12 @@ Default - ActLikeTrackpad - ButtonCount 3 - Darwin 16+ - - ApplePreferenceCapability - - ApplePreferenceIdentifier - com.apple.AppleMultitouchTrackpad - MT Built-in - - MTHIDDevice - - SupportsGestureScrolling - - TrackpadEmbedded - - TrackpadFourFingerGestures - - TrackpadSecondaryClickCorners - - TrackpadThreeFingerDrag - - DefaultResolution 240 DisableDevice - DisableLEDUpdating - FakeMiddleButton ForceDefaultResolution @@ -81,78 +52,16 @@ 0 MouseYInverter 1 - ProcessBluetoothMouseStopsTrackpad - - ProcessUSBMouseStopsTrackpad - - QuietTimeAfterTyping - 500000000 ResolutionMode 3 ScrollResolution 5 ScrollYInverter 1 - TrackpadScroll - WakeDelay 1000 - 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 - - ActLikeTrackpad - - DisableDevice - - - ProBook-102 - ProBook - ProBook-87 - ProBook - - ProductID - 547 - RM,deliverNotifications - - USBMouseStopsTrackpad - 0 - VendorID - 1452 OSBundleLibraries diff --git a/VoodooPS2Mouse/VoodooPS2Mouse.cpp b/VoodooPS2Mouse/VoodooPS2Mouse.cpp index b2dcb43f..2bbebf02 100644 --- a/VoodooPS2Mouse/VoodooPS2Mouse.cpp +++ b/VoodooPS2Mouse/VoodooPS2Mouse.cpp @@ -74,22 +74,11 @@ bool ApplePS2Mouse::init(OSDictionary * dict) _type = kMouseTypeStandard; _buttonCount = 3; _mouseInfoBytes = (UInt32)-1; - ignoreall = false; - ledpresent = false; resmode = -1; forcesetres = false; scrollres = 10; - actliketrackpad = false; - keytime = 0; - maxaftertyping = 500000000; - buttonmask = ~0; - scroll = true; - noled = false; wakedelay = 1000; - usb_mouse_stops_trackpad = true; _cmdGate = 0; - _processusbmouse = true; - _processbluetoothmouse = true; // state for middle button _buttonTimer = 0; @@ -123,22 +112,12 @@ void ApplePS2Mouse::setParamPropertiesGated(OSDictionary * config) const struct {const char *name; int *var;} boolvars[]={ {"ForceDefaultResolution", &forceres}, {"ForceSetResolution", &forcesetres}, - {"ActLikeTrackpad", &actliketrackpad}, - {"DisableLEDUpdating", &noled}, {"FakeMiddleButton", &_fakemiddlebutton}, - {"ProcessUSBMouseStopsTrackpad", &_processusbmouse}, - {"ProcessBluetoothMouseStopsTrackpad", &_processbluetoothmouse}, }; const struct {const char* name; bool* var;} lowbitvars[]={ - {"TrackpadScroll", &scroll}, - {"OutsidezoneNoAction When Typing", &outzone_wt}, - {"PalmNoAction Permanent", &palm}, - {"PalmNoAction When Typing", &palm_wt}, - {"USBMouseStopsTrackpad", &usb_mouse_stops_trackpad}, }; const struct {const char* name; uint64_t* var; } int64vars[]={ {"MiddleClickTime", &_maxmiddleclicktime}, - {"QuietTimeAfterTyping", &maxaftertyping}, }; @@ -173,12 +152,6 @@ void ApplePS2Mouse::setParamPropertiesGated(OSDictionary * config) *int32vars[i].var = num->unsigned32BitValue(); setProperty(int32vars[i].name, *int32vars[i].var, 32); } - - // disable trackpad when USB mouse is plugged in and this functionality is requested - if (attachedHIDPointerDevices && attachedHIDPointerDevices->getCount() > 0) { - ignoreall = usb_mouse_stops_trackpad; - updateTouchpadLED(); - } // convert to IOFixed format... defres <<= 16; @@ -212,42 +185,6 @@ IOReturn ApplePS2Mouse::setProperties(OSObject *props) // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void ApplePS2Mouse::injectVersionDependentProperties(OSDictionary *config) -{ - // inject properties specific to the version of Darwin that is runnning... - char buf[32]; - 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)))) - break; - // check for "Darwin major.x" - snprintf(buf, sizeof(buf), "Darwin %d.x", version_major); - 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+")))) - break; - } while (0); - - if (dict) - { - // found version specific properties above, inject... - 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)) - setProperty(key, value); - } - iter->release(); - } - } -} - ApplePS2Mouse* ApplePS2Mouse::probe(IOService * provider, SInt32 * score) { DEBUG_LOG("ApplePS2Mouse::probe entered...\n"); @@ -284,22 +221,9 @@ ApplePS2Mouse* ApplePS2Mouse::probe(IOService * provider, SInt32 * score) // load settings setParamPropertiesGated(config); - if (actliketrackpad) - injectVersionDependentProperties(config); OSSafeReleaseNULL(config); } - // remove some properties so system doesn't think it is a trackpad - // this should cause "Product" = "Mouse" in ioreg. - if (!actliketrackpad) - { - removeProperty("VendorID"); - removeProperty("ProductID"); - removeProperty("HIDPointerAccelerationType"); - removeProperty("HIDScrollAccelerationType"); - removeProperty("TrackpadScroll"); - } - // // Check to see if acknowledges are being received for commands to the mouse. // @@ -370,13 +294,6 @@ bool ApplePS2Mouse::start(IOService * provider) resetMouse(); pWorkLoop->addEventSource(_cmdGate); - - attachedHIDPointerDevices = OSSet::withCapacity(1); - if (attachedHIDPointerDevices == nullptr) - { - return false; - } - registerHIDPointerNotifications(); // // Setup button timer event source @@ -409,11 +326,8 @@ bool ApplePS2Mouse::start(IOService * provider) // Request message registration for keyboard to trackpad communication // - if (actliketrackpad) - { - //setProperty(kDeliverNotifications, true); - } - + setProperty(kDeliverNotifications, true); + return true; } @@ -428,9 +342,6 @@ void ApplePS2Mouse::stop(IOService * provider) // assert(_device == provider); - - unregisterHIDPointerNotifications(); - OSSafeReleaseNULL(attachedHIDPointerDevices); // // Disable the mouse itself, so that it may stop reporting mouse events. @@ -515,26 +426,6 @@ void ApplePS2Mouse::resetMouse() _device->submitRequestAndBlock(&request); if (6 != request.commandsCount) DEBUG_LOG("%s: reset mouse sequence failed: %d\n", getName(), request.commandsCount); - - // Now deal with Synaptics specifics (ActLikeTrackpad trick)... - ledpresent = false; - do if (actliketrackpad && !noled) - { - // do Synaptics specific, but only if it is Synaptics device - UInt8 buf3[3]; - if (!getTouchPadData(0x0, buf3) || (0x46 != buf3[1] && 0x47 != buf3[1])) - break; - // it is Synaptics, now test for LED capability... - if (!getTouchPadData(0x2, buf3) || !(buf3[0] & 0x80)) - break; - int nExtendedQueries = (buf3[0] & 0x70) >> 4; - // check LED capability if query is supported - if (nExtendedQueries >= 1 && getTouchPadData(0x9, buf3)) - { - ledpresent = (buf3[0] >> 6) & 1; - DEBUG_LOG("%s: ledpresent=%d\n", getName(), ledpresent); - } - } while (false); // // Obtain our mouse's resolution and sampling rate. @@ -583,10 +474,7 @@ void ApplePS2Mouse::resetMouse() // be present to enable acceleration for Z-axis movement. // setProperty(kIOHIDScrollResolutionKey, (scrollres << 16), 32); - if (!actliketrackpad) - setProperty(kIOHIDScrollAccelerationTypeKey, kIOHIDMouseAccelerationType); - else - setProperty(kIOHIDScrollAccelerationTypeKey, kIOHIDTrackpadAccelerationType); + setProperty(kIOHIDScrollAccelerationTypeKey, kIOHIDMouseAccelerationType); } else { @@ -595,10 +483,8 @@ void ApplePS2Mouse::resetMouse() removeProperty(kIOHIDScrollResolutionKey); removeProperty(kIOHIDScrollAccelerationTypeKey); } - if (!actliketrackpad) - setProperty(kIOHIDPointerAccelerationTypeKey, kIOHIDMouseAccelerationType); - else - setProperty(kIOHIDPointerAccelerationTypeKey, kIOHIDTrackpadAccelerationType); + + setProperty(kIOHIDPointerAccelerationTypeKey, kIOHIDMouseAccelerationType); // simulate three buttons with only two buttons if enabled @@ -734,7 +620,7 @@ void ApplePS2Mouse::onButtonTimer(void) UInt32 ApplePS2Mouse::middleButton(UInt32 buttons, uint64_t now_abs, MBComingFrom from) { - if (!_fakemiddlebutton || _buttonCount <= 2 || (ignoreall && fromMouse == from)) + if (!_fakemiddlebutton || _buttonCount <= 2) return buttons; // cancel timer if we see input before timeout has fired, but after expired @@ -903,37 +789,24 @@ void ApplePS2Mouse::dispatchRelativePointerEventWithPacket(UInt8 * packet, // PS2 mice is -8 to +7, thus the upper four bits are just a sign // bit. If we just sign extend the lower four bits, the scroll // calculation works for normal scrollwheel mice and five button mice. - if (!actliketrackpad || scroll) - dz = (SInt16)(((SInt8)(packet[3] << 4)) >> 4); + dz = (SInt16)(((SInt8)(packet[3] << 4)) >> 4); } buttons = middleButton(buttons, now_abs, fromMouse); lastbuttons = buttons; - // ignore button 1 and 2 (could be simulated by trackpad) if just after typing - if (palm_wt || outzone_wt) - { - if (now_ns-keytime <= maxaftertyping) - buttonmask = ~(buttons & 0x3); - else - buttonmask = ~0; - buttons &= buttonmask; - } - - if (!ignoreall) - dispatchRelativePointerEventX(dx, mouseyinverter*dy, buttons, now_abs); + dispatchRelativePointerEventX(dx, mouseyinverter*dy, buttons, now_abs); - if ( dz && (!(palm_wt || outzone_wt) || now_ns-keytime > maxaftertyping)) + if (dz) { // // The Z counter is negative on an upwards scroll (away from the user), // and positive when scrolling downwards. Invert this before passing to // HID/CG. // - if (!ignoreall) - dispatchScrollWheelEventX(-scrollyinverter*dz, 0, 0, now_abs); + dispatchScrollWheelEventX(-scrollyinverter*dz, 0, 0, now_abs); } - + #ifdef DEBUG_VERBOSE IOLog("ps2m: dx=%d, dy=%d, dz=%d, buttons=%d\n", dx, dy, dz, buttons); #endif @@ -1204,344 +1077,6 @@ void ApplePS2Mouse::setDevicePowerState( UInt32 whatToDo ) // Enable mouse and restore state. resetMouse(); - - // update touchpad LED after sleep - updateTouchpadLED(); - break; - } -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -IOReturn ApplePS2Mouse::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 is true when trackpad has been disabled - if (enable == ignoreall) - { - // save state, and update LED - ignoreall = !enable; - updateTouchpadLED(); - } - break; - } - - case kPS2M_notifyKeyTime: - { - // just remember last time key pressed... this can be used in - // interrupt handler to detect unintended input while typing - keytime = *((uint64_t*)argument); break; - } - } - - return kIOReturnSuccess; -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -// -// This code is specific to Synaptics Touchpads that have an LED indicator, but -// it does no harm to Synaptics units that don't have an LED. -// -// Generally it is used to indicate that the touchpad has been made inactive. -// -// In the case of this package, we can disable the touchpad with both keyboard -// and the touchpad itself. -// -// Linux sources were very useful in figuring this out... -// This patch to support HP Probook Synaptics LED in Linux was where found the -// information: -// https://github.com/mmonaco/PKGBUILDs/blob/master/synaptics-led/synled.patch -// -// To quote from the email: -// -// From: Takashi Iwai -// Date: Sun, 16 Sep 2012 14:19:41 -0600 -// Subject: [PATCH] input: Add LED support to Synaptics device -// -// The new Synaptics devices have an LED on the top-left corner. -// This patch adds a new LED class device to control it. It's created -// dynamically upon synaptics device probing. -// -// The LED is controlled via the command 0x0a with parameters 0x88 or 0x10. -// This seems only on/off control although other value might be accepted. -// -// The detection of the LED isn't clear yet. It should have been the new -// capability bits that indicate the presence, but on real machines, it -// doesn't fit. So, for the time being, the driver checks the product id -// in the ext capability bits and assumes that LED exists on the known -// devices. -// -// Signed-off-by: Takashi Iwai -// - -//REVIEW: this code copied from VoodooPS2SynapticsTouchPad.cpp -// would be nice to figure out how to share this code between the two kexts - -void ApplePS2Mouse::updateTouchpadLED() -{ - if (ledpresent && !noled) - setTouchpadLED(ignoreall ? 0x88 : 0x10); -} - -bool ApplePS2Mouse::setTouchpadLED(UInt8 touchLED) -{ - TPS2Request<12> request; - - // send NOP before special command sequence - request.commands[0].command = kPS2C_SendCommandAndCompareAck; - request.commands[0].inOrOut = kDP_SetMouseScaling1To1; - - // 4 set resolution commands, each encode 2 data bits of LED level - request.commands[1].command = kPS2C_SendCommandAndCompareAck; - request.commands[1].inOrOut = kDP_SetMouseResolution; - request.commands[2].command = kPS2C_SendCommandAndCompareAck; - request.commands[2].inOrOut = (touchLED >> 6) & 0x3; - - request.commands[3].command = kPS2C_SendCommandAndCompareAck; - request.commands[3].inOrOut = kDP_SetMouseResolution; - request.commands[4].command = kPS2C_SendCommandAndCompareAck; - request.commands[4].inOrOut = (touchLED >> 4) & 0x3; - - request.commands[5].command = kPS2C_SendCommandAndCompareAck; - request.commands[5].inOrOut = kDP_SetMouseResolution; - request.commands[6].command = kPS2C_SendCommandAndCompareAck; - request.commands[6].inOrOut = (touchLED >> 2) & 0x3; - - request.commands[7].command = kPS2C_SendCommandAndCompareAck; - request.commands[7].inOrOut = kDP_SetMouseResolution; - request.commands[8].command = kPS2C_SendCommandAndCompareAck; - request.commands[8].inOrOut = (touchLED >> 0) & 0x3; - - // Set sample rate 10 (10 is command for setting LED) - request.commands[9].command = kPS2C_SendCommandAndCompareAck; - request.commands[9].inOrOut = kDP_SetMouseSampleRate; - request.commands[10].command = kPS2C_SendCommandAndCompareAck; - request.commands[10].inOrOut = 10; // 0x0A command for setting LED - - // finally send NOP command to end the special sequence - request.commands[11].command = kPS2C_SendCommandAndCompareAck; - request.commands[11].inOrOut = kDP_SetMouseScaling1To1; - request.commandsCount = 12; - assert(request.commandsCount <= countof(request.commands)); - _device->submitRequestAndBlock(&request); - - return 12 == request.commandsCount; -} - -bool ApplePS2Mouse::getTouchPadData(UInt8 dataSelector, UInt8 buf3[]) -{ - TPS2Request<14> request; - - // Disable stream mode before the command sequence. - request.commands[0].command = kPS2C_SendCommandAndCompareAck; - request.commands[0].inOrOut = kDP_SetDefaultsAndDisable; - - // 4 set resolution commands, each encode 2 data bits. - request.commands[1].command = kPS2C_SendCommandAndCompareAck; - request.commands[1].inOrOut = kDP_SetMouseResolution; - request.commands[2].command = kPS2C_SendCommandAndCompareAck; - request.commands[2].inOrOut = (dataSelector >> 6) & 0x3; - - request.commands[3].command = kPS2C_SendCommandAndCompareAck; - request.commands[3].inOrOut = kDP_SetMouseResolution; - request.commands[4].command = kPS2C_SendCommandAndCompareAck; - request.commands[4].inOrOut = (dataSelector >> 4) & 0x3; - - request.commands[5].command = kPS2C_SendCommandAndCompareAck; - request.commands[5].inOrOut = kDP_SetMouseResolution; - request.commands[6].command = kPS2C_SendCommandAndCompareAck; - request.commands[6].inOrOut = (dataSelector >> 2) & 0x3; - - request.commands[7].command = kPS2C_SendCommandAndCompareAck; - request.commands[7].inOrOut = kDP_SetMouseResolution; - request.commands[8].command = kPS2C_SendCommandAndCompareAck; - request.commands[8].inOrOut = (dataSelector >> 0) & 0x3; - - // Read response bytes. - request.commands[9].command = kPS2C_SendCommandAndCompareAck; - request.commands[9].inOrOut = kDP_GetMouseInformation; - request.commands[10].command = kPS2C_ReadDataPort; - request.commands[10].inOrOut = 0; - request.commands[11].command = kPS2C_ReadDataPort; - request.commands[11].inOrOut = 0; - request.commands[12].command = kPS2C_ReadDataPort; - request.commands[12].inOrOut = 0; - request.commands[13].command = kPS2C_SendCommandAndCompareAck; - request.commands[13].inOrOut = kDP_SetDefaultsAndDisable; - request.commandsCount = 14; - assert(request.commandsCount <= countof(request.commands)); - _device->submitRequestAndBlock(&request); - if (14 != request.commandsCount) - return false; - - // store results - buf3[0] = request.commands[10].inOrOut; - buf3[1] = request.commands[11].inOrOut; - buf3[2] = request.commands[12].inOrOut; - - return true; -} - -void ApplePS2Mouse::registerHIDPointerNotifications() -{ - IOServiceMatchingNotificationHandler notificationHandler = OSMemberFunctionCast(IOServiceMatchingNotificationHandler, this, &ApplePS2Mouse::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"); - - 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"); - 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); - OSSafeReleaseNULL(matchingDictionary); - } -} - -void ApplePS2Mouse::unregisterHIDPointerNotifications() -{ - // Free device matching notifiers - if (usb_hid_publish_notify) { - usb_hid_publish_notify->remove(); - usb_hid_publish_notify = nullptr; - } - - if (usb_hid_terminate_notify) { - usb_hid_terminate_notify->remove(); - usb_hid_terminate_notify = nullptr; - } - - if (bluetooth_hid_publish_notify) { - bluetooth_hid_publish_notify->remove(); - bluetooth_hid_publish_notify = nullptr; - } - - if (bluetooth_hid_terminate_notify) { - bluetooth_hid_terminate_notify->remove(); - bluetooth_hid_terminate_notify = nullptr; - } - - attachedHIDPointerDevices->flushCollection(); -} - -void ApplePS2Mouse::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")); - - 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 - { - if (deviceClassMinor2 == kBluetoothDeviceClassMinorPeripheral2Unclassified || // Mouse - 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()); - } - } - } - } - } - - 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 - ignoreall = false; - } - } -} - -bool ApplePS2Mouse::notificationHIDAttachedHandler(void * refCon, - IOService * newService, - IONotifier * notifier) -{ - if (_cmdGate) { // defensive - _cmdGate->runAction(OSMemberFunctionCast(IOCommandGate::Action, this, &ApplePS2Mouse::notificationHIDAttachedHandlerGated), newService, notifier); } - - return true; } - diff --git a/VoodooPS2Mouse/VoodooPS2Mouse.h b/VoodooPS2Mouse/VoodooPS2Mouse.h index a3786bc7..a1ff789e 100644 --- a/VoodooPS2Mouse/VoodooPS2Mouse.h +++ b/VoodooPS2Mouse/VoodooPS2Mouse.h @@ -74,28 +74,7 @@ class EXPORT ApplePS2Mouse : public IOHIPointing int forcesetres; int32_t resmode; int32_t scrollres; - int actliketrackpad; - uint64_t keytime; - uint64_t maxaftertyping; - UInt32 buttonmask; - bool outzone_wt, palm, palm_wt; - bool scroll; - bool ignoreall; - bool ledpresent; - int noled; int wakedelay; - bool usb_mouse_stops_trackpad; - - int _processusbmouse; - int _processbluetoothmouse; - - 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 // for middle button simulation enum mbuttonstate @@ -129,19 +108,9 @@ class EXPORT ApplePS2Mouse : public IOHIPointing virtual void initMouse(); virtual void resetMouse(); virtual void setDevicePowerState(UInt32 whatToDo); - - void updateTouchpadLED(); - bool setTouchpadLED(UInt8 touchLED); - bool getTouchPadData(UInt8 dataSelector, UInt8 buf3[]); - void setParamPropertiesGated(OSDictionary * dict); - void injectVersionDependentProperties(OSDictionary* dict); - - void registerHIDPointerNotifications(); - void unregisterHIDPointerNotifications(); + void setParamPropertiesGated(OSDictionary * dict); - void notificationHIDAttachedHandlerGated(IOService * newService, IONotifier * notifier); - bool notificationHIDAttachedHandler(void * refCon, IOService * newService, IONotifier * notifier); protected: IOItemCount buttonCount() override; IOFixed resolution() override; @@ -168,8 +137,6 @@ class EXPORT ApplePS2Mouse : public IOHIPointing IOReturn setParamProperties(OSDictionary * dict) override; IOReturn setProperties (OSObject *props) override; - - IOReturn message(UInt32 type, IOService* provider, void* argument) override; }; #endif /* _APPLEPS2MOUSE_H */ From 4e27bd9ac216dc8e723a8f13844e4650c1101ade Mon Sep 17 00:00:00 2001 From: Vitaly Cheptsov <4348897+vit9696@users.noreply.github.com> Date: Sun, 2 Apr 2023 01:14:37 +0300 Subject: [PATCH 086/101] Sync Changelog --- Changelog.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Changelog.md b/Changelog.md index babb898f..1ab51e21 100644 --- a/Changelog.md +++ b/Changelog.md @@ -1,5 +1,8 @@ VoodooPS2 Changelog ============================ +#### v2.3.5 +- Removed actAsTrackpad and related logic + #### v2.3.4 - Fixed device count detection when `ps2rst=0` is set - Fixed handleClose not being called by VoodooInput From db22ab1d9801339d9cda22bd8c3ed1502351082f Mon Sep 17 00:00:00 2001 From: Avery Black Date: Sat, 1 Apr 2023 17:32:56 -0700 Subject: [PATCH 087/101] Use VoodooInput Trackpoint logic for Elan Touchpads (#60) --- VoodooPS2Trackpad/VoodooPS2Elan.cpp | 99 +++++++++---------- VoodooPS2Trackpad/VoodooPS2Elan.h | 18 ++-- .../VoodooPS2SynapticsTouchPad.cpp | 45 +++------ VoodooPS2Trackpad/VoodooPS2TrackpadCommon.h | 8 ++ 4 files changed, 76 insertions(+), 94 deletions(-) diff --git a/VoodooPS2Trackpad/VoodooPS2Elan.cpp b/VoodooPS2Trackpad/VoodooPS2Elan.cpp index cfa23539..b0e60200 100644 --- a/VoodooPS2Trackpad/VoodooPS2Elan.cpp +++ b/VoodooPS2Trackpad/VoodooPS2Elan.cpp @@ -33,13 +33,7 @@ // ApplePS2Elan Class Implementation // -OSDefineMetaClassAndStructors(ApplePS2Elan, IOHIPointing); - -UInt32 ApplePS2Elan::deviceType() -{ return NX_EVS_DEVICE_TYPE_MOUSE; }; - -UInt32 ApplePS2Elan::interfaceID() -{ return NX_EVS_DEVICE_INTERFACE_BUS_ACE; }; +OSDefineMetaClassAndStructors(ApplePS2Elan, IOService); bool ApplePS2Elan::init(OSDictionary *dict) { // Initialize this object's minimal state. This is invoked right after this @@ -239,18 +233,6 @@ bool ApplePS2Elan::start(IOService *provider) { } #endif - // 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) - setProperty("HIDScrollResolutionX", _scrollresolution << 16, 32); - setProperty("HIDScrollResolutionY", _scrollresolution << 16, 32); - // Setup workloop with command gate for thread syncronization... IOWorkLoop *pWorkLoop = getWorkLoop(); _cmdGate = IOCommandGate::commandGate(this); @@ -340,11 +322,15 @@ void ApplePS2Elan::setParamPropertiesGated(OSDictionary *config) { const struct {const char *name; int *var;} int32vars[] = { {"WakeDelay", &wakedelay}, - {"ScrollResolution", &_scrollresolution}, + {"TrackpointDeadzone", &_trackpointDeadzone}, {"TrackpointMultiplierX", &_trackpointMultiplierX}, {"TrackpointMultiplierY", &_trackpointMultiplierY}, {"TrackpointDividerX", &_trackpointDividerX}, {"TrackpointDividerY", &_trackpointDividerY}, + {"TrackpointScrollMultiplierX", &_trackpointScrollMultiplierX}, + {"TrackpointScrollMultiplierY", &_trackpointScrollMultiplierY}, + {"TrackpointScrollDividerY", &_trackpointScrollDividerX}, + {"TrackpointScrollDividerY", &_trackpointScrollDividerY}, {"MouseResolution", &_mouseResolution}, {"MouseSampleRate", &_mouseSampleRate}, {"ForceTouchMode", (int*)&_forceTouchMode}, @@ -412,16 +398,8 @@ void ApplePS2Elan::setParamPropertiesGated(OSDictionary *config) { if (attachedHIDPointerDevices && attachedHIDPointerDevices->getCount() > 0) { ignoreall = usb_mouse_stops_trackpad; } -} - -IOReturn ApplePS2Elan::setParamProperties(OSDictionary *dict) { - if (_cmdGate) { - // syncronize through workloop... - //_cmdGate->runAction(OSMemberFunctionCast(IOCommandGate::Action, this, &ApplePS2Elan::setParamPropertiesGated), dict); - setParamPropertiesGated(dict); - } - - return super::setParamProperties(dict); + + setTrackpointProperties(); } IOReturn ApplePS2Elan::setProperties(OSObject *props) { @@ -434,6 +412,28 @@ IOReturn ApplePS2Elan::setProperties(OSObject *props) { return super::setProperties(props); } +void ApplePS2Elan::setTrackpointProperties() +{ + // Trackpoint information for VoodooInput + OSDictionary *trackpoint = OSDictionary::withCapacity(10); + if (trackpoint == nullptr) + return; + + PS2DictSetNumber(trackpoint, VOODOO_TRACKPOINT_DEADZONE, _trackpointDeadzone); + PS2DictSetNumber(trackpoint, VOODOO_TRACKPOINT_BTN_CNT, 3); + PS2DictSetNumber(trackpoint, VOODOO_TRACKPOINT_MOUSE_MULT_X, _trackpointMultiplierX); + PS2DictSetNumber(trackpoint, VOODOO_TRACKPOINT_MOUSE_MULT_Y, _trackpointMultiplierY); + PS2DictSetNumber(trackpoint, VOODOO_TRACKPOINT_MOUSE_DIV_X, _trackpointDividerX); + PS2DictSetNumber(trackpoint, VOODOO_TRACKPOINT_MOUSE_DIV_Y, _trackpointDividerY); + PS2DictSetNumber(trackpoint, VOODOO_TRACKPOINT_SCROLL_MULT_X, _trackpointScrollMultiplierX); + PS2DictSetNumber(trackpoint, VOODOO_TRACKPOINT_SCROLL_MULT_Y, _trackpointScrollMultiplierY); + PS2DictSetNumber(trackpoint, VOODOO_TRACKPOINT_SCROLL_DIV_X, _trackpointScrollDividerX); + PS2DictSetNumber(trackpoint, VOODOO_TRACKPOINT_SCROLL_DIV_Y, _trackpointScrollDividerY); + + setProperty(VOODOO_TRACKPOINT_KEY, trackpoint); + OSSafeReleaseNULL(trackpoint); +} + IOReturn ApplePS2Elan::message(UInt32 type, IOService* provider, void* argument) { // Here is where we receive messages from the keyboard driver // @@ -1870,19 +1870,6 @@ void ApplePS2Elan::elantechReportTrackpoint() { 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); @@ -1891,12 +1878,13 @@ void ApplePS2Elan::elantechReportTrackpoint() { uint64_t timestamp_ns; absolutetime_to_nanoseconds(timestamp, ×tamp_ns); keytime = timestamp_ns; - - if (trackpointScrolling) { - dispatchScrollWheelEvent(dy, dx, 0, timestamp); - } else { - dispatchRelativePointerEvent(dx, dy, trackpointRightButton | trackpointLeftButton | trackpointMiddleButton, timestamp); - } + + trackpointReport.timestamp = timestamp; + trackpointReport.buttons = trackpointLeftButton | trackpointMiddleButton | trackpointRightButton; + trackpointReport.dx = dx; + trackpointReport.dy = dy; + super::messageClient(kIOMessageVoodooTrackpointMessage, voodooInputInstance, + &trackpointReport, sizeof(trackpointReport)); } void ApplePS2Elan::processPacketStatusV4() { @@ -2108,8 +2096,11 @@ void ApplePS2Elan::sendTouchData() { if (!info.is_buttonpad) { if (transducers_count == 0) { - UInt32 buttons = leftButton | rightButton; - dispatchRelativePointerEvent(0, 0, buttons, timestamp); + trackpointReport.timestamp = timestamp; + trackpointReport.buttons = leftButton | rightButton; + trackpointReport.dx = trackpointReport.dy = 0; + super::messageClient(kIOMessageVoodooTrackpointMessage, voodooInputInstance, + &trackpointReport, sizeof(trackpointReport)); } else { UInt32 buttons = 0; bool send = false; @@ -2122,7 +2113,11 @@ void ApplePS2Elan::sendTouchData() { send = true; } if (send) { - dispatchRelativePointerEvent(0, 0, buttons, timestamp); + trackpointReport.timestamp = timestamp; + trackpointReport.buttons = buttons; + trackpointReport.dx = trackpointReport.dy = 0; + super::messageClient(kIOMessageVoodooTrackpointMessage, voodooInputInstance, + &trackpointReport, sizeof(trackpointReport)); } } diff --git a/VoodooPS2Trackpad/VoodooPS2Elan.h b/VoodooPS2Trackpad/VoodooPS2Elan.h index 7a2d0143..e3230d4d 100644 --- a/VoodooPS2Trackpad/VoodooPS2Elan.h +++ b/VoodooPS2Trackpad/VoodooPS2Elan.h @@ -209,8 +209,8 @@ struct elantech_data { // ApplePS2Elan Class Declaration // -class EXPORT ApplePS2Elan : public IOHIPointing { - typedef IOHIPointing super; +class EXPORT ApplePS2Elan : public IOService { + typedef IOService super; OSDeclareDefaultStructors(ApplePS2Elan); private: @@ -225,6 +225,7 @@ class EXPORT ApplePS2Elan : public IOHIPointing { IOCommandGate* _cmdGate {nullptr}; VoodooInputEvent inputEvent {}; + TrackpointReport trackpointReport {}; // when trackpad has physical button UInt32 leftButton = 0; @@ -236,8 +237,6 @@ class EXPORT ApplePS2Elan : public IOHIPointing { const float cos30deg = 0.86602540378f; UInt32 lastFingers = 0; - bool trackpointScrolling {false}; - int heldFingers = 0; int headPacketsCount = 0; elan_virtual_finger_state virtualFinger[ETP_MAX_FINGERS] {}; @@ -246,12 +245,16 @@ class EXPORT ApplePS2Elan : public IOHIPointing { ForceTouchMode _forceTouchMode {FORCE_TOUCH_BUTTON}; - int _scrollresolution {2300}; int wakedelay {1000}; + int _trackpointDeadzone {1}; int _trackpointMultiplierX {120}; int _trackpointMultiplierY {120}; int _trackpointDividerX {120}; int _trackpointDividerY {120}; + int _trackpointScrollMultiplierX {120}; + int _trackpointScrollMultiplierY {120}; + int _trackpointScrollDividerX {120}; + int _trackpointScrollDividerY {120}; int _mouseResolution {0x3}; int _mouseSampleRate {200}; @@ -285,6 +288,7 @@ class EXPORT ApplePS2Elan : public IOHIPointing { void setParamPropertiesGated(OSDictionary *dict); void injectVersionDependentProperties(OSDictionary *dict); + void setTrackpointProperties(); void registerHIDPointerNotifications(); void unregisterHIDPointerNotifications(); @@ -344,10 +348,6 @@ class EXPORT ApplePS2Elan : public IOHIPointing { 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; diff --git a/VoodooPS2Trackpad/VoodooPS2SynapticsTouchPad.cpp b/VoodooPS2Trackpad/VoodooPS2SynapticsTouchPad.cpp index 88915ae9..d21e5800 100644 --- a/VoodooPS2Trackpad/VoodooPS2SynapticsTouchPad.cpp +++ b/VoodooPS2Trackpad/VoodooPS2SynapticsTouchPad.cpp @@ -1901,43 +1901,22 @@ IOReturn ApplePS2SynapticsTouchPad::setProperties(OSObject *props) void ApplePS2SynapticsTouchPad::setTrackpointProperties() { // Trackpoint information for VoodooInput - OSDictionary *trackpoint = OSDictionary::withCapacity(5); + OSDictionary *trackpoint = OSDictionary::withCapacity(10); if (trackpoint == nullptr) return; - OSNumber *deadzone = OSNumber::withNumber(_deadzone, 32); - OSNumber *buttonCnt = OSNumber::withNumber(3, 32); - OSNumber *multX = OSNumber::withNumber(_mouseMultiplierX, 32); - OSNumber *multY = OSNumber::withNumber(_mouseMultiplierY, 32); - OSNumber *divX = OSNumber::withNumber(_mouseDivisorX, 32); - OSNumber *divY = OSNumber::withNumber(_mouseDivisorY, 32); - OSNumber *scrollMultX = OSNumber::withNumber(_scrollMultiplierX, 32); - OSNumber *scrollMultY = OSNumber::withNumber(_scrollMultiplierY, 32); - OSNumber *scrollDivX = OSNumber::withNumber(_scrollDivisorX, 32); - OSNumber *scrollDivY = OSNumber::withNumber(_scrollDivisorY, 32); - - trackpoint->setObject(VOODOO_TRACKPOINT_DEADZONE, deadzone); - trackpoint->setObject(VOODOO_TRACKPOINT_BTN_CNT, buttonCnt); - trackpoint->setObject(VOODOO_TRACKPOINT_MOUSE_MULT_X, multX); - trackpoint->setObject(VOODOO_TRACKPOINT_MOUSE_MULT_Y, multY); - trackpoint->setObject(VOODOO_TRACKPOINT_MOUSE_DIV_X, divX); - trackpoint->setObject(VOODOO_TRACKPOINT_MOUSE_DIV_Y, divY); - trackpoint->setObject(VOODOO_TRACKPOINT_SCROLL_MULT_X, scrollMultX); - trackpoint->setObject(VOODOO_TRACKPOINT_SCROLL_MULT_Y, scrollMultY); - trackpoint->setObject(VOODOO_TRACKPOINT_SCROLL_DIV_X, scrollDivX); - trackpoint->setObject(VOODOO_TRACKPOINT_SCROLL_DIV_Y, scrollDivY); - setProperty(VOODOO_TRACKPOINT_KEY, trackpoint); + PS2DictSetNumber(trackpoint, VOODOO_TRACKPOINT_DEADZONE, _deadzone); + PS2DictSetNumber(trackpoint, VOODOO_TRACKPOINT_BTN_CNT, 3); + PS2DictSetNumber(trackpoint, VOODOO_TRACKPOINT_MOUSE_MULT_X, _mouseMultiplierX); + PS2DictSetNumber(trackpoint, VOODOO_TRACKPOINT_MOUSE_MULT_Y, _mouseMultiplierY); + PS2DictSetNumber(trackpoint, VOODOO_TRACKPOINT_MOUSE_DIV_X, _mouseDivisorX); + PS2DictSetNumber(trackpoint, VOODOO_TRACKPOINT_MOUSE_DIV_Y, _mouseDivisorY); + PS2DictSetNumber(trackpoint, VOODOO_TRACKPOINT_SCROLL_MULT_X, _scrollMultiplierX); + PS2DictSetNumber(trackpoint, VOODOO_TRACKPOINT_SCROLL_MULT_Y, _scrollMultiplierY); + PS2DictSetNumber(trackpoint, VOODOO_TRACKPOINT_SCROLL_DIV_X, _scrollDivisorX); + PS2DictSetNumber(trackpoint, VOODOO_TRACKPOINT_SCROLL_DIV_Y, _scrollDivisorY); - OSSafeReleaseNULL(deadzone); - OSSafeReleaseNULL(buttonCnt); - OSSafeReleaseNULL(multX); - OSSafeReleaseNULL(multY); - OSSafeReleaseNULL(divX); - OSSafeReleaseNULL(divY); - OSSafeReleaseNULL(scrollMultX); - OSSafeReleaseNULL(scrollMultY); - OSSafeReleaseNULL(scrollDivX); - OSSafeReleaseNULL(scrollDivY); + setProperty(VOODOO_TRACKPOINT_KEY, trackpoint); OSSafeReleaseNULL(trackpoint); } diff --git a/VoodooPS2Trackpad/VoodooPS2TrackpadCommon.h b/VoodooPS2Trackpad/VoodooPS2TrackpadCommon.h index 88cd681f..cb4fd34f 100644 --- a/VoodooPS2Trackpad/VoodooPS2TrackpadCommon.h +++ b/VoodooPS2Trackpad/VoodooPS2TrackpadCommon.h @@ -11,6 +11,14 @@ #define TEST_BIT(x, y) ((x >> y) & 0x1) +void inline PS2DictSetNumber(OSDictionary *dict, const char *key, unsigned int num) { + OSNumber *val = OSNumber::withNumber(num, 32); + if (val != nullptr) { + dict->setObject(key, val); + val->release(); + } +} + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // SimpleAverage Class Declaration // From 410118bd89723b7e5290ae9f21f5e00078f6fd04 Mon Sep 17 00:00:00 2001 From: Avery Black Date: Sat, 1 Apr 2023 17:35:24 -0700 Subject: [PATCH 088/101] Sync Changelog --- Changelog.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Changelog.md b/Changelog.md index 1ab51e21..312c3867 100644 --- a/Changelog.md +++ b/Changelog.md @@ -2,6 +2,8 @@ VoodooPS2 Changelog ============================ #### v2.3.5 - Removed actAsTrackpad and related logic +- Fix Trackpoints connected to Elan Touchpads +- Use VoodooInput Trackpoint logic for Elan Touchpads #### v2.3.4 - Fixed device count detection when `ps2rst=0` is set From 7f4e0698f1cd68e00f1a78d70ffaeecf145ca45a Mon Sep 17 00:00:00 2001 From: Andrey1970AppleLife Date: Mon, 3 Apr 2023 22:24:16 +0300 Subject: [PATCH 089/101] 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 57950f22..f0fdc456 100644 --- a/VoodooPS2Controller.xcodeproj/project.pbxproj +++ b/VoodooPS2Controller.xcodeproj/project.pbxproj @@ -765,7 +765,7 @@ KERNEL_FRAMEWORK_HEADERS = "$(PROJECT_DIR)/MacKernelSDK/Headers"; "LLVM_LTO[arch=x86_64]" = YES; MACOSX_DEPLOYMENT_TARGET = 10.11; - MODULE_VERSION = 2.3.5; + MODULE_VERSION = 2.3.6; ONLY_ACTIVE_ARCH = YES; "OTHER_LDFLAGS[arch=x86_64]" = "-dead_strip"; PRODUCT_NAME = VoodooPS2Controller; @@ -820,7 +820,7 @@ KERNEL_FRAMEWORK_HEADERS = "$(PROJECT_DIR)/MacKernelSDK/Headers"; "LLVM_LTO[arch=x86_64]" = YES; MACOSX_DEPLOYMENT_TARGET = 10.11; - MODULE_VERSION = 2.3.5; + MODULE_VERSION = 2.3.6; "OTHER_LDFLAGS[arch=x86_64]" = "-dead_strip"; PRODUCT_NAME = VoodooPS2Controller; SDKROOT = macosx; From 50ae04a4ffef5434de693baf90d1476d62144519 Mon Sep 17 00:00:00 2001 From: Avery Black Date: Thu, 19 Oct 2023 22:58:16 -0700 Subject: [PATCH 090/101] HID VoodooPS2Keyboard --- VoodooPS2Controller.xcodeproj/project.pbxproj | 40 +- VoodooPS2Controller/VoodooPS2Controller.cpp | 4 +- ...{ApplePS2ToADBMap.h => ApplePS2ToHIDMap.h} | 766 +++++----- VoodooPS2Keyboard/VoodooPS2EventDriver.hpp | 31 + .../VoodooPS2Keyboard-Info.plist | 25 + VoodooPS2Keyboard/VoodooPS2Keyboard.cpp | 1348 ++--------------- VoodooPS2Keyboard/VoodooPS2Keyboard.h | 67 +- .../VoodooPS2KeyboardHIDWrapper.cpp | 134 ++ .../VoodooPS2KeyboardHIDWrapper.hpp | 39 + 9 files changed, 796 insertions(+), 1658 deletions(-) rename VoodooPS2Keyboard/{ApplePS2ToADBMap.h => ApplePS2ToHIDMap.h} (53%) create mode 100644 VoodooPS2Keyboard/VoodooPS2EventDriver.hpp create mode 100644 VoodooPS2Keyboard/VoodooPS2KeyboardHIDWrapper.cpp create mode 100644 VoodooPS2Keyboard/VoodooPS2KeyboardHIDWrapper.hpp diff --git a/VoodooPS2Controller.xcodeproj/project.pbxproj b/VoodooPS2Controller.xcodeproj/project.pbxproj index f0fdc456..324e275c 100644 --- a/VoodooPS2Controller.xcodeproj/project.pbxproj +++ b/VoodooPS2Controller.xcodeproj/project.pbxproj @@ -19,7 +19,7 @@ 84833FA3161B627D00845294 /* ApplePS2Device.h in Headers */ = {isa = PBXBuildFile; fileRef = 84833F9D161B627D00845294 /* ApplePS2Device.h */; settings = {ATTRIBUTES = (); }; }; 84833FA5161B627D00845294 /* ApplePS2KeyboardDevice.h in Headers */ = {isa = PBXBuildFile; fileRef = 84833F9F161B627D00845294 /* ApplePS2KeyboardDevice.h */; settings = {ATTRIBUTES = (); }; }; 84833FA7161B627D00845294 /* ApplePS2MouseDevice.h in Headers */ = {isa = PBXBuildFile; fileRef = 84833FA1161B627D00845294 /* ApplePS2MouseDevice.h */; settings = {ATTRIBUTES = (); }; }; - 84833FAA161B629500845294 /* ApplePS2ToADBMap.h in Headers */ = {isa = PBXBuildFile; fileRef = 84833FA9161B629500845294 /* ApplePS2ToADBMap.h */; settings = {ATTRIBUTES = (); }; }; + 84833FAA161B629500845294 /* ApplePS2ToHIDMap.h in Headers */ = {isa = PBXBuildFile; fileRef = 84833FA9161B629500845294 /* ApplePS2ToHIDMap.h */; settings = {ATTRIBUTES = (); }; }; 84833FB1161B62A900845294 /* VoodooPS2ALPSGlidePoint.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 84833FAB161B62A900845294 /* VoodooPS2ALPSGlidePoint.cpp */; }; 84833FB2161B62A900845294 /* VoodooPS2ALPSGlidePoint.h in Headers */ = {isa = PBXBuildFile; fileRef = 84833FAC161B62A900845294 /* VoodooPS2ALPSGlidePoint.h */; settings = {ATTRIBUTES = (); }; }; 84833FB3161B62A900845294 /* VoodooPS2SentelicFSP.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 84833FAD161B62A900845294 /* VoodooPS2SentelicFSP.cpp */; }; @@ -39,6 +39,9 @@ CE8DA1C6251839B7008C44E8 /* libkmod.a in Frameworks */ = {isa = PBXBuildFile; fileRef = CE8DA1C4251839B2008C44E8 /* libkmod.a */; }; CE8DA1C7251839B9008C44E8 /* libkmod.a in Frameworks */ = {isa = PBXBuildFile; fileRef = CE8DA1C4251839B2008C44E8 /* libkmod.a */; }; CE8DA1CC251839BC008C44E8 /* libkmod.a in Frameworks */ = {isa = PBXBuildFile; fileRef = CE8DA1C4251839B2008C44E8 /* libkmod.a */; }; + EE4CEE1C2A9D85DA00314737 /* VoodooPS2KeyboardHIDWrapper.cpp in Sources */ = {isa = PBXBuildFile; fileRef = EE4CEE1A2A9D85DA00314737 /* VoodooPS2KeyboardHIDWrapper.cpp */; }; + EE4CEE1D2A9D85DA00314737 /* VoodooPS2KeyboardHIDWrapper.hpp in Headers */ = {isa = PBXBuildFile; fileRef = EE4CEE1B2A9D85DA00314737 /* VoodooPS2KeyboardHIDWrapper.hpp */; }; + EE4CEE252A9D8AF800314737 /* VoodooPS2EventDriver.hpp in Headers */ = {isa = PBXBuildFile; fileRef = EE4CEE232A9D8AF800314737 /* VoodooPS2EventDriver.hpp */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ @@ -100,7 +103,7 @@ 84833F9F161B627D00845294 /* ApplePS2KeyboardDevice.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ApplePS2KeyboardDevice.h; path = VoodooPS2Controller/ApplePS2KeyboardDevice.h; sourceTree = ""; }; 84833FA0161B627D00845294 /* ApplePS2MouseDevice.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ApplePS2MouseDevice.cpp; sourceTree = ""; }; 84833FA1161B627D00845294 /* ApplePS2MouseDevice.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ApplePS2MouseDevice.h; path = VoodooPS2Controller/ApplePS2MouseDevice.h; sourceTree = ""; }; - 84833FA9161B629500845294 /* ApplePS2ToADBMap.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ApplePS2ToADBMap.h; sourceTree = ""; }; + 84833FA9161B629500845294 /* ApplePS2ToHIDMap.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ApplePS2ToHIDMap.h; sourceTree = ""; }; 84833FAB161B62A900845294 /* VoodooPS2ALPSGlidePoint.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; lineEnding = 0; path = VoodooPS2ALPSGlidePoint.cpp; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.cpp; }; 84833FAC161B62A900845294 /* VoodooPS2ALPSGlidePoint.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = VoodooPS2ALPSGlidePoint.h; sourceTree = ""; }; 84833FAD161B62A900845294 /* VoodooPS2SentelicFSP.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; lineEnding = 0; path = VoodooPS2SentelicFSP.cpp; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.cpp; }; @@ -131,6 +134,9 @@ EDD95559208E2B640031D99E /* SSDT-Thinkpad_Clickpad.dsl */ = {isa = PBXFileReference; lastKnownFileType = text; path = "SSDT-Thinkpad_Clickpad.dsl"; sourceTree = ""; }; EDD9555A208E2E7A0031D99E /* SSDT-Thinkpad_Trackpad.dsl */ = {isa = PBXFileReference; lastKnownFileType = text; path = "SSDT-Thinkpad_Trackpad.dsl"; sourceTree = ""; }; EDD970FD1FD0B826004CCFFD /* SSDT-HP-FixLidSleep.dsl */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = "SSDT-HP-FixLidSleep.dsl"; sourceTree = ""; }; + EE4CEE1A2A9D85DA00314737 /* VoodooPS2KeyboardHIDWrapper.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = VoodooPS2KeyboardHIDWrapper.cpp; sourceTree = ""; }; + EE4CEE1B2A9D85DA00314737 /* VoodooPS2KeyboardHIDWrapper.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = VoodooPS2KeyboardHIDWrapper.hpp; sourceTree = ""; }; + EE4CEE232A9D8AF800314737 /* VoodooPS2EventDriver.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = VoodooPS2EventDriver.hpp; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -236,10 +242,13 @@ 8416782E161B5613002C60E6 /* VoodooPS2Keyboard */ = { isa = PBXGroup; children = ( - 84833FA9161B629500845294 /* ApplePS2ToADBMap.h */, + 84833FA9161B629500845294 /* ApplePS2ToHIDMap.h */, 84167834161B5613002C60E6 /* VoodooPS2Keyboard.h */, 84167835161B5613002C60E6 /* VoodooPS2Keyboard.cpp */, 8416782F161B5613002C60E6 /* Supporting Files */, + EE4CEE1A2A9D85DA00314737 /* VoodooPS2KeyboardHIDWrapper.cpp */, + EE4CEE1B2A9D85DA00314737 /* VoodooPS2KeyboardHIDWrapper.hpp */, + EE4CEE232A9D8AF800314737 /* VoodooPS2EventDriver.hpp */, ); path = VoodooPS2Keyboard; sourceTree = ""; @@ -373,8 +382,10 @@ isa = PBXHeadersBuildPhase; buildActionMask = 2147483647; files = ( - 84833FAA161B629500845294 /* ApplePS2ToADBMap.h in Headers */, + 84833FAA161B629500845294 /* ApplePS2ToHIDMap.h in Headers */, 84833FC2161B69C700845294 /* VoodooPS2Keyboard.h in Headers */, + EE4CEE1D2A9D85DA00314737 /* VoodooPS2KeyboardHIDWrapper.hpp in Headers */, + EE4CEE252A9D8AF800314737 /* VoodooPS2EventDriver.hpp in Headers */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -634,6 +645,7 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( + EE4CEE1C2A9D85DA00314737 /* VoodooPS2KeyboardHIDWrapper.cpp in Sources */, 84167836161B5613002C60E6 /* VoodooPS2Keyboard.cpp in Sources */, ); runOnlyForDeploymentPostprocessing = 0; @@ -765,7 +777,7 @@ KERNEL_FRAMEWORK_HEADERS = "$(PROJECT_DIR)/MacKernelSDK/Headers"; "LLVM_LTO[arch=x86_64]" = YES; MACOSX_DEPLOYMENT_TARGET = 10.11; - MODULE_VERSION = 2.3.6; + MODULE_VERSION = 3.0.0; ONLY_ACTIVE_ARCH = YES; "OTHER_LDFLAGS[arch=x86_64]" = "-dead_strip"; PRODUCT_NAME = VoodooPS2Controller; @@ -820,7 +832,7 @@ KERNEL_FRAMEWORK_HEADERS = "$(PROJECT_DIR)/MacKernelSDK/Headers"; "LLVM_LTO[arch=x86_64]" = YES; MACOSX_DEPLOYMENT_TARGET = 10.11; - MODULE_VERSION = 2.3.6; + MODULE_VERSION = 3.0.0; "OTHER_LDFLAGS[arch=x86_64]" = "-dead_strip"; PRODUCT_NAME = VoodooPS2Controller; SDKROOT = macosx; @@ -845,7 +857,7 @@ ); MODULE_NAME = as.acidanthera.driver.VoodooPS2Controller; OTHER_CFLAGS = "-fno-stack-protector"; - PRODUCT_BUNDLE_IDENTIFIER = as.acidanthera.voodoo.driver.PS2Controller; + PRODUCT_BUNDLE_IDENTIFIER = com.1revenger1.PS2Controller; PRODUCT_NAME = "$(TARGET_NAME)"; RUN_CLANG_STATIC_ANALYZER = YES; STRIP_INSTALLED_PRODUCT = YES; @@ -866,7 +878,7 @@ ); MODULE_NAME = as.acidanthera.driver.VoodooPS2Controller; OTHER_CFLAGS = "-fno-stack-protector"; - PRODUCT_BUNDLE_IDENTIFIER = as.acidanthera.voodoo.driver.PS2Controller; + PRODUCT_BUNDLE_IDENTIFIER = com.1revenger1.PS2Controller; PRODUCT_NAME = "$(TARGET_NAME)"; STRIP_INSTALLED_PRODUCT = YES; STRIP_STYLE = "non-global"; @@ -890,7 +902,7 @@ ); MODULE_NAME = as.acidanthera.driver.VoodooPS2Keyboard; OTHER_CFLAGS = "-fno-stack-protector"; - PRODUCT_BUNDLE_IDENTIFIER = as.acidanthera.voodoo.driver.PS2Keyboard; + PRODUCT_BUNDLE_IDENTIFIER = com.1revenger1.PS2Keyboard; PRODUCT_NAME = "$(TARGET_NAME)"; RUN_CLANG_STATIC_ANALYZER = YES; STRIP_INSTALLED_PRODUCT = YES; @@ -912,7 +924,7 @@ ); MODULE_NAME = as.acidanthera.driver.VoodooPS2Keyboard; OTHER_CFLAGS = "-fno-stack-protector"; - PRODUCT_BUNDLE_IDENTIFIER = as.acidanthera.voodoo.driver.PS2Keyboard; + PRODUCT_BUNDLE_IDENTIFIER = com.1revenger1.PS2Keyboard; PRODUCT_NAME = "$(TARGET_NAME)"; STRIP_INSTALLED_PRODUCT = YES; STRIP_STYLE = "non-global"; @@ -936,7 +948,7 @@ ); MODULE_NAME = as.acidanthera.driver.VoodooPS2Mouse; OTHER_CFLAGS = "-fno-stack-protector"; - PRODUCT_BUNDLE_IDENTIFIER = as.acidanthera.voodoo.driver.PS2Mouse; + PRODUCT_BUNDLE_IDENTIFIER = com.1revenger1.PS2Mouse; PRODUCT_NAME = "$(TARGET_NAME)"; RUN_CLANG_STATIC_ANALYZER = YES; STRIP_INSTALLED_PRODUCT = YES; @@ -958,7 +970,7 @@ ); MODULE_NAME = as.acidanthera.driver.VoodooPS2Mouse; OTHER_CFLAGS = "-fno-stack-protector"; - PRODUCT_BUNDLE_IDENTIFIER = as.acidanthera.voodoo.driver.PS2Mouse; + PRODUCT_BUNDLE_IDENTIFIER = com.1revenger1.PS2Mouse; PRODUCT_NAME = "$(TARGET_NAME)"; STRIP_INSTALLED_PRODUCT = YES; STRIP_STYLE = "non-global"; @@ -983,7 +995,7 @@ ); MODULE_NAME = as.acidanthera.driver.VoodooPS2Trackpad; OTHER_CFLAGS = "-fno-stack-protector"; - PRODUCT_BUNDLE_IDENTIFIER = as.acidanthera.voodoo.driver.PS2Trackpad; + PRODUCT_BUNDLE_IDENTIFIER = com.1revenger1.PS2Trackpad; PRODUCT_NAME = "$(TARGET_NAME)"; RUN_CLANG_STATIC_ANALYZER = YES; STRIP_INSTALLED_PRODUCT = YES; @@ -1006,7 +1018,7 @@ ); MODULE_NAME = as.acidanthera.driver.VoodooPS2Trackpad; OTHER_CFLAGS = "-fno-stack-protector"; - PRODUCT_BUNDLE_IDENTIFIER = as.acidanthera.voodoo.driver.PS2Trackpad; + PRODUCT_BUNDLE_IDENTIFIER = com.1revenger1.PS2Trackpad; PRODUCT_NAME = "$(TARGET_NAME)"; STRIP_INSTALLED_PRODUCT = YES; STRIP_STYLE = "non-global"; diff --git a/VoodooPS2Controller/VoodooPS2Controller.cpp b/VoodooPS2Controller/VoodooPS2Controller.cpp index 497b47bc..6194e90e 100644 --- a/VoodooPS2Controller/VoodooPS2Controller.cpp +++ b/VoodooPS2Controller/VoodooPS2Controller.cpp @@ -2126,7 +2126,7 @@ static OSString* getPlatformOverride(IORegistryEntry* reg, const char* sz) return NULL; } -static OSString* getPlatformManufacturer(IORegistryEntry* reg) +static LIBKERN_RETURNS_RETAINED OSString* getPlatformManufacturer(IORegistryEntry* reg) { // allow override in PS2K ACPI device OSString* id = getPlatformOverride(reg, "RM,oem-id"); @@ -2148,7 +2148,7 @@ static OSString* getPlatformManufacturer(IORegistryEntry* reg) return OSString::withCStringNoCopy(oemID); } -static OSString* getPlatformProduct(IORegistryEntry* reg) +static LIBKERN_RETURNS_RETAINED OSString* getPlatformProduct(IORegistryEntry* reg) { // allow override in PS2K ACPI device OSString* id = getPlatformOverride(reg, "RM,oem-table-id"); diff --git a/VoodooPS2Keyboard/ApplePS2ToADBMap.h b/VoodooPS2Keyboard/ApplePS2ToHIDMap.h similarity index 53% rename from VoodooPS2Keyboard/ApplePS2ToADBMap.h rename to VoodooPS2Keyboard/ApplePS2ToHIDMap.h index 022536ee..b2158217 100644 --- a/VoodooPS2Keyboard/ApplePS2ToADBMap.h +++ b/VoodooPS2Keyboard/ApplePS2ToHIDMap.h @@ -23,122 +23,119 @@ #ifndef _APPLEPS2TOADBMAP_H #define _APPLEPS2TOADBMAP_H +#include +#include + #define PROBOOK -#define DEADKEY 0x80 +#define DEADKEY 0x00 +#define DEADKEY_EXTENDED { 0, 0 } -#if 0 -// These ADB codes are for normal NX key brightness (broken in 10.12) -#define BRIGHTNESS_DOWN 0x91 -#define BRIGHTNESS_UP 0x90 -#else -// These ADB codes are for F14/F15 (works in 10.12) -#define BRIGHTNESS_DOWN 0x6b -#define BRIGHTNESS_UP 0x71 -#endif +#define BRIGHTNESS_DOWN { kHIDPage_AppleVendorTopCase, kHIDUsage_AV_TopCase_BrightnessDown } +#define BRIGHTNESS_UP { kHIDPage_AppleVendorTopCase, kHIDUsage_AV_TopCase_BrightnessUp } -#define ADB_CONVERTER_LEN 256 * 2 // 0x00~0xff : normal key , 0x100~0x1ff : extended key +#define ADB_CONVERTER_LEN 256 // 0x00~0xff : normal key , 0x100~0x1ff : extended key #define ADB_CONVERTER_EX_START 256 // PS/2 scancode reference : USB HID to PS/2 Scan Code Translation Table PS/2 Set 1 columns // http://download.microsoft.com/download/1/6/1/161ba512-40e2-4cc9-843a-923143f3456c/translate.pdf -static const UInt8 PS2ToADBMapStock[ADB_CONVERTER_LEN] = +static const UInt8 PS2ToHIDMapStock[ADB_CONVERTER_LEN] = { -/* ADB AT ANSI Key-Legend +/* HID AT ANSI Key-Legend ======================== */ - DEADKEY,// 00 - 0x35, // 01 Escape - 0x12, // 02 1! - 0x13, // 03 2@ - 0x14, // 04 3# - 0x15, // 05 4$ - 0x17, // 06 5% - 0x16, // 07 6^ - 0x1a, // 08 7& - 0x1c, // 09 8* - 0x19, // 0a 9( - 0x1d, // 0b 0) - 0x1b, // 0c -_ - 0x18, // 0d =+ - 0x33, // 0e Backspace - 0x30, // 0f Tab - 0x0c, // 10 qQ - 0x0d, // 11 wW - 0x0e, // 12 eE - 0x0f, // 13 rR - 0x11, // 14 tT - 0x10, // 15 yY - 0x20, // 16 uU - 0x22, // 17 iI - 0x1f, // 18 oO - 0x23, // 19 pP - 0x21, // 1a [{ - 0x1e, // 1b ]} - 0x24, // 1c Return - 0x3b, // 1d Left Control - 0x00, // 1e aA - 0x01, // 1f sS - 0x02, // 20 dD - 0x03, // 21 fF - 0x05, // 22 gG - 0x04, // 23 hH - 0x26, // 24 jJ - 0x28, // 25 kK - 0x25, // 26 lL - 0x29, // 27 ;: - 0x27, // 28 '" - 0x32, // 29 `~ - 0x38, // 2a Left Shift - 0x2a, // 2b \| , Europe 1(ISO) - 0x06, // 2c zZ - 0x07, // 2d xX - 0x08, // 2e cC - 0x09, // 2f vV - 0x0b, // 30 bB - 0x2d, // 31 nN - 0x2e, // 32 mM - 0x2b, // 33 ,< - 0x2f, // 34 .> - 0x2c, // 35 /? - 0x3c, // 36 Right Shift - 0x43, // 37 Keypad * - 0x3a, // 38 Left Alt - 0x31, // 39 Space - 0x39, // 3a Caps Lock - 0x7a, // 3b F1 - 0x78, // 3c F2 - 0x63, // 3d F3 - 0x76, // 3e F4 - 0x60, // 3f F5 - 0x61, // 40 F6 - 0x62, // 41 F7 - 0x64, // 42 F8 - 0x65, // 43 F9 - 0x6d, // 44 F10 - 0x47, // 45 Num Lock - 0x6b, // 46 Scroll Lock - 0x59, // 47 Keypad 7 Home - 0x5b, // 48 Keypad 8 Up - 0x5c, // 49 Keypad 9 PageUp - 0x4e, // 4a Keypad - - 0x56, // 4b Keypad 4 Left - 0x57, // 4c Keypad 5 - 0x58, // 4d Keypad 6 Right - 0x45, // 4e Keypad + - 0x53, // 4f Keypad 1 End - 0x54, // 50 Keypad 2 Down - 0x55, // 51 Keypad 3 PageDn - 0x52, // 52 Keypad 0 Insert - 0x41, // 53 Keypad . Delete - 0x44, // 54 SysReq + DEADKEY, // 00 + kHIDUsage_KeyboardEscape, // 01 Escape + kHIDUsage_Keyboard1, // 02 1! + kHIDUsage_Keyboard2, // 03 2@ + kHIDUsage_Keyboard3, // 04 3# + kHIDUsage_Keyboard4, // 05 4$ + kHIDUsage_Keyboard5, // 06 5% + kHIDUsage_Keyboard6, // 07 6^ + kHIDUsage_Keyboard7, // 08 7& + kHIDUsage_Keyboard8, // 09 8* + kHIDUsage_Keyboard9, // 0a 9( + kHIDUsage_Keyboard0, // 0b 0) + kHIDUsage_KeyboardHyphen, // 0c -_ + kHIDUsage_KeyboardEqualSign,// 0d =+ + kHIDUsage_KeyboardDeleteOrBackspace, // 0e Backspace + kHIDUsage_KeyboardTab, // 0f Tab + kHIDUsage_KeyboardQ, // 10 qQ + kHIDUsage_KeyboardW, // 11 wW + kHIDUsage_KeyboardE, // 12 eE + kHIDUsage_KeyboardR, // 13 rR + kHIDUsage_KeyboardT, // 14 tT + kHIDUsage_KeyboardY, // 15 yY + kHIDUsage_KeyboardU, // 16 uU + kHIDUsage_KeyboardI, // 17 iI + kHIDUsage_KeyboardO, // 18 oO + kHIDUsage_KeyboardP, // 19 pP + kHIDUsage_KeyboardOpenBracket, // 1a [{ + kHIDUsage_KeyboardCloseBracket, // 1b ]} + kHIDUsage_KeyboardReturnOrEnter, // 1c Return + kHIDUsage_KeyboardLeftControl, // 1d Left Control + kHIDUsage_KeyboardA, // 1e aA + kHIDUsage_KeyboardS, // 1f sS + kHIDUsage_KeyboardD, // 20 dD + kHIDUsage_KeyboardF, // 21 fF + kHIDUsage_KeyboardG, // 22 gG + kHIDUsage_KeyboardH, // 23 hH + kHIDUsage_KeyboardJ, // 24 jJ + kHIDUsage_KeyboardK, // 25 kK + kHIDUsage_KeyboardL, // 26 lL + kHIDUsage_KeyboardSemicolon,// 27 ;: + kHIDUsage_KeyboardQuote, // 28 '" + kHIDUsage_KeyboardGraveAccentAndTilde, // 29 `~ + kHIDUsage_KeyboardLeftShift, // 2a Left Shift + kHIDUsage_KeyboardBackslash, // 2b \| , Europe 1(ISO) + kHIDUsage_KeyboardZ, // 2c zZ + kHIDUsage_KeyboardX, // 2d xX + kHIDUsage_KeyboardC, // 2e cC + kHIDUsage_KeyboardV, // 2f vV + kHIDUsage_KeyboardB, // 30 bB + kHIDUsage_KeyboardN, // 31 nN + kHIDUsage_KeyboardM, // 32 mM + kHIDUsage_KeyboardComma, // 33 ,< + kHIDUsage_KeyboardPeriod, // 34 .> + kHIDUsage_KeyboardSlash, // 35 /? + kHIDUsage_KeyboardRightShift, // 36 Right Shift + kHIDUsage_KeypadAsterisk, // 37 Keypad * + kHIDUsage_KeyboardLeftAlt, // 38 Left Alt + kHIDUsage_KeyboardSpacebar, // 39 Space + kHIDUsage_KeyboardCapsLock, // 3a Caps Lock + kHIDUsage_KeyboardF1, // 3b F1 + kHIDUsage_KeyboardF2, // 3c F2 + kHIDUsage_KeyboardF3, // 3d F3 + kHIDUsage_KeyboardF4, // 3e F4 + kHIDUsage_KeyboardF5, // 3f F5 + kHIDUsage_KeyboardF6, // 40 F6 + kHIDUsage_KeyboardF7, // 41 F7 + kHIDUsage_KeyboardF8, // 42 F8 + kHIDUsage_KeyboardF9, // 43 F9 + kHIDUsage_KeyboardF10, // 44 F10 + kHIDUsage_KeypadNumLock, // 45 Num Lock + kHIDUsage_KeyboardScrollLock, // 46 Scroll Lock + kHIDUsage_Keypad7, // 47 Keypad 7 Home + kHIDUsage_Keypad8, // 48 Keypad 8 Up + kHIDUsage_Keypad9, // 49 Keypad 9 PageUp + kHIDUsage_KeypadHyphen, // 4a Keypad - + kHIDUsage_Keypad4, // 4b Keypad 4 Left + kHIDUsage_Keypad5, // 4c Keypad 5 + kHIDUsage_Keypad6, // 4d Keypad 6 Right + kHIDUsage_KeypadPlus, // 4e Keypad + + kHIDUsage_Keypad1, // 4f Keypad 1 End + kHIDUsage_Keypad2, // 50 Keypad 2 Down + kHIDUsage_Keypad3, // 51 Keypad 3 PageDn + kHIDUsage_Keypad0, // 52 Keypad 0 Insert + kHIDUsage_KeypadPeriod, // 53 Keypad . Delete + kHIDUsage_KeyboardSysReqOrAttention, // 54 SysReq 0x46, // 55 - 0x0a, // 56 Europe 2(ISO) - 0x67, // 57 F11 - 0x6f, // 58 F12 - 0x51, // 59 Keypad = + kHIDUsage_KeyboardNonUSBackslash, // 56 Europe 2(ISO) + kHIDUsage_KeyboardF11, // 57 F11 + kHIDUsage_KeyboardF12, // 58 F12 + kHIDUsage_KeypadEqualSign, // 59 Keypad = DEADKEY,// 5a DEADKEY,// 5b - 0x5f, // 5c Keyboard Int'l 6 (PC9800 Keypad , ) + kHIDUsage_KeyboardInternational6, // 5c Keyboard Int'l 6 (PC9800 Keypad , ) DEADKEY,// 5d DEADKEY,// 5e DEADKEY,// 5f @@ -146,33 +143,33 @@ static const UInt8 PS2ToADBMapStock[ADB_CONVERTER_LEN] = DEADKEY,// 61 DEADKEY,// 62 DEADKEY,// 63 - 0x69, // 64 F13 - 0x6b, // 65 F14 - 0x71, // 66 F15 - 0x6a, // 67 F16 - 0x40, // 68 F17 - 0x4f, // 69 F18 - 0x50, // 6a F19 - 0x5a, // 6b F20 - DEADKEY,// 6c F21 - DEADKEY,// 6d F22 - DEADKEY,// 6e F23 + kHIDUsage_KeyboardF13, // 64 F13 + kHIDUsage_KeyboardF14, // 65 F14 + kHIDUsage_KeyboardF15, // 66 F15 + kHIDUsage_KeyboardF16, // 67 F16 + kHIDUsage_KeyboardF17, // 68 F17 + kHIDUsage_KeyboardF18, // 69 F18 + kHIDUsage_KeyboardF19, // 6a F19 + kHIDUsage_KeyboardF20, // 6b F20 + kHIDUsage_KeyboardF21, // 6c F21 + kHIDUsage_KeyboardF22, // 6d F22 + kHIDUsage_KeyboardF23, // 6e F23 DEADKEY,// 6f - 0x68, // 70 Keyboard Intl'2 (Japanese Katakana/Hiragana) + kHIDUsage_KeyboardInternational2, // 70 Keyboard Intl'2 (Japanese Katakana/Hiragana) DEADKEY,// 71 DEADKEY,// 72 - 0x5e, // 73 Keyboard Int'l 1 (Japanese Ro) + kHIDUsage_KeyboardInternational1, // 73 Keyboard Int'l 1 (Japanese Ro) DEADKEY,// 74 DEADKEY,// 75 - DEADKEY,// 76 F24 , Keyboard Lang 5 (Japanese Zenkaku/Hankaku) - 0x68, // 77 Keyboard Lang 4 (Japanese Hiragana) - 0x68, // 78 Keyboard Lang 3 (Japanese Katakana) - 0x68, // 79 Keyboard Int'l 4 (Japanese Henkan) + kHIDUsage_KeyboardF24, // 76 F24 , Keyboard Lang 5 (Japanese Zenkaku/Hankaku) + kHIDUsage_KeyboardLANG4, // 77 Keyboard Lang 4 (Japanese Hiragana) + kHIDUsage_KeyboardLANG3, // 78 Keyboard Lang 3 (Japanese Katakana) + kHIDUsage_KeyboardInternational4, // 79 Keyboard Int'l 4 (Japanese Henkan) DEADKEY,// 7a - 0x66, // 7b Keyboard Int'l 5 (Japanese Muhenkan) + kHIDUsage_KeyboardInternational5, // 7b Keyboard Int'l 5 (Japanese Muhenkan) DEADKEY,// 7c - 0x5d, // 7d Keyboard Int'l 3 (Japanese Yen) - 0x5f, // 7e Keypad , (Brazilian Keypad .) + kHIDUsage_KeyboardInternational3, // 7d Keyboard Int'l 3 (Japanese Yen) + kHIDUsage_KeypadComma, // 7e Keypad , (Brazilian Keypad .) DEADKEY,// 7f DEADKEY,// 80 DEADKEY,// 81 @@ -287,8 +284,8 @@ static const UInt8 PS2ToADBMapStock[ADB_CONVERTER_LEN] = DEADKEY,// ee DEADKEY,// ef DEADKEY,// f0 - 0x66, // f1* Keyboard Lang 2 (Korean Hanja) - 0x68, // f2* Keyboard Lang 1 (Korean Hangul) + kHIDUsage_KeyboardLANG2, // f1* Keyboard Lang 2 (Korean Hanja) + kHIDUsage_KeyboardLANG1, // f2* Keyboard Lang 1 (Korean Hangul) DEADKEY,// f3 DEADKEY,// f4 DEADKEY,// f5 @@ -301,278 +298,289 @@ static const UInt8 PS2ToADBMapStock[ADB_CONVERTER_LEN] = DEADKEY,// fc DEADKEY,// fd DEADKEY,// fe - DEADKEY,// ff - DEADKEY,// e0 00 - DEADKEY,// e0 01 - DEADKEY,// e0 02 - DEADKEY,// e0 03 - DEADKEY,// e0 04 - BRIGHTNESS_DOWN, // e0 05 dell down - BRIGHTNESS_UP, // e0 06 dell up - DEADKEY,// e0 07 + DEADKEY,// ff +}; + +struct VoodooPS2HidElement { + uint16_t usagePage; + uint16_t usage; +}; + +#define KEY(a) { kHIDPage_KeyboardOrKeypad, (a)} +#define MEDIA(a) { kHIDPage_Consumer, (a)} + +static const VoodooPS2HidElement ExtendedPS2ToHIDStockMap[ADB_CONVERTER_LEN] { + DEADKEY_EXTENDED,// e0 00 + DEADKEY_EXTENDED,// e0 01 + DEADKEY_EXTENDED,// e0 02 + DEADKEY_EXTENDED,// e0 03 + DEADKEY_EXTENDED,// e0 04 + BRIGHTNESS_DOWN, // e0 05 dell down + BRIGHTNESS_UP, // e0 06 dell up + DEADKEY_EXTENDED,// e0 07 #ifndef PROBOOK BRIGHTNESS_UP, // e0 08 samsung up BRIGHTNESS_DOWN, // e0 09 samsung down #else - DEADKEY,// e0 08 - 0x83, // e0 09 Launchpad (hp Fn+F6) + DEADKEY_EXTENDED,// e0 08 + { kHIDPage_AppleVendorKeyboard, kHIDUsage_AppleVendorKeyboard_Launchpad }, // e0 09 Launchpad (hp Fn+F6) #endif - 0xa0, // e0 0a Mission Control (hp Fn+F5) - DEADKEY,// e0 0b - DEADKEY,// e0 0c - DEADKEY,// e0 0d - DEADKEY,// e0 0e - DEADKEY,// e0 0f - 0x4d, // e0 10 Scan Previous Track (hp Fn+F10) - DEADKEY,// e0 11 + { kHIDPage_AppleVendorKeyboard, kHIDUsage_AppleVendorKeyboard_Expose_All }, // e0 0a Mission Control (hp Fn+F5) + DEADKEY_EXTENDED,// e0 0b + DEADKEY_EXTENDED,// e0 0c + DEADKEY_EXTENDED,// e0 0d + DEADKEY_EXTENDED,// e0 0e + DEADKEY_EXTENDED,// e0 0f + MEDIA ( kHIDUsage_Csmr_ScanPreviousTrack ), // e0 10 Scan Previous Track (hp Fn+F10) + DEADKEY_EXTENDED,// e0 11 BRIGHTNESS_DOWN, // e0 12 hp down (Fn+F2) - DEADKEY,// e0 13 - DEADKEY,// e0 14 - DEADKEY,// e0 15 - DEADKEY,// e0 16 + DEADKEY_EXTENDED,// e0 13 + DEADKEY_EXTENDED,// e0 14 + DEADKEY_EXTENDED,// e0 15 + DEADKEY_EXTENDED,// e0 16 BRIGHTNESS_UP, // e0 17 hp up (Fn+F3) - DEADKEY,// e0 18 - 0x42, // e0 19 Scan Next Track (hp Fn+F12) - DEADKEY,// e0 1a - DEADKEY,// e0 1b - 0x4c, // e0 1c Keypad Enter - 0x3e, // e0 1d Right Control - DEADKEY,// e0 1e - DEADKEY,// e0 1f - 0x4a, // e0 20 Mute (hp Fn+F7) - DEADKEY,// e0 21 Calculator - 0x34, // e0 22 Play/Pause (hp Fn+F11) - DEADKEY,// e0 23 - DEADKEY,// e0 24 Stop - DEADKEY,// e0 25 - DEADKEY,// e0 26 - DEADKEY,// e0 27 - DEADKEY,// e0 28 - DEADKEY,// e0 29 - DEADKEY,// e0 2a - DEADKEY,// e0 2b - DEADKEY,// e0 2c - DEADKEY,// e0 2d - 0x49, // e0 2e Volume Down (hp Fn+F8) - DEADKEY,// e0 2f - 0x48, // e0 30 Volume Up (hp Fn+F9) - DEADKEY,// e0 31 - DEADKEY,// e0 32 WWW Home - DEADKEY,// e0 33 - DEADKEY,// e0 34 - 0x4b, // e0 35 Keypad / - DEADKEY,// e0 36 - 0x69, // e0 37 Print Screen - 0x3d, // e0 38 Right Alt - DEADKEY,// e0 39 - DEADKEY,// e0 3a - DEADKEY,// e0 3b - DEADKEY,// e0 3c - DEADKEY,// e0 3d - DEADKEY,// e0 3e - DEADKEY,// e0 3f - DEADKEY,// e0 40 - DEADKEY,// e0 41 - DEADKEY,// e0 42 - DEADKEY,// e0 43 - DEADKEY,// e0 44 - 0x71, // e0 45* Pause - DEADKEY,// e0 46* Break(Ctrl-Pause) - 0x73, // e0 47 Home - 0x7e, // e0 48 Up Arrow - 0x74, // e0 49 Page Up - DEADKEY,// e0 4a - 0x7b, // e0 4b Left Arrow - DEADKEY,// e0 4c - 0x7c, // e0 4d Right Arrow + DEADKEY_EXTENDED,// e0 18 + MEDIA ( kHIDUsage_Csmr_ScanNextTrack ), // e0 19 Scan Next Track (hp Fn+F12) + DEADKEY_EXTENDED,// e0 1a + DEADKEY_EXTENDED,// e0 1b + KEY( kHIDUsage_KeypadEnter ), // e0 1c Keypad Enter + KEY( kHIDUsage_KeyboardRightControl ), // e0 1d Right Control + DEADKEY_EXTENDED,// e0 1e + DEADKEY_EXTENDED,// e0 1f + MEDIA ( kHIDUsage_Csmr_Mute ), // e0 20 Mute (hp Fn+F7) + MEDIA ( kHIDUsage_Csmr_ALCalculator ),// e0 21 Calculator + MEDIA ( kHIDUsage_Csmr_PlayOrPause ), // e0 22 Play/Pause (hp Fn+F11) + DEADKEY_EXTENDED,// e0 23 + MEDIA ( kHIDUsage_Csmr_Stop ),// e0 24 Stop + DEADKEY_EXTENDED,// e0 25 + DEADKEY_EXTENDED,// e0 26 + DEADKEY_EXTENDED,// e0 27 + DEADKEY_EXTENDED,// e0 28 + DEADKEY_EXTENDED,// e0 29 + DEADKEY_EXTENDED,// e0 2a + DEADKEY_EXTENDED,// e0 2b + DEADKEY_EXTENDED,// e0 2c + DEADKEY_EXTENDED,// e0 2d + MEDIA ( kHIDUsage_Csmr_VolumeDecrement ), // e0 2e Volume Down (hp Fn+F8) + DEADKEY_EXTENDED,// e0 2f + MEDIA ( kHIDUsage_Csmr_VolumeIncrement ), // e0 30 Volume Up (hp Fn+F9) + DEADKEY_EXTENDED,// e0 31 + MEDIA ( kHIDUsage_Csmr_ACHome ),// e0 32 WWW Home + DEADKEY_EXTENDED,// e0 33 + DEADKEY_EXTENDED,// e0 34 + KEY ( kHIDUsage_KeypadSlash ), // e0 35 Keypad / + DEADKEY_EXTENDED,// e0 36 + KEY ( kHIDUsage_KeyboardPrintScreen ), // e0 37 Print Screen + KEY ( kHIDUsage_KeyboardRightAlt ), // e0 38 Right Alt + DEADKEY_EXTENDED,// e0 39 + DEADKEY_EXTENDED,// e0 3a + DEADKEY_EXTENDED,// e0 3b + DEADKEY_EXTENDED,// e0 3c + DEADKEY_EXTENDED,// e0 3d + DEADKEY_EXTENDED,// e0 3e + DEADKEY_EXTENDED,// e0 3f + DEADKEY_EXTENDED,// e0 40 + DEADKEY_EXTENDED,// e0 41 + DEADKEY_EXTENDED,// e0 42 + DEADKEY_EXTENDED,// e0 43 + DEADKEY_EXTENDED,// e0 44 + KEY ( kHIDUsage_KeyboardPause ), // e0 45* Pause + KEY ( kHIDUsage_KeyboardPause ), // e0 46* Break(Ctrl-Pause) + KEY ( kHIDUsage_KeyboardHome ), // e0 47 Home + KEY ( kHIDUsage_KeyboardUpArrow ), // e0 48 Up Arrow + KEY ( kHIDUsage_KeyboardPageUp ), // e0 49 Page Up + DEADKEY_EXTENDED,// e0 4a + KEY ( kHIDUsage_KeyboardLeftArrow ), // e0 4b Left Arrow + DEADKEY_EXTENDED,// e0 4c + KEY ( kHIDUsage_KeyboardRightArrow ), // e0 4d Right Arrow BRIGHTNESS_UP, // e0 4e acer up - 0x77, // e0 4f End - 0x7d, // e0 50 Down Arrow - 0x79, // e0 51 Page Down - 0x92, // e0 52 Insert = Eject - 0x75, // e0 53 Delete - DEADKEY,// e0 54 - DEADKEY,// e0 55 - DEADKEY,// e0 56 - DEADKEY,// e0 57 - DEADKEY,// e0 58 + KEY ( kHIDUsage_KeyboardEnd ), // e0 4f End + KEY ( kHIDUsage_KeyboardDownArrow ), // e0 50 Down Arrow + KEY ( kHIDUsage_KeyboardPageDown ), // e0 51 Page Down + MEDIA ( kHIDUsage_Csmr_Eject ), // e0 52 Insert = Eject + KEY ( kHIDUsage_KeyboardDeleteForward ), // e0 53 Delete + DEADKEY_EXTENDED,// e0 54 + DEADKEY_EXTENDED,// e0 55 + DEADKEY_EXTENDED,// e0 56 + DEADKEY_EXTENDED,// e0 57 + DEADKEY_EXTENDED,// e0 58 BRIGHTNESS_UP, // e0 59 acer up for my acer - DEADKEY,// e0 5a - 0x37, // e0 5b Left GUI(Windows) - 0x36, // e0 5c Right GUI(Windows) - 0x6e, // e0 5d App( Windows context menu key ) - 0x7f, // e0 5e System Power / Keyboard Power - DEADKEY,// e0 5f System Sleep (hp Fn+F1) - DEADKEY,// e0 60 - DEADKEY,// e0 61 - DEADKEY,// e0 62 - DEADKEY,// e0 63 System Wake - DEADKEY,// e0 64 - DEADKEY,// e0 65 WWW Search - DEADKEY,// e0 66 WWW Favorites - DEADKEY,// e0 67 WWW Refresh - DEADKEY,// e0 68 WWW Stop - DEADKEY,// e0 69 WWW Forward - DEADKEY,// e0 6a WWW Back - DEADKEY,// e0 6b My Computer - DEADKEY,// e0 6c Mail - DEADKEY,// e0 6d Media Select + DEADKEY_EXTENDED,// e0 5a + KEY ( kHIDUsage_KeyboardLeftGUI ), // e0 5b Left GUI(Windows) + KEY ( kHIDUsage_KeyboardRightGUI ), // e0 5c Right GUI(Windows) + KEY ( kHIDUsage_KeyboardApplication ), // e0 5d App( Windows context menu key ) + { kHIDPage_GenericDesktop, kHIDUsage_GD_SystemPowerDown }, // e0 5e System Power / Keyboard Power + { kHIDPage_GenericDesktop, kHIDUsage_GD_SystemSleep },// e0 5f System Sleep (hp Fn+F1) + DEADKEY_EXTENDED,// e0 60 + DEADKEY_EXTENDED,// e0 61 + DEADKEY_EXTENDED,// e0 62 + { kHIDPage_GenericDesktop, kHIDUsage_GD_SystemWakeUp },// e0 63 System Wake + DEADKEY_EXTENDED,// e0 64 + MEDIA ( kHIDUsage_Csmr_ACSearch ),// e0 65 WWW Search + MEDIA ( kHIDUsage_Csmr_ACBookmarks ),// e0 66 WWW Favorites + MEDIA ( kHIDUsage_Csmr_ACRefresh ),// e0 67 WWW Refresh + MEDIA ( kHIDUsage_Csmr_ACStop ),// e0 68 WWW Stop + MEDIA ( kHIDUsage_Csmr_ACForward ),// e0 69 WWW Forward + MEDIA ( kHIDUsage_Csmr_ACBack ),// e0 6a WWW Back + DEADKEY_EXTENDED,// e0 6b My Computer + MEDIA ( kHIDUsage_Csmr_ALEmailReader ),// e0 6c Mail + DEADKEY_EXTENDED,// e0 6d Media Select #ifndef PROBOOK BRIGHTNESS_UP, // e0 6e acer up BRIGHTNESS_DOWN, // e0 6f acer down #else - 0x70, // e0 6e Video Mirror = hp Fn+F4 - DEADKEY,// e0 6f Fn+Home + MEDIA ( 0x00 ), // e0 6e Video Mirror = hp Fn+F4 + DEADKEY_EXTENDED,// e0 6f Fn+Home #endif - DEADKEY,// e0 70 - DEADKEY,// e0 71 - DEADKEY,// e0 72 - DEADKEY,// e0 73 - DEADKEY,// e0 74 - DEADKEY,// e0 75 - DEADKEY,// e0 76 + DEADKEY_EXTENDED,// e0 70 + DEADKEY_EXTENDED,// e0 71 + DEADKEY_EXTENDED,// e0 72 + DEADKEY_EXTENDED,// e0 73 + DEADKEY_EXTENDED,// e0 74 + DEADKEY_EXTENDED,// e0 75 + DEADKEY_EXTENDED,// e0 76 #ifndef PROBOOK BRIGHTNESS_DOWN, // e0 77 lg down BRIGHTNESS_UP, // e0 78 lg up #else - DEADKEY,// e0 77 - DEADKEY,// e0 78 WiFi on/off button on HP ProBook + DEADKEY_EXTENDED,// e0 77 + DEADKEY_EXTENDED,// e0 78 WiFi on/off button on HP ProBook #endif - DEADKEY,// e0 79 - DEADKEY,// e0 7a - DEADKEY,// e0 7b - DEADKEY,// e0 7c - DEADKEY,// e0 7d - DEADKEY,// e0 7e - DEADKEY,// e0 7f - DEADKEY,// e0 80 - DEADKEY,// e0 81 - DEADKEY,// e0 82 - DEADKEY,// e0 83 - DEADKEY,// e0 84 - DEADKEY,// e0 85 - DEADKEY,// e0 86 - DEADKEY,// e0 87 - DEADKEY,// e0 88 - DEADKEY,// e0 89 - DEADKEY,// e0 8a - DEADKEY,// e0 8b - DEADKEY,// e0 8c - DEADKEY,// e0 8d - DEADKEY,// e0 8e - DEADKEY,// e0 8f - DEADKEY,// e0 90 - DEADKEY,// e0 91 - DEADKEY,// e0 92 - DEADKEY,// e0 93 - DEADKEY,// e0 94 - DEADKEY,// e0 95 - DEADKEY,// e0 96 - DEADKEY,// e0 97 - DEADKEY,// e0 98 - DEADKEY,// e0 99 - DEADKEY,// e0 9a - DEADKEY,// e0 9b - DEADKEY,// e0 9c - DEADKEY,// e0 9d - DEADKEY,// e0 9e - DEADKEY,// e0 9f - DEADKEY,// e0 a0 - DEADKEY,// e0 a1 - DEADKEY,// e0 a2 - DEADKEY,// e0 a3 - DEADKEY,// e0 a4 - DEADKEY,// e0 a5 - DEADKEY,// e0 a6 - DEADKEY,// e0 a7 - DEADKEY,// e0 a8 - DEADKEY,// e0 a9 - DEADKEY,// e0 aa - DEADKEY,// e0 ab - DEADKEY,// e0 ac - DEADKEY,// e0 ad - DEADKEY,// e0 ae - DEADKEY,// e0 af - DEADKEY,// e0 b0 - DEADKEY,// e0 b1 - DEADKEY,// e0 b2 - DEADKEY,// e0 b3 - DEADKEY,// e0 b4 - DEADKEY,// e0 b5 - DEADKEY,// e0 b6 - DEADKEY,// e0 b7 - DEADKEY,// e0 b8 - DEADKEY,// e0 b9 - DEADKEY,// e0 ba - DEADKEY,// e0 bb - DEADKEY,// e0 bc - DEADKEY,// e0 bd - DEADKEY,// e0 be - DEADKEY,// e0 bf - DEADKEY,// e0 c0 - DEADKEY,// e0 c1 - DEADKEY,// e0 c2 - DEADKEY,// e0 c3 - DEADKEY,// e0 c4 - DEADKEY,// e0 c5 - DEADKEY,// e0 c6 - DEADKEY,// e0 c7 - DEADKEY,// e0 c8 - DEADKEY,// e0 c9 - DEADKEY,// e0 ca - DEADKEY,// e0 cb - DEADKEY,// e0 cc - DEADKEY,// e0 cd - DEADKEY,// e0 ce - DEADKEY,// e0 cf - DEADKEY,// e0 d0 - DEADKEY,// e0 d1 - DEADKEY,// e0 d2 - DEADKEY,// e0 d3 - DEADKEY,// e0 d4 - DEADKEY,// e0 d5 - DEADKEY,// e0 d6 - DEADKEY,// e0 d7 - DEADKEY,// e0 d8 - DEADKEY,// e0 d9 - DEADKEY,// e0 da - DEADKEY,// e0 db - DEADKEY,// e0 dc - DEADKEY,// e0 dd - DEADKEY,// e0 de - DEADKEY,// e0 df - DEADKEY,// e0 e0 - DEADKEY,// e0 e1 - DEADKEY,// e0 e2 - DEADKEY,// e0 e3 - DEADKEY,// e0 e4 - DEADKEY,// e0 e5 - DEADKEY,// e0 e6 - DEADKEY,// e0 e7 - DEADKEY,// e0 e8 - DEADKEY,// e0 e9 - DEADKEY,// e0 ea - DEADKEY,// e0 eb - DEADKEY,// e0 ec - DEADKEY,// e0 ed - DEADKEY,// e0 ee - DEADKEY,// e0 ef - DEADKEY,// e0 f0 // Note: codes e0f0 through e0ff are reserved for ACPI callback - DEADKEY,// e0 f1 - DEADKEY,// e0 f2 - DEADKEY,// e0 f3 - DEADKEY,// e0 f4 - DEADKEY,// e0 f5 - DEADKEY,// e0 f6 - DEADKEY,// e0 f7 - DEADKEY,// e0 f8 - DEADKEY,// e0 f9 - DEADKEY,// e0 fa - DEADKEY,// e0 fb - DEADKEY,// e0 fc - DEADKEY,// e0 fd - DEADKEY,// e0 fe - DEADKEY // e0 ff // End reserved + DEADKEY_EXTENDED,// e0 79 + DEADKEY_EXTENDED,// e0 7a + DEADKEY_EXTENDED,// e0 7b + DEADKEY_EXTENDED,// e0 7c + DEADKEY_EXTENDED,// e0 7d + DEADKEY_EXTENDED,// e0 7e + DEADKEY_EXTENDED,// e0 7f + DEADKEY_EXTENDED,// e0 80 + DEADKEY_EXTENDED,// e0 81 + DEADKEY_EXTENDED,// e0 82 + DEADKEY_EXTENDED,// e0 83 + DEADKEY_EXTENDED,// e0 84 + DEADKEY_EXTENDED,// e0 85 + DEADKEY_EXTENDED,// e0 86 + DEADKEY_EXTENDED,// e0 87 + DEADKEY_EXTENDED,// e0 88 + DEADKEY_EXTENDED,// e0 89 + DEADKEY_EXTENDED,// e0 8a + DEADKEY_EXTENDED,// e0 8b + DEADKEY_EXTENDED,// e0 8c + DEADKEY_EXTENDED,// e0 8d + DEADKEY_EXTENDED,// e0 8e + DEADKEY_EXTENDED,// e0 8f + DEADKEY_EXTENDED,// e0 90 + DEADKEY_EXTENDED,// e0 91 + DEADKEY_EXTENDED,// e0 92 + DEADKEY_EXTENDED,// e0 93 + DEADKEY_EXTENDED,// e0 94 + DEADKEY_EXTENDED,// e0 95 + DEADKEY_EXTENDED,// e0 96 + DEADKEY_EXTENDED,// e0 97 + DEADKEY_EXTENDED,// e0 98 + DEADKEY_EXTENDED,// e0 99 + DEADKEY_EXTENDED,// e0 9a + DEADKEY_EXTENDED,// e0 9b + DEADKEY_EXTENDED,// e0 9c + DEADKEY_EXTENDED,// e0 9d + DEADKEY_EXTENDED,// e0 9e + DEADKEY_EXTENDED,// e0 9f + DEADKEY_EXTENDED,// e0 a0 + DEADKEY_EXTENDED,// e0 a1 + DEADKEY_EXTENDED,// e0 a2 + DEADKEY_EXTENDED,// e0 a3 + DEADKEY_EXTENDED,// e0 a4 + DEADKEY_EXTENDED,// e0 a5 + DEADKEY_EXTENDED,// e0 a6 + DEADKEY_EXTENDED,// e0 a7 + DEADKEY_EXTENDED,// e0 a8 + DEADKEY_EXTENDED,// e0 a9 + DEADKEY_EXTENDED,// e0 aa + DEADKEY_EXTENDED,// e0 ab + DEADKEY_EXTENDED,// e0 ac + DEADKEY_EXTENDED,// e0 ad + DEADKEY_EXTENDED,// e0 ae + DEADKEY_EXTENDED,// e0 af + DEADKEY_EXTENDED,// e0 b0 + DEADKEY_EXTENDED,// e0 b1 + DEADKEY_EXTENDED,// e0 b2 + DEADKEY_EXTENDED,// e0 b3 + DEADKEY_EXTENDED,// e0 b4 + DEADKEY_EXTENDED,// e0 b5 + DEADKEY_EXTENDED,// e0 b6 + DEADKEY_EXTENDED,// e0 b7 + DEADKEY_EXTENDED,// e0 b8 + DEADKEY_EXTENDED,// e0 b9 + DEADKEY_EXTENDED,// e0 ba + DEADKEY_EXTENDED,// e0 bb + DEADKEY_EXTENDED,// e0 bc + DEADKEY_EXTENDED,// e0 bd + DEADKEY_EXTENDED,// e0 be + DEADKEY_EXTENDED,// e0 bf + DEADKEY_EXTENDED,// e0 c0 + DEADKEY_EXTENDED,// e0 c1 + DEADKEY_EXTENDED,// e0 c2 + DEADKEY_EXTENDED,// e0 c3 + DEADKEY_EXTENDED,// e0 c4 + DEADKEY_EXTENDED,// e0 c5 + DEADKEY_EXTENDED,// e0 c6 + DEADKEY_EXTENDED,// e0 c7 + DEADKEY_EXTENDED,// e0 c8 + DEADKEY_EXTENDED,// e0 c9 + DEADKEY_EXTENDED,// e0 ca + DEADKEY_EXTENDED,// e0 cb + DEADKEY_EXTENDED,// e0 cc + DEADKEY_EXTENDED,// e0 cd + DEADKEY_EXTENDED,// e0 ce + DEADKEY_EXTENDED,// e0 cf + DEADKEY_EXTENDED,// e0 d0 + DEADKEY_EXTENDED,// e0 d1 + DEADKEY_EXTENDED,// e0 d2 + DEADKEY_EXTENDED,// e0 d3 + DEADKEY_EXTENDED,// e0 d4 + DEADKEY_EXTENDED,// e0 d5 + DEADKEY_EXTENDED,// e0 d6 + DEADKEY_EXTENDED,// e0 d7 + DEADKEY_EXTENDED,// e0 d8 + DEADKEY_EXTENDED,// e0 d9 + DEADKEY_EXTENDED,// e0 da + DEADKEY_EXTENDED,// e0 db + DEADKEY_EXTENDED,// e0 dc + DEADKEY_EXTENDED,// e0 dd + DEADKEY_EXTENDED,// e0 de + DEADKEY_EXTENDED,// e0 df + DEADKEY_EXTENDED,// e0 e0 + DEADKEY_EXTENDED,// e0 e1 + DEADKEY_EXTENDED,// e0 e2 + DEADKEY_EXTENDED,// e0 e3 + DEADKEY_EXTENDED,// e0 e4 + DEADKEY_EXTENDED,// e0 e5 + DEADKEY_EXTENDED,// e0 e6 + DEADKEY_EXTENDED,// e0 e7 + DEADKEY_EXTENDED,// e0 e8 + DEADKEY_EXTENDED,// e0 e9 + DEADKEY_EXTENDED,// e0 ea + DEADKEY_EXTENDED,// e0 eb + DEADKEY_EXTENDED,// e0 ec + DEADKEY_EXTENDED,// e0 ed + DEADKEY_EXTENDED,// e0 ee + DEADKEY_EXTENDED,// e0 ef + DEADKEY_EXTENDED,// e0 f0 // Note: codes e0f0 through e0ff are reserved for ACPI callback + DEADKEY_EXTENDED,// e0 f1 + DEADKEY_EXTENDED,// e0 f2 + DEADKEY_EXTENDED,// e0 f3 + DEADKEY_EXTENDED,// e0 f4 + DEADKEY_EXTENDED,// e0 f5 + DEADKEY_EXTENDED,// e0 f6 + DEADKEY_EXTENDED,// e0 f7 + DEADKEY_EXTENDED,// e0 f8 + DEADKEY_EXTENDED,// e0 f9 + DEADKEY_EXTENDED,// e0 fa + DEADKEY_EXTENDED,// e0 fb + DEADKEY_EXTENDED,// e0 fc + DEADKEY_EXTENDED,// e0 fd + DEADKEY_EXTENDED,// e0 fe + DEADKEY_EXTENDED // e0 ff // End reserved }; /////////////////////////////////////////////////////////////////////////////////// @@ -605,7 +613,7 @@ static const UInt8 PS2ToADBMapStock[ADB_CONVERTER_LEN] = #define kMaskLeftFn 0x0100 #define kMaskWindowsContext 0x0200 -static const UInt16 _PS2flagsStock[ADB_CONVERTER_LEN] = +static const UInt16 _PS2flagsStock[256*2] = { // flags/modifier key AT ANSI Key-Legend 0x00, // 00 diff --git a/VoodooPS2Keyboard/VoodooPS2EventDriver.hpp b/VoodooPS2Keyboard/VoodooPS2EventDriver.hpp new file mode 100644 index 00000000..d773d3ca --- /dev/null +++ b/VoodooPS2Keyboard/VoodooPS2EventDriver.hpp @@ -0,0 +1,31 @@ +// +// HIDPS2EventDriver.hpp +// HIDPS2Keyboard +// +// Created by Gwydien on 8/27/23. +// Copyright © 2023 coolstar. All rights reserved. +// + +#ifndef HIDPS2EventDriver_hpp +#define HIDPS2EventDriver_hpp + +#include + +class VoodooPS2KeyboardHIDEventDriver : public IOHIDEventService +{ + OSDeclareDefaultStructors( VoodooPS2KeyboardHIDEventDriver ); + friend class VoodooPS2KeyboardHIDWrapper; + +public: + bool start(IOService *provider) override { + IOHIDInterface *interface = OSDynamicCast(IOHIDInterface, provider); + if (!IOHIDEventService::start(provider)) { + return false; + } + + registerService(); + return interface->open(this, 0, nullptr, nullptr); + } +}; + +#endif /* HIDPS2EventDriver_hpp */ diff --git a/VoodooPS2Keyboard/VoodooPS2Keyboard-Info.plist b/VoodooPS2Keyboard/VoodooPS2Keyboard-Info.plist index 7e224756..ca4e7058 100644 --- a/VoodooPS2Keyboard/VoodooPS2Keyboard-Info.plist +++ b/VoodooPS2Keyboard/VoodooPS2Keyboard-Info.plist @@ -22,6 +22,31 @@ ${MODULE_VERSION} IOKitPersonalities + VoodooPS2HIDEventDriver + + CFBundleIdentifier + com.1Revenger1.PS2Keyboard + DeviceUsagePairs + + + DeviceUsage + 1 + DeviceUsagePage + 12 + + + IOClass + VoodooPS2KeyboardHIDEventDriver + IOProbeScore + 8000 + IOPropertyMatch + + Transport + PS2 + + IOProviderClass + IOHIDInterface + ApplePS2Keyboard CFBundleIdentifier diff --git a/VoodooPS2Keyboard/VoodooPS2Keyboard.cpp b/VoodooPS2Keyboard/VoodooPS2Keyboard.cpp index fe47247e..ab90c7b9 100644 --- a/VoodooPS2Keyboard/VoodooPS2Keyboard.cpp +++ b/VoodooPS2Keyboard/VoodooPS2Keyboard.cpp @@ -20,12 +20,6 @@ * @APPLE_LICENSE_HEADER_END@ */ -// enable for keyboard debugging -#ifdef DEBUG_MSG -//#define DEBUG_VERBOSE -#define DEBUG_LITE -#endif - #include #include @@ -34,10 +28,8 @@ #include #include -#include "ApplePS2ToADBMap.h" #include "VoodooPS2Controller.h" #include "VoodooPS2Keyboard.h" -#include "ApplePS2ToADBMap.h" #include "AppleACPIPS2Nub.h" #include @@ -45,10 +37,7 @@ // Constants for Info.plist settings #define kSleepPressTime "SleepPressTime" -#define kHIDFKeyMode "HIDFKeyMode" #define kHIDF12EjectDelay "HIDF12EjectDelay" -#define kFunctionKeysStandard "Function Keys Standard" -#define kFunctionKeysSpecial "Function Keys Special" #define kRemapPrntScr "RemapPrntScr" #define kNumLockSupport "NumLockSupport" #define kNumLockOnAtBoot "NumLockOnAtBoot" @@ -58,54 +47,12 @@ #define kMakeApplicationKeyAppleFN "Make Application key into Apple Fn key" #define kMakeRightModsHangulHanja "Make right modifier keys into Hangul and Hanja" #define kUseISOLayoutKeyboard "Use ISO layout keyboard" -#define kLogScanCodes "LogScanCodes" - -#define kBrightnessHack "BrightnessHack" -#define kMacroInversion "Macro Inversion" -#define kMacroTranslation "Macro Translation" -#define kMaxMacroTime "MaximumMacroTime" - -// 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) -#define kOutputBytes 2 // two bytes of Macro Inversion are used to specify output -#define kModifierBytes 4 // 4 bytes specify modifier key match criteria -#define kOutputBytesOffset (kIgnoreBytes+0) -#define kModifierBytesOffset (kIgnoreBytes+kOutputBytes+0) -#define kPrefixBytes (kIgnoreBytes+kOutputBytes+kModifierBytes) -#define kSequenceBytesOffset (kPrefixBytes+0) -#define kMinMacroInversion (kPrefixBytes+2) - -// Constants for other services to communicate with - -#define kIOHIDSystem "IOHIDSystem" // ============================================================================= // ApplePS2Keyboard Class Implementation // -// get some keyboard id information from IOHIDFamily/IOHIDKeyboard.h and Gestalt.h -//#define APPLEPS2KEYBOARD_DEVICE_TYPE 205 // Generic ISO keyboard -#define APPLEPS2KEYBOARD_DEVICE_TYPE 3 // Unknown ANSI keyboard - -OSDefineMetaClassAndStructors(ApplePS2Keyboard, IOHIKeyboard); - -UInt32 ApplePS2Keyboard::deviceType() -{ - OSNumber *xml_handlerID; - UInt32 ret_id; - - if ( (xml_handlerID = OSDynamicCast( OSNumber, getProperty("alt_handler_id"))) ) - ret_id = xml_handlerID->unsigned32BitValue(); - else - ret_id = APPLEPS2KEYBOARD_DEVICE_TYPE; - - return ret_id; -} - -UInt32 ApplePS2Keyboard::interfaceID() { return NX_EVS_DEVICE_INTERFACE_ADB; } - -UInt32 ApplePS2Keyboard::maxKeyCodes() { return NX_NUMKEYCODES; } +OSDefineMetaClassAndStructors(ApplePS2Keyboard, IOService); // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -128,7 +75,7 @@ static const char* parseHex(const char *psz, char term1, char term2, unsigned& o return psz; } -static bool parseRemap(const char *psz, UInt16 &scanFrom, UInt16& scanTo) +static bool parseRemap(const char *psz, UInt16 &scanFrom, UInt32& scanTo) { // psz is of the form: "scanfrom=scanto", examples: // non-extended: "1d=3a" @@ -141,7 +88,7 @@ static bool parseRemap(const char *psz, UInt16 &scanFrom, UInt16& scanTo) return false; scanFrom = n; psz = parseHex(psz+1, '\n', ';', n); - if (NULL == psz || n > 0xFFFF) + if (NULL == psz) return false; scanTo = n; return true; @@ -173,35 +120,20 @@ bool ApplePS2Keyboard::init(OSDictionary * dict) _sleepEjectTimer = 0; _cmdGate = 0; - _fkeymode = 0; - _fkeymodesupported = false; - _keysStandard = 0; - _keysSpecial = 0; _f12ejectdelay = 250; // default is 250 ms - // initialize ACPI support for keyboard backlight - _provider = 0; - _backlightLevels = 0; - - _logscancodes = 0; - _brightnessHack = false; - - // initalize macro translation - _macroInversion = 0; - _macroTranslation = 0; - _macroBuffer = 0; - _macroCurrent = 0; - _macroMax = 0; - _macroMaxTime = 25000000ULL; - _macroTimer = 0; - _ignoreCapsLedChange = false; // start out with all keys up bzero(_keyBitVector, sizeof(_keyBitVector)); // make separate copy of ADB translation table. - bcopy(PS2ToADBMapStock, _PS2ToADBMapMapped, sizeof(_PS2ToADBMapMapped)); + for (int i = 0; i < ADB_CONVERTER_LEN; i++) { + _PS2ToHIDMap[i].usagePage = kHIDPage_KeyboardOrKeypad; + _PS2ToHIDMap[i].usage = PS2ToHIDMapStock[i]; + } + + bcopy(ExtendedPS2ToHIDStockMap, &_PS2ToHIDMap[256], sizeof(ExtendedPS2ToHIDStockMap)); // Setup the PS2 -> PS2 scan code mapper for (int i = 0; i < countof(_PS2ToPS2Map); i++) @@ -210,6 +142,7 @@ bool ApplePS2Keyboard::init(OSDictionary * dict) // first half of map is normal scan codes, second half is extended scan codes (e0) _PS2ToPS2Map[i] = i; } + bcopy(_PS2flagsStock, _PS2flags, sizeof(_PS2flags)); return true; @@ -263,45 +196,9 @@ ApplePS2Keyboard* ApplePS2Keyboard::probe(IOService * provider, SInt32 * score) loadBreaklessPS2(config, "Breakless PS2"); // now load PS2 -> ADB configuration data - loadCustomADBMap(config, "Custom ADB Map"); - - // determine if _fkeymode property should be handled in setParamProperties - _keysStandard = OSDynamicCast(OSArray, config->getObject(kFunctionKeysStandard)); - _keysSpecial = OSDynamicCast(OSArray, config->getObject(kFunctionKeysSpecial)); - _fkeymodesupported = _keysStandard && _keysSpecial; - if (_fkeymodesupported) - { - setProperty(kHIDFKeyMode, (uint64_t)0, 64); - _keysStandard->retain(); - _keysSpecial->retain(); - loadCustomPS2Map(_keysSpecial); - } - else - { - _keysStandard = NULL; - _keysSpecial = NULL; - } - - // load custom macro data - _macroTranslation = loadMacroData(config, kMacroTranslation); - _macroInversion = loadMacroData(config, kMacroInversion); - if (_macroInversion) - { - int max = 0; - for (OSData** p = _macroInversion; *p; p++) - { - int length = (*p)->getLength()-kPrefixBytes; - if (length > max) - max = length; - } - _macroBuffer = new UInt8[max*kPacketLength]; - _macroMax = max; - } + loadCustomHIDMap(config, "Custom ADB Map"); } - // now copy to our PS2ToADBMap -- working copy... - bcopy(_PS2ToADBMapMapped, _PS2ToADBMap, sizeof(_PS2ToADBMap)); - // populate rest of values via setParamProperties setParamPropertiesGated(config); OSSafeReleaseNULL(config); @@ -381,66 +278,6 @@ bool ApplePS2Keyboard::start(IOService * provider) return false; } - // get IOACPIPlatformDevice for Device (PS2K) - //REVIEW: should really look at the parent chain for IOACPIPlatformDevice instead. - _provider = (IOACPIPlatformDevice*)IORegistryEntry::fromPath("IOService:/AppleACPIPlatformExpert/PS2K"); - - // - // get keyboard backlight levels for ACPI based backlight keys - // - - OSObject* result = 0; - if (_provider) do - { - // check for brightness methods - if (kIOReturnSuccess != _provider->validateObject("KKCL") || kIOReturnSuccess != _provider->validateObject("KKCM") || kIOReturnSuccess != _provider->validateObject("KKQC")) - { - DEBUG_LOG("ps2bl: KKCL, KKCM, KKQC methods not found in DSDT\n"); - break; - } - - // methods are there, so now try to collect brightness levels - if (kIOReturnSuccess != _provider->evaluateObject("KKCL", &result)) - { - DEBUG_LOG("ps2bl: KKCL returned error\n"); - break; - } - OSArray* array = OSDynamicCast(OSArray, result); - if (!array) - { - DEBUG_LOG("ps2bl: KKCL returned non-array package\n"); - break; - } - int count = array->getCount(); - if (count < 2) - { - DEBUG_LOG("ps2bl: KKCL returned invalid package\n"); - break; - } - _backlightCount = count; - _backlightLevels = new int[_backlightCount]; - if (!_backlightLevels) - { - DEBUG_LOG("ps2bl: _backlightLevels new int[] failed\n"); - break; - } - for (int i = 0; i < _backlightCount; i++) - { - OSNumber* num = OSDynamicCast(OSNumber, array->getObject(i)); - int brightness = num ? num->unsigned32BitValue() : 0; - _backlightLevels[i] = brightness; - } -#ifdef DEBUG_VERBOSE - DEBUG_LOG("ps2bl: Keyboard backlight levels: { "); - for (int i = 0; i < _backlightCount; i++) - DEBUG_LOG("%d, ", _backlightLevels[i]); - DEBUG_LOG("}\n"); -#endif - break; - } while (false); - - OSSafeReleaseNULL(result); - // // Lock the controller during initialization // @@ -453,20 +290,27 @@ bool ApplePS2Keyboard::start(IOService * provider) initKeyboard(); - // - // Set NumLock State to On (if specified). - // - - if (_numLockOnAtBoot) - setNumLock(true); +// // +// // Set NumLock State to On (if specified). +// // +// +// if (_numLockOnAtBoot) +// setNumLock(true); pWorkLoop->addEventSource(_sleepEjectTimer); pWorkLoop->addEventSource(_cmdGate); - // _macroTimer is used in for macro inversion - _macroTimer = IOTimerEventSource::timerEventSource(this, OSMemberFunctionCast(IOTimerEventSource::Action, this, &ApplePS2Keyboard::onMacroTimer)); - if (_macroTimer) - pWorkLoop->addEventSource(_macroTimer); + // + // Construct HID Wrapper + // + _hidWrapper = OSTypeAlloc(VoodooPS2KeyboardHIDWrapper); + if (_hidWrapper == nullptr || + !_hidWrapper->init() || + !_hidWrapper->attach(this) || + !_hidWrapper->start(this)) { + IOLog("%s: HID Wrapper fail :(", getName()); + return nullptr; + } // // Install our driver's interrupt handler, for asynchronous data delivery. @@ -487,11 +331,6 @@ bool ApplePS2Keyboard::start(IOService * provider) _device->installPowerControlAction( this, OSMemberFunctionCast(PS2PowerControlAction,this, &ApplePS2Keyboard::setDevicePowerState )); _powerControlHandlerInstalled = true; - - // - // Tell ACPIPS2Nub that we are interested in ACPI notifications - // - //setProperty(kDeliverNotifications, true); DEBUG_LOG("ApplePS2Keyboard::start leaving.\n"); @@ -515,7 +354,8 @@ void ApplePS2Keyboard::loadCustomPS2Map(OSArray* pArray) if (';' == *psz) continue; // otherwise, try to parse it - UInt16 scanIn, scanOut; + UInt16 scanIn; + UInt32 scanOut; if (!parseRemap(psz, scanIn, scanOut)) { IOLog("VoodooPS2Keyboard: invalid custom PS2 map entry: \"%s\"\n", psz); @@ -574,7 +414,7 @@ void ApplePS2Keyboard::loadBreaklessPS2(OSDictionary* dict, const char* name) } } -void ApplePS2Keyboard::loadCustomADBMap(OSDictionary* dict, const char* name) +void ApplePS2Keyboard::loadCustomHIDMap(OSDictionary* dict, const char* name) { OSArray* pArray = OSDynamicCast(OSArray, dict->getObject(name)); if (NULL != pArray) @@ -590,77 +430,27 @@ void ApplePS2Keyboard::loadCustomADBMap(OSDictionary* dict, const char* name) if (';' == *psz) continue; // otherwise, try to parse it - UInt16 scanIn, adbOut; - if (!parseRemap(psz, scanIn, adbOut)) + UInt16 scanIn; + UInt32 hidOut; + if (!parseRemap(psz, scanIn, hidOut)) { IOLog("VoodooPS2Keyboard: invalid custom ADB map entry: \"%s\"\n", psz); continue; } // must be normal scan code or extended, nothing else, adbOut is only a byte UInt8 exIn = scanIn >> 8; - if ((exIn != 0 && exIn != 0xe0) || adbOut > 0xFF) + if (exIn != 0 && exIn != 0xe0) { IOLog("VoodooPS2Keyboard: scan code invalid for ADB map entry: \"%s\"\n", psz); continue; } // modify PS2 to ADB map per remap entry int index = (scanIn & 0xff) + (exIn == 0xe0 ? ADB_CONVERTER_EX_START : 0); - assert(index < countof(_PS2ToADBMapMapped)); - _PS2ToADBMapMapped[index] = adbOut; - } - } -} - -OSData** ApplePS2Keyboard::loadMacroData(OSDictionary* dict, const char* name) -{ - OSData** result = 0; - OSArray* pArray = OSDynamicCast(OSArray, dict->getObject(name)); - if (NULL != pArray) - { - // count valid entries - int total = 0; - int count = pArray->getCount(); - for (int i = 0; i < count; i++) - { - if (OSData* pData = OSDynamicCast(OSData, pArray->getObject(i))) - { - int length = pData->getLength(); - if (length >= kMinMacroInversion && !(length & 0x01)) - { - const UInt8* p = static_cast(pData->getBytesNoCopy()); - if (p[0] == 0xFF && p[1] == 0xFF) - total++; - } - } - } - if (total) - { - // store valid entries - result = new OSData*[total+1]; - if (result) - { - bzero(result, sizeof(char*)*(total+1)); - int index = 0; - for (int i = 0; i < count; i++) - { - if (OSData* pData = OSDynamicCast(OSData, pArray->getObject(i))) - { - int length = pData->getLength(); - if (length >= kMinMacroInversion && !(length & 0x01)) - { - const UInt8* p = static_cast(pData->getBytesNoCopy()); - if (p[0] == 0xFF && p[1] == 0xFF) - { - result[index++] = pData; - pData->retain(); - } - } - } - } - } + assert(index < countof(_PS2ToHIDMap)); + _PS2ToHIDMap[index].usagePage = hidOut >> 16; + _PS2ToHIDMap[index].usage = hidOut & 0xFFFF; } } - return result; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -684,29 +474,6 @@ void ApplePS2Keyboard::setParamPropertiesGated(OSDictionary * dict) _f12ejectdelay = num->unsigned32BitValue(); setProperty(kHIDF12EjectDelay, _f12ejectdelay, 32); } - // get time between keys part of a macro "inversion" - if (OSNumber* num = OSDynamicCast(OSNumber, dict->getObject(kMaxMacroTime))) - { - _macroMaxTime = num->unsigned64BitValue(); - setProperty(kMaxMacroTime, _macroMaxTime, 64); - } - - if (_fkeymodesupported) - { - // get function key mode - UInt32 oldfkeymode = _fkeymode; - if (OSNumber* num = OSDynamicCast(OSNumber, dict->getObject(kHIDFKeyMode))) - { - _fkeymode = num->unsigned32BitValue(); - setProperty(kHIDFKeyMode, _fkeymode, 32); - } - if (oldfkeymode != _fkeymode) - { - OSArray* keys = _fkeymode ? _keysStandard : _keysSpecial; - assert(keys); - loadCustomPS2Map(keys); - } - } // // Configure user preferences from Info.plist @@ -714,12 +481,11 @@ void ApplePS2Keyboard::setParamPropertiesGated(OSDictionary * dict) OSBoolean* xml = OSDynamicCast(OSBoolean, dict->getObject(kSwapCapsLockLeftControl)); if (xml) { if (xml->isTrue()) { - _PS2ToADBMap[0x3a] = _PS2ToADBMapMapped[0x1d]; - _PS2ToADBMap[0x1d] = _PS2ToADBMapMapped[0x3a]; - } - else { - _PS2ToADBMap[0x3a] = _PS2ToADBMapMapped[0x3a]; - _PS2ToADBMap[0x1d] = _PS2ToADBMapMapped[0x1d]; + _PS2ToHIDMap[0x3a].usage = PS2ToHIDMapStock[0x1d]; + _PS2ToHIDMap[0x1d].usage = PS2ToHIDMapStock[0x3a]; + } else { + _PS2ToHIDMap[0x3a].usage = PS2ToHIDMapStock[0x3a]; + _PS2ToHIDMap[0x1d].usage = PS2ToHIDMapStock[0x1d]; } setProperty(kSwapCapsLockLeftControl, xml->isTrue() ? kOSBooleanTrue : kOSBooleanFalse); } @@ -728,29 +494,20 @@ void ApplePS2Keyboard::setParamPropertiesGated(OSDictionary * dict) if (xml) { if (xml->isTrue()) { _swapcommandoption = true; - _PS2ToADBMap[0x38] = _PS2ToADBMapMapped[0x15b]; - _PS2ToADBMap[0x15b] = _PS2ToADBMapMapped[0x38]; - _PS2ToADBMap[0x138] = _PS2ToADBMapMapped[0x15c]; - _PS2ToADBMap[0x15c] = _PS2ToADBMapMapped[0x138]; - } - else { + _PS2ToHIDMap[0x38].usage = kHIDUsage_KeyboardLeftGUI; // Left Alt -> Left GUI + _PS2ToHIDMap[0x15b].usage = kHIDUsage_KeyboardLeftAlt; // Left GUI -> Left Alt + _PS2ToHIDMap[0x138].usage = kHIDUsage_KeyboardRightGUI; // Right Alt -> Right GUI + _PS2ToHIDMap[0x15c].usage = kHIDUsage_KeyboardRightAlt; // Right GUI -> Right Alt + } else { _swapcommandoption = false; - _PS2ToADBMap[0x38] = _PS2ToADBMapMapped[0x38]; - _PS2ToADBMap[0x15b] = _PS2ToADBMapMapped[0x15b]; - _PS2ToADBMap[0x138] = _PS2ToADBMapMapped[0x138]; - _PS2ToADBMap[0x15c] = _PS2ToADBMapMapped[0x15c]; + _PS2ToHIDMap[0x38].usage = kHIDUsage_KeyboardLeftAlt; + _PS2ToHIDMap[0x15b].usage = kHIDUsage_KeyboardLeftGUI; + _PS2ToHIDMap[0x138].usage = kHIDUsage_KeyboardRightAlt; + _PS2ToHIDMap[0x15c].usage = kHIDUsage_KeyboardRightGUI; } setProperty(kSwapCommandOption, xml->isTrue() ? kOSBooleanTrue : kOSBooleanFalse); } - // special hack for HP Envy brightness - xml = OSDynamicCast(OSBoolean, dict->getObject(kBrightnessHack)); - if (xml && xml->isTrue()) - { - //REVIEW: should really read the key assignments via Info.plist instead of hardcoding to F2/F3 - _brightnessHack = true; - } - if ((xml = OSDynamicCast(OSBoolean, dict->getObject(kRemapPrntScr)))) { _remapPrntScr = xml->getValue(); @@ -768,48 +525,30 @@ void ApplePS2Keyboard::setParamPropertiesGated(OSDictionary * dict) _numLockOnAtBoot = xml->getValue(); setProperty(kNumLockOnAtBoot, _numLockOnAtBoot); } - - // these two options are mutually exclusive - // kMakeApplicationKeyAppleFN is ignored if kMakeApplicationKeyRightWindows is set - bool temp = false; + xml = OSDynamicCast(OSBoolean, dict->getObject(kMakeApplicationKeyRightWindows)); if (xml) { if (xml->isTrue()) { - _PS2ToADBMap[0x15d] = _swapcommandoption ? 0x3d : 0x36; // ADB = right-option/right-command - temp = true; + _PS2ToHIDMap[0x15d].usage = _swapcommandoption ? kHIDUsage_KeyboardRightAlt : kHIDUsage_KeyboardRightGUI; } else { - _PS2ToADBMap[0x15d] = _PS2ToADBMapMapped[0x15d]; + _PS2ToHIDMap[0x15d].usage = kHIDUsage_KeyboardApplication; } setProperty(kMakeApplicationKeyRightWindows, xml->isTrue() ? kOSBooleanTrue : kOSBooleanFalse); } - // not implemented yet (Note: maybe not true any more) - // Apple Fn key works well, but no combined key action was made. - xml = OSDynamicCast(OSBoolean, dict->getObject(kMakeApplicationKeyAppleFN)); - if (xml) { - if (!temp) { - if (xml->isTrue()) { - _PS2ToADBMap[0x15d] = 0x3f; // ADB = AppleFN - } - else { - _PS2ToADBMap[0x15d] = _PS2ToADBMapMapped[0x15d]; - } - } - setProperty(kMakeApplicationKeyAppleFN, xml->isTrue() ? kOSBooleanTrue : kOSBooleanFalse); - } xml = OSDynamicCast(OSBoolean, dict->getObject(kMakeRightModsHangulHanja)); if (xml) { if (xml->isTrue()) { - _PS2ToADBMap[0x138] = _PS2ToADBMapMapped[0xf2]; // Right alt becomes Hangul - _PS2ToADBMap[0x11d] = _PS2ToADBMapMapped[0xf1]; // Right control becomes Hanja + _PS2ToHIDMap[0x138].usage = kHIDUsage_KeyboardLANG1; // Right alt becomes Hangul + _PS2ToHIDMap[0x11d].usage = kHIDUsage_KeyboardLANG2; // Right control becomes Hanja } else { if (_swapcommandoption) - _PS2ToADBMap[0x138] = _PS2ToADBMapMapped[0x15c]; + _PS2ToHIDMap[0x138].usage = kHIDUsage_KeyboardRightGUI; else - _PS2ToADBMap[0x138] = _PS2ToADBMapMapped[0x138]; - _PS2ToADBMap[0x11d] = _PS2ToADBMapMapped[0x11d]; + _PS2ToHIDMap[0x138].usage = kHIDUsage_KeyboardRightAlt; + _PS2ToHIDMap[0x11d].usage = kHIDUsage_KeyboardRightControl; } setProperty(kMakeRightModsHangulHanja, xml->isTrue() ? kOSBooleanTrue : kOSBooleanFalse); } @@ -819,34 +558,15 @@ void ApplePS2Keyboard::setParamPropertiesGated(OSDictionary * dict) xml = OSDynamicCast(OSBoolean, dict->getObject(kUseISOLayoutKeyboard)); if (xml) { if (xml->isTrue()) { - _PS2ToADBMap[0x29] = _PS2ToADBMapMapped[0x56]; //Europe2 '' - _PS2ToADBMap[0x56] = _PS2ToADBMapMapped[0x29]; //Grave '~' + _PS2ToHIDMap[0x29].usage = kHIDUsage_KeyboardNonUSBackslash; + _PS2ToHIDMap[0x56].usage = kHIDUsage_KeyboardGraveAccentAndTilde; } else { - _PS2ToADBMap[0x29] = _PS2ToADBMapMapped[0x29]; - _PS2ToADBMap[0x56] = _PS2ToADBMapMapped[0x56]; + _PS2ToHIDMap[0x29].usage = kHIDUsage_KeyboardGraveAccentAndTilde; + _PS2ToHIDMap[0x56].usage = kHIDUsage_KeyboardNonUSBackslash; } setProperty(kUseISOLayoutKeyboard, xml->isTrue() ? kOSBooleanTrue : kOSBooleanFalse); } - - if (OSNumber* num = OSDynamicCast(OSNumber, dict->getObject(kLogScanCodes))) { - _logscancodes = num->unsigned32BitValue(); - setProperty(kLogScanCodes, num); - } -} - -IOReturn ApplePS2Keyboard::setParamProperties(OSDictionary *dict) -{ - ////IOReturn result = super::setParamProperties(dict); - if (_cmdGate) - { - // syncronize through workloop... - ////_cmdGate->runAction(OSMemberFunctionCast(IOCommandGate::Action, this, &ApplePS2Keyboard::setParamPropertiesGated), dict); - setParamPropertiesGated(dict); - } - - return super::setParamProperties(dict); - ////return result; } IOReturn ApplePS2Keyboard::setProperties(OSObject *props) @@ -873,6 +593,11 @@ void ApplePS2Keyboard::stop(IOService * provider) assert(_device == provider); + if (_hidWrapper) { + _hidWrapper->terminate(); + _hidWrapper->release(); + } + // // Disable the keyboard itself, so that it may stop reporting key events. // @@ -895,12 +620,6 @@ void ApplePS2Keyboard::stop(IOService * provider) _sleepEjectTimer->release(); _sleepEjectTimer = 0; } - if (_macroTimer) - { - pWorkLoop->removeEventSource(_macroTimer); - _macroTimer->release(); - _macroTimer = 0; - } } // @@ -923,43 +642,6 @@ void ApplePS2Keyboard::stop(IOService * provider) OSSafeReleaseNULL(_device); - // - // Release ACPI provider for PS2K ACPI device - // - OSSafeReleaseNULL(_provider); - - // - // Release data related to keyboard backlight - // - if (_backlightLevels) - { - delete[] _backlightLevels; - _backlightLevels = 0; - } - - OSSafeReleaseNULL(_keysStandard); - OSSafeReleaseNULL(_keysSpecial); - - if (_macroInversion) - { - for (OSData** p = _macroInversion; *p; p++) - (*p)->release(); - delete[] _macroInversion; - _macroInversion = 0; - } - if (_macroTranslation) - { - for (OSData** p = _macroTranslation; *p; p++) - (*p)->release(); - delete[] _macroTranslation; - _macroTranslation = 0; - } - if (_macroBuffer) - { - delete[] _macroBuffer; - _macroBuffer = 0; - } - super::stop(provider); } @@ -987,29 +669,17 @@ IOReturn ApplePS2Keyboard::message(UInt32 type, IOService* provider, void* argum { // mark packet with timestamp clock_get_uptime((uint64_t*)(&packet[kPacketTimeOffset])); - if (!_macroInversion || !invertMacros(packet)) - { - // normal packet - dispatchKeyboardEventWithPacket(packet); - } + dispatchKeyboardEventWithPacket(packet); } if (3 == packet[0] || 4 == packet[0]) { // code 3 and 4 indicate send both make and break packet[0] -= 2; clock_get_uptime((uint64_t*)(&packet[kPacketTimeOffset])); - if (!_macroInversion || !invertMacros(packet)) - { - // normal packet (make) - dispatchKeyboardEventWithPacket(packet); - } + dispatchKeyboardEventWithPacket(packet); clock_get_uptime((uint64_t*)(&packet[kPacketTimeOffset])); packet[1] |= 0x80; // break code - if (!_macroInversion || !invertMacros(packet)) - { - // normal packet (break) - dispatchKeyboardEventWithPacket(packet); - } + dispatchKeyboardEventWithPacket(packet); } } } @@ -1043,7 +713,7 @@ IOReturn ApplePS2Keyboard::message(UInt32 type, IOService* provider, void* argum if (!keystroke->eatKey) { // the key is consumed keystroke->eatKey = true; - dispatchKeyboardEventX(keystroke->adbKeyCode, keystroke->goingDown, keystroke->time); +// dispatchKeyboardEventX(keystroke->adbKeyCode, keystroke->goingDown, keystroke->time); } } break; @@ -1056,10 +726,6 @@ IOReturn ApplePS2Keyboard::message(UInt32 type, IOService* provider, void* argum PS2InterruptResult ApplePS2Keyboard::interruptOccurred(UInt8 data) // PS2InterruptAction { - ////IOLog("ps2interrupt: scanCode = %02x\n", data); - ////uint64_t time; - ////clock_get_uptime(&time); - ////IOLog("ps2interrupt(%lld): scanCode = %02x\n", time, data); // // This will be invoked automatically from our device when asynchronous @@ -1177,11 +843,8 @@ void ApplePS2Keyboard::packetReady() UInt8* packet = _ringBuffer.tail(); if (0x00 != packet[0]) { - if (!_macroInversion || !invertMacros(packet)) - { - // normal packet - dispatchKeyboardEventWithPacket(packet); - } + // normal packet + dispatchKeyboardEventWithPacket(packet); } else { @@ -1192,188 +855,6 @@ void ApplePS2Keyboard::packetReady() } } -bool ApplePS2Keyboard::compareMacro(const UInt8* buffer, const UInt8* data, int count) -{ - while (count--) - { - if (buffer[0] != data[0] || buffer[1] != data[1]) - return false; - buffer += kPacketLength; - data += kPacketKeyDataLength; - } - return true; -} - -bool ApplePS2Keyboard::invertMacros(const UInt8* packet) -{ - assert(_macroInversion); - - if (!_macroTimer || !_macroBuffer) - return false; - - if (_macroCurrent > 0) - { - // cancel macro conversion if packet arrives too late - uint64_t now_ns; - absolutetime_to_nanoseconds(*(uint64_t*)(&packet[kPacketTimeOffset]), &now_ns); - uint64_t prev; - absolutetime_to_nanoseconds(*(uint64_t*)(&_macroBuffer[(_macroCurrent-1)*kPacketLength+kPacketTimeOffset]), &prev); - if (now_ns-prev > _macroMaxTime) - dispatchInvertBuffer(); -#if 0 // for testing min/max between macro segments - uint64_t diff = now_ns-prev; - static uint64_t diffmin = UINT64_MAX, diffmax = 0; - if (diff > diffmax) diffmax = diff; - if (diff < diffmin) diffmin = diff; - IOLog("diffmin=%lld, diffmax=%lld\n", diffmin, diffmax); -#endif - } - - // add current packet to macro buffer for comparison - memcpy(_macroBuffer+_macroCurrent*kPacketLength, packet, kPacketLength); - int buffered = _macroCurrent+1; - int total = buffered*kPacketKeyDataLength; - // compare against macro inversions - for (OSData** p = _macroInversion; *p; p++) - { - int length = (*p)->getLength()-kPrefixBytes; - if (total <= length) - { - const UInt8* data = static_cast((*p)->getBytesNoCopy()); - if (compareMacro(_macroBuffer, data+kSequenceBytesOffset, buffered)) - { - if (total == length) - { - // get modifier mask/compare from macro definition - UInt16 mask = (static_cast(data[kModifierBytesOffset+0]) << 8) + data[kModifierBytesOffset+1]; - UInt16 compare = (static_cast(data[kModifierBytesOffset+2]) << 8) + data[kModifierBytesOffset+3]; - if ((0xFFFF == compare && (_PS2modifierState & mask)) || ((_PS2modifierState & mask) == compare)) - { - // exact match causes macro inversion - // grab bytes from macro definition - _macroBuffer[0] = data[kOutputBytesOffset+0]; - _macroBuffer[1] = data[kOutputBytesOffset+1]; - // dispatch constructed packet (timestamp is stamp on first macro packet) - dispatchKeyboardEventWithPacket(_macroBuffer); - cancelTimer(_macroTimer); - _macroCurrent = 0; - return true; - } - } - else - { - // partial match, keep waiting for full match - cancelTimer(_macroTimer); - setTimerTimeout(_macroTimer, _macroMaxTime); - _macroCurrent++; - return true; - } - } - } - } - // no match, so... empty macro buffer that may have been existing... - if (_macroCurrent > 0) - dispatchInvertBuffer(); - - return false; -} - -void ApplePS2Keyboard::onMacroTimer() -{ - DEBUG_LOG("ApplePS2Keyboard::onMacroTimer\n"); - - // timers have a very high priority, packets may have been placed in the - // input queue already. - - // by calling packetReady, these packets are processed before dealing with - // the timer (the packets may have arrived before the timer) - packetReady(); - - // after all packets have been processed, ok to check for time expiration - if (_macroCurrent > 0) - { - uint64_t now_abs, now_ns; - clock_get_uptime(&now_abs); - absolutetime_to_nanoseconds(now_abs, &now_ns); - uint64_t prev; - absolutetime_to_nanoseconds(*(uint64_t*)(&_macroBuffer[(_macroCurrent-1)*kPacketLength+kPacketTimeOffset]), &prev); - if (now_ns-prev > _macroMaxTime) - dispatchInvertBuffer(); - } -} - -void ApplePS2Keyboard::dispatchInvertBuffer() -{ - UInt8* packet = _macroBuffer; - for (int i = 0; i < _macroCurrent; i++) - { - // dispatch constructed packet - dispatchKeyboardEventWithPacket(packet); - packet += kPacketLength; - } - _macroCurrent = 0; - cancelTimer(_macroTimer); -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -// -// Note: trying for ACPI backlight control for ASUS notebooks -// -// This one did work, so leaving this in. It is done in a generic way such that -// it can be used on more than just ASUS laptops, provided you can figure out -// how to implememnt the KKQC, KKCM, and KKCL methods. -// - -void ApplePS2Keyboard::modifyKeyboardBacklight(int keyCode, bool goingDown) -{ - assert(_provider); - assert(_backlightLevels); - - // get current brightness level - UInt32 result; - if (kIOReturnSuccess != _provider->evaluateInteger("KKQC", &result)) - { - DEBUG_LOG("ps2bl: KKQC returned error\n"); - return; - } - int current = result; -#ifdef DEBUG_VERBOSE - if (goingDown) - DEBUG_LOG("ps2bl: Current keyboard backlight: %d\n", current); -#endif - // calculate new brightness level, find current in table >= entry in table - // note first two entries in table are ac-power/battery - int index = 0; - while (index < _backlightCount) - { - if (_backlightLevels[index] >= current) - break; - ++index; - } - // move to next or previous - index += (keyCode == 0x4e ? +1 : -1); - if (index >= _backlightCount) - index = _backlightCount - 1; - if (index < 0) - index = 0; -#ifdef DEBUG_VERBOSE - if (goingDown) - DEBUG_LOG("ps2bl: setting keyboard backlight %d\n", _backlightLevels[index]); -#endif - OSNumber* num = OSNumber::withNumber(_backlightLevels[index], 32); - if (!num) - { - DEBUG_LOG("ps2bl: OSNumber::withNumber failed\n"); - return; - } - if (goingDown && kIOReturnSuccess != _provider->evaluateObject("KKCM", NULL, (OSObject**)&num, 1)) - { - DEBUG_LOG("ps2bl: KKCM returned error\n"); - } - num->release(); -} - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void ApplePS2Keyboard::onSleepEjectTimer() @@ -1392,7 +873,7 @@ void ApplePS2Keyboard::onSleepEjectTimer() { uint64_t now_abs; clock_get_uptime(&now_abs); - dispatchKeyboardEventX(0x92, true, now_abs); + dispatchKeyboardEventX(kHIDPage_Consumer, kHIDUsage_Csmr_Eject, true, now_abs); break; } } @@ -1407,17 +888,11 @@ bool ApplePS2Keyboard::dispatchKeyboardEventWithPacket(const UInt8* packet) UInt8 extended = packet[0] - 1; UInt8 scanCode = packet[1]; - -#ifdef DEBUG_VERBOSE - DEBUG_LOG("%s: PS/2 scancode %s 0x%x\n", getName(), extended ? "extended" : "", scanCode); -#endif unsigned keyCodeRaw = scanCode & ~kSC_UpBit; bool goingDown = !(scanCode & kSC_UpBit); unsigned keyCode; uint64_t now_abs = *(uint64_t*)(&packet[kPacketTimeOffset]); - uint64_t now_ns; - absolutetime_to_nanoseconds(now_abs, &now_ns); // // Convert the scan code into a key code index. @@ -1435,36 +910,20 @@ bool ApplePS2Keyboard::dispatchKeyboardEventWithPacket(const UInt8* packet) if (scanCode == 0xf2 || scanCode == 0xf1) { clock_get_uptime(&now_abs); - dispatchKeyboardEventX(_PS2ToADBMap[scanCode], true, now_abs); + dispatchKeyboardEventX(_PS2ToHIDMap[scanCode], true, now_abs); clock_get_uptime(&now_abs); - dispatchKeyboardEventX(_PS2ToADBMap[scanCode], false, now_abs); + dispatchKeyboardEventX(_PS2ToHIDMap[scanCode], false, now_abs); return true; } // Allow PS2 -> PS2 map to work, look in normal part of the table keyCode = _PS2ToPS2Map[keyCodeRaw]; - -#ifdef DEBUG_VERBOSE - if (keyCode != keyCodeRaw) - DEBUG_LOG("%s: keycode translated from=0x%02x to=0x%04x\n", getName(), keyCodeRaw, keyCode); -#endif } else { // allow PS2 -> PS2 map to work, look in extended part of the table keyCodeRaw += KBV_NUM_SCANCODES; keyCode = _PS2ToPS2Map[keyCodeRaw]; - -#ifdef DEBUG_VERBOSE - if (keyCode != keyCodeRaw) - DEBUG_LOG("%s: keycode translated from=0xe0%02x to=0x%04x\n", getName(), keyCodeRaw, keyCode); -#endif - // handle special cases - switch (keyCodeRaw) - { - case 0x012a: // header or trailer for PrintScreen - return false; - } } // tracking modifier key state @@ -1474,85 +933,15 @@ bool ApplePS2Keyboard::dispatchKeyboardEventWithPacket(const UInt8* packet) goingDown ? _PS2modifierState |= mask : _PS2modifierState &= ~mask; } - // codes e0f0 through e0ff can be used to call back into ACPI methods on this device - if (keyCode >= 0x01f0 && keyCode <= 0x01ff && _provider != NULL) - { - // evaluate RKA[0-F] for these keys - char method[5] = "RKAx"; - char n = keyCode - 0x01f0; - method[3] = n < 10 ? n + '0' : n - 10 + 'A'; - if (OSNumber* num = OSNumber::withNumber(goingDown, 32)) - { - // call ACPI RKAx(Arg0=goingDown) - _provider->evaluateObject(method, NULL, (OSObject**)&num, 1); - num->release(); - } - } - // handle special cases switch (keyCode) { - case 0x45: // NumLock - if (_numLockSupport && (scanCode == 0xc5)) // NumLock -> Up - { - setNumLock(!numLock()); - return true; - } - else if (_numLockSupport && (scanCode == 0x45)) // NumLock -> Down - return false; - break; - - case 0x4e: // Numpad+ - case 0x4a: // Numpad- - if (_backlightLevels && checkModifierState(kMaskLeftControl|kMaskLeftAlt)) - { - // Ctrl+Alt+Numpad(+/-) => use to manipulate keyboard backlight - modifyKeyboardBacklight(keyCode, goingDown); - keyCode = 0; - } - else if (_brightnessHack && checkModifierState(kMaskLeftControl|kMaskLeftShift)) - { - // Ctrl+Shift+NumPad(+/0) => manipulate brightness (special hack for HP Envy) - // Fn+F2 generates e0 ab and so does Fn+F3 (we will null those out in ps2 map) - static unsigned keys[] = { 0x2a, 0x1d }; - // if Option key is down don't pull up on the Shift keys - int state = checkModifierState(kMaskLeftWindows) ? 1 : 0; - for (int i = state; i < countof(keys); i++) - if (KBV_IS_KEYDOWN(keys[i])) - dispatchKeyboardEventX(_PS2ToADBMap[keys[i]], false, now_abs); - dispatchKeyboardEventX(keyCode == 0x4e ? 0x90 : 0x91, goingDown, now_abs); - for (int i = state; i < countof(keys); i++) - if (KBV_IS_KEYDOWN(keys[i])) - dispatchKeyboardEventX(_PS2ToADBMap[keys[i]], true, now_abs); - keyCode = 0; - } - break; - - case 0x0153: // delete - // check for Ctrl+Alt+Delete? (three finger salute) - if (checkModifierState(kMaskLeftControl|kMaskLeftAlt)) - { - keyCode = 0; - if (!goingDown) - { - // Note: If OS X thinks the Command and Control keys are down at the time of - // receiving an ADB 0x7f (power button), it will unconditionaly and unsafely - // reboot the computer, much like the old PC/AT Ctrl+Alt+Delete! - // That's why we make sure Control (0x3b) and Alt (0x37) are up!! - dispatchKeyboardEventX(0x37, false, now_abs); - dispatchKeyboardEventX(0x3b, false, now_abs); - dispatchKeyboardEventX(0x7f, true, now_abs); - dispatchKeyboardEventX(0x7f, false, now_abs); - } - } - break; - case 0x015f: // sleep keyCode = 0; if (goingDown) { _timerFunc = kTimerSleep; - if (_fkeymode || !_maxsleeppresstime) + if (!_maxsleeppresstime) onSleepEjectTimer(); else setTimerTimeout(_sleepEjectTimer, (uint64_t)_maxsleeppresstime * 1000000); @@ -1562,287 +951,78 @@ bool ApplePS2Keyboard::dispatchKeyboardEventWithPacket(const UInt8* packet) cancelTimer(_sleepEjectTimer); } break; - - //REVIEW: this is getting a bit ugly - case 0x0054: // SysRq (PrntScr when combined with Alt modifier -left or right-) - if (!_remapPrntScr) - break; - case 0x0128: // alternate that cannot fnkeys toggle (discrete trackpad toggle) - { - - // PrntScr is handled specially by some keyboard devices. - // See: 5.19 on https://www.win.tue.nl/~aeb/linux/kbd/scancodes-5.html#mtek -#ifdef DEBUG - UInt16 debug_originalModifiers = _PS2modifierState; -#endif - // Force Alt (Left) key to be down when receiving this keycode, dont rely on KB firmware - _PS2modifierState &= ~kMaskRightAlt; - _PS2modifierState |= kMaskLeftAlt; - keyCode = 0x0137; // Rewrite keycode - -#ifdef DEBUG - IOLog("VoodooPS2Keyboard: special PrntScr: modifiersBefore=%#.4X modifiersAfter=%#.4X\n", debug_originalModifiers, _PS2modifierState); -#endif - - // Fall to the original PrntScr handling case - } - case 0x0137: // prt sc/sys rq - { - if (!_remapPrntScr) - break; - - /* Supported Voodoo PrntScr Key combinations: - PrntScr Enable/Disable touchpad - Windows+PrntScr Enable/Disable touchpad+keyboard - Ctrl+Alt+PrntScr Reset and enable touchpad - Shift+PrntScr Send SysRq scancode to the kernel - - Notes: - - Alt+Windows combo seems to be masked out by some keyboard devices and dont produce any ScanCode. - Dont rely on it. - */ - - unsigned origKeyCode = keyCode; - keyCode = 0; // Handle all these keycode variants internally - -#ifdef DEBUG - bool debug_control = checkModifierStateAny(kMaskLeftControl|kMaskRightControl); - bool debug_alt = checkModifierStateAny(kMaskLeftAlt|kMaskRightAlt); - bool debug_shift = checkModifierStateAny(kMaskLeftShift|kMaskRightShift); - bool debug_windows = checkModifierStateAny(kMaskLeftWindows|kMaskRightWindows); - - IOLog("VoodooPS2Keyboard: PrtScr:: goingDown=%s control=%s alt=%s shift=%s windows=%s modifiers=%d\n", - goingDown ? "Yes" : "No", - debug_control ? "Yes" : "No", - debug_alt ? "Yes" : "No", - debug_shift ? "Yes" : "No", - debug_windows ? "Yes" : "No", - _PS2modifierState); -#endif - - if (!goingDown) - break; - - if (checkModifierStateAny(kMaskLeftControl|kMaskRightControl)) - { - // Shift is ignored from this point onwards - if (checkModifierStateAny(kMaskLeftAlt|kMaskRightAlt)) - { - // Ctrl+Alt+PrntScr - IOLog("VoodooPS2Keyboard: Sending RESET signal to touchpad."); // Dont wrap into a DEBUG compilation condition since this should be a workaroung to be used on faulty states only - int val = 1; - _device->dispatchMessage(kPS2M_resetTouchpad, &val); // Reset touchpad - } - } - else - { - if (checkModifierState(kMaskLeftShift) || checkModifierState(kMaskRightShift)) - { - // Shift+PrntScr, no other modifiers present -#ifdef DEBUG - IOLog("VoodooPS2Keyboard: Sending SysRq virtual scancode 0x58"); -#endif - dispatchKeyboardEventX(0x58, true, now_abs); // Send SysRq to the kernel - dispatchKeyboardEventX(0x58, false, now_abs); - } - else - { - if (checkModifierStateAny(kMaskRightShift|kMaskLeftShift|kMaskRightAlt|kMaskLeftAlt)) - break; // Eat combinations where Ctrl is Up and Alt or Shift are Down (!Ctrl+[Alt|Shift]) - - bool enabled; - if (checkModifierStateAny(kMaskLeftWindows|kMaskRightWindows)) - { - // Windows+PrntScr - // Disable keyboard input along with the touchpad using Windows(Option)+prtsc, useful for 2-in-1 applications. -#ifdef DEBUG - IOLog("VoodooPS2Keyboard: Toggling keyboard+Touchpad enabled state."); -#endif - enabled = _disableInput; - _disableInput = !_disableInput; - _device->dispatchMessage(kPS2M_setDisableTouchpad, &enabled); // Sync Keyboard and Touchpad enabled states - } - else - { - // No other modifiers pressed down -#ifdef DEBUG - IOLog("VoodooPS2Keyboard: Toggling Touchpad enabled state."); -#endif - // Touchpad enable/disable: get current enabled status, and toggle it - _device->dispatchMessage(kPS2M_getDisableTouchpad, &enabled); - enabled = !enabled; - _device->dispatchMessage(kPS2M_setDisableTouchpad, &enabled); - } - } - - break; - } - - if (origKeyCode != 0x0137) - break; // do not fall through for 0x0128 - // fall through - } - case 0x0127: // alternate for fnkeys toggle (discrete fnkeys toggle) - keyCode = 0; - if (!goingDown) - break; - if (_fkeymodesupported) - { - // modify HIDFKeyMode via IOService... IOHIDSystem - if (IOService* service = IOService::waitForMatchingService(serviceMatching(kIOHIDSystem), 0)) - { - const OSObject* num = OSNumber::withNumber(!_fkeymode, 32); - const OSString* key = OSString::withCString(kHIDFKeyMode); - if (num && key) - { - if (OSDictionary* dict = OSDictionary::withObjects(&num, &key, 1)) - { - service->setProperties(dict); - dict->release(); - } - } - OSSafeReleaseNULL(num); - OSSafeReleaseNULL(key); - service->release(); - } - } - break; -#ifdef DEBUG - default: - IOLog("VoodooPS2Keyboard: Unhandled keycode: %#.4X\n", keyCode); -#endif } // If keyboard input is disabled drop the key code.. if (_disableInput && goingDown) keyCode=0; -#ifdef DEBUG - // allow hold Alt+numpad keys to type in arbitrary ADB key code - static int genADB = -1; - if (goingDown && checkModifierState(kMaskLeftAlt) && - ((keyCodeRaw >= 0x47 && keyCodeRaw <= 0x52 && keyCodeRaw != 0x4e && keyCodeRaw != 0x4a) || - (keyCodeRaw >= 0x02 && keyCodeRaw <= 0x0B))) - { - // map numpad scan codes to digits - static int map1[0x52-0x47+1] = { 7, 8, 9, -1, 4, 5, 6, -1, 1, 2, 3, 0 }; - static int map2[0x0B-0x02+1] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 0 }; - if (-1 == genADB) - genADB = 0; - int digit = keyCodeRaw >= 0x47 ? map1[keyCodeRaw-0x47] : map2[keyCodeRaw-0x02]; - if (-1 != digit) - genADB = genADB * 10 + digit; - DEBUG_LOG("%s: genADB = %d\n", getName(), genADB); - keyCode = 0; // eat it - } -#endif - // We have a valid key event -- dispatch it to our superclass. // map scan code to Apple code - UInt8 adbKeyCode = _PS2ToADBMap[keyCode]; - bool eatKey = false; + const VoodooPS2HidElement &hidKeyCode = _PS2ToHIDMap[keyCode]; +// bool eatKey = false; // special cases - switch (adbKeyCode) - { - case 0x92: // eject - if (0 == _PS2modifierState) + if (hidKeyCode.usage == kHIDUsage_Csmr_Eject && hidKeyCode.usagePage == kHIDPage_Consumer) { + if (0 == _PS2modifierState) + { + if (goingDown) { - if (goingDown) - { - eatKey = true; - _timerFunc = kTimerEject; - if (!_f12ejectdelay) - onSleepEjectTimer(); - else - setTimerTimeout(_sleepEjectTimer, (uint64_t)_f12ejectdelay * 1000000); - } +// eatKey = true; + _timerFunc = kTimerEject; + if (!_f12ejectdelay) + onSleepEjectTimer(); else - { - cancelTimer(_sleepEjectTimer); - } + setTimerTimeout(_sleepEjectTimer, (uint64_t)_f12ejectdelay * 1000000); } - break; + else + { + cancelTimer(_sleepEjectTimer); + } + } } - -#ifdef DEBUG_VERBOSE - if (adbKeyCode == DEADKEY && 0 != keyCode) - DEBUG_LOG("%s: Unknown ADB key for PS2 scancode: 0x%x\n", getName(), scanCode); - else - DEBUG_LOG("%s: ADB key code 0x%x %s\n", getName(), adbKeyCode, goingDown?"down":"up"); -#endif -#ifdef DEBUG_LITE - int logscancodes = 2; -#else - int logscancodes = _logscancodes; +#ifdef DEBUG + uint16_t debugCode = keyCode > KBV_NUM_SCANCODES ? (keyCode & 0xFF) | 0xe000 : keyCode; + IOLog("%s: Sending key %x = Page %x Usage %x %s\n", getName(), debugCode, hidKeyCode.usagePage, hidKeyCode.usage, goingDown ? "down" : "up"); #endif - if (logscancodes==2 || (logscancodes==1 && goingDown)) - { - if (keyCode == keyCodeRaw) - IOLog("%s: sending key %x=%x %s\n", getName(), keyCode > KBV_NUM_SCANCODES ? (keyCode & 0xFF) | 0xe000 : keyCode, adbKeyCode, goingDown?"down":"up"); - else - IOLog("%s: sending key %x=%x, %x=%x %s\n", getName(), keyCodeRaw > KBV_NUM_SCANCODES ? (keyCodeRaw & 0xFF) | 0xe000 : keyCodeRaw, keyCode > KBV_NUM_SCANCODES ? (keyCode & 0xFF) | 0xe000 : keyCode, keyCode > KBV_NUM_SCANCODES ? (keyCode & 0xFF) | 0xe000 : keyCode, adbKeyCode, goingDown?"down":"up"); - } // allow mouse/trackpad driver to have time of last keyboard activity // used to implement "PalmNoAction When Typing" and "OutsizeZoneNoAction When Typing" - PS2KeyInfo info; - info.time = now_ns; - info.adbKeyCode = adbKeyCode; - info.goingDown = goingDown; - info.eatKey = eatKey; - - _device->dispatchMessage(kPS2M_notifyKeyPressed, &info); +// PS2KeyInfo info; +// info.time = now_ns; +// info.adbKeyCode = hidKeyCode.usage; +// info.goingDown = goingDown; +// info.eatKey = eatKey; +// +// _device->dispatchMessage(kPS2M_notifyKeyPressed, &info); - //REVIEW: work around for caps lock bug on Sierra 10.12... - if (adbKeyCode == 0x39 && version_major >= 16) - { - // Mojave 10.14 only needs a part of the workaround: - // https://github.com/RehabMan/OS-X-Voodoo-PS2-Controller/issues/142#issuecomment-529813842 - if (goingDown || version_major >= 18) - { - DEBUG_LOG("%s: Caps Lock goingDown: 0x%x\n", getName(), goingDown); - _ignoreCapsLedChange = true; - clock_get_uptime(&now_abs); - dispatchKeyboardEventX(adbKeyCode, true, now_abs); - clock_get_uptime(&now_abs); - dispatchKeyboardEventX(adbKeyCode, false, now_abs); - } - if (goingDown && version_major < 18) { - static bool firsttime = true; - if (!firsttime) - { - clock_get_uptime(&now_abs); - dispatchKeyboardEventX(adbKeyCode, true, now_abs); - clock_get_uptime(&now_abs); - dispatchKeyboardEventX(adbKeyCode, false, now_abs); - } - firsttime = false; + // Convert ALT + Brightness to Keyboard Brightness + if (hidKeyCode.usagePage == kHIDPage_AppleVendorTopCase && checkModifierState(kMaskLeftAlt)) { + // Release left alt before sending brightness keys. macOS otherwise ignores the keypress + VoodooPS2HidElement altElem = _PS2ToHIDMap[0x38]; + dispatchKeyboardEventX(altElem, false, now_abs); + + if (hidKeyCode.usage == kHIDUsage_AV_TopCase_BrightnessUp) { + dispatchKeyboardEventX(kHIDPage_AppleVendorTopCase, kHIDUsage_AV_TopCase_IlluminationUp, goingDown, now_abs); + dispatchKeyboardEventX(altElem, true, now_abs); + return true; + } else if (hidKeyCode.usage == kHIDUsage_AV_TopCase_BrightnessDown) { + dispatchKeyboardEventX(kHIDPage_AppleVendorTopCase, kHIDUsage_AV_TopCase_IlluminationDown, goingDown, now_abs); + dispatchKeyboardEventX(altElem, true, now_abs); + return true; } - return true; } - - if (keyCode && !info.eatKey) + + if (hidKeyCode.usage != 0 && hidKeyCode.usagePage != 0) { // dispatch to HID system if (goingDown || !(_PS2flags[keyCodeRaw] & kBreaklessKey)) - dispatchKeyboardEventX(adbKeyCode, goingDown, now_abs); + dispatchKeyboardEventX(hidKeyCode, goingDown, now_abs); if (goingDown && (_PS2flags[keyCodeRaw] & kBreaklessKey)) - dispatchKeyboardEventX(adbKeyCode, false, now_abs); + dispatchKeyboardEventX(hidKeyCode, false, now_abs); } - -#ifdef DEBUG - if (0x38 == keyCode && !goingDown && -1 != genADB) // Alt going up - { - // dispatch typed adb code - dispatchKeyboardEventX(genADB, true, now_abs); - dispatchKeyboardEventX(genADB, false, now_abs); - DEBUG_LOG("%s: sending typed ADB code 0x%x\n", getName(), genADB); - genADB = -1; - } -#endif return true; } @@ -1892,18 +1072,14 @@ void ApplePS2Keyboard::setLEDs(UInt8 ledState) // It is safe to issue this request from the interrupt/completion context. // - PS2Request* request = _device->allocateRequest(4); + PS2Request* request = _device->allocateRequest(2); // (set LEDs command) - request->commands[0].command = kPS2C_WriteDataPort; + request->commands[0].command = kPS2C_SendCommandAndCompareAck; request->commands[0].inOrOut = kDP_SetKeyboardLEDs; - request->commands[1].command = kPS2C_ReadDataPortAndCompare; - request->commands[1].inOrOut = kSC_Acknowledge; - request->commands[2].command = kPS2C_WriteDataPort; - request->commands[2].inOrOut = ledState; - request->commands[3].command = kPS2C_ReadDataPortAndCompare; - request->commands[3].inOrOut = kSC_Acknowledge; - request->commandsCount = 4; + request->commands[1].command = kPS2C_SendCommandAndCompareAck; + request->commands[1].inOrOut = ledState; + request->commandsCount = 2; _device->submitRequest(request); } @@ -1921,270 +1097,16 @@ void ApplePS2Keyboard::setKeyboardEnable(bool enable) // // (keyboard enable/disable command) - TPS2Request<2> request; - request.commands[0].command = kPS2C_WriteDataPort; + TPS2Request<1> request; + request.commands[0].command = kPS2C_SendCommandAndCompareAck; request.commands[0].inOrOut = enable ? kDP_Enable : kDP_SetDefaults; - request.commands[1].command = kPS2C_ReadDataPortAndCompare; - request.commands[1].inOrOut = kSC_Acknowledge; - request.commandsCount = 2; + request.commandsCount = 1; assert(request.commandsCount <= countof(request.commands)); _device->submitRequestAndBlock(&request); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -const unsigned char * ApplePS2Keyboard::defaultKeymapOfLength(UInt32 * length) -{ - // - // Keymap data borrowed and modified from IOHIDFamily/IOHIDKeyboard.cpp - // references http://www.xfree.org/current/dumpkeymap.1.html - // http://www.tamasoft.co.jp/en/general-info/unicode.html - // - static const unsigned char appleUSAKeyMap[] = { - 0x00,0x00, // use byte unit. - - - // modifier definition - 0x0b, //Number of modifier keys. - // ( modifier , num of keys, ADB keycodes... ) - // ( 0x00 , 0x01 , 0x39 ) - //0x00,0x01,0x39, //NX_MODIFIERKEY_ALPHALOCK, uses one byte, ADB keycode is 0x39 - //13,0x01,0x39,//NX_MODIFIERKEY_ALPHALOCK_STATELESS - NX_MODIFIERKEY_SHIFT, 0x01,0x38, - NX_MODIFIERKEY_CONTROL, 0x01,0x3b, - NX_MODIFIERKEY_ALTERNATE, 0x01,0x3a, - NX_MODIFIERKEY_COMMAND, 0x01,0x37, - NX_MODIFIERKEY_NUMERICPAD, 0x15,0x52,0x41,0x4c,0x53,0x54,0x55,0x45,0x58,0x57,0x56,0x5b,0x5c,0x43,0x4b,0x51,0x7b,0x7d,0x7e,0x7c,0x4e,0x59, - NX_MODIFIERKEY_HELP, 0x01,0x72, - NX_MODIFIERKEY_SECONDARYFN, 0x01,0x3f, // Apple's Fn key - NX_MODIFIERKEY_RSHIFT, 0x01,0x3c, - NX_MODIFIERKEY_RCONTROL, 0x01,0x3e, - NX_MODIFIERKEY_RALTERNATE, 0x01,0x3d, - NX_MODIFIERKEY_RCOMMAND, 0x01,0x36, - - - // ADB virtual key definitions - 0xa2, // number of key definitions - // ( modifier mask , generated character{char_set,char_code}... ) - // ( 0x0d[has 3bit modifiers], {0x00,0x3c}, {0x00,0x3e}, ... total 2^3 characters ) - 0x0d,0x00,0x61,0x00,0x41,0x00,0x01,0x00,0x01,0x00,0xca,0x00,0xc7,0x00,0x01,0x00,0x01, //00 A - 0x0d,0x00,0x73,0x00,0x53,0x00,0x13,0x00,0x13,0x00,0xfb,0x00,0xa7,0x00,0x13,0x00,0x13, //01 S - 0x0d,0x00,0x64,0x00,0x44,0x00,0x04,0x00,0x04,0x01,0x44,0x01,0xb6,0x00,0x04,0x00,0x04, //02 D - 0x0d,0x00,0x66,0x00,0x46,0x00,0x06,0x00,0x06,0x00,0xa6,0x01,0xac,0x00,0x06,0x00,0x06, //03 F - 0x0d,0x00,0x68,0x00,0x48,0x00,0x08,0x00,0x08,0x00,0xe3,0x00,0xeb,0x00,0x00,0x18,0x00, //04 H - 0x0d,0x00,0x67,0x00,0x47,0x00,0x07,0x00,0x07,0x00,0xf1,0x00,0xe1,0x00,0x07,0x00,0x07, //05 G - 0x0d,0x00,0x7a,0x00,0x5a,0x00,0x1a,0x00,0x1a,0x00,0xcf,0x01,0x57,0x00,0x1a,0x00,0x1a, //06 Z - 0x0d,0x00,0x78,0x00,0x58,0x00,0x18,0x00,0x18,0x01,0xb4,0x01,0xce,0x00,0x18,0x00,0x18, //07 X - 0x0d,0x00,0x63,0x00,0x43,0x00,0x03,0x00,0x03,0x01,0xe3,0x01,0xd3,0x00,0x03,0x00,0x03, //08 C - 0x0d,0x00,0x76,0x00,0x56,0x00,0x16,0x00,0x16,0x01,0xd6,0x01,0xe0,0x00,0x16,0x00,0x16, //09 V - 0x02,0x00,0x3c,0x00,0x3e, //0a NON-US-BACKSLASH on ANSI and JIS keyboards GRAVE on ISO - 0x0d,0x00,0x62,0x00,0x42,0x00,0x02,0x00,0x02,0x01,0xe5,0x01,0xf2,0x00,0x02,0x00,0x02, //0b B - 0x0d,0x00,0x71,0x00,0x51,0x00,0x11,0x00,0x11,0x00,0xfa,0x00,0xea,0x00,0x11,0x00,0x11, //0c Q - 0x0d,0x00,0x77,0x00,0x57,0x00,0x17,0x00,0x17,0x01,0xc8,0x01,0xc7,0x00,0x17,0x00,0x17, //0d W - 0x0d,0x00,0x65,0x00,0x45,0x00,0x05,0x00,0x05,0x00,0xc2,0x00,0xc5,0x00,0x05,0x00,0x05, //0e E - 0x0d,0x00,0x72,0x00,0x52,0x00,0x12,0x00,0x12,0x01,0xe2,0x01,0xd2,0x00,0x12,0x00,0x12, //0f R - 0x0d,0x00,0x79,0x00,0x59,0x00,0x19,0x00,0x19,0x00,0xa5,0x01,0xdb,0x00,0x19,0x00,0x19, //10 Y - 0x0d,0x00,0x74,0x00,0x54,0x00,0x14,0x00,0x14,0x01,0xe4,0x01,0xd4,0x00,0x14,0x00,0x14, //11 T - 0x0a,0x00,0x31,0x00,0x21,0x01,0xad,0x00,0xa1, //12 1 - 0x0e,0x00,0x32,0x00,0x40,0x00,0x32,0x00,0x00,0x00,0xb2,0x00,0xb3,0x00,0x00,0x00,0x00, //13 2 - 0x0a,0x00,0x33,0x00,0x23,0x00,0xa3,0x01,0xba, //14 3 - 0x0a,0x00,0x34,0x00,0x24,0x00,0xa2,0x00,0xa8, //15 4 - 0x0e,0x00,0x36,0x00,0x5e,0x00,0x36,0x00,0x1e,0x00,0xb6,0x00,0xc3,0x00,0x1e,0x00,0x1e, //16 6 - 0x0a,0x00,0x35,0x00,0x25,0x01,0xa5,0x00,0xbd, //17 5 - 0x0a,0x00,0x3d,0x00,0x2b,0x01,0xb9,0x01,0xb1, //18 EQUALS - 0x0a,0x00,0x39,0x00,0x28,0x00,0xac,0x00,0xab, //19 9 - 0x0a,0x00,0x37,0x00,0x26,0x01,0xb0,0x01,0xab, //1a 7 - 0x0e,0x00,0x2d,0x00,0x5f,0x00,0x1f,0x00,0x1f,0x00,0xb1,0x00,0xd0,0x00,0x1f,0x00,0x1f, //1b MINUS - 0x0a,0x00,0x38,0x00,0x2a,0x00,0xb7,0x00,0xb4, //1c 8 - 0x0a,0x00,0x30,0x00,0x29,0x00,0xad,0x00,0xbb, //1d 0 - 0x0e,0x00,0x5d,0x00,0x7d,0x00,0x1d,0x00,0x1d,0x00,0x27,0x00,0xba,0x00,0x1d,0x00,0x1d, //1e RIGHTBRACKET - 0x0d,0x00,0x6f,0x00,0x4f,0x00,0x0f,0x00,0x0f,0x00,0xf9,0x00,0xe9,0x00,0x0f,0x00,0x0f, //1f O - 0x0d,0x00,0x75,0x00,0x55,0x00,0x15,0x00,0x15,0x00,0xc8,0x00,0xcd,0x00,0x15,0x00,0x15, //20 U - 0x0e,0x00,0x5b,0x00,0x7b,0x00,0x1b,0x00,0x1b,0x00,0x60,0x00,0xaa,0x00,0x1b,0x00,0x1b, //21 LEFTBRACKET - 0x0d,0x00,0x69,0x00,0x49,0x00,0x09,0x00,0x09,0x00,0xc1,0x00,0xf5,0x00,0x09,0x00,0x09, //22 I - 0x0d,0x00,0x70,0x00,0x50,0x00,0x10,0x00,0x10,0x01,0x70,0x01,0x50,0x00,0x10,0x00,0x10, //23 P - 0x10,0x00,0x0d,0x00,0x03, //24 RETURN - 0x0d,0x00,0x6c,0x00,0x4c,0x00,0x0c,0x00,0x0c,0x00,0xf8,0x00,0xe8,0x00,0x0c,0x00,0x0c, //25 L - 0x0d,0x00,0x6a,0x00,0x4a,0x00,0x0a,0x00,0x0a,0x00,0xc6,0x00,0xae,0x00,0x0a,0x00,0x0a, //26 J - 0x0a,0x00,0x27,0x00,0x22,0x00,0xa9,0x01,0xae, //27 APOSTROPHE - 0x0d,0x00,0x6b,0x00,0x4b,0x00,0x0b,0x00,0x0b,0x00,0xce,0x00,0xaf,0x00,0x0b,0x00,0x0b, //28 K - 0x0a,0x00,0x3b,0x00,0x3a,0x01,0xb2,0x01,0xa2, //29 SEMICOLON - 0x0e,0x00,0x5c,0x00,0x7c,0x00,0x1c,0x00,0x1c,0x00,0xe3,0x00,0xeb,0x00,0x1c,0x00,0x1c, //2a BACKSLASH - 0x0a,0x00,0x2c,0x00,0x3c,0x00,0xcb,0x01,0xa3, //2b COMMA - 0x0a,0x00,0x2f,0x00,0x3f,0x01,0xb8,0x00,0xbf, //2c SLASH - 0x0d,0x00,0x6e,0x00,0x4e,0x00,0x0e,0x00,0x0e,0x00,0xc4,0x01,0xaf,0x00,0x0e,0x00,0x0e, //2d N - 0x0d,0x00,0x6d,0x00,0x4d,0x00,0x0d,0x00,0x0d,0x01,0x6d,0x01,0xd8,0x00,0x0d,0x00,0x0d, //2e M - 0x0a,0x00,0x2e,0x00,0x3e,0x00,0xbc,0x01,0xb3, //2f PERIOD - 0x02,0x00,0x09,0x00,0x19, //30 TAB - 0x0c,0x00,0x20,0x00,0x00,0x00,0x80,0x00,0x00, //31 SPACE - 0x0a,0x00,0x60,0x00,0x7e,0x00,0x60,0x01,0xbb, //32 GRAVE on ANSI and JIS keyboards, NON-US-BACKSLASH on ISO - 0x02,0x00,0x7f,0x00,0x08, //33 BACKSPACE - 0xff, //34 PLAY/PAUSE - 0x02,0x00,0x1b,0x00,0x7e, //35 ESCAPE - 0xff, //36 RGUI - 0xff, //37 LGUI - 0xff, //38 LSHIFT - 0xff, //39 CAPSLOCK - 0xff, //3a LALT - 0xff, //3b LCTRL - 0xff, //3c RSHIFT - 0xff, //3d RALT - 0xff, //3e RCTRL - 0xff, //3f Apple Fn key - 0x00,0xfe,0x36, //40 F17 - 0x00,0x00,0x2e, //41 KEYPAD_PERIOD - 0xff, //42 NEXT TRACK or FAST - 0x00,0x00,0x2a, //43 KEYPAD_MULTIPLY - 0xff, //44 - 0x00,0x00,0x2b, //45 KEYPAD_PLUS - 0xff, //46 - 0x00,0x00,0x1b, //47 CLEAR - 0xff, //48 VOLUME UP - 0xff, //49 VOLUME DOWN - 0xff, //4a MUTE - 0x0e,0x00,0x2f,0x00,0x5c,0x00,0x2f,0x00,0x1c,0x00,0x2f,0x00,0x5c,0x00,0x00,0x0a,0x00, //4b KEYPAD_DIVIDE - 0x00,0x00,0x0d, //4c Apple Fn + Return = ENTER //XX03 - 0xff, //4d PREVIOUS TRACK or REWIND - 0x00,0x00,0x2d, //4e KEYPAD_MINUS - 0x00,0xfe,0x37, //4f F18 - 0x00,0xfe,0x38, //50 F19 - 0x0e,0x00,0x3d,0x00,0x7c,0x00,0x3d,0x00,0x1c,0x00,0x3d,0x00,0x7c,0x00,0x00,0x18,0x46, //51 KEYPAD_EQUALS - 0x00,0x00,0x30, //52 KEYPAD_0 - 0x00,0x00,0x31, //53 KEYPAD_1 - 0x00,0x00,0x32, //54 KEYPAD_2 - 0x00,0x00,0x33, //55 KEYPAD_3 - 0x00,0x00,0x34, //56 KEYPAD_4 - 0x00,0x00,0x35, //57 KEYPAD_5 - 0x00,0x00,0x36, //58 KEYPAD_6 - 0x00,0x00,0x37, //59 KEYPAD_7 - 0x00,0xfe,0x39, //5a F20 - 0x00,0x00,0x38, //5b KEYPAD_8 - 0x00,0x00,0x39, //5c KEYPAD_9 - 0xff, //0x02,0x00,0xa5,0x00,0x7c, //5d JIS JAPANESE YEN - 0xff, //0x00,0x00,0x5f, //5e JIS JAPANESE RO - 0xff, //0x00,0x00,0x2c, //5f KEYPAD_COMMA, JIS only - 0x00,0xfe,0x24, //60 F5 - 0x00,0xfe,0x25, //61 F6 - 0x00,0xfe,0x26, //62 F7 - 0x00,0xfe,0x22, //63 F3 - 0x00,0xfe,0x27, //64 F8 - 0x00,0xfe,0x28, //65 F9 - 0xff, //66 JIS JAPANESE EISU, KOREAN HANJA - 0x00,0xfe,0x2a, //67 F11 - 0xff, //68 JIS JAPANESE KANA, KOREAN HANGUL - 0x00,0xfe,0x32, //69 F13 - 0x00,0xfe,0x35, //6a F16 - 0x00,0xfe,0x33, //6b F14 - 0xff, //6c - 0x00,0xfe,0x29, //6d F10 - 0xff, //6e - 0x00,0xfe,0x2b, //6f F12 - 0xff, //70 - 0x00,0xfe,0x34, //71 F15 - 0xff, //72 HELP - 0x00,0xfe,0x2e, //73 HOME - 0x00,0xfe,0x30, //74 PAGEUP - 0x00,0xfe,0x2d, //75 DELETE - 0x00,0xfe,0x23, //76 F4 - 0x00,0xfe,0x2f, //77 END - 0x00,0xfe,0x21, //78 F2 - 0x00,0xfe,0x31, //79 PAGEDOWN - 0x00,0xfe,0x20, //7a F1 - 0x00,0x01,0xac, //7b LEFT ARROW - 0x00,0x01,0xae, //7c RIGHT ARROW - 0x00,0x01,0xaf, //7d DOWN ARROW - 0x00,0x01,0xad, //7e UP ARROW - 0x00,0x00,0x00, //7f POWER - 0x00,0x00,0x00, - 0x00,0x00,0x00, //81 Spotlight - 0x00,0x00,0x00, //82 Dashboard - 0x00,0x00,0x00, //83 Launchpad - 0x00,0x00,0x00, - 0x00,0x00,0x00, - 0x00,0x00,0x00, - 0x00,0x00,0x00, - 0x00,0x00,0x00, - 0x00,0x00,0x00, - 0x00,0x00,0x00, - 0x00,0x00,0x00, - 0x00,0x00,0x00, - 0x00,0x00,0x00, - 0x00,0x00,0x00, - 0x00,0x00,0x00, - 0x00,0x00,0x00, //90 Main Brightness Up - 0x00,0x00,0x00, //91 Main Brightness Down - 0x00,0x00,0x00, - 0x00,0x00,0x00, - 0x00,0x00,0x00, - 0x00,0x00,0x00, - 0x00,0x00,0x00, - 0x00,0x00,0x00, - 0x00,0x00,0x00, - 0x00,0x00,0x00, - 0x00,0x00,0x00, - 0x00,0x00,0x00, - 0x00,0x00,0x00, - 0x00,0x00,0x00, - 0x00,0x00,0x00, - 0x00,0x00,0x00, - 0x00,0x00,0x00, // a0 Exposes All - 0x00,0x00,0x00, // a1 Expose Desktop - - - // key sequence definition - // I tested some key sequence "Command + Shift + '['", but it doesn't work well. - // No one sequence was used on key deff table now. - 0x11, // number of of sequence definitions - // ( num of keys, generated sequence characters(char_set,char_code)... ) - // ( 0x02 , {0xff,0x04}, {0x00,0x31}, ) - 0x02,0xff,0x04,0x00,0x31, // Command + '1' - 0x02,0xff,0x04,0x00,0x32, // Command + '2' - 0x02,0xff,0x04,0x00,0x33, // Command + '3' - 0x02,0xff,0x04,0x00,0x34, // Command + '4' - 0x02,0xff,0x04,0x00,0x35, // Command + '5' - 0x02,0xff,0x04,0x00,0x36, // Command + '6' - 0x02,0xff,0x04,0x00,0x37, // Command + '7' - 0x02,0xff,0x04,0x00,0x38, // Command + '8' - 0x02,0xff,0x04,0x00,0x39, // Command + '9' - 0x02,0xff,0x04,0x00,0x30, // Command + '0' - 0x02,0xff,0x04,0x00,0x2d, // Command + '-' - 0x02,0xff,0x04,0x00,0x3d, // Command + '=' - 0x02,0xff,0x04,0x00,0x70, // Command + 'p' - 0x02,0xff,0x04,0x00,0x5d, // Command + ']' - 0x02,0xff,0x04,0x00,0x5b, // Command + '[' - 0x03,0xff,0x04,0xff,0x01,0x00,0x5b, // Command + Shift + '[' - 0x03,0xff,0x04,0xff,0x01,0x00,0x5d, // Command + shift + ']' - - - // special key definition - 0x0e, // number of special keys - // ( NX_KEYTYPE, Virtual ADB code ) - NX_KEYTYPE_CAPS_LOCK, 0x39, - NX_KEYTYPE_HELP, 0x72, - NX_POWER_KEY, 0x7f, - NX_KEYTYPE_MUTE, 0x4a, - NX_KEYTYPE_SOUND_UP, 0x48, - NX_KEYTYPE_SOUND_DOWN, 0x49, - // remove arrow keys as special keys. They are generating double up/down scroll events - // in both carbon and coco apps. - //NX_UP_ARROW_KEY, 0x7e, // ADB is 3e raw, 7e virtual (KMAP) - //NX_DOWN_ARROW_KEY, 0x7d, // ADB is 0x3d raw, 7d virtual - NX_KEYTYPE_NUM_LOCK, 0x47, // ADB combines with CLEAR key for numlock - NX_KEYTYPE_VIDMIRROR, 0x70, - NX_KEYTYPE_PLAY, 0x34, - NX_KEYTYPE_NEXT, 0x42, // if this event repeated, act as NX_KEYTYPE_FAST - NX_KEYTYPE_PREVIOUS, 0x4d, // if this event repeated, act as NX_KEYTYPE_REWIND - NX_KEYTYPE_BRIGHTNESS_UP, 0x90, - NX_KEYTYPE_BRIGHTNESS_DOWN, 0x91, - NX_KEYTYPE_EJECT, 0x92, - }; - - *length = sizeof(appleUSAKeyMap); - return appleUSAKeyMap; -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void ApplePS2Keyboard::setDevicePowerState( UInt32 whatToDo ) { switch ( whatToDo ) @@ -2213,12 +1135,10 @@ void ApplePS2Keyboard::initKeyboard() // Reset the keyboard to its default state. // - TPS2Request<2> request; - request.commands[0].command = kPS2C_WriteDataPort; + TPS2Request<1> request; + request.commands[0].command = kPS2C_SendCommandAndCompareAck; request.commands[0].inOrOut = kDP_SetDefaults; - request.commands[1].command = kPS2C_ReadDataPortAndCompare; - request.commands[1].inOrOut = kSC_Acknowledge; - request.commandsCount = 2; + request.commandsCount = 1; assert(request.commandsCount <= countof(request.commands)); _device->submitRequestAndBlock(&request); diff --git a/VoodooPS2Keyboard/VoodooPS2Keyboard.h b/VoodooPS2Keyboard/VoodooPS2Keyboard.h index 797120f9..d0dc226d 100644 --- a/VoodooPS2Keyboard/VoodooPS2Keyboard.h +++ b/VoodooPS2Keyboard/VoodooPS2Keyboard.h @@ -25,7 +25,8 @@ #include #include "../VoodooPS2Controller/ApplePS2KeyboardDevice.h" -#include +#include "VoodooPS2KeyboardHIDWrapper.hpp" +#include "ApplePS2ToHIDMap.h" #include @@ -68,9 +69,9 @@ #define kPacketTimeOffset 8 #define kPacketKeyDataLength 2 -class EXPORT ApplePS2Keyboard : public IOHIKeyboard +class EXPORT ApplePS2Keyboard : public IOService { - typedef IOHIKeyboard super; + typedef IOService super; OSDeclareDefaultStructors(ApplePS2Keyboard); private: @@ -86,16 +87,10 @@ class EXPORT ApplePS2Keyboard : public IOHIKeyboard // for keyboard remapping UInt16 _PS2modifierState; - UInt16 _PS2ToPS2Map[KBV_NUM_SCANCODES*2]; - UInt16 _PS2flags[KBV_NUM_SCANCODES*2]; - UInt8 _PS2ToADBMap[ADB_CONVERTER_LEN]; - UInt8 _PS2ToADBMapMapped[ADB_CONVERTER_LEN]; - UInt32 _fkeymode; - bool _fkeymodesupported; - OSArray* _keysStandard; - OSArray* _keysSpecial; + UInt16 _PS2ToPS2Map[KBV_NUM_SCANCODES]; + UInt16 _PS2flags[KBV_NUM_SCANCODES]; + VoodooPS2HidElement _PS2ToHIDMap[512]; bool _swapcommandoption; - int _logscancodes; UInt32 _f12ejectdelay; enum { kTimerSleep, kTimerEject } _timerFunc; bool _remapPrntScr; @@ -105,37 +100,21 @@ class EXPORT ApplePS2Keyboard : public IOHIKeyboard // dealing with sleep key delay IOTimerEventSource* _sleepEjectTimer; UInt32 _maxsleeppresstime; - - // ACPI support for keyboard backlight - IOACPIPlatformDevice * _provider; - int * _backlightLevels; - int _backlightCount; - - // special hack for Envy brightness access, while retaining F2/F3 functionality - bool _brightnessHack; // Toggle keyboard input along with touchpad when Windows+printscreen is pressed bool _disableInput; - // macro processing - OSData** _macroTranslation; - OSData** _macroInversion; - UInt8* _macroBuffer; - int _macroMax; - int _macroCurrent; - uint64_t _macroMaxTime; - IOTimerEventSource* _macroTimer; - // fix caps lock led bool _ignoreCapsLedChange; + + VoodooPS2KeyboardHIDWrapper *_hidWrapper {nullptr}; virtual bool dispatchKeyboardEventWithPacket(const UInt8* packet); virtual void setLEDs(UInt8 ledState); virtual void setKeyboardEnable(bool enable); virtual void initKeyboard(); virtual void setDevicePowerState(UInt32 whatToDo); - void modifyKeyboardBacklight(int adbKeyCode, bool goingDown); - void modifyScreenBrightness(int adbKeyCode, bool goingDown); + inline bool checkModifierState(UInt16 mask) { return mask == (_PS2modifierState & mask); } inline bool checkModifierStateAny(UInt16 mask) @@ -143,24 +122,18 @@ class EXPORT ApplePS2Keyboard : public IOHIKeyboard void loadCustomPS2Map(OSArray* pArray); void loadBreaklessPS2(OSDictionary* dict, const char* name); - void loadCustomADBMap(OSDictionary* dict, const char* name); + void loadCustomHIDMap(OSDictionary* dict, const char* name); void setParamPropertiesGated(OSDictionary* dict); void onSleepEjectTimer(void); - - static OSData** loadMacroData(OSDictionary* dict, const char* name); - static void freeMacroData(OSData** data); - void onMacroTimer(void); - bool invertMacros(const UInt8* packet); - void dispatchInvertBuffer(); - static bool compareMacro(const UInt8* packet, const UInt8* data, int count); protected: - const unsigned char * defaultKeymapOfLength(UInt32 * length) override; - void setAlphaLockFeedback(bool locked) override; - void setNumLockFeedback(bool locked) override; - UInt32 maxKeyCodes() override; - inline void dispatchKeyboardEventX(unsigned int keyCode, bool goingDown, uint64_t time) - { dispatchKeyboardEvent(keyCode, goingDown, *(AbsoluteTime*)&time); } + void setAlphaLockFeedback(bool locked); + void setNumLockFeedback(bool locked); + + inline void dispatchKeyboardEventX(const VoodooPS2HidElement &elem, bool goingDown, uint64_t time) + { dispatchKeyboardEventX(elem.usagePage, elem.usage, goingDown, time); } + inline void dispatchKeyboardEventX(uint16_t usagePage, uint32_t usage, bool goingDown, uint64_t time) + { if (_hidWrapper) _hidWrapper->dispatchKeyboardEvent(time, usagePage, usage, goingDown); } inline void setTimerTimeout(IOTimerEventSource* timer, uint64_t time) { timer->setTimeout(*(AbsoluteTime*)&time); } inline void cancelTimer(IOTimerEventSource* timer) @@ -176,10 +149,6 @@ class EXPORT ApplePS2Keyboard : public IOHIKeyboard virtual PS2InterruptResult interruptOccurred(UInt8 scanCode); virtual void packetReady(); - 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; diff --git a/VoodooPS2Keyboard/VoodooPS2KeyboardHIDWrapper.cpp b/VoodooPS2Keyboard/VoodooPS2KeyboardHIDWrapper.cpp new file mode 100644 index 00000000..e6b3c377 --- /dev/null +++ b/VoodooPS2Keyboard/VoodooPS2KeyboardHIDWrapper.cpp @@ -0,0 +1,134 @@ +// +// VoodooPS2KeyboardHIDWrapper.cpp +// VoodooPS2Keyboard +// +// Created by Gwydien on 8/28/23. +// Copyright © 2023 Acidanthera. All rights reserved. +// + +#include "VoodooPS2KeyboardHIDWrapper.hpp" +#include +#include + +OSDefineMetaClassAndStructors(VoodooPS2KeyboardHIDWrapper, IOHIDDevice); +OSDefineMetaClassAndStructors(VoodooPS2KeyboardHIDEventDriver, IOHIDEventService); + +static constexpr uint8_t ReportDescriptor[] = { + 0x05, 0x01, // Usage Page (Generic Desktop) + 0x09, 0x06, // USAGE (Keyboard) + 0xa1, 0x01, // COLLECTION (Application) + 0x85, 0x01, // REPORT_ID (Keyboard) + 0x05, 0x07, // USAGE_PAGE (Keyboard) + 0x19, 0xe0, // USAGE_MINIMUM (Keyboard LeftControl) + 0x29, 0xe7, // USAGE_MAXIMUM (Keyboard Right GUI) + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0x25, 0x01, // LOGICAL_MAXIMUM (1) + 0x75, 0x01, // REPORT_SIZE (1) + 0x95, 0x08, // REPORT_COUNT (8) + 0x81, 0x02, // INPUT (Data,Var,Abs) + 0x95, 0x01, // REPORT_COUNT (1) + 0x75, 0x08, // REPORT_SIZE (8) + 0x81, 0x03, // INPUT (Cnst,Var,Abs) + 0x95, 0x05, // REPORT_COUNT (5) + 0x75, 0x01, // REPORT_SIZE (1) + 0x05, 0x08, // USAGE_PAGE (LEDs) + 0x19, 0x01, // USAGE_MINIMUM (Num Lock) + 0x29, 0x05, // USAGE_MAXIMUM (Kana) + 0x91, 0x02, // OUTPUT (Data,Var,Abs) + 0x95, 0x01, // REPORT_COUNT (1) + 0x75, 0x03, // REPORT_SIZE (3) + 0x91, 0x03, // OUTPUT (Cnst,Var,Abs) + 0x95, 0x06, // REPORT_COUNT (6) + 0x75, 0x08, // REPORT_SIZE (8) + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0x25, 0x65, // LOGICAL_MAXIMUM (101) + 0x05, 0x07, // USAGE_PAGE (Keyboard) + 0x19, 0x00, // USAGE_MINIMUM (Reserved (no event indicated)) + 0x29, 0x65, // USAGE_MAXIMUM (Keyboard Application) + 0x81, 0x00, // INPUT (Data,Ary,Abs) + 0xc0, // END_COLLECTION +}; + +bool VoodooPS2KeyboardHIDWrapper::start(IOService *provider) { + setProperty(kIOHIDBuiltInKey, kOSBooleanTrue); + setProperty("HIDDefaultBehavior", kOSBooleanTrue); + setProperty("AppleVendorSupported", kOSBooleanTrue); + + registerService(); + if (!IOHIDDevice::start(provider)) return false; + + return true; +} + +void VoodooPS2KeyboardHIDWrapper::stop(IOService *provider) { + return IOHIDDevice::stop(provider); +} + +void VoodooPS2KeyboardHIDWrapper::dispatchKeyboardEvent(AbsoluteTime time, uint16_t usagePage, uint16_t usage, uint8_t value) { + if (eventDriver != nullptr) { + eventDriver->dispatchKeyboardEvent(time, usagePage, usage, value); + } +} + +bool VoodooPS2KeyboardHIDWrapper::handleOpen(IOService *forClient, IOOptionBits options, void *arg) { + VoodooPS2KeyboardHIDEventDriver *temp = OSDynamicCast(VoodooPS2KeyboardHIDEventDriver, forClient); + if (eventDriver == nullptr && temp != nullptr && IOHIDDevice::handleOpen(forClient, options, arg)) { + eventDriver = temp; + return true; + } + + return IOHIDDevice::handleOpen(forClient, options, arg); +} + +void VoodooPS2KeyboardHIDWrapper::handleClose(IOService *forClient, IOOptionBits options) { + if (forClient == eventDriver) { + eventDriver = nullptr; + } + + IOHIDDevice::handleClose(forClient, options); +} + +IOReturn VoodooPS2KeyboardHIDWrapper::newReportDescriptor(IOMemoryDescriptor **descriptor) const { + IOBufferMemoryDescriptor *buffer = IOBufferMemoryDescriptor::inTaskWithOptions(kernel_task, 0, sizeof(ReportDescriptor)); + + if (buffer == NULL) return kIOReturnNoResources; + buffer->writeBytes(0, ReportDescriptor, sizeof(ReportDescriptor)); + *descriptor = buffer; + + return kIOReturnSuccess; +} + +OSString* VoodooPS2KeyboardHIDWrapper::newManufacturerString() const { + return OSString::withCString("Acidanthera"); +} + +OSNumber* VoodooPS2KeyboardHIDWrapper::newPrimaryUsageNumber() const { + return OSNumber::withNumber(kHIDUsage_GD_Keyboard, 32); +} + +OSNumber* VoodooPS2KeyboardHIDWrapper::newPrimaryUsagePageNumber() const { + return OSNumber::withNumber(kHIDPage_GenericDesktop, 32); +} + +/* + * Apple vendor is needed for keyboard backlight filters to attach. + * To prevent Apple event drivers from attaching, use a bogus + * product ID. + */ + +OSNumber* VoodooPS2KeyboardHIDWrapper::newVendorIDNumber() const { + // Apple Vendor needed for + return OSNumber::withNumber(1452, 16); +} + +OSNumber* VoodooPS2KeyboardHIDWrapper::newProductIDNumber() const { + return OSNumber::withNumber(0x9999, 32); +} + +OSString* VoodooPS2KeyboardHIDWrapper::newProductString() const { + return OSString::withCString("PS2 Keyboard"); +} + +OSString* VoodooPS2KeyboardHIDWrapper::newTransportString() const { + return OSString::withCString("PS2"); +} diff --git a/VoodooPS2Keyboard/VoodooPS2KeyboardHIDWrapper.hpp b/VoodooPS2Keyboard/VoodooPS2KeyboardHIDWrapper.hpp new file mode 100644 index 00000000..9008013d --- /dev/null +++ b/VoodooPS2Keyboard/VoodooPS2KeyboardHIDWrapper.hpp @@ -0,0 +1,39 @@ +// +// VoodooPS2KeyboardHIDWrapper.hpp +// VoodooPS2Keyboard +// +// Created by Gwydien on 8/28/23. +// Copyright © 2023 Acidanthera. All rights reserved. +// + +#ifndef VoodooPS2KeyboardHIDWrapper_hpp +#define VoodooPS2KeyboardHIDWrapper_hpp + +#include +#include "VoodooPS2EventDriver.hpp" + +class VoodooPS2KeyboardHIDWrapper : public IOHIDDevice { + OSDeclareDefaultStructors(VoodooPS2KeyboardHIDWrapper); +public: + bool start(IOService *start) override; + void stop(IOService *start) override; + bool handleOpen(IOService *forClient, IOOptionBits options, void *arg) override; + void handleClose(IOService *forClient, IOOptionBits options) override; + + IOReturn newReportDescriptor(IOMemoryDescriptor **descriptor) const override; + + virtual OSString* newManufacturerString() const override; + virtual OSNumber* newPrimaryUsageNumber() const override; + virtual OSNumber* newPrimaryUsagePageNumber() const override; + virtual OSString* newProductString() const override; + virtual OSString* newTransportString() const override; + virtual OSNumber* newVendorIDNumber() const override; + virtual OSNumber* newProductIDNumber() const override; + + void dispatchKeyboardEvent(AbsoluteTime time, uint16_t usagePage, uint16_t usage, uint8_t value); + +private: + VoodooPS2KeyboardHIDEventDriver *eventDriver {nullptr}; +}; + +#endif /* VoodooPS2KeyboardHIDWrapper_hpp */ From 8e05d4f97bd0d3fa9066040c50a7ab99a0c60f65 Mon Sep 17 00:00:00 2001 From: Avery Black Date: Thu, 19 Oct 2023 22:59:51 -0700 Subject: [PATCH 091/101] Revert "HID VoodooPS2Keyboard" This reverts commit 50ae04a4ffef5434de693baf90d1476d62144519. --- VoodooPS2Controller.xcodeproj/project.pbxproj | 40 +- VoodooPS2Controller/VoodooPS2Controller.cpp | 4 +- ...{ApplePS2ToHIDMap.h => ApplePS2ToADBMap.h} | 766 +++++----- VoodooPS2Keyboard/VoodooPS2EventDriver.hpp | 31 - .../VoodooPS2Keyboard-Info.plist | 25 - VoodooPS2Keyboard/VoodooPS2Keyboard.cpp | 1348 +++++++++++++++-- VoodooPS2Keyboard/VoodooPS2Keyboard.h | 67 +- .../VoodooPS2KeyboardHIDWrapper.cpp | 134 -- .../VoodooPS2KeyboardHIDWrapper.hpp | 39 - 9 files changed, 1658 insertions(+), 796 deletions(-) rename VoodooPS2Keyboard/{ApplePS2ToHIDMap.h => ApplePS2ToADBMap.h} (53%) delete mode 100644 VoodooPS2Keyboard/VoodooPS2EventDriver.hpp delete mode 100644 VoodooPS2Keyboard/VoodooPS2KeyboardHIDWrapper.cpp delete mode 100644 VoodooPS2Keyboard/VoodooPS2KeyboardHIDWrapper.hpp diff --git a/VoodooPS2Controller.xcodeproj/project.pbxproj b/VoodooPS2Controller.xcodeproj/project.pbxproj index 324e275c..f0fdc456 100644 --- a/VoodooPS2Controller.xcodeproj/project.pbxproj +++ b/VoodooPS2Controller.xcodeproj/project.pbxproj @@ -19,7 +19,7 @@ 84833FA3161B627D00845294 /* ApplePS2Device.h in Headers */ = {isa = PBXBuildFile; fileRef = 84833F9D161B627D00845294 /* ApplePS2Device.h */; settings = {ATTRIBUTES = (); }; }; 84833FA5161B627D00845294 /* ApplePS2KeyboardDevice.h in Headers */ = {isa = PBXBuildFile; fileRef = 84833F9F161B627D00845294 /* ApplePS2KeyboardDevice.h */; settings = {ATTRIBUTES = (); }; }; 84833FA7161B627D00845294 /* ApplePS2MouseDevice.h in Headers */ = {isa = PBXBuildFile; fileRef = 84833FA1161B627D00845294 /* ApplePS2MouseDevice.h */; settings = {ATTRIBUTES = (); }; }; - 84833FAA161B629500845294 /* ApplePS2ToHIDMap.h in Headers */ = {isa = PBXBuildFile; fileRef = 84833FA9161B629500845294 /* ApplePS2ToHIDMap.h */; settings = {ATTRIBUTES = (); }; }; + 84833FAA161B629500845294 /* ApplePS2ToADBMap.h in Headers */ = {isa = PBXBuildFile; fileRef = 84833FA9161B629500845294 /* ApplePS2ToADBMap.h */; settings = {ATTRIBUTES = (); }; }; 84833FB1161B62A900845294 /* VoodooPS2ALPSGlidePoint.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 84833FAB161B62A900845294 /* VoodooPS2ALPSGlidePoint.cpp */; }; 84833FB2161B62A900845294 /* VoodooPS2ALPSGlidePoint.h in Headers */ = {isa = PBXBuildFile; fileRef = 84833FAC161B62A900845294 /* VoodooPS2ALPSGlidePoint.h */; settings = {ATTRIBUTES = (); }; }; 84833FB3161B62A900845294 /* VoodooPS2SentelicFSP.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 84833FAD161B62A900845294 /* VoodooPS2SentelicFSP.cpp */; }; @@ -39,9 +39,6 @@ CE8DA1C6251839B7008C44E8 /* libkmod.a in Frameworks */ = {isa = PBXBuildFile; fileRef = CE8DA1C4251839B2008C44E8 /* libkmod.a */; }; CE8DA1C7251839B9008C44E8 /* libkmod.a in Frameworks */ = {isa = PBXBuildFile; fileRef = CE8DA1C4251839B2008C44E8 /* libkmod.a */; }; CE8DA1CC251839BC008C44E8 /* libkmod.a in Frameworks */ = {isa = PBXBuildFile; fileRef = CE8DA1C4251839B2008C44E8 /* libkmod.a */; }; - EE4CEE1C2A9D85DA00314737 /* VoodooPS2KeyboardHIDWrapper.cpp in Sources */ = {isa = PBXBuildFile; fileRef = EE4CEE1A2A9D85DA00314737 /* VoodooPS2KeyboardHIDWrapper.cpp */; }; - EE4CEE1D2A9D85DA00314737 /* VoodooPS2KeyboardHIDWrapper.hpp in Headers */ = {isa = PBXBuildFile; fileRef = EE4CEE1B2A9D85DA00314737 /* VoodooPS2KeyboardHIDWrapper.hpp */; }; - EE4CEE252A9D8AF800314737 /* VoodooPS2EventDriver.hpp in Headers */ = {isa = PBXBuildFile; fileRef = EE4CEE232A9D8AF800314737 /* VoodooPS2EventDriver.hpp */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ @@ -103,7 +100,7 @@ 84833F9F161B627D00845294 /* ApplePS2KeyboardDevice.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ApplePS2KeyboardDevice.h; path = VoodooPS2Controller/ApplePS2KeyboardDevice.h; sourceTree = ""; }; 84833FA0161B627D00845294 /* ApplePS2MouseDevice.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ApplePS2MouseDevice.cpp; sourceTree = ""; }; 84833FA1161B627D00845294 /* ApplePS2MouseDevice.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ApplePS2MouseDevice.h; path = VoodooPS2Controller/ApplePS2MouseDevice.h; sourceTree = ""; }; - 84833FA9161B629500845294 /* ApplePS2ToHIDMap.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ApplePS2ToHIDMap.h; sourceTree = ""; }; + 84833FA9161B629500845294 /* ApplePS2ToADBMap.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ApplePS2ToADBMap.h; sourceTree = ""; }; 84833FAB161B62A900845294 /* VoodooPS2ALPSGlidePoint.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; lineEnding = 0; path = VoodooPS2ALPSGlidePoint.cpp; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.cpp; }; 84833FAC161B62A900845294 /* VoodooPS2ALPSGlidePoint.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = VoodooPS2ALPSGlidePoint.h; sourceTree = ""; }; 84833FAD161B62A900845294 /* VoodooPS2SentelicFSP.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; lineEnding = 0; path = VoodooPS2SentelicFSP.cpp; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.cpp; }; @@ -134,9 +131,6 @@ EDD95559208E2B640031D99E /* SSDT-Thinkpad_Clickpad.dsl */ = {isa = PBXFileReference; lastKnownFileType = text; path = "SSDT-Thinkpad_Clickpad.dsl"; sourceTree = ""; }; EDD9555A208E2E7A0031D99E /* SSDT-Thinkpad_Trackpad.dsl */ = {isa = PBXFileReference; lastKnownFileType = text; path = "SSDT-Thinkpad_Trackpad.dsl"; sourceTree = ""; }; EDD970FD1FD0B826004CCFFD /* SSDT-HP-FixLidSleep.dsl */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = "SSDT-HP-FixLidSleep.dsl"; sourceTree = ""; }; - EE4CEE1A2A9D85DA00314737 /* VoodooPS2KeyboardHIDWrapper.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = VoodooPS2KeyboardHIDWrapper.cpp; sourceTree = ""; }; - EE4CEE1B2A9D85DA00314737 /* VoodooPS2KeyboardHIDWrapper.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = VoodooPS2KeyboardHIDWrapper.hpp; sourceTree = ""; }; - EE4CEE232A9D8AF800314737 /* VoodooPS2EventDriver.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = VoodooPS2EventDriver.hpp; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -242,13 +236,10 @@ 8416782E161B5613002C60E6 /* VoodooPS2Keyboard */ = { isa = PBXGroup; children = ( - 84833FA9161B629500845294 /* ApplePS2ToHIDMap.h */, + 84833FA9161B629500845294 /* ApplePS2ToADBMap.h */, 84167834161B5613002C60E6 /* VoodooPS2Keyboard.h */, 84167835161B5613002C60E6 /* VoodooPS2Keyboard.cpp */, 8416782F161B5613002C60E6 /* Supporting Files */, - EE4CEE1A2A9D85DA00314737 /* VoodooPS2KeyboardHIDWrapper.cpp */, - EE4CEE1B2A9D85DA00314737 /* VoodooPS2KeyboardHIDWrapper.hpp */, - EE4CEE232A9D8AF800314737 /* VoodooPS2EventDriver.hpp */, ); path = VoodooPS2Keyboard; sourceTree = ""; @@ -382,10 +373,8 @@ isa = PBXHeadersBuildPhase; buildActionMask = 2147483647; files = ( - 84833FAA161B629500845294 /* ApplePS2ToHIDMap.h in Headers */, + 84833FAA161B629500845294 /* ApplePS2ToADBMap.h in Headers */, 84833FC2161B69C700845294 /* VoodooPS2Keyboard.h in Headers */, - EE4CEE1D2A9D85DA00314737 /* VoodooPS2KeyboardHIDWrapper.hpp in Headers */, - EE4CEE252A9D8AF800314737 /* VoodooPS2EventDriver.hpp in Headers */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -645,7 +634,6 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( - EE4CEE1C2A9D85DA00314737 /* VoodooPS2KeyboardHIDWrapper.cpp in Sources */, 84167836161B5613002C60E6 /* VoodooPS2Keyboard.cpp in Sources */, ); runOnlyForDeploymentPostprocessing = 0; @@ -777,7 +765,7 @@ KERNEL_FRAMEWORK_HEADERS = "$(PROJECT_DIR)/MacKernelSDK/Headers"; "LLVM_LTO[arch=x86_64]" = YES; MACOSX_DEPLOYMENT_TARGET = 10.11; - MODULE_VERSION = 3.0.0; + MODULE_VERSION = 2.3.6; ONLY_ACTIVE_ARCH = YES; "OTHER_LDFLAGS[arch=x86_64]" = "-dead_strip"; PRODUCT_NAME = VoodooPS2Controller; @@ -832,7 +820,7 @@ KERNEL_FRAMEWORK_HEADERS = "$(PROJECT_DIR)/MacKernelSDK/Headers"; "LLVM_LTO[arch=x86_64]" = YES; MACOSX_DEPLOYMENT_TARGET = 10.11; - MODULE_VERSION = 3.0.0; + MODULE_VERSION = 2.3.6; "OTHER_LDFLAGS[arch=x86_64]" = "-dead_strip"; PRODUCT_NAME = VoodooPS2Controller; SDKROOT = macosx; @@ -857,7 +845,7 @@ ); MODULE_NAME = as.acidanthera.driver.VoodooPS2Controller; OTHER_CFLAGS = "-fno-stack-protector"; - PRODUCT_BUNDLE_IDENTIFIER = com.1revenger1.PS2Controller; + PRODUCT_BUNDLE_IDENTIFIER = as.acidanthera.voodoo.driver.PS2Controller; PRODUCT_NAME = "$(TARGET_NAME)"; RUN_CLANG_STATIC_ANALYZER = YES; STRIP_INSTALLED_PRODUCT = YES; @@ -878,7 +866,7 @@ ); MODULE_NAME = as.acidanthera.driver.VoodooPS2Controller; OTHER_CFLAGS = "-fno-stack-protector"; - PRODUCT_BUNDLE_IDENTIFIER = com.1revenger1.PS2Controller; + PRODUCT_BUNDLE_IDENTIFIER = as.acidanthera.voodoo.driver.PS2Controller; PRODUCT_NAME = "$(TARGET_NAME)"; STRIP_INSTALLED_PRODUCT = YES; STRIP_STYLE = "non-global"; @@ -902,7 +890,7 @@ ); MODULE_NAME = as.acidanthera.driver.VoodooPS2Keyboard; OTHER_CFLAGS = "-fno-stack-protector"; - PRODUCT_BUNDLE_IDENTIFIER = com.1revenger1.PS2Keyboard; + PRODUCT_BUNDLE_IDENTIFIER = as.acidanthera.voodoo.driver.PS2Keyboard; PRODUCT_NAME = "$(TARGET_NAME)"; RUN_CLANG_STATIC_ANALYZER = YES; STRIP_INSTALLED_PRODUCT = YES; @@ -924,7 +912,7 @@ ); MODULE_NAME = as.acidanthera.driver.VoodooPS2Keyboard; OTHER_CFLAGS = "-fno-stack-protector"; - PRODUCT_BUNDLE_IDENTIFIER = com.1revenger1.PS2Keyboard; + PRODUCT_BUNDLE_IDENTIFIER = as.acidanthera.voodoo.driver.PS2Keyboard; PRODUCT_NAME = "$(TARGET_NAME)"; STRIP_INSTALLED_PRODUCT = YES; STRIP_STYLE = "non-global"; @@ -948,7 +936,7 @@ ); MODULE_NAME = as.acidanthera.driver.VoodooPS2Mouse; OTHER_CFLAGS = "-fno-stack-protector"; - PRODUCT_BUNDLE_IDENTIFIER = com.1revenger1.PS2Mouse; + PRODUCT_BUNDLE_IDENTIFIER = as.acidanthera.voodoo.driver.PS2Mouse; PRODUCT_NAME = "$(TARGET_NAME)"; RUN_CLANG_STATIC_ANALYZER = YES; STRIP_INSTALLED_PRODUCT = YES; @@ -970,7 +958,7 @@ ); MODULE_NAME = as.acidanthera.driver.VoodooPS2Mouse; OTHER_CFLAGS = "-fno-stack-protector"; - PRODUCT_BUNDLE_IDENTIFIER = com.1revenger1.PS2Mouse; + PRODUCT_BUNDLE_IDENTIFIER = as.acidanthera.voodoo.driver.PS2Mouse; PRODUCT_NAME = "$(TARGET_NAME)"; STRIP_INSTALLED_PRODUCT = YES; STRIP_STYLE = "non-global"; @@ -995,7 +983,7 @@ ); MODULE_NAME = as.acidanthera.driver.VoodooPS2Trackpad; OTHER_CFLAGS = "-fno-stack-protector"; - PRODUCT_BUNDLE_IDENTIFIER = com.1revenger1.PS2Trackpad; + PRODUCT_BUNDLE_IDENTIFIER = as.acidanthera.voodoo.driver.PS2Trackpad; PRODUCT_NAME = "$(TARGET_NAME)"; RUN_CLANG_STATIC_ANALYZER = YES; STRIP_INSTALLED_PRODUCT = YES; @@ -1018,7 +1006,7 @@ ); MODULE_NAME = as.acidanthera.driver.VoodooPS2Trackpad; OTHER_CFLAGS = "-fno-stack-protector"; - PRODUCT_BUNDLE_IDENTIFIER = com.1revenger1.PS2Trackpad; + PRODUCT_BUNDLE_IDENTIFIER = as.acidanthera.voodoo.driver.PS2Trackpad; PRODUCT_NAME = "$(TARGET_NAME)"; STRIP_INSTALLED_PRODUCT = YES; STRIP_STYLE = "non-global"; diff --git a/VoodooPS2Controller/VoodooPS2Controller.cpp b/VoodooPS2Controller/VoodooPS2Controller.cpp index 6194e90e..497b47bc 100644 --- a/VoodooPS2Controller/VoodooPS2Controller.cpp +++ b/VoodooPS2Controller/VoodooPS2Controller.cpp @@ -2126,7 +2126,7 @@ static OSString* getPlatformOverride(IORegistryEntry* reg, const char* sz) return NULL; } -static LIBKERN_RETURNS_RETAINED OSString* getPlatformManufacturer(IORegistryEntry* reg) +static OSString* getPlatformManufacturer(IORegistryEntry* reg) { // allow override in PS2K ACPI device OSString* id = getPlatformOverride(reg, "RM,oem-id"); @@ -2148,7 +2148,7 @@ static LIBKERN_RETURNS_RETAINED OSString* getPlatformManufacturer(IORegistryEntr return OSString::withCStringNoCopy(oemID); } -static LIBKERN_RETURNS_RETAINED OSString* getPlatformProduct(IORegistryEntry* reg) +static OSString* getPlatformProduct(IORegistryEntry* reg) { // allow override in PS2K ACPI device OSString* id = getPlatformOverride(reg, "RM,oem-table-id"); diff --git a/VoodooPS2Keyboard/ApplePS2ToHIDMap.h b/VoodooPS2Keyboard/ApplePS2ToADBMap.h similarity index 53% rename from VoodooPS2Keyboard/ApplePS2ToHIDMap.h rename to VoodooPS2Keyboard/ApplePS2ToADBMap.h index b2158217..022536ee 100644 --- a/VoodooPS2Keyboard/ApplePS2ToHIDMap.h +++ b/VoodooPS2Keyboard/ApplePS2ToADBMap.h @@ -23,119 +23,122 @@ #ifndef _APPLEPS2TOADBMAP_H #define _APPLEPS2TOADBMAP_H -#include -#include - #define PROBOOK -#define DEADKEY 0x00 -#define DEADKEY_EXTENDED { 0, 0 } +#define DEADKEY 0x80 -#define BRIGHTNESS_DOWN { kHIDPage_AppleVendorTopCase, kHIDUsage_AV_TopCase_BrightnessDown } -#define BRIGHTNESS_UP { kHIDPage_AppleVendorTopCase, kHIDUsage_AV_TopCase_BrightnessUp } +#if 0 +// These ADB codes are for normal NX key brightness (broken in 10.12) +#define BRIGHTNESS_DOWN 0x91 +#define BRIGHTNESS_UP 0x90 +#else +// These ADB codes are for F14/F15 (works in 10.12) +#define BRIGHTNESS_DOWN 0x6b +#define BRIGHTNESS_UP 0x71 +#endif -#define ADB_CONVERTER_LEN 256 // 0x00~0xff : normal key , 0x100~0x1ff : extended key +#define ADB_CONVERTER_LEN 256 * 2 // 0x00~0xff : normal key , 0x100~0x1ff : extended key #define ADB_CONVERTER_EX_START 256 // PS/2 scancode reference : USB HID to PS/2 Scan Code Translation Table PS/2 Set 1 columns // http://download.microsoft.com/download/1/6/1/161ba512-40e2-4cc9-843a-923143f3456c/translate.pdf -static const UInt8 PS2ToHIDMapStock[ADB_CONVERTER_LEN] = +static const UInt8 PS2ToADBMapStock[ADB_CONVERTER_LEN] = { -/* HID AT ANSI Key-Legend +/* ADB AT ANSI Key-Legend ======================== */ - DEADKEY, // 00 - kHIDUsage_KeyboardEscape, // 01 Escape - kHIDUsage_Keyboard1, // 02 1! - kHIDUsage_Keyboard2, // 03 2@ - kHIDUsage_Keyboard3, // 04 3# - kHIDUsage_Keyboard4, // 05 4$ - kHIDUsage_Keyboard5, // 06 5% - kHIDUsage_Keyboard6, // 07 6^ - kHIDUsage_Keyboard7, // 08 7& - kHIDUsage_Keyboard8, // 09 8* - kHIDUsage_Keyboard9, // 0a 9( - kHIDUsage_Keyboard0, // 0b 0) - kHIDUsage_KeyboardHyphen, // 0c -_ - kHIDUsage_KeyboardEqualSign,// 0d =+ - kHIDUsage_KeyboardDeleteOrBackspace, // 0e Backspace - kHIDUsage_KeyboardTab, // 0f Tab - kHIDUsage_KeyboardQ, // 10 qQ - kHIDUsage_KeyboardW, // 11 wW - kHIDUsage_KeyboardE, // 12 eE - kHIDUsage_KeyboardR, // 13 rR - kHIDUsage_KeyboardT, // 14 tT - kHIDUsage_KeyboardY, // 15 yY - kHIDUsage_KeyboardU, // 16 uU - kHIDUsage_KeyboardI, // 17 iI - kHIDUsage_KeyboardO, // 18 oO - kHIDUsage_KeyboardP, // 19 pP - kHIDUsage_KeyboardOpenBracket, // 1a [{ - kHIDUsage_KeyboardCloseBracket, // 1b ]} - kHIDUsage_KeyboardReturnOrEnter, // 1c Return - kHIDUsage_KeyboardLeftControl, // 1d Left Control - kHIDUsage_KeyboardA, // 1e aA - kHIDUsage_KeyboardS, // 1f sS - kHIDUsage_KeyboardD, // 20 dD - kHIDUsage_KeyboardF, // 21 fF - kHIDUsage_KeyboardG, // 22 gG - kHIDUsage_KeyboardH, // 23 hH - kHIDUsage_KeyboardJ, // 24 jJ - kHIDUsage_KeyboardK, // 25 kK - kHIDUsage_KeyboardL, // 26 lL - kHIDUsage_KeyboardSemicolon,// 27 ;: - kHIDUsage_KeyboardQuote, // 28 '" - kHIDUsage_KeyboardGraveAccentAndTilde, // 29 `~ - kHIDUsage_KeyboardLeftShift, // 2a Left Shift - kHIDUsage_KeyboardBackslash, // 2b \| , Europe 1(ISO) - kHIDUsage_KeyboardZ, // 2c zZ - kHIDUsage_KeyboardX, // 2d xX - kHIDUsage_KeyboardC, // 2e cC - kHIDUsage_KeyboardV, // 2f vV - kHIDUsage_KeyboardB, // 30 bB - kHIDUsage_KeyboardN, // 31 nN - kHIDUsage_KeyboardM, // 32 mM - kHIDUsage_KeyboardComma, // 33 ,< - kHIDUsage_KeyboardPeriod, // 34 .> - kHIDUsage_KeyboardSlash, // 35 /? - kHIDUsage_KeyboardRightShift, // 36 Right Shift - kHIDUsage_KeypadAsterisk, // 37 Keypad * - kHIDUsage_KeyboardLeftAlt, // 38 Left Alt - kHIDUsage_KeyboardSpacebar, // 39 Space - kHIDUsage_KeyboardCapsLock, // 3a Caps Lock - kHIDUsage_KeyboardF1, // 3b F1 - kHIDUsage_KeyboardF2, // 3c F2 - kHIDUsage_KeyboardF3, // 3d F3 - kHIDUsage_KeyboardF4, // 3e F4 - kHIDUsage_KeyboardF5, // 3f F5 - kHIDUsage_KeyboardF6, // 40 F6 - kHIDUsage_KeyboardF7, // 41 F7 - kHIDUsage_KeyboardF8, // 42 F8 - kHIDUsage_KeyboardF9, // 43 F9 - kHIDUsage_KeyboardF10, // 44 F10 - kHIDUsage_KeypadNumLock, // 45 Num Lock - kHIDUsage_KeyboardScrollLock, // 46 Scroll Lock - kHIDUsage_Keypad7, // 47 Keypad 7 Home - kHIDUsage_Keypad8, // 48 Keypad 8 Up - kHIDUsage_Keypad9, // 49 Keypad 9 PageUp - kHIDUsage_KeypadHyphen, // 4a Keypad - - kHIDUsage_Keypad4, // 4b Keypad 4 Left - kHIDUsage_Keypad5, // 4c Keypad 5 - kHIDUsage_Keypad6, // 4d Keypad 6 Right - kHIDUsage_KeypadPlus, // 4e Keypad + - kHIDUsage_Keypad1, // 4f Keypad 1 End - kHIDUsage_Keypad2, // 50 Keypad 2 Down - kHIDUsage_Keypad3, // 51 Keypad 3 PageDn - kHIDUsage_Keypad0, // 52 Keypad 0 Insert - kHIDUsage_KeypadPeriod, // 53 Keypad . Delete - kHIDUsage_KeyboardSysReqOrAttention, // 54 SysReq + DEADKEY,// 00 + 0x35, // 01 Escape + 0x12, // 02 1! + 0x13, // 03 2@ + 0x14, // 04 3# + 0x15, // 05 4$ + 0x17, // 06 5% + 0x16, // 07 6^ + 0x1a, // 08 7& + 0x1c, // 09 8* + 0x19, // 0a 9( + 0x1d, // 0b 0) + 0x1b, // 0c -_ + 0x18, // 0d =+ + 0x33, // 0e Backspace + 0x30, // 0f Tab + 0x0c, // 10 qQ + 0x0d, // 11 wW + 0x0e, // 12 eE + 0x0f, // 13 rR + 0x11, // 14 tT + 0x10, // 15 yY + 0x20, // 16 uU + 0x22, // 17 iI + 0x1f, // 18 oO + 0x23, // 19 pP + 0x21, // 1a [{ + 0x1e, // 1b ]} + 0x24, // 1c Return + 0x3b, // 1d Left Control + 0x00, // 1e aA + 0x01, // 1f sS + 0x02, // 20 dD + 0x03, // 21 fF + 0x05, // 22 gG + 0x04, // 23 hH + 0x26, // 24 jJ + 0x28, // 25 kK + 0x25, // 26 lL + 0x29, // 27 ;: + 0x27, // 28 '" + 0x32, // 29 `~ + 0x38, // 2a Left Shift + 0x2a, // 2b \| , Europe 1(ISO) + 0x06, // 2c zZ + 0x07, // 2d xX + 0x08, // 2e cC + 0x09, // 2f vV + 0x0b, // 30 bB + 0x2d, // 31 nN + 0x2e, // 32 mM + 0x2b, // 33 ,< + 0x2f, // 34 .> + 0x2c, // 35 /? + 0x3c, // 36 Right Shift + 0x43, // 37 Keypad * + 0x3a, // 38 Left Alt + 0x31, // 39 Space + 0x39, // 3a Caps Lock + 0x7a, // 3b F1 + 0x78, // 3c F2 + 0x63, // 3d F3 + 0x76, // 3e F4 + 0x60, // 3f F5 + 0x61, // 40 F6 + 0x62, // 41 F7 + 0x64, // 42 F8 + 0x65, // 43 F9 + 0x6d, // 44 F10 + 0x47, // 45 Num Lock + 0x6b, // 46 Scroll Lock + 0x59, // 47 Keypad 7 Home + 0x5b, // 48 Keypad 8 Up + 0x5c, // 49 Keypad 9 PageUp + 0x4e, // 4a Keypad - + 0x56, // 4b Keypad 4 Left + 0x57, // 4c Keypad 5 + 0x58, // 4d Keypad 6 Right + 0x45, // 4e Keypad + + 0x53, // 4f Keypad 1 End + 0x54, // 50 Keypad 2 Down + 0x55, // 51 Keypad 3 PageDn + 0x52, // 52 Keypad 0 Insert + 0x41, // 53 Keypad . Delete + 0x44, // 54 SysReq 0x46, // 55 - kHIDUsage_KeyboardNonUSBackslash, // 56 Europe 2(ISO) - kHIDUsage_KeyboardF11, // 57 F11 - kHIDUsage_KeyboardF12, // 58 F12 - kHIDUsage_KeypadEqualSign, // 59 Keypad = + 0x0a, // 56 Europe 2(ISO) + 0x67, // 57 F11 + 0x6f, // 58 F12 + 0x51, // 59 Keypad = DEADKEY,// 5a DEADKEY,// 5b - kHIDUsage_KeyboardInternational6, // 5c Keyboard Int'l 6 (PC9800 Keypad , ) + 0x5f, // 5c Keyboard Int'l 6 (PC9800 Keypad , ) DEADKEY,// 5d DEADKEY,// 5e DEADKEY,// 5f @@ -143,33 +146,33 @@ static const UInt8 PS2ToHIDMapStock[ADB_CONVERTER_LEN] = DEADKEY,// 61 DEADKEY,// 62 DEADKEY,// 63 - kHIDUsage_KeyboardF13, // 64 F13 - kHIDUsage_KeyboardF14, // 65 F14 - kHIDUsage_KeyboardF15, // 66 F15 - kHIDUsage_KeyboardF16, // 67 F16 - kHIDUsage_KeyboardF17, // 68 F17 - kHIDUsage_KeyboardF18, // 69 F18 - kHIDUsage_KeyboardF19, // 6a F19 - kHIDUsage_KeyboardF20, // 6b F20 - kHIDUsage_KeyboardF21, // 6c F21 - kHIDUsage_KeyboardF22, // 6d F22 - kHIDUsage_KeyboardF23, // 6e F23 + 0x69, // 64 F13 + 0x6b, // 65 F14 + 0x71, // 66 F15 + 0x6a, // 67 F16 + 0x40, // 68 F17 + 0x4f, // 69 F18 + 0x50, // 6a F19 + 0x5a, // 6b F20 + DEADKEY,// 6c F21 + DEADKEY,// 6d F22 + DEADKEY,// 6e F23 DEADKEY,// 6f - kHIDUsage_KeyboardInternational2, // 70 Keyboard Intl'2 (Japanese Katakana/Hiragana) + 0x68, // 70 Keyboard Intl'2 (Japanese Katakana/Hiragana) DEADKEY,// 71 DEADKEY,// 72 - kHIDUsage_KeyboardInternational1, // 73 Keyboard Int'l 1 (Japanese Ro) + 0x5e, // 73 Keyboard Int'l 1 (Japanese Ro) DEADKEY,// 74 DEADKEY,// 75 - kHIDUsage_KeyboardF24, // 76 F24 , Keyboard Lang 5 (Japanese Zenkaku/Hankaku) - kHIDUsage_KeyboardLANG4, // 77 Keyboard Lang 4 (Japanese Hiragana) - kHIDUsage_KeyboardLANG3, // 78 Keyboard Lang 3 (Japanese Katakana) - kHIDUsage_KeyboardInternational4, // 79 Keyboard Int'l 4 (Japanese Henkan) + DEADKEY,// 76 F24 , Keyboard Lang 5 (Japanese Zenkaku/Hankaku) + 0x68, // 77 Keyboard Lang 4 (Japanese Hiragana) + 0x68, // 78 Keyboard Lang 3 (Japanese Katakana) + 0x68, // 79 Keyboard Int'l 4 (Japanese Henkan) DEADKEY,// 7a - kHIDUsage_KeyboardInternational5, // 7b Keyboard Int'l 5 (Japanese Muhenkan) + 0x66, // 7b Keyboard Int'l 5 (Japanese Muhenkan) DEADKEY,// 7c - kHIDUsage_KeyboardInternational3, // 7d Keyboard Int'l 3 (Japanese Yen) - kHIDUsage_KeypadComma, // 7e Keypad , (Brazilian Keypad .) + 0x5d, // 7d Keyboard Int'l 3 (Japanese Yen) + 0x5f, // 7e Keypad , (Brazilian Keypad .) DEADKEY,// 7f DEADKEY,// 80 DEADKEY,// 81 @@ -284,8 +287,8 @@ static const UInt8 PS2ToHIDMapStock[ADB_CONVERTER_LEN] = DEADKEY,// ee DEADKEY,// ef DEADKEY,// f0 - kHIDUsage_KeyboardLANG2, // f1* Keyboard Lang 2 (Korean Hanja) - kHIDUsage_KeyboardLANG1, // f2* Keyboard Lang 1 (Korean Hangul) + 0x66, // f1* Keyboard Lang 2 (Korean Hanja) + 0x68, // f2* Keyboard Lang 1 (Korean Hangul) DEADKEY,// f3 DEADKEY,// f4 DEADKEY,// f5 @@ -298,289 +301,278 @@ static const UInt8 PS2ToHIDMapStock[ADB_CONVERTER_LEN] = DEADKEY,// fc DEADKEY,// fd DEADKEY,// fe - DEADKEY,// ff -}; - -struct VoodooPS2HidElement { - uint16_t usagePage; - uint16_t usage; -}; - -#define KEY(a) { kHIDPage_KeyboardOrKeypad, (a)} -#define MEDIA(a) { kHIDPage_Consumer, (a)} - -static const VoodooPS2HidElement ExtendedPS2ToHIDStockMap[ADB_CONVERTER_LEN] { - DEADKEY_EXTENDED,// e0 00 - DEADKEY_EXTENDED,// e0 01 - DEADKEY_EXTENDED,// e0 02 - DEADKEY_EXTENDED,// e0 03 - DEADKEY_EXTENDED,// e0 04 - BRIGHTNESS_DOWN, // e0 05 dell down - BRIGHTNESS_UP, // e0 06 dell up - DEADKEY_EXTENDED,// e0 07 + DEADKEY,// ff + DEADKEY,// e0 00 + DEADKEY,// e0 01 + DEADKEY,// e0 02 + DEADKEY,// e0 03 + DEADKEY,// e0 04 + BRIGHTNESS_DOWN, // e0 05 dell down + BRIGHTNESS_UP, // e0 06 dell up + DEADKEY,// e0 07 #ifndef PROBOOK BRIGHTNESS_UP, // e0 08 samsung up BRIGHTNESS_DOWN, // e0 09 samsung down #else - DEADKEY_EXTENDED,// e0 08 - { kHIDPage_AppleVendorKeyboard, kHIDUsage_AppleVendorKeyboard_Launchpad }, // e0 09 Launchpad (hp Fn+F6) + DEADKEY,// e0 08 + 0x83, // e0 09 Launchpad (hp Fn+F6) #endif - { kHIDPage_AppleVendorKeyboard, kHIDUsage_AppleVendorKeyboard_Expose_All }, // e0 0a Mission Control (hp Fn+F5) - DEADKEY_EXTENDED,// e0 0b - DEADKEY_EXTENDED,// e0 0c - DEADKEY_EXTENDED,// e0 0d - DEADKEY_EXTENDED,// e0 0e - DEADKEY_EXTENDED,// e0 0f - MEDIA ( kHIDUsage_Csmr_ScanPreviousTrack ), // e0 10 Scan Previous Track (hp Fn+F10) - DEADKEY_EXTENDED,// e0 11 + 0xa0, // e0 0a Mission Control (hp Fn+F5) + DEADKEY,// e0 0b + DEADKEY,// e0 0c + DEADKEY,// e0 0d + DEADKEY,// e0 0e + DEADKEY,// e0 0f + 0x4d, // e0 10 Scan Previous Track (hp Fn+F10) + DEADKEY,// e0 11 BRIGHTNESS_DOWN, // e0 12 hp down (Fn+F2) - DEADKEY_EXTENDED,// e0 13 - DEADKEY_EXTENDED,// e0 14 - DEADKEY_EXTENDED,// e0 15 - DEADKEY_EXTENDED,// e0 16 + DEADKEY,// e0 13 + DEADKEY,// e0 14 + DEADKEY,// e0 15 + DEADKEY,// e0 16 BRIGHTNESS_UP, // e0 17 hp up (Fn+F3) - DEADKEY_EXTENDED,// e0 18 - MEDIA ( kHIDUsage_Csmr_ScanNextTrack ), // e0 19 Scan Next Track (hp Fn+F12) - DEADKEY_EXTENDED,// e0 1a - DEADKEY_EXTENDED,// e0 1b - KEY( kHIDUsage_KeypadEnter ), // e0 1c Keypad Enter - KEY( kHIDUsage_KeyboardRightControl ), // e0 1d Right Control - DEADKEY_EXTENDED,// e0 1e - DEADKEY_EXTENDED,// e0 1f - MEDIA ( kHIDUsage_Csmr_Mute ), // e0 20 Mute (hp Fn+F7) - MEDIA ( kHIDUsage_Csmr_ALCalculator ),// e0 21 Calculator - MEDIA ( kHIDUsage_Csmr_PlayOrPause ), // e0 22 Play/Pause (hp Fn+F11) - DEADKEY_EXTENDED,// e0 23 - MEDIA ( kHIDUsage_Csmr_Stop ),// e0 24 Stop - DEADKEY_EXTENDED,// e0 25 - DEADKEY_EXTENDED,// e0 26 - DEADKEY_EXTENDED,// e0 27 - DEADKEY_EXTENDED,// e0 28 - DEADKEY_EXTENDED,// e0 29 - DEADKEY_EXTENDED,// e0 2a - DEADKEY_EXTENDED,// e0 2b - DEADKEY_EXTENDED,// e0 2c - DEADKEY_EXTENDED,// e0 2d - MEDIA ( kHIDUsage_Csmr_VolumeDecrement ), // e0 2e Volume Down (hp Fn+F8) - DEADKEY_EXTENDED,// e0 2f - MEDIA ( kHIDUsage_Csmr_VolumeIncrement ), // e0 30 Volume Up (hp Fn+F9) - DEADKEY_EXTENDED,// e0 31 - MEDIA ( kHIDUsage_Csmr_ACHome ),// e0 32 WWW Home - DEADKEY_EXTENDED,// e0 33 - DEADKEY_EXTENDED,// e0 34 - KEY ( kHIDUsage_KeypadSlash ), // e0 35 Keypad / - DEADKEY_EXTENDED,// e0 36 - KEY ( kHIDUsage_KeyboardPrintScreen ), // e0 37 Print Screen - KEY ( kHIDUsage_KeyboardRightAlt ), // e0 38 Right Alt - DEADKEY_EXTENDED,// e0 39 - DEADKEY_EXTENDED,// e0 3a - DEADKEY_EXTENDED,// e0 3b - DEADKEY_EXTENDED,// e0 3c - DEADKEY_EXTENDED,// e0 3d - DEADKEY_EXTENDED,// e0 3e - DEADKEY_EXTENDED,// e0 3f - DEADKEY_EXTENDED,// e0 40 - DEADKEY_EXTENDED,// e0 41 - DEADKEY_EXTENDED,// e0 42 - DEADKEY_EXTENDED,// e0 43 - DEADKEY_EXTENDED,// e0 44 - KEY ( kHIDUsage_KeyboardPause ), // e0 45* Pause - KEY ( kHIDUsage_KeyboardPause ), // e0 46* Break(Ctrl-Pause) - KEY ( kHIDUsage_KeyboardHome ), // e0 47 Home - KEY ( kHIDUsage_KeyboardUpArrow ), // e0 48 Up Arrow - KEY ( kHIDUsage_KeyboardPageUp ), // e0 49 Page Up - DEADKEY_EXTENDED,// e0 4a - KEY ( kHIDUsage_KeyboardLeftArrow ), // e0 4b Left Arrow - DEADKEY_EXTENDED,// e0 4c - KEY ( kHIDUsage_KeyboardRightArrow ), // e0 4d Right Arrow + DEADKEY,// e0 18 + 0x42, // e0 19 Scan Next Track (hp Fn+F12) + DEADKEY,// e0 1a + DEADKEY,// e0 1b + 0x4c, // e0 1c Keypad Enter + 0x3e, // e0 1d Right Control + DEADKEY,// e0 1e + DEADKEY,// e0 1f + 0x4a, // e0 20 Mute (hp Fn+F7) + DEADKEY,// e0 21 Calculator + 0x34, // e0 22 Play/Pause (hp Fn+F11) + DEADKEY,// e0 23 + DEADKEY,// e0 24 Stop + DEADKEY,// e0 25 + DEADKEY,// e0 26 + DEADKEY,// e0 27 + DEADKEY,// e0 28 + DEADKEY,// e0 29 + DEADKEY,// e0 2a + DEADKEY,// e0 2b + DEADKEY,// e0 2c + DEADKEY,// e0 2d + 0x49, // e0 2e Volume Down (hp Fn+F8) + DEADKEY,// e0 2f + 0x48, // e0 30 Volume Up (hp Fn+F9) + DEADKEY,// e0 31 + DEADKEY,// e0 32 WWW Home + DEADKEY,// e0 33 + DEADKEY,// e0 34 + 0x4b, // e0 35 Keypad / + DEADKEY,// e0 36 + 0x69, // e0 37 Print Screen + 0x3d, // e0 38 Right Alt + DEADKEY,// e0 39 + DEADKEY,// e0 3a + DEADKEY,// e0 3b + DEADKEY,// e0 3c + DEADKEY,// e0 3d + DEADKEY,// e0 3e + DEADKEY,// e0 3f + DEADKEY,// e0 40 + DEADKEY,// e0 41 + DEADKEY,// e0 42 + DEADKEY,// e0 43 + DEADKEY,// e0 44 + 0x71, // e0 45* Pause + DEADKEY,// e0 46* Break(Ctrl-Pause) + 0x73, // e0 47 Home + 0x7e, // e0 48 Up Arrow + 0x74, // e0 49 Page Up + DEADKEY,// e0 4a + 0x7b, // e0 4b Left Arrow + DEADKEY,// e0 4c + 0x7c, // e0 4d Right Arrow BRIGHTNESS_UP, // e0 4e acer up - KEY ( kHIDUsage_KeyboardEnd ), // e0 4f End - KEY ( kHIDUsage_KeyboardDownArrow ), // e0 50 Down Arrow - KEY ( kHIDUsage_KeyboardPageDown ), // e0 51 Page Down - MEDIA ( kHIDUsage_Csmr_Eject ), // e0 52 Insert = Eject - KEY ( kHIDUsage_KeyboardDeleteForward ), // e0 53 Delete - DEADKEY_EXTENDED,// e0 54 - DEADKEY_EXTENDED,// e0 55 - DEADKEY_EXTENDED,// e0 56 - DEADKEY_EXTENDED,// e0 57 - DEADKEY_EXTENDED,// e0 58 + 0x77, // e0 4f End + 0x7d, // e0 50 Down Arrow + 0x79, // e0 51 Page Down + 0x92, // e0 52 Insert = Eject + 0x75, // e0 53 Delete + DEADKEY,// e0 54 + DEADKEY,// e0 55 + DEADKEY,// e0 56 + DEADKEY,// e0 57 + DEADKEY,// e0 58 BRIGHTNESS_UP, // e0 59 acer up for my acer - DEADKEY_EXTENDED,// e0 5a - KEY ( kHIDUsage_KeyboardLeftGUI ), // e0 5b Left GUI(Windows) - KEY ( kHIDUsage_KeyboardRightGUI ), // e0 5c Right GUI(Windows) - KEY ( kHIDUsage_KeyboardApplication ), // e0 5d App( Windows context menu key ) - { kHIDPage_GenericDesktop, kHIDUsage_GD_SystemPowerDown }, // e0 5e System Power / Keyboard Power - { kHIDPage_GenericDesktop, kHIDUsage_GD_SystemSleep },// e0 5f System Sleep (hp Fn+F1) - DEADKEY_EXTENDED,// e0 60 - DEADKEY_EXTENDED,// e0 61 - DEADKEY_EXTENDED,// e0 62 - { kHIDPage_GenericDesktop, kHIDUsage_GD_SystemWakeUp },// e0 63 System Wake - DEADKEY_EXTENDED,// e0 64 - MEDIA ( kHIDUsage_Csmr_ACSearch ),// e0 65 WWW Search - MEDIA ( kHIDUsage_Csmr_ACBookmarks ),// e0 66 WWW Favorites - MEDIA ( kHIDUsage_Csmr_ACRefresh ),// e0 67 WWW Refresh - MEDIA ( kHIDUsage_Csmr_ACStop ),// e0 68 WWW Stop - MEDIA ( kHIDUsage_Csmr_ACForward ),// e0 69 WWW Forward - MEDIA ( kHIDUsage_Csmr_ACBack ),// e0 6a WWW Back - DEADKEY_EXTENDED,// e0 6b My Computer - MEDIA ( kHIDUsage_Csmr_ALEmailReader ),// e0 6c Mail - DEADKEY_EXTENDED,// e0 6d Media Select + DEADKEY,// e0 5a + 0x37, // e0 5b Left GUI(Windows) + 0x36, // e0 5c Right GUI(Windows) + 0x6e, // e0 5d App( Windows context menu key ) + 0x7f, // e0 5e System Power / Keyboard Power + DEADKEY,// e0 5f System Sleep (hp Fn+F1) + DEADKEY,// e0 60 + DEADKEY,// e0 61 + DEADKEY,// e0 62 + DEADKEY,// e0 63 System Wake + DEADKEY,// e0 64 + DEADKEY,// e0 65 WWW Search + DEADKEY,// e0 66 WWW Favorites + DEADKEY,// e0 67 WWW Refresh + DEADKEY,// e0 68 WWW Stop + DEADKEY,// e0 69 WWW Forward + DEADKEY,// e0 6a WWW Back + DEADKEY,// e0 6b My Computer + DEADKEY,// e0 6c Mail + DEADKEY,// e0 6d Media Select #ifndef PROBOOK BRIGHTNESS_UP, // e0 6e acer up BRIGHTNESS_DOWN, // e0 6f acer down #else - MEDIA ( 0x00 ), // e0 6e Video Mirror = hp Fn+F4 - DEADKEY_EXTENDED,// e0 6f Fn+Home + 0x70, // e0 6e Video Mirror = hp Fn+F4 + DEADKEY,// e0 6f Fn+Home #endif - DEADKEY_EXTENDED,// e0 70 - DEADKEY_EXTENDED,// e0 71 - DEADKEY_EXTENDED,// e0 72 - DEADKEY_EXTENDED,// e0 73 - DEADKEY_EXTENDED,// e0 74 - DEADKEY_EXTENDED,// e0 75 - DEADKEY_EXTENDED,// e0 76 + DEADKEY,// e0 70 + DEADKEY,// e0 71 + DEADKEY,// e0 72 + DEADKEY,// e0 73 + DEADKEY,// e0 74 + DEADKEY,// e0 75 + DEADKEY,// e0 76 #ifndef PROBOOK BRIGHTNESS_DOWN, // e0 77 lg down BRIGHTNESS_UP, // e0 78 lg up #else - DEADKEY_EXTENDED,// e0 77 - DEADKEY_EXTENDED,// e0 78 WiFi on/off button on HP ProBook + DEADKEY,// e0 77 + DEADKEY,// e0 78 WiFi on/off button on HP ProBook #endif - DEADKEY_EXTENDED,// e0 79 - DEADKEY_EXTENDED,// e0 7a - DEADKEY_EXTENDED,// e0 7b - DEADKEY_EXTENDED,// e0 7c - DEADKEY_EXTENDED,// e0 7d - DEADKEY_EXTENDED,// e0 7e - DEADKEY_EXTENDED,// e0 7f - DEADKEY_EXTENDED,// e0 80 - DEADKEY_EXTENDED,// e0 81 - DEADKEY_EXTENDED,// e0 82 - DEADKEY_EXTENDED,// e0 83 - DEADKEY_EXTENDED,// e0 84 - DEADKEY_EXTENDED,// e0 85 - DEADKEY_EXTENDED,// e0 86 - DEADKEY_EXTENDED,// e0 87 - DEADKEY_EXTENDED,// e0 88 - DEADKEY_EXTENDED,// e0 89 - DEADKEY_EXTENDED,// e0 8a - DEADKEY_EXTENDED,// e0 8b - DEADKEY_EXTENDED,// e0 8c - DEADKEY_EXTENDED,// e0 8d - DEADKEY_EXTENDED,// e0 8e - DEADKEY_EXTENDED,// e0 8f - DEADKEY_EXTENDED,// e0 90 - DEADKEY_EXTENDED,// e0 91 - DEADKEY_EXTENDED,// e0 92 - DEADKEY_EXTENDED,// e0 93 - DEADKEY_EXTENDED,// e0 94 - DEADKEY_EXTENDED,// e0 95 - DEADKEY_EXTENDED,// e0 96 - DEADKEY_EXTENDED,// e0 97 - DEADKEY_EXTENDED,// e0 98 - DEADKEY_EXTENDED,// e0 99 - DEADKEY_EXTENDED,// e0 9a - DEADKEY_EXTENDED,// e0 9b - DEADKEY_EXTENDED,// e0 9c - DEADKEY_EXTENDED,// e0 9d - DEADKEY_EXTENDED,// e0 9e - DEADKEY_EXTENDED,// e0 9f - DEADKEY_EXTENDED,// e0 a0 - DEADKEY_EXTENDED,// e0 a1 - DEADKEY_EXTENDED,// e0 a2 - DEADKEY_EXTENDED,// e0 a3 - DEADKEY_EXTENDED,// e0 a4 - DEADKEY_EXTENDED,// e0 a5 - DEADKEY_EXTENDED,// e0 a6 - DEADKEY_EXTENDED,// e0 a7 - DEADKEY_EXTENDED,// e0 a8 - DEADKEY_EXTENDED,// e0 a9 - DEADKEY_EXTENDED,// e0 aa - DEADKEY_EXTENDED,// e0 ab - DEADKEY_EXTENDED,// e0 ac - DEADKEY_EXTENDED,// e0 ad - DEADKEY_EXTENDED,// e0 ae - DEADKEY_EXTENDED,// e0 af - DEADKEY_EXTENDED,// e0 b0 - DEADKEY_EXTENDED,// e0 b1 - DEADKEY_EXTENDED,// e0 b2 - DEADKEY_EXTENDED,// e0 b3 - DEADKEY_EXTENDED,// e0 b4 - DEADKEY_EXTENDED,// e0 b5 - DEADKEY_EXTENDED,// e0 b6 - DEADKEY_EXTENDED,// e0 b7 - DEADKEY_EXTENDED,// e0 b8 - DEADKEY_EXTENDED,// e0 b9 - DEADKEY_EXTENDED,// e0 ba - DEADKEY_EXTENDED,// e0 bb - DEADKEY_EXTENDED,// e0 bc - DEADKEY_EXTENDED,// e0 bd - DEADKEY_EXTENDED,// e0 be - DEADKEY_EXTENDED,// e0 bf - DEADKEY_EXTENDED,// e0 c0 - DEADKEY_EXTENDED,// e0 c1 - DEADKEY_EXTENDED,// e0 c2 - DEADKEY_EXTENDED,// e0 c3 - DEADKEY_EXTENDED,// e0 c4 - DEADKEY_EXTENDED,// e0 c5 - DEADKEY_EXTENDED,// e0 c6 - DEADKEY_EXTENDED,// e0 c7 - DEADKEY_EXTENDED,// e0 c8 - DEADKEY_EXTENDED,// e0 c9 - DEADKEY_EXTENDED,// e0 ca - DEADKEY_EXTENDED,// e0 cb - DEADKEY_EXTENDED,// e0 cc - DEADKEY_EXTENDED,// e0 cd - DEADKEY_EXTENDED,// e0 ce - DEADKEY_EXTENDED,// e0 cf - DEADKEY_EXTENDED,// e0 d0 - DEADKEY_EXTENDED,// e0 d1 - DEADKEY_EXTENDED,// e0 d2 - DEADKEY_EXTENDED,// e0 d3 - DEADKEY_EXTENDED,// e0 d4 - DEADKEY_EXTENDED,// e0 d5 - DEADKEY_EXTENDED,// e0 d6 - DEADKEY_EXTENDED,// e0 d7 - DEADKEY_EXTENDED,// e0 d8 - DEADKEY_EXTENDED,// e0 d9 - DEADKEY_EXTENDED,// e0 da - DEADKEY_EXTENDED,// e0 db - DEADKEY_EXTENDED,// e0 dc - DEADKEY_EXTENDED,// e0 dd - DEADKEY_EXTENDED,// e0 de - DEADKEY_EXTENDED,// e0 df - DEADKEY_EXTENDED,// e0 e0 - DEADKEY_EXTENDED,// e0 e1 - DEADKEY_EXTENDED,// e0 e2 - DEADKEY_EXTENDED,// e0 e3 - DEADKEY_EXTENDED,// e0 e4 - DEADKEY_EXTENDED,// e0 e5 - DEADKEY_EXTENDED,// e0 e6 - DEADKEY_EXTENDED,// e0 e7 - DEADKEY_EXTENDED,// e0 e8 - DEADKEY_EXTENDED,// e0 e9 - DEADKEY_EXTENDED,// e0 ea - DEADKEY_EXTENDED,// e0 eb - DEADKEY_EXTENDED,// e0 ec - DEADKEY_EXTENDED,// e0 ed - DEADKEY_EXTENDED,// e0 ee - DEADKEY_EXTENDED,// e0 ef - DEADKEY_EXTENDED,// e0 f0 // Note: codes e0f0 through e0ff are reserved for ACPI callback - DEADKEY_EXTENDED,// e0 f1 - DEADKEY_EXTENDED,// e0 f2 - DEADKEY_EXTENDED,// e0 f3 - DEADKEY_EXTENDED,// e0 f4 - DEADKEY_EXTENDED,// e0 f5 - DEADKEY_EXTENDED,// e0 f6 - DEADKEY_EXTENDED,// e0 f7 - DEADKEY_EXTENDED,// e0 f8 - DEADKEY_EXTENDED,// e0 f9 - DEADKEY_EXTENDED,// e0 fa - DEADKEY_EXTENDED,// e0 fb - DEADKEY_EXTENDED,// e0 fc - DEADKEY_EXTENDED,// e0 fd - DEADKEY_EXTENDED,// e0 fe - DEADKEY_EXTENDED // e0 ff // End reserved + DEADKEY,// e0 79 + DEADKEY,// e0 7a + DEADKEY,// e0 7b + DEADKEY,// e0 7c + DEADKEY,// e0 7d + DEADKEY,// e0 7e + DEADKEY,// e0 7f + DEADKEY,// e0 80 + DEADKEY,// e0 81 + DEADKEY,// e0 82 + DEADKEY,// e0 83 + DEADKEY,// e0 84 + DEADKEY,// e0 85 + DEADKEY,// e0 86 + DEADKEY,// e0 87 + DEADKEY,// e0 88 + DEADKEY,// e0 89 + DEADKEY,// e0 8a + DEADKEY,// e0 8b + DEADKEY,// e0 8c + DEADKEY,// e0 8d + DEADKEY,// e0 8e + DEADKEY,// e0 8f + DEADKEY,// e0 90 + DEADKEY,// e0 91 + DEADKEY,// e0 92 + DEADKEY,// e0 93 + DEADKEY,// e0 94 + DEADKEY,// e0 95 + DEADKEY,// e0 96 + DEADKEY,// e0 97 + DEADKEY,// e0 98 + DEADKEY,// e0 99 + DEADKEY,// e0 9a + DEADKEY,// e0 9b + DEADKEY,// e0 9c + DEADKEY,// e0 9d + DEADKEY,// e0 9e + DEADKEY,// e0 9f + DEADKEY,// e0 a0 + DEADKEY,// e0 a1 + DEADKEY,// e0 a2 + DEADKEY,// e0 a3 + DEADKEY,// e0 a4 + DEADKEY,// e0 a5 + DEADKEY,// e0 a6 + DEADKEY,// e0 a7 + DEADKEY,// e0 a8 + DEADKEY,// e0 a9 + DEADKEY,// e0 aa + DEADKEY,// e0 ab + DEADKEY,// e0 ac + DEADKEY,// e0 ad + DEADKEY,// e0 ae + DEADKEY,// e0 af + DEADKEY,// e0 b0 + DEADKEY,// e0 b1 + DEADKEY,// e0 b2 + DEADKEY,// e0 b3 + DEADKEY,// e0 b4 + DEADKEY,// e0 b5 + DEADKEY,// e0 b6 + DEADKEY,// e0 b7 + DEADKEY,// e0 b8 + DEADKEY,// e0 b9 + DEADKEY,// e0 ba + DEADKEY,// e0 bb + DEADKEY,// e0 bc + DEADKEY,// e0 bd + DEADKEY,// e0 be + DEADKEY,// e0 bf + DEADKEY,// e0 c0 + DEADKEY,// e0 c1 + DEADKEY,// e0 c2 + DEADKEY,// e0 c3 + DEADKEY,// e0 c4 + DEADKEY,// e0 c5 + DEADKEY,// e0 c6 + DEADKEY,// e0 c7 + DEADKEY,// e0 c8 + DEADKEY,// e0 c9 + DEADKEY,// e0 ca + DEADKEY,// e0 cb + DEADKEY,// e0 cc + DEADKEY,// e0 cd + DEADKEY,// e0 ce + DEADKEY,// e0 cf + DEADKEY,// e0 d0 + DEADKEY,// e0 d1 + DEADKEY,// e0 d2 + DEADKEY,// e0 d3 + DEADKEY,// e0 d4 + DEADKEY,// e0 d5 + DEADKEY,// e0 d6 + DEADKEY,// e0 d7 + DEADKEY,// e0 d8 + DEADKEY,// e0 d9 + DEADKEY,// e0 da + DEADKEY,// e0 db + DEADKEY,// e0 dc + DEADKEY,// e0 dd + DEADKEY,// e0 de + DEADKEY,// e0 df + DEADKEY,// e0 e0 + DEADKEY,// e0 e1 + DEADKEY,// e0 e2 + DEADKEY,// e0 e3 + DEADKEY,// e0 e4 + DEADKEY,// e0 e5 + DEADKEY,// e0 e6 + DEADKEY,// e0 e7 + DEADKEY,// e0 e8 + DEADKEY,// e0 e9 + DEADKEY,// e0 ea + DEADKEY,// e0 eb + DEADKEY,// e0 ec + DEADKEY,// e0 ed + DEADKEY,// e0 ee + DEADKEY,// e0 ef + DEADKEY,// e0 f0 // Note: codes e0f0 through e0ff are reserved for ACPI callback + DEADKEY,// e0 f1 + DEADKEY,// e0 f2 + DEADKEY,// e0 f3 + DEADKEY,// e0 f4 + DEADKEY,// e0 f5 + DEADKEY,// e0 f6 + DEADKEY,// e0 f7 + DEADKEY,// e0 f8 + DEADKEY,// e0 f9 + DEADKEY,// e0 fa + DEADKEY,// e0 fb + DEADKEY,// e0 fc + DEADKEY,// e0 fd + DEADKEY,// e0 fe + DEADKEY // e0 ff // End reserved }; /////////////////////////////////////////////////////////////////////////////////// @@ -613,7 +605,7 @@ static const VoodooPS2HidElement ExtendedPS2ToHIDStockMap[ADB_CONVERTER_LEN] { #define kMaskLeftFn 0x0100 #define kMaskWindowsContext 0x0200 -static const UInt16 _PS2flagsStock[256*2] = +static const UInt16 _PS2flagsStock[ADB_CONVERTER_LEN] = { // flags/modifier key AT ANSI Key-Legend 0x00, // 00 diff --git a/VoodooPS2Keyboard/VoodooPS2EventDriver.hpp b/VoodooPS2Keyboard/VoodooPS2EventDriver.hpp deleted file mode 100644 index d773d3ca..00000000 --- a/VoodooPS2Keyboard/VoodooPS2EventDriver.hpp +++ /dev/null @@ -1,31 +0,0 @@ -// -// HIDPS2EventDriver.hpp -// HIDPS2Keyboard -// -// Created by Gwydien on 8/27/23. -// Copyright © 2023 coolstar. All rights reserved. -// - -#ifndef HIDPS2EventDriver_hpp -#define HIDPS2EventDriver_hpp - -#include - -class VoodooPS2KeyboardHIDEventDriver : public IOHIDEventService -{ - OSDeclareDefaultStructors( VoodooPS2KeyboardHIDEventDriver ); - friend class VoodooPS2KeyboardHIDWrapper; - -public: - bool start(IOService *provider) override { - IOHIDInterface *interface = OSDynamicCast(IOHIDInterface, provider); - if (!IOHIDEventService::start(provider)) { - return false; - } - - registerService(); - return interface->open(this, 0, nullptr, nullptr); - } -}; - -#endif /* HIDPS2EventDriver_hpp */ diff --git a/VoodooPS2Keyboard/VoodooPS2Keyboard-Info.plist b/VoodooPS2Keyboard/VoodooPS2Keyboard-Info.plist index ca4e7058..7e224756 100644 --- a/VoodooPS2Keyboard/VoodooPS2Keyboard-Info.plist +++ b/VoodooPS2Keyboard/VoodooPS2Keyboard-Info.plist @@ -22,31 +22,6 @@ ${MODULE_VERSION} IOKitPersonalities - VoodooPS2HIDEventDriver - - CFBundleIdentifier - com.1Revenger1.PS2Keyboard - DeviceUsagePairs - - - DeviceUsage - 1 - DeviceUsagePage - 12 - - - IOClass - VoodooPS2KeyboardHIDEventDriver - IOProbeScore - 8000 - IOPropertyMatch - - Transport - PS2 - - IOProviderClass - IOHIDInterface - ApplePS2Keyboard CFBundleIdentifier diff --git a/VoodooPS2Keyboard/VoodooPS2Keyboard.cpp b/VoodooPS2Keyboard/VoodooPS2Keyboard.cpp index ab90c7b9..fe47247e 100644 --- a/VoodooPS2Keyboard/VoodooPS2Keyboard.cpp +++ b/VoodooPS2Keyboard/VoodooPS2Keyboard.cpp @@ -20,6 +20,12 @@ * @APPLE_LICENSE_HEADER_END@ */ +// enable for keyboard debugging +#ifdef DEBUG_MSG +//#define DEBUG_VERBOSE +#define DEBUG_LITE +#endif + #include #include @@ -28,8 +34,10 @@ #include #include +#include "ApplePS2ToADBMap.h" #include "VoodooPS2Controller.h" #include "VoodooPS2Keyboard.h" +#include "ApplePS2ToADBMap.h" #include "AppleACPIPS2Nub.h" #include @@ -37,7 +45,10 @@ // Constants for Info.plist settings #define kSleepPressTime "SleepPressTime" +#define kHIDFKeyMode "HIDFKeyMode" #define kHIDF12EjectDelay "HIDF12EjectDelay" +#define kFunctionKeysStandard "Function Keys Standard" +#define kFunctionKeysSpecial "Function Keys Special" #define kRemapPrntScr "RemapPrntScr" #define kNumLockSupport "NumLockSupport" #define kNumLockOnAtBoot "NumLockOnAtBoot" @@ -47,12 +58,54 @@ #define kMakeApplicationKeyAppleFN "Make Application key into Apple Fn key" #define kMakeRightModsHangulHanja "Make right modifier keys into Hangul and Hanja" #define kUseISOLayoutKeyboard "Use ISO layout keyboard" +#define kLogScanCodes "LogScanCodes" + +#define kBrightnessHack "BrightnessHack" +#define kMacroInversion "Macro Inversion" +#define kMacroTranslation "Macro Translation" +#define kMaxMacroTime "MaximumMacroTime" + +// 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) +#define kOutputBytes 2 // two bytes of Macro Inversion are used to specify output +#define kModifierBytes 4 // 4 bytes specify modifier key match criteria +#define kOutputBytesOffset (kIgnoreBytes+0) +#define kModifierBytesOffset (kIgnoreBytes+kOutputBytes+0) +#define kPrefixBytes (kIgnoreBytes+kOutputBytes+kModifierBytes) +#define kSequenceBytesOffset (kPrefixBytes+0) +#define kMinMacroInversion (kPrefixBytes+2) + +// Constants for other services to communicate with + +#define kIOHIDSystem "IOHIDSystem" // ============================================================================= // ApplePS2Keyboard Class Implementation // -OSDefineMetaClassAndStructors(ApplePS2Keyboard, IOService); +// get some keyboard id information from IOHIDFamily/IOHIDKeyboard.h and Gestalt.h +//#define APPLEPS2KEYBOARD_DEVICE_TYPE 205 // Generic ISO keyboard +#define APPLEPS2KEYBOARD_DEVICE_TYPE 3 // Unknown ANSI keyboard + +OSDefineMetaClassAndStructors(ApplePS2Keyboard, IOHIKeyboard); + +UInt32 ApplePS2Keyboard::deviceType() +{ + OSNumber *xml_handlerID; + UInt32 ret_id; + + if ( (xml_handlerID = OSDynamicCast( OSNumber, getProperty("alt_handler_id"))) ) + ret_id = xml_handlerID->unsigned32BitValue(); + else + ret_id = APPLEPS2KEYBOARD_DEVICE_TYPE; + + return ret_id; +} + +UInt32 ApplePS2Keyboard::interfaceID() { return NX_EVS_DEVICE_INTERFACE_ADB; } + +UInt32 ApplePS2Keyboard::maxKeyCodes() { return NX_NUMKEYCODES; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -75,7 +128,7 @@ static const char* parseHex(const char *psz, char term1, char term2, unsigned& o return psz; } -static bool parseRemap(const char *psz, UInt16 &scanFrom, UInt32& scanTo) +static bool parseRemap(const char *psz, UInt16 &scanFrom, UInt16& scanTo) { // psz is of the form: "scanfrom=scanto", examples: // non-extended: "1d=3a" @@ -88,7 +141,7 @@ static bool parseRemap(const char *psz, UInt16 &scanFrom, UInt32& scanTo) return false; scanFrom = n; psz = parseHex(psz+1, '\n', ';', n); - if (NULL == psz) + if (NULL == psz || n > 0xFFFF) return false; scanTo = n; return true; @@ -120,20 +173,35 @@ bool ApplePS2Keyboard::init(OSDictionary * dict) _sleepEjectTimer = 0; _cmdGate = 0; + _fkeymode = 0; + _fkeymodesupported = false; + _keysStandard = 0; + _keysSpecial = 0; _f12ejectdelay = 250; // default is 250 ms + // initialize ACPI support for keyboard backlight + _provider = 0; + _backlightLevels = 0; + + _logscancodes = 0; + _brightnessHack = false; + + // initalize macro translation + _macroInversion = 0; + _macroTranslation = 0; + _macroBuffer = 0; + _macroCurrent = 0; + _macroMax = 0; + _macroMaxTime = 25000000ULL; + _macroTimer = 0; + _ignoreCapsLedChange = false; // start out with all keys up bzero(_keyBitVector, sizeof(_keyBitVector)); // make separate copy of ADB translation table. - for (int i = 0; i < ADB_CONVERTER_LEN; i++) { - _PS2ToHIDMap[i].usagePage = kHIDPage_KeyboardOrKeypad; - _PS2ToHIDMap[i].usage = PS2ToHIDMapStock[i]; - } - - bcopy(ExtendedPS2ToHIDStockMap, &_PS2ToHIDMap[256], sizeof(ExtendedPS2ToHIDStockMap)); + bcopy(PS2ToADBMapStock, _PS2ToADBMapMapped, sizeof(_PS2ToADBMapMapped)); // Setup the PS2 -> PS2 scan code mapper for (int i = 0; i < countof(_PS2ToPS2Map); i++) @@ -142,7 +210,6 @@ bool ApplePS2Keyboard::init(OSDictionary * dict) // first half of map is normal scan codes, second half is extended scan codes (e0) _PS2ToPS2Map[i] = i; } - bcopy(_PS2flagsStock, _PS2flags, sizeof(_PS2flags)); return true; @@ -196,9 +263,45 @@ ApplePS2Keyboard* ApplePS2Keyboard::probe(IOService * provider, SInt32 * score) loadBreaklessPS2(config, "Breakless PS2"); // now load PS2 -> ADB configuration data - loadCustomHIDMap(config, "Custom ADB Map"); + loadCustomADBMap(config, "Custom ADB Map"); + + // determine if _fkeymode property should be handled in setParamProperties + _keysStandard = OSDynamicCast(OSArray, config->getObject(kFunctionKeysStandard)); + _keysSpecial = OSDynamicCast(OSArray, config->getObject(kFunctionKeysSpecial)); + _fkeymodesupported = _keysStandard && _keysSpecial; + if (_fkeymodesupported) + { + setProperty(kHIDFKeyMode, (uint64_t)0, 64); + _keysStandard->retain(); + _keysSpecial->retain(); + loadCustomPS2Map(_keysSpecial); + } + else + { + _keysStandard = NULL; + _keysSpecial = NULL; + } + + // load custom macro data + _macroTranslation = loadMacroData(config, kMacroTranslation); + _macroInversion = loadMacroData(config, kMacroInversion); + if (_macroInversion) + { + int max = 0; + for (OSData** p = _macroInversion; *p; p++) + { + int length = (*p)->getLength()-kPrefixBytes; + if (length > max) + max = length; + } + _macroBuffer = new UInt8[max*kPacketLength]; + _macroMax = max; + } } + // now copy to our PS2ToADBMap -- working copy... + bcopy(_PS2ToADBMapMapped, _PS2ToADBMap, sizeof(_PS2ToADBMap)); + // populate rest of values via setParamProperties setParamPropertiesGated(config); OSSafeReleaseNULL(config); @@ -278,6 +381,66 @@ bool ApplePS2Keyboard::start(IOService * provider) return false; } + // get IOACPIPlatformDevice for Device (PS2K) + //REVIEW: should really look at the parent chain for IOACPIPlatformDevice instead. + _provider = (IOACPIPlatformDevice*)IORegistryEntry::fromPath("IOService:/AppleACPIPlatformExpert/PS2K"); + + // + // get keyboard backlight levels for ACPI based backlight keys + // + + OSObject* result = 0; + if (_provider) do + { + // check for brightness methods + if (kIOReturnSuccess != _provider->validateObject("KKCL") || kIOReturnSuccess != _provider->validateObject("KKCM") || kIOReturnSuccess != _provider->validateObject("KKQC")) + { + DEBUG_LOG("ps2bl: KKCL, KKCM, KKQC methods not found in DSDT\n"); + break; + } + + // methods are there, so now try to collect brightness levels + if (kIOReturnSuccess != _provider->evaluateObject("KKCL", &result)) + { + DEBUG_LOG("ps2bl: KKCL returned error\n"); + break; + } + OSArray* array = OSDynamicCast(OSArray, result); + if (!array) + { + DEBUG_LOG("ps2bl: KKCL returned non-array package\n"); + break; + } + int count = array->getCount(); + if (count < 2) + { + DEBUG_LOG("ps2bl: KKCL returned invalid package\n"); + break; + } + _backlightCount = count; + _backlightLevels = new int[_backlightCount]; + if (!_backlightLevels) + { + DEBUG_LOG("ps2bl: _backlightLevels new int[] failed\n"); + break; + } + for (int i = 0; i < _backlightCount; i++) + { + OSNumber* num = OSDynamicCast(OSNumber, array->getObject(i)); + int brightness = num ? num->unsigned32BitValue() : 0; + _backlightLevels[i] = brightness; + } +#ifdef DEBUG_VERBOSE + DEBUG_LOG("ps2bl: Keyboard backlight levels: { "); + for (int i = 0; i < _backlightCount; i++) + DEBUG_LOG("%d, ", _backlightLevels[i]); + DEBUG_LOG("}\n"); +#endif + break; + } while (false); + + OSSafeReleaseNULL(result); + // // Lock the controller during initialization // @@ -290,27 +453,20 @@ bool ApplePS2Keyboard::start(IOService * provider) initKeyboard(); -// // -// // Set NumLock State to On (if specified). -// // -// -// if (_numLockOnAtBoot) -// setNumLock(true); + // + // Set NumLock State to On (if specified). + // + + if (_numLockOnAtBoot) + setNumLock(true); pWorkLoop->addEventSource(_sleepEjectTimer); pWorkLoop->addEventSource(_cmdGate); - // - // Construct HID Wrapper - // - _hidWrapper = OSTypeAlloc(VoodooPS2KeyboardHIDWrapper); - if (_hidWrapper == nullptr || - !_hidWrapper->init() || - !_hidWrapper->attach(this) || - !_hidWrapper->start(this)) { - IOLog("%s: HID Wrapper fail :(", getName()); - return nullptr; - } + // _macroTimer is used in for macro inversion + _macroTimer = IOTimerEventSource::timerEventSource(this, OSMemberFunctionCast(IOTimerEventSource::Action, this, &ApplePS2Keyboard::onMacroTimer)); + if (_macroTimer) + pWorkLoop->addEventSource(_macroTimer); // // Install our driver's interrupt handler, for asynchronous data delivery. @@ -331,6 +487,11 @@ bool ApplePS2Keyboard::start(IOService * provider) _device->installPowerControlAction( this, OSMemberFunctionCast(PS2PowerControlAction,this, &ApplePS2Keyboard::setDevicePowerState )); _powerControlHandlerInstalled = true; + + // + // Tell ACPIPS2Nub that we are interested in ACPI notifications + // + //setProperty(kDeliverNotifications, true); DEBUG_LOG("ApplePS2Keyboard::start leaving.\n"); @@ -354,8 +515,7 @@ void ApplePS2Keyboard::loadCustomPS2Map(OSArray* pArray) if (';' == *psz) continue; // otherwise, try to parse it - UInt16 scanIn; - UInt32 scanOut; + UInt16 scanIn, scanOut; if (!parseRemap(psz, scanIn, scanOut)) { IOLog("VoodooPS2Keyboard: invalid custom PS2 map entry: \"%s\"\n", psz); @@ -414,7 +574,7 @@ void ApplePS2Keyboard::loadBreaklessPS2(OSDictionary* dict, const char* name) } } -void ApplePS2Keyboard::loadCustomHIDMap(OSDictionary* dict, const char* name) +void ApplePS2Keyboard::loadCustomADBMap(OSDictionary* dict, const char* name) { OSArray* pArray = OSDynamicCast(OSArray, dict->getObject(name)); if (NULL != pArray) @@ -430,27 +590,77 @@ void ApplePS2Keyboard::loadCustomHIDMap(OSDictionary* dict, const char* name) if (';' == *psz) continue; // otherwise, try to parse it - UInt16 scanIn; - UInt32 hidOut; - if (!parseRemap(psz, scanIn, hidOut)) + UInt16 scanIn, adbOut; + if (!parseRemap(psz, scanIn, adbOut)) { IOLog("VoodooPS2Keyboard: invalid custom ADB map entry: \"%s\"\n", psz); continue; } // must be normal scan code or extended, nothing else, adbOut is only a byte UInt8 exIn = scanIn >> 8; - if (exIn != 0 && exIn != 0xe0) + if ((exIn != 0 && exIn != 0xe0) || adbOut > 0xFF) { IOLog("VoodooPS2Keyboard: scan code invalid for ADB map entry: \"%s\"\n", psz); continue; } // modify PS2 to ADB map per remap entry int index = (scanIn & 0xff) + (exIn == 0xe0 ? ADB_CONVERTER_EX_START : 0); - assert(index < countof(_PS2ToHIDMap)); - _PS2ToHIDMap[index].usagePage = hidOut >> 16; - _PS2ToHIDMap[index].usage = hidOut & 0xFFFF; + assert(index < countof(_PS2ToADBMapMapped)); + _PS2ToADBMapMapped[index] = adbOut; + } + } +} + +OSData** ApplePS2Keyboard::loadMacroData(OSDictionary* dict, const char* name) +{ + OSData** result = 0; + OSArray* pArray = OSDynamicCast(OSArray, dict->getObject(name)); + if (NULL != pArray) + { + // count valid entries + int total = 0; + int count = pArray->getCount(); + for (int i = 0; i < count; i++) + { + if (OSData* pData = OSDynamicCast(OSData, pArray->getObject(i))) + { + int length = pData->getLength(); + if (length >= kMinMacroInversion && !(length & 0x01)) + { + const UInt8* p = static_cast(pData->getBytesNoCopy()); + if (p[0] == 0xFF && p[1] == 0xFF) + total++; + } + } + } + if (total) + { + // store valid entries + result = new OSData*[total+1]; + if (result) + { + bzero(result, sizeof(char*)*(total+1)); + int index = 0; + for (int i = 0; i < count; i++) + { + if (OSData* pData = OSDynamicCast(OSData, pArray->getObject(i))) + { + int length = pData->getLength(); + if (length >= kMinMacroInversion && !(length & 0x01)) + { + const UInt8* p = static_cast(pData->getBytesNoCopy()); + if (p[0] == 0xFF && p[1] == 0xFF) + { + result[index++] = pData; + pData->retain(); + } + } + } + } + } } } + return result; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -474,6 +684,29 @@ void ApplePS2Keyboard::setParamPropertiesGated(OSDictionary * dict) _f12ejectdelay = num->unsigned32BitValue(); setProperty(kHIDF12EjectDelay, _f12ejectdelay, 32); } + // get time between keys part of a macro "inversion" + if (OSNumber* num = OSDynamicCast(OSNumber, dict->getObject(kMaxMacroTime))) + { + _macroMaxTime = num->unsigned64BitValue(); + setProperty(kMaxMacroTime, _macroMaxTime, 64); + } + + if (_fkeymodesupported) + { + // get function key mode + UInt32 oldfkeymode = _fkeymode; + if (OSNumber* num = OSDynamicCast(OSNumber, dict->getObject(kHIDFKeyMode))) + { + _fkeymode = num->unsigned32BitValue(); + setProperty(kHIDFKeyMode, _fkeymode, 32); + } + if (oldfkeymode != _fkeymode) + { + OSArray* keys = _fkeymode ? _keysStandard : _keysSpecial; + assert(keys); + loadCustomPS2Map(keys); + } + } // // Configure user preferences from Info.plist @@ -481,11 +714,12 @@ void ApplePS2Keyboard::setParamPropertiesGated(OSDictionary * dict) OSBoolean* xml = OSDynamicCast(OSBoolean, dict->getObject(kSwapCapsLockLeftControl)); if (xml) { if (xml->isTrue()) { - _PS2ToHIDMap[0x3a].usage = PS2ToHIDMapStock[0x1d]; - _PS2ToHIDMap[0x1d].usage = PS2ToHIDMapStock[0x3a]; - } else { - _PS2ToHIDMap[0x3a].usage = PS2ToHIDMapStock[0x3a]; - _PS2ToHIDMap[0x1d].usage = PS2ToHIDMapStock[0x1d]; + _PS2ToADBMap[0x3a] = _PS2ToADBMapMapped[0x1d]; + _PS2ToADBMap[0x1d] = _PS2ToADBMapMapped[0x3a]; + } + else { + _PS2ToADBMap[0x3a] = _PS2ToADBMapMapped[0x3a]; + _PS2ToADBMap[0x1d] = _PS2ToADBMapMapped[0x1d]; } setProperty(kSwapCapsLockLeftControl, xml->isTrue() ? kOSBooleanTrue : kOSBooleanFalse); } @@ -494,20 +728,29 @@ void ApplePS2Keyboard::setParamPropertiesGated(OSDictionary * dict) if (xml) { if (xml->isTrue()) { _swapcommandoption = true; - _PS2ToHIDMap[0x38].usage = kHIDUsage_KeyboardLeftGUI; // Left Alt -> Left GUI - _PS2ToHIDMap[0x15b].usage = kHIDUsage_KeyboardLeftAlt; // Left GUI -> Left Alt - _PS2ToHIDMap[0x138].usage = kHIDUsage_KeyboardRightGUI; // Right Alt -> Right GUI - _PS2ToHIDMap[0x15c].usage = kHIDUsage_KeyboardRightAlt; // Right GUI -> Right Alt - } else { + _PS2ToADBMap[0x38] = _PS2ToADBMapMapped[0x15b]; + _PS2ToADBMap[0x15b] = _PS2ToADBMapMapped[0x38]; + _PS2ToADBMap[0x138] = _PS2ToADBMapMapped[0x15c]; + _PS2ToADBMap[0x15c] = _PS2ToADBMapMapped[0x138]; + } + else { _swapcommandoption = false; - _PS2ToHIDMap[0x38].usage = kHIDUsage_KeyboardLeftAlt; - _PS2ToHIDMap[0x15b].usage = kHIDUsage_KeyboardLeftGUI; - _PS2ToHIDMap[0x138].usage = kHIDUsage_KeyboardRightAlt; - _PS2ToHIDMap[0x15c].usage = kHIDUsage_KeyboardRightGUI; + _PS2ToADBMap[0x38] = _PS2ToADBMapMapped[0x38]; + _PS2ToADBMap[0x15b] = _PS2ToADBMapMapped[0x15b]; + _PS2ToADBMap[0x138] = _PS2ToADBMapMapped[0x138]; + _PS2ToADBMap[0x15c] = _PS2ToADBMapMapped[0x15c]; } setProperty(kSwapCommandOption, xml->isTrue() ? kOSBooleanTrue : kOSBooleanFalse); } + // special hack for HP Envy brightness + xml = OSDynamicCast(OSBoolean, dict->getObject(kBrightnessHack)); + if (xml && xml->isTrue()) + { + //REVIEW: should really read the key assignments via Info.plist instead of hardcoding to F2/F3 + _brightnessHack = true; + } + if ((xml = OSDynamicCast(OSBoolean, dict->getObject(kRemapPrntScr)))) { _remapPrntScr = xml->getValue(); @@ -525,30 +768,48 @@ void ApplePS2Keyboard::setParamPropertiesGated(OSDictionary * dict) _numLockOnAtBoot = xml->getValue(); setProperty(kNumLockOnAtBoot, _numLockOnAtBoot); } - + + // these two options are mutually exclusive + // kMakeApplicationKeyAppleFN is ignored if kMakeApplicationKeyRightWindows is set + bool temp = false; xml = OSDynamicCast(OSBoolean, dict->getObject(kMakeApplicationKeyRightWindows)); if (xml) { if (xml->isTrue()) { - _PS2ToHIDMap[0x15d].usage = _swapcommandoption ? kHIDUsage_KeyboardRightAlt : kHIDUsage_KeyboardRightGUI; + _PS2ToADBMap[0x15d] = _swapcommandoption ? 0x3d : 0x36; // ADB = right-option/right-command + temp = true; } else { - _PS2ToHIDMap[0x15d].usage = kHIDUsage_KeyboardApplication; + _PS2ToADBMap[0x15d] = _PS2ToADBMapMapped[0x15d]; } setProperty(kMakeApplicationKeyRightWindows, xml->isTrue() ? kOSBooleanTrue : kOSBooleanFalse); } + // not implemented yet (Note: maybe not true any more) + // Apple Fn key works well, but no combined key action was made. + xml = OSDynamicCast(OSBoolean, dict->getObject(kMakeApplicationKeyAppleFN)); + if (xml) { + if (!temp) { + if (xml->isTrue()) { + _PS2ToADBMap[0x15d] = 0x3f; // ADB = AppleFN + } + else { + _PS2ToADBMap[0x15d] = _PS2ToADBMapMapped[0x15d]; + } + } + setProperty(kMakeApplicationKeyAppleFN, xml->isTrue() ? kOSBooleanTrue : kOSBooleanFalse); + } xml = OSDynamicCast(OSBoolean, dict->getObject(kMakeRightModsHangulHanja)); if (xml) { if (xml->isTrue()) { - _PS2ToHIDMap[0x138].usage = kHIDUsage_KeyboardLANG1; // Right alt becomes Hangul - _PS2ToHIDMap[0x11d].usage = kHIDUsage_KeyboardLANG2; // Right control becomes Hanja + _PS2ToADBMap[0x138] = _PS2ToADBMapMapped[0xf2]; // Right alt becomes Hangul + _PS2ToADBMap[0x11d] = _PS2ToADBMapMapped[0xf1]; // Right control becomes Hanja } else { if (_swapcommandoption) - _PS2ToHIDMap[0x138].usage = kHIDUsage_KeyboardRightGUI; + _PS2ToADBMap[0x138] = _PS2ToADBMapMapped[0x15c]; else - _PS2ToHIDMap[0x138].usage = kHIDUsage_KeyboardRightAlt; - _PS2ToHIDMap[0x11d].usage = kHIDUsage_KeyboardRightControl; + _PS2ToADBMap[0x138] = _PS2ToADBMapMapped[0x138]; + _PS2ToADBMap[0x11d] = _PS2ToADBMapMapped[0x11d]; } setProperty(kMakeRightModsHangulHanja, xml->isTrue() ? kOSBooleanTrue : kOSBooleanFalse); } @@ -558,15 +819,34 @@ void ApplePS2Keyboard::setParamPropertiesGated(OSDictionary * dict) xml = OSDynamicCast(OSBoolean, dict->getObject(kUseISOLayoutKeyboard)); if (xml) { if (xml->isTrue()) { - _PS2ToHIDMap[0x29].usage = kHIDUsage_KeyboardNonUSBackslash; - _PS2ToHIDMap[0x56].usage = kHIDUsage_KeyboardGraveAccentAndTilde; + _PS2ToADBMap[0x29] = _PS2ToADBMapMapped[0x56]; //Europe2 '' + _PS2ToADBMap[0x56] = _PS2ToADBMapMapped[0x29]; //Grave '~' } else { - _PS2ToHIDMap[0x29].usage = kHIDUsage_KeyboardGraveAccentAndTilde; - _PS2ToHIDMap[0x56].usage = kHIDUsage_KeyboardNonUSBackslash; + _PS2ToADBMap[0x29] = _PS2ToADBMapMapped[0x29]; + _PS2ToADBMap[0x56] = _PS2ToADBMapMapped[0x56]; } setProperty(kUseISOLayoutKeyboard, xml->isTrue() ? kOSBooleanTrue : kOSBooleanFalse); } + + if (OSNumber* num = OSDynamicCast(OSNumber, dict->getObject(kLogScanCodes))) { + _logscancodes = num->unsigned32BitValue(); + setProperty(kLogScanCodes, num); + } +} + +IOReturn ApplePS2Keyboard::setParamProperties(OSDictionary *dict) +{ + ////IOReturn result = super::setParamProperties(dict); + if (_cmdGate) + { + // syncronize through workloop... + ////_cmdGate->runAction(OSMemberFunctionCast(IOCommandGate::Action, this, &ApplePS2Keyboard::setParamPropertiesGated), dict); + setParamPropertiesGated(dict); + } + + return super::setParamProperties(dict); + ////return result; } IOReturn ApplePS2Keyboard::setProperties(OSObject *props) @@ -593,11 +873,6 @@ void ApplePS2Keyboard::stop(IOService * provider) assert(_device == provider); - if (_hidWrapper) { - _hidWrapper->terminate(); - _hidWrapper->release(); - } - // // Disable the keyboard itself, so that it may stop reporting key events. // @@ -620,6 +895,12 @@ void ApplePS2Keyboard::stop(IOService * provider) _sleepEjectTimer->release(); _sleepEjectTimer = 0; } + if (_macroTimer) + { + pWorkLoop->removeEventSource(_macroTimer); + _macroTimer->release(); + _macroTimer = 0; + } } // @@ -642,6 +923,43 @@ void ApplePS2Keyboard::stop(IOService * provider) OSSafeReleaseNULL(_device); + // + // Release ACPI provider for PS2K ACPI device + // + OSSafeReleaseNULL(_provider); + + // + // Release data related to keyboard backlight + // + if (_backlightLevels) + { + delete[] _backlightLevels; + _backlightLevels = 0; + } + + OSSafeReleaseNULL(_keysStandard); + OSSafeReleaseNULL(_keysSpecial); + + if (_macroInversion) + { + for (OSData** p = _macroInversion; *p; p++) + (*p)->release(); + delete[] _macroInversion; + _macroInversion = 0; + } + if (_macroTranslation) + { + for (OSData** p = _macroTranslation; *p; p++) + (*p)->release(); + delete[] _macroTranslation; + _macroTranslation = 0; + } + if (_macroBuffer) + { + delete[] _macroBuffer; + _macroBuffer = 0; + } + super::stop(provider); } @@ -669,17 +987,29 @@ IOReturn ApplePS2Keyboard::message(UInt32 type, IOService* provider, void* argum { // mark packet with timestamp clock_get_uptime((uint64_t*)(&packet[kPacketTimeOffset])); - dispatchKeyboardEventWithPacket(packet); + if (!_macroInversion || !invertMacros(packet)) + { + // normal packet + dispatchKeyboardEventWithPacket(packet); + } } if (3 == packet[0] || 4 == packet[0]) { // code 3 and 4 indicate send both make and break packet[0] -= 2; clock_get_uptime((uint64_t*)(&packet[kPacketTimeOffset])); - dispatchKeyboardEventWithPacket(packet); + if (!_macroInversion || !invertMacros(packet)) + { + // normal packet (make) + dispatchKeyboardEventWithPacket(packet); + } clock_get_uptime((uint64_t*)(&packet[kPacketTimeOffset])); packet[1] |= 0x80; // break code - dispatchKeyboardEventWithPacket(packet); + if (!_macroInversion || !invertMacros(packet)) + { + // normal packet (break) + dispatchKeyboardEventWithPacket(packet); + } } } } @@ -713,7 +1043,7 @@ IOReturn ApplePS2Keyboard::message(UInt32 type, IOService* provider, void* argum if (!keystroke->eatKey) { // the key is consumed keystroke->eatKey = true; -// dispatchKeyboardEventX(keystroke->adbKeyCode, keystroke->goingDown, keystroke->time); + dispatchKeyboardEventX(keystroke->adbKeyCode, keystroke->goingDown, keystroke->time); } } break; @@ -726,6 +1056,10 @@ IOReturn ApplePS2Keyboard::message(UInt32 type, IOService* provider, void* argum PS2InterruptResult ApplePS2Keyboard::interruptOccurred(UInt8 data) // PS2InterruptAction { + ////IOLog("ps2interrupt: scanCode = %02x\n", data); + ////uint64_t time; + ////clock_get_uptime(&time); + ////IOLog("ps2interrupt(%lld): scanCode = %02x\n", time, data); // // This will be invoked automatically from our device when asynchronous @@ -843,8 +1177,11 @@ void ApplePS2Keyboard::packetReady() UInt8* packet = _ringBuffer.tail(); if (0x00 != packet[0]) { - // normal packet - dispatchKeyboardEventWithPacket(packet); + if (!_macroInversion || !invertMacros(packet)) + { + // normal packet + dispatchKeyboardEventWithPacket(packet); + } } else { @@ -855,6 +1192,188 @@ void ApplePS2Keyboard::packetReady() } } +bool ApplePS2Keyboard::compareMacro(const UInt8* buffer, const UInt8* data, int count) +{ + while (count--) + { + if (buffer[0] != data[0] || buffer[1] != data[1]) + return false; + buffer += kPacketLength; + data += kPacketKeyDataLength; + } + return true; +} + +bool ApplePS2Keyboard::invertMacros(const UInt8* packet) +{ + assert(_macroInversion); + + if (!_macroTimer || !_macroBuffer) + return false; + + if (_macroCurrent > 0) + { + // cancel macro conversion if packet arrives too late + uint64_t now_ns; + absolutetime_to_nanoseconds(*(uint64_t*)(&packet[kPacketTimeOffset]), &now_ns); + uint64_t prev; + absolutetime_to_nanoseconds(*(uint64_t*)(&_macroBuffer[(_macroCurrent-1)*kPacketLength+kPacketTimeOffset]), &prev); + if (now_ns-prev > _macroMaxTime) + dispatchInvertBuffer(); +#if 0 // for testing min/max between macro segments + uint64_t diff = now_ns-prev; + static uint64_t diffmin = UINT64_MAX, diffmax = 0; + if (diff > diffmax) diffmax = diff; + if (diff < diffmin) diffmin = diff; + IOLog("diffmin=%lld, diffmax=%lld\n", diffmin, diffmax); +#endif + } + + // add current packet to macro buffer for comparison + memcpy(_macroBuffer+_macroCurrent*kPacketLength, packet, kPacketLength); + int buffered = _macroCurrent+1; + int total = buffered*kPacketKeyDataLength; + // compare against macro inversions + for (OSData** p = _macroInversion; *p; p++) + { + int length = (*p)->getLength()-kPrefixBytes; + if (total <= length) + { + const UInt8* data = static_cast((*p)->getBytesNoCopy()); + if (compareMacro(_macroBuffer, data+kSequenceBytesOffset, buffered)) + { + if (total == length) + { + // get modifier mask/compare from macro definition + UInt16 mask = (static_cast(data[kModifierBytesOffset+0]) << 8) + data[kModifierBytesOffset+1]; + UInt16 compare = (static_cast(data[kModifierBytesOffset+2]) << 8) + data[kModifierBytesOffset+3]; + if ((0xFFFF == compare && (_PS2modifierState & mask)) || ((_PS2modifierState & mask) == compare)) + { + // exact match causes macro inversion + // grab bytes from macro definition + _macroBuffer[0] = data[kOutputBytesOffset+0]; + _macroBuffer[1] = data[kOutputBytesOffset+1]; + // dispatch constructed packet (timestamp is stamp on first macro packet) + dispatchKeyboardEventWithPacket(_macroBuffer); + cancelTimer(_macroTimer); + _macroCurrent = 0; + return true; + } + } + else + { + // partial match, keep waiting for full match + cancelTimer(_macroTimer); + setTimerTimeout(_macroTimer, _macroMaxTime); + _macroCurrent++; + return true; + } + } + } + } + // no match, so... empty macro buffer that may have been existing... + if (_macroCurrent > 0) + dispatchInvertBuffer(); + + return false; +} + +void ApplePS2Keyboard::onMacroTimer() +{ + DEBUG_LOG("ApplePS2Keyboard::onMacroTimer\n"); + + // timers have a very high priority, packets may have been placed in the + // input queue already. + + // by calling packetReady, these packets are processed before dealing with + // the timer (the packets may have arrived before the timer) + packetReady(); + + // after all packets have been processed, ok to check for time expiration + if (_macroCurrent > 0) + { + uint64_t now_abs, now_ns; + clock_get_uptime(&now_abs); + absolutetime_to_nanoseconds(now_abs, &now_ns); + uint64_t prev; + absolutetime_to_nanoseconds(*(uint64_t*)(&_macroBuffer[(_macroCurrent-1)*kPacketLength+kPacketTimeOffset]), &prev); + if (now_ns-prev > _macroMaxTime) + dispatchInvertBuffer(); + } +} + +void ApplePS2Keyboard::dispatchInvertBuffer() +{ + UInt8* packet = _macroBuffer; + for (int i = 0; i < _macroCurrent; i++) + { + // dispatch constructed packet + dispatchKeyboardEventWithPacket(packet); + packet += kPacketLength; + } + _macroCurrent = 0; + cancelTimer(_macroTimer); +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + +// +// Note: trying for ACPI backlight control for ASUS notebooks +// +// This one did work, so leaving this in. It is done in a generic way such that +// it can be used on more than just ASUS laptops, provided you can figure out +// how to implememnt the KKQC, KKCM, and KKCL methods. +// + +void ApplePS2Keyboard::modifyKeyboardBacklight(int keyCode, bool goingDown) +{ + assert(_provider); + assert(_backlightLevels); + + // get current brightness level + UInt32 result; + if (kIOReturnSuccess != _provider->evaluateInteger("KKQC", &result)) + { + DEBUG_LOG("ps2bl: KKQC returned error\n"); + return; + } + int current = result; +#ifdef DEBUG_VERBOSE + if (goingDown) + DEBUG_LOG("ps2bl: Current keyboard backlight: %d\n", current); +#endif + // calculate new brightness level, find current in table >= entry in table + // note first two entries in table are ac-power/battery + int index = 0; + while (index < _backlightCount) + { + if (_backlightLevels[index] >= current) + break; + ++index; + } + // move to next or previous + index += (keyCode == 0x4e ? +1 : -1); + if (index >= _backlightCount) + index = _backlightCount - 1; + if (index < 0) + index = 0; +#ifdef DEBUG_VERBOSE + if (goingDown) + DEBUG_LOG("ps2bl: setting keyboard backlight %d\n", _backlightLevels[index]); +#endif + OSNumber* num = OSNumber::withNumber(_backlightLevels[index], 32); + if (!num) + { + DEBUG_LOG("ps2bl: OSNumber::withNumber failed\n"); + return; + } + if (goingDown && kIOReturnSuccess != _provider->evaluateObject("KKCM", NULL, (OSObject**)&num, 1)) + { + DEBUG_LOG("ps2bl: KKCM returned error\n"); + } + num->release(); +} + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void ApplePS2Keyboard::onSleepEjectTimer() @@ -873,7 +1392,7 @@ void ApplePS2Keyboard::onSleepEjectTimer() { uint64_t now_abs; clock_get_uptime(&now_abs); - dispatchKeyboardEventX(kHIDPage_Consumer, kHIDUsage_Csmr_Eject, true, now_abs); + dispatchKeyboardEventX(0x92, true, now_abs); break; } } @@ -888,11 +1407,17 @@ bool ApplePS2Keyboard::dispatchKeyboardEventWithPacket(const UInt8* packet) UInt8 extended = packet[0] - 1; UInt8 scanCode = packet[1]; + +#ifdef DEBUG_VERBOSE + DEBUG_LOG("%s: PS/2 scancode %s 0x%x\n", getName(), extended ? "extended" : "", scanCode); +#endif unsigned keyCodeRaw = scanCode & ~kSC_UpBit; bool goingDown = !(scanCode & kSC_UpBit); unsigned keyCode; uint64_t now_abs = *(uint64_t*)(&packet[kPacketTimeOffset]); + uint64_t now_ns; + absolutetime_to_nanoseconds(now_abs, &now_ns); // // Convert the scan code into a key code index. @@ -910,20 +1435,36 @@ bool ApplePS2Keyboard::dispatchKeyboardEventWithPacket(const UInt8* packet) if (scanCode == 0xf2 || scanCode == 0xf1) { clock_get_uptime(&now_abs); - dispatchKeyboardEventX(_PS2ToHIDMap[scanCode], true, now_abs); + dispatchKeyboardEventX(_PS2ToADBMap[scanCode], true, now_abs); clock_get_uptime(&now_abs); - dispatchKeyboardEventX(_PS2ToHIDMap[scanCode], false, now_abs); + dispatchKeyboardEventX(_PS2ToADBMap[scanCode], false, now_abs); return true; } // Allow PS2 -> PS2 map to work, look in normal part of the table keyCode = _PS2ToPS2Map[keyCodeRaw]; + +#ifdef DEBUG_VERBOSE + if (keyCode != keyCodeRaw) + DEBUG_LOG("%s: keycode translated from=0x%02x to=0x%04x\n", getName(), keyCodeRaw, keyCode); +#endif } else { // allow PS2 -> PS2 map to work, look in extended part of the table keyCodeRaw += KBV_NUM_SCANCODES; keyCode = _PS2ToPS2Map[keyCodeRaw]; + +#ifdef DEBUG_VERBOSE + if (keyCode != keyCodeRaw) + DEBUG_LOG("%s: keycode translated from=0xe0%02x to=0x%04x\n", getName(), keyCodeRaw, keyCode); +#endif + // handle special cases + switch (keyCodeRaw) + { + case 0x012a: // header or trailer for PrintScreen + return false; + } } // tracking modifier key state @@ -933,15 +1474,85 @@ bool ApplePS2Keyboard::dispatchKeyboardEventWithPacket(const UInt8* packet) goingDown ? _PS2modifierState |= mask : _PS2modifierState &= ~mask; } + // codes e0f0 through e0ff can be used to call back into ACPI methods on this device + if (keyCode >= 0x01f0 && keyCode <= 0x01ff && _provider != NULL) + { + // evaluate RKA[0-F] for these keys + char method[5] = "RKAx"; + char n = keyCode - 0x01f0; + method[3] = n < 10 ? n + '0' : n - 10 + 'A'; + if (OSNumber* num = OSNumber::withNumber(goingDown, 32)) + { + // call ACPI RKAx(Arg0=goingDown) + _provider->evaluateObject(method, NULL, (OSObject**)&num, 1); + num->release(); + } + } + // handle special cases switch (keyCode) { + case 0x45: // NumLock + if (_numLockSupport && (scanCode == 0xc5)) // NumLock -> Up + { + setNumLock(!numLock()); + return true; + } + else if (_numLockSupport && (scanCode == 0x45)) // NumLock -> Down + return false; + break; + + case 0x4e: // Numpad+ + case 0x4a: // Numpad- + if (_backlightLevels && checkModifierState(kMaskLeftControl|kMaskLeftAlt)) + { + // Ctrl+Alt+Numpad(+/-) => use to manipulate keyboard backlight + modifyKeyboardBacklight(keyCode, goingDown); + keyCode = 0; + } + else if (_brightnessHack && checkModifierState(kMaskLeftControl|kMaskLeftShift)) + { + // Ctrl+Shift+NumPad(+/0) => manipulate brightness (special hack for HP Envy) + // Fn+F2 generates e0 ab and so does Fn+F3 (we will null those out in ps2 map) + static unsigned keys[] = { 0x2a, 0x1d }; + // if Option key is down don't pull up on the Shift keys + int state = checkModifierState(kMaskLeftWindows) ? 1 : 0; + for (int i = state; i < countof(keys); i++) + if (KBV_IS_KEYDOWN(keys[i])) + dispatchKeyboardEventX(_PS2ToADBMap[keys[i]], false, now_abs); + dispatchKeyboardEventX(keyCode == 0x4e ? 0x90 : 0x91, goingDown, now_abs); + for (int i = state; i < countof(keys); i++) + if (KBV_IS_KEYDOWN(keys[i])) + dispatchKeyboardEventX(_PS2ToADBMap[keys[i]], true, now_abs); + keyCode = 0; + } + break; + + case 0x0153: // delete + // check for Ctrl+Alt+Delete? (three finger salute) + if (checkModifierState(kMaskLeftControl|kMaskLeftAlt)) + { + keyCode = 0; + if (!goingDown) + { + // Note: If OS X thinks the Command and Control keys are down at the time of + // receiving an ADB 0x7f (power button), it will unconditionaly and unsafely + // reboot the computer, much like the old PC/AT Ctrl+Alt+Delete! + // That's why we make sure Control (0x3b) and Alt (0x37) are up!! + dispatchKeyboardEventX(0x37, false, now_abs); + dispatchKeyboardEventX(0x3b, false, now_abs); + dispatchKeyboardEventX(0x7f, true, now_abs); + dispatchKeyboardEventX(0x7f, false, now_abs); + } + } + break; + case 0x015f: // sleep keyCode = 0; if (goingDown) { _timerFunc = kTimerSleep; - if (!_maxsleeppresstime) + if (_fkeymode || !_maxsleeppresstime) onSleepEjectTimer(); else setTimerTimeout(_sleepEjectTimer, (uint64_t)_maxsleeppresstime * 1000000); @@ -951,78 +1562,287 @@ bool ApplePS2Keyboard::dispatchKeyboardEventWithPacket(const UInt8* packet) cancelTimer(_sleepEjectTimer); } break; + + //REVIEW: this is getting a bit ugly + case 0x0054: // SysRq (PrntScr when combined with Alt modifier -left or right-) + if (!_remapPrntScr) + break; + case 0x0128: // alternate that cannot fnkeys toggle (discrete trackpad toggle) + { + + // PrntScr is handled specially by some keyboard devices. + // See: 5.19 on https://www.win.tue.nl/~aeb/linux/kbd/scancodes-5.html#mtek +#ifdef DEBUG + UInt16 debug_originalModifiers = _PS2modifierState; +#endif + // Force Alt (Left) key to be down when receiving this keycode, dont rely on KB firmware + _PS2modifierState &= ~kMaskRightAlt; + _PS2modifierState |= kMaskLeftAlt; + keyCode = 0x0137; // Rewrite keycode + +#ifdef DEBUG + IOLog("VoodooPS2Keyboard: special PrntScr: modifiersBefore=%#.4X modifiersAfter=%#.4X\n", debug_originalModifiers, _PS2modifierState); +#endif + + // Fall to the original PrntScr handling case + } + case 0x0137: // prt sc/sys rq + { + if (!_remapPrntScr) + break; + + /* Supported Voodoo PrntScr Key combinations: + PrntScr Enable/Disable touchpad + Windows+PrntScr Enable/Disable touchpad+keyboard + Ctrl+Alt+PrntScr Reset and enable touchpad + Shift+PrntScr Send SysRq scancode to the kernel + + Notes: + - Alt+Windows combo seems to be masked out by some keyboard devices and dont produce any ScanCode. + Dont rely on it. + */ + + unsigned origKeyCode = keyCode; + keyCode = 0; // Handle all these keycode variants internally + +#ifdef DEBUG + bool debug_control = checkModifierStateAny(kMaskLeftControl|kMaskRightControl); + bool debug_alt = checkModifierStateAny(kMaskLeftAlt|kMaskRightAlt); + bool debug_shift = checkModifierStateAny(kMaskLeftShift|kMaskRightShift); + bool debug_windows = checkModifierStateAny(kMaskLeftWindows|kMaskRightWindows); + + IOLog("VoodooPS2Keyboard: PrtScr:: goingDown=%s control=%s alt=%s shift=%s windows=%s modifiers=%d\n", + goingDown ? "Yes" : "No", + debug_control ? "Yes" : "No", + debug_alt ? "Yes" : "No", + debug_shift ? "Yes" : "No", + debug_windows ? "Yes" : "No", + _PS2modifierState); +#endif + + if (!goingDown) + break; + + if (checkModifierStateAny(kMaskLeftControl|kMaskRightControl)) + { + // Shift is ignored from this point onwards + if (checkModifierStateAny(kMaskLeftAlt|kMaskRightAlt)) + { + // Ctrl+Alt+PrntScr + IOLog("VoodooPS2Keyboard: Sending RESET signal to touchpad."); // Dont wrap into a DEBUG compilation condition since this should be a workaroung to be used on faulty states only + int val = 1; + _device->dispatchMessage(kPS2M_resetTouchpad, &val); // Reset touchpad + } + } + else + { + if (checkModifierState(kMaskLeftShift) || checkModifierState(kMaskRightShift)) + { + // Shift+PrntScr, no other modifiers present +#ifdef DEBUG + IOLog("VoodooPS2Keyboard: Sending SysRq virtual scancode 0x58"); +#endif + dispatchKeyboardEventX(0x58, true, now_abs); // Send SysRq to the kernel + dispatchKeyboardEventX(0x58, false, now_abs); + } + else + { + if (checkModifierStateAny(kMaskRightShift|kMaskLeftShift|kMaskRightAlt|kMaskLeftAlt)) + break; // Eat combinations where Ctrl is Up and Alt or Shift are Down (!Ctrl+[Alt|Shift]) + + bool enabled; + if (checkModifierStateAny(kMaskLeftWindows|kMaskRightWindows)) + { + // Windows+PrntScr + // Disable keyboard input along with the touchpad using Windows(Option)+prtsc, useful for 2-in-1 applications. +#ifdef DEBUG + IOLog("VoodooPS2Keyboard: Toggling keyboard+Touchpad enabled state."); +#endif + enabled = _disableInput; + _disableInput = !_disableInput; + _device->dispatchMessage(kPS2M_setDisableTouchpad, &enabled); // Sync Keyboard and Touchpad enabled states + } + else + { + // No other modifiers pressed down +#ifdef DEBUG + IOLog("VoodooPS2Keyboard: Toggling Touchpad enabled state."); +#endif + // Touchpad enable/disable: get current enabled status, and toggle it + _device->dispatchMessage(kPS2M_getDisableTouchpad, &enabled); + enabled = !enabled; + _device->dispatchMessage(kPS2M_setDisableTouchpad, &enabled); + } + } + + break; + } + + if (origKeyCode != 0x0137) + break; // do not fall through for 0x0128 + // fall through + } + case 0x0127: // alternate for fnkeys toggle (discrete fnkeys toggle) + keyCode = 0; + if (!goingDown) + break; + if (_fkeymodesupported) + { + // modify HIDFKeyMode via IOService... IOHIDSystem + if (IOService* service = IOService::waitForMatchingService(serviceMatching(kIOHIDSystem), 0)) + { + const OSObject* num = OSNumber::withNumber(!_fkeymode, 32); + const OSString* key = OSString::withCString(kHIDFKeyMode); + if (num && key) + { + if (OSDictionary* dict = OSDictionary::withObjects(&num, &key, 1)) + { + service->setProperties(dict); + dict->release(); + } + } + OSSafeReleaseNULL(num); + OSSafeReleaseNULL(key); + service->release(); + } + } + break; +#ifdef DEBUG + default: + IOLog("VoodooPS2Keyboard: Unhandled keycode: %#.4X\n", keyCode); +#endif } // If keyboard input is disabled drop the key code.. if (_disableInput && goingDown) keyCode=0; +#ifdef DEBUG + // allow hold Alt+numpad keys to type in arbitrary ADB key code + static int genADB = -1; + if (goingDown && checkModifierState(kMaskLeftAlt) && + ((keyCodeRaw >= 0x47 && keyCodeRaw <= 0x52 && keyCodeRaw != 0x4e && keyCodeRaw != 0x4a) || + (keyCodeRaw >= 0x02 && keyCodeRaw <= 0x0B))) + { + // map numpad scan codes to digits + static int map1[0x52-0x47+1] = { 7, 8, 9, -1, 4, 5, 6, -1, 1, 2, 3, 0 }; + static int map2[0x0B-0x02+1] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 0 }; + if (-1 == genADB) + genADB = 0; + int digit = keyCodeRaw >= 0x47 ? map1[keyCodeRaw-0x47] : map2[keyCodeRaw-0x02]; + if (-1 != digit) + genADB = genADB * 10 + digit; + DEBUG_LOG("%s: genADB = %d\n", getName(), genADB); + keyCode = 0; // eat it + } +#endif + // We have a valid key event -- dispatch it to our superclass. // map scan code to Apple code - const VoodooPS2HidElement &hidKeyCode = _PS2ToHIDMap[keyCode]; -// bool eatKey = false; + UInt8 adbKeyCode = _PS2ToADBMap[keyCode]; + bool eatKey = false; // special cases - if (hidKeyCode.usage == kHIDUsage_Csmr_Eject && hidKeyCode.usagePage == kHIDPage_Consumer) { - if (0 == _PS2modifierState) - { - if (goingDown) + switch (adbKeyCode) + { + case 0x92: // eject + if (0 == _PS2modifierState) { -// eatKey = true; - _timerFunc = kTimerEject; - if (!_f12ejectdelay) - onSleepEjectTimer(); + if (goingDown) + { + eatKey = true; + _timerFunc = kTimerEject; + if (!_f12ejectdelay) + onSleepEjectTimer(); + else + setTimerTimeout(_sleepEjectTimer, (uint64_t)_f12ejectdelay * 1000000); + } else - setTimerTimeout(_sleepEjectTimer, (uint64_t)_f12ejectdelay * 1000000); - } - else - { - cancelTimer(_sleepEjectTimer); + { + cancelTimer(_sleepEjectTimer); + } } - } + break; } + +#ifdef DEBUG_VERBOSE + if (adbKeyCode == DEADKEY && 0 != keyCode) + DEBUG_LOG("%s: Unknown ADB key for PS2 scancode: 0x%x\n", getName(), scanCode); + else + DEBUG_LOG("%s: ADB key code 0x%x %s\n", getName(), adbKeyCode, goingDown?"down":"up"); +#endif -#ifdef DEBUG - uint16_t debugCode = keyCode > KBV_NUM_SCANCODES ? (keyCode & 0xFF) | 0xe000 : keyCode; - IOLog("%s: Sending key %x = Page %x Usage %x %s\n", getName(), debugCode, hidKeyCode.usagePage, hidKeyCode.usage, goingDown ? "down" : "up"); +#ifdef DEBUG_LITE + int logscancodes = 2; +#else + int logscancodes = _logscancodes; #endif + if (logscancodes==2 || (logscancodes==1 && goingDown)) + { + if (keyCode == keyCodeRaw) + IOLog("%s: sending key %x=%x %s\n", getName(), keyCode > KBV_NUM_SCANCODES ? (keyCode & 0xFF) | 0xe000 : keyCode, adbKeyCode, goingDown?"down":"up"); + else + IOLog("%s: sending key %x=%x, %x=%x %s\n", getName(), keyCodeRaw > KBV_NUM_SCANCODES ? (keyCodeRaw & 0xFF) | 0xe000 : keyCodeRaw, keyCode > KBV_NUM_SCANCODES ? (keyCode & 0xFF) | 0xe000 : keyCode, keyCode > KBV_NUM_SCANCODES ? (keyCode & 0xFF) | 0xe000 : keyCode, adbKeyCode, goingDown?"down":"up"); + } // allow mouse/trackpad driver to have time of last keyboard activity // used to implement "PalmNoAction When Typing" and "OutsizeZoneNoAction When Typing" -// PS2KeyInfo info; -// info.time = now_ns; -// info.adbKeyCode = hidKeyCode.usage; -// info.goingDown = goingDown; -// info.eatKey = eatKey; -// -// _device->dispatchMessage(kPS2M_notifyKeyPressed, &info); + PS2KeyInfo info; + info.time = now_ns; + info.adbKeyCode = adbKeyCode; + info.goingDown = goingDown; + info.eatKey = eatKey; - // Convert ALT + Brightness to Keyboard Brightness - if (hidKeyCode.usagePage == kHIDPage_AppleVendorTopCase && checkModifierState(kMaskLeftAlt)) { - // Release left alt before sending brightness keys. macOS otherwise ignores the keypress - VoodooPS2HidElement altElem = _PS2ToHIDMap[0x38]; - dispatchKeyboardEventX(altElem, false, now_abs); - - if (hidKeyCode.usage == kHIDUsage_AV_TopCase_BrightnessUp) { - dispatchKeyboardEventX(kHIDPage_AppleVendorTopCase, kHIDUsage_AV_TopCase_IlluminationUp, goingDown, now_abs); - dispatchKeyboardEventX(altElem, true, now_abs); - return true; - } else if (hidKeyCode.usage == kHIDUsage_AV_TopCase_BrightnessDown) { - dispatchKeyboardEventX(kHIDPage_AppleVendorTopCase, kHIDUsage_AV_TopCase_IlluminationDown, goingDown, now_abs); - dispatchKeyboardEventX(altElem, true, now_abs); - return true; + _device->dispatchMessage(kPS2M_notifyKeyPressed, &info); + + //REVIEW: work around for caps lock bug on Sierra 10.12... + if (adbKeyCode == 0x39 && version_major >= 16) + { + // Mojave 10.14 only needs a part of the workaround: + // https://github.com/RehabMan/OS-X-Voodoo-PS2-Controller/issues/142#issuecomment-529813842 + if (goingDown || version_major >= 18) + { + DEBUG_LOG("%s: Caps Lock goingDown: 0x%x\n", getName(), goingDown); + _ignoreCapsLedChange = true; + clock_get_uptime(&now_abs); + dispatchKeyboardEventX(adbKeyCode, true, now_abs); + clock_get_uptime(&now_abs); + dispatchKeyboardEventX(adbKeyCode, false, now_abs); } + if (goingDown && version_major < 18) { + static bool firsttime = true; + if (!firsttime) + { + clock_get_uptime(&now_abs); + dispatchKeyboardEventX(adbKeyCode, true, now_abs); + clock_get_uptime(&now_abs); + dispatchKeyboardEventX(adbKeyCode, false, now_abs); + } + firsttime = false; + } + return true; } - - if (hidKeyCode.usage != 0 && hidKeyCode.usagePage != 0) + + if (keyCode && !info.eatKey) { // dispatch to HID system if (goingDown || !(_PS2flags[keyCodeRaw] & kBreaklessKey)) - dispatchKeyboardEventX(hidKeyCode, goingDown, now_abs); + dispatchKeyboardEventX(adbKeyCode, goingDown, now_abs); if (goingDown && (_PS2flags[keyCodeRaw] & kBreaklessKey)) - dispatchKeyboardEventX(hidKeyCode, false, now_abs); + dispatchKeyboardEventX(adbKeyCode, false, now_abs); } + +#ifdef DEBUG + if (0x38 == keyCode && !goingDown && -1 != genADB) // Alt going up + { + // dispatch typed adb code + dispatchKeyboardEventX(genADB, true, now_abs); + dispatchKeyboardEventX(genADB, false, now_abs); + DEBUG_LOG("%s: sending typed ADB code 0x%x\n", getName(), genADB); + genADB = -1; + } +#endif return true; } @@ -1072,14 +1892,18 @@ void ApplePS2Keyboard::setLEDs(UInt8 ledState) // It is safe to issue this request from the interrupt/completion context. // - PS2Request* request = _device->allocateRequest(2); + PS2Request* request = _device->allocateRequest(4); // (set LEDs command) - request->commands[0].command = kPS2C_SendCommandAndCompareAck; + request->commands[0].command = kPS2C_WriteDataPort; request->commands[0].inOrOut = kDP_SetKeyboardLEDs; - request->commands[1].command = kPS2C_SendCommandAndCompareAck; - request->commands[1].inOrOut = ledState; - request->commandsCount = 2; + request->commands[1].command = kPS2C_ReadDataPortAndCompare; + request->commands[1].inOrOut = kSC_Acknowledge; + request->commands[2].command = kPS2C_WriteDataPort; + request->commands[2].inOrOut = ledState; + request->commands[3].command = kPS2C_ReadDataPortAndCompare; + request->commands[3].inOrOut = kSC_Acknowledge; + request->commandsCount = 4; _device->submitRequest(request); } @@ -1097,16 +1921,270 @@ void ApplePS2Keyboard::setKeyboardEnable(bool enable) // // (keyboard enable/disable command) - TPS2Request<1> request; - request.commands[0].command = kPS2C_SendCommandAndCompareAck; + TPS2Request<2> request; + request.commands[0].command = kPS2C_WriteDataPort; request.commands[0].inOrOut = enable ? kDP_Enable : kDP_SetDefaults; - request.commandsCount = 1; + request.commands[1].command = kPS2C_ReadDataPortAndCompare; + request.commands[1].inOrOut = kSC_Acknowledge; + request.commandsCount = 2; assert(request.commandsCount <= countof(request.commands)); _device->submitRequestAndBlock(&request); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +const unsigned char * ApplePS2Keyboard::defaultKeymapOfLength(UInt32 * length) +{ + // + // Keymap data borrowed and modified from IOHIDFamily/IOHIDKeyboard.cpp + // references http://www.xfree.org/current/dumpkeymap.1.html + // http://www.tamasoft.co.jp/en/general-info/unicode.html + // + static const unsigned char appleUSAKeyMap[] = { + 0x00,0x00, // use byte unit. + + + // modifier definition + 0x0b, //Number of modifier keys. + // ( modifier , num of keys, ADB keycodes... ) + // ( 0x00 , 0x01 , 0x39 ) + //0x00,0x01,0x39, //NX_MODIFIERKEY_ALPHALOCK, uses one byte, ADB keycode is 0x39 + //13,0x01,0x39,//NX_MODIFIERKEY_ALPHALOCK_STATELESS + NX_MODIFIERKEY_SHIFT, 0x01,0x38, + NX_MODIFIERKEY_CONTROL, 0x01,0x3b, + NX_MODIFIERKEY_ALTERNATE, 0x01,0x3a, + NX_MODIFIERKEY_COMMAND, 0x01,0x37, + NX_MODIFIERKEY_NUMERICPAD, 0x15,0x52,0x41,0x4c,0x53,0x54,0x55,0x45,0x58,0x57,0x56,0x5b,0x5c,0x43,0x4b,0x51,0x7b,0x7d,0x7e,0x7c,0x4e,0x59, + NX_MODIFIERKEY_HELP, 0x01,0x72, + NX_MODIFIERKEY_SECONDARYFN, 0x01,0x3f, // Apple's Fn key + NX_MODIFIERKEY_RSHIFT, 0x01,0x3c, + NX_MODIFIERKEY_RCONTROL, 0x01,0x3e, + NX_MODIFIERKEY_RALTERNATE, 0x01,0x3d, + NX_MODIFIERKEY_RCOMMAND, 0x01,0x36, + + + // ADB virtual key definitions + 0xa2, // number of key definitions + // ( modifier mask , generated character{char_set,char_code}... ) + // ( 0x0d[has 3bit modifiers], {0x00,0x3c}, {0x00,0x3e}, ... total 2^3 characters ) + 0x0d,0x00,0x61,0x00,0x41,0x00,0x01,0x00,0x01,0x00,0xca,0x00,0xc7,0x00,0x01,0x00,0x01, //00 A + 0x0d,0x00,0x73,0x00,0x53,0x00,0x13,0x00,0x13,0x00,0xfb,0x00,0xa7,0x00,0x13,0x00,0x13, //01 S + 0x0d,0x00,0x64,0x00,0x44,0x00,0x04,0x00,0x04,0x01,0x44,0x01,0xb6,0x00,0x04,0x00,0x04, //02 D + 0x0d,0x00,0x66,0x00,0x46,0x00,0x06,0x00,0x06,0x00,0xa6,0x01,0xac,0x00,0x06,0x00,0x06, //03 F + 0x0d,0x00,0x68,0x00,0x48,0x00,0x08,0x00,0x08,0x00,0xe3,0x00,0xeb,0x00,0x00,0x18,0x00, //04 H + 0x0d,0x00,0x67,0x00,0x47,0x00,0x07,0x00,0x07,0x00,0xf1,0x00,0xe1,0x00,0x07,0x00,0x07, //05 G + 0x0d,0x00,0x7a,0x00,0x5a,0x00,0x1a,0x00,0x1a,0x00,0xcf,0x01,0x57,0x00,0x1a,0x00,0x1a, //06 Z + 0x0d,0x00,0x78,0x00,0x58,0x00,0x18,0x00,0x18,0x01,0xb4,0x01,0xce,0x00,0x18,0x00,0x18, //07 X + 0x0d,0x00,0x63,0x00,0x43,0x00,0x03,0x00,0x03,0x01,0xe3,0x01,0xd3,0x00,0x03,0x00,0x03, //08 C + 0x0d,0x00,0x76,0x00,0x56,0x00,0x16,0x00,0x16,0x01,0xd6,0x01,0xe0,0x00,0x16,0x00,0x16, //09 V + 0x02,0x00,0x3c,0x00,0x3e, //0a NON-US-BACKSLASH on ANSI and JIS keyboards GRAVE on ISO + 0x0d,0x00,0x62,0x00,0x42,0x00,0x02,0x00,0x02,0x01,0xe5,0x01,0xf2,0x00,0x02,0x00,0x02, //0b B + 0x0d,0x00,0x71,0x00,0x51,0x00,0x11,0x00,0x11,0x00,0xfa,0x00,0xea,0x00,0x11,0x00,0x11, //0c Q + 0x0d,0x00,0x77,0x00,0x57,0x00,0x17,0x00,0x17,0x01,0xc8,0x01,0xc7,0x00,0x17,0x00,0x17, //0d W + 0x0d,0x00,0x65,0x00,0x45,0x00,0x05,0x00,0x05,0x00,0xc2,0x00,0xc5,0x00,0x05,0x00,0x05, //0e E + 0x0d,0x00,0x72,0x00,0x52,0x00,0x12,0x00,0x12,0x01,0xe2,0x01,0xd2,0x00,0x12,0x00,0x12, //0f R + 0x0d,0x00,0x79,0x00,0x59,0x00,0x19,0x00,0x19,0x00,0xa5,0x01,0xdb,0x00,0x19,0x00,0x19, //10 Y + 0x0d,0x00,0x74,0x00,0x54,0x00,0x14,0x00,0x14,0x01,0xe4,0x01,0xd4,0x00,0x14,0x00,0x14, //11 T + 0x0a,0x00,0x31,0x00,0x21,0x01,0xad,0x00,0xa1, //12 1 + 0x0e,0x00,0x32,0x00,0x40,0x00,0x32,0x00,0x00,0x00,0xb2,0x00,0xb3,0x00,0x00,0x00,0x00, //13 2 + 0x0a,0x00,0x33,0x00,0x23,0x00,0xa3,0x01,0xba, //14 3 + 0x0a,0x00,0x34,0x00,0x24,0x00,0xa2,0x00,0xa8, //15 4 + 0x0e,0x00,0x36,0x00,0x5e,0x00,0x36,0x00,0x1e,0x00,0xb6,0x00,0xc3,0x00,0x1e,0x00,0x1e, //16 6 + 0x0a,0x00,0x35,0x00,0x25,0x01,0xa5,0x00,0xbd, //17 5 + 0x0a,0x00,0x3d,0x00,0x2b,0x01,0xb9,0x01,0xb1, //18 EQUALS + 0x0a,0x00,0x39,0x00,0x28,0x00,0xac,0x00,0xab, //19 9 + 0x0a,0x00,0x37,0x00,0x26,0x01,0xb0,0x01,0xab, //1a 7 + 0x0e,0x00,0x2d,0x00,0x5f,0x00,0x1f,0x00,0x1f,0x00,0xb1,0x00,0xd0,0x00,0x1f,0x00,0x1f, //1b MINUS + 0x0a,0x00,0x38,0x00,0x2a,0x00,0xb7,0x00,0xb4, //1c 8 + 0x0a,0x00,0x30,0x00,0x29,0x00,0xad,0x00,0xbb, //1d 0 + 0x0e,0x00,0x5d,0x00,0x7d,0x00,0x1d,0x00,0x1d,0x00,0x27,0x00,0xba,0x00,0x1d,0x00,0x1d, //1e RIGHTBRACKET + 0x0d,0x00,0x6f,0x00,0x4f,0x00,0x0f,0x00,0x0f,0x00,0xf9,0x00,0xe9,0x00,0x0f,0x00,0x0f, //1f O + 0x0d,0x00,0x75,0x00,0x55,0x00,0x15,0x00,0x15,0x00,0xc8,0x00,0xcd,0x00,0x15,0x00,0x15, //20 U + 0x0e,0x00,0x5b,0x00,0x7b,0x00,0x1b,0x00,0x1b,0x00,0x60,0x00,0xaa,0x00,0x1b,0x00,0x1b, //21 LEFTBRACKET + 0x0d,0x00,0x69,0x00,0x49,0x00,0x09,0x00,0x09,0x00,0xc1,0x00,0xf5,0x00,0x09,0x00,0x09, //22 I + 0x0d,0x00,0x70,0x00,0x50,0x00,0x10,0x00,0x10,0x01,0x70,0x01,0x50,0x00,0x10,0x00,0x10, //23 P + 0x10,0x00,0x0d,0x00,0x03, //24 RETURN + 0x0d,0x00,0x6c,0x00,0x4c,0x00,0x0c,0x00,0x0c,0x00,0xf8,0x00,0xe8,0x00,0x0c,0x00,0x0c, //25 L + 0x0d,0x00,0x6a,0x00,0x4a,0x00,0x0a,0x00,0x0a,0x00,0xc6,0x00,0xae,0x00,0x0a,0x00,0x0a, //26 J + 0x0a,0x00,0x27,0x00,0x22,0x00,0xa9,0x01,0xae, //27 APOSTROPHE + 0x0d,0x00,0x6b,0x00,0x4b,0x00,0x0b,0x00,0x0b,0x00,0xce,0x00,0xaf,0x00,0x0b,0x00,0x0b, //28 K + 0x0a,0x00,0x3b,0x00,0x3a,0x01,0xb2,0x01,0xa2, //29 SEMICOLON + 0x0e,0x00,0x5c,0x00,0x7c,0x00,0x1c,0x00,0x1c,0x00,0xe3,0x00,0xeb,0x00,0x1c,0x00,0x1c, //2a BACKSLASH + 0x0a,0x00,0x2c,0x00,0x3c,0x00,0xcb,0x01,0xa3, //2b COMMA + 0x0a,0x00,0x2f,0x00,0x3f,0x01,0xb8,0x00,0xbf, //2c SLASH + 0x0d,0x00,0x6e,0x00,0x4e,0x00,0x0e,0x00,0x0e,0x00,0xc4,0x01,0xaf,0x00,0x0e,0x00,0x0e, //2d N + 0x0d,0x00,0x6d,0x00,0x4d,0x00,0x0d,0x00,0x0d,0x01,0x6d,0x01,0xd8,0x00,0x0d,0x00,0x0d, //2e M + 0x0a,0x00,0x2e,0x00,0x3e,0x00,0xbc,0x01,0xb3, //2f PERIOD + 0x02,0x00,0x09,0x00,0x19, //30 TAB + 0x0c,0x00,0x20,0x00,0x00,0x00,0x80,0x00,0x00, //31 SPACE + 0x0a,0x00,0x60,0x00,0x7e,0x00,0x60,0x01,0xbb, //32 GRAVE on ANSI and JIS keyboards, NON-US-BACKSLASH on ISO + 0x02,0x00,0x7f,0x00,0x08, //33 BACKSPACE + 0xff, //34 PLAY/PAUSE + 0x02,0x00,0x1b,0x00,0x7e, //35 ESCAPE + 0xff, //36 RGUI + 0xff, //37 LGUI + 0xff, //38 LSHIFT + 0xff, //39 CAPSLOCK + 0xff, //3a LALT + 0xff, //3b LCTRL + 0xff, //3c RSHIFT + 0xff, //3d RALT + 0xff, //3e RCTRL + 0xff, //3f Apple Fn key + 0x00,0xfe,0x36, //40 F17 + 0x00,0x00,0x2e, //41 KEYPAD_PERIOD + 0xff, //42 NEXT TRACK or FAST + 0x00,0x00,0x2a, //43 KEYPAD_MULTIPLY + 0xff, //44 + 0x00,0x00,0x2b, //45 KEYPAD_PLUS + 0xff, //46 + 0x00,0x00,0x1b, //47 CLEAR + 0xff, //48 VOLUME UP + 0xff, //49 VOLUME DOWN + 0xff, //4a MUTE + 0x0e,0x00,0x2f,0x00,0x5c,0x00,0x2f,0x00,0x1c,0x00,0x2f,0x00,0x5c,0x00,0x00,0x0a,0x00, //4b KEYPAD_DIVIDE + 0x00,0x00,0x0d, //4c Apple Fn + Return = ENTER //XX03 + 0xff, //4d PREVIOUS TRACK or REWIND + 0x00,0x00,0x2d, //4e KEYPAD_MINUS + 0x00,0xfe,0x37, //4f F18 + 0x00,0xfe,0x38, //50 F19 + 0x0e,0x00,0x3d,0x00,0x7c,0x00,0x3d,0x00,0x1c,0x00,0x3d,0x00,0x7c,0x00,0x00,0x18,0x46, //51 KEYPAD_EQUALS + 0x00,0x00,0x30, //52 KEYPAD_0 + 0x00,0x00,0x31, //53 KEYPAD_1 + 0x00,0x00,0x32, //54 KEYPAD_2 + 0x00,0x00,0x33, //55 KEYPAD_3 + 0x00,0x00,0x34, //56 KEYPAD_4 + 0x00,0x00,0x35, //57 KEYPAD_5 + 0x00,0x00,0x36, //58 KEYPAD_6 + 0x00,0x00,0x37, //59 KEYPAD_7 + 0x00,0xfe,0x39, //5a F20 + 0x00,0x00,0x38, //5b KEYPAD_8 + 0x00,0x00,0x39, //5c KEYPAD_9 + 0xff, //0x02,0x00,0xa5,0x00,0x7c, //5d JIS JAPANESE YEN + 0xff, //0x00,0x00,0x5f, //5e JIS JAPANESE RO + 0xff, //0x00,0x00,0x2c, //5f KEYPAD_COMMA, JIS only + 0x00,0xfe,0x24, //60 F5 + 0x00,0xfe,0x25, //61 F6 + 0x00,0xfe,0x26, //62 F7 + 0x00,0xfe,0x22, //63 F3 + 0x00,0xfe,0x27, //64 F8 + 0x00,0xfe,0x28, //65 F9 + 0xff, //66 JIS JAPANESE EISU, KOREAN HANJA + 0x00,0xfe,0x2a, //67 F11 + 0xff, //68 JIS JAPANESE KANA, KOREAN HANGUL + 0x00,0xfe,0x32, //69 F13 + 0x00,0xfe,0x35, //6a F16 + 0x00,0xfe,0x33, //6b F14 + 0xff, //6c + 0x00,0xfe,0x29, //6d F10 + 0xff, //6e + 0x00,0xfe,0x2b, //6f F12 + 0xff, //70 + 0x00,0xfe,0x34, //71 F15 + 0xff, //72 HELP + 0x00,0xfe,0x2e, //73 HOME + 0x00,0xfe,0x30, //74 PAGEUP + 0x00,0xfe,0x2d, //75 DELETE + 0x00,0xfe,0x23, //76 F4 + 0x00,0xfe,0x2f, //77 END + 0x00,0xfe,0x21, //78 F2 + 0x00,0xfe,0x31, //79 PAGEDOWN + 0x00,0xfe,0x20, //7a F1 + 0x00,0x01,0xac, //7b LEFT ARROW + 0x00,0x01,0xae, //7c RIGHT ARROW + 0x00,0x01,0xaf, //7d DOWN ARROW + 0x00,0x01,0xad, //7e UP ARROW + 0x00,0x00,0x00, //7f POWER + 0x00,0x00,0x00, + 0x00,0x00,0x00, //81 Spotlight + 0x00,0x00,0x00, //82 Dashboard + 0x00,0x00,0x00, //83 Launchpad + 0x00,0x00,0x00, + 0x00,0x00,0x00, + 0x00,0x00,0x00, + 0x00,0x00,0x00, + 0x00,0x00,0x00, + 0x00,0x00,0x00, + 0x00,0x00,0x00, + 0x00,0x00,0x00, + 0x00,0x00,0x00, + 0x00,0x00,0x00, + 0x00,0x00,0x00, + 0x00,0x00,0x00, + 0x00,0x00,0x00, //90 Main Brightness Up + 0x00,0x00,0x00, //91 Main Brightness Down + 0x00,0x00,0x00, + 0x00,0x00,0x00, + 0x00,0x00,0x00, + 0x00,0x00,0x00, + 0x00,0x00,0x00, + 0x00,0x00,0x00, + 0x00,0x00,0x00, + 0x00,0x00,0x00, + 0x00,0x00,0x00, + 0x00,0x00,0x00, + 0x00,0x00,0x00, + 0x00,0x00,0x00, + 0x00,0x00,0x00, + 0x00,0x00,0x00, + 0x00,0x00,0x00, // a0 Exposes All + 0x00,0x00,0x00, // a1 Expose Desktop + + + // key sequence definition + // I tested some key sequence "Command + Shift + '['", but it doesn't work well. + // No one sequence was used on key deff table now. + 0x11, // number of of sequence definitions + // ( num of keys, generated sequence characters(char_set,char_code)... ) + // ( 0x02 , {0xff,0x04}, {0x00,0x31}, ) + 0x02,0xff,0x04,0x00,0x31, // Command + '1' + 0x02,0xff,0x04,0x00,0x32, // Command + '2' + 0x02,0xff,0x04,0x00,0x33, // Command + '3' + 0x02,0xff,0x04,0x00,0x34, // Command + '4' + 0x02,0xff,0x04,0x00,0x35, // Command + '5' + 0x02,0xff,0x04,0x00,0x36, // Command + '6' + 0x02,0xff,0x04,0x00,0x37, // Command + '7' + 0x02,0xff,0x04,0x00,0x38, // Command + '8' + 0x02,0xff,0x04,0x00,0x39, // Command + '9' + 0x02,0xff,0x04,0x00,0x30, // Command + '0' + 0x02,0xff,0x04,0x00,0x2d, // Command + '-' + 0x02,0xff,0x04,0x00,0x3d, // Command + '=' + 0x02,0xff,0x04,0x00,0x70, // Command + 'p' + 0x02,0xff,0x04,0x00,0x5d, // Command + ']' + 0x02,0xff,0x04,0x00,0x5b, // Command + '[' + 0x03,0xff,0x04,0xff,0x01,0x00,0x5b, // Command + Shift + '[' + 0x03,0xff,0x04,0xff,0x01,0x00,0x5d, // Command + shift + ']' + + + // special key definition + 0x0e, // number of special keys + // ( NX_KEYTYPE, Virtual ADB code ) + NX_KEYTYPE_CAPS_LOCK, 0x39, + NX_KEYTYPE_HELP, 0x72, + NX_POWER_KEY, 0x7f, + NX_KEYTYPE_MUTE, 0x4a, + NX_KEYTYPE_SOUND_UP, 0x48, + NX_KEYTYPE_SOUND_DOWN, 0x49, + // remove arrow keys as special keys. They are generating double up/down scroll events + // in both carbon and coco apps. + //NX_UP_ARROW_KEY, 0x7e, // ADB is 3e raw, 7e virtual (KMAP) + //NX_DOWN_ARROW_KEY, 0x7d, // ADB is 0x3d raw, 7d virtual + NX_KEYTYPE_NUM_LOCK, 0x47, // ADB combines with CLEAR key for numlock + NX_KEYTYPE_VIDMIRROR, 0x70, + NX_KEYTYPE_PLAY, 0x34, + NX_KEYTYPE_NEXT, 0x42, // if this event repeated, act as NX_KEYTYPE_FAST + NX_KEYTYPE_PREVIOUS, 0x4d, // if this event repeated, act as NX_KEYTYPE_REWIND + NX_KEYTYPE_BRIGHTNESS_UP, 0x90, + NX_KEYTYPE_BRIGHTNESS_DOWN, 0x91, + NX_KEYTYPE_EJECT, 0x92, + }; + + *length = sizeof(appleUSAKeyMap); + return appleUSAKeyMap; +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + void ApplePS2Keyboard::setDevicePowerState( UInt32 whatToDo ) { switch ( whatToDo ) @@ -1135,10 +2213,12 @@ void ApplePS2Keyboard::initKeyboard() // Reset the keyboard to its default state. // - TPS2Request<1> request; - request.commands[0].command = kPS2C_SendCommandAndCompareAck; + TPS2Request<2> request; + request.commands[0].command = kPS2C_WriteDataPort; request.commands[0].inOrOut = kDP_SetDefaults; - request.commandsCount = 1; + request.commands[1].command = kPS2C_ReadDataPortAndCompare; + request.commands[1].inOrOut = kSC_Acknowledge; + request.commandsCount = 2; assert(request.commandsCount <= countof(request.commands)); _device->submitRequestAndBlock(&request); diff --git a/VoodooPS2Keyboard/VoodooPS2Keyboard.h b/VoodooPS2Keyboard/VoodooPS2Keyboard.h index d0dc226d..797120f9 100644 --- a/VoodooPS2Keyboard/VoodooPS2Keyboard.h +++ b/VoodooPS2Keyboard/VoodooPS2Keyboard.h @@ -25,8 +25,7 @@ #include #include "../VoodooPS2Controller/ApplePS2KeyboardDevice.h" -#include "VoodooPS2KeyboardHIDWrapper.hpp" -#include "ApplePS2ToHIDMap.h" +#include #include @@ -69,9 +68,9 @@ #define kPacketTimeOffset 8 #define kPacketKeyDataLength 2 -class EXPORT ApplePS2Keyboard : public IOService +class EXPORT ApplePS2Keyboard : public IOHIKeyboard { - typedef IOService super; + typedef IOHIKeyboard super; OSDeclareDefaultStructors(ApplePS2Keyboard); private: @@ -87,10 +86,16 @@ class EXPORT ApplePS2Keyboard : public IOService // for keyboard remapping UInt16 _PS2modifierState; - UInt16 _PS2ToPS2Map[KBV_NUM_SCANCODES]; - UInt16 _PS2flags[KBV_NUM_SCANCODES]; - VoodooPS2HidElement _PS2ToHIDMap[512]; + UInt16 _PS2ToPS2Map[KBV_NUM_SCANCODES*2]; + UInt16 _PS2flags[KBV_NUM_SCANCODES*2]; + UInt8 _PS2ToADBMap[ADB_CONVERTER_LEN]; + UInt8 _PS2ToADBMapMapped[ADB_CONVERTER_LEN]; + UInt32 _fkeymode; + bool _fkeymodesupported; + OSArray* _keysStandard; + OSArray* _keysSpecial; bool _swapcommandoption; + int _logscancodes; UInt32 _f12ejectdelay; enum { kTimerSleep, kTimerEject } _timerFunc; bool _remapPrntScr; @@ -100,21 +105,37 @@ class EXPORT ApplePS2Keyboard : public IOService // dealing with sleep key delay IOTimerEventSource* _sleepEjectTimer; UInt32 _maxsleeppresstime; + + // ACPI support for keyboard backlight + IOACPIPlatformDevice * _provider; + int * _backlightLevels; + int _backlightCount; + + // special hack for Envy brightness access, while retaining F2/F3 functionality + bool _brightnessHack; // Toggle keyboard input along with touchpad when Windows+printscreen is pressed bool _disableInput; + // macro processing + OSData** _macroTranslation; + OSData** _macroInversion; + UInt8* _macroBuffer; + int _macroMax; + int _macroCurrent; + uint64_t _macroMaxTime; + IOTimerEventSource* _macroTimer; + // fix caps lock led bool _ignoreCapsLedChange; - - VoodooPS2KeyboardHIDWrapper *_hidWrapper {nullptr}; virtual bool dispatchKeyboardEventWithPacket(const UInt8* packet); virtual void setLEDs(UInt8 ledState); virtual void setKeyboardEnable(bool enable); virtual void initKeyboard(); virtual void setDevicePowerState(UInt32 whatToDo); - + void modifyKeyboardBacklight(int adbKeyCode, bool goingDown); + void modifyScreenBrightness(int adbKeyCode, bool goingDown); inline bool checkModifierState(UInt16 mask) { return mask == (_PS2modifierState & mask); } inline bool checkModifierStateAny(UInt16 mask) @@ -122,18 +143,24 @@ class EXPORT ApplePS2Keyboard : public IOService void loadCustomPS2Map(OSArray* pArray); void loadBreaklessPS2(OSDictionary* dict, const char* name); - void loadCustomHIDMap(OSDictionary* dict, const char* name); + void loadCustomADBMap(OSDictionary* dict, const char* name); void setParamPropertiesGated(OSDictionary* dict); void onSleepEjectTimer(void); + + static OSData** loadMacroData(OSDictionary* dict, const char* name); + static void freeMacroData(OSData** data); + void onMacroTimer(void); + bool invertMacros(const UInt8* packet); + void dispatchInvertBuffer(); + static bool compareMacro(const UInt8* packet, const UInt8* data, int count); protected: - void setAlphaLockFeedback(bool locked); - void setNumLockFeedback(bool locked); - - inline void dispatchKeyboardEventX(const VoodooPS2HidElement &elem, bool goingDown, uint64_t time) - { dispatchKeyboardEventX(elem.usagePage, elem.usage, goingDown, time); } - inline void dispatchKeyboardEventX(uint16_t usagePage, uint32_t usage, bool goingDown, uint64_t time) - { if (_hidWrapper) _hidWrapper->dispatchKeyboardEvent(time, usagePage, usage, goingDown); } + const unsigned char * defaultKeymapOfLength(UInt32 * length) override; + void setAlphaLockFeedback(bool locked) override; + void setNumLockFeedback(bool locked) override; + UInt32 maxKeyCodes() override; + inline void dispatchKeyboardEventX(unsigned int keyCode, bool goingDown, uint64_t time) + { dispatchKeyboardEvent(keyCode, goingDown, *(AbsoluteTime*)&time); } inline void setTimerTimeout(IOTimerEventSource* timer, uint64_t time) { timer->setTimeout(*(AbsoluteTime*)&time); } inline void cancelTimer(IOTimerEventSource* timer) @@ -149,6 +176,10 @@ class EXPORT ApplePS2Keyboard : public IOService virtual PS2InterruptResult interruptOccurred(UInt8 scanCode); virtual void packetReady(); + 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; diff --git a/VoodooPS2Keyboard/VoodooPS2KeyboardHIDWrapper.cpp b/VoodooPS2Keyboard/VoodooPS2KeyboardHIDWrapper.cpp deleted file mode 100644 index e6b3c377..00000000 --- a/VoodooPS2Keyboard/VoodooPS2KeyboardHIDWrapper.cpp +++ /dev/null @@ -1,134 +0,0 @@ -// -// VoodooPS2KeyboardHIDWrapper.cpp -// VoodooPS2Keyboard -// -// Created by Gwydien on 8/28/23. -// Copyright © 2023 Acidanthera. All rights reserved. -// - -#include "VoodooPS2KeyboardHIDWrapper.hpp" -#include -#include - -OSDefineMetaClassAndStructors(VoodooPS2KeyboardHIDWrapper, IOHIDDevice); -OSDefineMetaClassAndStructors(VoodooPS2KeyboardHIDEventDriver, IOHIDEventService); - -static constexpr uint8_t ReportDescriptor[] = { - 0x05, 0x01, // Usage Page (Generic Desktop) - 0x09, 0x06, // USAGE (Keyboard) - 0xa1, 0x01, // COLLECTION (Application) - 0x85, 0x01, // REPORT_ID (Keyboard) - 0x05, 0x07, // USAGE_PAGE (Keyboard) - 0x19, 0xe0, // USAGE_MINIMUM (Keyboard LeftControl) - 0x29, 0xe7, // USAGE_MAXIMUM (Keyboard Right GUI) - 0x15, 0x00, // LOGICAL_MINIMUM (0) - 0x25, 0x01, // LOGICAL_MAXIMUM (1) - 0x75, 0x01, // REPORT_SIZE (1) - 0x95, 0x08, // REPORT_COUNT (8) - 0x81, 0x02, // INPUT (Data,Var,Abs) - 0x95, 0x01, // REPORT_COUNT (1) - 0x75, 0x08, // REPORT_SIZE (8) - 0x81, 0x03, // INPUT (Cnst,Var,Abs) - 0x95, 0x05, // REPORT_COUNT (5) - 0x75, 0x01, // REPORT_SIZE (1) - 0x05, 0x08, // USAGE_PAGE (LEDs) - 0x19, 0x01, // USAGE_MINIMUM (Num Lock) - 0x29, 0x05, // USAGE_MAXIMUM (Kana) - 0x91, 0x02, // OUTPUT (Data,Var,Abs) - 0x95, 0x01, // REPORT_COUNT (1) - 0x75, 0x03, // REPORT_SIZE (3) - 0x91, 0x03, // OUTPUT (Cnst,Var,Abs) - 0x95, 0x06, // REPORT_COUNT (6) - 0x75, 0x08, // REPORT_SIZE (8) - 0x15, 0x00, // LOGICAL_MINIMUM (0) - 0x25, 0x65, // LOGICAL_MAXIMUM (101) - 0x05, 0x07, // USAGE_PAGE (Keyboard) - 0x19, 0x00, // USAGE_MINIMUM (Reserved (no event indicated)) - 0x29, 0x65, // USAGE_MAXIMUM (Keyboard Application) - 0x81, 0x00, // INPUT (Data,Ary,Abs) - 0xc0, // END_COLLECTION -}; - -bool VoodooPS2KeyboardHIDWrapper::start(IOService *provider) { - setProperty(kIOHIDBuiltInKey, kOSBooleanTrue); - setProperty("HIDDefaultBehavior", kOSBooleanTrue); - setProperty("AppleVendorSupported", kOSBooleanTrue); - - registerService(); - if (!IOHIDDevice::start(provider)) return false; - - return true; -} - -void VoodooPS2KeyboardHIDWrapper::stop(IOService *provider) { - return IOHIDDevice::stop(provider); -} - -void VoodooPS2KeyboardHIDWrapper::dispatchKeyboardEvent(AbsoluteTime time, uint16_t usagePage, uint16_t usage, uint8_t value) { - if (eventDriver != nullptr) { - eventDriver->dispatchKeyboardEvent(time, usagePage, usage, value); - } -} - -bool VoodooPS2KeyboardHIDWrapper::handleOpen(IOService *forClient, IOOptionBits options, void *arg) { - VoodooPS2KeyboardHIDEventDriver *temp = OSDynamicCast(VoodooPS2KeyboardHIDEventDriver, forClient); - if (eventDriver == nullptr && temp != nullptr && IOHIDDevice::handleOpen(forClient, options, arg)) { - eventDriver = temp; - return true; - } - - return IOHIDDevice::handleOpen(forClient, options, arg); -} - -void VoodooPS2KeyboardHIDWrapper::handleClose(IOService *forClient, IOOptionBits options) { - if (forClient == eventDriver) { - eventDriver = nullptr; - } - - IOHIDDevice::handleClose(forClient, options); -} - -IOReturn VoodooPS2KeyboardHIDWrapper::newReportDescriptor(IOMemoryDescriptor **descriptor) const { - IOBufferMemoryDescriptor *buffer = IOBufferMemoryDescriptor::inTaskWithOptions(kernel_task, 0, sizeof(ReportDescriptor)); - - if (buffer == NULL) return kIOReturnNoResources; - buffer->writeBytes(0, ReportDescriptor, sizeof(ReportDescriptor)); - *descriptor = buffer; - - return kIOReturnSuccess; -} - -OSString* VoodooPS2KeyboardHIDWrapper::newManufacturerString() const { - return OSString::withCString("Acidanthera"); -} - -OSNumber* VoodooPS2KeyboardHIDWrapper::newPrimaryUsageNumber() const { - return OSNumber::withNumber(kHIDUsage_GD_Keyboard, 32); -} - -OSNumber* VoodooPS2KeyboardHIDWrapper::newPrimaryUsagePageNumber() const { - return OSNumber::withNumber(kHIDPage_GenericDesktop, 32); -} - -/* - * Apple vendor is needed for keyboard backlight filters to attach. - * To prevent Apple event drivers from attaching, use a bogus - * product ID. - */ - -OSNumber* VoodooPS2KeyboardHIDWrapper::newVendorIDNumber() const { - // Apple Vendor needed for - return OSNumber::withNumber(1452, 16); -} - -OSNumber* VoodooPS2KeyboardHIDWrapper::newProductIDNumber() const { - return OSNumber::withNumber(0x9999, 32); -} - -OSString* VoodooPS2KeyboardHIDWrapper::newProductString() const { - return OSString::withCString("PS2 Keyboard"); -} - -OSString* VoodooPS2KeyboardHIDWrapper::newTransportString() const { - return OSString::withCString("PS2"); -} diff --git a/VoodooPS2Keyboard/VoodooPS2KeyboardHIDWrapper.hpp b/VoodooPS2Keyboard/VoodooPS2KeyboardHIDWrapper.hpp deleted file mode 100644 index 9008013d..00000000 --- a/VoodooPS2Keyboard/VoodooPS2KeyboardHIDWrapper.hpp +++ /dev/null @@ -1,39 +0,0 @@ -// -// VoodooPS2KeyboardHIDWrapper.hpp -// VoodooPS2Keyboard -// -// Created by Gwydien on 8/28/23. -// Copyright © 2023 Acidanthera. All rights reserved. -// - -#ifndef VoodooPS2KeyboardHIDWrapper_hpp -#define VoodooPS2KeyboardHIDWrapper_hpp - -#include -#include "VoodooPS2EventDriver.hpp" - -class VoodooPS2KeyboardHIDWrapper : public IOHIDDevice { - OSDeclareDefaultStructors(VoodooPS2KeyboardHIDWrapper); -public: - bool start(IOService *start) override; - void stop(IOService *start) override; - bool handleOpen(IOService *forClient, IOOptionBits options, void *arg) override; - void handleClose(IOService *forClient, IOOptionBits options) override; - - IOReturn newReportDescriptor(IOMemoryDescriptor **descriptor) const override; - - virtual OSString* newManufacturerString() const override; - virtual OSNumber* newPrimaryUsageNumber() const override; - virtual OSNumber* newPrimaryUsagePageNumber() const override; - virtual OSString* newProductString() const override; - virtual OSString* newTransportString() const override; - virtual OSNumber* newVendorIDNumber() const override; - virtual OSNumber* newProductIDNumber() const override; - - void dispatchKeyboardEvent(AbsoluteTime time, uint16_t usagePage, uint16_t usage, uint8_t value); - -private: - VoodooPS2KeyboardHIDEventDriver *eventDriver {nullptr}; -}; - -#endif /* VoodooPS2KeyboardHIDWrapper_hpp */ From daae383ed35dce52b3ea31215b4b533e835b97ca Mon Sep 17 00:00:00 2001 From: Ivy <78825510+Lost-Entrepreneur439@users.noreply.github.com> Date: Wed, 4 Sep 2024 05:48:32 -0230 Subject: [PATCH 092/101] Change minimum macOS to 10.10 (#62) --- 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 f0fdc456..00971319 100644 --- a/VoodooPS2Controller.xcodeproj/project.pbxproj +++ b/VoodooPS2Controller.xcodeproj/project.pbxproj @@ -764,7 +764,7 @@ KERNEL_EXTENSION_HEADER_SEARCH_PATHS = "$(PROJECT_DIR)/MacKernelSDK/Headers"; KERNEL_FRAMEWORK_HEADERS = "$(PROJECT_DIR)/MacKernelSDK/Headers"; "LLVM_LTO[arch=x86_64]" = YES; - MACOSX_DEPLOYMENT_TARGET = 10.11; + MACOSX_DEPLOYMENT_TARGET = 10.10; MODULE_VERSION = 2.3.6; ONLY_ACTIVE_ARCH = YES; "OTHER_LDFLAGS[arch=x86_64]" = "-dead_strip"; @@ -819,7 +819,7 @@ KERNEL_EXTENSION_HEADER_SEARCH_PATHS = "$(PROJECT_DIR)/MacKernelSDK/Headers"; KERNEL_FRAMEWORK_HEADERS = "$(PROJECT_DIR)/MacKernelSDK/Headers"; "LLVM_LTO[arch=x86_64]" = YES; - MACOSX_DEPLOYMENT_TARGET = 10.11; + MACOSX_DEPLOYMENT_TARGET = 10.10; MODULE_VERSION = 2.3.6; "OTHER_LDFLAGS[arch=x86_64]" = "-dead_strip"; PRODUCT_NAME = VoodooPS2Controller; From 43dac6d04e40994950c3562790be3fb2c4d0b801 Mon Sep 17 00:00:00 2001 From: Vitaly Cheptsov <4348897+vit9696@users.noreply.github.com> Date: Wed, 4 Sep 2024 11:18:55 +0300 Subject: [PATCH 093/101] Sync changelog --- Changelog.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Changelog.md b/Changelog.md index 312c3867..14f2e9cc 100644 --- a/Changelog.md +++ b/Changelog.md @@ -1,5 +1,8 @@ VoodooPS2 Changelog ============================ +#### v2.3.6 +- Lowered macOS requirements to 10.10 + #### v2.3.5 - Removed actAsTrackpad and related logic - Fix Trackpoints connected to Elan Touchpads From 4750716a998f4a19042e9506260095bf8e069527 Mon Sep 17 00:00:00 2001 From: Avery Black Date: Fri, 4 Oct 2024 09:42:01 -0700 Subject: [PATCH 094/101] SMBus Companion Devices (#63) * Set LIBKERN_RETURN_RETAINED * Add PS/2 stub driver * Create companion device in start instead of probe * Retain/Release companion info dictionary * Clean up PS2 stub device * Save OSSymbol in class * Save symbol in class * Update copyright --- VoodooPS2Controller.xcodeproj/project.pbxproj | 8 ++ VoodooPS2Controller/ApplePS2Device.cpp | 7 ++ VoodooPS2Controller/ApplePS2Device.h | 6 +- VoodooPS2Controller/VoodooPS2Controller.cpp | 19 ++++- VoodooPS2Controller/VoodooPS2Controller.h | 3 + VoodooPS2Trackpad/VoodooPS2SMBusDevice.cpp | 81 +++++++++++++++++++ VoodooPS2Trackpad/VoodooPS2SMBusDevice.h | 45 +++++++++++ .../VoodooPS2SynapticsTouchPad.cpp | 69 ++++++++-------- .../VoodooPS2SynapticsTouchPad.h | 6 +- 9 files changed, 202 insertions(+), 42 deletions(-) create mode 100644 VoodooPS2Trackpad/VoodooPS2SMBusDevice.cpp create mode 100644 VoodooPS2Trackpad/VoodooPS2SMBusDevice.h diff --git a/VoodooPS2Controller.xcodeproj/project.pbxproj b/VoodooPS2Controller.xcodeproj/project.pbxproj index 00971319..dcebfd07 100644 --- a/VoodooPS2Controller.xcodeproj/project.pbxproj +++ b/VoodooPS2Controller.xcodeproj/project.pbxproj @@ -39,6 +39,8 @@ CE8DA1C6251839B7008C44E8 /* libkmod.a in Frameworks */ = {isa = PBXBuildFile; fileRef = CE8DA1C4251839B2008C44E8 /* libkmod.a */; }; CE8DA1C7251839B9008C44E8 /* libkmod.a in Frameworks */ = {isa = PBXBuildFile; fileRef = CE8DA1C4251839B2008C44E8 /* libkmod.a */; }; CE8DA1CC251839BC008C44E8 /* libkmod.a in Frameworks */ = {isa = PBXBuildFile; fileRef = CE8DA1C4251839B2008C44E8 /* libkmod.a */; }; + EE914A902C952F0D0023CFE0 /* VoodooPS2SMBusDevice.cpp in Sources */ = {isa = PBXBuildFile; fileRef = EE914A8E2C952F0D0023CFE0 /* VoodooPS2SMBusDevice.cpp */; }; + EE914A912C952F0D0023CFE0 /* VoodooPS2SMBusDevice.h in Headers */ = {isa = PBXBuildFile; fileRef = EE914A8F2C952F0D0023CFE0 /* VoodooPS2SMBusDevice.h */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ @@ -131,6 +133,8 @@ EDD95559208E2B640031D99E /* SSDT-Thinkpad_Clickpad.dsl */ = {isa = PBXFileReference; lastKnownFileType = text; path = "SSDT-Thinkpad_Clickpad.dsl"; sourceTree = ""; }; EDD9555A208E2E7A0031D99E /* SSDT-Thinkpad_Trackpad.dsl */ = {isa = PBXFileReference; lastKnownFileType = text; path = "SSDT-Thinkpad_Trackpad.dsl"; sourceTree = ""; }; EDD970FD1FD0B826004CCFFD /* SSDT-HP-FixLidSleep.dsl */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = "SSDT-HP-FixLidSleep.dsl"; sourceTree = ""; }; + EE914A8E2C952F0D0023CFE0 /* VoodooPS2SMBusDevice.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = VoodooPS2SMBusDevice.cpp; sourceTree = ""; }; + EE914A8F2C952F0D0023CFE0 /* VoodooPS2SMBusDevice.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = VoodooPS2SMBusDevice.h; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -287,6 +291,8 @@ 84833FB0161B62A900845294 /* VoodooPS2SynapticsTouchPad.h */, 84833FAF161B62A900845294 /* VoodooPS2SynapticsTouchPad.cpp */, 4CC27EB2251FBC7700824FE1 /* VoodooPS2TrackpadCommon.h */, + EE914A8F2C952F0D0023CFE0 /* VoodooPS2SMBusDevice.h */, + EE914A8E2C952F0D0023CFE0 /* VoodooPS2SMBusDevice.cpp */, 84167857161B56C4002C60E6 /* Supporting Files */, ); path = VoodooPS2Trackpad; @@ -393,6 +399,7 @@ 356B896323007F4F0042F30F /* VoodooInputEvent.h in Headers */, 9828A93024A2B6C200550FAA /* VoodooPS2Elan.h in Headers */, 356B896223007F4F0042F30F /* VoodooInputMessages.h in Headers */, + EE914A912C952F0D0023CFE0 /* VoodooPS2SMBusDevice.h in Headers */, 356B896423007F4F0042F30F /* VoodooInputTransducer.h in Headers */, 84833FB2161B62A900845294 /* VoodooPS2ALPSGlidePoint.h in Headers */, 356B896523007F4F0042F30F /* MultitouchHelpers.h in Headers */, @@ -653,6 +660,7 @@ 84833FB1161B62A900845294 /* VoodooPS2ALPSGlidePoint.cpp in Sources */, 9828A92F24A2B6C200550FAA /* VoodooPS2Elan.cpp in Sources */, 84833FB3161B62A900845294 /* VoodooPS2SentelicFSP.cpp in Sources */, + EE914A902C952F0D0023CFE0 /* VoodooPS2SMBusDevice.cpp in Sources */, 84833FB5161B62A900845294 /* VoodooPS2SynapticsTouchPad.cpp in Sources */, ); runOnlyForDeploymentPostprocessing = 0; diff --git a/VoodooPS2Controller/ApplePS2Device.cpp b/VoodooPS2Controller/ApplePS2Device.cpp index 9f935d63..cb5d009e 100644 --- a/VoodooPS2Controller/ApplePS2Device.cpp +++ b/VoodooPS2Controller/ApplePS2Device.cpp @@ -181,6 +181,13 @@ void ApplePS2Device::dispatchMessage(int message, void *data) // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +IOReturn ApplePS2Device::startSMBusCompanion(OSDictionary *companionData, UInt8 smbusAddr) +{ + return _controller->startSMBusCompanion(companionData, smbusAddr); +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + ApplePS2Controller* ApplePS2Device::getController() { return _controller; diff --git a/VoodooPS2Controller/ApplePS2Device.h b/VoodooPS2Controller/ApplePS2Device.h index 35aefb10..03100b5f 100644 --- a/VoodooPS2Controller/ApplePS2Device.h +++ b/VoodooPS2Controller/ApplePS2Device.h @@ -516,6 +516,8 @@ typedef void (*PS2PowerControlAction)(void * target, UInt32 whatToDo); // Published property for devices to express interest in receiving messages #define kDeliverNotifications "RM,deliverNotifications" +#define kSmbusCompanion "VoodooSMBusCompanionDevice" + // Published property for device nub port location #define kPortKey "Port Num" @@ -532,9 +534,6 @@ enum kPS2M_resetTouchpad = iokit_vendor_specific_msg(151), // Force touchpad reset (data is int*) - // from trackpad on I2C/SMBus - kPS2M_SMBusStart = iokit_vendor_specific_msg(152), // Reset, disable PS2 comms to not interfere with SMBus comms - // from sensor (such as yoga mode indicator) to keyboard kPS2K_setKeyboardStatus = iokit_vendor_specific_msg(200), // set disable/enable keyboard (data is bool*) kPS2K_getKeyboardStatus = iokit_vendor_specific_msg(201), // get disable/enable keyboard (data is bool*) @@ -607,6 +606,7 @@ class EXPORT ApplePS2Device : public IOService // Messaging virtual void dispatchMessage(int message, void *data); + virtual IOReturn startSMBusCompanion(OSDictionary *companionData, UInt8 smbusAddr); // Exclusive access (command byte contention) diff --git a/VoodooPS2Controller/VoodooPS2Controller.cpp b/VoodooPS2Controller/VoodooPS2Controller.cpp index 497b47bc..0dc60a59 100644 --- a/VoodooPS2Controller/VoodooPS2Controller.cpp +++ b/VoodooPS2Controller/VoodooPS2Controller.cpp @@ -280,6 +280,10 @@ bool ApplePS2Controller::init(OSDictionary* dict) _deliverNotification = OSSymbol::withCString(kDeliverNotifications); if (_deliverNotification == NULL) return false; + + _smbusCompanion = OSSymbol::withCString(kSmbusCompanion); + if (_smbusCompanion == NULL) + return false; queue_init(&_requestQueue); @@ -747,6 +751,7 @@ void ApplePS2Controller::stop(IOService * provider) // Free the RMCF configuration cache OSSafeReleaseNULL(_rmcfCache); OSSafeReleaseNULL(_deliverNotification); + OSSafeReleaseNULL(_smbusCompanion); // Free the request queue lock and empty out the request queue. if (_requestQueueLock) @@ -2126,7 +2131,7 @@ static OSString* getPlatformOverride(IORegistryEntry* reg, const char* sz) return NULL; } -static OSString* getPlatformManufacturer(IORegistryEntry* reg) +static LIBKERN_RETURNS_RETAINED OSString* getPlatformManufacturer(IORegistryEntry* reg) { // allow override in PS2K ACPI device OSString* id = getPlatformOverride(reg, "RM,oem-id"); @@ -2148,7 +2153,7 @@ static OSString* getPlatformManufacturer(IORegistryEntry* reg) return OSString::withCStringNoCopy(oemID); } -static OSString* getPlatformProduct(IORegistryEntry* reg) +static LIBKERN_RETURNS_RETAINED OSString* getPlatformProduct(IORegistryEntry* reg) { // allow override in PS2K ACPI device OSString* id = getPlatformOverride(reg, "RM,oem-table-id"); @@ -2423,3 +2428,13 @@ OSDictionary* ApplePS2Controller::makeConfigurationNode(OSDictionary* list, cons return result; } + +IOReturn ApplePS2Controller::startSMBusCompanion(OSDictionary *companionData, UInt8 smbusAddr) { + IOReturn ret = callPlatformFunction(_smbusCompanion, + false, + static_cast(this), + static_cast(companionData), + reinterpret_cast(smbusAddr), + nullptr); + return ret; +} diff --git a/VoodooPS2Controller/VoodooPS2Controller.h b/VoodooPS2Controller/VoodooPS2Controller.h index eb97fc56..793e200d 100644 --- a/VoodooPS2Controller/VoodooPS2Controller.h +++ b/VoodooPS2Controller/VoodooPS2Controller.h @@ -282,6 +282,7 @@ class EXPORT ApplePS2Controller : public IOService #endif OSDictionary* _rmcfCache {nullptr}; const OSSymbol* _deliverNotification {nullptr}; + const OSSymbol* _smbusCompanion {nullptr}; int _resetControllerFlag {RESET_CONTROLLER_ON_BOOT | RESET_CONTROLLER_ON_WAKEUP}; bool _kbdOnly {0}; @@ -371,6 +372,8 @@ class EXPORT ApplePS2Controller : public IOService OSDictionary* getConfigurationOverride(IOACPIPlatformDevice* acpi, const char* method); OSObject* translateArray(OSArray* array); OSObject* translateEntry(OSObject* obj); + + IOReturn startSMBusCompanion(OSDictionary *companionData, UInt8 smbusAddr); }; #endif /* _APPLEPS2CONTROLLER_H */ diff --git a/VoodooPS2Trackpad/VoodooPS2SMBusDevice.cpp b/VoodooPS2Trackpad/VoodooPS2SMBusDevice.cpp new file mode 100644 index 00000000..36803959 --- /dev/null +++ b/VoodooPS2Trackpad/VoodooPS2SMBusDevice.cpp @@ -0,0 +1,81 @@ +// +// VoodooPS2SMBusDevice.cpp +// VoodooPS2Trackpad +// +// Created by Avery Black on 9/13/24. +// Copyright © 2024 Acidanthera. All rights reserved. +// + +#include "VoodooPS2SMBusDevice.h" + +// ============================================================================= +// ApplePS2SmbusDevice Class Implementation +// + +OSDefineMetaClassAndStructors(ApplePS2SmbusDevice, IOService); + +ApplePS2SmbusDevice *ApplePS2SmbusDevice::withReset(bool resetNeeded, OSDictionary *data, uint8_t addr) { + ApplePS2SmbusDevice *dev = OSTypeAlloc(ApplePS2SmbusDevice); + + if (dev == nullptr) { + return nullptr; + } + + if (!dev->init()) { + OSSafeReleaseNULL(dev); + return nullptr; + } + + dev->_resetNeeded = resetNeeded; + dev->_data = data; + dev->_data->retain(); + dev->_addr = addr; + return dev; +} + +bool ApplePS2SmbusDevice::start(IOService *provider) { + if (!super::start(provider)) + return false; + + _nub = OSDynamicCast(ApplePS2MouseDevice, provider); + if (_nub == nullptr) + return false; + + if (_resetNeeded) + resetDevice(); + + if (_nub->startSMBusCompanion(_data, _addr) != kIOReturnSuccess) { + return false; + } + + _nub->installPowerControlAction(this, + OSMemberFunctionCast(PS2PowerControlAction, this, &ApplePS2SmbusDevice::powerAction)); + return true; +} + +void ApplePS2SmbusDevice::free() { + OSSafeReleaseNULL(_data); + super::free(); +} + +void ApplePS2SmbusDevice::powerAction(uint32_t ordinal) { + if (ordinal == kPS2C_EnableDevice && _resetNeeded) { + (void) resetDevice(); + } +} + +IOReturn ApplePS2SmbusDevice::resetDevice() { + TPS2Request<> request; + request.commands[0].command = kPS2C_SendCommandAndCompareAck; + request.commands[0].inOrOut = kDP_SetDefaultsAndDisable; // F5 + request.commandsCount = 1; + _nub->submitRequestAndBlock(&request); + + if (request.commandsCount == 1) { + DEBUG_LOG("VoodooPS2Trackpad: sending $FF failed: %d\n", request.commandsCount); + return kIOReturnError; + } + + return kIOReturnSuccess; +} + diff --git a/VoodooPS2Trackpad/VoodooPS2SMBusDevice.h b/VoodooPS2Trackpad/VoodooPS2SMBusDevice.h new file mode 100644 index 00000000..26f386cd --- /dev/null +++ b/VoodooPS2Trackpad/VoodooPS2SMBusDevice.h @@ -0,0 +1,45 @@ +// +// VoodooPS2SMBusDevice.hpp +// VoodooPS2Trackpad +// +// Created by Avery Black on 9/13/24. +// Copyright © 2024 Acidanthera. All rights reserved. +// + +#ifndef VoodooPS2SMBusDevice_hpp +#define VoodooPS2SMBusDevice_hpp + + +#include "../VoodooPS2Controller/ApplePS2MouseDevice.h" +#include + +#include "VoodooPS2TrackpadCommon.h" + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +// ApplePS2SmbusDevice Class Declaration +// Synaptics and Elans devices still need resets over PS2. This acts as a +// PS/2 stub driver that attaches in lieu of the full touchpad driver to reset +// on wakeups and sleep. This also prevents other devices attaching and using +// the otherwise unused PS/2 interface +// + +class EXPORT ApplePS2SmbusDevice : public IOService { + typedef IOService super; + OSDeclareDefaultStructors(ApplePS2SmbusDevice); +public: + static ApplePS2SmbusDevice *withReset(bool resetNeeded, OSDictionary *data, uint8_t addr); + + bool start(IOService *provider) override; + void free() override; + +private: + ApplePS2MouseDevice *_nub {nullptr}; + bool _resetNeeded {false}; + OSDictionary *_data {nullptr}; + uint8_t _addr{0}; + + IOReturn resetDevice(); + void powerAction(uint32_t ordinal); +}; + +#endif /* VoodooPS2SMBusDevice_hpp */ diff --git a/VoodooPS2Trackpad/VoodooPS2SynapticsTouchPad.cpp b/VoodooPS2Trackpad/VoodooPS2SynapticsTouchPad.cpp index d21e5800..f8cdf8e7 100644 --- a/VoodooPS2Trackpad/VoodooPS2SynapticsTouchPad.cpp +++ b/VoodooPS2Trackpad/VoodooPS2SynapticsTouchPad.cpp @@ -44,6 +44,7 @@ #include #include #include +#include "VoodooPS2SMBusDevice.h" #include "VoodooPS2Controller.h" #include "VoodooPS2SynapticsTouchPad.h" #include "VoodooInputMultitouch/VoodooInputTransducer.h" @@ -75,6 +76,10 @@ bool ApplePS2SynapticsTouchPad::init(OSDictionary * dict) memset(freeFingerTypes, true, kMT2FingerTypeCount); freeFingerTypes[kMT2FingerTypeUndefined] = false; + + _smbusCompanion = OSSymbol::withCString(kSmbusCompanion); + if (_smbusCompanion == NULL) + return false; // announce version extern kmod_info_t kmod_info; @@ -123,7 +128,7 @@ void ApplePS2SynapticsTouchPad::injectVersionDependentProperties(OSDictionary *c } } -ApplePS2SynapticsTouchPad* ApplePS2SynapticsTouchPad::probe(IOService * provider, SInt32 * score) +IOService* ApplePS2SynapticsTouchPad::probe(IOService * provider, SInt32 * score) { DEBUG_LOG("ApplePS2SynapticsTouchPad::probe entered...\n"); @@ -191,6 +196,27 @@ ApplePS2SynapticsTouchPad* ApplePS2SynapticsTouchPad::probe(IOService * provider return 0; } + // + // Query the touchpad for the capabilities we need to know. + // + queryCapabilities(); + + // + // Attempt to start SMBus Companion. If succesful, attach a stub PS/2 driver. + // + IOService *resources = getResourceService(); + if (_cont_caps.intertouch && resources && resources->getProperty(_smbusCompanion)) { + // Helpful information for SMBus drivers + OSDictionary *dictionary = OSDictionary::withCapacity(2); + dictionary->setObject("TrackstickButtons", _securepad.trackstick_btns ? + kOSBooleanTrue : kOSBooleanFalse); + dictionary->setObject("Clickpad", _cont_caps.one_btn_clickpad ? + kOSBooleanTrue : kOSBooleanFalse); + ApplePS2SmbusDevice *smbus = ApplePS2SmbusDevice::withReset(true, dictionary, 0x2C); + OSSafeReleaseNULL(dictionary); + return smbus; + } + _device = 0; DEBUG_LOG("ApplePS2SynapticsTouchPad::probe leaving.\n"); @@ -365,16 +391,6 @@ void ApplePS2SynapticsTouchPad::queryCapabilities() setTrackpointProperties(); setProperty("VoodooInputSupported", kOSBooleanTrue); - - // Helpful information for SMBus drivers - OSDictionary *dictionary = OSDictionary::withCapacity(2); - dictionary->setObject("TrackstickButtons", _securepad.trackstick_btns ? - kOSBooleanTrue : kOSBooleanFalse); - dictionary->setObject("Clickpad", _cont_caps.one_btn_clickpad ? - kOSBooleanTrue : kOSBooleanFalse); - setProperty("GPIO Data", dictionary); - - OSSafeReleaseNULL(dictionary); INFO_LOG("VoodooPS2Trackpad: logical %dx%d-%dx%d physical_max %dx%d upmm %dx%d", logical_min_x, logical_min_y, @@ -467,11 +483,6 @@ bool ApplePS2SynapticsTouchPad::start( IOService * provider ) attachedHIDPointerDevices = OSSet::withCapacity(1); registerHIDPointerNotifications(); - // - // Query the touchpad for the capabilities we need to know. - // - queryCapabilities(); - // // Set the touchpad mode byte, which will also... // Enable the mouse clock (should already be so) and the mouse IRQ line. @@ -594,6 +605,12 @@ void ApplePS2SynapticsTouchPad::stop( IOService * provider ) // OSSafeReleaseNULL(_provider); + // + // Release OSSymbols + // + + OSSafeReleaseNULL(_smbusCompanion); + super::stop(provider); } @@ -1924,11 +1941,6 @@ void ApplePS2SynapticsTouchPad::setTrackpointProperties() void ApplePS2SynapticsTouchPad::setDevicePowerState( UInt32 whatToDo ) { - if (otherBusInUse) { - // SMBus/I2C is handling power management - return; - } - switch ( whatToDo ) { case kPS2C_DisableDevice: @@ -1992,7 +2004,7 @@ IOReturn ApplePS2SynapticsTouchPad::message(UInt32 type, IOService* provider, vo { bool enable = *((bool*)argument); // ignoreall is true when trackpad has been disabled - if (enable == ignoreall && !otherBusInUse) + if (enable == ignoreall) { // save state, and update LED ignoreall = !enable; @@ -2005,7 +2017,7 @@ IOReturn ApplePS2SynapticsTouchPad::message(UInt32 type, IOService* provider, vo { int* reqCode = (int*)argument; IOLog("VoodooPS2SynapticsTouchPad::kPS2M_resetTouchpad reqCode: %d\n", *reqCode); - if (*reqCode == 1 && !otherBusInUse) + if (*reqCode == 1) { ignoreall = false; initTouchPad(); @@ -2095,17 +2107,6 @@ IOReturn ApplePS2SynapticsTouchPad::message(UInt32 type, IOService* provider, vo keycode = pInfo->adbKeyCode; break; } - case kPS2M_SMBusStart: { - // Trackpad is being taken over by another driver - - // Queries/standing up before this point needs to be reset - // Fixes issues with CSM/Fast Boot on HP laptops - doHardwareReset(); - - // Prevent any PS2 transactions, otherwise the trackpad can completely lock up from PS2 commands - // This is called after ::start (specifically registerService()), so only prevent power management/reset msgs - otherBusInUse = true; - } } return kIOReturnSuccess; diff --git a/VoodooPS2Trackpad/VoodooPS2SynapticsTouchPad.h b/VoodooPS2Trackpad/VoodooPS2SynapticsTouchPad.h index 85c7a1dc..061a9981 100644 --- a/VoodooPS2Trackpad/VoodooPS2SynapticsTouchPad.h +++ b/VoodooPS2Trackpad/VoodooPS2SynapticsTouchPad.h @@ -315,7 +315,6 @@ class EXPORT ApplePS2SynapticsTouchPad : public IOService uint64_t keytime {0}; UInt16 keycode {0}; bool ignoreall {false}; - bool otherBusInUse {false}; // Trackpad being used over SMBus/I2C #ifdef SIMULATE_PASSTHRU UInt32 trackbuttons {0}; #endif @@ -324,6 +323,8 @@ class EXPORT ApplePS2SynapticsTouchPad : public IOService int _processusbmouse {true}; int _processbluetoothmouse {true}; + const OSSymbol* _smbusCompanion {nullptr}; + OSSet* attachedHIDPointerDevices {nullptr}; IONotifier* usb_hid_publish_notify {nullptr}; // Notification when an USB mouse HID device is connected @@ -376,8 +377,7 @@ class EXPORT ApplePS2SynapticsTouchPad : public IOService public: bool init( OSDictionary * properties ) override; - ApplePS2SynapticsTouchPad * probe( IOService * provider, - SInt32 * score ) override; + IOService * probe( IOService * provider, SInt32 * score ) override; bool start( IOService * provider ) override; void stop( IOService * provider ) override; From 80e0171e2695ba68bbfcb4916bc1ce5d00b5a37a Mon Sep 17 00:00:00 2001 From: Avery Black Date: Fri, 4 Oct 2024 09:46:29 -0700 Subject: [PATCH 095/101] Sync Changelog --- Changelog.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Changelog.md b/Changelog.md index 14f2e9cc..f6655e33 100644 --- a/Changelog.md +++ b/Changelog.md @@ -2,6 +2,8 @@ VoodooPS2 Changelog ============================ #### v2.3.6 - Lowered macOS requirements to 10.10 +- Added PS/2 stub driver for better VoodooRMI compatibility +- Removed old external reset interface originally used by VoodooRMI #### v2.3.5 - Removed actAsTrackpad and related logic From f38140076907058028f26751266e52386f514600 Mon Sep 17 00:00:00 2001 From: Avery Black Date: Sat, 12 Oct 2024 09:00:31 -0700 Subject: [PATCH 096/101] 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 dcebfd07..362193ad 100644 --- a/VoodooPS2Controller.xcodeproj/project.pbxproj +++ b/VoodooPS2Controller.xcodeproj/project.pbxproj @@ -773,7 +773,7 @@ KERNEL_FRAMEWORK_HEADERS = "$(PROJECT_DIR)/MacKernelSDK/Headers"; "LLVM_LTO[arch=x86_64]" = YES; MACOSX_DEPLOYMENT_TARGET = 10.10; - MODULE_VERSION = 2.3.6; + MODULE_VERSION = 2.3.7; ONLY_ACTIVE_ARCH = YES; "OTHER_LDFLAGS[arch=x86_64]" = "-dead_strip"; PRODUCT_NAME = VoodooPS2Controller; @@ -828,7 +828,7 @@ KERNEL_FRAMEWORK_HEADERS = "$(PROJECT_DIR)/MacKernelSDK/Headers"; "LLVM_LTO[arch=x86_64]" = YES; MACOSX_DEPLOYMENT_TARGET = 10.10; - MODULE_VERSION = 2.3.6; + MODULE_VERSION = 2.3.7; "OTHER_LDFLAGS[arch=x86_64]" = "-dead_strip"; PRODUCT_NAME = VoodooPS2Controller; SDKROOT = macosx; From 7350e3ee759418cdad452a7755f63da9372cbc67 Mon Sep 17 00:00:00 2001 From: Avery Black Date: Sun, 13 Oct 2024 06:55:22 -0700 Subject: [PATCH 097/101] Fixed multiple PS2/SMBus devices attaching (#64) --- Changelog.md | 3 +++ VoodooPS2Trackpad/VoodooPS2SynapticsTouchPad.cpp | 4 ++++ 2 files changed, 7 insertions(+) diff --git a/Changelog.md b/Changelog.md index f6655e33..2ede4810 100644 --- a/Changelog.md +++ b/Changelog.md @@ -1,5 +1,8 @@ VoodooPS2 Changelog ============================ +#### v2.3.7 +- Fixed multiple PS2/SMBus devices attaching + #### v2.3.6 - Lowered macOS requirements to 10.10 - Added PS/2 stub driver for better VoodooRMI compatibility diff --git a/VoodooPS2Trackpad/VoodooPS2SynapticsTouchPad.cpp b/VoodooPS2Trackpad/VoodooPS2SynapticsTouchPad.cpp index f8cdf8e7..ee668b82 100644 --- a/VoodooPS2Trackpad/VoodooPS2SynapticsTouchPad.cpp +++ b/VoodooPS2Trackpad/VoodooPS2SynapticsTouchPad.cpp @@ -213,6 +213,10 @@ IOService* ApplePS2SynapticsTouchPad::probe(IOService * provider, SInt32 * score dictionary->setObject("Clickpad", _cont_caps.one_btn_clickpad ? kOSBooleanTrue : kOSBooleanFalse); ApplePS2SmbusDevice *smbus = ApplePS2SmbusDevice::withReset(true, dictionary, 0x2C); + + // gIOMatchCategoryKey is necessary to prevent multiple services attaching to the PS2 device + if (smbus) + smbus->setProperty(gIOMatchCategoryKey, getProperty(gIOMatchCategoryKey)); OSSafeReleaseNULL(dictionary); return smbus; } From bdbf80639936701337f4574bae8c3ea25bb8dd3d Mon Sep 17 00:00:00 2001 From: Avery Black Date: Sun, 13 Oct 2024 07:47:14 -0700 Subject: [PATCH 098/101] Disable PS/2 stub on shutdown (#65) --- Changelog.md | 1 + VoodooPS2Trackpad/VoodooPS2SMBusDevice.cpp | 6 ++++++ VoodooPS2Trackpad/VoodooPS2SMBusDevice.h | 1 + 3 files changed, 8 insertions(+) diff --git a/Changelog.md b/Changelog.md index 2ede4810..34156d34 100644 --- a/Changelog.md +++ b/Changelog.md @@ -2,6 +2,7 @@ VoodooPS2 Changelog ============================ #### v2.3.7 - Fixed multiple PS2/SMBus devices attaching +- Fixed eratic pointer in bootpicker by disabling SMBus/PS2 devices on shutdown #### v2.3.6 - Lowered macOS requirements to 10.10 diff --git a/VoodooPS2Trackpad/VoodooPS2SMBusDevice.cpp b/VoodooPS2Trackpad/VoodooPS2SMBusDevice.cpp index 36803959..7b938230 100644 --- a/VoodooPS2Trackpad/VoodooPS2SMBusDevice.cpp +++ b/VoodooPS2Trackpad/VoodooPS2SMBusDevice.cpp @@ -53,6 +53,12 @@ bool ApplePS2SmbusDevice::start(IOService *provider) { return true; } +void ApplePS2SmbusDevice::stop(IOService *provider) { + _nub->uninstallPowerControlAction(); + resetDevice(); + super::stop(provider); +} + void ApplePS2SmbusDevice::free() { OSSafeReleaseNULL(_data); super::free(); diff --git a/VoodooPS2Trackpad/VoodooPS2SMBusDevice.h b/VoodooPS2Trackpad/VoodooPS2SMBusDevice.h index 26f386cd..de3bfd75 100644 --- a/VoodooPS2Trackpad/VoodooPS2SMBusDevice.h +++ b/VoodooPS2Trackpad/VoodooPS2SMBusDevice.h @@ -30,6 +30,7 @@ class EXPORT ApplePS2SmbusDevice : public IOService { static ApplePS2SmbusDevice *withReset(bool resetNeeded, OSDictionary *data, uint8_t addr); bool start(IOService *provider) override; + void stop(IOService *provider) override; void free() override; private: From 3175575e19cf0e8ce8b3789f33ffc4b280f086ce Mon Sep 17 00:00:00 2001 From: Andrey1970 Date: Mon, 30 Dec 2024 01:35:35 +0300 Subject: [PATCH 099/101] 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 362193ad..a4fa4a14 100644 --- a/VoodooPS2Controller.xcodeproj/project.pbxproj +++ b/VoodooPS2Controller.xcodeproj/project.pbxproj @@ -773,7 +773,7 @@ KERNEL_FRAMEWORK_HEADERS = "$(PROJECT_DIR)/MacKernelSDK/Headers"; "LLVM_LTO[arch=x86_64]" = YES; MACOSX_DEPLOYMENT_TARGET = 10.10; - MODULE_VERSION = 2.3.7; + MODULE_VERSION = 2.3.8; ONLY_ACTIVE_ARCH = YES; "OTHER_LDFLAGS[arch=x86_64]" = "-dead_strip"; PRODUCT_NAME = VoodooPS2Controller; @@ -828,7 +828,7 @@ KERNEL_FRAMEWORK_HEADERS = "$(PROJECT_DIR)/MacKernelSDK/Headers"; "LLVM_LTO[arch=x86_64]" = YES; MACOSX_DEPLOYMENT_TARGET = 10.10; - MODULE_VERSION = 2.3.7; + MODULE_VERSION = 2.3.8; "OTHER_LDFLAGS[arch=x86_64]" = "-dead_strip"; PRODUCT_NAME = VoodooPS2Controller; SDKROOT = macosx; From b6713c37b9919bd95c3b7f4d484bd049371bcfc1 Mon Sep 17 00:00:00 2001 From: Andrey1970 Date: Tue, 7 Jan 2025 19:59:43 +0300 Subject: [PATCH 100/101] Update CI badge links --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 0e450785..41846e7b 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ VoodooPS2 ========= -[![Build Status](https://github.com/acidanthera/VoodooPS2/workflows/CI/badge.svg?branch=master)](https://github.com/acidanthera/VoodooPS2/actions) [![Scan Status](https://scan.coverity.com/projects/22190/badge.svg?flat=1)](https://scan.coverity.com/projects/22190) +[![Build Status](https://github.com/acidanthera/VoodooPS2/actions/workflows/main.yml/badge.svg?branch=master)](https://github.com/acidanthera/VoodooPS2/actions) [![Scan Status](https://scan.coverity.com/projects/22190/badge.svg?flat=1)](https://scan.coverity.com/projects/22190) New **VoodooPS2Trackpad** uses VoodooInput's Magic Trackpad II emulation in order to use macOS native driver instead of handling all gestures itself. This enables the use of any from one to four finger gestures defined by Apple including: * Look up & data detectors From 7eab4a344d901d1e4aa6ece4189ecde5a7356287 Mon Sep 17 00:00:00 2001 From: Avery Black Date: Sun, 2 Nov 2025 08:35:31 -0800 Subject: [PATCH 101/101] Update GitHub actions (#67) --- .github/workflows/main.yml | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 960ef254..68e40d7b 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -17,8 +17,8 @@ jobs: env: JOB_TYPE: BUILD steps: - - uses: actions/checkout@v3 - - uses: actions/checkout@v3 + - uses: actions/checkout@v5 + - uses: actions/checkout@v5 with: repository: acidanthera/MacKernelSDK path: MacKernelSDK @@ -33,13 +33,13 @@ jobs: - run: xcodebuild -jobs 1 -configuration Release - name: Upload to Artifacts - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: name: Artifacts path: build/*/*/*.zip - name: Upload to Release if: github.event_name == 'release' - uses: svenstaro/upload-release-action@e74ff71f7d8a4c4745b560a485cc5fdb9b5b999d + uses: svenstaro/upload-release-action@81c65b7cd4de9b2570615ce3aad67a41de5b1a13 with: repo_token: ${{ secrets.GITHUB_TOKEN }} file: build/*/*/*.zip @@ -52,8 +52,8 @@ jobs: env: JOB_TYPE: ANALYZE steps: - - uses: actions/checkout@v3 - - uses: actions/checkout@v3 + - uses: actions/checkout@v5 + - uses: actions/checkout@v5 with: repository: acidanthera/MacKernelSDK path: MacKernelSDK @@ -74,8 +74,8 @@ jobs: JOB_TYPE: COVERITY if: github.repository_owner == 'acidanthera' && github.event_name != 'pull_request' steps: - - uses: actions/checkout@v3 - - uses: actions/checkout@v3 + - uses: actions/checkout@v5 + - uses: actions/checkout@v5 with: repository: acidanthera/MacKernelSDK path: MacKernelSDK