Skip to content

Commit

Permalink
Workaround for buggy vendor backlight implements (#26)
Browse files Browse the repository at this point in the history
  • Loading branch information
zhen-zen committed Sep 28, 2020
1 parent ac8c2bb commit 86d8fb2
Show file tree
Hide file tree
Showing 3 changed files with 90 additions and 44 deletions.
10 changes: 7 additions & 3 deletions VoodooPS2Controller/ApplePS2Device.h
Expand Up @@ -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
Expand All @@ -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

Expand Down
116 changes: 77 additions & 39 deletions VoodooPS2Keyboard/VoodooPS2Keyboard.cpp
Expand Up @@ -65,7 +65,7 @@

// Constants for brightness keys

#define kBrightnessDevice "BrightnessDevice"
#define kBrightnessPanel "BrightnessPanel"
#define kBrightnessKey "BrightnessKey"

// Definitions for Macro Inversion data format
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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) {
Expand All @@ -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;
}
Expand All @@ -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 * {
Expand All @@ -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);
}

// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Expand Down Expand Up @@ -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.
Expand Down Expand Up @@ -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);

//
Expand Down Expand Up @@ -2050,30 +2087,31 @@ 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:
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());
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());
Expand Down
8 changes: 6 additions & 2 deletions VoodooPS2Keyboard/VoodooPS2Keyboard.h
Expand Up @@ -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;
Expand Down Expand Up @@ -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);
Expand Down

0 comments on commit 86d8fb2

Please sign in to comment.