This patch adds RFKill handler functions to the driver, allowing it to register and update the rfkill switch. Also, a comment block was moved from the header to the poll function, as it explains why we need to poll the killswitch on older devices. Signed-off-by: Azael Avalos <coproscefalo@xxxxxxxxx> --- drivers/platform/x86/toshiba_bluetooth.c | 77 ++++++++++++++++++++++++++++---- 1 file changed, 68 insertions(+), 9 deletions(-) diff --git a/drivers/platform/x86/toshiba_bluetooth.c b/drivers/platform/x86/toshiba_bluetooth.c index a619ba6..a3b2d38 100644 --- a/drivers/platform/x86/toshiba_bluetooth.c +++ b/drivers/platform/x86/toshiba_bluetooth.c @@ -10,12 +10,6 @@ * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. - * - * Note the Toshiba Bluetooth RFKill switch seems to be a strange - * fish. It only provides a BT event when the switch is flipped to - * the 'on' position. When flipping it to 'off', the USB device is - * simply pulled away underneath us, without any BT event being - * delivered. */ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt @@ -25,6 +19,7 @@ #include <linux/init.h> #include <linux/types.h> #include <linux/acpi.h> +#include <linux/rfkill.h> #define BT_KILLSWITCH_MASK 0x01 #define BT_PLUGGED_MASK 0x40 @@ -36,6 +31,7 @@ MODULE_LICENSE("GPL"); struct toshiba_bluetooth_dev { struct acpi_device *acpi_dev; + struct rfkill *rfk; bool killswitch; bool plugged; @@ -191,6 +187,49 @@ static int toshiba_bluetooth_sync_status(struct toshiba_bluetooth_dev *bt_dev) return 0; } +/* RFKill handlers */ +static int bt_rfkill_set_block(void *data, bool blocked) +{ + struct toshiba_bluetooth_dev *bt_dev = data; + int ret; + + ret = toshiba_bluetooth_sync_status(bt_dev); + if (ret) + return ret; + + if (!bt_dev->killswitch) + return 0; + + if (blocked) + ret = toshiba_bluetooth_disable(bt_dev->acpi_dev->handle); + else + ret = toshiba_bluetooth_enable(bt_dev->acpi_dev->handle); + + return ret; +} + +static void bt_rfkill_poll(struct rfkill *rfkill, void *data) +{ + struct toshiba_bluetooth_dev *bt_dev = data; + + if (toshiba_bluetooth_sync_status(bt_dev)) + return; + + /* + * Note the Toshiba Bluetooth RFKill switch seems to be a strange + * fish. It only provides a BT event when the switch is flipped to + * the 'on' position. When flipping it to 'off', the USB device is + * simply pulled away underneath us, without any BT event being + * delivered. + */ + rfkill_set_hw_state(bt_dev->rfk, !bt_dev->killswitch); +} + +static const struct rfkill_ops rfk_ops = { + .set_block = bt_rfkill_set_block, + .poll = bt_rfkill_poll, +}; + /* ACPI driver functions */ static void toshiba_bt_rfkill_notify(struct acpi_device *device, u32 event) { @@ -228,10 +267,25 @@ static int toshiba_bt_rfkill_add(struct acpi_device *device) return result; } - /* Enable the BT device */ - result = toshiba_bluetooth_enable(device->handle); - if (result) + bt_dev->rfk = rfkill_alloc("Toshiba Bluetooth", + &device->dev, + RFKILL_TYPE_BLUETOOTH, + &rfk_ops, + bt_dev); + if (!bt_dev->rfk) { + pr_err("Unable to allocate rfkill device\n"); + kfree(bt_dev); + return -ENOMEM; + } + + rfkill_set_hw_state(bt_dev->rfk, !bt_dev->killswitch); + + result = rfkill_register(bt_dev->rfk); + if (result) { + pr_err("Unable to register rfkill device\n"); + rfkill_destroy(bt_dev->rfk); kfree(bt_dev); + } return result; } @@ -241,6 +295,11 @@ static int toshiba_bt_rfkill_remove(struct acpi_device *device) struct toshiba_bluetooth_dev *bt_dev = acpi_driver_data(device); /* clean up */ + if (bt_dev->rfk) { + rfkill_unregister(bt_dev->rfk); + rfkill_destroy(bt_dev->rfk); + } + kfree(bt_dev); return toshiba_bluetooth_disable(device->handle); -- 2.3.5 -- To unsubscribe from this list: send the line "unsubscribe platform-driver-x86" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html