00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045
00046
00047
00048
00049
00050
00051
00052
00053
00054
00055
00056
00057
00058
00059
00060
00061 #include <config-klaptopdaemon.h>
00062 #include <klocale.h>
00063 #include <kdebug.h>
00064 #include <stdio.h>
00065 #include "portable.h"
00066
00067 #ifdef __linux__
00068
00069
00070
00071
00072 #include <sys/types.h>
00073 #include <unistd.h>
00074 #include <sys/stat.h>
00075 #include <time.h>
00076 #include <stdlib.h>
00077 #include <math.h>
00078 #include <fcntl.h>
00079 #include <sys/ioctl.h>
00080 #include <dirent.h>
00081 #include <QPushButton>
00082 #include <QDir>
00083 #include <QFile>
00084 #include <qfileinfo.h>
00085 #include <qstringlist.h>
00086
00087 #include <QObject>
00088 #include <QRegExp>
00089 #include <qiodevice.h>
00090 #include <QLayout>
00091 #include <q3valuevector.h>
00092
00093 #include <QLabel>
00094 #include <QVBoxLayout>
00095
00096 #include <k3activelabel.h>
00097 #include <kconfig.h>
00098 #include <kstandarddirs.h>
00099 #include <kprocess.h>
00100 #include <krichtextlabel.h>
00101
00102
00103 extern "C"{
00104 #include "thinkpad_common.h"
00105 #include "smapi.h"
00106 #include "smapidev.h"
00107 }
00108
00109
00110
00111
00112
00113 typedef struct apm_info {
00114 unsigned int apm_flags;
00115 unsigned int ac_line_status;
00116 int battery_percentage;
00117 int battery_time;
00118 } apm_info;
00119
00120 static int
00121 apm_read(apm_info *ap)
00122 {
00123 FILE *f = 0;
00124 char tmp2[10];
00125 int tmp, s;
00126 unsigned int utmp;
00127 char version[256];
00128
00129 f = fopen("/proc/apm", "r");
00130 if (f == NULL)
00131 return(1);
00132 s = fscanf(f, "%255s %d.%d %x %x %x %x %d%% %d %s\n",
00133 version,
00134 &tmp,
00135 &tmp,
00136 &ap->apm_flags,
00137 &ap->ac_line_status,
00138 &utmp,
00139 &utmp,
00140 &ap->battery_percentage,
00141 &ap->battery_time,
00142 tmp2);
00143 if (s < 9) {
00144 fclose(f);
00145 return(1);
00146 }
00147 if (version[0] == 'B') {
00148 fclose(f);
00149 return(2);
00150 }
00151 if (ap->battery_percentage > 100)
00152 ap->battery_percentage = -1;
00153 if (strcmp(tmp2, "sec") == 0)
00154 ap->battery_time /= 60;
00155 fclose(f);
00156 return(0);
00157 }
00158
00159
00160
00161
00162
00163 static int pmustate = 0;
00164
00165 static bool
00166 have_pmu(void)
00167 {
00168 if (pmustate != 0)
00169 return (pmustate == 1);
00170 if (!access("/proc/pmu", R_OK|X_OK)) {
00171 kDebug() << "Found powermac PMU. Using that." ;
00172 pmustate = 1;
00173 return true;
00174 }
00175 pmustate = -1;
00176 return false;
00177 }
00178
00179
00180 static int
00181 pmu_read(apm_info *ap)
00182 {
00183 int bcnt = 0;
00184 memset(ap, 0, sizeof(apm_info));
00185 QFile f("/proc/pmu/info");
00186 if (!f.open(QIODevice::ReadOnly))
00187 return 1;
00188
00189 while (!f.atEnd()) {
00190 QString l;
00191 l = f.readLine();
00192 QStringList ll = QStringList::split(':', l, false);
00193 if (ll[0].trimmed() == "AC Power") {
00194 ap->ac_line_status = ll[1].trimmed().toInt();
00195
00196 } else if (ll[0].trimmed() == "Battery count") {
00197 bcnt = ll[1].trimmed().toInt();
00198
00199 }
00200 }
00201
00202 f.close();
00203
00204 int charge = 0;
00205 int timerem = 0;
00206 int maxcharge = 0;
00207 for (int i = 0; i < bcnt; i++) {
00208 QFile bf(QString("/proc/pmu/battery_%1").arg(i));
00209 if (!bf.open(QIODevice::ReadOnly))
00210 continue;
00211
00212 while(!bf.atEnd()) {
00213 QString l;
00214 l = bf.readLine();
00215 QStringList ll = QStringList::split(':', l, false);
00216 if (ll[0].trimmed() == "charge") {
00217 charge += ll[1].trimmed().toInt();
00218
00219 } else if (ll[0].trimmed() == "max_charge") {
00220 maxcharge += ll[1].trimmed().toInt();
00221
00222 } else if (ll[0].trimmed() == "time rem.") {
00223 timerem += ll[1].trimmed().toInt();
00224
00225 }
00226 }
00227 bf.close();
00228 }
00229 ap->battery_percentage = int(rint(100.0*float(float(charge)/float(maxcharge))));
00230 ap->battery_time = timerem;
00231
00232 if (ap->ac_line_status > 0 || timerem == 0 ||
00233 (ap->ac_line_status == 0 && charge > 100 && timerem == 0))
00234 ap->battery_time = -1;
00235
00236 return 0;
00237 }
00238
00239
00240 struct acpi_battery_info {
00241 int percentage;
00242 bool present;
00243 int cap;
00244 int cap_low;
00245 int remaining;
00246 int rate;
00247 QString name;
00248 QString state_file;
00249 QString info_file;
00250 };
00251
00252 static Q3ValueVector<acpi_battery_info> acpi_batteries;
00253 static int acpi_last_known=0;
00254 static int last_seed=1;
00255
00256 static unsigned char acpi_ac_ok;
00257
00258
00259
00260
00261
00262
00263
00264
00265
00266 static int
00267 acpi_ac_status()
00268 {
00269 DIR *dfd;
00270 struct dirent *dp;
00271 FILE *f = NULL;
00272 static char buff[NAME_MAX+50];
00273 static bool inited=0;
00274 static bool bad=0;
00275
00276 if (inited) {
00277 if (bad)
00278 return(-1);
00279 f = fopen(buff, "r");
00280 goto readit;
00281 }
00282 inited = 1;
00283
00284 dfd = opendir("/proc/acpi/ac_adapter/");
00285 if (dfd) {
00286 for (;;) {
00287 dp = readdir(dfd);
00288 if (dp == 0)
00289 break;
00290 if (strcmp(dp->d_name, ".") == 0 ||
00291 strcmp(dp->d_name, "..") == 0)
00292 continue;
00293 strcpy(buff, "/proc/acpi/ac_adapter/");
00294 strcat(buff, dp->d_name);
00295 strcat(buff, "/status");
00296 f = fopen(buff, "r");
00297 if (!f) {
00298 strcpy(buff, "/proc/acpi/ac_adapter/");
00299 strcat(buff, dp->d_name);
00300 strcat(buff, "/state");
00301 f = fopen(buff, "r");
00302 }
00303 if (f)
00304 break;
00305 }
00306 closedir(dfd);
00307 readit:
00308 if (f) {
00309 for (;;) {
00310 char buff2[1024];
00311 if (fgets(buff2, sizeof(buff), f) == NULL)
00312 break;
00313 if (strstr(buff2, "Status:") != NULL ||
00314 strstr(buff2, "state:") != NULL) {
00315 if (strstr(buff2, "on-line") != NULL) {
00316 fclose(f);
00317 return(1);
00318 }
00319 }
00320 }
00321 fclose(f);
00322 return(0);
00323 }
00324 }
00325 bad=1;
00326 return(-1);
00327 }
00328
00329 static void acpi_read_batteries() {
00330 QString buff;
00331 QFile *f;
00332 static int test_count = 0;
00333 bool skip = false;
00334
00335 for(int i = 0; i < acpi_batteries.count(); ++i) {
00336 acpi_battery_info& bat = acpi_batteries[i];
00337 bool present = false;
00338 if ((test_count==0 || acpi_last_known != last_seed) && !bat.info_file.isNull()) {
00339 f = new QFile(bat.info_file);
00340 if (f && f->open(QIODevice::ReadOnly)) {
00341 while( !( buff=f->readLine() ).isNull() ) {
00342 if (buff.contains("design capacity low:", Qt::CaseInsensitive)) {
00343 QRegExp rx("(\\d*)\\D*$");
00344 rx.search(buff);
00345 bat.cap_low = rx.cap(1).toInt();
00346 if (bat.cap_low < 0)
00347 bat.cap_low = 0;
00348 continue;
00349 }
00350 if (buff.contains("last full capacity:", Qt::CaseInsensitive)) {
00351 QRegExp rx("(\\d*)\\D*$");
00352 rx.search(buff);
00353 bat.cap = rx.cap(1).toInt();
00354 continue;
00355 }
00356 }
00357 f->close();
00358 bat.cap -= bat.cap_low;
00359 }
00360 delete f;
00361 }
00362 if (bat.cap <= 0) {
00363 KConfig* config = new KConfig("kcmlaptoprc", true , false );
00364 config->setGroup("AcpiBattery");
00365 bat.cap = config->readEntry(bat.name,0);
00366 delete config;
00367 }
00368 if (!bat.state_file.isNull()) {
00369 f = new QFile(bat.state_file);
00370 if (f && f->open(QIODevice::ReadOnly)) {
00371 while( !( buff= f->readLine() ).isNull()) {
00372 if (buff.contains("present rate:", Qt::CaseInsensitive)) {
00373 QRegExp rx("(\\d*)\\D*$");
00374 rx.search(buff);
00375 bat.rate = rx.cap(1).toInt();
00376 if (bat.rate < 0)
00377 bat.rate = 0;
00378 present = true;
00379 continue;
00380 }
00381 if (buff.contains("remaining capacity:", Qt::CaseInsensitive)) {
00382 QRegExp rx("(\\d*)\\D*$");
00383 rx.search(buff);
00384 bat.remaining = rx.cap(1).toInt();
00385 bat.remaining -= bat.cap_low;
00386 if (bat.remaining < 0)
00387 bat.remaining = 0;
00388 present = true;
00389 continue;
00390 }
00391 }
00392 f->close();
00393 }
00394 delete f;
00395 }
00396 if(present && !bat.present)
00397 skip = true;
00398 bat.present = present;
00399 if (bat.present) {
00400 if (bat.remaining > bat.cap) {
00401 bat.cap = bat.remaining;
00402 KConfig* config = new KConfig("kcmlaptoprc", false , false );
00403 config->setGroup("AcpiBattery");
00404 config->writeEntry(bat.name, bat.cap);
00405 config->sync();
00406 delete config;
00407 skip = true;
00408 }
00409 if (bat.cap == 0)
00410 bat.percentage = 0;
00411 else
00412 bat.percentage = bat.remaining*100/bat.cap;
00413 }
00414 else
00415 bat.percentage = 0;
00416 }
00417
00418 if (!skip) {
00419 acpi_last_known = last_seed;
00420 test_count++;
00421 }
00422 else
00423 test_count = 0;
00424 if (test_count > 1000)
00425 test_count = 0;
00426
00427 }
00428
00429 static int
00430 acpi_read(apm_info *ap)
00431 {
00432 int rate, part, total;
00433 int ret = 1;
00434 bool present = 0;
00435
00436 part = 0;
00437 total = 0;
00438 rate = 0;
00439
00440 acpi_read_batteries();
00441
00442 for(int i = 0; i < acpi_batteries.count(); ++i) {
00443 acpi_battery_info& bat = acpi_batteries[i];
00444 present |= bat.present;
00445 if(bat.present) {
00446 total += bat.cap;
00447 part += bat.remaining;
00448 rate += bat.rate;
00449 }
00450 ret = 0;
00451 }
00452
00453
00454
00455 if (rate == 0)
00456 {
00457 static int last_remaining = 0;
00458 static time_t last_time = 0;
00459 if (last_remaining != 0
00460 && last_time != 0)
00461 {
00462 int diff_time = time(0) - last_time;
00463 if (diff_time > 0)
00464 rate = (last_remaining - part) * 3600 / diff_time;
00465 }
00466 last_remaining = part;
00467 last_time = time(0);
00468 if (rate < 0)
00469 rate = 0;
00470 }
00471
00472 static int nrates = 0;
00473 static int saved_rate[8];
00474 static unsigned char ignore_next = 2;
00475
00476 ap->ac_line_status = 0;
00477
00478
00479
00480
00481
00482
00483
00484
00485
00486
00487
00488
00489 if (acpi_ac_status() == 1) {
00490 ap->ac_line_status |= 1;
00491 ignore_next = 2;
00492 } else {
00493
00494
00495
00496 if (ignore_next == 0) {
00497 if (nrates < 8)
00498 nrates++;
00499 for (int i = 8-1; i > 0; i--)
00500 saved_rate[i] = saved_rate[i-1];
00501 saved_rate[0] = rate;
00502 } else {
00503 ignore_next--;
00504 }
00505 }
00506
00507
00508
00509
00510
00511 if (nrates == 0) {
00512 ap->battery_time = -1;
00513 } else {
00514 rate = 0;
00515 for (int i = 0; i < nrates; i++)
00516 rate += saved_rate[i];
00517 rate = (rate+2*saved_rate[0])/(nrates+2);
00518 ap->battery_time = (rate==0 ? -1 : 60*part/rate);
00519 }
00520 ap->battery_percentage = (total==0?0:100*part/total);
00521 if (!present) {
00522 ap->battery_percentage = -1;
00523 ap->battery_time = -1;
00524 }
00525 ap->apm_flags = 0;
00526 return(ret);
00527 }
00528
00529 static int apm_no_time;
00530 static apm_info apmx = {0,0,0,0};
00531 static int
00532 has_apm()
00533 {
00534 static int init = 0;
00535 static int val;
00536 if (init)
00537 return(val);
00538 init = 1;
00539 val = 1;
00540 apm_no_time=0;
00541 if (apm_read(&apmx) || (apmx.apm_flags&0x20)) {
00542 val = 0;
00543 apm_no_time = 1;
00544 } else {
00545 apm_no_time = apmx.battery_time < 0;
00546 }
00547
00548 if (val == 0) {
00549 val = have_pmu();
00550 if (val && pmu_read(&apmx)) {
00551 val = 0;
00552 }
00553 }
00554 return(val);
00555 }
00556
00557
00558 static int
00559 has_pmu()
00560 {
00561 static int init = 0;
00562 static int val;
00563 if (init)
00564 return val;
00565 init = 1;
00566 val = 1;
00567 if (!QDir("/proc/pmu").exists()) {
00568 val = 0;
00569 }
00570 return val;
00571 }
00572
00573 static bool software_suspend_is_preferred = false;
00574 static bool acpi_helper_ok(bool type);
00575 static bool
00576 has_software_suspend(int type)
00577 {
00578 static int known=0;
00579 static bool present=0;
00580 static bool available=0;
00581 if (known != last_seed) {
00582 known = last_seed;
00583 available = 0;
00584 present = (((::access("/proc/sys/kernel/swsusp", F_OK) == 0) ||
00585 (::access("/proc/software_suspend", F_OK) == 0)) ||
00586 (::access("/proc/suspend2", F_OK) == 0)) &&
00587 (::access("/usr/sbin/hibernate", F_OK) == 0);
00588 if (present) {
00589 if (::getuid() == 0) {
00590 available = ::access("/usr/sbin/hibernate", X_OK) == 0 && acpi_helper_ok(1);
00591 } else {
00592 available = acpi_helper_ok(0);
00593 }
00594 }
00595 }
00596 switch (type) {
00597 case 0: return(present);
00598 case 1: return(present&available&software_suspend_is_preferred);
00599 case 2: return(present&available);
00600 default:return(0);
00601 }
00602 }
00603
00604 bool
00605 laptop_portable::has_software_suspend(int type)
00606 {
00607 return(::has_software_suspend(type));
00608 }
00609
00610 void
00611 laptop_portable::software_suspend_set_mask(bool hibernate)
00612 {
00613 software_suspend_is_preferred = hibernate;
00614 }
00615
00616
00617 static int x_acpi_init = 0;
00618 static bool
00619 has_acpi()
00620 {
00621 static bool val;
00622 static bool checked = 0;
00623
00624 if (!checked) {
00625 val = ::access("/proc/acpi", F_OK) == 0;
00626 checked = 1;
00627 }
00628 return(val);
00629 }
00630
00631 static int
00632 has_acpi_power()
00633 {
00634 static int val;
00635
00636 if (x_acpi_init)
00637 return(val);
00638 x_acpi_init = 1;
00639 val = 0;
00640
00641 acpi_batteries.clear();
00642
00643 if (acpi_ac_status() >= 0)
00644 acpi_ac_ok = 1;
00645
00646 QDir battdir("/proc/acpi/battery");
00647 battdir.setFilter(QDir::Dirs);
00648 if(!battdir.isReadable())
00649 return(val = 0);
00650 for(uint i = 0; !battdir[i].isNull(); ++i) {
00651 if(battdir[i] == "." || battdir[i] == "..")
00652 continue;
00653 bool ok = 0;
00654 acpi_battery_info bat = {0,0,0,0,0,0,0,0,0};
00655 QString base = battdir.path() + "/" + battdir[i] + "/";
00656 QString name(base + "state");
00657 QFileInfo f(name);
00658 if(f.isReadable()) {
00659 bat.state_file = name;
00660 ok = true;
00661 } else {
00662 name = base + "status";
00663 f.setFile(name);
00664 if(f.isReadable()) {
00665 bat.state_file = name;
00666 ok = true;
00667 }
00668 }
00669 name = base + "info";
00670 f.setFile(name);
00671 if(f.isReadable()) {
00672 bat.info_file = name;
00673 ok = true;
00674 }
00675 if (ok) {
00676 bat.name = battdir[i];
00677 acpi_batteries.append(bat);
00678 val = 1;
00679 }
00680 }
00681 if (!acpi_ac_ok)
00682 val = 0;
00683 return(val);
00684 }
00685
00686 static unsigned long acpi_sleep_enabled = 0x00;
00687
00688
00689 static bool
00690 has_acpi_sleep(int state)
00691 {
00692 static int known=0;
00693 static unsigned long mask=0;
00694 if (known != last_seed) {
00695 known = last_seed;
00696 mask = 0;
00697 QFile f("/proc/acpi/sleep");
00698 if (f.open(QIODevice::ReadOnly)) {
00699 QString l;
00700 l= f.readLine();
00701 QStringList ll = QStringList::split(' ',l,false);
00702 for (QStringList::const_iterator i = ll.constBegin(); i!=ll.constEnd(); ++i) {
00703 QString s = *i;
00704 if (s[0] == 'S') {
00705 int c = s[1].digitValue();
00706 if (c >= 0 && c <= 9)
00707 mask |= 1<<c;
00708 }
00709 }
00710 f.close();
00711 }
00712 }
00713 return((mask&acpi_sleep_enabled&(1<<state)) != 0);
00714 }
00715
00716 static bool acpi_performance_enabled = 0;
00717 static bool acpi_throttle_enabled = 0;
00718 void
00719 laptop_portable::acpi_set_mask(bool standby, bool suspend, bool hibernate, bool perf, bool throttle)
00720 {
00721 acpi_sleep_enabled =
00722 (standby ? (1<<1)|(1<<2) : 0) |
00723 (suspend ? 1<<3 : 0) |
00724 (hibernate ? 1<<4 : 0);
00725 acpi_performance_enabled = perf;
00726 acpi_throttle_enabled = throttle;
00727 last_seed++;
00728 }
00729
00730 static void
00731 invoke_acpi_helper(const char *param, const char *param2, const char *param3)
00732 {
00733 KProcess proc;
00734 proc << KStandardDirs::findExe("klaptop_acpi_helper");
00735 proc << param;
00736 if (param2)
00737 proc << param2;
00738 if (param3)
00739 proc << param3;
00740 proc.execute();
00741 }
00742
00743 static unsigned long apm_sleep_enabled = 0x0c;
00744 static bool
00745 has_apm_sleep(int state)
00746 {
00747 return((apm_sleep_enabled&(1<<state)) != 0);
00748 }
00749
00750 void
00751 laptop_portable::apm_set_mask(bool standby, bool suspend)
00752 {
00753 apm_sleep_enabled =
00754 (standby ? 1<<2 : 0) |
00755 (suspend ? 1<<3 : 0);
00756 last_seed++;
00757 }
00758
00759 static bool apm_sleep_access_ok();
00760 static bool acpi_sleep_access_ok();
00761
00762 static int
00763 apm_has_time()
00764 {
00765 return(!apm_no_time);
00766 }
00767
00768
00769
00770
00771 void
00772 laptop_portable::power_management_restart()
00773 {
00774 last_seed++;
00775 x_acpi_init = 0;
00776 }
00777
00778 int laptop_portable::has_apm(int type)
00779 {
00780 switch (type) {
00781 case 0:
00782 return(::has_apm());
00783 case 1:
00784 return(::has_apm() && ::apm_sleep_access_ok());
00785 default:
00786 return(0);
00787 }
00788 }
00789
00790
00791
00792
00793 int laptop_portable::has_acpi(int type)
00794 {
00795 switch (type) {
00796 case 0:
00797 return(::has_acpi_power());
00798 case 1:
00799 return(::has_acpi() && ::acpi_sleep_access_ok());
00800 case 3:
00801 return(::has_acpi() &&::acpi_sleep_access_ok() && (::has_acpi_sleep(1)||::has_acpi_sleep(2)));
00802 case 4:
00803 return(::has_acpi() &&::acpi_sleep_access_ok() && ::has_acpi_sleep(3));
00804 case 5:
00805 return(::has_acpi() &&::acpi_sleep_access_ok() && ::has_acpi_sleep(4));
00806 default:
00807 return(0);
00808 }
00809 }
00810
00811
00812
00813
00814
00815
00816
00817 static const char *ibm_device;
00818 static int ibm_fd = -1;
00819
00820 static bool has_ibm()
00821 {
00822 static int known=0;
00823 static bool result;
00824 if (known == last_seed)
00825 return(result);
00826 known = last_seed;
00827 result = 0;
00828 if (ibm_fd >= 0) {
00829 result = 1;
00830 return(1);
00831 }
00832 ibm_device = "/dev/thinkpad/thinkpad";
00833 if ((ibm_fd = open(ibm_device, O_RDWR)) < 0) {
00834 ibm_device = "/dev/thinkpad";
00835 if ((ibm_fd = open(ibm_device, O_RDWR)) < 0)
00836 return(0);
00837 }
00838 result = 1;
00839 return(1);
00840 }
00841
00842
00843
00844 int laptop_portable::has_power_management()
00845 {
00846 if (::has_apm())
00847 return 1;
00848 if (::has_pmu())
00849 return 1;
00850 if (::has_acpi_power())
00851 return 1;
00852 if (::has_ibm())
00853 return 1;
00854
00855 return 0;
00856 }
00857
00858
00859
00860 int laptop_portable::has_battery_time()
00861 {
00862 if (::has_acpi_power())
00863 return 1;
00864 if (::apm_has_time())
00865 return 1;
00866
00867 return 0;
00868 }
00869
00870
00871
00872
00873 int laptop_portable::has_suspend()
00874 {
00875 if (::has_acpi())
00876 return ::acpi_sleep_access_ok() && ::has_acpi_sleep(3);
00877 if (::has_pmu())
00878 return 1;
00879 if (::has_ibm())
00880 return 1;
00881 if (::has_apm())
00882 return ::apm_sleep_access_ok() && ::has_apm_sleep(3);
00883
00884 return 0;
00885 }
00886
00887
00888
00889
00890 int laptop_portable::has_standby()
00891 {
00892 if (::has_pmu())
00893 return 0;
00894 if (::has_acpi())
00895 return ::acpi_sleep_access_ok() && (::has_acpi_sleep(1)||::has_acpi_sleep(2));
00896 if (::has_ibm())
00897 return 1;
00898 if (::has_apm())
00899 return ::apm_sleep_access_ok() && ::has_apm_sleep(2);
00900
00901 return 0;
00902 }
00903
00904
00905
00906
00907
00908 int laptop_portable::has_hibernation()
00909 {
00910 if (::has_pmu())
00911 return 0;
00912 if (::has_software_suspend(1))
00913 return 1;
00914 if (::has_acpi())
00915 return ::acpi_sleep_access_ok() && ::has_acpi_sleep(4);
00916 if (::has_ibm())
00917 return 1;
00918
00919 return 0;
00920 }
00921
00922
00923
00924
00925
00926
00927 K3ActiveLabel *laptop_portable::no_power_management_explanation(QWidget *parent)
00928 {
00929 if (access("/proc/acpi", F_OK) == 0) {
00930 K3ActiveLabel* explain = new K3ActiveLabel(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);
00931 return(explain);
00932 }
00933
00934 K3ActiveLabel* explain = new K3ActiveLabel(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);
00935
00936 return(explain);
00937 }
00938
00939
00940
00941
00942 QLabel *laptop_portable::how_to_do_suspend_resume(QWidget *parent)
00943 {
00944 if (::has_apm()) {
00945
00946 QLabel* note = new KRichTextLabel(i18n("\nIf you make /usr/bin/apm setuid then you will also "
00947 "be able to choose 'suspend' and 'standby' in the above "
00948 "dialog - check out the help button below to find out "
00949 "how to do this").replace("\n", QString()), parent);
00950 return(note);
00951 }
00952 if (::has_acpi()) {
00953
00954 QLabel* note = new KRichTextLabel(i18n("\nYou may need to enable ACPI suspend/resume in the ACPI panel").replace("\n", QString()), parent);
00955 return(note);
00956 }
00957
00958 QLabel* note = new KRichTextLabel(i18n("\nYour system does not support suspend/standby").replace("\n", QString()), parent);
00959 return(note);
00960 }
00961
00962 static char tmp0[256], tmp1[256];
00963 static int present=0;
00964 static
00965 void get_pcmcia_info()
00966 {
00967 FILE *f = fopen("/var/lib/pcmcia/stab", "r");
00968 if (!f) f = fopen("/var/run/stab", "r");
00969 if (f) {
00970 int c;
00971 char *cp;
00972
00973 present = 1;
00974 cp = tmp0;
00975 for (;;) {
00976 c = fgetc(f);
00977 if (c == EOF || c == '\n')
00978 break;
00979 if (c == ':') {
00980 while ((c = fgetc(f)) == ' ')
00981 ;
00982 if (c == EOF)
00983 break;
00984 for (;;) {
00985 *cp++ = c;
00986 c = fgetc(f);
00987 if (c == EOF || c == '\n')
00988 break;
00989 }
00990 break;
00991 }
00992 }
00993 *cp = 0;
00994
00995 if (c != EOF) {
00996 cp = tmp1;
00997 for (;;) {
00998 c = fgetc(f);
00999 if (c == EOF)
01000 break;
01001 if (c == ':') {
01002 while ((c = fgetc(f)) == ' ')
01003 ;
01004 if (c == EOF)
01005 break;
01006 for (;;) {
01007 *cp++ = c;
01008 c = fgetc(f);
01009 if (c == EOF || c == '\n')
01010 break;
01011 }
01012 break;
01013 }
01014 }
01015 *cp = 0;
01016 }
01017
01018 fclose(f);
01019 } else {
01020 present = 0;
01021 }
01022 }
01023
01024
01025
01026
01027
01028 QLabel *laptop_portable::pcmcia_info(int x, QWidget *parent)
01029 {
01030 if (x == 0)
01031 get_pcmcia_info();
01032 if (!present) {
01033 if (x == 1)
01034 return(new QLabel(i18n("No PCMCIA controller detected"), parent));
01035 return(new QLabel(parent));
01036 } else {
01037 switch (x) {
01038 case 0: return(new QLabel(i18n("Card 0:"), parent));
01039 case 1: return(new QLabel(tmp0, parent));
01040 case 2: return(new QLabel(i18n("Card 1:"), parent));
01041 default:return(new QLabel(tmp1, parent));
01042 }
01043 }
01044 }
01045
01046
01047
01048
01049 void laptop_portable::invoke_standby()
01050 {
01051 last_seed++;
01052 if (::has_acpi()) {
01053 if (::has_acpi_sleep(1)) {
01054 ::invoke_acpi_helper("--standby", 0, 0);
01055 } else {
01056 ::invoke_acpi_helper("--standby2", 0, 0);
01057 }
01058 return;
01059 }
01060 if (::has_ibm()) {
01061 smapi_ioparm_t ioparmMy;
01062 sync();
01063 ioparmMy.in.bFunc = (byte) 0x70;
01064 ioparmMy.in.bSubFunc = (byte) 0;
01065 ioparmMy.in.wParm1 = (word) 0;
01066 ioparmMy.in.wParm2 = (word) 0;
01067 ioparmMy.in.wParm3 = (word) 0;
01068 ioparmMy.in.dwParm4 = (dword) 0;
01069 ioparmMy.in.dwParm5 = (dword) 0;
01070 (void)ioctl_smapi( ibm_fd, &ioparmMy );
01071 return;
01072 }
01073
01074 KProcess proc;
01075 proc << "/usr/bin/apm";
01076 proc << "--standby";
01077 proc.execute();
01078 }
01079
01080
01081
01082
01083 void laptop_portable::invoke_suspend()
01084 {
01085 last_seed++;
01086
01087 if (::has_pmu()) {
01088 KProcess proc;
01089 proc << "/usr/bin/apm";
01090 proc << "-f";
01091 proc.execute();
01092 return;
01093 }
01094
01095 if (::has_acpi()) {
01096 ::invoke_acpi_helper("--suspend", 0, 0);
01097 return;
01098 }
01099 if (::has_ibm()) {
01100 smapi_ioparm_t ioparmMy;
01101 sync();
01102 ioparmMy.in.bFunc = (byte) 0x70;
01103 ioparmMy.in.bSubFunc = (byte) 1;
01104 ioparmMy.in.wParm1 = (word) 0;
01105 ioparmMy.in.wParm2 = (word) 0;
01106 ioparmMy.in.wParm3 = (word) 0;
01107 ioparmMy.in.dwParm4 = (dword) 0;
01108 ioparmMy.in.dwParm5 = (dword) 0;
01109 (void)ioctl_smapi( ibm_fd, &ioparmMy );
01110 return;
01111 }
01112
01113 KProcess proc;
01114 proc << "/usr/bin/apm";
01115 proc << "--suspend";
01116 proc.execute();
01117 }
01118
01119
01120
01121
01122 void laptop_portable::invoke_hibernation()
01123 {
01124 last_seed++;
01125 if (::has_software_suspend(1)) {
01126 ::invoke_acpi_helper("--software-suspend", 0, 0);
01127 return;
01128 }
01129 if (::has_acpi()) {
01130 ::invoke_acpi_helper("--hibernate", 0, 0);
01131 return;
01132 }
01133 if (::has_ibm()) {
01134 smapi_ioparm_t ioparmMy;
01135 sync();
01136 ioparmMy.in.bFunc = (byte) 0x70;
01137 ioparmMy.in.bSubFunc = (byte) 2;
01138 ioparmMy.in.wParm1 = (word) 0;
01139 ioparmMy.in.wParm2 = (word) 0;
01140 ioparmMy.in.wParm3 = (word) 0;
01141 ioparmMy.in.dwParm4 = (dword) 0;
01142 ioparmMy.in.dwParm5 = (dword) 0;
01143 (void)ioctl_smapi( ibm_fd, &ioparmMy );
01144 return;
01145 }
01146
01147 }
01148
01149 void
01150 laptop_portable::extra_config(QWidget *wp, KConfig *, QVBoxLayout *top_layout)
01151 {
01152 if (laptop_portable::has_apm(1) || laptop_portable::has_acpi(1))
01153 return;
01154 if (laptop_portable::has_apm(0)) {
01155 QLabel* explain = new KRichTextLabel( i18n("Your system has APM installed but may not be able to use all "
01156 "of its features without further setup - look in the 'APM Config' "
01157 "tab for information about setting up APM for suspend and resume"), wp);
01158 top_layout->addWidget(explain, 0);
01159 }
01160 if (laptop_portable::has_acpi(0)) {
01161 QLabel* explain = new KRichTextLabel( i18n("Your system has ACPI installed but may not be able to use all "
01162 "of its features without further setup - look in the 'ACPI Config' "
01163 "tab for information about setting up ACPI for suspend and resume"), wp);
01164 top_layout->addWidget(explain, 0);
01165 }
01166 }
01167
01168
01169
01170
01171 struct power_result laptop_portable::poll_battery_state()
01172 {
01173 struct power_result p;
01174
01175 apm_info x = {0,0,0,-1};
01176 if (have_pmu()) {
01177 pmu_read(&x);
01178 } else
01179 if ((::has_acpi_power() ? ::acpi_read(&x) : ::apm_read(&x)) || (x.apm_flags&0x20)) {
01180
01181 p.powered = 0;
01182 p.percentage=0;
01183 p.time = -1;
01184 return p;
01185 }
01186 p.powered = x.ac_line_status&1;
01187 p.percentage = x.battery_percentage;
01188 p.time = x.battery_time;
01189 return(p);
01190 }
01191
01192 void
01193 laptop_portable::get_battery_status(int &num_batteries, QStringList &names, QStringList &state, QStringList &values)
01194 {
01195 struct power_result r;
01196
01197 if (!has_power_management()) {
01198 num_batteries = 0;
01199 names.clear();
01200 state.clear();
01201 values.clear();
01202 return;
01203 }
01204
01205 if (::has_acpi_power()) {
01206 names.clear();
01207 state.clear();
01208 values.clear();
01209 acpi_read_batteries();
01210 num_batteries = acpi_batteries.count();
01211 for(int i = 0; i < acpi_batteries.count(); ++i) {
01212 acpi_battery_info& bat = acpi_batteries[i];
01213 names.append(bat.name);
01214 values.append(QString("%1").arg(bat.percentage));
01215 state.append(bat.present ? "yes" : "no");
01216 }
01217 return;
01218 }
01219
01220
01221
01222 num_batteries = 1;
01223 r = poll_battery_state();
01224 names.append("BAT1");
01225 state.append("yes");
01226 QString s;
01227 s.setNum(r.percentage);
01228 values.append(s);
01229 }
01230
01231
01232
01233
01234
01235 static QFile lav_file;
01236 static bool lav_inited=0;
01237 static bool lav_openok=0;
01238
01239 static bool has_lav()
01240 {
01241 if (!lav_inited) {
01242 lav_inited =1;
01243 lav_file.setName("/proc/loadavg");
01244 lav_openok = lav_file.open( QIODevice::ReadOnly );
01245 if (lav_openok)
01246 lav_file.close();
01247 }
01248 return(lav_openok);
01249 }
01250
01251 bool laptop_portable::has_lav()
01252 {
01253 return ::has_lav();
01254 }
01255
01256 float laptop_portable::get_load_average()
01257 {
01258 if (!::has_lav())
01259 return(-1);
01260 lav_file.open( QIODevice::ReadOnly );
01261 QString l;
01262 l=lav_file.readLine();
01263 lav_file.close();
01264 QStringList ll = QStringList::split(' ', l, false);
01265 l = ll[0];
01266 bool ok;
01267 float f = l.toFloat(&ok);
01268 if (!ok)
01269 f = -1;
01270 return(f);
01271 }
01272
01273
01274 int laptop_portable::has_cpufreq() {
01275 struct stat sb;
01276 int rc;
01277 rc = stat("/proc/cpufreq", &sb);
01278 if (rc == 0) {
01279 rc = stat("/proc/cpuinfo", &sb);
01280 if (rc == 0)
01281 return 1;
01282 }
01283
01284 return 0;
01285 }
01286
01287
01288 QString laptop_portable::cpu_frequency() {
01289 QString rc;
01290 QFile cf("/proc/cpufreq");
01291 bool haveProfile = false;
01292
01293 if (cf.open(QIODevice::ReadOnly)) {
01294 while (!cf.atEnd()) {
01295 QString l;
01296 l = cf.readLine();
01297 if (l.left(3) == "CPU") {
01298 QStringList ll = QStringList::split(' ', l, false);
01299 rc = ll.last();
01300 haveProfile = true;
01301 break;
01302 }
01303 }
01304
01305 }
01306 if (haveProfile) {
01307 QFile ci("/proc/cpuinfo");
01308 if (ci.open(QIODevice::ReadOnly)) {
01309 while (!ci.atEnd()) {
01310 QString l;
01311 l=ci.readLine();
01312 QStringList ll =
01313 QStringList::split(':',l,false);
01314 if (ll.count() != 2)
01315 continue;
01316 if (ll.first().trimmed()
01317 == "cpu MHz") {
01318 rc = i18n("%1 MHz (%2)", ll.last().trimmed(), rc);
01319 break;
01320 } else if (ll.first().trimmed()
01321 == "clock") {
01322 rc = QString("%1 (%2)").arg(ll.last().trimmed()).arg(rc);
01323 break;
01324 }
01325 }
01326 }
01327 }
01328
01329 return rc;
01330 }
01331
01332 static int sonyFd = -1;
01333 static int has_toshiba_brightness = 0;
01334
01335 static bool
01336 acpi_helper_ok(bool type)
01337 {
01338 static int known[2]={0,0};
01339 static bool known_res[2];
01340
01341 if (known[type] == last_seed)
01342 return(known_res[type]);
01343 known[type] = last_seed;
01344 known_res[type] = 0;
01345 struct stat sb;
01346