Version:  2.0.40 2.2.26 2.4.37 3.10 3.11 3.12 3.13 3.14 3.15 3.16 3.17 3.18 3.19 4.0 4.1 4.2 4.3 4.4 4.5 4.6 4.7

Linux/drivers/platform/x86/toshiba_bluetooth.c

  1 /*
  2  * Toshiba Bluetooth Enable Driver
  3  *
  4  * Copyright (C) 2009 Jes Sorensen <Jes.Sorensen@gmail.com>
  5  * Copyright (C) 2015 Azael Avalos <coproscefalo@gmail.com>
  6  *
  7  * Thanks to Matthew Garrett for background info on ACPI innards which
  8  * normal people aren't meant to understand :-)
  9  *
 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
 12  * published by the Free Software Foundation.
 13  */
 14 
 15 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
 16 
 17 #include <linux/kernel.h>
 18 #include <linux/module.h>
 19 #include <linux/init.h>
 20 #include <linux/types.h>
 21 #include <linux/acpi.h>
 22 #include <linux/rfkill.h>
 23 
 24 #define BT_KILLSWITCH_MASK      0x01
 25 #define BT_PLUGGED_MASK         0x40
 26 #define BT_POWER_MASK           0x80
 27 
 28 MODULE_AUTHOR("Jes Sorensen <Jes.Sorensen@gmail.com>");
 29 MODULE_DESCRIPTION("Toshiba Laptop ACPI Bluetooth Enable Driver");
 30 MODULE_LICENSE("GPL");
 31 
 32 struct toshiba_bluetooth_dev {
 33         struct acpi_device *acpi_dev;
 34         struct rfkill *rfk;
 35 
 36         bool killswitch;
 37         bool plugged;
 38         bool powered;
 39 };
 40 
 41 static int toshiba_bt_rfkill_add(struct acpi_device *device);
 42 static int toshiba_bt_rfkill_remove(struct acpi_device *device);
 43 static void toshiba_bt_rfkill_notify(struct acpi_device *device, u32 event);
 44 
 45 static const struct acpi_device_id bt_device_ids[] = {
 46         { "TOS6205", 0},
 47         { "", 0},
 48 };
 49 MODULE_DEVICE_TABLE(acpi, bt_device_ids);
 50 
 51 #ifdef CONFIG_PM_SLEEP
 52 static int toshiba_bt_resume(struct device *dev);
 53 #endif
 54 static SIMPLE_DEV_PM_OPS(toshiba_bt_pm, NULL, toshiba_bt_resume);
 55 
 56 static struct acpi_driver toshiba_bt_rfkill_driver = {
 57         .name =         "Toshiba BT",
 58         .class =        "Toshiba",
 59         .ids =          bt_device_ids,
 60         .ops =          {
 61                                 .add =          toshiba_bt_rfkill_add,
 62                                 .remove =       toshiba_bt_rfkill_remove,
 63                                 .notify =       toshiba_bt_rfkill_notify,
 64                         },
 65         .owner =        THIS_MODULE,
 66         .drv.pm =       &toshiba_bt_pm,
 67 };
 68 
 69 static int toshiba_bluetooth_present(acpi_handle handle)
 70 {
 71         acpi_status result;
 72         u64 bt_present;
 73 
 74         /*
 75          * Some Toshiba laptops may have a fake TOS6205 device in
 76          * their ACPI BIOS, so query the _STA method to see if there
 77          * is really anything there.
 78          */
 79         result = acpi_evaluate_integer(handle, "_STA", NULL, &bt_present);
 80         if (ACPI_FAILURE(result)) {
 81                 pr_err("ACPI call to query Bluetooth presence failed\n");
 82                 return -ENXIO;
 83         } else if (!bt_present) {
 84                 pr_info("Bluetooth device not present\n");
 85                 return -ENODEV;
 86         }
 87 
 88         return 0;
 89 }
 90 
 91 static int toshiba_bluetooth_status(acpi_handle handle)
 92 {
 93         acpi_status result;
 94         u64 status;
 95 
 96         result = acpi_evaluate_integer(handle, "BTST", NULL, &status);
 97         if (ACPI_FAILURE(result)) {
 98                 pr_err("Could not get Bluetooth device status\n");
 99                 return -ENXIO;
100         }
101 
102         return status;
103 }
104 
105 static int toshiba_bluetooth_enable(acpi_handle handle)
106 {
107         acpi_status result;
108 
109         result = acpi_evaluate_object(handle, "AUSB", NULL, NULL);
110         if (ACPI_FAILURE(result)) {
111                 pr_err("Could not attach USB Bluetooth device\n");
112                 return -ENXIO;
113         }
114 
115         result = acpi_evaluate_object(handle, "BTPO", NULL, NULL);
116         if (ACPI_FAILURE(result)) {
117                 pr_err("Could not power ON Bluetooth device\n");
118                 return -ENXIO;
119         }
120 
121         return 0;
122 }
123 
124 static int toshiba_bluetooth_disable(acpi_handle handle)
125 {
126         acpi_status result;
127 
128         result = acpi_evaluate_object(handle, "BTPF", NULL, NULL);
129         if (ACPI_FAILURE(result)) {
130                 pr_err("Could not power OFF Bluetooth device\n");
131                 return -ENXIO;
132         }
133 
134         result = acpi_evaluate_object(handle, "DUSB", NULL, NULL);
135         if (ACPI_FAILURE(result)) {
136                 pr_err("Could not detach USB Bluetooth device\n");
137                 return -ENXIO;
138         }
139 
140         return 0;
141 }
142 
143 /* Helper function */
144 static int toshiba_bluetooth_sync_status(struct toshiba_bluetooth_dev *bt_dev)
145 {
146         int status;
147 
148         status = toshiba_bluetooth_status(bt_dev->acpi_dev->handle);
149         if (status < 0) {
150                 pr_err("Could not sync bluetooth device status\n");
151                 return status;
152         }
153 
154         bt_dev->killswitch = (status & BT_KILLSWITCH_MASK) ? true : false;
155         bt_dev->plugged = (status & BT_PLUGGED_MASK) ? true : false;
156         bt_dev->powered = (status & BT_POWER_MASK) ? true : false;
157 
158         pr_debug("Bluetooth status %d killswitch %d plugged %d powered %d\n",
159                  status, bt_dev->killswitch, bt_dev->plugged, bt_dev->powered);
160 
161         return 0;
162 }
163 
164 /* RFKill handlers */
165 static int bt_rfkill_set_block(void *data, bool blocked)
166 {
167         struct toshiba_bluetooth_dev *bt_dev = data;
168         int ret;
169 
170         ret = toshiba_bluetooth_sync_status(bt_dev);
171         if (ret)
172                 return ret;
173 
174         if (!bt_dev->killswitch)
175                 return 0;
176 
177         if (blocked)
178                 ret = toshiba_bluetooth_disable(bt_dev->acpi_dev->handle);
179         else
180                 ret = toshiba_bluetooth_enable(bt_dev->acpi_dev->handle);
181 
182         return ret;
183 }
184 
185 static void bt_rfkill_poll(struct rfkill *rfkill, void *data)
186 {
187         struct toshiba_bluetooth_dev *bt_dev = data;
188 
189         if (toshiba_bluetooth_sync_status(bt_dev))
190                 return;
191 
192         /*
193          * Note the Toshiba Bluetooth RFKill switch seems to be a strange
194          * fish. It only provides a BT event when the switch is flipped to
195          * the 'on' position. When flipping it to 'off', the USB device is
196          * simply pulled away underneath us, without any BT event being
197          * delivered.
198          */
199         rfkill_set_hw_state(bt_dev->rfk, !bt_dev->killswitch);
200 }
201 
202 static const struct rfkill_ops rfk_ops = {
203         .set_block = bt_rfkill_set_block,
204         .poll = bt_rfkill_poll,
205 };
206 
207 /* ACPI driver functions */
208 static void toshiba_bt_rfkill_notify(struct acpi_device *device, u32 event)
209 {
210         struct toshiba_bluetooth_dev *bt_dev = acpi_driver_data(device);
211 
212         if (toshiba_bluetooth_sync_status(bt_dev))
213                 return;
214 
215         rfkill_set_hw_state(bt_dev->rfk, !bt_dev->killswitch);
216 }
217 
218 #ifdef CONFIG_PM_SLEEP
219 static int toshiba_bt_resume(struct device *dev)
220 {
221         struct toshiba_bluetooth_dev *bt_dev;
222         int ret;
223 
224         bt_dev = acpi_driver_data(to_acpi_device(dev));
225 
226         ret = toshiba_bluetooth_sync_status(bt_dev);
227         if (ret)
228                 return ret;
229 
230         rfkill_set_hw_state(bt_dev->rfk, !bt_dev->killswitch);
231 
232         return 0;
233 }
234 #endif
235 
236 static int toshiba_bt_rfkill_add(struct acpi_device *device)
237 {
238         struct toshiba_bluetooth_dev *bt_dev;
239         int result;
240 
241         result = toshiba_bluetooth_present(device->handle);
242         if (result)
243                 return result;
244 
245         pr_info("Toshiba ACPI Bluetooth device driver\n");
246 
247         bt_dev = kzalloc(sizeof(*bt_dev), GFP_KERNEL);
248         if (!bt_dev)
249                 return -ENOMEM;
250         bt_dev->acpi_dev = device;
251         device->driver_data = bt_dev;
252         dev_set_drvdata(&device->dev, bt_dev);
253 
254         result = toshiba_bluetooth_sync_status(bt_dev);
255         if (result) {
256                 kfree(bt_dev);
257                 return result;
258         }
259 
260         bt_dev->rfk = rfkill_alloc("Toshiba Bluetooth",
261                                    &device->dev,
262                                    RFKILL_TYPE_BLUETOOTH,
263                                    &rfk_ops,
264                                    bt_dev);
265         if (!bt_dev->rfk) {
266                 pr_err("Unable to allocate rfkill device\n");
267                 kfree(bt_dev);
268                 return -ENOMEM;
269         }
270 
271         rfkill_set_hw_state(bt_dev->rfk, !bt_dev->killswitch);
272 
273         result = rfkill_register(bt_dev->rfk);
274         if (result) {
275                 pr_err("Unable to register rfkill device\n");
276                 rfkill_destroy(bt_dev->rfk);
277                 kfree(bt_dev);
278         }
279 
280         return result;
281 }
282 
283 static int toshiba_bt_rfkill_remove(struct acpi_device *device)
284 {
285         struct toshiba_bluetooth_dev *bt_dev = acpi_driver_data(device);
286 
287         /* clean up */
288         if (bt_dev->rfk) {
289                 rfkill_unregister(bt_dev->rfk);
290                 rfkill_destroy(bt_dev->rfk);
291         }
292 
293         kfree(bt_dev);
294 
295         return toshiba_bluetooth_disable(device->handle);
296 }
297 
298 module_acpi_driver(toshiba_bt_rfkill_driver);
299 

This page was automatically generated by LXR 0.3.1 (source).  •  Linux is a registered trademark of Linus Torvalds  •  Contact us