Hi, On 5/21/07, Henrique de Moraes Holschuh <[EMAIL PROTECTED]> 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 <[EMAIL PROTECTED]> --- 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@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/ibm-acpi-devel