toshiba_bluetooth: Add RFKill handler functions
This patch adds RFKill handler functions to the driver, allowing it to register and update the rfkill switch status. Also, a comment block was moved from the header to the poll function, as it explains why we need to poll the killswitch on older devices. Signed-off-by: Azael Avalos <coproscefalo@gmail.com> Signed-off-by: Darren Hart <dvhart@linux.intel.com>
This commit is contained in:
parent
84c0691e51
commit
7ee8cd3319
|
@ -642,6 +642,7 @@ config ACPI_TOSHIBA
|
||||||
config TOSHIBA_BT_RFKILL
|
config TOSHIBA_BT_RFKILL
|
||||||
tristate "Toshiba Bluetooth RFKill switch support"
|
tristate "Toshiba Bluetooth RFKill switch support"
|
||||||
depends on ACPI
|
depends on ACPI
|
||||||
|
depends on RFKILL || RFKILL = n
|
||||||
---help---
|
---help---
|
||||||
This driver adds support for Bluetooth events for the RFKill
|
This driver adds support for Bluetooth events for the RFKill
|
||||||
switch on modern Toshiba laptops with full ACPI support and
|
switch on modern Toshiba laptops with full ACPI support and
|
||||||
|
|
|
@ -10,12 +10,6 @@
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* This program is free software; you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License version 2 as
|
* it under the terms of the GNU General Public License version 2 as
|
||||||
* published by the Free Software Foundation.
|
* published by the Free Software Foundation.
|
||||||
*
|
|
||||||
* Note the Toshiba Bluetooth RFKill switch seems to be a strange
|
|
||||||
* fish. It only provides a BT event when the switch is flipped to
|
|
||||||
* the 'on' position. When flipping it to 'off', the USB device is
|
|
||||||
* simply pulled away underneath us, without any BT event being
|
|
||||||
* delivered.
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
|
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
|
||||||
|
@ -25,6 +19,7 @@
|
||||||
#include <linux/init.h>
|
#include <linux/init.h>
|
||||||
#include <linux/types.h>
|
#include <linux/types.h>
|
||||||
#include <linux/acpi.h>
|
#include <linux/acpi.h>
|
||||||
|
#include <linux/rfkill.h>
|
||||||
|
|
||||||
#define BT_KILLSWITCH_MASK 0x01
|
#define BT_KILLSWITCH_MASK 0x01
|
||||||
#define BT_PLUGGED_MASK 0x40
|
#define BT_PLUGGED_MASK 0x40
|
||||||
|
@ -36,6 +31,7 @@ MODULE_LICENSE("GPL");
|
||||||
|
|
||||||
struct toshiba_bluetooth_dev {
|
struct toshiba_bluetooth_dev {
|
||||||
struct acpi_device *acpi_dev;
|
struct acpi_device *acpi_dev;
|
||||||
|
struct rfkill *rfk;
|
||||||
|
|
||||||
bool killswitch;
|
bool killswitch;
|
||||||
bool plugged;
|
bool plugged;
|
||||||
|
@ -191,6 +187,49 @@ static int toshiba_bluetooth_sync_status(struct toshiba_bluetooth_dev *bt_dev)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* RFKill handlers */
|
||||||
|
static int bt_rfkill_set_block(void *data, bool blocked)
|
||||||
|
{
|
||||||
|
struct toshiba_bluetooth_dev *bt_dev = data;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
ret = toshiba_bluetooth_sync_status(bt_dev);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
if (!bt_dev->killswitch)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (blocked)
|
||||||
|
ret = toshiba_bluetooth_disable(bt_dev->acpi_dev->handle);
|
||||||
|
else
|
||||||
|
ret = toshiba_bluetooth_enable(bt_dev->acpi_dev->handle);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void bt_rfkill_poll(struct rfkill *rfkill, void *data)
|
||||||
|
{
|
||||||
|
struct toshiba_bluetooth_dev *bt_dev = data;
|
||||||
|
|
||||||
|
if (toshiba_bluetooth_sync_status(bt_dev))
|
||||||
|
return;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Note the Toshiba Bluetooth RFKill switch seems to be a strange
|
||||||
|
* fish. It only provides a BT event when the switch is flipped to
|
||||||
|
* the 'on' position. When flipping it to 'off', the USB device is
|
||||||
|
* simply pulled away underneath us, without any BT event being
|
||||||
|
* delivered.
|
||||||
|
*/
|
||||||
|
rfkill_set_hw_state(bt_dev->rfk, !bt_dev->killswitch);
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct rfkill_ops rfk_ops = {
|
||||||
|
.set_block = bt_rfkill_set_block,
|
||||||
|
.poll = bt_rfkill_poll,
|
||||||
|
};
|
||||||
|
|
||||||
/* ACPI driver functions */
|
/* ACPI driver functions */
|
||||||
static void toshiba_bt_rfkill_notify(struct acpi_device *device, u32 event)
|
static void toshiba_bt_rfkill_notify(struct acpi_device *device, u32 event)
|
||||||
{
|
{
|
||||||
|
@ -228,10 +267,25 @@ static int toshiba_bt_rfkill_add(struct acpi_device *device)
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Enable the BT device */
|
bt_dev->rfk = rfkill_alloc("Toshiba Bluetooth",
|
||||||
result = toshiba_bluetooth_enable(device->handle);
|
&device->dev,
|
||||||
if (result)
|
RFKILL_TYPE_BLUETOOTH,
|
||||||
|
&rfk_ops,
|
||||||
|
bt_dev);
|
||||||
|
if (!bt_dev->rfk) {
|
||||||
|
pr_err("Unable to allocate rfkill device\n");
|
||||||
kfree(bt_dev);
|
kfree(bt_dev);
|
||||||
|
return -ENOMEM;
|
||||||
|
}
|
||||||
|
|
||||||
|
rfkill_set_hw_state(bt_dev->rfk, !bt_dev->killswitch);
|
||||||
|
|
||||||
|
result = rfkill_register(bt_dev->rfk);
|
||||||
|
if (result) {
|
||||||
|
pr_err("Unable to register rfkill device\n");
|
||||||
|
rfkill_destroy(bt_dev->rfk);
|
||||||
|
kfree(bt_dev);
|
||||||
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
@ -241,6 +295,11 @@ static int toshiba_bt_rfkill_remove(struct acpi_device *device)
|
||||||
struct toshiba_bluetooth_dev *bt_dev = acpi_driver_data(device);
|
struct toshiba_bluetooth_dev *bt_dev = acpi_driver_data(device);
|
||||||
|
|
||||||
/* clean up */
|
/* clean up */
|
||||||
|
if (bt_dev->rfk) {
|
||||||
|
rfkill_unregister(bt_dev->rfk);
|
||||||
|
rfkill_destroy(bt_dev->rfk);
|
||||||
|
}
|
||||||
|
|
||||||
kfree(bt_dev);
|
kfree(bt_dev);
|
||||||
|
|
||||||
return toshiba_bluetooth_disable(device->handle);
|
return toshiba_bluetooth_disable(device->handle);
|
||||||
|
|
Loading…
Reference in New Issue