-------- Original Message --------
Subject: [PATCH] powertop: wifi
Date: Mon, 27 Jul 2009 07:29:40 -0700
From: Johannes Berg <[email protected]>
To: Kok, Auke-jan H <[email protected]>
CC: Arjan van de Ven <[email protected]>, "Guy, Wey-Yi W"     
<[email protected]>

The current wifi code in powertop is pretty much broken
on current kernels due to various changes in how rfkill
is wired up, sysfs changes, etc.

On the other hand, the complexity really isn't required
on current kernels. Power saving can be enabled via the
regular wireless extensions ioctls, and there no longer
is a need to touch rfkill to save power, just clearing
IFF_UP for an interface is sufficient.

This patch adds a new file, wifi-new.c, containing all
the new logic for current kernels, which also doesn't
depend on iwlwifi or such, it's completely generic now.
I've kept the old file for backward compatibility, even
though it won't be doing anything on current kernels.

Here, 'current' might be the net-next-2.6 of now, or
maybe even later versions. However, the wireless.c code
has pretty restrictive assumptions anyway that make it
somewhat unlikely to work properly on many platforms,
like for instance assuming 'rfkill0' is always the right
rfkill instance -- this is wrong on almost all laptops.

Signed-off-by: Johannes Berg <[email protected]>
---
 Makefile   |    2
 powertop.c |    1
 powertop.h |    1
 wifi-new.c |  203 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 206 insertions(+), 1 deletion(-)

--- powertop-1.11.orig/powertop.c       2009-07-27 14:16:20.000000000 +0200
+++ powertop-1.11/powertop.c    2009-07-27 16:21:41.000000000 +0200
@@ -1134,6 +1134,7 @@ int main(int argc, char **argv)
                        suggest_hpet();
                suggest_ac97_powersave();
                suggest_wireless_powersave();
+               suggest_wifi_new_powersave();
                suggest_ondemand_governor();
                suggest_noatime();
                suggest_sata_alpm();
--- powertop-1.11.orig/powertop.h       2009-07-27 14:16:20.000000000 +0200
+++ powertop-1.11/powertop.h    2009-07-27 14:19:04.000000000 +0200
@@ -51,6 +51,7 @@ void suggest_nmi_watchdog(void);
 void suggest_hpet(void);
 void suggest_ac97_powersave(void);
 void suggest_wireless_powersave(void);
+void suggest_wifi_new_powersave(void);
 void suggest_ondemand_governor(void);
 void suggest_noatime(void);
 void suggest_sata_alpm(void);
