aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/platform
diff options
context:
space:
mode:
authorLen Brown <len.brown@intel.com>2009-12-16 13:57:16 -0500
committerLen Brown <len.brown@intel.com>2009-12-16 13:57:16 -0500
commit243e1ef842ef9e24fbf1cc7ddf4fd1c01471544a (patch)
treeaf808f66a8a8518c82c0e8189df7ac0d4252f31b /drivers/platform
parent7d8c22060555a51c23b9c6a76b97a5e75b5db882 (diff)
parent42b4e9ee3d1d3b691bcae37f217f08740320c58c (diff)
Merge branch 'toshiba-bt' into release
Diffstat (limited to 'drivers/platform')
-rw-r--r--drivers/platform/x86/Kconfig15
-rw-r--r--drivers/platform/x86/Makefile1
-rw-r--r--drivers/platform/x86/toshiba_bluetooth.c144
3 files changed, 160 insertions, 0 deletions
diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig
index ba3638fdf0ce..fc5bf9d2a3f3 100644
--- a/drivers/platform/x86/Kconfig
+++ b/drivers/platform/x86/Kconfig
@@ -449,4 +449,19 @@ config ACPI_TOSHIBA
449 449
450 If you have a legacy free Toshiba laptop (such as the Libretto L1 450 If you have a legacy free Toshiba laptop (such as the Libretto L1
451 series), say Y. 451 series), say Y.
452
453config TOSHIBA_BT_RFKILL
454 tristate "Toshiba Bluetooth RFKill switch support"
455 depends on ACPI
456 ---help---
457 This driver adds support for Bluetooth events for the RFKill
458 switch on modern Toshiba laptops with full ACPI support and
459 an RFKill switch.
460
461 This driver handles RFKill events for the TOS6205 Bluetooth,
462 and re-enables it when the switch is set back to the 'on'
463 position.
464
465 If you have a modern Toshiba laptop with a Bluetooth and an
466 RFKill switch (such as the Portege R500), say Y.
452endif # X86_PLATFORM_DEVICES 467endif # X86_PLATFORM_DEVICES
diff --git a/drivers/platform/x86/Makefile b/drivers/platform/x86/Makefile
index 13aa37310f33..b7474b6a8bf1 100644
--- a/drivers/platform/x86/Makefile
+++ b/drivers/platform/x86/Makefile
@@ -22,3 +22,4 @@ obj-$(CONFIG_MSI_WMI) += msi-wmi.o
22obj-$(CONFIG_ACPI_ASUS) += asus_acpi.o 22obj-$(CONFIG_ACPI_ASUS) += asus_acpi.o
23obj-$(CONFIG_TOPSTAR_LAPTOP) += topstar-laptop.o 23obj-$(CONFIG_TOPSTAR_LAPTOP) += topstar-laptop.o
24obj-$(CONFIG_ACPI_TOSHIBA) += toshiba_acpi.o 24obj-$(CONFIG_ACPI_TOSHIBA) += toshiba_acpi.o
25obj-$(CONFIG_TOSHIBA_BT_RFKILL) += toshiba_bluetooth.o
diff --git a/drivers/platform/x86/toshiba_bluetooth.c b/drivers/platform/x86/toshiba_bluetooth.c
new file mode 100644
index 000000000000..a350418e87ea
--- /dev/null
+++ b/drivers/platform/x86/toshiba_bluetooth.c
@@ -0,0 +1,144 @@
1/*
2 * Toshiba Bluetooth Enable Driver
3 *
4 * Copyright (C) 2009 Jes Sorensen <Jes.Sorensen@gmail.com>
5 *
6 * Thanks to Matthew Garrett for background info on ACPI innards which
7 * normal people aren't meant to understand :-)
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License version 2 as
11 * published by the Free Software Foundation.
12 *
13 * Note the Toshiba Bluetooth RFKill switch seems to be a strange
14 * fish. It only provides a BT event when the switch is flipped to
15 * the 'on' position. When flipping it to 'off', the USB device is
16 * simply pulled away underneath us, without any BT event being
17 * delivered.
18 */
19
20#include <linux/kernel.h>
21#include <linux/module.h>
22#include <linux/init.h>
23#include <linux/types.h>
24#include <acpi/acpi_bus.h>
25#include <acpi/acpi_drivers.h>
26
27MODULE_AUTHOR("Jes Sorensen <Jes.Sorensen@gmail.com>");
28MODULE_DESCRIPTION("Toshiba Laptop ACPI Bluetooth Enable Driver");
29MODULE_LICENSE("GPL");
30
31
32static int toshiba_bt_rfkill_add(struct acpi_device *device);
33static int toshiba_bt_rfkill_remove(struct acpi_device *device, int type);
34static void toshiba_bt_rfkill_notify(struct acpi_device *device, u32 event);
35static int toshiba_bt_resume(struct acpi_device *device);
36
37static const struct acpi_device_id bt_device_ids[] = {
38 { "TOS6205", 0},
39 { "", 0},
40};
41MODULE_DEVICE_TABLE(acpi, bt_device_ids);
42
43static struct acpi_driver toshiba_bt_rfkill_driver = {
44 .name = "Toshiba BT",
45 .class = "Toshiba",
46 .ids = bt_device_ids,
47 .ops = {
48 .add = toshiba_bt_rfkill_add,
49 .remove = toshiba_bt_rfkill_remove,
50 .notify = toshiba_bt_rfkill_notify,
51 .resume = toshiba_bt_resume,
52 },
53 .owner = THIS_MODULE,
54};
55
56
57static int toshiba_bluetooth_enable(acpi_handle handle)
58{
59 acpi_status res1, res2;
60 acpi_integer result;
61
62 /*
63 * Query ACPI to verify RFKill switch is set to 'on'.
64 * If not, we return silently, no need to report it as
65 * an error.
66 */
67 res1 = acpi_evaluate_integer(handle, "BTST", NULL, &result);
68 if (ACPI_FAILURE(res1))
69 return res1;
70 if (!(result & 0x01))
71 return 0;
72
73 printk(KERN_INFO "toshiba_bluetooth: Re-enabling Toshiba Bluetooth\n");
74 res1 = acpi_evaluate_object(handle, "AUSB", NULL, NULL);
75 res2 = acpi_evaluate_object(handle, "BTPO", NULL, NULL);
76 if (!ACPI_FAILURE(res1) || !ACPI_FAILURE(res2))
77 return 0;
78
79 printk(KERN_WARNING "toshiba_bluetooth: Failed to re-enable "
80 "Toshiba Bluetooth\n");
81
82 return -ENODEV;
83}
84
85static void toshiba_bt_rfkill_notify(struct acpi_device *device, u32 event)
86{
87 toshiba_bluetooth_enable(device->handle);
88}
89
90static int toshiba_bt_resume(struct acpi_device *device)
91{
92 return toshiba_bluetooth_enable(device->handle);
93}
94
95static int toshiba_bt_rfkill_add(struct acpi_device *device)
96{
97 acpi_status status;
98 acpi_integer bt_present;
99 int result = -ENODEV;
100
101 /*
102 * Some Toshiba laptops may have a fake TOS6205 device in
103 * their ACPI BIOS, so query the _STA method to see if there
104 * is really anything there, before trying to enable it.
105 */
106 status = acpi_evaluate_integer(device->handle, "_STA", NULL,
107 &bt_present);
108
109 if (!ACPI_FAILURE(status) && bt_present) {
110 printk(KERN_INFO "Detected Toshiba ACPI Bluetooth device - "
111 "installing RFKill handler\n");
112 result = toshiba_bluetooth_enable(device->handle);
113 }
114
115 return result;
116}
117
118static int __init toshiba_bt_rfkill_init(void)
119{
120 int result;
121
122 result = acpi_bus_register_driver(&toshiba_bt_rfkill_driver);
123 if (result < 0) {
124 ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
125 "Error registering driver\n"));
126 return result;
127 }
128
129 return 0;
130}
131
132static int toshiba_bt_rfkill_remove(struct acpi_device *device, int type)
133{
134 /* clean up */
135 return 0;
136}
137
138static void __exit toshiba_bt_rfkill_exit(void)
139{
140 acpi_bus_unregister_driver(&toshiba_bt_rfkill_driver);
141}
142
143module_init(toshiba_bt_rfkill_init);
144module_exit(toshiba_bt_rfkill_exit);