Version:  2.0.40 2.2.26 2.4.37 3.5 3.6 3.7 3.8 3.9 3.10 3.11 3.12 3.13 3.14 3.15 3.16 3.17 3.18 3.19 4.0 4.1

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  * 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  */
 20 
 21 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
 22 
 23 #include <linux/kernel.h>
 24 #include <linux/module.h>
 25 #include <linux/init.h>
 26 #include <linux/types.h>
 27 #include <linux/acpi.h>
 28 
 29 #define BT_KILLSWITCH_MASK      0x01
 30 #define BT_PLUGGED_MASK         0x40
 31 #define BT_POWER_MASK           0x80
 32 
 33 MODULE_AUTHOR("Jes Sorensen <Jes.Sorensen@gmail.com>");
 34 MODULE_DESCRIPTION("Toshiba Laptop ACPI Bluetooth Enable Driver");
 35 MODULE_LICENSE("GPL");
 36 
 37 static int toshiba_bt_rfkill_add(struct acpi_device *device);
 38 static int toshiba_bt_rfkill_remove(struct acpi_device *device);
 39 static void toshiba_bt_rfkill_notify(struct acpi_device *device, u32 event);
 40 
 41 static const struct acpi_device_id bt_device_ids[] = {
 42         { "TOS6205", 0},
 43         { "", 0},
 44 };
 45 MODULE_DEVICE_TABLE(acpi, bt_device_ids);
 46 
 47 #ifdef CONFIG_PM_SLEEP
 48 static int toshiba_bt_resume(struct device *dev);
 49 #endif
 50 static SIMPLE_DEV_PM_OPS(toshiba_bt_pm, NULL, toshiba_bt_resume);
 51 
 52 static struct acpi_driver toshiba_bt_rfkill_driver = {
 53         .name =         "Toshiba BT",
 54         .class =        "Toshiba",
 55         .ids =          bt_device_ids,
 56         .ops =          {
 57                                 .add =          toshiba_bt_rfkill_add,
 58                                 .remove =       toshiba_bt_rfkill_remove,
 59                                 .notify =       toshiba_bt_rfkill_notify,
 60                         },
 61         .owner =        THIS_MODULE,
 62         .drv.pm =       &toshiba_bt_pm,
 63 };
 64 
 65 static int toshiba_bluetooth_present(acpi_handle handle)
 66 {
 67         acpi_status result;
 68         u64 bt_present;
 69 
 70         /*
 71          * Some Toshiba laptops may have a fake TOS6205 device in
 72          * their ACPI BIOS, so query the _STA method to see if there
 73          * is really anything there.
 74          */
 75         result = acpi_evaluate_integer(handle, "_STA", NULL, &bt_present);
 76         if (ACPI_FAILURE(result)) {
 77                 pr_err("ACPI call to query Bluetooth presence failed");
 78                 return -ENXIO;
 79         } else if (!bt_present) {
 80                 pr_info("Bluetooth device not present\n");
 81                 return -ENODEV;
 82         }
 83 
 84         return 0;
 85 }
 86 
 87 static int toshiba_bluetooth_status(acpi_handle handle)
 88 {
 89         acpi_status result;
 90         u64 status;
 91 
 92         result = acpi_evaluate_integer(handle, "BTST", NULL, &status);
 93         if (ACPI_FAILURE(result)) {
 94                 pr_err("Could not get Bluetooth device status\n");
 95                 return -ENXIO;
 96         }
 97 
 98         pr_info("Bluetooth status %llu\n", status);
 99 
100         return status;
101 }
102 
103 static int toshiba_bluetooth_enable(acpi_handle handle)
104 {
105         acpi_status result;
106         bool killswitch;
107         bool powered;
108         bool plugged;
109         int status;
110 
111         /*
112          * Query ACPI to verify RFKill switch is set to 'on'.
113          * If not, we return silently, no need to report it as
114          * an error.
115          */
116         status = toshiba_bluetooth_status(handle);
117         if (status < 0)
118                 return status;
119 
120         killswitch = (status & BT_KILLSWITCH_MASK) ? true : false;
121         powered = (status & BT_POWER_MASK) ? true : false;
122         plugged = (status & BT_PLUGGED_MASK) ? true : false;
123 
124         if (!killswitch)
125                 return 0;
126         /*
127          * This check ensures to only enable the device if it is powered
128          * off or detached, as some recent devices somehow pass the killswitch
129          * test, causing a loop enabling/disabling the device, see bug 93911.
130          */
131         if (powered || plugged)
132                 return 0;
133 
134         result = acpi_evaluate_object(handle, "AUSB", NULL, NULL);
135         if (ACPI_FAILURE(result)) {
136                 pr_err("Could not attach USB Bluetooth device\n");
137                 return -ENXIO;
138         }
139 
140         result = acpi_evaluate_object(handle, "BTPO", NULL, NULL);
141         if (ACPI_FAILURE(result)) {
142                 pr_err("Could not power ON Bluetooth device\n");
143                 return -ENXIO;
144         }
145 
146         return 0;
147 }
148 
149 static int toshiba_bluetooth_disable(acpi_handle handle)
150 {
151         acpi_status result;
152 
153         result = acpi_evaluate_object(handle, "BTPF", NULL, NULL);
154         if (ACPI_FAILURE(result)) {
155                 pr_err("Could not power OFF Bluetooth device\n");
156                 return -ENXIO;
157         }
158 
159         result = acpi_evaluate_object(handle, "DUSB", NULL, NULL);
160         if (ACPI_FAILURE(result)) {
161                 pr_err("Could not detach USB Bluetooth device\n");
162                 return -ENXIO;
163         }
164 
165         return 0;
166 }
167 
168 static void toshiba_bt_rfkill_notify(struct acpi_device *device, u32 event)
169 {
170         toshiba_bluetooth_enable(device->handle);
171 }
172 
173 #ifdef CONFIG_PM_SLEEP
174 static int toshiba_bt_resume(struct device *dev)
175 {
176         return toshiba_bluetooth_enable(to_acpi_device(dev)->handle);
177 }
178 #endif
179 
180 static int toshiba_bt_rfkill_add(struct acpi_device *device)
181 {
182         int result;
183 
184         result = toshiba_bluetooth_present(device->handle);
185         if (result)
186                 return result;
187 
188         pr_info("Toshiba ACPI Bluetooth device driver\n");
189 
190         /* Enable the BT device */
191         result = toshiba_bluetooth_enable(device->handle);
192         if (result)
193                 return result;
194 
195         return result;
196 }
197 
198 static int toshiba_bt_rfkill_remove(struct acpi_device *device)
199 {
200         /* clean up */
201         return toshiba_bluetooth_disable(device->handle);
202 }
203 
204 module_acpi_driver(toshiba_bt_rfkill_driver);
205 

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