Skip to content

Commit

Permalink
Move I2C setPowerState into work loop (#123)
Browse files Browse the repository at this point in the history
* Fix deadlock occuring when waking from sleep
  • Loading branch information
1Revenger1 authored Sep 3, 2021
1 parent adc41f4 commit 78dcbee
Show file tree
Hide file tree
Showing 2 changed files with 26 additions and 16 deletions.
39 changes: 24 additions & 15 deletions VoodooRMI/Transports/I2C/RMII2C.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,7 @@ bool RMII2C::start(IOService *provider) {
work_loop->addEventSource(interrupt_simulator);
}

startInterrupt();

PMinit();
provider->joinPMtree(this);
Expand Down Expand Up @@ -175,7 +176,8 @@ int RMII2C::rmi_set_page(u8 page) {
RMI_WRITE_REPORT_ID,
0x01,
RMI_PAGE_SELECT_REGISTER,
page };
page
};

if (device_nub->writeI2C(writeReport, sizeof(writeReport)) != kIOReturnSuccess) {
IOLogError("%s::%s failed to write request output report", getName(), name);
Expand Down Expand Up @@ -248,7 +250,8 @@ int RMII2C::rmi_set_mode(u8 mode) {
0x04, // size & 0xFF; 2 + reportID + buf (reportID excluded)
0x00, // size >> 8;
RMI_SET_RMI_MODE_REPORT_ID, // report_id = buf[0];
mode };
mode
};

if (device_nub->writeI2C(command, sizeof(command)) != kIOReturnSuccess)
return -1;
Expand Down Expand Up @@ -386,14 +389,11 @@ int RMII2C::blockWrite(u16 rmiaddr, u8 *buf, size_t len) {
return retval;
}

// We are in the workloop (not interrupt context), it's OK to use IOLog, messageClient, etc
void RMII2C::interruptOccured(OSObject *owner, IOInterruptEventSource *src, int intCount) {
if (!ready || !bus)
return;

command_gate->attemptAction(OSMemberFunctionCast(IOCommandGate::Action, this, &RMII2C::notifyClient));
}

void RMII2C::notifyClient() {
messageClient(reportMode == RMI_MODE_ATTN_REPORTS ? kIOMessageVoodooI2CLegacyHostNotify : kIOMessageVoodooI2CHostNotify, bus);
}

Expand All @@ -402,15 +402,8 @@ void RMII2C::simulateInterrupt(OSObject* owner, IOTimerEventSource* timer) {
interrupt_simulator->setTimeoutMS(INTERRUPT_SIMULATOR_TIMEOUT);
}

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) {
IOReturn RMII2C::setPowerStateGated() {
if (currentPowerState == 0) {
messageClient(kIOMessageRMI4Sleep, bus);
stopInterrupt();
} else {
Expand All @@ -435,6 +428,22 @@ IOReturn RMII2C::setPowerState(unsigned long powerState, IOService *whatDevice){
return kIOPMAckImplied;
}

IOReturn RMII2C::setPowerState(unsigned long newPowerState, IOService *whatDevice) {
IOLogDebug("%s::%s powerState %ld : %s", getName(), name, newPowerState, newPowerState ? "on" : "off");

if (whatDevice != this)
return kIOReturnInvalid;

if (!bus || currentPowerState == newPowerState)
return kIOPMAckImplied;

currentPowerState = newPowerState;
IOReturn ret = command_gate->attemptAction(OSMemberFunctionCast(IOCommandGate::Action, this, &RMII2C::setPowerStateGated));

if (ret) IOLogDebug("%s::%s powerState ret 0x%x", getName(), name, ret);
return kIOPMAckImplied;
}

void RMII2C::startInterrupt() {
if (interrupt_simulator) {
interrupt_simulator->setTimeoutMS(200);
Expand Down
3 changes: 2 additions & 1 deletion VoodooRMI/Transports/I2C/RMII2C.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,7 @@ class RMII2C : public RMITransport {

private:
bool ready {false};
unsigned long currentPowerState {1};
int page {0};
int reportMode {RMI_MODE_NO_PACKED_ATTN_REPORTS};

Expand All @@ -104,7 +105,7 @@ class RMII2C : public RMITransport {

void interruptOccured(OSObject* owner, IOInterruptEventSource* src, int intCount);
void simulateInterrupt(OSObject* owner, IOTimerEventSource* timer);
void notifyClient();
IOReturn setPowerStateGated();

__le16 wHIDDescRegister {RMI_HID_DESC_REGISTER};
i2c_hid_desc hdesc;
Expand Down

0 comments on commit 78dcbee

Please sign in to comment.