root/drivers/platform/x86/toshiba_bluetooth.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. toshiba_bluetooth_present
  2. toshiba_bluetooth_status
  3. toshiba_bluetooth_enable
  4. toshiba_bluetooth_disable
  5. toshiba_bluetooth_sync_status
  6. bt_rfkill_set_block
  7. bt_rfkill_poll
  8. toshiba_bt_rfkill_notify
  9. toshiba_bt_resume
  10. toshiba_bt_rfkill_add
  11. toshiba_bt_rfkill_remove

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

/* [<][>][^][v][top][bottom][index][help] */