Hi,
On 5/21/07, Henrique de Moraes Holschuh <hmh@xxxxxxxxxx> wrote:
On Mon, 21 May 2007, Richard Hughes wrote:
> Has there been any work on implementing rfkill for thinkpad_acpi? If
> there is nobody working on this I am offering to add support into
> thinkpad_acpi this week.
Yes, I have been talking to the rfkill people, but we had some disagreements
on how to best to it. I let it rest for a week or so to think better about
some issues they raised, and also in order not to waste too much bandwidth
from either side of the issue.
Basically, I want a "fetch data from the hardware to know what state it is
in for real" interface. They want a "find a way to make sure the hardware
is doing what we told it to do" interface.
I might even find out that we are better off not using rfkill in
thinkpad-acpi itself, and letting the bluetooth and wwan drivers process it.
We shall see. The thinkpad ACPI interface does a lot more than just
radio-kill, it actually kills power to the *devices* themselves, AFAIK
(removes them from the USB bus, causing hotunplug events). Anyone with a
bluetooth and WWAN device, please speak up.
So far, what I got is that rfkill is all about handling "please disable
radios" system-wide events, and not about providing drivers with a standard
sysfs interface to enable/disable radio functionality. At least for now.
RFkill is not only about "please disable radios", it _does_ provide
the standard sysfs interface to control the radios as well.
You know I got curious and looked at thinkpad_acpi driver and adding
rfkill support for bluetooth to it turned out to be pretty easy. What
was missing is export on rfkill_toggle_radio to accomodate needs of
thinkpad_acpi legacy sysfs and procfs interfaces otherwise the patch
is really tiny.
Sorry for attachment.
--
Dmitry
Signed-off-by: Dmitry Torokhov <dtor@xxxxxxx>
---
drivers/misc/thinkpad_acpi.c | 143 +++++++++++++++++++++++++++++++------------
drivers/misc/thinkpad_acpi.h | 1
include/linux/rfkill.h | 1
net/rfkill/rfkill.c | 16 +++-
4 files changed, 121 insertions(+), 40 deletions(-)
Index: linux/drivers/misc/thinkpad_acpi.c
===================================================================
--- linux.orig/drivers/misc/thinkpad_acpi.c
+++ linux/drivers/misc/thinkpad_acpi.c
@@ -1020,6 +1020,97 @@ static struct ibm_struct hotkey_driver_d
* Bluetooth subdriver
*/
+struct rfkill *bluetooth_rfkill;
+static enum rfkill_state bluetooth_state;
+
+static int bluetooth_get_radiosw(void)
+{
+ int status;
+
+ if (!tp_features.bluetooth)
+ return -ENODEV;
+
+ if (!acpi_evalf(hkey_handle, &status, "GBDC", "d"))
+ return -EIO;
+
+ return ((status & TP_ACPI_BLUETOOTH_RADIOSSW) != 0);
+}
+
+static int bluetooth_set_radiosw(int radio_on)
+{
+ int status;
+
+ if (!tp_features.bluetooth)
+ return -ENODEV;
+
+ if (!acpi_evalf(hkey_handle, &status, "GBDC", "d"))
+ return -EIO;
+ if (radio_on)
+ status |= TP_ACPI_BLUETOOTH_RADIOSSW;
+ else
+ status &= ~TP_ACPI_BLUETOOTH_RADIOSSW;
+ if (!acpi_evalf(hkey_handle, NULL, "SBDC", "vd", status))
+ return -EIO;
+
+ return 0;
+}
+
+static int bluetooth_toggle_radio(void *data, enum rfkill_state state)
+{
+ int error;
+
+ if (bluetooth_state != state) {
+ error = bluetooth_set_radiosw(state == RFKILL_STATE_ON ? 1 : 0);
+ if (error)
+ return error;
+
+ bluetooth_state = state;
+ }
+
+ return 0;
+}
+
+static int bluetooth_register_rfkill(void)
+{
+ int retval;
+
+ bluetooth_rfkill = rfkill_allocate(&tpacpi_pdev->dev,
+ RFKILL_TYPE_BLUETOOTH);
+ if (!bluetooth_rfkill) {
+ printk(IBM_ERR "not enough memory for bluetooth RF switch\n");
+ return -ENOMEM;
+ }
+
+ retval = bluetooth_get_radiosw();
+ if (retval < 0) {
+ printk(IBM_ERR "failed to get bluettoth radio state, "
+ "asuming ON\n");
+ retval = 0;
+ }
+ bluetooth_state = retval ? RFKILL_STATE_ON : RFKILL_STATE_OFF;
+
+ bluetooth_rfkill->toggle_radio = bluetooth_toggle_radio;
+
+ retval = rfkill_register(bluetooth_rfkill);
+ if (retval) {
+ printk(IBM_ERR "failed to register bluetooth RF switch, "
+ "error %d\n", retval);
+ rfkill_free(bluetooth_rfkill);
+ return retval;
+ }
+
+ return 0;
+}
+
+static void bluetooth_unregister_rfkill(void)
+{
+ if (bluetooth_rfkill) {
+ rfkill_unregister(bluetooth_rfkill);
+ rfkill_free(bluetooth_rfkill);
+ bluetooth_rfkill = NULL;
+ }
+}
+
/* sysfs bluetooth enable ---------------------------------------------- */
static ssize_t bluetooth_enable_show(struct device *dev,
struct device_attribute *attr,
@@ -1044,7 +1135,8 @@ static ssize_t bluetooth_enable_store(st
if (parse_strtoul(buf, 1, &t))
return -EINVAL;
- res = bluetooth_set_radiosw(t);
+ res = rfkill_toggle_radio(bluetooth_rfkill,
+ t ? RFKILL_STATE_ON : RFKILL_STATE_OFF);
return (res) ? res : count;
}
@@ -1090,10 +1182,16 @@ static int __init bluetooth_init(struct
dbg_printk(TPACPI_DBG_INIT,
"bluetooth hardware not installed\n");
} else {
+ res = bluetooth_register_rfkill();
+ if (res)
+ return res;
+
res = sysfs_create_group(&tpacpi_pdev->dev.kobj,
&bluetooth_attr_group);
- if (res)
+ if (res) {
+ bluetooth_unregister_rfkill();
return res;
+ }
}
}
@@ -1103,39 +1201,8 @@ static int __init bluetooth_init(struct
static void bluetooth_exit(void)
{
sysfs_remove_group(&tpacpi_pdev->dev.kobj,
- &bluetooth_attr_group);
-}
-
-static int bluetooth_get_radiosw(void)
-{
- int status;
-
- if (!tp_features.bluetooth)
- return -ENODEV;
-
- if (!acpi_evalf(hkey_handle, &status, "GBDC", "d"))
- return -EIO;
-
- return ((status & TP_ACPI_BLUETOOTH_RADIOSSW) != 0);
-}
-
-static int bluetooth_set_radiosw(int radio_on)
-{
- int status;
-
- if (!tp_features.bluetooth)
- return -ENODEV;
-
- if (!acpi_evalf(hkey_handle, &status, "GBDC", "d"))
- return -EIO;
- if (radio_on)
- status |= TP_ACPI_BLUETOOTH_RADIOSSW;
- else
- status &= ~TP_ACPI_BLUETOOTH_RADIOSSW;
- if (!acpi_evalf(hkey_handle, NULL, "SBDC", "vd", status))
- return -EIO;
-
- return 0;
+ &bluetooth_attr_group);
+ bluetooth_unregister_rfkill();
}
/* procfs -------------------------------------------------------------- */
@@ -1164,9 +1231,11 @@ static int bluetooth_write(char *buf)
while ((cmd = next_cmd(&buf))) {
if (strlencmp(cmd, "enable") == 0) {
- bluetooth_set_radiosw(1);
+ rfkill_toggle_radio(bluetooth_rfkill,
+ RFKILL_STATE_ON);
} else if (strlencmp(cmd, "disable") == 0) {
- bluetooth_set_radiosw(0);
+ rfkill_toggle_radio(bluetooth_rfkill,
+ RFKILL_STATE_OFF);
} else
return -EINVAL;
}
Index: linux/drivers/misc/thinkpad_acpi.h
===================================================================
--- linux.orig/drivers/misc/thinkpad_acpi.h
+++ linux/drivers/misc/thinkpad_acpi.h
@@ -39,6 +39,7 @@
#include <linux/platform_device.h>
#include <linux/hwmon.h>
#include <linux/hwmon-sysfs.h>
+#include <linux/rfkill.h>
#include <asm/uaccess.h>
#include <linux/dmi.h>
Index: linux/include/linux/rfkill.h
===================================================================
--- linux.orig/include/linux/rfkill.h
+++ linux/include/linux/rfkill.h
@@ -84,6 +84,7 @@ void rfkill_free(struct rfkill *rfkill);
int rfkill_register(struct rfkill *rfkill);
void rfkill_unregister(struct rfkill *rfkill);
+int rfkill_toggle_radio(struct rfkill *rfkill, enum rfkill_state state);
void rfkill_switch_all(enum rfkill_type type, enum rfkill_state state);
#endif /* RFKILL_H */
Index: linux/net/rfkill/rfkill.c
===================================================================
--- linux.orig/net/rfkill/rfkill.c
+++ linux/net/rfkill/rfkill.c
@@ -37,8 +37,17 @@ static DEFINE_MUTEX(rfkill_mutex);
static enum rfkill_state rfkill_states[RFKILL_TYPE_MAX];
-static int rfkill_toggle_radio(struct rfkill *rfkill,
- enum rfkill_state state)
+/**
+ * rfkill_toggle_radio - change state of a particluar RF switch
+ * @rfkill: switchi to be toggled
+ * @state: new state
+ *
+ * This function changes state of one RF switch in the system. Please
+ * note that this functio is exported for benefit of legacy interfaces,
+ * new drivers should rely on RFkills standard sysfs attributes to
+ * control their raqdio state.
+ */
+int rfkill_toggle_radio(struct rfkill *rfkill, enum rfkill_state state)
{
int retval;
@@ -55,6 +64,7 @@ static int rfkill_toggle_radio(struct rf
mutex_unlock(&rfkill->mutex);
return retval;
}
+EXPORT_SYMBOL(rfkill_toggle_radio);
/**
* rfkill_switch_all - Toggle state of all switches of given type
@@ -296,7 +306,7 @@ struct rfkill *rfkill_allocate(struct de
struct device *dev;
rfkill = kzalloc(sizeof(struct rfkill), GFP_KERNEL);
- if (rfkill)
+ if (!rfkill)
return NULL;
mutex_init(&rfkill->mutex);
-------------------------------------------------------------------------
This SF.net email is sponsored by DB2 Express
Download DB2 Express C - the FREE version of DB2 express and take
control of your XML. No limits. Just data. Click to get it now.
http://sourceforge.net/powerbar/db2/
_______________________________________________
ibm-acpi-devel mailing list
ibm-acpi-devel@xxxxxxxxxxxxxxxxxxxxx
https://lists.sourceforge.net/lists/listinfo/ibm-acpi-devel