summaryrefslogtreecommitdiffstats
path: root/klaptopdaemon/portable.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'klaptopdaemon/portable.cpp')
-rw-r--r--klaptopdaemon/portable.cpp3087
1 files changed, 3087 insertions, 0 deletions
diff --git a/klaptopdaemon/portable.cpp b/klaptopdaemon/portable.cpp
new file mode 100644
index 0000000..f56dc1e
--- /dev/null
+++ b/klaptopdaemon/portable.cpp
@@ -0,0 +1,3087 @@
+/*
+ * portable.cpp
+ *
+ * $Id$
+ *
+ * Copyright (c) 1999 Paul Campbell <paul@taniwha.com>
+ *
+ * Requires the Qt widget libraries, available at no cost at
+ * http://www.troll.no/
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+//
+// this file contains the machine specific laptop power management stuff
+// to add support for your own OS this is should be the only place you need
+// to change - to add your own stuff insert above the line marked
+// 'INSERT HERE' :
+//
+// #ifdef MY_OS"
+// .. copy of linux code or whatever you want to use as a base
+// # else
+//
+// then tag an extra '#endif' at the end
+//
+// There is support for the following OSsen right now:
+//
+// Linux (#if __linux__)
+// FreeBSD (#elif __FreeBSD__)
+// NetBSD (#elif __NetBSD_APM__)
+// generic nothing (#else)
+//
+//
+// The code here is written in a C rather than C++ like to encourage
+// people more used to kernel types to do stuff here
+//
+// If you have any problems, questions, whatever please get in touch
+//
+// Paul Campbell
+// paul@taniwha.com
+//
+//
+// Thanks to Cajus Pollmeier <C.Pollmeier@gmx.net>
+// and Robert Ellis Parrott <parrott@fas.harvard.edu>
+// who both provided ACPI support
+// and Volker Krause <volker.krause@rwth-aachen.de> who provided ACPI bug fixes
+//
+
+#include <config.h>
+#include <klocale.h>
+#include <kdebug.h>
+#include <stdio.h>
+#include "portable.h"
+
+#ifdef __linux__
+
+/*
+** This is the Linux-specific laptop code.
+*/
+#include <sys/types.h>
+#include <unistd.h>
+#include <sys/stat.h>
+#include <time.h>
+#include <stdlib.h>
+#include <math.h>
+#include <fcntl.h>
+#include <sys/ioctl.h>
+#include <dirent.h>
+#include <qpushbutton.h>
+#include <qdir.h>
+#include <qfile.h>
+#include <qfileinfo.h>
+#include <qstringlist.h>
+#include <qstring.h>
+#include <qobject.h>
+#include <qregexp.h>
+#include <qiodevice.h>
+#include <qlayout.h>
+#include <qvgroupbox.h>
+#include <qvaluevector.h>
+
+#include <kactivelabel.h>
+#include <kconfig.h>
+#include <kstandarddirs.h>
+#include <kprocess.h>
+#include <krichtextlabel.h>
+
+// ibm specific stuff
+extern "C"{
+#include "thinkpad_common.h"
+#include "smapi.h"
+#include "smapidev.h"
+}
+
+//
+// here's the Linux specific laptop control panel stuff
+//
+
+typedef struct apm_info {
+ unsigned int apm_flags;
+ unsigned int ac_line_status;
+ int battery_percentage;
+ int battery_time;
+} apm_info;
+
+static int
+apm_read(apm_info *ap)
+{
+ FILE *f = 0;
+ char tmp2[10];
+ int tmp, s;
+ unsigned int utmp;
+ char version[256];
+
+ f = fopen("/proc/apm", "r");
+ if (f == NULL)
+ return(1);
+ s = fscanf(f, "%255s %d.%d %x %x %x %x %d%% %d %s\n",
+ version,
+ &tmp,
+ &tmp,
+ &ap->apm_flags,
+ &ap->ac_line_status,
+ &utmp,
+ &utmp,
+ &ap->battery_percentage,
+ &ap->battery_time,
+ tmp2);
+ fclose(f);
+ if (s < 9)
+ return(1);
+ if (version[0] == 'B')
+ return(2);
+ if (ap->battery_percentage > 100)
+ ap->battery_percentage = -1;
+ if (strcmp(tmp2, "sec") == 0)
+ ap->battery_time /= 60;
+ return(0);
+}
+
+
+// 0 => unknown
+// 1 => have it
+// -1 => don't have it
+static int pmustate = 0;
+
+static bool
+have_pmu(void)
+{
+ if (pmustate != 0)
+ return (pmustate == 1);
+ if (!access("/proc/pmu", R_OK|X_OK)) {
+ kdDebug() << "Found powermac PMU. Using that." << endl;
+ pmustate = 1;
+ return true;
+ }
+ pmustate = -1;
+ return false;
+}
+
+/* Only supports 1 battery right now - all batteries are merged into one stat */
+static int
+pmu_read(apm_info *ap)
+{
+ int bcnt = 0;
+ memset(ap, 0, sizeof(apm_info));
+ QFile f("/proc/pmu/info");
+ if (!f.open(IO_ReadOnly))
+ return 1;
+
+ while (!f.atEnd()) {
+ QString l;
+ f.readLine(l, 500);
+ QStringList ll = QStringList::split(':', l, false);
+ if (ll[0].stripWhiteSpace() == "AC Power") {
+ ap->ac_line_status = ll[1].stripWhiteSpace().toInt();
+ //kdDebug() << "line status " << ap->ac_line_status << endl;
+ } else if (ll[0].stripWhiteSpace() == "Battery count") {
+ bcnt = ll[1].stripWhiteSpace().toInt();
+ //kdDebug() << "batteries: " << bcnt << endl;
+ }
+ }
+
+ f.close();
+
+ int charge = 0;
+ int timerem = 0;
+ int maxcharge = 0;
+ for (int i = 0; i < bcnt; i++) {
+ QFile bf(QString("/proc/pmu/battery_%1").arg(i));
+ if (!bf.open(IO_ReadOnly))
+ continue;
+
+ while(!bf.atEnd()) {
+ QString l;
+ bf.readLine(l, 500);
+ QStringList ll = QStringList::split(':', l, false);
+ if (ll[0].stripWhiteSpace() == "charge") {
+ charge += ll[1].stripWhiteSpace().toInt();
+ //kdDebug() << "charge: " << charge << endl;
+ } else if (ll[0].stripWhiteSpace() == "max_charge") {
+ maxcharge += ll[1].stripWhiteSpace().toInt();
+ //kdDebug() << "max charge: " << maxcharge << endl;
+ } else if (ll[0].stripWhiteSpace() == "time rem.") {
+ timerem += ll[1].stripWhiteSpace().toInt();
+ //kdDebug() << "time: " << timerem << endl;
+ }
+ }
+ bf.close();
+ }
+ ap->battery_percentage = int(rint(100.0*float(float(charge)/float(maxcharge))));
+ ap->battery_time = timerem;
+
+ if (ap->ac_line_status > 0 || timerem == 0 ||
+ (ap->ac_line_status == 0 && charge > 100 && timerem == 0))
+ ap->battery_time = -1;
+
+ return 0;
+}
+
+
+struct acpi_battery_info {
+ int percentage;
+ bool present;
+ int cap;
+ int cap_low;
+ int remaining;
+ int rate;
+ QString name;
+ QString state_file;
+ QString info_file;
+};
+
+static QValueVector<acpi_battery_info> acpi_batteries;
+static int acpi_last_known=0;
+static int last_seed=1; // increment this to force revaluation
+
+static unsigned char acpi_ac_ok;
+
+//
+// linux APCI doesn't return useful stuff like how much TIME is left yet
+// the 'rate' is not smoothed over time so it's faked out here
+// it's not pretty and it's a quick estimate
+//
+// for the moment we prefer APM
+//
+
+static int
+acpi_ac_status()
+{
+ DIR *dfd;
+ struct dirent *dp;
+ FILE *f = NULL;
+ static char buff[NAME_MAX+50];
+ static bool inited=0;
+ static bool bad=0;
+
+ if (inited) {
+ if (bad)
+ return(-1);
+ f = fopen(buff, "r");
+ goto readit;
+ }
+ inited = 1;
+
+ dfd = opendir("/proc/acpi/ac_adapter/");
+ if (dfd) {
+ for (;;) {
+ dp = readdir(dfd);
+ if (dp == 0)
+ break;
+ if (strcmp(dp->d_name, ".") == 0 ||
+ strcmp(dp->d_name, "..") == 0)
+ continue;
+ strcpy(buff, "/proc/acpi/ac_adapter/");
+ strcat(buff, dp->d_name);
+ strcat(buff, "/status");
+ f = fopen(buff, "r");
+ if (!f) {
+ strcpy(buff, "/proc/acpi/ac_adapter/");
+ strcat(buff, dp->d_name);
+ strcat(buff, "/state");
+ f = fopen(buff, "r");
+ }
+ if (f)
+ break;
+ }
+ closedir(dfd);
+readit:
+ if (f) {
+ for (;;) {
+ char buff2[1024];
+ if (fgets(buff2, sizeof(buff), f) == NULL)
+ break;
+ if (strstr(buff2, "Status:") != NULL ||
+ strstr(buff2, "state:") != NULL) {
+ if (strstr(buff2, "on-line") != NULL) {
+ fclose(f);
+ return(1);
+ }
+ }
+ }
+ fclose(f);
+ return(0);
+ }
+ }
+ bad=1;
+ return(-1);
+}
+
+static void acpi_read_batteries() {
+ QString buff;
+ QFile *f;
+ static int test_count = 0;
+ bool skip = false;
+
+ for(unsigned int i = 0; i < acpi_batteries.count(); ++i) {
+ acpi_battery_info& bat = acpi_batteries[i];
+ bool present = false;
+ if ((test_count==0 || acpi_last_known != last_seed) && !bat.info_file.isNull()) {
+ f = new QFile(bat.info_file);
+ if (f && f->open(IO_ReadOnly)) {
+ while(f->readLine(buff,1024) > 0) {
+ if (buff.contains("design capacity low:", false)) {
+ QRegExp rx("(\\d*)\\D*$");
+ rx.search(buff);
+ bat.cap_low = rx.cap(1).toInt();
+ if (bat.cap_low < 0)
+ bat.cap_low = 0;
+ continue;
+ }
+ if (buff.contains("last full capacity:", false)) {
+ QRegExp rx("(\\d*)\\D*$");
+ rx.search(buff);
+ bat.cap = rx.cap(1).toInt();
+ continue;
+ }
+ }
+ f->close();
+ bat.cap -= bat.cap_low;
+ }
+ delete f;
+ }
+ if (bat.cap <= 0) {
+ KConfig* config = new KConfig("kcmlaptoprc", true /*readonly*/, false /*useKDEGlobals*/);
+ config->setGroup("AcpiBattery");
+ bat.cap = config->readNumEntry(bat.name,0);
+ delete config;
+ }
+ if (!bat.state_file.isNull()) {
+ f = new QFile(bat.state_file);
+ if (f && f->open(IO_ReadOnly)) {
+ while(f->readLine(buff,1024) > 0) {
+ if (buff.contains("present rate:", false)) {
+ QRegExp rx("(\\d*)\\D*$");
+ rx.search(buff);
+ bat.rate = rx.cap(1).toInt();
+ if (bat.rate < 0)
+ bat.rate = 0;
+ present = true;
+ continue;
+ }
+ if (buff.contains("remaining capacity:", false)) {
+ QRegExp rx("(\\d*)\\D*$");
+ rx.search(buff);
+ bat.remaining = rx.cap(1).toInt();
+ bat.remaining -= bat.cap_low;
+ if (bat.remaining < 0)
+ bat.remaining = 0;
+ present = true;
+ continue;
+ }
+ }
+ f->close();
+ }
+ delete f;
+ }
+ if(present && !bat.present) // recheck capacity if a battery was put in
+ skip = true;
+ bat.present = present;
+ if (bat.present) {
+ if (bat.remaining > bat.cap) { // happens e.g. if the system doesn't provide a capacity value
+ bat.cap = bat.remaining;
+ KConfig* config = new KConfig("kcmlaptoprc", false /*readonly*/, false /*useKDEGlobals*/);
+ config->setGroup("AcpiBattery");
+ config->writeEntry(bat.name, bat.cap);
+ config->sync();
+ delete config;
+ skip = true;
+ }
+ if (bat.cap == 0)
+ bat.percentage = 0;
+ else
+ bat.percentage = bat.remaining*100/bat.cap;
+ }
+ else
+ bat.percentage = 0;
+ }
+
+ if (!skip) {
+ acpi_last_known = last_seed;
+ test_count++;
+ }
+ else
+ test_count = 0;
+ if (test_count > 1000) // every 1000 or so times recheck the battery capacity
+ test_count = 0;
+
+}
+
+static int
+acpi_read(apm_info *ap)
+{
+ int rate, part, total;
+ int ret = 1;
+ bool present = 0;
+
+ part = 0;
+ total = 0;
+ rate = 0;
+
+ acpi_read_batteries();
+
+ for(unsigned int i = 0; i < acpi_batteries.count(); ++i) {
+ acpi_battery_info& bat = acpi_batteries[i];
+ present |= bat.present;
+ if(bat.present) {
+ total += bat.cap;
+ part += bat.remaining;
+ rate += bat.rate;
+ }
+ ret = 0;
+ }
+
+ // some broken ACPI implementations don't return a rate
+ // compute a 'fake' rate by diffing remaining values
+ if (rate == 0)
+ {
+ static int last_remaining = 0;
+ static time_t last_time = 0;
+ if (last_remaining != 0
+ && last_time != 0)
+ {
+ int diff_time = time(0) - last_time;
+ if (diff_time > 0)
+ rate = (last_remaining - part) * 3600 / diff_time;
+ }
+ last_remaining = part;
+ last_time = time(0);
+ if (rate < 0)
+ rate = 0;
+ }
+
+ static int nrates = 0;
+ static int saved_rate[8];
+ static unsigned char ignore_next = 2; // ignore the first couple
+
+ ap->ac_line_status = 0;
+ //
+ // ACPI (unlike nice systems like some APM implementations) doesn't
+ // tell us how much battery TIME we have left - here we
+ // do a weighted average of the discharge rate (in mW) and
+ // figure out how long we have left by dividing it into the
+ // remaining capacity
+ //
+ // because some ACPI implementations return bogus
+ // rates when charging we can't estimate the battery life
+ // so we only collect discharge rate data when we're actually
+ // discharging
+ //
+ if (acpi_ac_status() == 1) {
+ ap->ac_line_status |= 1;
+ ignore_next = 2;
+ } else {
+ // after switching from power to unpowered we often get
+ // a bad reading from ACPI resulting in bizarre
+ // readings
+ if (ignore_next == 0) {
+ if (nrates < 8) // smooth the power flow
+ nrates++; // simple box filter
+ for (int i = 8-1; i > 0; i--)
+ saved_rate[i] = saved_rate[i-1];
+ saved_rate[0] = rate;
+ } else {
+ ignore_next--;
+ }
+ }
+ //
+ // if we haven't got any discharge rate data yet don't return a
+ // battery time - probably happens when you start up with the
+ // ac adaptor plugged in
+ //
+ if (nrates == 0) {
+ ap->battery_time = -1;
+ } else {
+ rate = 0;
+ for (int i = 0; i < nrates; i++)
+ rate += saved_rate[i];
+ rate = (rate+2*saved_rate[0])/(nrates+2); // weight it slighly
+ ap->battery_time = (rate==0 ? -1 : 60*part/rate);
+ }
+ ap->battery_percentage = (total==0?0:100*part/total);
+ if (!present) {
+ ap->battery_percentage = -1;
+ ap->battery_time = -1;
+ }
+ ap->apm_flags = 0;
+ return(ret);
+}
+
+static int apm_no_time;
+static apm_info apmx = {0,0,0,0};
+static int
+has_apm()
+{
+ static int init = 0;
+ static int val;
+ if (init)
+ return(val);
+ init = 1;
+ val = 1;
+ apm_no_time=0;
+ if (apm_read(&apmx) || (apmx.apm_flags&0x20)) {
+ val = 0;
+ apm_no_time = 1;
+ } else {
+ apm_no_time = apmx.battery_time < 0;
+ }
+
+ if (val == 0) {
+ val = have_pmu();
+ if (val && pmu_read(&apmx)) {
+ val = 0;
+ }
+ }
+ return(val);
+}
+
+// Power to the powermacs!!
+static int
+has_pmu()
+{
+ static int init = 0;
+ static int val;
+ if (init)
+ return val;
+ init = 1;
+ val = 1;
+ if (!QDir("/proc/pmu").exists()) {
+ val = 0;
+ }
+ return val;
+}
+
+static bool software_suspend_is_preferred = false; // user prefers to use SS for hibernate
+static bool acpi_helper_ok(bool type);
+static bool
+has_software_suspend(int type)
+{
+ static int known=0;
+ static bool present=0; // functionality seems to be here
+ static bool available=0; // helper can work
+ if (known != last_seed) {
+ known = last_seed;
+ available = 0;
+ present = (((::access("/proc/sys/kernel/swsusp", F_OK) == 0) ||
+ (::access("/proc/software_suspend", F_OK) == 0) ||
+ (::access("/proc/suspend2", F_OK) == 0)) &&
+ ::access("/usr/sbin/hibernate", F_OK) == 0);
+ if (present) {
+ if (::getuid() == 0) { // running as root
+ available = ::access("/usr/sbin/hibernate", X_OK) == 0 && acpi_helper_ok(1);
+ } else {
+ available = acpi_helper_ok(0);
+ }
+ }
+ }
+ switch (type) {
+ case 0: return(present);
+ case 1: return(present&available&software_suspend_is_preferred);
+ case 2: return(present&available);
+ default:return(0);
+ }
+}
+
+bool
+laptop_portable::has_software_suspend(int type)
+{
+ return(::has_software_suspend(type));
+}
+
+void
+laptop_portable::software_suspend_set_mask(bool hibernate)
+{
+ software_suspend_is_preferred = hibernate;
+}
+
+
+static int x_acpi_init = 0;
+static bool
+has_acpi()
+{
+ static bool val;
+ static bool checked = 0;
+
+ if (!checked) {
+ val = ::access("/proc/acpi", F_OK) == 0;
+ checked = 1;
+ }
+ return(val);
+}
+
+static int
+has_acpi_power()
+{
+ static int val;
+
+ if (x_acpi_init)
+ return(val);
+ x_acpi_init = 1;
+ val = 0;
+
+ acpi_batteries.clear();
+
+ if (acpi_ac_status() >= 0)
+ acpi_ac_ok = 1;
+
+ QDir battdir("/proc/acpi/battery");
+ battdir.setFilter(QDir::Dirs);
+ if(!battdir.isReadable())
+ return(val = 0);
+ for(uint i = 0; !battdir[i].isNull(); ++i) {
+ if(battdir[i] == "." || battdir[i] == "..")
+ continue;
+ bool ok = 0;
+ acpi_battery_info bat = {0,0,0,0,0,0,0,0,0};
+ QString base = battdir.path() + "/" + battdir[i] + "/";
+ QString name(base + "state");
+ QFileInfo f(name);
+ if(f.isReadable()) {
+ bat.state_file = name;
+ ok = true;
+ } else {
+ name = base + "status";
+ f.setFile(name);
+ if(f.isReadable()) {
+ bat.state_file = name;
+ ok = true;
+ }
+ }
+ name = base + "info";
+ f.setFile(name);
+ if(f.isReadable()) {
+ bat.info_file = name;
+ ok = true;
+ }
+ if (ok) {
+ bat.name = battdir[i];
+ acpi_batteries.append(bat);
+ val = 1;
+ }
+ }
+ if (!acpi_ac_ok)
+ val = 0;
+ return(val);
+}
+
+static unsigned long acpi_sleep_enabled = 0x00; // acpi sleep functions enabled mask
+
+
+static bool
+has_acpi_sleep(int state)
+{
+ static int known=0;
+ static unsigned long mask=0;
+ if (known != last_seed) {
+ known = last_seed;
+ mask = 0;
+
+ QFile p("/sys/power/state");
+ QFile f("/proc/acpi/sleep");
+
+ if (p.open(IO_ReadOnly)) {
+ QString l;
+ QTextStream t(&p);
+ l = t.readLine();
+ QStringList ll = QStringList::split(' ',l,false);
+ for (QValueListIterator<QString> i = ll.begin(); i!=ll.end(); i++) {
+ QString s = *i;
+
+ if (s.compare("standby")==0)
+ mask |= (1<<1);
+ else if (s.compare("mem")==0)
+ mask |= (1<<3);
+ else if (s.compare("disk")==0)
+ mask |= (1<<4);
+ }
+ p.close();
+ }
+ else if (f.open(IO_ReadOnly)) {
+ QString l;
+ QTextStream t(&f);
+ l = t.readLine();
+ QStringList ll = QStringList::split(' ',l,false);
+ for (QValueListIterator<QString> i = ll.begin(); i!=ll.end(); i++) {
+ QString s = *i;
+ if (s[0] == 'S') {
+ int c = s[1].digitValue();
+ if (c >= 0 && c <= 9)
+ mask |= 1<<c;
+ }
+ }
+ f.close();
+ }
+ }
+ return((mask&acpi_sleep_enabled&(1<<state)) != 0);
+}
+
+static bool acpi_performance_enabled = 0;
+static bool acpi_throttle_enabled = 0;
+void
+laptop_portable::acpi_set_mask(bool standby, bool suspend, bool hibernate, bool perf, bool throttle)
+{
+ acpi_sleep_enabled =
+ (standby ? (1<<1)|(1<<2) : 0) |
+ (suspend ? 1<<3 : 0) |
+ (hibernate ? 1<<4 : 0);
+ acpi_performance_enabled = perf;
+ acpi_throttle_enabled = throttle;
+ last_seed++;
+}
+
+static void
+invoke_acpi_helper(const char *param, const char *param2, const char *param3)
+{
+ KProcess proc;
+ proc << KStandardDirs::findExe("klaptop_acpi_helper");
+ proc << param;
+ if (param2)
+ proc << param2;
+ if (param3)
+ proc << param3;
+ proc.start(KProcess::Block); // helper runs fast and we want to see the result
+}
+
+static unsigned long apm_sleep_enabled = 0x0c; // apm sleep functions enabled mask
+static bool
+has_apm_sleep(int state)
+{
+ return((apm_sleep_enabled&(1<<state)) != 0);
+}
+
+void
+laptop_portable::apm_set_mask(bool standby, bool suspend)
+{
+ apm_sleep_enabled =
+ (standby ? 1<<2 : 0) |
+ (suspend ? 1<<3 : 0);
+ last_seed++;
+}
+
+static bool apm_sleep_access_ok();
+static bool acpi_sleep_access_ok();
+
+static int
+apm_has_time()
+{
+ return(!apm_no_time);
+}
+
+//
+// something changed maybe we need to check out environment again
+//
+void
+laptop_portable::power_management_restart()
+{
+ last_seed++;
+ x_acpi_init = 0;
+}
+
+int laptop_portable::has_apm(int type)
+{
+ switch (type) {
+ case 0:
+ return(::has_apm());
+ case 1:
+ return(::has_apm() && ::apm_sleep_access_ok());
+ default:
+ return(0);
+ }
+}
+
+//
+// returns 1 if we support acpi
+//
+int laptop_portable::has_acpi(int type)
+{
+ switch (type) {
+ case 0:
+ return(::has_acpi_power());
+ case 1:
+ return(::has_acpi() && ::acpi_sleep_access_ok());
+ case 3:
+ return(::has_acpi() &&::acpi_sleep_access_ok() && (::has_acpi_sleep(1)||::has_acpi_sleep(2)));
+ case 4:
+ return(::has_acpi() &&::acpi_sleep_access_ok() && ::has_acpi_sleep(3));
+ case 5:
+ return(::has_acpi() &&::acpi_sleep_access_ok() && ::has_acpi_sleep(4));
+ default:
+ return(0);
+ }
+}
+
+//
+// The following code was derived from tpctl for IBM thinkpad support
+// (Thomas Hood, Bill Mair - tpctl.sourceforge.net)
+//
+// we check for the existence of /dev/thinkpad/thinkpad or /dev/thinkpad
+//
+static const char *ibm_device;
+static int ibm_fd = -1;
+
+static bool has_ibm()
+{
+ static int known=0;
+ static bool result;
+ if (known == last_seed)
+ return(result);
+ known = last_seed;
+ result = 0;
+ if (ibm_fd >= 0) {
+ result = 1;
+ return(1);
+ }
+ ibm_device = "/dev/thinkpad/thinkpad";
+ if ((ibm_fd = open(ibm_device, O_RDWR)) < 0) {
+ ibm_device = "/dev/thinkpad";
+ if ((ibm_fd = open(ibm_device, O_RDWR)) < 0)
+ return(0);
+ }
+ result = 1;
+ return(1);
+}
+//
+// returns 1 if we support power management
+//
+int laptop_portable::has_power_management()
+{
+ if (::has_apm())
+ return 1;
+ if (::has_pmu())
+ return 1;
+ if (::has_acpi_power())
+ return 1;
+ if (::has_ibm())
+ return 1;
+ // INSERT HERE
+ return 0;
+}
+//
+// returns 1 if the BIOS returns the time left in the battery rather than a % of full
+//
+int laptop_portable::has_battery_time()
+{
+ if (::has_acpi_power())
+ return 1;
+ if (::apm_has_time())
+ return 1;
+ // INSERT HERE
+ return 0;
+}
+//
+// returns 1 if we can perform a change-to-suspend-mode operation for the user
+// (has_power_management() has already returned 1)
+//
+int laptop_portable::has_suspend()
+{
+ if (::has_acpi())
+ return ::acpi_sleep_access_ok() && ::has_acpi_sleep(3);
+ if (::has_pmu())
+ return 1;
+ if (::has_ibm())
+ return 1;
+ if (::has_apm())
+ return ::apm_sleep_access_ok() && ::has_apm_sleep(3);
+ // INSERT HERE
+ return 0;
+}
+//
+// returns 1 if we can perform a change-to-standby-mode operation for the user
+// (has_power_management() has already returned 1)
+//
+int laptop_portable::has_standby()
+{
+ if (::has_pmu())
+ return 0;
+ if (::has_acpi())
+ return ::acpi_sleep_access_ok() && (::has_acpi_sleep(1)||::has_acpi_sleep(2));
+ if (::has_ibm())
+ return 1;
+ if (::has_apm())
+ return ::apm_sleep_access_ok() && ::has_apm_sleep(2);
+ // INSERT HERE
+ return 0;
+}
+//
+// returns 1 if we can perform a change-to-hibernate-mode for a user
+// (has_power_management() has already returned 1) [hibernate is the save-to-disk mode
+// not supported by linux APM]
+//
+int laptop_portable::has_hibernation()
+{
+ if (::has_pmu())
+ return 0;
+ if (::has_software_suspend(1)) // must be before acpi
+ return 1;
+ if (::has_acpi())
+ return ::acpi_sleep_access_ok() && ::has_acpi_sleep(4);
+ if (::has_ibm())
+ return 1;
+ // INSERT HERE
+ return 0;
+}
+
+//
+// explain to the user what they need to do if has_power_management() returned 0
+// to get any software they lack
+//
+
+KActiveLabel *laptop_portable::no_power_management_explanation(QWidget *parent)
+{
+ if (access("/proc/acpi", F_OK) == 0) { // probably has default kernel ACPI installed
+ KActiveLabel* explain = new KActiveLabel(i18n("Your computer seems to have a partial ACPI installation. ACPI was probably enabled, but some of the sub-options were not - you need to enable at least 'AC Adaptor' and 'Control Method Battery' and then rebuild your kernel."), parent);
+ return(explain);
+ }
+
+ KActiveLabel* explain = new KActiveLabel(i18n("Your computer doesn't have the Linux APM (Advanced Power Management) or ACPI software installed, or doesn't have the APM kernel drivers installed - check out the <a href=\"http://www.linuxdoc.org/HOWTO/Laptop-HOWTO.html\">Linux Laptop-HOWTO</a> document for information on how to install APM."), parent);
+
+ return(explain);
+}
+
+//
+// explain to the user what they need to do to get suspend/resume to work from user mode
+//
+QLabel *laptop_portable::how_to_do_suspend_resume(QWidget *parent)
+{
+ if (::has_apm()) {
+ // TODO: remove linefeed from string, can't do it right now coz we have a string freeze
+ QLabel* note = new KRichTextLabel(i18n("\nIf you make /usr/bin/apm setuid then you will also "
+ "be able to choose 'suspend' and 'standby' in the above "
+ "dialog - check out the help button below to find out "
+ "how to do this").replace("\n", QString::null), parent);
+ return(note);
+ }
+ if (::has_acpi()) {
+ // TODO: remove linefeed from string, can't do it right now coz we have a string freeze
+ QLabel* note = new KRichTextLabel(i18n("\nYou may need to enable ACPI suspend/resume in the ACPI panel").replace("\n", QString::null), parent);
+ return(note);
+ }
+ // TODO: remove linefeed from string, can't do it right now coz we have a string freeze
+ QLabel* note = new KRichTextLabel(i18n("\nYour system does not support suspend/standby").replace("\n", QString::null), parent);
+ return(note);
+}
+
+static char tmp0[256], tmp1[256];
+static int present=0;
+static
+void get_pcmcia_info()
+{
+ FILE *f = fopen("/var/lib/pcmcia/stab", "r");
+ if (!f) f = fopen("/var/run/stab", "r");
+ if (f) {
+ int c;
+ char *cp;
+
+ present = 1;
+ cp = tmp0;
+ for (;;) {
+ c = fgetc(f);
+ if (c == EOF || c == '\n')
+ break;
+ if (c == ':') {
+ while ((c = fgetc(f)) == ' ')
+ ;
+ if (c == EOF)
+ break;
+ for (;;) {
+ *cp++ = c;
+ c = fgetc(f);
+ if (c == EOF || c == '\n')
+ break;
+ }
+ break;
+ }
+ }
+ *cp = 0;
+
+ if (c != EOF) {
+ cp = tmp1;
+ for (;;) {
+ c = fgetc(f);
+ if (c == EOF)
+ break;
+ if (c == ':') {
+ while ((c = fgetc(f)) == ' ')
+ ;
+ if (c == EOF)
+ break;
+ for (;;) {
+ *cp++ = c;
+ c = fgetc(f);
+ if (c == EOF || c == '\n')
+ break;
+ }
+ break;
+ }
+ }
+ *cp = 0;
+ }
+
+ fclose(f);
+ } else {
+ present = 0;
+ }
+}
+
+//
+// pcmcia support - this will be replaced by better - pcmcia support being worked on by
+// others
+//
+QLabel *laptop_portable::pcmcia_info(int x, QWidget *parent)
+{
+ if (x == 0)
+ get_pcmcia_info();
+ if (!present) {
+ if (x == 1)
+ return(new QLabel(i18n("No PCMCIA controller detected"), parent));
+ return(new QLabel(i18n(""), parent));
+ } else {
+ switch (x) {
+ case 0: return(new QLabel(i18n("Card 0:"), parent));
+ case 1: return(new QLabel(tmp0, parent));
+ case 2: return(new QLabel(i18n("Card 1:"), parent));
+ default:return(new QLabel(tmp1, parent));
+ }
+ }
+}
+
+//
+// puts us into standby mode
+//
+void laptop_portable::invoke_standby()
+{
+ last_seed++; // make it look for battery removal/return
+ if (::has_acpi()) {
+ if (::has_acpi_sleep(1)) { // people seem to argue as to which is 'standby' the S1 people are winning
+ ::invoke_acpi_helper("--standby", 0, 0);
+ } else {
+ ::invoke_acpi_helper("--standby2", 0, 0);
+ }
+ return;
+ }
+ if (::has_ibm()) {
+ smapi_ioparm_t ioparmMy;
+ sync();
+ ioparmMy.in.bFunc = (byte) 0x70;
+ ioparmMy.in.bSubFunc = (byte) 0;
+ ioparmMy.in.wParm1 = (word) 0;
+ ioparmMy.in.wParm2 = (word) 0;
+ ioparmMy.in.wParm3 = (word) 0;
+ ioparmMy.in.dwParm4 = (dword) 0;
+ ioparmMy.in.dwParm5 = (dword) 0;
+ (void)ioctl_smapi( ibm_fd, &ioparmMy );
+ return;
+ }
+ // add other machine specific standbys here
+ KProcess proc;
+ proc << "/usr/bin/apm";
+ proc << "--standby";
+ proc.start(KProcess::Block); // helper runs fast and we want to see the result
+}
+
+//
+// puts us into suspend mode
+//
+void laptop_portable::invoke_suspend()
+{
+ last_seed++; // make it look for battery removal/return
+
+ if (::has_pmu()) {
+ KProcess proc;
+ proc << "/usr/bin/apm";
+ proc << "-f";
+ proc.start(KProcess::Block); // helper runs fast and we want to see the result
+ return;
+ }
+
+ if (::has_acpi()) {
+ ::invoke_acpi_helper("--suspend", 0, 0);
+ return;
+ }
+ if (::has_ibm()) {
+ smapi_ioparm_t ioparmMy;
+ sync();
+ ioparmMy.in.bFunc = (byte) 0x70;
+ ioparmMy.in.bSubFunc = (byte) 1;
+ ioparmMy.in.wParm1 = (word) 0;
+ ioparmMy.in.wParm2 = (word) 0;
+ ioparmMy.in.wParm3 = (word) 0;
+ ioparmMy.in.dwParm4 = (dword) 0;
+ ioparmMy.in.dwParm5 = (dword) 0;
+ (void)ioctl_smapi( ibm_fd, &ioparmMy );
+ return;
+ }
+ // add other machine specific suspends here
+ KProcess proc;
+ proc << "/usr/bin/apm";
+ proc << "--suspend";
+ proc.start(KProcess::Block); // helper runs fast and we want to see the result
+}
+
+//
+// puts us into hibernate mode
+//
+void laptop_portable::invoke_hibernation()
+{
+ last_seed++; // make it look for battery removal/return
+ if (::has_software_suspend(1)) { // must be before acpi
+ ::invoke_acpi_helper("--software-suspend", 0, 0);
+ return;
+ }
+ if (::has_acpi()) {
+ ::invoke_acpi_helper("--hibernate", 0, 0);
+ return;
+ }
+ if (::has_ibm()) {
+ smapi_ioparm_t ioparmMy;
+ sync();
+ ioparmMy.in.bFunc = (byte) 0x70;
+ ioparmMy.in.bSubFunc = (byte) 2;
+ ioparmMy.in.wParm1 = (word) 0;
+ ioparmMy.in.wParm2 = (word) 0;
+ ioparmMy.in.wParm3 = (word) 0;
+ ioparmMy.in.dwParm4 = (dword) 0;
+ ioparmMy.in.dwParm5 = (dword) 0;
+ (void)ioctl_smapi( ibm_fd, &ioparmMy );
+ return;
+ }
+ // add other machine specific hibernates here
+}
+
+void
+laptop_portable::extra_config(QWidget *wp, KConfig *, QVBoxLayout *top_layout)
+{
+ if (laptop_portable::has_apm(1) || laptop_portable::has_acpi(1))
+ return;
+ if (laptop_portable::has_apm(0)) {
+ QLabel* explain = new KRichTextLabel( i18n("Your system has APM installed but may not be able to use all "
+ "of its features without further setup - look in the 'APM Config' "
+ "tab for information about setting up APM for suspend and resume"), wp);
+ top_layout->addWidget(explain, 0);
+ }
+ if (laptop_portable::has_acpi(0)) {
+ QLabel* explain = new KRichTextLabel( i18n("Your system has ACPI installed but may not be able to use all "
+ "of its features without further setup - look in the 'ACPI Config' "
+ "tab for information about setting up ACPI for suspend and resume"), wp);
+ top_layout->addWidget(explain, 0);
+ }
+}
+
+//
+// return current battery state
+//
+struct power_result laptop_portable::poll_battery_state()
+{
+ struct power_result p;
+
+ apm_info x = {0,0,0,-1};
+ if (have_pmu()) {
+ pmu_read(&x);
+ } else
+ if ((::has_acpi_power() ? ::acpi_read(&x) : ::apm_read(&x)) || (x.apm_flags&0x20)) {
+ // INSERT HERE
+ p.powered = 0;
+ p.percentage=0;
+ p.time = -1;
+ return p;
+ }
+ p.powered = x.ac_line_status&1;
+ p.percentage = x.battery_percentage;
+ p.time = x.battery_time;
+ return(p);
+}
+
+void
+laptop_portable::get_battery_status(int &num_batteries, QStringList &names, QStringList &state, QStringList &values)
+{
+ struct power_result r;
+
+ if (!has_power_management()) {
+ num_batteries = 0;
+ names.clear();
+ state.clear();
+ values.clear();
+ return;
+ }
+
+ if (::has_acpi_power()) {
+ names.clear();
+ state.clear();
+ values.clear();
+ acpi_read_batteries();
+ num_batteries = acpi_batteries.count();
+ for(unsigned int i = 0; i < acpi_batteries.count(); ++i) {
+ acpi_battery_info& bat = acpi_batteries[i];
+ names.append(bat.name);
+ values.append(QString("%1").arg(bat.percentage));
+ state.append(bat.present ? "yes" : "no");
+ }
+ return;
+ }
+
+ // INSERT HERE
+
+ num_batteries = 1;
+ r = poll_battery_state();
+ names.append("BAT1");
+ state.append("yes");
+ QString s;
+ s.setNum(r.percentage);
+ values.append(s);
+}
+
+
+//
+// returns the current system load average, -1 if none
+//
+static QFile lav_file;
+static bool lav_inited=0;
+static bool lav_openok=0;
+
+static bool has_lav()
+{
+ if (!lav_inited) {
+ lav_inited =1;
+ lav_file.setName("/proc/loadavg");
+ lav_openok = lav_file.open( IO_ReadOnly );
+ if (lav_openok)
+ lav_file.close();
+ }
+ return(lav_openok);
+}
+
+bool laptop_portable::has_lav()
+{
+ return ::has_lav();
+}
+
+float laptop_portable::get_load_average()
+{
+ if (!::has_lav())
+ return(-1);
+ lav_file.open( IO_ReadOnly );
+ QString l;
+ lav_file.readLine(l, 500);
+ lav_file.close();
+ QStringList ll = QStringList::split(' ', l, false);
+ l = ll[0];
+ bool ok;
+ float f = l.toFloat(&ok);
+ if (!ok)
+ f = -1;
+ return(f);
+}
+
+
+int laptop_portable::has_cpufreq() {
+ struct stat sb;
+ int rc;
+ rc = stat("/proc/cpufreq", &sb);
+ if (rc == 0) {
+ rc = stat("/proc/cpuinfo", &sb);
+ if (rc == 0)
+ return 1;
+ }
+ // INSERT HERE
+ return 0;
+}
+
+
+QString laptop_portable::cpu_frequency() {
+ QString rc;
+ QFile cf("/proc/cpufreq");
+ bool haveProfile = false;
+
+ if (cf.open(IO_ReadOnly)) {
+ while (!cf.atEnd()) {
+ QString l;
+ cf.readLine(l, 500);
+ if (l.left(3) == "CPU") {
+ QStringList ll = QStringList::split(' ', l, false);
+ rc = ll.last();
+ haveProfile = true;
+ break;
+ }
+ }
+
+ }
+ if (haveProfile) {
+ QFile ci("/proc/cpuinfo");
+ if (ci.open(IO_ReadOnly)) {
+ while (!ci.atEnd()) {
+ QString l;
+ ci.readLine(l, 500);
+ QStringList ll =
+ QStringList::split(':',l,false);
+ if (ll.count() != 2)
+ continue;
+ if (ll.first().stripWhiteSpace()
+ == "cpu MHz") {
+ rc = i18n("%1 MHz (%2)").arg(ll.last().stripWhiteSpace()).arg(rc);
+ break;
+ } else if (ll.first().stripWhiteSpace()
+ == "clock") {
+ rc = QString("%1 (%2)").arg(ll.last().stripWhiteSpace()).arg(rc);
+ break;
+ }
+ }
+ }
+ }
+
+ return rc;
+}
+
+static int sonyFd = -1;
+static int has_toshiba_brightness = 0;
+
+static bool
+acpi_helper_ok(bool type)
+{
+ static int known[2]={0,0};
+ static bool known_res[2];
+
+ if (known[type] == last_seed)
+ return(known_res[type]);
+ known[type] = last_seed;
+ known_res[type] = 0;
+ struct stat sb;
+ QString str = KStandardDirs::findExe("klaptop_acpi_helper");
+ if (str.isNull() || str.isEmpty())
+ return(0);
+
+ if (stat(str.latin1(), &sb) < 0)
+ return(0);
+ if (!S_ISREG(sb.st_mode))
+ return(0);
+ if (!type && getuid() != 0 && (sb.st_uid != 0 || !(sb.st_mode&S_ISUID)))
+ return(0);
+ if (!(sb.st_mode&0x111))
+ return(0);
+ known_res[type] = 1;
+ return(1);
+}
+
+static bool
+acpi_sleep_access_ok()
+{
+ static int known=0;
+ static int known_res=1;
+
+ if (known != last_seed) {
+ known = last_seed;
+ known_res = (::access("/proc/acpi/sleep", R_OK|W_OK)==0 && ::acpi_helper_ok(1)) ||
+ (::access("/proc/acpi/sleep", R_OK)==0 && ::acpi_helper_ok(0)) ||
+ (::access("/sys/power/state", R_OK|W_OK)==0 && ::acpi_helper_ok(1)) ||
+ (::access("/sys/power/state", R_OK)==0 && ::acpi_helper_ok(0));
+ }
+ return(known_res);
+}
+
+static bool
+apm_helper_ok(bool type)
+{
+ static int known[2]={0,0};
+ static bool known_res[2];
+
+ if (known[type] == last_seed)
+ return(known_res[type]);
+ known[type] = last_seed;
+ known_res[type] = 0;
+ struct stat sb;
+ QString str = "/usr/bin/apm";
+ if (str.isNull() || str.isEmpty())
+ return(0);
+ if (stat(str.latin1(), &sb) < 0)
+ return(0);
+ if (!S_ISREG(sb.st_mode))
+ return(0);
+ if (!type && getuid() != 0 && (sb.st_uid != 0 || !(sb.st_mode&S_ISUID)))
+ return(0);
+ if (!(sb.st_mode&0x111))
+ return(0);
+ known_res[type] = 1;
+ return(1);
+}
+
+static bool
+apm_sleep_access_ok()
+{
+ static int known=0;
+ static int known_res=1;
+
+ if (known != last_seed) {
+ known = last_seed;
+ known_res = (::access("/proc/apm", R_OK|W_OK)==0 && ::apm_helper_ok(1)) ||
+ (::access("/proc/apm", R_OK)==0 && ::apm_helper_ok(0));
+ }
+ return(known_res);
+}
+
+int
+laptop_portable::has_brightness()
+{
+ static int known=0;
+ static int known_res=1;
+
+ if (known == last_seed)
+ return(known_res);
+ known = last_seed;
+ if (sonyFd == -1 && ::access("/dev/sonypi", R_OK) == 0)
+ sonyFd = ::open("/dev/sonypi", O_RDONLY|O_NONBLOCK);
+ if (sonyFd >= 0)
+ return(1);
+ if (::has_acpi() &&
+ (((::access("/proc/acpi/TOSHIBA1/lcd", R_OK|W_OK)==0 || ::access("/proc/acpi/toshiba/lcd", R_OK|W_OK)==0) && ::acpi_helper_ok(1)) ||
+ ((::access("/proc/acpi/TOSHIBA1/lcd", R_OK)==0 || ::access("/proc/acpi/toshiba/lcd", R_OK)==0) && ::acpi_helper_ok(0)))) {
+ has_toshiba_brightness = 1;
+ return(1);
+ }
+ // check for new devices here
+ // INSERT HERE
+ known_res = 0;
+ return 0;
+}
+
+#define SONYPI_IOCSBRT _IOW('v', 0, unsigned char)
+
+//
+// There are two sorts of brightness calls - ones where we expect the user to raise the brightness themselves
+// by doing something (for these we don't allow the panel to go completely dark), and those where the
+// laptop software is going to remember the brightness and set it back later (like closing the lid
+// where we can go all the way black)
+//
+// NOTE: some panel interfaces (sony) can't actually go all the way blank anyway so we ignore the blank tag
+//
+void
+laptop_portable::set_brightness(bool blank, int val) // val = 0-255 255 brightest, 0 means dimmest (if !blank it must be still visible),
+{
+ if (sonyFd >= 0) {
+ unsigned char v;
+ if (val < 0)
+ val = 0;
+ if (val > 255)
+ val = 255;
+ v = val;
+ (void)::ioctl(sonyFd, SONYPI_IOCSBRT, &v);
+ return;
+ }
+ if (has_toshiba_brightness) {
+ char tmp[20];
+
+ if (val < 0)
+ val = 0;
+ if (val > 255)
+ val = 255;
+ val >>= 5;
+ if (val == 0 && !blank)
+ val = 1;
+ snprintf(tmp, sizeof(tmp), "%d", val&7);
+ ::invoke_acpi_helper("--toshibalcd", tmp, 0);
+ return;
+ }
+ // INSERT HERE
+}
+
+int
+laptop_portable::get_brightness() // return a val 0-255, or -1 if you can't
+{
+ if (sonyFd >= 0)
+ return(-1); // sonypi doesn't seem to return this reliably
+
+ // INSERT HERE
+ return(-1); // means can't extract it
+}
+
+#define MAP_SIZE 20
+static int acpi_performance_map[MAP_SIZE]; // hidden acpi state map
+static bool acpi_performance_enable[MAP_SIZE];
+static QStringList performance_list;
+static QString acpi_performance_cpu;
+static int acpi_throttle_map[MAP_SIZE];
+static bool acpi_throttle_enable[MAP_SIZE];
+static QStringList throttle_list;
+static QString acpi_throttle_cpu;
+
+static bool
+get_acpi_list(char p, int *map, const char *dev, QStringList &list, int &index, QString &cpu, bool get_enable, bool *enable_list)
+{
+ DIR *dfd;
+ struct dirent *dp;
+ unsigned int i = 0;
+ bool result = 0;
+
+ index = 0;
+ list.clear();
+ dfd = opendir("/proc/acpi/processor/");
+ if (dfd) {
+ for (dp = readdir(dfd);dp ;dp = readdir(dfd)) {
+ if (strcmp(dp->d_name, ".") == 0 ||
+ strcmp(dp->d_name, "..") == 0)
+ continue;
+ QString name("/proc/acpi/processor/");
+ name += dp->d_name;
+ name += dev;
+ if (!(::access(name.latin1(), R_OK|W_OK)==0 && ::acpi_helper_ok(1)) &&
+ !(::access(name.latin1(), R_OK)==0 && ::acpi_helper_ok(0)))
+ continue;
+ QFile f(name);
+ if (f.open(IO_ReadOnly)) {
+ while (!f.atEnd() && i < MAP_SIZE) {
+ QString l;
+ f.readLine(l, 500);
+ QStringList ll = QStringList::split(':',l,false);
+ QString tag = ll[0].stripWhiteSpace();
+ bool is_this = tag[0] == '*';
+ if (is_this) {
+ if (tag[1] != p)
+ continue;
+ tag.remove(0, 2);
+ } else {
+ if (tag[0] != p)
+ continue;
+ tag.remove(0, 1);
+ }
+ bool ok;
+ int val = tag.toInt(&ok);
+ if (ok) {
+ if (!result)
+ cpu = dp->d_name;
+ if (is_this)
+ index = i;
+ map[i] = val;
+ list.append(ll[1].stripWhiteSpace());
+ result = 1;
+ enable_list[i] = 1;
+ i++;
+ }
+ }
+ f.close();
+
+ //
+ // get the limit info if asked for
+ //
+ if (get_enable) {
+ name = QString("/proc/acpi/processor/")+dp->d_name+"/limit";
+ f.setName(name);
+ if (f.open(IO_ReadOnly)) {
+ while (!f.atEnd() && i < MAP_SIZE) {
+ QString l;
+ f.readLine(l, 500);
+ if (l.contains("active limit", false)) {
+ QRegExp rx(QString("%1(\\d+)").arg(p));
+ if (rx.search(l) >= 0) {
+ bool ok;
+ int min = rx.cap(1).toInt(&ok);
+ if (ok) {
+ for (int j = 0; j < min; j++)
+ enable_list[j] = 0;
+
+ }
+ }
+ break;
+ }
+ }
+ f.close();
+ }
+ }
+ break;
+ }
+ }
+ closedir(dfd);
+ }
+ return(result);
+}
+
+#define CPUFREQ_NONE 0
+#define CPUFREQ_24 1
+#define CPUFREQ_25 2
+#define CPUFREQ_SYSFS 3
+
+static QString cpufreq_cpu = "";
+static QString cpufreq_minmax_frequency[2];
+
+// get CPUFreq scaling policies via the sysfs interface
+static int get_cpufreq_sysfs_state(QStringList &states, int &current, const QString cpu) {
+ QString cur, buffer;
+
+ // read current scaling policy
+ QFile f("/sys/devices/system/cpu/" + cpu + "/cpufreq/scaling_governor");
+ if(!f.open(IO_ReadOnly) || f.atEnd())
+ return CPUFREQ_NONE;
+ f.readLine(buffer, 256);
+ cur = buffer.stripWhiteSpace();
+ f.close();
+
+ // read available scaling policies
+ states.clear();
+ f.setName("/sys/devices/system/cpu/" + cpu + "/cpufreq/scaling_available_governors");
+ if(!f.open(IO_ReadOnly))
+ return CPUFREQ_NONE;
+ int count = 0;
+ if(!f.atEnd()) {
+ f.readLine(buffer, 1024);
+ QStringList l = QStringList::split(' ', buffer.stripWhiteSpace(), false);
+ for(unsigned int i = 0; i < l.size(); ++i, ++count) {
+ states.append(l[i].stripWhiteSpace());
+ if(states[i] == cur)
+ current = count;
+ }
+ }
+ f.close();
+
+ return CPUFREQ_SYSFS;
+}
+
+// get CPUFreq scaling policies via the 2.5 /proc interface
+// sample output of cat /proc/cpufreq:
+// minimum CPU frequency - maximum CPU frequency - policy
+// CPU 0 700000 kHz ( 70 %) - 1000000 kHz (100 %) - powersave
+static int get_cpufreq_25_state(QStringList &states, int &current) {
+ current = -1;
+ states.clear();
+
+ QFile f("/proc/cpufreq");
+ if (f.open(IO_ReadOnly)) {
+ while (!f.atEnd()) {
+ QString l;
+ f.readLine(l, 1024);
+ QRegExp rx("CPU.*\\d+.*(\\d+).*-.*(\\d+).*-\\W*(\\w*)");
+ if (rx.search(l) >= 0) {
+ cpufreq_minmax_frequency[0] = rx.cap(1);
+ cpufreq_minmax_frequency[1] = rx.cap(2);
+ if(rx.cap(3) == "performance")
+ current = 0;
+ else
+ current = 1;
+ break;
+ }
+ }
+ }
+ f.close();
+
+ if(current < 0)
+ return CPUFREQ_NONE;
+
+ // we don't know all available scaling governors, so use only a minimal set
+ states.append("performance");
+ states.append("powersave");
+ return CPUFREQ_25;
+}
+
+// get CPUFreq scaling policies via the 2.4 /proc interface
+// The old interface doesn't support policies yet, we only get the min and max frequency,
+// so we use these as performance states.
+static int get_cpufreq_24_state(QStringList &states, int &current, const QString cpu) {
+ QString buffer, cur;
+ states.clear();
+
+ // current frequency
+ QFile f("/proc/sys/cpu/" + cpu + "/speed");
+ if(!f.open(IO_ReadOnly) || f.atEnd())
+ return CPUFREQ_NONE;
+ f.readLine(buffer, 16);
+ f.close();
+ cur = buffer.stripWhiteSpace();
+
+ // read maximal and minimal frequency
+ const char* files[] = { "max", "min" };
+ for(int i = 0; i <= 1; ++i) {
+ f.setName("/proc/sys/cpu/" + cpu + "/speed-" + files[i]);
+ if(!f.open(IO_ReadOnly) || f.atEnd())
+ return CPUFREQ_NONE;
+ f.readLine(buffer, 16);
+ f.close();
+ cpufreq_minmax_frequency[i] = buffer;
+ unsigned int val = buffer.toUInt() / 1000;
+ states.append(i18n("%1 MHz").arg(val));
+ if(buffer.stripWhiteSpace() == cur)
+ current = i;
+ }
+ return CPUFREQ_24;
+}
+
+// check for CPUFreq support and get a list of all available scaling policies
+// this method doesn't support multiple CPU's (neither does get_acpi_list() above),
+// but this shouldn't be a problem on notebooks...
+static int get_cpufreq_state(bool force, QStringList &states, int &current) {
+ static int known = -1;
+
+ // check wether we already know which interface to use
+ if(!force && known >= 0) {
+ switch(known) {
+ case CPUFREQ_SYSFS:
+ return get_cpufreq_sysfs_state(states, current, cpufreq_cpu);
+ break;
+ case CPUFREQ_25:
+ return get_cpufreq_25_state(states, current);
+ break;
+ case CPUFREQ_24:
+ return get_cpufreq_24_state(states, current, cpufreq_cpu);
+ break;
+ default:
+ return CPUFREQ_NONE;
+ }
+ }
+
+ // look for the CPUFreq sysfs interface first
+ QDir dir("/sys/devices/system/cpu");
+ dir.setFilter(QDir::Dirs);
+ if(dir.isReadable()) {
+ for(unsigned int i = 0; !dir[i].isNull(); ++i) {
+ if(dir[i] == "." || dir[i] == "..")
+ continue;
+ cpufreq_cpu = dir[i];
+ if(get_cpufreq_sysfs_state(states, current, cpufreq_cpu))
+ return (known = CPUFREQ_SYSFS);
+ }
+ }
+
+ // try the /proc interface from the 2.5 kernel series next
+ if(get_cpufreq_25_state(states, current))
+ return (known = CPUFREQ_25);
+
+ // last chance: the /proc interface from the 2.4 kernel series
+ dir.setPath("/proc/sys/cpu");
+ dir.setFilter(QDir::Dirs);
+ if(dir.isReadable()) {
+ for(unsigned int i = 0; !dir[i].isNull(); ++i) {
+ if(dir[i] == "." || dir[i] == "..")
+ continue;
+ cpufreq_cpu = dir[i];
+ if(get_cpufreq_24_state(states, current, cpufreq_cpu))
+ return (known = CPUFREQ_24);
+ }
+ }
+
+ // no CPUFreq support found
+ return (known = CPUFREQ_NONE);
+}
+
+bool
+laptop_portable::get_system_performance(bool force, int &current, QStringList &s, bool *&active) // do something to help get system profiles from places like ACPI
+{
+ if(!acpi_performance_enabled)
+ return false;
+ static int known=0;
+ static int index=0;
+ static bool result = 0;
+ if (known != last_seed || force) {
+ known = last_seed;
+ performance_list.clear();
+ result = 0;
+ current = 0;
+ if (::has_acpi()) {
+ active = acpi_performance_enable;
+ result = get_acpi_list('P', acpi_performance_map, "/performance", performance_list, index, acpi_performance_cpu, force, acpi_performance_enable);
+ }
+ // CPUFreq support
+ if (!result && get_cpufreq_state(force, performance_list, index)) {
+ for(unsigned int i = 0; i < performance_list.size(); ++i)
+ acpi_performance_enable[i] = true;
+ active = acpi_performance_enable;
+ result = true;
+ }
+ if (!result) {
+ // INSERT HERE
+ }
+ }
+ current = index;
+ s = performance_list;
+ return(result);
+}
+
+bool
+laptop_portable::get_system_throttling(bool force, int &current, QStringList &s, bool *&active) // do something to help get system throttling data from places like ACPI
+{
+ static int known=0;
+ static int index=0;
+ static bool result = 0;
+ if (known != last_seed || force) {
+ known = last_seed;
+ throttle_list.clear();
+ result = 0;
+ current = 0;
+ if (::has_acpi() && acpi_throttle_enabled) {
+ active = acpi_throttle_enable;
+ result = get_acpi_list('T', acpi_throttle_map, "/throttling", throttle_list, index, acpi_throttle_cpu, force, acpi_throttle_enable);
+ }
+ if (!result) {
+ // INSERT HERE
+ }
+ }
+ current = index;
+ s = throttle_list;
+ return(result);
+}
+
+void
+laptop_portable::set_system_performance(QString val) // val = string given by get_system_performance above
+{
+ if(!acpi_performance_enabled)
+ return;
+ int current, result;
+ if((result = get_acpi_list('P', acpi_performance_map, "/performance", performance_list, current, acpi_performance_cpu, false, acpi_performance_enable))) {
+ char tmp[20];
+ int ind = performance_list.findIndex(val);
+ if (ind < 0 || ind >= MAP_SIZE || current == ind)
+ return;
+ snprintf(tmp, sizeof(tmp), "%d", acpi_performance_map[ind]);
+ tmp[sizeof(tmp)-1]=0;
+ ::invoke_acpi_helper("--performance", acpi_performance_cpu.latin1(), tmp);
+ return;
+ }
+ // CPUFreq support
+ if((result = get_cpufreq_state(false, performance_list, current))) {
+ if(performance_list[current] == val)
+ return;
+ QString tmp;
+ switch(result) {
+ case CPUFREQ_SYSFS:
+ invoke_acpi_helper("--cpufreq-sysfs", cpufreq_cpu.latin1(), val.latin1());
+ return;
+ case CPUFREQ_25:
+ tmp = cpufreq_minmax_frequency[0] + ":" + cpufreq_minmax_frequency[1] + ":" + val;
+ invoke_acpi_helper("--cpufreq-25", tmp.latin1(), 0);
+ return;
+ case CPUFREQ_24:
+ int target = performance_list.findIndex(val);
+ invoke_acpi_helper("--cpufreq-24", cpufreq_cpu.latin1(), cpufreq_minmax_frequency[target].latin1());
+ return;
+ }
+ }
+ // INSERT HERE
+ return;
+}
+
+void
+laptop_portable::set_system_throttling(QString val) // val = string given by get_system_throttle above
+{
+ if (::has_acpi()) {
+ char tmp[20];
+ int ind = throttle_list.findIndex(val);
+ if (ind < 0 || ind >= MAP_SIZE)
+ return;
+ snprintf(tmp, sizeof(tmp), "%d", acpi_throttle_map[ind]);
+ tmp[sizeof(tmp)-1]=0;
+ ::invoke_acpi_helper("--throttling", acpi_throttle_cpu.latin1(), tmp);
+ return;
+ }
+ // INSERT HERE
+ return;
+}
+
+static QString acpi_power_name, acpi_lid_name; // names of paths to ACPI lid states
+
+static bool
+acpi_check_button(const char *prefix, QString &result)
+{
+ DIR *dfd;
+ struct dirent *dp;
+ bool v=0;
+
+ dfd = opendir(prefix);
+ if (dfd) {
+ for (dp = readdir(dfd);dp ;dp = readdir(dfd)) {
+ if (strcmp(dp->d_name, ".") == 0 ||
+ strcmp(dp->d_name, "..") == 0)
+ continue;
+ QString name(prefix);
+ name += "/";
+ name += dp->d_name;
+ name += "/state";
+ if (::access(name.latin1(), R_OK)!=0)
+ continue;
+ QFile f(name);
+ if (f.open(IO_ReadOnly)) {
+ while (!f.atEnd()) {
+ QString l;
+ f.readLine(l, 500);
+ if (l.contains("state:")) {
+ result = name;
+ v = 1;
+ break;
+ }
+ }
+ f.close();
+ if (v)
+ break;
+ }
+ }
+ closedir(dfd);
+ }
+ return(v);
+}
+
+bool
+laptop_portable::has_button(LaptopButton l) // true if we have support for a particular button
+{
+ static int known[2]={0,0};
+ static bool result[2] = {0,0};
+ int type = (l==LidButton?0:1);
+ if (known[type] != last_seed) {
+ result[type] = 0;
+ known[type] = last_seed;
+ if (::has_acpi()) {
+ switch (l) {
+ case LidButton:
+ result[type] = ::acpi_check_button("/proc/acpi/button/lid", acpi_lid_name);
+ break;
+ case PowerButton:
+ result[type] = ::acpi_check_button("/proc/acpi/button/power", acpi_power_name);
+ break;
+ default:
+ break;
+ }
+ }
+ if (!result[type] && ::has_ibm() && l == LidButton)
+ result[type] = 1;
+ if (!result[type]) {
+ // INSERT HERE
+ }
+ }
+ return(result[type]);
+}
+
+bool
+laptop_portable::get_button(LaptopButton l) // true if a button is pressed
+{
+ if (::has_acpi()) {
+ QString name;
+ switch (l) {
+ case LidButton:
+ name = acpi_lid_name;
+ break;
+ case PowerButton:
+ name = acpi_power_name;
+ break;
+ default:
+ break;
+ }
+ if (!name.isEmpty()) {
+ QFile f(name);
+ if (f.open(IO_ReadOnly)) {
+ while (!f.atEnd()) {
+ QString l;
+ f.readLine(l, 500);
+ QStringList ll = QStringList::split(':',l,false);
+ if (ll[0].stripWhiteSpace() == "state") {
+ if (ll[1].stripWhiteSpace() == "open") {
+ f.close();
+ return(0);
+ }
+ if (ll[1].stripWhiteSpace() == "closed") {
+ f.close();
+ return(1);
+ }
+ break;
+ }
+ }
+ f.close();
+ }
+
+ }
+ }
+ if (::has_ibm() && l == LidButton) {
+ smapidev_sensorinfo_t t;
+ if (smapidev_GetSensorInfo(ibm_fd, &t) == 0)
+ return(t.fLidClosed != 0);
+ }
+ // INSERT HERE
+ return(0);
+}
+
+#elif defined(__FreeBSD__) && HAVE_MACHINE_APM_BIOS_H
+
+/*
+** This is the FreeBSD-specific code.
+*/
+
+#include <errno.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <machine/apm_bios.h>
+#include <sys/stat.h>
+#include <qpushbutton.h>
+#include <qobject.h>
+#include <kactivelabel.h>
+#include <kprocess.h>
+
+#define APMDEV "/dev/apm"
+
+// FreeBSD support by yours truly. Yay.
+// Actually this code was "adapted" from apm(8) from
+// FreeBSD's collection of tools. The original apm program
+// was pieced together by Tatsumi Hosokawa <hosokawa@jp.FreeBSD.org> in 1994
+
+//
+// returns 1 if we support power management
+//
+
+#include <iostream>
+using namespace std;
+
+//
+// something changed maybe we need to check out environment again
+//
+void
+laptop_portable::power_management_restart()
+{
+ // INSERT HERE
+}
+
+int
+laptop_portable::has_power_management()
+{
+ int ret, fd = ::open(APMDEV, O_RDWR);
+
+ if (fd == -1) {
+ return 0;
+ }
+
+ struct apm_info info;
+ ret=ioctl(fd, APMIO_GETINFO, &info);
+ ::close(fd);
+
+ if (ret == -1) {
+ return 0;
+ }
+
+ return info.ai_status;
+}
+//
+// returns 1 if the BIOS returns the time left in the battery rather than a % of full
+//
+int laptop_portable::has_battery_time()
+{
+ int ret, fd = ::open(APMDEV, O_RDWR);
+
+ if (fd == -1)
+ return 0;
+
+ struct apm_info info;
+ ret=ioctl(fd, APMIO_GETINFO, &info);
+ ::close(fd);
+
+ if (ret == -1)
+ return 0;
+
+ return (info.ai_batt_time != 0xffff);
+}
+
+//
+// returns 1 if we can perform a change-to-suspend-mode operation for the user
+// (has_power_management() has already returned 1)
+//
+int laptop_portable::has_suspend()
+{
+ int ret, fd = ::open(APMDEV, O_RDWR);
+
+ if (fd == -1)
+ return 0;
+
+ struct apm_info info;
+ ret=ioctl(fd, APMIO_GETINFO, &info);
+ ::close(fd);
+
+ if (ret == -1)
+ return 0;
+
+ return (info.ai_capabilities & 0x02);
+}
+//
+// returns 1 if we can perform a change-to-standby-mode operation for the user
+// (has_power_management() has already returned 1)
+//
+int laptop_portable::has_standby()
+{
+ int ret, fd = ::open(APMDEV, O_RDWR);
+
+ if (fd == -1)
+ return 0;
+
+ struct apm_info info;
+ ret=ioctl(fd, APMIO_GETINFO, &info);
+ ::close(fd);
+
+ if (ret == -1)
+ return 0;
+
+ return (info.ai_capabilities & 0x01);
+}
+//
+// returns 1 if we can perform a change-to-hibernate-mode for a user
+// (has_power_management() has already returned 1) [hibernate is the save-to-disk mode
+// not supported by linux - different laptops have their own - the first here is for
+// a ThinkPad]
+//
+int laptop_portable::has_hibernation()
+{
+ if (::access(PATH_TPCTL, X_OK)==0)
+ return(1);
+ return(0);
+}
+
+//
+// explain to the user what they need to do if has_power_management() returned 0
+// to get any software they lack
+//
+KActiveLabel *laptop_portable::no_power_management_explanation(QWidget *parent)
+{
+ int fd;
+ KActiveLabel *explain;
+
+ fd = ::open(APMDEV, O_RDWR);
+ if (fd == -1) {
+ switch (errno) {
+ case ENOENT:
+ explain = new KActiveLabel(i18n("There is no /dev/apm file on this system. Please review the FreeBSD handbook on how to create a device node for the APM device driver (man 4 apm)."), parent);
+ break;
+ case EACCES:
+ explain = new KActiveLabel(i18n("Your system has the proper device node for APM support, however you cannot access it. If you are logged in as root right now, you have a problem, otherwise contact your local sysadmin and ask for read/write access to /dev/apm."), parent);
+ break;
+ case ENXIO:
+ explain = new KActiveLabel(i18n("Your kernel lacks support for Advanced Power Management."), parent);
+ break;
+ break;
+ default:
+ explain = new KActiveLabel(i18n("There was a generic error while opening /dev/apm."), parent);
+ break;
+ }
+ } else {
+ close(fd);
+ explain = new KActiveLabel(i18n("APM has most likely been disabled."), parent);
+ }
+
+ return(explain);
+}
+
+//
+// explain to the user what they need to do to get suspend/resume to work from user mode
+//
+QLabel *laptop_portable::how_to_do_suspend_resume(QWidget *parent)
+{
+ QLabel* note = new QLabel(" ", parent);
+ return(note);
+}
+
+
+//
+// pcmcia support - this will be replaced by better - pcmcia support being worked on by
+// others
+//
+QLabel *laptop_portable::pcmcia_info(int x, QWidget *parent)
+{
+ if (x == 0)
+ return(new QLabel(i18n("No PCMCIA controller detected"), parent));
+ return(new QLabel(i18n(""), parent));
+}
+//
+// puts us into standby mode
+//
+void laptop_portable::invoke_standby()
+{
+ int fd = ::open(APMDEV, O_RDWR);
+
+ if (fd == -1)
+ return;
+
+ ioctl(fd, APMIO_STANDBY, NULL);
+ ::close(fd);
+
+ return;
+}
+
+//
+// puts us into suspend mode
+//
+void laptop_portable::invoke_suspend()
+{
+ int fd = ::open(APMDEV, O_RDWR);
+
+ if (fd == -1)
+ return;
+
+ ioctl(fd, APMIO_SUSPEND, NULL);
+ ::close(fd);
+
+ return;
+}
+//
+// puts us into hibernate mode
+//
+void laptop_portable::invoke_hibernation()
+{
+ KProcess thisProc;
+
+ if (::access(PATH_TPCTL, X_OK)==0) {
+ thisProc << PATH_TPCTL;
+ thisProc << "---hibernate";
+ thisProc.start(KProcess::Block);
+ return;
+ }
+}
+
+//
+//ACPI specific - chances are you don't need to implement this one
+//
+void
+laptop_portable::acpi_set_mask(bool, bool, bool, bool, bool )
+{
+ // INSERT HERE
+}
+
+int laptop_portable::has_acpi(int)
+{
+ // INSERT HERE
+ return (0);
+}
+
+int laptop_portable::has_apm(int type)
+{
+ if (type == 1) // implement me .... this is the hook that pops up the panel for making /usr/sbin/apm setuid
+ return(0); // or in this case you could make an acpi_helper type app freebsd
+ return (1);
+}
+
+void
+laptop_portable::apm_set_mask(bool , bool )
+{
+}
+
+
+//
+// adds extra widgets to the battery panel
+//
+void
+laptop_portable::extra_config(QWidget * /*parent*/, KConfig * /*config*/, QVBoxLayout * /*layout*/)
+{
+ // INSERT HERE
+}
+
+
+
+//
+// return current battery state
+//
+struct power_result laptop_portable::poll_battery_state()
+{
+ struct power_result p;
+ int ret;
+
+ int fd = ::open(APMDEV, O_RDWR);
+
+ if (fd == -1)
+ goto bad;
+
+ struct apm_info info;
+ ret=ioctl(fd, APMIO_GETINFO, &info);
+ ::close(fd);
+
+ if (ret == -1)
+ goto bad;
+
+ p.powered = info.ai_acline;
+ p.percentage = (info.ai_batt_life==255 ? 100 : info.ai_batt_life);
+ p.time = (info.ai_batt_time != 0xffff ? info.ai_batt_time/60 : -1);
+ return(p);
+
+bad:
+ p.powered = 1;
+ p.percentage = 100;
+ p.time = 0;
+ return(p);
+}
+
+//
+// return the system load
+//
+
+bool laptop_portable::has_lav() { return 0; }
+
+float laptop_portable::get_load_average()
+{
+ // INSERT HERE
+ return(-1);
+}
+
+int laptop_portable::has_cpufreq() {
+ // INSERT HERE
+ return 0;
+}
+
+QString laptop_portable::cpu_frequency() {
+ // INSERT HERE
+ return "";
+}
+
+int
+laptop_portable::has_brightness()
+{
+ // INSERT HERE
+ return 0;
+}
+
+void
+laptop_portable::set_brightness(bool /*blank*/, int /*val*/) // val = 0-255 255 brightest, 0 means dimmest (if !blank it must be still visible),
+{
+ // INSERT HERE
+}
+
+int
+laptop_portable::get_brightness()
+{
+ // INSERT HERE
+ return(-1); // means can't extract it
+}
+
+bool
+laptop_portable::get_system_performance(bool, int &current, QStringList &s, bool *&) // do something to help get system profiles from places like ACPI
+{
+ // INSERT HERE
+ current = 0;
+ s.clear();
+ return(0); // if no profiles are available
+}
+
+bool
+laptop_portable::get_system_throttling(bool, int &current, QStringList &s, bool *&) // do something to help get system throttling data from places like ACPI
+{
+ // INSERT HERE
+ current = 0;
+ s.clear();
+ return(0);
+}
+
+void
+laptop_portable::set_system_performance(QString)
+{
+ // INSERT HERE
+}
+
+void
+laptop_portable::set_system_throttling(QString)
+{
+ // INSERT HERE
+}
+
+bool
+laptop_portable::has_button(LaptopButton) // true if we have support for a particular button
+{
+ // INSERT HERE
+ return(0);
+}
+
+bool
+laptop_portable::get_button(LaptopButton) // true if a button is pressed
+{
+ // INSERT HERE
+ return(0);
+}
+
+void
+laptop_portable::get_battery_status(int &num_batteries, QStringList &names, QStringList &state, QStringList &values) // get multiple battery status
+{
+ struct power_result r;
+
+ if (!has_power_management()) {
+ num_batteries = 0;
+ names.clear();
+ state.clear();
+ values.clear();
+ return;
+ }
+
+ // INSERT HERE
+
+ num_batteries = 1;
+ r = poll_battery_state();
+ names.append("BAT1");
+ state.append("yes");
+ QString s;
+ s.setNum(r.percentage);
+ values.append(s);
+}
+
+bool
+laptop_portable::has_software_suspend(int /*type*/)
+{
+ return false; // (::has_software_suspend(type));
+}
+
+void
+laptop_portable::software_suspend_set_mask(bool /*hibernate*/)
+{
+ // software_suspend_is_preferred = hibernate;
+}
+
+
+#elif defined(__NetBSD_APM__)
+
+#include <errno.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <sys/ioctl.h>
+#include <sys/stat.h>
+#include <machine/apmvar.h>
+#include <iostream.h>
+
+//
+// klaptopdeamon interface to NetBSD 1.5 apm.
+// Scott Presnell, srp@zgi.com, srp@tworoads.net
+// Fri Jun 29 17:21:25 PDT 2001
+// Tested on Dell I4K running NetBSD 1.5R
+//
+#define APMDEV "/dev/apm"
+
+//
+// Check for apm in kernel by talking to /dev/apm
+// (opening read only is allowed by any process).
+// returns 1 if we support power management
+//
+int
+laptop_portable::has_power_management()
+{
+ int ret, fd = ::open(APMDEV, O_RDONLY);
+
+ if (fd == -1) {
+ return 0;
+ }
+
+ struct apm_power_info info;
+ ret=ioctl(fd, APM_IOC_GETPOWER, &info);
+ ::close(fd);
+
+ if (ret == -1) {
+ return 0;
+ }
+
+ return 1;
+}
+
+void
+laptop_portable::power_management_restart()
+{
+ // INSERT HERE
+}
+
+//
+// returns 1 if the BIOS returns the time left in the battery rather than a % of full
+//
+int laptop_portable::has_battery_time()
+{
+ int ret, fd = ::open(APMDEV, O_RDONLY);
+
+ if (fd == -1)
+ return 0;
+
+ struct apm_power_info info;
+ ret=ioctl(fd, APM_IOC_GETPOWER, &info);
+ ::close(fd);
+
+ if (ret == -1)
+ return 0;
+
+ return (info.minutes_left != 0xffff);
+}
+
+//
+// returns 1 if we can perform a change-to-suspend-mode operation for the user
+// (ust check to see if we have the binary)
+// (has_power_management() has already returned 1)
+//
+int laptop_portable::has_suspend()
+{
+
+ struct stat s;
+ if (stat("/usr/sbin/apm", &s))
+ return(0);
+ return(1);
+}
+
+//
+// returns 1 if we can perform a change-to-standby-mode operation for the user
+// (just check to see if we have the binary)
+// (has_power_management() has already returned 1)
+//
+int laptop_portable::has_standby()
+{
+
+ struct stat s;
+ if (stat("/usr/sbin/apm", &s))
+ return(0);
+ return(1);
+}
+
+//
+// returns 1 if we can perform a change-to-hibernate-mode for a user
+// (has_power_management() has already returned 1) [hibernate is the save-to-disk mode
+// not supported by linux - different laptops have their own - the first here is for
+// a ThinkPad]
+// No support in NetBSD at this time.
+//
+int laptop_portable::has_hibernation()
+{
+ // INSERT HERE
+ return(0);
+}
+
+//
+// explain to the user what they need to do if has_power_management() returned 0
+// to get any software they lack
+//
+KActiveLabel *laptop_portable::no_power_management_explanation(QWidget *parent)
+{
+ int fd;
+ KActiveLabel *explain;
+
+ fd = ::open(APMDEV, O_RDONLY);
+ if (fd == -1) {
+ switch (errno) {
+ case ENOENT:
+ explain = new KActiveLabel(i18n("There is no /dev/apm file on this system. Please review the NetBSD documentation on how to create a device node for the APM device driver (man 4 apm)."), parent);
+ break;
+ case EACCES:
+ explain = new KActiveLabel(i18n("Your system has the proper device node for APM support, however you cannot access it. If you have APM compiled into the kernel this should not happen."), parent);
+ break;
+ case ENXIO:
+ explain = new KActiveLabel(i18n("Your kernel lacks support for Advanced Power Management."), parent);
+ break;
+ break;
+ default:
+ explain = new KActiveLabel(i18n("There was a generic error while opening /dev/apm."), parent);
+ break;
+ }
+ } else {
+ close(fd);
+ explain = new KActiveLabel(i18n("APM has most likely been disabled."), parent);
+ }
+
+ return(explain);
+}
+
+//
+// explain to the user what they need to do to get suspend/resume to work from user mode
+//
+QLabel *laptop_portable::how_to_do_suspend_resume(QWidget *parent)
+{
+ // INSERT HERE
+ QLabel* note = new QLabel(" ", parent);
+ return(note);
+}
+
+//
+// pcmcia support - this will be replaced by better - pcmcia support being worked on by
+// others
+//
+QLabel *laptop_portable::pcmcia_info(int x, QWidget *parent)
+{
+ // INSERT HERE
+ if (x == 0)
+ return(new QLabel(i18n("No PCMCIA controller detected"), parent));
+ return(new QLabel(i18n(""), parent));
+}
+
+//
+// puts us into standby mode
+// Use apm rather than ioctls in case they are running apmd
+// (as they should be).
+//
+void laptop_portable::invoke_standby()
+{
+ KProcess proc;
+ proc << "/usr/sbin/apm";
+ proc << "-S";
+ proc.start(KProcess::Block); // helper runs fast and we want to see the result
+}
+
+//
+// puts us into suspend mode
+// Use apm rather than ioctls in case they are running apmd
+// (as they should be).
+//
+void laptop_portable::invoke_suspend()
+{
+ KProcess proc;
+ proc << "/usr/sbin/apm";
+ proc << "-z";
+ proc.start(KProcess::Block); // helper runs fast and we want to see the result
+}
+
+//
+// puts us into hibernate mode
+// No hibernate mode for NetBSD.
+//
+void laptop_portable::invoke_hibernation()
+{
+ // INSERT HERE
+ return;
+}
+
+//
+//ACPI specific - chances are you don't need to implement this one
+//
+void
+laptop_portable::acpi_set_mask(bool, bool, bool, bool, bool )
+{
+ // INSERT HERE
+}
+
+int laptop_portable::has_acpi(int)
+{
+ // INSERT HERE
+ return (0);
+}
+
+int laptop_portable::has_apm(int type)
+{
+ if (type == 1) // implement me .... this is the hook that pops up the panel for making /usr/sbin/apm setuid
+ return(0);
+ return (1);
+}
+
+void
+laptop_portable::apm_set_mask(bool , bool )
+{
+}
+
+
+//
+// return current battery state
+//
+struct power_result laptop_portable::poll_battery_state()
+{
+ struct power_result p;
+ int ret;
+
+ int fd = ::open(APMDEV, O_RDONLY);
+
+ if (fd == -1)
+ goto bad;
+
+ struct apm_power_info info;
+ ret=ioctl(fd, APM_IOC_GETPOWER, &info);
+ ::close(fd);
+
+ if (ret == -1)
+ goto bad;
+
+ p.powered = (info.ac_state == APM_AC_ON);
+ p.percentage = (info.battery_life==255 ? 100 : info.battery_life);
+ p.time = (info.minutes_left != 0xffff ? info.minutes_left : -1);
+ return(p);
+
+bad:
+ p.powered = 1;
+ p.percentage = 100;
+ p.time = 0;
+ return(p);
+}
+
+//
+// return the system load
+//
+
+bool laptop_portable::has_lav() { return 0; }
+
+float laptop_portable::get_load_average()
+{
+ // INSERT HERE
+ return(-1);
+}
+
+
+int laptop_portable::has_cpufreq() {
+ // INSERT HERE
+ return 0;
+}
+
+QString laptop_portable::cpu_frequency() {
+ // INSERT HERE
+ return "";
+}
+
+int
+laptop_portable::has_brightness()
+{
+ // INSERT HERE
+ return 0;
+}
+
+void
+laptop_portable::set_brightness(bool blank, int val) // val = 0-255 255 brightest, 0 means dimmest (if !blank it must be still visible),
+{
+ // INSERT HERE
+}
+
+int
+laptop_portable::get_brightness()
+{
+ // INSERT HERE
+ return(-1); // means can't extract it
+}
+
+bool
+laptop_portable::get_system_throttling(bool, int &current, QStringList &s) // do something to help get system throttling data from places like ACPI
+{
+ // INSERT HERE
+ current = 0;
+ s.clear();
+ return(0);
+}
+
+void
+laptop_portable::set_system_performance(QString)
+{
+ // INSERT HERE
+}
+
+void
+laptop_portable::set_system_throttling(QString)
+{
+ // INSERT HERE
+}
+
+bool
+laptop_portable::has_button(LaptopButton) // true if we have support for a particular button
+{
+ // INSERT HERE
+ return(0);
+}
+
+bool
+laptop_portable::get_button(LaptopButton) // true if a button is pressed
+{
+ // INSERT HERE
+ return(0);
+}
+
+void
+laptop_portable::get_battery_status(int &num_batteries, QStringList &names, QStringList &state, QStringList &values) // get multiple battery status
+{
+ struct power_result r;
+
+ if (!has_power_management()) {
+ num_batteries = 0;
+ names.clear();
+ state.clear();
+ values.clear();
+ return;
+ }
+
+ // INSERT HERE
+
+ num_batteries = 1;
+ r = poll_battery_state();
+ names.append("BAT1");
+ state.append("yes");
+ QString s;
+ s.setNum(r.percentage);
+ values.append(s);
+}
+
+#else
+
+/*
+** This is utterly generic code.
+*/
+
+//
+// something changed maybe we need to check out environment again
+//
+void
+laptop_portable::power_management_restart()
+{
+ // INSERT HERE
+}
+
+//
+// returns 1 if we support power management
+//
+int
+laptop_portable::has_power_management()
+{
+ // INSERT HERE
+ return(0);
+}
+
+//
+// returns 1 if the BIOS returns the time left in the battery rather than a % of full
+//
+int laptop_portable::has_battery_time()
+{
+ // INSERT HERE
+ return (0);
+}
+
+//
+// returns 1 if we can perform a change-to-suspend-mode operation for the user
+// (has_power_management() has already returned 1)
+//
+int laptop_portable::has_suspend()
+{
+ // INSERT HERE
+ return(0);
+}
+//
+// returns 1 if we can perform a change-to-standby-mode operation for the user
+// (has_power_management() has already returned 1)
+//
+int laptop_portable::has_standby()
+{
+ // INSERT HERE
+ return(0);
+}
+//
+// returns 1 if we can perform a change-to-hibernate-mode for a user
+// (has_power_management() has already returned 1) [hibernate is the save-to-disk mode
+// not supported by linux]
+//
+int laptop_portable::has_hibernation()
+{
+ // INSERT HERE
+ return(0);
+}
+
+//
+// explain to the user what they need to do if has_power_management() returned 0
+// to get any software they lack
+//
+KActiveLabel *laptop_portable::no_power_management_explanation(QWidget *parent)
+{
+ KActiveLabel* explain = new KActiveLabel(i18n("Your computer or operating system is not supported by the current version of the\nKDE laptop control panels. If you want help porting these panels to work with it\nplease contact paul@taniwha.com."), parent);
+ // INSERT HERE
+ return(explain);
+}
+
+//
+// explain to the user what they need to do to get suspend/resume to work from user mode
+//
+QLabel *laptop_portable::how_to_do_suspend_resume(QWidget *parent)
+{
+ QLabel* note = new QLabel(" ", parent);
+ // INSERT HERE
+ return(note);
+}
+
+
+//
+// pcmcia support - this will be replaced by better - pcmcia support being worked on by
+// others
+//
+QLabel *laptop_portable::pcmcia_info(int x, QWidget *parent)
+{
+ // INSERT HERE
+ if (x == 0)
+ return(new QLabel(i18n("No PCMCIA controller detected"), parent));
+ return(new QLabel(i18n(""), parent));
+}
+//
+// puts us into standby mode
+//
+void laptop_portable::invoke_standby()
+{
+ // INSERT HERE
+}
+
+//
+// puts us into suspend mode
+//
+void laptop_portable::invoke_suspend()
+{
+ // INSERT HERE
+}
+//
+// puts us into hibernate mode
+//
+void laptop_portable::invoke_hibernation()
+{
+ // INSERT HERE
+}
+
+//
+//ACPI specific - chances are you don't need to implement this one
+//
+void
+laptop_portable::acpi_set_mask(bool, bool, bool, bool, bool )
+{
+ // INSERT HERE
+}
+
+int laptop_portable::has_acpi(int)
+{
+ // INSERT HERE
+ return (0);
+}
+
+void
+laptop_portable::apm_set_mask(bool, bool)
+{
+ // INSERT HERE
+}
+
+int laptop_portable::has_apm(int)
+{
+ // INSERT HERE
+ return (0);
+}
+
+
+//
+// adds extra widgets to the battery panel
+//
+void
+laptop_portable::extra_config(QWidget *parent, KConfig *config, QVBoxLayout *layout)
+{
+ // INSERT HERE
+}
+
+//
+// return current battery state
+//
+struct power_result laptop_portable::poll_battery_state()
+{
+ struct power_result p;
+ // INSERT HERE
+ p.powered = 0;
+ p.percentage = 0;
+ p.time = 0;
+ return(p);
+}
+
+//
+// return the system load
+//
+
+bool laptop_portable::has_lav() { return 0; }
+
+float laptop_portable::get_load_average()
+{
+ // INSERT HERE
+ return(-1);
+}
+
+int laptop_portable::has_cpufreq() {
+ // INSERT HERE
+ return 0;
+}
+
+QString laptop_portable::cpu_frequency() {
+ // INSERT HERE
+ return "";
+}
+
+int
+laptop_portable::has_brightness()
+{
+ // INSERT HERE
+ return 0;
+}
+
+void
+laptop_portable::set_brightness(bool blank, int val) // val = 0-255 255 brightest, 0 means dimmest (if !blank it must be still visible),
+{
+ // INSERT HERE
+}
+
+int
+laptop_portable::get_brightness()
+{
+ // INSERT HERE
+ return(-1); // means can't extract it
+}
+
+bool
+laptop_portable::get_system_performance(bool, int &current, QStringList &s, bool *&) // do something to help get system profiles from places like ACPI
+{
+ // INSERT HERE
+ current = 0;
+ s.clear();
+ return(0); // if no profiles are available
+}
+
+bool
+laptop_portable::get_system_throttling(bool, int &current, QStringList &s, bool *&) // do something to help get system throttling data from places like ACPI
+{
+ // INSERT HERE
+ current = 0;
+ s.clear();
+ return(0);
+}
+
+void
+laptop_portable::set_system_performance(QString)
+{
+ // INSERT HERE
+}
+
+void
+laptop_portable::set_system_throttling(QString)
+{
+ // INSERT HERE
+}
+
+bool
+laptop_portable::has_button(LaptopButton) // true if we have support for a particular button
+{
+ // INSERT HERE
+ return(0);
+}
+
+bool
+laptop_portable::get_button(LaptopButton) // true if a button is pressed
+{
+ // INSERT HERE
+ return(0);
+}
+
+void
+laptop_portable::get_battery_status(int &num_batteries, QStringList &names, QStringList &state, QStringList &values) // get multiple battery status
+{
+ struct power_result r;
+
+ if (!has_power_management()) {
+ num_batteries = 0;
+ names.clear();
+ state.clear();
+ values.clear();
+ return;
+ }
+
+ // INSERT HERE
+
+ num_batteries = 1;
+ r = poll_battery_state();
+ names.append("BAT1");
+ state.append("yes");
+ QString s;
+ s.setNum(r.percentage);
+ values.append(s);
+}
+
+bool
+laptop_portable::has_software_suspend(int type)
+{
+ return false; // (::has_software_suspend(type));
+}
+
+void
+laptop_portable::software_suspend_set_mask(bool hibernate)
+{
+ // software_suspend_is_preferred = hibernate;
+}
+#endif