cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

toshiba_bluetooth.c (6965B)


      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 int 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	.owner = 	THIS_MODULE,
     63	.drv.pm =	&toshiba_bt_pm,
     64};
     65
     66static 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
     90static 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
    104static 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
    123static 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 */
    143static 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 */
    164static 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
    184static 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
    201static const struct rfkill_ops rfk_ops = {
    202	.set_block = bt_rfkill_set_block,
    203	.poll = bt_rfkill_poll,
    204};
    205
    206/* ACPI driver functions */
    207static 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
    218static 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
    235static 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
    282static 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
    297module_acpi_driver(toshiba_bt_rfkill_driver);