[prev in list] [next in list] [prev in thread] [next in thread]
List: kde-commits
Subject: [kde-workspace/KDE/4.9] powerdevil/daemon/backends/upower: Fix handling of backlight on FreeBSD
From: Alberto Villa <avilla () FreeBSD ! org>
Date: 2012-10-11 10:25:20
Message-ID: 20121011102520.90FC3A605D () git ! kde ! org
[Download RAW message or body]
Git commit 742db7756131b030a136620721d986750b1d40df by Alberto Villa.
Committed on 11/10/2012 at 12:15.
Pushed by avilla into branch 'KDE/4.9'.
Fix handling of backlight on FreeBSD
The implementation uses acpi_video(4) sysctl interface. The code was
inspired by Junk-uk Kim's following patch:
https://bugs.freedesktop.org/show_bug.cgi?id=24765
REVIEW: 106790
M +118 -8 powerdevil/daemon/backends/upower/backlighthelper.cpp
M +7 -0 powerdevil/daemon/backends/upower/backlighthelper.h
http://commits.kde.org/kde-workspace/742db7756131b030a136620721d986750b1d40df
diff --git a/powerdevil/daemon/backends/upower/backlighthelper.cpp \
b/powerdevil/daemon/backends/upower/backlighthelper.cpp index 86b359a..747a637 100644
--- a/powerdevil/daemon/backends/upower/backlighthelper.cpp
+++ b/powerdevil/daemon/backends/upower/backlighthelper.cpp
@@ -24,6 +24,17 @@
#include <sys/utsname.h>
+#ifdef Q_OS_FREEBSD
+#define USE_SYSCTL
+#endif
+
+#ifdef USE_SYSCTL
+#include <sys/types.h>
+#include <sys/sysctl.h>
+
+#define HAS_SYSCTL(n) (sysctlbyname(n, NULL, NULL, NULL, 0) == 0)
+#endif
+
#define PREFIX "/sys/class/backlight/"
BacklightHelper::BacklightHelper(QObject * parent)
@@ -42,8 +53,12 @@ void BacklightHelper::init()
}
if (m_dirname.isEmpty()) {
- qWarning() << "no kernel backlight interface found";
- return;
+ initUsingSysctl();
+
+ if (m_sysctlDevice.isEmpty() || m_sysctlBrightnessLevels.isEmpty()) {
+ qWarning() << "no kernel backlight interface found";
+ return;
+ }
}
m_isSupported = true;
@@ -162,6 +177,59 @@ bool BacklightHelper::useWhitelistInit()
return false;//Use Type based interafce
}
+void BacklightHelper::initUsingSysctl()
+{
+#ifdef USE_SYSCTL
+ /*
+ * lcd0 would probably be the correct device, but some ACPI implementations \
can't report it + * correctly; thus, an LCD screen can appear as crtN (crt1, in \
my case). Let's search for the + * first device with brightness management, then.
+ */
+ QStringList types;
+ types << "lcd" << "crt";
+ foreach (const QString &type, types) {
+ for (int i = 0; m_sysctlDevice.isEmpty(); i++) {
+ QString device = QString("%1%2").arg(type, QString::number(i));
+ // We don't care about the value, we only want the sysctl to be there.
+ if (!HAS_SYSCTL(qPrintable(QString("hw.acpi.video.%1.active").arg(device)))) \
{ + break;
+ }
+ if (HAS_SYSCTL(qPrintable(QString("hw.acpi.video.%1.brightness").arg(device))) \
&& + HAS_SYSCTL(qPrintable(QString("hw.acpi.video.%1.levels").arg(device)))) \
{ + m_sysctlDevice = device;
+ break;
+ }
+ }
+ }
+
+ if (m_sysctlDevice.isEmpty()) {
+ return;
+ }
+
+ size_t len;
+ if (sysctlbyname(qPrintable(QString("hw.acpi.video.%1.levels").arg(m_sysctlDevice)), \
NULL, &len, NULL, 0) != 0 || + len == 0) {
+ return;
+ }
+ int *levels = (int *)malloc(len);
+ if (!levels) {
+ return;
+ }
+ if (sysctlbyname(qPrintable(QString("hw.acpi.video.%1.levels").arg(m_sysctlDevice)), \
levels, &len, NULL, 0) != 0) { + free(levels);
+ return;
+ }
+ // acpi_video(4) supports only some predefined brightness levels.
+ int nlevels = len / sizeof(int);
+ for (int i = 0; i < nlevels; i++) {
+ m_sysctlBrightnessLevels << levels[i];
+ }
+ free(levels);
+ // Sorting helps when finding max value and when scanning for the nearest level \
in setbrightness(). + qSort(m_sysctlBrightnessLevels.begin(), \
m_sysctlBrightnessLevels.end()); +#endif
+}
+
ActionReply BacklightHelper::brightness(const QVariantMap & args)
{
Q_UNUSED(args);
@@ -174,6 +242,15 @@ ActionReply BacklightHelper::brightness(const QVariantMap & \
args) }
// current brightness
+ int brightness;
+
+#ifdef USE_SYSCTL
+ size_t len = sizeof(int);
+ if (sysctlbyname(qPrintable(QString("hw.acpi.video.%1.brightness").arg(m_sysctlDevice)), \
&brightness, &len, NULL, 0) != 0) { + reply = ActionReply::HelperErrorReply;
+ return reply;
+ }
+#else
QFile file(m_dirname + "/brightness");
if (!file.open(QIODevice::ReadOnly)) {
reply = ActionReply::HelperErrorReply;
@@ -183,11 +260,11 @@ ActionReply BacklightHelper::brightness(const QVariantMap & \
args) }
QTextStream stream(&file);
- int brightness;
stream >> brightness;
- //qDebug() << "brightness:" << brightness;
file.close();
+#endif
+ //qDebug() << "brightness:" << brightness;
reply.addData("brightness", brightness * 100 / maxBrightness());
//qDebug() << "data contains:" << reply.data()["brightness"];
@@ -203,6 +280,34 @@ ActionReply BacklightHelper::setbrightness(const QVariantMap & \
args) return reply;
}
+ int actual_brightness = qRound(args["brightness"].toFloat() * maxBrightness() / \
100); + //qDebug() << "setting brightness:" << actual_brightness;
+
+#ifdef USE_SYSCTL
+ int actual_level = -1;
+ int d1 = 101;
+ // Search for the nearest level.
+ foreach (int level, m_sysctlBrightnessLevels) {
+ int d2 = qAbs(level - actual_brightness);
+ /*
+ * The list is sorted, so we break when it starts diverging. There may be \
repeated values, + * so we keep going on equal gap (e.g., value = 7.5, levels \
= 0 0 10 ...: we don't break at + * the second '0' so we can get to the \
'10'). This also means that the value will always + * round off to the bigger \
level when in the middle (e.g., value = 5, levels = 0 10 ...: + * value \
rounds off to 10). + */
+ if (d2 > d1) {
+ break;
+ }
+ actual_level = level;
+ d1 = d2;
+ }
+ size_t len = sizeof(int);
+ if (sysctlbyname(qPrintable(QString("hw.acpi.video.%1.brightness").arg(m_sysctlDevice)), \
NULL, NULL, &actual_level, len) != 0) { + reply = \
ActionReply::HelperErrorReply; + return reply;
+ }
+#else
QFile file(m_dirname + "/brightness");
if (!file.open(QIODevice::WriteOnly)) {
reply = ActionReply::HelperErrorReply;
@@ -211,8 +316,6 @@ ActionReply BacklightHelper::setbrightness(const QVariantMap & \
args) return reply;
}
- int actual_brightness = qRound(args["brightness"].toFloat() * maxBrightness() / \
100);
- //qDebug() << "setting brightness:" << actual_brightness;
int result = file.write(QByteArray::number(actual_brightness));
file.close();
@@ -221,6 +324,7 @@ ActionReply BacklightHelper::setbrightness(const QVariantMap & \
args) reply.setErrorCode(file.error());
qWarning() << "writing brightness failed with error code " << file.error() \
<< file.errorString(); }
+#endif
return reply;
}
@@ -228,6 +332,11 @@ ActionReply BacklightHelper::setbrightness(const QVariantMap & \
args) int BacklightHelper::maxBrightness() const
{
// maximum brightness
+ int max_brightness;
+
+#ifdef USE_SYSCTL
+ max_brightness = m_sysctlBrightnessLevels.last();
+#else
QFile file(m_dirname + "/max_brightness");
if (!file.open(QIODevice::ReadOnly)) {
qWarning() << "reading max brightness failed with error code " << \
file.error() << file.errorString(); @@ -235,10 +344,11 @@ int \
BacklightHelper::maxBrightness() const }
QTextStream stream(&file);
- int max_brightness;
stream >> max_brightness;
- //qDebug() << "max brightness:" << max_brightness;
file.close();
+#endif
+
+ //qDebug() << "max brightness:" << max_brightness;
return max_brightness ? max_brightness : -1;
}
diff --git a/powerdevil/daemon/backends/upower/backlighthelper.h \
b/powerdevil/daemon/backends/upower/backlighthelper.h index fe659e7..9eae1f1 100644
--- a/powerdevil/daemon/backends/upower/backlighthelper.h
+++ b/powerdevil/daemon/backends/upower/backlighthelper.h
@@ -52,6 +52,11 @@ private:
void initUsingBacklightType();
/**
+ * FreeBSD (and other BSDs) can control backlight via acpi_video(4)
+ */
+ void initUsingSysctl();
+
+ /**
* If Kernel older than 2.6.37 use whitelsit, otherwise use backlight/type
* @see https://bugs.kde.org/show_bug.cgi?id=288180
*/
@@ -59,6 +64,8 @@ private:
int maxBrightness() const;
bool m_isSupported;
QString m_dirname;
+ QString m_sysctlDevice;
+ QList<int> m_sysctlBrightnessLevels;
};
#endif // BACKLIGHTHELPER_H
[prev in list] [next in list] [prev in thread] [next in thread]
Configure |
About |
News |
Add a list |
Sponsored by KoreLogic