diff --git a/VoodooRMI.xcodeproj/project.pbxproj b/VoodooRMI.xcodeproj/project.pbxproj index 3dd66bf..f91ba1e 100644 --- a/VoodooRMI.xcodeproj/project.pbxproj +++ b/VoodooRMI.xcodeproj/project.pbxproj @@ -148,8 +148,8 @@ isa = PBXGroup; children = ( 286587D824C13D9600E74848 /* Info.plist */, - A4560F0B247F406F0009CBE0 /* RMISMBus.cpp */, 286587AE24C13D0B00E74848 /* RMISMBus.hpp */, + A4560F0B247F406F0009CBE0 /* RMISMBus.cpp */, ); path = SMBus; sourceTree = ""; diff --git a/VoodooRMI/Functions/F01.cpp b/VoodooRMI/Functions/F01.cpp index 4e819ed..0499dd4 100644 --- a/VoodooRMI/Functions/F01.cpp +++ b/VoodooRMI/Functions/F01.cpp @@ -449,20 +449,22 @@ void F01::rmi_f01_attention() IOReturn F01::message(UInt32 type, IOService *provider, void *argument) { - int error; + int error = 0; switch (type) { - case kHandleRMISuspend: + case kHandleRMISleep: error = rmi_f01_suspend(); - if (error) return kIOReturnError; break; case kHandleRMIResume: error = rmi_f01_resume(); - if (error) return kIOReturnError; break; case kHandleRMIAttention: rmi_f01_attention(); break; + case kHandleRMIConfig: + error = rmi_f01_config(); + break; } + if (error) return kIOReturnError; return kIOReturnSuccess; } diff --git a/VoodooRMI/Functions/F03.hpp b/VoodooRMI/Functions/F03.hpp index a2b7d93..a681dc1 100644 --- a/VoodooRMI/Functions/F03.hpp +++ b/VoodooRMI/Functions/F03.hpp @@ -158,15 +158,15 @@ class F03 : public RMIFunction { IOWorkLoop* getWorkLoop(); - int rmi_f03_pt_write (unsigned char val); + int rmi_f03_pt_write(unsigned char val); int ps2DoSendbyteGated(u8 byte, uint64_t timeout); int ps2CommandGated(u8 *param, unsigned int *command); int ps2Command(u8 *param, unsigned int command); void handleByte(u8); void initPS2(); - void initPS2Interrupt (OSObject *owner, IOTimerEventSource *timer); + void initPS2Interrupt(OSObject *owner, IOTimerEventSource *timer); // TODO: Move to math file as long as with abs in rmi_driver.h - int signum (int value); + int signum(int value); void handlePacket(u8 *packet); }; diff --git a/VoodooRMI/Functions/F11.cpp b/VoodooRMI/Functions/F11.cpp index 5a7ae03..0229f61 100644 --- a/VoodooRMI/Functions/F11.cpp +++ b/VoodooRMI/Functions/F11.cpp @@ -54,13 +54,10 @@ bool F11::start(IOService *provider) if (!super::start(provider)) return false; - int rc; - - rc = f11_write_control_regs(&sens_query, &dev_controls, - fn_descriptor->query_base_addr); + int rc = rmi_f11_config(); if (rc < 0) - return !rc; + return false; registerService(); @@ -97,6 +94,9 @@ IOReturn F11::message(UInt32 type, IOService *provider, void *argument) case kHandleRMIClickpadSet: case kHandleRMITrackpoint: return messageClient(type, sensor, argument); + case kHandleRMIConfig: + rmi_f11_config(); + break; } return kIOReturnSuccess; @@ -168,6 +168,12 @@ bool F11::getReport() return true; } +int F11::rmi_f11_config() +{ + return f11_write_control_regs(&sens_query, &dev_controls, + fn_descriptor->query_base_addr); +} + int F11::f11_read_control_regs(f11_2d_ctrl *ctrl, u16 ctrl_base_addr) { int error = 0; diff --git a/VoodooRMI/Functions/F11.hpp b/VoodooRMI/Functions/F11.hpp index f1e8f4b..f87fc91 100644 --- a/VoodooRMI/Functions/F11.hpp +++ b/VoodooRMI/Functions/F11.hpp @@ -540,6 +540,7 @@ class F11 : public RMIFunction { unsigned long *rel_mask; bool getReport(); + int rmi_f11_config(); int rmi_f11_initialize(); int rmi_f11_get_query_parameters(f11_2d_sensor_queries *sensor_query, u16 query_base_addr); diff --git a/VoodooRMI/Functions/F12.cpp b/VoodooRMI/Functions/F12.cpp index 37f8c0f..02a0f7f 100644 --- a/VoodooRMI/Functions/F12.cpp +++ b/VoodooRMI/Functions/F12.cpp @@ -145,6 +145,54 @@ bool F12::attach(IOService *provider) } bool F12::start(IOService *provider) +{ + int ret = rmi_f12_config(); + if (ret < 0) + return false; + + registerService(); + + if (!sensor->attach(this)) + return false; + + if (!sensor->start(this)) + return false; + + return super::start(provider); +} + +void F12::stop(IOService *provider) +{ + sensor->detach(this); + sensor->stop(this); + super::stop(provider); +} + +void F12::free() +{ + clearDesc(); + OSSafeReleaseNULL(sensor); + super::free(); +} + +IOReturn F12::message(UInt32 type, IOService *provider, void *argument) +{ + switch (type) + { + case kHandleRMIAttention: + getReport(); + break; + case kHandleRMIClickpadSet: + case kHandleRMITrackpoint: + return messageClient(type, sensor, argument); + case kHandleRMIConfig: + return rmi_f12_config(); + } + + return kIOReturnSuccess; +} + +int F12::rmi_f12_config() { const struct rmi_register_desc_item *item; unsigned long control_size; @@ -191,43 +239,6 @@ bool F12::start(IOService *provider) } } - registerService(); - - if (!sensor->attach(this)) - return false; - - if (!sensor->start(this)) - return false; - - return super::start(provider); -} - -void F12::stop(IOService *provider) -{ - sensor->detach(this); - sensor->stop(this); - super::stop(provider); -} - -void F12::free() -{ - clearDesc(); - OSSafeReleaseNULL(sensor); - super::free(); -} - -IOReturn F12::message(UInt32 type, IOService *provider, void *argument) -{ - switch (type) - { - case kHandleRMIAttention: - getReport(); - break; - case kHandleRMIClickpadSet: - case kHandleRMITrackpoint: - return messageClient(type, sensor, argument); - } - return kIOReturnSuccess; } diff --git a/VoodooRMI/Functions/F12.hpp b/VoodooRMI/Functions/F12.hpp index fdd1b88..cc57580 100644 --- a/VoodooRMI/Functions/F12.hpp +++ b/VoodooRMI/Functions/F12.hpp @@ -72,6 +72,8 @@ class F12 : public RMIFunction { static bool rmi_register_desc_has_subpacket(const rmi_register_desc_item *item, u8 subpacket); + int rmi_f12_config(); + /* F12 Data */ RMI2DSensor *sensor; struct rmi_2d_sensor_platform_data sensor_pdata; diff --git a/VoodooRMI/Functions/F30.cpp b/VoodooRMI/Functions/F30.cpp index e820d48..096ff18 100644 --- a/VoodooRMI/Functions/F30.cpp +++ b/VoodooRMI/Functions/F30.cpp @@ -34,14 +34,8 @@ bool F30::start(IOService *provider) if (!super::start(provider)) return false; - int error = rmiBus->blockWrite(fn_descriptor->control_base_addr, - ctrl_regs, ctrl_regs_size); - - if (error) { - IOLogError("%s: Could not write control registers at 0x%x: 0x%x", - __func__, fn_descriptor->control_base_addr, error); - return false;; - } + int ret = rmi_f30_config(); + if (ret < 0) return false; voodooTrackpointInstance = rmiBus->getVoodooInput(); @@ -62,9 +56,10 @@ void F30::free() IOReturn F30::message(UInt32 type, IOService *provider, void *argument) { + int error; switch (type) { case kHandleRMIAttention: - int error = rmiBus->readBlock(fn_descriptor->data_base_addr, + error = rmiBus->readBlock(fn_descriptor->data_base_addr, data_regs, register_count); if (error < 0) { @@ -76,11 +71,25 @@ IOReturn F30::message(UInt32 type, IOService *provider, void *argument) rmi_f30_report_button(); break; + case kHandleRMIConfig: + return rmi_f30_config(); } return kIOReturnSuccess; } +int F30::rmi_f30_config() +{ + int error = rmiBus->blockWrite(fn_descriptor->control_base_addr, + ctrl_regs, ctrl_regs_size); + + if (error) { + IOLogError("%s: Could not write control registers at 0x%x: 0x%x", + __func__, fn_descriptor->control_base_addr, error); + } + return error; +} + int F30::rmi_f30_initialize() { u8 *ctrl_reg = ctrl_regs; diff --git a/VoodooRMI/Functions/F30.hpp b/VoodooRMI/Functions/F30.hpp index 84fcc1d..4debefe 100644 --- a/VoodooRMI/Functions/F30.hpp +++ b/VoodooRMI/Functions/F30.hpp @@ -97,6 +97,7 @@ class F30 : public RMIFunction { bool hasTrackpointButtons; int rmi_f30_initialize(); + int rmi_f30_config(); void rmi_f30_set_ctrl_data(rmi_f30_ctrl_data *ctrl, int *ctrl_addr, int len, u8 **reg); int rmi_f30_read_control_parameters(); diff --git a/VoodooRMI/RMIBus.cpp b/VoodooRMI/RMIBus.cpp index 9094695..71cf028 100644 --- a/VoodooRMI/RMIBus.cpp +++ b/VoodooRMI/RMIBus.cpp @@ -82,10 +82,6 @@ bool RMIBus::start(IOService *provider) { if (retval) goto err; - PMinit(); - provider->joinPMtree(this); - registerPowerDriver(this, RMIPowerStates, 2); - setProperty(RMIBusIdentifier, kOSBooleanTrue); if (!transport->open(this)) @@ -165,26 +161,62 @@ void RMIBus::handleHostNotifyLegacy() OSSafeReleaseNULL(iter); } +void RMIBus::handleReset() +{ + if (!data || !data->f01_container) { + IOLogDebug("Device not ready for reset, ignoring..."); + return; + } + + int error = readBlock(data->f01_container->fd.control_base_addr + 1, + reinterpret_cast(&data->current_irq_mask), + data->num_of_irq_regs); + + if (error < 0) { + IOLogError("Failed to read current IRQ mask during reset!"); + return; + } + + messageClients(kHandleRMIConfig); +} + IOReturn RMIBus::message(UInt32 type, IOService *provider, void *argument) { + IOReturn err; + switch (type) { case kIOMessageVoodooI2CHostNotify: case kIOMessageVoodooSMBusHostNotify: - if (awake) - handleHostNotify(); - return kIOReturnSuccess; + handleHostNotify(); + break; case kIOMessageVoodooI2CLegacyHostNotify: - if (awake) - handleHostNotifyLegacy(); - return kIOReturnSuccess; + handleHostNotifyLegacy(); + break; + case kIOMessageRMI4ResetHandler: + handleReset(); + break; + case kIOMessageRMI4Sleep: + IOLogDebug("Sleep"); + messageClients(kHandleRMISleep); + rmi_driver_clear_irq_bits(this); + break; + case kIOMessageRMI4Resume: + IOLogDebug("Wakeup"); + err = rmi_driver_set_irq_bits(this); + if (err < 0) { + IOLogError("Could not wakeup device"); + return kIOReturnError; + } + messageClients(kHandleRMIResume); + break; default: return super::message(type, provider); } + + return kIOReturnSuccess; } void RMIBus::notify(UInt32 type, unsigned int argument) { - // TODO: Maybe make notify not check the type of message, and just send to all? - // Would save having to write cases for every message that goes through here. OSIterator* iter = OSCollectionIterator::withCollection(functions); while(RMIFunction *func = OSDynamicCast(RMIFunction, iter->getNextObject())) { switch (type) { @@ -208,36 +240,6 @@ void RMIBus::notify(UInt32 type, unsigned int argument) OSSafeReleaseNULL(iter); } -IOReturn RMIBus::setPowerState(unsigned long whichState, IOService* whatDevice) { - if (whatDevice != this) - return kIOPMAckImplied; - - if (whichState == 0 && awake) { - IOLogDebug("Sleep"); - messageClients(kHandleRMISuspend); - rmi_driver_clear_irq_bits(this); - awake = false; - } else if (!awake) { - IOSleep(1000); - IOLogDebug("Wakeup"); - if (reset() < 0) - IOLogError("Could not get SMBus Version on wakeup"); - // c++ lambdas are wack - // Sensor doesn't wake up if we don't scan property tables - rmi_scan_pdt(this, NULL, [](RMIBus *rmi_dev, - void *ctx, const struct pdt_entry *pdt) -> int - { - IOLogDebug("Function F%X found again", pdt->function_number); - return 0; - }); - rmi_driver_set_irq_bits(this); - messageClients(kHandleRMIResume); - awake = true; - } - - return kIOPMAckImplied; -} - void RMIBus::stop(IOService *provider) { OSIterator *iter = OSCollectionIterator::withCollection(functions); @@ -245,7 +247,6 @@ void RMIBus::stop(IOService *provider) { OSSafeReleaseNULL(commandGate); OSSafeReleaseNULL(workLoop); - PMstop(); rmi_driver_clear_irq_bits(this); while (RMIFunction *func = OSDynamicCast(RMIFunction, iter->getNextObject())) { diff --git a/VoodooRMI/RMIBus.hpp b/VoodooRMI/RMIBus.hpp index 79ea929..6b36da6 100644 --- a/VoodooRMI/RMIBus.hpp +++ b/VoodooRMI/RMIBus.hpp @@ -44,16 +44,13 @@ class RMIBus : public IOService { virtual void stop(IOService *provider) override; virtual bool willTerminate(IOService *provider, IOOptionBits options) override; virtual void free() override; - IOReturn setPowerState(unsigned long whichState, IOService* whatDevice) override; IOReturn message(UInt32 type, IOService *provider, void *argument = 0) override; IOReturn setProperties(OSObject* properties) override; - // TODO: Clean up pointers rmi_driver_data *data; RMITransport *transport; gpio_data gpio; - bool awake {true}; // rmi_read inline int read(u16 addr, u8 *buf) { @@ -98,6 +95,9 @@ class RMIBus : public IOService { void handleHostNotify(); void handleHostNotifyLegacy(); + void handleReset(); + + void configAllFunctions(); }; #endif /* RMIBus_h */ diff --git a/VoodooRMI/Transports/I2C/RMII2C.cpp b/VoodooRMI/Transports/I2C/RMII2C.cpp index 732e939..c1576fc 100644 --- a/VoodooRMI/Transports/I2C/RMII2C.cpp +++ b/VoodooRMI/Transports/I2C/RMII2C.cpp @@ -252,17 +252,24 @@ int RMII2C::rmi_set_mode(u8 mode) { if (device_nub->writeI2C(command, sizeof(command)) != kIOReturnSuccess) return -1; + + IOLogDebug("%s::%s mode set", getName(), name); - IOLogInfo("%s::%s reset completed", getName(), name); return 1; } int RMII2C::reset() { int retval = rmi_set_mode(reportMode); - if (retval >= 0) - ready = true; + if (retval < 0) + return retval; + + ready = true; + + // Tell driver to reconfigure + retval = messageClient(kIOMessageRMI4ResetHandler, bus); + IOLogInfo("%s::%s reset completed", getName(), name); return retval; }; @@ -314,6 +321,13 @@ int RMII2C::readBlock(u16 rmiaddr, u8 *databuff, size_t len) { if (i2cInput[2] != RMI_READ_DATA_REPORT_ID) { IOLogError("%s::%s RMI_READ_DATA_REPORT_ID mismatch %d", getName(), name, i2cInput[2]); + if (i2cInput[2] == HID_GENERIC_MOUSE || + i2cInput[2] == HID_GENERIC_POINTER) { + int err = reset(); + if (err < 0) { + IOLogError("Failed to reset trackpad after report id mismatch!"); + } + } retval = -1; goto exit; } @@ -392,13 +406,32 @@ IOReturn RMII2C::setPowerState(unsigned long powerState, IOService *whatDevice){ IOLogDebug("%s::%s powerState %ld : %s", getName(), name, powerState, powerState ? "on" : "off"); if (!bus) return kIOPMAckImplied; + if (whatDevice != this) return kIOReturnInvalid; - if (powerState == 0) + if (powerState == 0) { + messageClient(kIOMessageRMI4Sleep, bus); stopInterrupt(); - else + } else { startInterrupt(); + + // FIXME: Hardcode 1s sleep delay because device will otherwise time out during reconfig + IOSleep(1000); + + int retval = reset(); + if (retval < 0) { + IOLogError("Failed to config trackpad!"); + return kIOPMAckImplied; + } + + retval = messageClient(kIOMessageRMI4Resume, bus); + if (retval < 0) { + IOLogError("Failed to resume trackpad!"); + return kIOPMAckImplied; + } + } + return kIOPMAckImplied; } diff --git a/VoodooRMI/Transports/I2C/RMII2C.hpp b/VoodooRMI/Transports/I2C/RMII2C.hpp index ad9ba86..f7e307b 100644 --- a/VoodooRMI/Transports/I2C/RMII2C.hpp +++ b/VoodooRMI/Transports/I2C/RMII2C.hpp @@ -35,6 +35,9 @@ #define RMI_HID_DATA_REGISTER 0x23 #define RMI_HID_OUTPUT_REGISTER 0x25 +#define HID_GENERIC_POINTER 0x01 +#define HID_GENERIC_MOUSE 0x02 + #define INTERRUPT_SIMULATOR_INTERVAL 200 #define INTERRUPT_SIMULATOR_TIMEOUT 5 #define INTERRUPT_SIMULATOR_TIMEOUT_BUSY 2 diff --git a/VoodooRMI/Transports/RMITransport.hpp b/VoodooRMI/Transports/RMITransport.hpp index 5bc18d8..2397964 100644 --- a/VoodooRMI/Transports/RMITransport.hpp +++ b/VoodooRMI/Transports/RMITransport.hpp @@ -17,9 +17,12 @@ #include "../Utility/Logging.h" #include "../rmi.h" -#define kIOMessageVoodooSMBusHostNotify iokit_vendor_specific_msg(420) -#define kIOMessageVoodooI2CHostNotify iokit_vendor_specific_msg(421) -#define kIOMessageVoodooI2CLegacyHostNotify iokit_vendor_specific_msg(422) +#define kIOMessageVoodooSMBusHostNotify iokit_vendor_specific_msg(420) +#define kIOMessageVoodooI2CHostNotify iokit_vendor_specific_msg(421) +#define kIOMessageVoodooI2CLegacyHostNotify iokit_vendor_specific_msg(422) +#define kIOMessageRMI4ResetHandler iokit_vendor_specific_msg(423) +#define kIOMessageRMI4Sleep iokit_vendor_specific_msg(424) +#define kIOMessageRMI4Resume iokit_vendor_specific_msg(425) #define RMIBusIdentifier "Synaptics RMI4 Device" #define RMIBusSupported "RMI4 Supported" diff --git a/VoodooRMI/Transports/SMBus/RMISMBus.cpp b/VoodooRMI/Transports/SMBus/RMISMBus.cpp index bc1419e..d5e26d4 100644 --- a/VoodooRMI/Transports/SMBus/RMISMBus.cpp +++ b/VoodooRMI/Transports/SMBus/RMISMBus.cpp @@ -117,6 +117,10 @@ bool RMISMBus::rmiStart() setProperty("SMBus Version", retval, 32); IOLogInfo("SMBus version %u", retval); + PMinit(); + device_nub->joinPMtree(this); + registerPowerDriver(this, RMIPowerStates, 2); + setProperty(RMIBusSupported, kOSBooleanTrue); registerService(); return true; @@ -124,6 +128,7 @@ bool RMISMBus::rmiStart() void RMISMBus::stop(IOService *provider) { + PMstop(); super::stop(provider); } @@ -140,7 +145,7 @@ int RMISMBus::rmi_smb_get_version() { int retval; - /* Check if for SMBus new version device by reading version byte. */ + /* Check for SMBus new version device by reading version byte. */ retval = device_nub->readByteData(SMB_PROTOCOL_VERSION_ADDRESS); if (retval < 0) { return retval; @@ -149,6 +154,18 @@ int RMISMBus::rmi_smb_get_version() return retval + 1; } +int RMISMBus::reset() +{ + /* Discard mapping table */ + IOLockLock(mapping_table_mutex); + memset(mapping_table, 0, sizeof(mapping_table)); + IOLockUnlock(mapping_table_mutex); + + // Full reset can only be done in PS2 + // Getting the version allows the trackpad to be used over SMBus + return rmi_smb_get_version(); +} + /* * The function to get command code for smbus operations and keeps * records to the driver mapping table @@ -289,3 +306,38 @@ IOReturn RMISMBus::message(UInt32 type, IOService *provider, void *argument) { return IOService::message(type, provider, argument); } }; + +IOReturn RMISMBus::setPowerState(unsigned long whichState, IOService* whatDevice) { + if (whatDevice != this) + return kIOPMAckImplied; + + if (whichState == 0) { + messageClient(kIOMessageRMI4Sleep, bus); + } else { + // FIXME: Hardcode 1s sleep delay because device will otherwise time out during reconfig + IOSleep(1000); + + // Put trackpad in SMBus mode again + int retval = reset(); + if (retval < 0) { + IOLogError("Failed to reset trackpad!"); + return kIOPMAckImplied; + } + + // Reconfigure device + retval = messageClient(kIOMessageRMI4ResetHandler, bus); + if (retval < 0) { + IOLogError("Failed to config trackpad!"); + return kIOPMAckImplied; + } + + // Enable trackpad again + retval = messageClient(kIOMessageRMI4Resume, bus); + if (retval < 0) { + IOLogError("Failed to resume trackpad!"); + return kIOPMAckImplied; + } + } + + return kIOPMAckImplied; +} diff --git a/VoodooRMI/Transports/SMBus/RMISMBus.hpp b/VoodooRMI/Transports/SMBus/RMISMBus.hpp index 1a9bb60..94d2cef 100644 --- a/VoodooRMI/Transports/SMBus/RMISMBus.hpp +++ b/VoodooRMI/Transports/SMBus/RMISMBus.hpp @@ -33,24 +33,14 @@ class RMISMBus : public RMITransport { RMISMBus *probe(IOService *provider, SInt32 *score) override; bool start(IOService *provider) override; IOReturn message(UInt32 type, IOService *provider, void *argument = 0) override; + IOReturn setPowerState(unsigned long whichState, IOService* whatDevice) override; void stop(IOService *provider) override; void free() override; int readBlock(u16 rmiaddr, u8 *databuff, size_t len) override; int blockWrite(u16 rmiaddr, u8 *buf, size_t len) override; - inline int reset() override { - /* Discord mapping table */ - IOLockLock(mapping_table_mutex); - memset(mapping_table, 0, sizeof(mapping_table)); - IOLockUnlock(mapping_table_mutex); - - /* - * I don't think this does a full reset, as it still seems to retain memory - * I believe a PS2 reset needs to be done to completely reset the sensor - */ - return rmi_smb_get_version(); - } + int reset() override; private: VoodooSMBusDeviceNub *device_nub; IOLock *page_mutex; diff --git a/VoodooRMI/rmi.h b/VoodooRMI/rmi.h index 476a63b..1cdd5e4 100644 --- a/VoodooRMI/rmi.h +++ b/VoodooRMI/rmi.h @@ -31,15 +31,16 @@ enum { kPS2M_SMBusStart = iokit_vendor_specific_msg(152), // Reset, disable PS2 comms to not interfere with SMBus comms }; -// RMI message types +// RMI Bus message types enum { kHandleRMIAttention = iokit_vendor_specific_msg(2046), kHandleRMIClickpadSet = iokit_vendor_specific_msg(2047), - kHandleRMISuspend = iokit_vendor_specific_msg(2048), + kHandleRMISleep = iokit_vendor_specific_msg(2048), kHandleRMIResume = iokit_vendor_specific_msg(2049), kHandleRMITrackpoint = iokit_vendor_specific_msg(2050), kHandleRMITrackpointButton = iokit_vendor_specific_msg(2051), - kHandleRMIInputReport = iokit_vendor_specific_msg(2052) + kHandleRMIInputReport = iokit_vendor_specific_msg(2052), + kHandleRMIConfig = iokit_vendor_specific_msg(2053), }; /*