diff options
author | Azael Avalos <coproscefalo@gmail.com> | 2015-05-03 19:42:07 -0400 |
---|---|---|
committer | Darren Hart <dvhart@linux.intel.com> | 2015-05-06 18:12:39 -0400 |
commit | 7ee8cd3319d5e57b1b5e2b348f078af44e67a577 (patch) | |
tree | ac2a3071bff2516502cc829e8cc1ff7316309251 | |
parent | 84c0691e514539900d0f90b1e4442ce49664da5a (diff) |
toshiba_bluetooth: Add RFKill handler functions
This patch adds RFKill handler functions to the driver, allowing it
to register and update the rfkill switch status.
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@gmail.com>
Signed-off-by: Darren Hart <dvhart@linux.intel.com>
-rw-r--r-- | drivers/platform/x86/Kconfig | 1 | ||||
-rw-r--r-- | drivers/platform/x86/toshiba_bluetooth.c | 77 |
2 files changed, 69 insertions, 9 deletions
diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig index 822171cb50d5..399085d79015 100644 --- a/drivers/platform/x86/Kconfig +++ b/drivers/platform/x86/Kconfig | |||
@@ -642,6 +642,7 @@ config ACPI_TOSHIBA | |||
642 | config TOSHIBA_BT_RFKILL | 642 | config TOSHIBA_BT_RFKILL |
643 | tristate "Toshiba Bluetooth RFKill switch support" | 643 | tristate "Toshiba Bluetooth RFKill switch support" |
644 | depends on ACPI | 644 | depends on ACPI |
645 | depends on RFKILL || RFKILL = n | ||
645 | ---help--- | 646 | ---help--- |
646 | This driver adds support for Bluetooth events for the RFKill | 647 | This driver adds support for Bluetooth events for the RFKill |
647 | switch on modern Toshiba laptops with full ACPI support and | 648 | switch on modern Toshiba laptops with full ACPI support and |
diff --git a/drivers/platform/x86/toshiba_bluetooth.c b/drivers/platform/x86/toshiba_bluetooth.c index a619ba67b9d4..a3b2d3883dd6 100644 --- a/drivers/platform/x86/toshiba_bluetooth.c +++ b/drivers/platform/x86/toshiba_bluetooth.c | |||
@@ -10,12 +10,6 @@ | |||
10 | * This program is free software; you can redistribute it and/or modify | 10 | * This program is free software; you can redistribute it and/or modify |
11 | * it under the terms of the GNU General Public License version 2 as | 11 | * it under the terms of the GNU General Public License version 2 as |
12 | * published by the Free Software Foundation. | 12 | * published by the Free Software Foundation. |
13 | * | ||
14 | * Note the Toshiba Bluetooth RFKill switch seems to be a strange | ||
15 | * fish. It only provides a BT event when the switch is flipped to | ||
16 | * the 'on' position. When flipping it to 'off', the USB device is | ||
17 | * simply pulled away underneath us, without any BT event being | ||
18 | * delivered. | ||
19 | */ | 13 | */ |
20 | 14 | ||
21 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt | 15 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt |
@@ -25,6 +19,7 @@ | |||
25 | #include <linux/init.h> | 19 | #include <linux/init.h> |
26 | #include <linux/types.h> | 20 | #include <linux/types.h> |
27 | #include <linux/acpi.h> | 21 | #include <linux/acpi.h> |
22 | #include <linux/rfkill.h> | ||
28 | 23 | ||
29 | #define BT_KILLSWITCH_MASK 0x01 | 24 | #define BT_KILLSWITCH_MASK 0x01 |
30 | #define BT_PLUGGED_MASK 0x40 | 25 | #define BT_PLUGGED_MASK 0x40 |
@@ -36,6 +31,7 @@ MODULE_LICENSE("GPL"); | |||
36 | 31 | ||
37 | struct toshiba_bluetooth_dev { | 32 | struct toshiba_bluetooth_dev { |
38 | struct acpi_device *acpi_dev; | 33 | struct acpi_device *acpi_dev; |
34 | struct rfkill *rfk; | ||
39 | 35 | ||
40 | bool killswitch; | 36 | bool killswitch; |
41 | bool plugged; | 37 | bool plugged; |
@@ -191,6 +187,49 @@ static int toshiba_bluetooth_sync_status(struct toshiba_bluetooth_dev *bt_dev) | |||
191 | return 0; | 187 | return 0; |
192 | } | 188 | } |
193 | 189 | ||
190 | /* RFKill handlers */ | ||
191 | static int bt_rfkill_set_block(void *data, bool blocked) | ||
192 | { | ||
193 | struct toshiba_bluetooth_dev *bt_dev = data; | ||
194 | int ret; | ||
195 | |||
196 | ret = toshiba_bluetooth_sync_status(bt_dev); | ||
197 | if (ret) | ||
198 | return ret; | ||
199 | |||
200 | if (!bt_dev->killswitch) | ||
201 | return 0; | ||
202 | |||
203 | if (blocked) | ||
204 | ret = toshiba_bluetooth_disable(bt_dev->acpi_dev->handle); | ||
205 | else | ||
206 | ret = toshiba_bluetooth_enable(bt_dev->acpi_dev->handle); | ||
207 | |||
208 | return ret; | ||
209 | } | ||
210 | |||
211 | static void bt_rfkill_poll(struct rfkill *rfkill, void *data) | ||
212 | { | ||
213 | struct toshiba_bluetooth_dev *bt_dev = data; | ||
214 | |||
215 | if (toshiba_bluetooth_sync_status(bt_dev)) | ||
216 | return; | ||
217 | |||
218 | /* | ||
219 | * Note the Toshiba Bluetooth RFKill switch seems to be a strange | ||
220 | * fish. It only provides a BT event when the switch is flipped to | ||
221 | * the 'on' position. When flipping it to 'off', the USB device is | ||
222 | * simply pulled away underneath us, without any BT event being | ||
223 | * delivered. | ||
224 | */ | ||
225 | rfkill_set_hw_state(bt_dev->rfk, !bt_dev->killswitch); | ||
226 | } | ||
227 | |||
228 | static const struct rfkill_ops rfk_ops = { | ||
229 | .set_block = bt_rfkill_set_block, | ||
230 | .poll = bt_rfkill_poll, | ||
231 | }; | ||
232 | |||
194 | /* ACPI driver functions */ | 233 | /* ACPI driver functions */ |
195 | static void toshiba_bt_rfkill_notify(struct acpi_device *device, u32 event) | 234 | static void toshiba_bt_rfkill_notify(struct acpi_device *device, u32 event) |
196 | { | 235 | { |
@@ -228,10 +267,25 @@ static int toshiba_bt_rfkill_add(struct acpi_device *device) | |||
228 | return result; | 267 | return result; |
229 | } | 268 | } |
230 | 269 | ||
231 | /* Enable the BT device */ | 270 | bt_dev->rfk = rfkill_alloc("Toshiba Bluetooth", |
232 | result = toshiba_bluetooth_enable(device->handle); | 271 | &device->dev, |
233 | if (result) | 272 | RFKILL_TYPE_BLUETOOTH, |
273 | &rfk_ops, | ||
274 | bt_dev); | ||
275 | if (!bt_dev->rfk) { | ||
276 | pr_err("Unable to allocate rfkill device\n"); | ||
277 | kfree(bt_dev); | ||
278 | return -ENOMEM; | ||
279 | } | ||
280 | |||
281 | rfkill_set_hw_state(bt_dev->rfk, !bt_dev->killswitch); | ||
282 | |||
283 | result = rfkill_register(bt_dev->rfk); | ||
284 | if (result) { | ||
285 | pr_err("Unable to register rfkill device\n"); | ||
286 | rfkill_destroy(bt_dev->rfk); | ||
234 | kfree(bt_dev); | 287 | kfree(bt_dev); |
288 | } | ||
235 | 289 | ||
236 | return result; | 290 | return result; |
237 | } | 291 | } |
@@ -241,6 +295,11 @@ static int toshiba_bt_rfkill_remove(struct acpi_device *device) | |||
241 | struct toshiba_bluetooth_dev *bt_dev = acpi_driver_data(device); | 295 | struct toshiba_bluetooth_dev *bt_dev = acpi_driver_data(device); |
242 | 296 | ||
243 | /* clean up */ | 297 | /* clean up */ |
298 | if (bt_dev->rfk) { | ||
299 | rfkill_unregister(bt_dev->rfk); | ||
300 | rfkill_destroy(bt_dev->rfk); | ||
301 | } | ||
302 | |||
244 | kfree(bt_dev); | 303 | kfree(bt_dev); |
245 | 304 | ||
246 | return toshiba_bluetooth_disable(device->handle); | 305 | return toshiba_bluetooth_disable(device->handle); |