← Back to team overview

sony-vaio-z-series team mailing list archive

patch for correct rfkill support for bluetooth/wwan/wifi

 

Hi all,

today Matthew Garrett posted a patch to lkml to the in-tree sony-laptop
module that adds full rfkill support for wwan/bluetooth/wifi. So you can
turn on and off the different things to your liking.

Now with this patch (attached email) practically everything is working
BUT one thing: The turning off the nvidia card, i.e. the stamina-speed
stuff. But since that reduces the power consumption considerably I have
to use the sony-vaioZ module.

Now it would be nice to merge over *only* the stuff concerning
speed/stamina into the in-kernel driver added with the patch for rfkill
support.

Well, maybe one can take a look at it.

Best wishes

Norbert

-------------------------------------------------------------------------------
Dr. Norbert Preining <preining@xxxxxxxx>        Vienna University of Technology
Debian Developer <preining@xxxxxxxxxx>                         Debian TeX Group
gpg DSA: 0x09C5B094      fp: 14DF 2E6C 0307 BE6D AD76  A9C0 D2BF 4AA3 09C5 B094
-------------------------------------------------------------------------------
PABBY (n.,vb.)
(Fencing term.) The play, or manoeuvre, where one swordsman leaps on
to the table and pulls the battleaxe off the wall.
			--- Douglas Adams, The Meaning of Liff
--- Begin Message ---
Enable events on all Vaio's with the new-style ACPI interface, and use
it to support rfkill where available.
    
Signed-off-by: Matthew Garrett <mjg@xxxxxxxxxx>

---

Mattia, I didn't want to mess with the DMI stuff, but I suspect we can 
probably drop the setup callbacks there and just enable them on all 
hardware that supports these methods. We possibly also want to be 
calling the ECON method on the SNC since some codepaths in the tables 
seem to depend on them - but I'm also worried to a certain extent on how 
much that might change driver interactions with some machines.

diff --git a/drivers/platform/x86/sony-laptop.c b/drivers/platform/x86/sony-laptop.c
index 537959d..c57f54c 100644
--- a/drivers/platform/x86/sony-laptop.c
+++ b/drivers/platform/x86/sony-laptop.c
@@ -64,6 +64,7 @@
 #include <asm/uaccess.h>
 #include <linux/sonypi.h>
 #include <linux/sony-laptop.h>
+#include <linux/rfkill.h>
 #ifdef CONFIG_SONYPI_COMPAT
 #include <linux/poll.h>
 #include <linux/miscdevice.h>
@@ -143,6 +144,11 @@ struct sony_laptop_keypress {
 	int key;
 };
 
+static struct rfkill *sony_wifi_rfkill;
+static struct rfkill *sony_bluetooth_rfkill;
+static struct rfkill *sony_wwan_rfkill;
+static struct rfkill *sony_wimax_rfkill;
+
 /* Correspondance table between sonypi events
  * and input layer indexes in the keymap
  */
@@ -981,6 +987,145 @@ static int sony_nc_resume(struct acpi_device *device)
 	return 0;
 }
 
