FILE
toshiba_bluetooth.c
File preview with syntax highlighting.
linux-6.19.14/drivers/platform/x86/toshiba_bluetooth.c
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 25MODULE_AUTHOR("Jes Sorensen <Jes.Sorensen@gmail.com>"); 26MODULE_DESCRIPTION("Toshiba Laptop ACPI Bluetooth Enable Driver"); 27MODULE_LICENSE("GPL"); 28 29struct 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 38static int toshiba_bt_rfkill_add(struct acpi_device *device); 39static void toshiba_bt_rfkill_remove(struct acpi_device *device); 40static void toshiba_bt_rfkill_notify(struct acpi_device *device, u32 event); 41 42static const struct acpi_device_id bt_device_ids[] = { 43 { "TOS6205", 0}, 44 { "", 0}, 45}; 46MODULE_DEVICE_TABLE(acpi, bt_device_ids); 47 48#ifdef CONFIG_PM_SLEEP 49static int toshiba_bt_resume(struct device *dev); 50#endif 51static SIMPLE_DEV_PM_OPS(toshiba_bt_pm, NULL, toshiba_bt_resume); 52 53static 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 .drv.pm = &toshiba_bt_pm, 63}; 64 65static 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\n"); 78 return -ENXIO; 79 } 80 81 if (!bt_present) { 82 pr_info("Bluetooth device not present\n"); 83 return -ENODEV; 84 } 85 86 return 0; 87} 88 89static int toshiba_bluetooth_status(acpi_handle handle) 90{ 91 acpi_status result; 92 u64 status; 93 94 result = acpi_evaluate_integer(handle, "BTST", NULL, &status); 95 if (ACPI_FAILURE(result)) { 96 pr_err("Could not get Bluetooth device status\n"); 97 return -ENXIO; 98 } 99 100 return status; 101} 102 103static int toshiba_bluetooth_enable(acpi_handle handle) 104{ 105 acpi_status result; 106 107 result = acpi_evaluate_object(handle, "AUSB", NULL, NULL); 108 if (ACPI_FAILURE(result)) { 109 pr_err("Could not attach USB Bluetooth device\n"); 110 return -ENXIO; 111 } 112 113 result = acpi_evaluate_object(handle, "BTPO", NULL, NULL); 114 if (ACPI_FAILURE(result)) { 115 pr_err("Could not power ON Bluetooth device\n"); 116 return -ENXIO; 117 } 118 119 return 0; 120} 121 122static int toshiba_bluetooth_disable(acpi_handle handle) 123{ 124 acpi_status result; 125 126 result = acpi_evaluate_object(handle, "BTPF", NULL, NULL); 127 if (ACPI_FAILURE(result)) { 128 pr_err("Could not power OFF Bluetooth device\n"); 129 return -ENXIO; 130 } 131 132 result = acpi_evaluate_object(handle, "DUSB", NULL, NULL); 133 if (ACPI_FAILURE(result)) { 134 pr_err("Could not detach USB Bluetooth device\n"); 135 return -ENXIO; 136 } 137 138 return 0; 139} 140 141/* Helper function */ 142static int toshiba_bluetooth_sync_status(struct toshiba_bluetooth_dev *bt_dev) 143{ 144 int status; 145 146 status = toshiba_bluetooth_status(bt_dev->acpi_dev->handle); 147 if (status < 0) { 148 pr_err("Could not sync bluetooth device status\n"); 149 return status; 150 } 151 152 bt_dev->killswitch = (status & BT_KILLSWITCH_MASK) ? true : false; 153 bt_dev->plugged = (status & BT_PLUGGED_MASK) ? true : false; 154 bt_dev->powered = (status & BT_POWER_MASK) ? true : false; 155 156 pr_debug("Bluetooth status %d killswitch %d plugged %d powered %d\n", 157 status, bt_dev->killswitch, bt_dev->plugged, bt_dev->powered); 158 159 return 0; 160} 161 162/* RFKill handlers */ 163static int bt_rfkill_set_block(void *data, bool blocked) 164{ 165 struct toshiba_bluetooth_dev *bt_dev = data; 166 int ret; 167 168 ret = toshiba_bluetooth_sync_status(bt_dev); 169 if (ret) 170 return ret; 171 172 if (!bt_dev->killswitch) 173 return 0; 174 175 if (blocked) 176 ret = toshiba_bluetooth_disable(bt_dev->acpi_dev->handle); 177 else 178 ret = toshiba_bluetooth_enable(bt_dev->acpi_dev->handle); 179 180 return ret; 181} 182 183static void bt_rfkill_poll(struct rfkill *rfkill, void *data) 184{ 185 struct toshiba_bluetooth_dev *bt_dev = data; 186 187 if (toshiba_bluetooth_sync_status(bt_dev)) 188 return; 189 190 /* 191 * Note the Toshiba Bluetooth RFKill switch seems to be a strange 192 * fish. It only provides a BT event when the switch is flipped to 193 * the 'on' position. When flipping it to 'off', the USB device is 194 * simply pulled away underneath us, without any BT event being 195 * delivered. 196 */ 197 rfkill_set_hw_state(bt_dev->rfk, !bt_dev->killswitch); 198} 199 200static const struct rfkill_ops rfk_ops = { 201 .set_block = bt_rfkill_set_block, 202 .poll = bt_rfkill_poll, 203}; 204 205/* ACPI driver functions */ 206static void toshiba_bt_rfkill_notify(struct acpi_device *device, u32 event) 207{ 208 struct toshiba_bluetooth_dev *bt_dev = acpi_driver_data(device); 209 210 if (toshiba_bluetooth_sync_status(bt_dev)) 211 return; 212 213 rfkill_set_hw_state(bt_dev->rfk, !bt_dev->killswitch); 214} 215 216#ifdef CONFIG_PM_SLEEP 217static int toshiba_bt_resume(struct device *dev) 218{ 219 struct toshiba_bluetooth_dev *bt_dev; 220 int ret; 221 222 bt_dev = acpi_driver_data(to_acpi_device(dev)); 223 224 ret = toshiba_bluetooth_sync_status(bt_dev); 225 if (ret) 226 return ret; 227 228 rfkill_set_hw_state(bt_dev->rfk, !bt_dev->killswitch); 229 230 return 0; 231} 232#endif 233 234static int toshiba_bt_rfkill_add(struct acpi_device *device) 235{ 236 struct toshiba_bluetooth_dev *bt_dev; 237 int result; 238 239 result = toshiba_bluetooth_present(device->handle); 240 if (result) 241 return result; 242 243 pr_info("Toshiba ACPI Bluetooth device driver\n"); 244 245 bt_dev = kzalloc(sizeof(*bt_dev), GFP_KERNEL); 246 if (!bt_dev) 247 return -ENOMEM; 248 bt_dev->acpi_dev = device; 249 device->driver_data = bt_dev; 250 dev_set_drvdata(&device->dev, bt_dev); 251 252 result = toshiba_bluetooth_sync_status(bt_dev); 253 if (result) { 254 kfree(bt_dev); 255 return result; 256 } 257 258 bt_dev->rfk = rfkill_alloc("Toshiba Bluetooth", 259 &device->dev, 260 RFKILL_TYPE_BLUETOOTH, 261 &rfk_ops, 262 bt_dev); 263 if (!bt_dev->rfk) { 264 pr_err("Unable to allocate rfkill device\n"); 265 kfree(bt_dev); 266 return -ENOMEM; 267 } 268 269 rfkill_set_hw_state(bt_dev->rfk, !bt_dev->killswitch); 270 271 result = rfkill_register(bt_dev->rfk); 272 if (result) { 273 pr_err("Unable to register rfkill device\n"); 274 rfkill_destroy(bt_dev->rfk); 275 kfree(bt_dev); 276 } 277 278 return result; 279} 280 281static void toshiba_bt_rfkill_remove(struct acpi_device *device) 282{ 283 struct toshiba_bluetooth_dev *bt_dev = acpi_driver_data(device); 284 285 /* clean up */ 286 if (bt_dev->rfk) { 287 rfkill_unregister(bt_dev->rfk); 288 rfkill_destroy(bt_dev->rfk); 289 } 290 291 kfree(bt_dev); 292 293 toshiba_bluetooth_disable(device->handle); 294} 295 296module_acpi_driver(toshiba_bt_rfkill_driver);
~/
Read-only file preview.