Skip to content

Commit

Permalink
Fix I2C HID Interrupt Behavior (#193)
Browse files Browse the repository at this point in the history
Read in HID interrupt reports rather than querying registers directly.
Fixes freezing on boot and spammed IRQs on I2C touchpads.
  • Loading branch information
1Revenger1 authored Oct 23, 2024
1 parent 12384ef commit e23fb3a
Show file tree
Hide file tree
Showing 24 changed files with 213 additions and 220 deletions.
5 changes: 2 additions & 3 deletions VoodooRMI/Functions/F01.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
2 changes: 1 addition & 1 deletion VoodooRMI/Functions/F01.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down
24 changes: 10 additions & 14 deletions VoodooRMI/Functions/F03.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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!
Expand All @@ -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]);
Expand Down Expand Up @@ -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");
Expand All @@ -229,7 +225,7 @@ void F03::attention()
continue;
}

handleByte(ob_data);
handleByte(time, ob_data);
}
}

Expand Down Expand Up @@ -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
Expand All @@ -306,7 +302,7 @@ void F03::handleByte(UInt8 byte)
databuf[index++] = byte;

if (index == 3)
handlePacket(databuf);
handlePacket(time, databuf);
return;
}

Expand Down
6 changes: 3 additions & 3 deletions VoodooRMI/Functions/F03.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -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};
Expand Down Expand Up @@ -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 */
29 changes: 19 additions & 10 deletions VoodooRMI/Functions/F11.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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(&timestamp);

if (shouldDiscardReport(timestamp))
if (shouldDiscardReport(time))
return;

IOLogDebug("F11 Packet");
Expand Down Expand Up @@ -94,7 +103,7 @@ void F11::attention()
}
}

report.timestamp = timestamp;
report.timestamp = time;
report.fingers = fingers;

handleReport(&report);
Expand Down
2 changes: 1 addition & 1 deletion VoodooRMI/Functions/F11.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
98 changes: 42 additions & 56 deletions VoodooRMI/Functions/F12.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -79,53 +79,33 @@ 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)
data_offset += item->reg_size;

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;
}

Expand Down Expand Up @@ -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(&timestamp);
if (shouldDiscardReport(timestamp))
if (shouldDiscardReport(time))
return;

IOLogDebug("F12 Packet");
Expand All @@ -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);
Expand Down
21 changes: 4 additions & 17 deletions VoodooRMI/Functions/F12.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -54,16 +54,14 @@ 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;

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);
Expand All @@ -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);
Expand Down
Loading

0 comments on commit e23fb3a

Please sign in to comment.