+static void sony_rfkill_cleanup(void)
+{
+	if (sony_wifi_rfkill)
+		rfkill_unregister(sony_wifi_rfkill);
+	if (sony_bluetooth_rfkill)
+		rfkill_unregister(sony_bluetooth_rfkill);
+	if (sony_wwan_rfkill)
+		rfkill_unregister(sony_wwan_rfkill);
+	if (sony_wimax_rfkill)
+		rfkill_unregister(sony_wimax_rfkill);
+}
+
+static int sony_nc_rfkill_get(void *data, enum rfkill_state *state)
+{
+	int result;
+
+	acpi_callsetfunc(sony_nc_acpi_handle, "SN07", 0x3 | ((long) data << 8),
+			 &result);
+	if (result & 0xf)
+		*state = RFKILL_STATE_UNBLOCKED;
+	else
+		*state = RFKILL_STATE_SOFT_BLOCKED;
+	return 0;
+}
+
+static int sony_nc_rfkill_set(void *data, enum rfkill_state state)
+{
+	int result;
+	int call = 0x3 | (((long) data + 1) << 8);
+
+	if (state == RFKILL_STATE_UNBLOCKED)
+		call |= 0xff0000;
+
+	return acpi_callsetfunc(sony_nc_acpi_handle, "SN07", call, &result);
+}
+
+static int sony_nc_setup_wifi_rfkill(struct acpi_device *device)
+{
+	int err = 0;
+
+	sony_wifi_rfkill = rfkill_allocate(&device->dev, RFKILL_TYPE_WLAN);
+	if (!sony_wifi_rfkill)
+		return -1;
+	sony_wifi_rfkill->name = "sony-wifi";
+	sony_wifi_rfkill->toggle_radio = sony_nc_rfkill_set;
+	sony_wifi_rfkill->get_state = sony_nc_rfkill_get;
+	sony_wifi_rfkill->user_claim_unsupported = 1;
+	sony_wifi_rfkill->data = (void *)3;
+	err = rfkill_register(sony_wifi_rfkill);
+	if (err)
+		rfkill_unregister(sony_wifi_rfkill);
+	return err;
+}
+
+static int sony_nc_setup_bluetooth_rfkill(struct acpi_device *device)
+{
+	int err = 0;
+
+	sony_bluetooth_rfkill = rfkill_allocate(&device->dev,
+						RFKILL_TYPE_BLUETOOTH);
+	if (!sony_bluetooth_rfkill)
+		return -1;
+	sony_bluetooth_rfkill->name = "sony-bluetooth";
+	sony_bluetooth_rfkill->toggle_radio = sony_nc_rfkill_set;
+	sony_bluetooth_rfkill->get_state = sony_nc_rfkill_get;
+	sony_bluetooth_rfkill->user_claim_unsupported = 1;
+	sony_bluetooth_rfkill->data = (void *)5;
+	err = rfkill_register(sony_bluetooth_rfkill);
+	if (err)
+		rfkill_unregister(sony_bluetooth_rfkill);
+	return err;
+}
+
+static int sony_nc_setup_wwan_rfkill(struct acpi_device *device)
+{
+	int err = 0;
+
+	sony_wwan_rfkill = rfkill_allocate(&device->dev, RFKILL_TYPE_WWAN);
+	if (!sony_wwan_rfkill)
+		return -1;
+	sony_wwan_rfkill->name = "sony-wwan";
+	sony_wwan_rfkill->toggle_radio = sony_nc_rfkill_set;
+	sony_wwan_rfkill->get_state = sony_nc_rfkill_get;
+	sony_wwan_rfkill->user_claim_unsupported = 1;
+	sony_wwan_rfkill->data = (void *)7;
+	err = rfkill_register(sony_wwan_rfkill);
+	if (err)
+		rfkill_unregister(sony_wwan_rfkill);
+	return err;
+}
+
+static int sony_nc_setup_wimax_rfkill(struct acpi_device *device)
+{
+	int err = 0;
+
+	sony_wimax_rfkill = rfkill_allocate(&device->dev, RFKILL_TYPE_WIMAX);
+	if (!sony_wimax_rfkill)
+		return -1;
+	sony_wimax_rfkill->name = "sony-wimax";
+	sony_wimax_rfkill->toggle_radio = sony_nc_rfkill_set;
+	sony_wimax_rfkill->get_state = sony_nc_rfkill_get;
+	sony_wimax_rfkill->user_claim_unsupported = 1;
+	sony_wimax_rfkill->data = (void *)9;
+	err = rfkill_register(sony_wimax_rfkill);
+	if (err)
+		rfkill_unregister(sony_wimax_rfkill);
+	return err;
+}
+
+static int sony_nc_function_setup(struct acpi_device *device)
+{
+	int result;
+
+	/* Enable all events */
+	acpi_callsetfunc(sony_nc_acpi_handle, "SN02", 0xffff, &result);
+
+	/* Setup hotkey decoding */
+	acpi_callsetfunc(sony_nc_acpi_handle, "SN07", 0x2, &result);
+
+	/* Eaable hotkey event generation */
+	acpi_callsetfunc(sony_nc_acpi_handle, "SN07", 0, &result);
+
+	/* Set BCHA, whatever /that/ does */
+	acpi_callsetfunc(sony_nc_acpi_handle, "SN07", 0x101, &result);
+
+	acpi_callsetfunc(sony_nc_acpi_handle, "SN07", 0xb03, &result);
+
+	if (result & 0x1)
+		sony_nc_setup_wifi_rfkill(device);
+	if (result & 0x2)
+		sony_nc_setup_bluetooth_rfkill(device);
+	if (result & 0x1c)
+		sony_nc_setup_wwan_rfkill(device);
+	if (result & 0x20)
+		sony_nc_setup_wimax_rfkill(device);
+
+	return 0;
+}
+
 static int sony_nc_add(struct acpi_device *device)
 {
 	acpi_status status;
@@ -1024,6 +1169,12 @@ static int sony_nc_add(struct acpi_device *device)
 			dprintk("_INI Method failed\n");
 	}
 
+	if (ACPI_SUCCESS(acpi_get_handle(sony_nc_acpi_handle, "SN07",
+					 &handle))) {
+		dprintk("Doing SNC setup\n");
+		sony_nc_function_setup(device);
+	}
+
 	/* setup input devices and helper fifo */
 	result = sony_laptop_setup_input(device);
 	if (result) {
@@ -1131,6 +1282,7 @@ static int sony_nc_add(struct acpi_device *device)
 	sony_laptop_remove_input();
 
       outwalk:
+	sony_rfkill_cleanup();
 	return result;
 }
 
@@ -1156,6 +1308,7 @@ static int sony_nc_remove(struct acpi_device *device, int type)
 
 	sony_pf_remove();
 	sony_laptop_remove_input();
+	sony_rfkill_cleanup();
 	dprintk(SONY_NC_DRIVER_NAME " removed.\n");
 
 	return 0;

-- 
Matthew Garrett | mjg59@xxxxxxxxxxxxx
--
To unsubscribe from this list: send the line "unsubscribe linux-acpi" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html

--- End Message ---