--- /dev/null   1970-01-01 00:00:00.000000000 +0000
+++ powertop-1.11/wifi-new.c    2009-07-27 16:29:13.000000000 +0200
@@ -0,0 +1,203 @@
+/*
+ * Copyright 2007, Intel Corporation
+ * Copyright 2009      Johannes Berg <[email protected]>
+ *
+ * This file is part of PowerTOP
+ *
+ * This program file 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; version 2 of the License.
+ *
+ * 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 in a file named COPYING; if not, write to the
+ * Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301 USA
+ *
+ * Authors:
+ *     Arjan van de Ven <[email protected]>
+ *     Johannes Berg <[email protected]>
+ */
+
+#include <unistd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdbool.h>
+#include <string.h>
+#include <stdint.h>
+#include <sys/types.h>
+#include <dirent.h>
+#include <linux/types.h>
+#include <linux/sockios.h>
+#include <sys/ioctl.h>
+/* satisfy weird wireless.h include dependencies */
+#include <sys/socket.h>
+#include <linux/if.h>
+#include <linux/wireless.h>
+
+#include "powertop.h"
+
+static int wext_sock = -1;
+static char wireless_nic[IFNAMSIZ + 1] = {0};
+static bool ps_not_working = false;
+
+static bool check_wireless_unused(void)
+{
+       struct iwreq wrq;
+       char ssid[34] = {0}; /* wext sometimes NUL-terminates */
+
+       memset(&wrq, 0, sizeof(wrq));
+       strncpy(wrq.ifr_name, wireless_nic, sizeof(wrq.ifr_name));
+
+       /* get mode -- PS only available in STA mode */
+       if (ioctl(wext_sock, SIOCGIWMODE, &wrq) < 0)
+               return false;
+       if (wrq.u.mode != IW_MODE_INFRA)
+               return false;
+
+       wrq.u.essid.pointer = ssid;
+       wrq.u.essid.length = sizeof(ssid);
+       if (ioctl(wext_sock, SIOCGIWESSID, &wrq) < 0)
+               return false;
+
+       /* no SSID, so can't be connected */
+       if (!wrq.u.essid.flags)
+               return true;
+
+       if (ioctl(wext_sock, SIOCGIWAP, &wrq) < 0)
+               return false;
+
+       /* no AP -- not connected */
+       if (memcmp(wrq.u.ap_addr.sa_data, "\0\0\0\0\0\0", 6) == 0)
+               return true;
+
+       return false;
+}
+
+static void activate_down_suggestion(void)
+{
+       struct ifreq ifr;
+       int ret;
+
+       strncpy(ifr.ifr_name, wireless_nic, sizeof(ifr.ifr_name));
+
+       /* get flags */
+       ret = ioctl(wext_sock, SIOCGIFFLAGS, &ifr);
+       if (ret < 0)
+               return;
+       ifr.ifr_flags &= ~IFF_UP;
+
+       ioctl(wext_sock, SIOCSIFFLAGS, &ifr);
+}
+
+static int check_wireless_powersave(void)
+{
+       struct iwreq wrq;
+
+       if (ps_not_working)
+               return false;
+
+       memset(&wrq, 0, sizeof(wrq));
+       strncpy(wrq.ifr_name, wireless_nic, sizeof(wrq.ifr_name));
+
+       /* get powersave -- if supported */
+       if (ioctl(wext_sock, SIOCGIWPOWER, &wrq) < 0)
+               return false;
+
+       return wrq.u.param.disabled;
+}
+
+static void activate_wireless_suggestion(void)
+{
+       struct iwreq wrq;
+
+       memset(&wrq, 0, sizeof(wrq));
+       strncpy(wrq.ifr_name, wireless_nic, sizeof(wrq.ifr_name));
+
+       wrq.u.param.disabled = false;
+       wrq.u.param.flags = IW_POWER_ON | IW_POWER_TIMEOUT;
+       wrq.u.param.value = 500*1000; /* 500 ms */
+ again:
+       /* set powersave -- if supported */
+       if (ioctl(wext_sock, SIOCSIWPOWER, &wrq) == 0)
+               return;
+
+       /* maybe timeout is not supported? */
+       if (wrq.u.param.flags & IW_POWER_TIMEOUT) {
+               wrq.u.param.flags = IW_POWER_ON;
+               goto again;
+       }
+
+       ps_not_working = true;
+}
+
+static void find_wireless_nic(void)
+{
+       DIR *net;
+       struct dirent *ent;
+       struct ifreq ifr;
+       struct iwreq wrq;
+       int ret;
+
+       memset(&ifr, 0, sizeof(struct ifreq));
+       memset(&wrq, 0, sizeof(wrq));
+
+       net = opendir("/sys/class/net/");
+       if (!net)
+               return;
+
+       while ((ent = readdir(net))) {
+               strncpy(ifr.ifr_name, ent->d_name, sizeof(ifr.ifr_name));
+               strncpy(wrq.ifr_name, ent->d_name, sizeof(wrq.ifr_name));
+
+               /* Check if the interface is up */
+               ret = ioctl(wext_sock, SIOCGIFFLAGS, &ifr);
+               if (ret < 0)
+                       continue;
+               if (!(ifr.ifr_flags & (IFF_UP | IFF_RUNNING)))
+                       continue;
+
+               /* and a wireless interface (that we handle) */
+               ret = ioctl(wext_sock, SIOCGIWNAME, &wrq);
+               if (ret < 0)
+                       continue;
+
+               strcpy(wireless_nic, "wlan0");
+               break;
+       }
+
+       closedir(net);
+}
+
+void suggest_wifi_new_powersave(void)
+{
+       char sug[1024];
+
+       if (wext_sock == -1) {
+               wext_sock = socket(AF_INET, SOCK_DGRAM, 0);
+               if (wext_sock < 0)
+                       return;
+       }
+
+       if (strlen(wireless_nic) == 0)
+               find_wireless_nic();
+
+       if (strlen(wireless_nic) == 0)
+               return;
+
+       if (check_wireless_unused()) {
+               sprintf(sug, _("Suggestion: Disable the unused WIFI radio by 
setting the
interface down:\n "
+                              "ifconfig %s down\n"), wireless_nic);
+               add_suggestion(sug, 60, 'D', _(" D - disable wireless "),
activate_down_suggestion);
+       } else if (check_wireless_powersave()) {
+               sprintf(sug, _("Suggestion: Enable wireless power saving mode 
by executing the
following command:\n "
+                              " iwconfig %s power timeout 500ms\n"
+                              "This will sacrifice network performance 
slightly to save power."),
wireless_nic);
+               add_suggestion(sug, 20, 'P', _(" P - Enable wireless power 
saving "),
activate_wireless_suggestion);
+       }
+}
--- powertop-1.11.orig/Makefile 2009-07-27 14:18:43.000000000 +0200
+++ powertop-1.11/Makefile      2009-07-27 14:18:48.000000000 +0200
@@ -16,7 +16,7 @@ CC?=gcc
 #

 OBJS = powertop.o config.o process.o misctips.o bluetooth.o display.o
suggestions.o wireless.o cpufreq.o \
-       sata.o xrandr.o ethernet.o cpufreqstats.o usb.o urbnum.o intelcstates.o
+       sata.o xrandr.o ethernet.o cpufreqstats.o usb.o urbnum.o intelcstates.o 
wifi-new.o
        

 powertop: $(OBJS) Makefile powertop.h


_______________________________________________
Power mailing list
[email protected]
http://www.bughost.org/mailman/listinfo/power

Reply via email to