From e23fb3ae5cf552856c18e888d149fbc7bbf386e8 Mon Sep 17 00:00:00 2001 From: Avery Black Date: Tue, 22 Oct 2024 19:04:59 -0700 Subject: [PATCH] Fix I2C HID Interrupt Behavior (#193) Read in HID interrupt reports rather than querying registers directly. Fixes freezing on boot and spammed IRQs on I2C touchpads. --- VoodooRMI/Functions/F01.cpp | 5 +- VoodooRMI/Functions/F01.hpp | 2 +- VoodooRMI/Functions/F03.cpp | 24 ++--- VoodooRMI/Functions/F03.hpp | 6 +- VoodooRMI/Functions/F11.cpp | 29 ++++-- VoodooRMI/Functions/F11.hpp | 2 +- VoodooRMI/Functions/F12.cpp | 98 ++++++++----------- VoodooRMI/Functions/F12.hpp | 21 +--- VoodooRMI/Functions/F17.cpp | 7 +- VoodooRMI/Functions/F17.hpp | 2 +- VoodooRMI/Functions/Input/RMIFunction.cpp | 33 +++++++ VoodooRMI/Functions/Input/RMIFunction.hpp | 4 +- VoodooRMI/Functions/Input/RMIGPIOFunction.cpp | 21 ++-- VoodooRMI/Functions/Input/RMIGPIOFunction.hpp | 4 +- .../Functions/Input/RMITrackpadFunction.hpp | 3 - .../Functions/Input/RMITrackpointFunction.cpp | 5 +- .../Functions/Input/RMITrackpointFunction.hpp | 1 + VoodooRMI/RMIBus.cpp | 41 +++----- VoodooRMI/RMIBus.hpp | 3 +- VoodooRMI/Transports/I2C/Info.plist | 2 - VoodooRMI/Transports/I2C/RMII2C.cpp | 70 ++++++------- VoodooRMI/Transports/I2C/RMII2C.hpp | 6 +- VoodooRMI/Transports/RMITransport.hpp | 41 ++++---- VoodooRMI/Transports/SMBus/RMISMBus.cpp | 3 +- 24 files changed, 213 insertions(+), 220 deletions(-) diff --git a/VoodooRMI/Functions/F01.cpp b/VoodooRMI/Functions/F01.cpp index 16a1c98..bdf1e72 100644 --- a/VoodooRMI/Functions/F01.cpp +++ b/VoodooRMI/Functions/F01.cpp @@ -373,13 +373,12 @@ int F01::rmi_f01_resume() return error; } -void F01::attention() +void F01::attention(AbsoluteTime time, UInt8 *data[], size_t *size) { - int error; + IOReturn error; UInt8 device_status = 0; error = readByte(getDataAddr(), &device_status); - if (error) { IOLogError("F01: Failed to read device status: %d", error); return; diff --git a/VoodooRMI/Functions/F01.hpp b/VoodooRMI/Functions/F01.hpp index 98c805e..04bec0b 100644 --- a/VoodooRMI/Functions/F01.hpp +++ b/VoodooRMI/Functions/F01.hpp @@ -125,7 +125,7 @@ class F01 : public RMIFunction { public: bool attach(IOService *provider) override; IOReturn config() override; - void attention() override; + void attention(AbsoluteTime time, UInt8 *data[], size_t *size) override; IOReturn setPowerState(unsigned long powerStateOrdinal, IOService *whatDevice) override; diff --git a/VoodooRMI/Functions/F03.cpp b/VoodooRMI/Functions/F03.cpp index 7b8ff87..116a25d 100644 --- a/VoodooRMI/Functions/F03.cpp +++ b/VoodooRMI/Functions/F03.cpp @@ -155,7 +155,7 @@ int F03::rmi_f03_pt_write(unsigned char val) return error; } -void F03::handlePacket(UInt8 *packet) +void F03::handlePacket(AbsoluteTime time, UInt8 *packet) { RMITrackpointReport report; // Trackpoint isn't initialized! @@ -172,6 +172,7 @@ void F03::handlePacket(UInt8 *packet) timer->enable(); } + report.timestamp = time; report.buttons = (packet[0] & 0x7); report.dx = ((packet[0] & 0x10) ? 0xffffff00 : 0) | packet[1]; report.dy = -(((packet[0] & 0x20) ? 0xffffff00 : 0) | packet[2]); @@ -199,26 +200,21 @@ IOReturn F03::setPowerState(unsigned long powerStateOrdinal, IOService *whatDevi return kIOPMAckImplied; } -void F03::attention() +void F03::attention(AbsoluteTime time, UInt8 *data[], size_t *size) { - const UInt16 data_addr = getDataAddr() + RMI_F03_OB_OFFSET; - const UInt8 ob_len = rx_queue_length * RMI_F03_OB_SIZE; - UInt8 obs[RMI_F03_QUEUE_LENGTH * RMI_F03_OB_SIZE]; + const UInt8 ob_len = RMI_F03_OB_OFFSET + (rx_queue_length * RMI_F03_OB_SIZE); + UInt8 obs[RMI_F03_OB_OFFSET + (RMI_F03_QUEUE_LENGTH * RMI_F03_OB_SIZE)]; - int error = readBlock(data_addr, obs, ob_len); - if (error) { - IOLogError("F03 - Failed to read output buffers: %d", error); + if (!getInputData(obs, ob_len, data, size)) return; - } - for (int i = 0; i < ob_len; i += RMI_F03_OB_SIZE) { + for (int i = RMI_F03_OB_OFFSET; i < ob_len; i += RMI_F03_OB_SIZE) { UInt8 ob_status = obs[i]; UInt8 ob_data = obs[i + RMI_F03_OB_DATA_OFFSET]; if (!(ob_status & RMI_F03_RX_DATA_OFB)) continue; - IOLogDebug("F03 - Recieved data over PS2: %x", ob_data); if (ob_status & RMI_F03_OB_FLAG_TIMEOUT) { IOLogDebug("F03 Timeout Flag"); @@ -229,7 +225,7 @@ void F03::attention() continue; } - handleByte(ob_data); + handleByte(time, ob_data); } } @@ -296,7 +292,7 @@ void F03::initPS2Interrupt(OSObject *owner, IOTimerEventSource *timer) timer->disable(); } -void F03::handleByte(UInt8 byte) +void F03::handleByte(AbsoluteTime time, UInt8 byte) { if (!cmdcnt && !flags) { // Wait for start of packets @@ -306,7 +302,7 @@ void F03::handleByte(UInt8 byte) databuf[index++] = byte; if (index == 3) - handlePacket(databuf); + handlePacket(time, databuf); return; } diff --git a/VoodooRMI/Functions/F03.hpp b/VoodooRMI/Functions/F03.hpp index 719a5f6..38ad054 100644 --- a/VoodooRMI/Functions/F03.hpp +++ b/VoodooRMI/Functions/F03.hpp @@ -24,7 +24,7 @@ class F03 : public RMITrackpointFunction { bool start(IOService *provider) override; void stop(IOService *provider) override; IOReturn setPowerState(unsigned long powerStateOrdinal, IOService *whatDevice) override; - void attention() override; + void attention(AbsoluteTime time, UInt8 *data[], size_t *size) override; private: IOWorkLoop *work_loop {nullptr}; @@ -53,11 +53,11 @@ class F03 : public RMITrackpointFunction { int ps2DoSendbyteGated(UInt8 byte, uint64_t timeout); int ps2CommandGated(UInt8 *param, unsigned int *command); int ps2Command(UInt8 *param, unsigned int command); - void handleByte(UInt8); + void handleByte(AbsoluteTime time, UInt8); void initPS2(); void initPS2Interrupt(OSObject *owner, IOTimerEventSource *timer); - void handlePacket(UInt8 *packet); + void handlePacket(AbsoluteTime time, UInt8 *packet); }; #endif /* F03_hpp */ diff --git a/VoodooRMI/Functions/F11.cpp b/VoodooRMI/Functions/F11.cpp index dcd29ff..8ee73df 100644 --- a/VoodooRMI/Functions/F11.cpp +++ b/VoodooRMI/Functions/F11.cpp @@ -40,22 +40,31 @@ void F11::free() super::free(); } -void F11::attention() +void F11::attention(AbsoluteTime time, UInt8 *data[], size_t *size) { int error, abs_size; size_t fingers; UInt8 finger_state; - AbsoluteTime timestamp; - error = readBlock(getDataAddr(), data_pkt, pkt_size); - if (error < 0) { - IOLogError("Could not read F11 attention data: %d", error); - return; + if (*data) { + if (*size < attn_size) { + IOLogError("F11 attention larger than remaining data"); + return; + } + + memcpy(data_pkt, *data, attn_size); + (*data) += attn_size; + (*size) -= attn_size; + } else { + error = readBlock(getDataAddr(), data_pkt, pkt_size); + + if (error < 0) { + IOLogError("F11 Could not read attention data: %d", error); + return; + } } - clock_get_uptime(×tamp); - - if (shouldDiscardReport(timestamp)) + if (shouldDiscardReport(time)) return; IOLogDebug("F11 Packet"); @@ -94,7 +103,7 @@ void F11::attention() } } - report.timestamp = timestamp; + report.timestamp = time; report.fingers = fingers; handleReport(&report); diff --git a/VoodooRMI/Functions/F11.hpp b/VoodooRMI/Functions/F11.hpp index 9af8c6f..d706356 100644 --- a/VoodooRMI/Functions/F11.hpp +++ b/VoodooRMI/Functions/F11.hpp @@ -500,7 +500,7 @@ class F11 : public RMITrackpadFunction { public: bool attach(IOService *provider) override; - void attention() override; + void attention(AbsoluteTime time, UInt8 *data[], size_t *size) override; void free() override; IOReturn config() override; diff --git a/VoodooRMI/Functions/F12.cpp b/VoodooRMI/Functions/F12.cpp index 58cbbb0..6610997 100644 --- a/VoodooRMI/Functions/F12.cpp +++ b/VoodooRMI/Functions/F12.cpp @@ -79,9 +79,9 @@ bool F12::attach(IOService *provider) /* * Figure out what data is contained in the data registers. HID devices * may have registers defined, but their data is not reported in the - * HID attention report. Registers which are not reported in the HID - * attention report check to see if the device is receiving data from - * HID attention reports. + * HID attention report. As we don't care about pen or acm data, we can do + * a simplified check for ACM data to get attention size and ignore the data + * offset. */ item = rmi_get_register_desc_item(&data_reg_desc, 0); if (item) @@ -89,43 +89,23 @@ bool F12::attach(IOService *provider) item = rmi_get_register_desc_item(&data_reg_desc, 1); if (!item) { - return false; IOLogError("F12 - No Data1 Reg!"); + return false; } - - data1 = item; + data1_offset = data_offset; - data_offset += item->reg_size; - nbr_fingers = item->num_subpackets; - report_abs = 1; attn_size += item->reg_size; - - item = rmi_get_register_desc_item(&data_reg_desc, 2); - if (item) - data_offset += item->reg_size; - - item = rmi_get_register_desc_item(&data_reg_desc, 3); - if (item) - data_offset += item->reg_size; - - item = rmi_get_register_desc_item(&data_reg_desc, 4); - if (item) - data_offset += item->reg_size; + nbr_fingers = item->num_subpackets; item = rmi_get_register_desc_item(&data_reg_desc, 5); - if (item) { - data5 = item; - data5_offset = data_offset; - data_offset += item->reg_size; + if (item) attn_size += item->reg_size; - } - // Skip 6-15 as they do not increase attention size and only gives relative info + // Skip 6-15 as they do not increase attention size setProperty("Number of fingers", nbr_fingers, 8); IOLogDebug("F12 - Number of fingers %u", nbr_fingers); - return true; } @@ -267,22 +247,31 @@ int F12::rmi_f12_read_sensor_tuning() return 0; } -void F12::attention() +void F12::attention(AbsoluteTime time, UInt8 *data[], size_t *size) { - AbsoluteTime timestamp; - - if (!data1) - return; - - int retval = readBlock(getDataAddr(), data_pkt, pkt_size); - - if (retval < 0) { - IOLogError("F12 - Failed to read object data. Code: %d", retval); - return; + RMI2DSensorReport report {}; + size_t offset = data1_offset; + + if (*data) { + if (*size < attn_size) { + IOLogError("F12 attention larger than remaining data"); + return; + } + + memcpy(data_pkt, *data, attn_size); + (*data) += attn_size; + (*size) -= attn_size; + offset = 0; + } else { + IOReturn error = readBlock(getDataAddr(), data_pkt, pkt_size); + + if (error < 0) { + IOLogError("F12 Could not read attention data: %d", error); + return; + } } - clock_get_uptime(×tamp); - if (shouldDiscardReport(timestamp)) + if (shouldDiscardReport(time)) return; IOLogDebug("F12 Packet"); @@ -293,32 +282,29 @@ void F12::attention() #endif // debug int fingers = min (nbr_fingers, 5); - UInt8 *data = &data_pkt[data1_offset]; - for (int i = 0; i < fingers; i++) { - rmi_2d_sensor_abs_object *obj = &report.objs[i]; + rmi_2d_sensor_abs_object &obj = report.objs[i]; + UInt8 *fingerData = &data_pkt[offset + (i * F12_DATA1_BYTES_PER_OBJ)]; - switch (data[0]) { + switch (fingerData[0]) { case RMI_F12_OBJECT_FINGER: - obj->type = RMI_2D_OBJECT_FINGER; + obj.type = RMI_2D_OBJECT_FINGER; break; case RMI_F12_OBJECT_STYLUS: - obj->type = RMI_2D_OBJECT_STYLUS; + obj.type = RMI_2D_OBJECT_STYLUS; break; default: - obj->type = RMI_2D_OBJECT_NONE; + obj.type = RMI_2D_OBJECT_NONE; } - obj->x = (data[2] << 8) | data[1]; - obj->y = (data[4] << 8) | data[3]; - obj->z = data[5]; - obj->wx = data[6]; - obj->wy = data[7]; - - data += F12_DATA1_BYTES_PER_OBJ; + obj.x = (fingerData[2] << 8) | fingerData[1]; + obj.y = (fingerData[4] << 8) | fingerData[3]; + obj.z = fingerData[5]; + obj.wx = fingerData[6]; + obj.wy = fingerData[7]; } - report.timestamp = timestamp; + report.timestamp = time; report.fingers = fingers; handleReport(&report); diff --git a/VoodooRMI/Functions/F12.hpp b/VoodooRMI/Functions/F12.hpp index d6d011e..03bd5e3 100644 --- a/VoodooRMI/Functions/F12.hpp +++ b/VoodooRMI/Functions/F12.hpp @@ -54,7 +54,7 @@ class F12 : public RMITrackpadFunction { public: bool attach(IOService *provider) override; - void attention() override; + void attention(AbsoluteTime time, UInt8 *data[], size_t *size) override; void free() override; IOReturn config() override; @@ -62,8 +62,6 @@ class F12 : public RMITrackpadFunction { private: IOService *voodooInputInstance {nullptr}; - RMI2DSensorReport report {}; - static rmi_register_desc_item *rmi_get_register_desc_item(rmi_register_descriptor *rdesc, UInt16 reg); static size_t rmi_register_desc_calc_size(rmi_register_descriptor *rdesc); static int rmi_register_desc_calc_reg_offset(rmi_register_descriptor *rdesc, UInt16 reg); @@ -72,26 +70,15 @@ class F12 : public RMITrackpadFunction { /* F12 Data */ UInt8 *data_pkt; - size_t pkt_size; - size_t attn_size; + size_t pkt_size {0}; + size_t attn_size {0}; bool has_dribble; + size_t data1_offset; rmi_register_descriptor query_reg_desc; rmi_register_descriptor control_reg_desc; rmi_register_descriptor data_reg_desc; - /* F12 Data1 describes sensed objects */ - const rmi_register_desc_item *data1 {nullptr}; - UInt16 data1_offset; - - /* F12 Data5 describes finger ACM */ - const rmi_register_desc_item *data5 {nullptr}; - UInt16 data5_offset; - - /* F12 Data5 describes Pen */ - const rmi_register_desc_item *data6 {nullptr}; - UInt16 data6_offset; - int rmi_f12_read_sensor_tuning(); int rmi_read_register_desc(UInt16 addr, rmi_register_descriptor *rdesc); diff --git a/VoodooRMI/Functions/F17.cpp b/VoodooRMI/Functions/F17.cpp index d07e68c..acf1a5f 100644 --- a/VoodooRMI/Functions/F17.cpp +++ b/VoodooRMI/Functions/F17.cpp @@ -34,7 +34,7 @@ void F17::free() super::free(); } -void F17::attention() +void F17::attention(AbsoluteTime time, UInt8 *data[], size_t *size) { int retval = 0; for (int i = 0; i < f17.query.number_of_sticks + 1 && !retval; i++) @@ -215,7 +215,6 @@ int F17::config() { int F17::rmi_f17_process_stick(struct rmi_f17_stick_data *stick) { int retval = 0; - const RmiConfiguration &conf = getConfiguration(); RMITrackpointReport report; if (stick->query.general.has_absolute) { @@ -244,8 +243,8 @@ int F17::rmi_f17_process_stick(struct rmi_f17_stick_data *stick) { } else { IOLogDebug("%s: Reporting dx: %d, dy: %d\n", __func__, stick->data.rel.x_delta, stick->data.rel.y_delta); - report.dx = (SInt32)((SInt64)stick->data.rel.x_delta * conf.trackpointMult / DEFAULT_MULT); - report.dy = -(SInt32)((SInt64)stick->data.rel.y_delta * conf.trackpointMult / DEFAULT_MULT); + report.dx = (SInt32)((SInt64)stick->data.rel.x_delta); + report.dy = -(SInt32)((SInt64)stick->data.rel.y_delta); report.buttons = 0; handleReport(&report); diff --git a/VoodooRMI/Functions/F17.hpp b/VoodooRMI/Functions/F17.hpp index cffbf10..c58ec70 100644 --- a/VoodooRMI/Functions/F17.hpp +++ b/VoodooRMI/Functions/F17.hpp @@ -150,7 +150,7 @@ class F17 : public RMITrackpointFunction { public: bool attach(IOService *provider) override; void free() override; - void attention() override; + void attention(AbsoluteTime time, UInt8 *data[], size_t *size) override; IOReturn config() override; private: diff --git a/VoodooRMI/Functions/Input/RMIFunction.cpp b/VoodooRMI/Functions/Input/RMIFunction.cpp index 137c5a5..801b57b 100644 --- a/VoodooRMI/Functions/Input/RMIFunction.cpp +++ b/VoodooRMI/Functions/Input/RMIFunction.cpp @@ -5,6 +5,7 @@ */ #include "RMIFunction.hpp" +#include "RMILogging.h" OSDefineMetaClassAndStructors(RMIFunction, IOService) @@ -39,3 +40,35 @@ bool RMIFunction::start(IOService *provider) { registerService(); return true; } + +bool RMIFunction::getInputData(UInt8 dest[], size_t destSize, UInt8 *srcData[], size_t *srcSize) { + if (*srcData) { + if (*srcSize < destSize) { + IOLogError("%s Attention size smaller than expected", getName()); + return false; + } + + memcpy(dest, *srcData, destSize); + (*srcData) += destSize; + (*srcSize) -= destSize; + return true; + } + + if (destSize == 1) { + IOReturn error = readByte(getDataAddr(), dest); + + if (error) { + IOLogError("%s Failed to read device status: %d", getName(), error); + return false; + } + } else { + IOReturn error = readBlock(getDataAddr(), dest, destSize); + + if (error) { + IOLogError("%s Failed to read block data: %d", getName(), error); + return false; + } + } + + return true; +} diff --git a/VoodooRMI/Functions/Input/RMIFunction.hpp b/VoodooRMI/Functions/Input/RMIFunction.hpp index 74e3a94..50dfebf 100644 --- a/VoodooRMI/Functions/Input/RMIFunction.hpp +++ b/VoodooRMI/Functions/Input/RMIFunction.hpp @@ -56,13 +56,15 @@ class RMIFunction : public IOService { virtual IOReturn config() { return kIOReturnSuccess; }; // Attention is called whenever this function has data. Any input data // should be read here. - virtual void attention() { }; + virtual void attention(AbsoluteTime time, UInt8 *data[], size_t *size) { }; private: RmiPdtEntry pdtEntry; RMIBus *bus {nullptr}; protected: + bool getInputData(UInt8 dest[], size_t destSize, UInt8 *srcData[], size_t *srcSize); + // Useful functions to talk to RMI4 devicce inline void sendVoodooInputPacket(UInt32 msg, void *packet) { IOService *vi = bus->getVoodooInput(); diff --git a/VoodooRMI/Functions/Input/RMIGPIOFunction.cpp b/VoodooRMI/Functions/Input/RMIGPIOFunction.cpp index 9f1c2e7..7acb262 100644 --- a/VoodooRMI/Functions/Input/RMIGPIOFunction.cpp +++ b/VoodooRMI/Functions/Input/RMIGPIOFunction.cpp @@ -96,20 +96,16 @@ int RMIGPIOFunction::mapGpios() return 0; } -void RMIGPIOFunction::attention() +void RMIGPIOFunction::attention(AbsoluteTime time, UInt8 *data[], size_t *size) { - int error = readBlock(getDataAddr(), - data_regs, register_count); - - if (error < 0) { - IOLogError("Could not read %s data: %d", getName(), error); - } - + if (!getInputData(data_regs, register_count, data, size)) + return; + if (has_gpio) - reportButton(); + reportButton(time); } -void RMIGPIOFunction::reportButton() +void RMIGPIOFunction::reportButton(AbsoluteTime time) { TrackpointReport relativeEvent {}; unsigned int mask, trackpointBtns = 0, btns = 0; @@ -150,12 +146,9 @@ void RMIGPIOFunction::reportButton() } if (numButtons > 1) { - AbsoluteTime timestamp; - clock_get_uptime(×tamp); - relativeEvent.dx = relativeEvent.dy = 0; relativeEvent.buttons = btns; - relativeEvent.timestamp = timestamp; + relativeEvent.timestamp = time; sendVoodooInputPacket(kIOMessageVoodooTrackpointRelativePointer, &relativeEvent); } diff --git a/VoodooRMI/Functions/Input/RMIGPIOFunction.hpp b/VoodooRMI/Functions/Input/RMIGPIOFunction.hpp index 8c51a36..33d34a8 100644 --- a/VoodooRMI/Functions/Input/RMIGPIOFunction.hpp +++ b/VoodooRMI/Functions/Input/RMIGPIOFunction.hpp @@ -18,7 +18,7 @@ class RMIGPIOFunction : public RMIFunction { public: bool attach(IOService *provider) override; IOReturn config() override; - void attention() override; + void attention(AbsoluteTime time, UInt8 *data[], size_t *size) override; void free() override; protected: @@ -42,7 +42,7 @@ class RMIGPIOFunction : public RMIFunction { virtual inline bool is_valid_button(int button) {return false;}; int mapGpios(); - void reportButton(); + void reportButton(AbsoluteTime time); }; #endif /* RMIGPIOFunction_hpp */ diff --git a/VoodooRMI/Functions/Input/RMITrackpadFunction.hpp b/VoodooRMI/Functions/Input/RMITrackpadFunction.hpp index b3939ec..6523103 100644 --- a/VoodooRMI/Functions/Input/RMITrackpadFunction.hpp +++ b/VoodooRMI/Functions/Input/RMITrackpadFunction.hpp @@ -82,9 +82,6 @@ class RMITrackpadFunction : public RMIFunction { const Rmi2DSensorData &getData() const; protected: - UInt8 report_abs {0}; - UInt8 report_rel {0}; - UInt8 nbr_fingers; void handleReport(RMI2DSensorReport *report); diff --git a/VoodooRMI/Functions/Input/RMITrackpointFunction.cpp b/VoodooRMI/Functions/Input/RMITrackpointFunction.cpp index bafc8f3..f44ec2c 100644 --- a/VoodooRMI/Functions/Input/RMITrackpointFunction.cpp +++ b/VoodooRMI/Functions/Input/RMITrackpointFunction.cpp @@ -9,14 +9,11 @@ OSDefineMetaClassAndStructors(RMITrackpointFunction, RMIFunction) void RMITrackpointFunction::handleReport(RMITrackpointReport *report) { - AbsoluteTime timestamp; - clock_get_uptime(×tamp); - TrackpointReport trackpointReport; + trackpointReport.timestamp = report->timestamp; trackpointReport.dx = report->dx; trackpointReport.dy = report->dy; trackpointReport.buttons = report->buttons | overwrite_buttons; - trackpointReport.timestamp = timestamp; sendVoodooInputPacket(kIOMessageVoodooTrackpointMessage, &trackpointReport); if (report->dx || report->dy) { diff --git a/VoodooRMI/Functions/Input/RMITrackpointFunction.hpp b/VoodooRMI/Functions/Input/RMITrackpointFunction.hpp index 40ebef5..89d53a4 100644 --- a/VoodooRMI/Functions/Input/RMITrackpointFunction.hpp +++ b/VoodooRMI/Functions/Input/RMITrackpointFunction.hpp @@ -9,6 +9,7 @@ #include struct RMITrackpointReport { + AbsoluteTime timestamp; SInt32 dx; SInt32 dy; UInt32 buttons; diff --git a/VoodooRMI/RMIBus.cpp b/VoodooRMI/RMIBus.cpp index b954ef9..963e7ad 100644 --- a/VoodooRMI/RMIBus.cpp +++ b/VoodooRMI/RMIBus.cpp @@ -77,7 +77,7 @@ bool RMIBus::start(IOService *provider) { // Ready for interrupts setProperty(RMIBusIdentifier, kOSBooleanTrue); - if (!transport->open(this)) { + if (!transport->open(this, 0, OSMemberFunctionCast(RMIAttentionAction, this, &RMIBus::handleHostNotify))) { IOLogError("Could not open transport"); goto err; } @@ -106,19 +106,24 @@ bool RMIBus::start(IOService *provider) { return false; } -void RMIBus::handleHostNotify() { +void RMIBus::handleHostNotify(AbsoluteTime time, UInt8 *data, size_t size) { UInt32 irqStatus; - + UInt8 *dataPtr = nullptr; if (controlFunction == nullptr) { IOLogError("Interrupt - No F01"); return; } - IOReturn error = controlFunction->readIRQ(irqStatus); - - if (error != kIOReturnSuccess){ - IOLogError("Unable to read IRQ"); - return; + if (data) { + irqStatus = data[0]; + dataPtr = &data[1]; + size -= sizeof(UInt8); + } else { + IOReturn error = controlFunction->readIRQ(irqStatus); + if (error != kIOReturnSuccess){ + IOLogError("Unable to read IRQ"); + return; + } } OSIterator* iter = OSCollectionIterator::withCollection(functions); @@ -129,33 +134,15 @@ void RMIBus::handleHostNotify() { while(RMIFunction *func = OSDynamicCast(RMIFunction, iter->getNextObject())) { if (func->hasAttnSig(irqStatus)) { - func->attention(); + func->attention(time, &dataPtr, &size); } } OSSafeReleaseNULL(iter); } -void RMIBus::handleHostNotifyLegacy() { - if (controlFunction == nullptr) { - IOLogError("Interrupt - No F01"); - } - - OSIterator* iter = OSCollectionIterator::withCollection(functions); - while(RMIFunction *func = OSDynamicCast(RMIFunction, iter->getNextObject())) - func->attention(); - OSSafeReleaseNULL(iter); -} - IOReturn RMIBus::message(UInt32 type, IOService *provider, void *argument) { switch (type) { - case kIOMessageVoodooI2CHostNotify: - case kIOMessageVoodooSMBusHostNotify: - handleHostNotify(); - break; - case kIOMessageVoodooI2CLegacyHostNotify: - handleHostNotifyLegacy(); - break; case kIOMessageRMI4ResetHandler: rmiEnableSensor(); break; diff --git a/VoodooRMI/RMIBus.hpp b/VoodooRMI/RMIBus.hpp index e8e9217..ab4ee06 100644 --- a/VoodooRMI/RMIBus.hpp +++ b/VoodooRMI/RMIBus.hpp @@ -87,8 +87,7 @@ class RMIBus : public IOService { IOService *trackpointFunction {nullptr}; F01 *controlFunction {nullptr}; - void handleHostNotify(); - void handleHostNotifyLegacy(); + void handleHostNotify(AbsoluteTime time, UInt8 *data, size_t size); // IRQ information UInt8 irqCount {0}; diff --git a/VoodooRMI/Transports/I2C/Info.plist b/VoodooRMI/Transports/I2C/Info.plist index 0acaf56..3598dea 100644 --- a/VoodooRMI/Transports/I2C/Info.plist +++ b/VoodooRMI/Transports/I2C/Info.plist @@ -35,8 +35,6 @@ VoodooI2CDeviceNub IOClass RMII2C - Legacy - CFBundleIdentifier com.1Revenger1.RMII2C diff --git a/VoodooRMI/Transports/I2C/RMII2C.cpp b/VoodooRMI/Transports/I2C/RMII2C.cpp index d5a6f4c..b78555d 100644 --- a/VoodooRMI/Transports/I2C/RMII2C.cpp +++ b/VoodooRMI/Transports/I2C/RMII2C.cpp @@ -28,14 +28,6 @@ RMII2C *RMII2C::probe(IOService *provider, SInt32 *score) { name = provider->getName(); IOLogDebug("%s::%s probing", getName(), name); - OSBoolean *isLegacy= OSDynamicCast(OSBoolean, getProperty("Legacy")); - if (isLegacy == nullptr) { - IOLogInfo("%s::%s Legacy mode not set, default to false", getName(), name); - } else if (isLegacy->getValue()) { - reportMode = RMI_MODE_ATTN_REPORTS; - IOLogInfo("%s::%s running in legacy mode", getName(), name); - } - device_nub = OSDynamicCast(VoodooI2CDeviceNub, provider); if (!device_nub) { IOLogError("%s::%s Could not cast nub", getName(), name); @@ -57,7 +49,7 @@ RMII2C *RMII2C::probe(IOService *provider, SInt32 *score) { do { IOLogDebug("%s::%s Trying to set mode, attempt %d", getName(), name, attempts); - error = rmi_set_mode(reportMode); + error = rmi_set_mode(RMI_MODE_ATTN_REPORTS); IOSleep(500); } while (error < 0 && attempts++ < 5); @@ -102,6 +94,7 @@ bool RMII2C::start(IOService *provider) { interrupt_source = IOInterruptEventSource::interruptEventSource(this, OSMemberFunctionCast(IOInterruptEventAction, this, &RMII2C::interruptOccured), device_nub, 0); if (interrupt_source) { + interrupt_source->enablePrimaryInterruptTimestamp(true); work_loop->addEventSource(interrupt_source); } else { IOLogInfo("%s::%s Could not get interrupt event source, falling back to polling", getName(), name); @@ -110,10 +103,12 @@ bool RMII2C::start(IOService *provider) { IOLogError("%s::%s Could not get timer event source", getName(), name); goto exit; } - + work_loop->addEventSource(interrupt_simulator); } + inputBuffer = new UInt8[hdesc.wMaxInputLength]; + startInterrupt(); PMinit(); @@ -150,6 +145,10 @@ void RMII2C::releaseResources() { device_nub->close(this); device_nub = nullptr; } + + if (inputBuffer) { + delete inputBuffer; + } OSSafeReleaseNULL(command_gate); OSSafeReleaseNULL(interrupt_source); @@ -264,7 +263,7 @@ int RMII2C::rmi_set_mode(UInt8 mode) { } int RMII2C::reset() { - int retval = rmi_set_mode(reportMode); + int retval = rmi_set_mode(RMI_MODE_ATTN_REPORTS); if (retval < 0) return retval; @@ -278,16 +277,13 @@ int RMII2C::reset() { return retval; }; -bool RMII2C::handleOpen(IOService *forClient, IOOptionBits options, void *arg) { - if (forClient && forClient->getProperty(RMIBusIdentifier)) { - bus = forClient; - bus->retain(); - - startInterrupt(); - return true; +bool RMII2C::open(IOService *client, IOOptionBits options, RMIAttentionAction action) { + if (!super::open(client, options, action)) { + return false; } - - return IOService::handleOpen(forClient, options, arg); + + startInterrupt(); + return true; } int RMII2C::readBlock(UInt16 rmiaddr, UInt8 *databuff, size_t len) { @@ -337,16 +333,7 @@ int RMII2C::readBlock(UInt16 rmiaddr, UInt8 *databuff, size_t len) { goto exit; } - // FIXME: whether to rebuild packet - if (reportMode == RMI_MODE_ATTN_REPORTS && len == 68) { - memcpy(databuff, i2cInput+4, 16); - device_nub->readI2C(i2cInput, len+4); - memcpy(databuff+16, i2cInput+4, 16); - device_nub->readI2C(i2cInput, len+4); - memcpy(databuff+32, i2cInput+4, 16); - } else { - memcpy(databuff, i2cInput+4, len); - } + memcpy(databuff, i2cInput+4, len); exit: delete[] i2cInput; IOLockUnlock(page_mutex); @@ -395,8 +382,25 @@ int RMII2C::blockWrite(UInt16 rmiaddr, UInt8 *buf, size_t len) { void RMII2C::interruptOccured(OSObject *owner, IOInterruptEventSource *src, int intCount) { if (!ready || !bus) return; - - messageClient(reportMode == RMI_MODE_ATTN_REPORTS ? kIOMessageVoodooI2CLegacyHostNotify : kIOMessageVoodooI2CHostNotify, bus); + + if (device_nub->readI2C(inputBuffer, hdesc.wMaxInputLength) != kIOReturnSuccess) { + IOLogError("%s::%s Unable to read interrupt data", getName(), name); + return; + } + + UInt16 size = inputBuffer[0] | (inputBuffer[1] << 8); + UInt8 reportId = inputBuffer[2]; + + if (!size || reportId != RMI_ATTN_REPORT_ID) { + return; + } + + AbsoluteTime timestamp = mach_absolute_time(); + if (interrupt_source != nullptr) { + timestamp = interrupt_source->getPimaryInterruptTimestamp(); + } + + handleAttention(timestamp, &inputBuffer[3], size - 3); } void RMII2C::simulateInterrupt(OSObject* owner, IOTimerEventSource* timer) { @@ -414,7 +418,7 @@ IOReturn RMII2C::setPowerStateGated() { // FIXME: Hardcode 1s sleep delay because device will otherwise time out during reconfig IOSleep(1000); - int retval = rmi_set_mode(reportMode); + int retval = rmi_set_mode(RMI_MODE_ATTN_REPORTS); if (retval < 0) { IOLogError("Failed to config trackpad!"); return kIOPMAckImplied; diff --git a/VoodooRMI/Transports/I2C/RMII2C.hpp b/VoodooRMI/Transports/I2C/RMII2C.hpp index 79719fb..d1475cf 100644 --- a/VoodooRMI/Transports/I2C/RMII2C.hpp +++ b/VoodooRMI/Transports/I2C/RMII2C.hpp @@ -72,7 +72,7 @@ typedef struct __attribute__((__packed__)) { class RMII2C : public RMITransport { OSDeclareDefaultStructors(RMII2C); - typedef IOService super; + typedef RMITransport super; public: const char* name; @@ -81,7 +81,7 @@ class RMII2C : public RMITransport { bool start(IOService *provider) APPLE_KEXT_OVERRIDE; void stop(IOService *provider) APPLE_KEXT_OVERRIDE; IOReturn setPowerState(unsigned long powerState, IOService *whatDevice) APPLE_KEXT_OVERRIDE; - bool handleOpen(IOService *forClient, IOOptionBits options, void *arg) APPLE_KEXT_OVERRIDE; + bool open(IOService *client, IOOptionBits options, RMIAttentionAction action) APPLE_KEXT_OVERRIDE; int reset() APPLE_KEXT_OVERRIDE; int readBlock(UInt16 rmiaddr, UInt8 *databuff, size_t len) APPLE_KEXT_OVERRIDE; @@ -92,7 +92,7 @@ class RMII2C : public RMITransport { bool ready {false}; unsigned long currentPowerState {1}; int page {0}; - int reportMode {RMI_MODE_NO_PACKED_ATTN_REPORTS}; + UInt8 *inputBuffer {nullptr}; VoodooI2CDeviceNub *device_nub {nullptr}; diff --git a/VoodooRMI/Transports/RMITransport.hpp b/VoodooRMI/Transports/RMITransport.hpp index 78eed9b..4ba6449 100644 --- a/VoodooRMI/Transports/RMITransport.hpp +++ b/VoodooRMI/Transports/RMITransport.hpp @@ -15,14 +15,14 @@ #include #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" +typedef void (*RMIAttentionAction)(OSObject *target, AbsoluteTime timestamp, UInt8 *data, size_t size); + /* * read/write/reset APIs can be used before opening. Opening/Closing is needed to recieve interrupts */ @@ -38,30 +38,35 @@ class RMITransport : public IOService { virtual int reset() { return 0; }; virtual OSDictionary *createConfig() { return nullptr; }; - - /* - * IMPORTANT: These handleClose/handleOpen must be called. These can be overriden, - * but said implementation must call the ones below. - */ - inline virtual void handleClose(IOService *forClient, IOOptionBits options) override { - OSSafeReleaseNULL(bus); - IOService::handleClose(forClient, options); + + virtual bool open(IOService *client, IOOptionBits options, RMIAttentionAction action) { + if (!IOService::open(client, options)) { + return false; + } + + bus = client; + interruptAction = action; + return true; + } + + virtual void close(IOService *client, IOOptionBits options = 0) override { + bus = nullptr; + interruptAction = nullptr; + IOService::close(client); } - inline virtual bool handleOpen(IOService *forClient, IOOptionBits options, void *arg) override { - if (forClient && forClient->getProperty(RMIBusIdentifier) - && IOService::handleOpen(forClient, options, arg)) { - bus = forClient; - bus->retain(); - - return true; + void handleAttention(AbsoluteTime timestamp, UInt8 *data, size_t size) { + if (!interruptAction) { + return; } - return false; + (*interruptAction)(bus, timestamp, data, size); } protected: IOService *bus {nullptr}; +private: + RMIAttentionAction interruptAction {nullptr}; }; #endif // RMITransport_H diff --git a/VoodooRMI/Transports/SMBus/RMISMBus.cpp b/VoodooRMI/Transports/SMBus/RMISMBus.cpp index 99288fe..6e3f984 100644 --- a/VoodooRMI/Transports/SMBus/RMISMBus.cpp +++ b/VoodooRMI/Transports/SMBus/RMISMBus.cpp @@ -268,7 +268,8 @@ IOReturn RMISMBus::message(UInt32 type, IOService *provider, void *argument) { switch (type) { case kIOMessageVoodooSMBusHostNotify: - return messageClient(kIOMessageVoodooSMBusHostNotify, bus); + handleAttention(mach_absolute_time(), nullptr, 0); + return kIOReturnSuccess; default: return IOService::message(type, provider, argument); }