rfkill: rewrite
This patch completely rewrites the rfkill core to address the following deficiencies: * all rfkill drivers need to implement polling where necessary rather than having one central implementation * updating the rfkill state cannot be done from arbitrary contexts, forcing drivers to use schedule_work and requiring lots of code * rfkill drivers need to keep track of soft/hard blocked internally -- the core should do this * the rfkill API has many unexpected quirks, for example being asymmetric wrt. alloc/free and register/unregister * rfkill can call back into a driver from within a function the driver called -- this is prone to deadlocks and generally should be avoided * rfkill-input pointlessly is a separate module * drivers need to #ifdef rfkill functions (unless they want to depend on or select RFKILL) -- rfkill should provide inlines that do nothing if it isn't compiled in * the rfkill structure is not opaque -- drivers need to initialise it correctly (lots of sanity checking code required) -- instead force drivers to pass the right variables to rfkill_alloc() * the documentation is hard to read because it always assumes the reader is completely clueless and contains way TOO MANY CAPS * the rfkill code needlessly uses a lot of locks and atomic operations in locked sections * fix LED trigger to actually change the LED when the radio state changes -- this wasn't done before Tested-by: Alan Jenkins <alan-jenkins@tuffmail.co.uk> Signed-off-by: Henrique de Moraes Holschuh <hmh@hmh.eng.br> [thinkpad] Signed-off-by: Johannes Berg <johannes@sipsolutions.net> Signed-off-by: John W. Linville <linville@tuxdriver.com>
This commit is contained in:

committed by
John W. Linville

parent
0f6399c4c5
commit
19d337dff9
@@ -21,7 +21,7 @@ config ACER_WMI
|
||||
depends on NEW_LEDS
|
||||
depends on BACKLIGHT_CLASS_DEVICE
|
||||
depends on SERIO_I8042
|
||||
depends on RFKILL
|
||||
depends on RFKILL || RFKILL = n
|
||||
select ACPI_WMI
|
||||
---help---
|
||||
This is a driver for newer Acer (and Wistron) laptops. It adds
|
||||
@@ -60,7 +60,7 @@ config DELL_LAPTOP
|
||||
depends on DCDBAS
|
||||
depends on EXPERIMENTAL
|
||||
depends on BACKLIGHT_CLASS_DEVICE
|
||||
depends on RFKILL
|
||||
depends on RFKILL || RFKILL = n
|
||||
depends on POWER_SUPPLY
|
||||
default n
|
||||
---help---
|
||||
@@ -117,7 +117,7 @@ config HP_WMI
|
||||
tristate "HP WMI extras"
|
||||
depends on ACPI_WMI
|
||||
depends on INPUT
|
||||
depends on RFKILL
|
||||
depends on RFKILL || RFKILL = n
|
||||
help
|
||||
Say Y here if you want to support WMI-based hotkeys on HP laptops and
|
||||
to read data from WMI such as docking or ambient light sensor state.
|
||||
@@ -196,14 +196,13 @@ config THINKPAD_ACPI
|
||||
tristate "ThinkPad ACPI Laptop Extras"
|
||||
depends on ACPI
|
||||
depends on INPUT
|
||||
depends on RFKILL || RFKILL = n
|
||||
select BACKLIGHT_LCD_SUPPORT
|
||||
select BACKLIGHT_CLASS_DEVICE
|
||||
select HWMON
|
||||
select NVRAM
|
||||
select NEW_LEDS
|
||||
select LEDS_CLASS
|
||||
select NET
|
||||
select RFKILL
|
||||
---help---
|
||||
This is a driver for the IBM and Lenovo ThinkPad laptops. It adds
|
||||
support for Fn-Fx key combinations, Bluetooth control, video
|
||||
@@ -338,9 +337,9 @@ config EEEPC_LAPTOP
|
||||
depends on ACPI
|
||||
depends on INPUT
|
||||
depends on EXPERIMENTAL
|
||||
depends on RFKILL || RFKILL = n
|
||||
select BACKLIGHT_CLASS_DEVICE
|
||||
select HWMON
|
||||
select RFKILL
|
||||
---help---
|
||||
This driver supports the Fn-Fx keys on Eee PC laptops.
|
||||
It also adds the ability to switch camera/wlan on/off.
|
||||
@@ -405,9 +404,8 @@ config ACPI_TOSHIBA
|
||||
tristate "Toshiba Laptop Extras"
|
||||
depends on ACPI
|
||||
depends on INPUT
|
||||
depends on RFKILL || RFKILL = n
|
||||
select INPUT_POLLDEV
|
||||
select NET
|
||||
select RFKILL
|
||||
select BACKLIGHT_CLASS_DEVICE
|
||||
---help---
|
||||
This driver adds support for access to certain system settings
|
||||
|
@@ -958,58 +958,50 @@ static void acer_rfkill_update(struct work_struct *ignored)
|
||||
|
||||
status = get_u32(&state, ACER_CAP_WIRELESS);
|
||||
if (ACPI_SUCCESS(status))
|
||||
rfkill_force_state(wireless_rfkill, state ?
|
||||
RFKILL_STATE_UNBLOCKED : RFKILL_STATE_SOFT_BLOCKED);
|
||||
rfkill_set_sw_state(wireless_rfkill, !!state);
|
||||
|
||||
if (has_cap(ACER_CAP_BLUETOOTH)) {
|
||||
status = get_u32(&state, ACER_CAP_BLUETOOTH);
|
||||
if (ACPI_SUCCESS(status))
|
||||
rfkill_force_state(bluetooth_rfkill, state ?
|
||||
RFKILL_STATE_UNBLOCKED :
|
||||
RFKILL_STATE_SOFT_BLOCKED);
|
||||
rfkill_set_sw_state(bluetooth_rfkill, !!state);
|
||||
}
|
||||
|
||||
schedule_delayed_work(&acer_rfkill_work, round_jiffies_relative(HZ));
|
||||
}
|
||||
|
||||
static int acer_rfkill_set(void *data, enum rfkill_state state)
|
||||
static int acer_rfkill_set(void *data, bool blocked)
|
||||
{
|
||||
acpi_status status;
|
||||
u32 *cap = data;
|
||||
status = set_u32((u32) (state == RFKILL_STATE_UNBLOCKED), *cap);
|
||||
u32 cap = (unsigned long)data;
|
||||
status = set_u32(!!blocked, cap);
|
||||
if (ACPI_FAILURE(status))
|
||||
return -ENODEV;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct rfkill * acer_rfkill_register(struct device *dev,
|
||||
enum rfkill_type type, char *name, u32 cap)
|
||||
static const struct rfkill_ops acer_rfkill_ops = {
|
||||
.set_block = acer_rfkill_set,
|
||||
};
|
||||
|
||||
static struct rfkill *acer_rfkill_register(struct device *dev,
|
||||
enum rfkill_type type,
|
||||
char *name, u32 cap)
|
||||
{
|
||||
int err;
|
||||
u32 state;
|
||||
u32 *data;
|
||||
struct rfkill *rfkill_dev;
|
||||
|
||||
rfkill_dev = rfkill_allocate(dev, type);
|
||||
rfkill_dev = rfkill_alloc(name, dev, type,
|
||||
&acer_rfkill_ops,
|
||||
(void *)(unsigned long)cap);
|
||||
if (!rfkill_dev)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
rfkill_dev->name = name;
|
||||
get_u32(&state, cap);
|
||||
rfkill_dev->state = state ? RFKILL_STATE_UNBLOCKED :
|
||||
RFKILL_STATE_SOFT_BLOCKED;
|
||||
data = kzalloc(sizeof(u32), GFP_KERNEL);
|
||||
if (!data) {
|
||||
rfkill_free(rfkill_dev);
|
||||
return ERR_PTR(-ENOMEM);
|
||||
}
|
||||
*data = cap;
|
||||
rfkill_dev->data = data;
|
||||
rfkill_dev->toggle_radio = acer_rfkill_set;
|
||||
rfkill_set_sw_state(rfkill_dev, !state);
|
||||
|
||||
err = rfkill_register(rfkill_dev);
|
||||
if (err) {
|
||||
kfree(rfkill_dev->data);
|
||||
rfkill_free(rfkill_dev);
|
||||
rfkill_destroy(rfkill_dev);
|
||||
return ERR_PTR(err);
|
||||
}
|
||||
return rfkill_dev;
|
||||
@@ -1027,8 +1019,8 @@ static int acer_rfkill_init(struct device *dev)
|
||||
RFKILL_TYPE_BLUETOOTH, "acer-bluetooth",
|
||||
ACER_CAP_BLUETOOTH);
|
||||
if (IS_ERR(bluetooth_rfkill)) {
|
||||
kfree(wireless_rfkill->data);
|
||||
rfkill_unregister(wireless_rfkill);
|
||||
rfkill_destroy(wireless_rfkill);
|
||||
return PTR_ERR(bluetooth_rfkill);
|
||||
}
|
||||
}
|
||||
@@ -1041,11 +1033,13 @@ static int acer_rfkill_init(struct device *dev)
|
||||
static void acer_rfkill_exit(void)
|
||||
{
|
||||
cancel_delayed_work_sync(&acer_rfkill_work);
|
||||
kfree(wireless_rfkill->data);
|
||||
|
||||
rfkill_unregister(wireless_rfkill);
|
||||
rfkill_destroy(wireless_rfkill);
|
||||
|
||||
if (has_cap(ACER_CAP_BLUETOOTH)) {
|
||||
kfree(bluetooth_rfkill->data);
|
||||
rfkill_unregister(bluetooth_rfkill);
|
||||
rfkill_destroy(bluetooth_rfkill);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
@@ -174,10 +174,11 @@ dell_send_request(struct calling_interface_buffer *buffer, int class,
|
||||
result[3]: NVRAM format version number
|
||||
*/
|
||||
|
||||
static int dell_rfkill_set(int radio, enum rfkill_state state)
|
||||
static int dell_rfkill_set(void *data, bool blocked)
|
||||
{
|
||||
struct calling_interface_buffer buffer;
|
||||
int disable = (state == RFKILL_STATE_UNBLOCKED) ? 0 : 1;
|
||||
int disable = blocked ? 0 : 1;
|
||||
unsigned long radio = (unsigned long)data;
|
||||
|
||||
memset(&buffer, 0, sizeof(struct calling_interface_buffer));
|
||||
buffer.input[0] = (1 | (radio<<8) | (disable << 16));
|
||||
@@ -186,56 +187,24 @@ static int dell_rfkill_set(int radio, enum rfkill_state state)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dell_wifi_set(void *data, enum rfkill_state state)
|
||||
{
|
||||
return dell_rfkill_set(1, state);
|
||||
}
|
||||
|
||||
static int dell_bluetooth_set(void *data, enum rfkill_state state)
|
||||
{
|
||||
return dell_rfkill_set(2, state);
|
||||
}
|
||||
|
||||
static int dell_wwan_set(void *data, enum rfkill_state state)
|
||||
{
|
||||
return dell_rfkill_set(3, state);
|
||||
}
|
||||
|
||||
static int dell_rfkill_get(int bit, enum rfkill_state *state)
|
||||
static void dell_rfkill_query(struct rfkill *rfkill, void *data)
|
||||
{
|
||||
struct calling_interface_buffer buffer;
|
||||
int status;
|
||||
int new_state = RFKILL_STATE_HARD_BLOCKED;
|
||||
int bit = (unsigned long)data + 16;
|
||||
|
||||
memset(&buffer, 0, sizeof(struct calling_interface_buffer));
|
||||
dell_send_request(&buffer, 17, 11);
|
||||
status = buffer.output[1];
|
||||
|
||||
if (status & (1<<16))
|
||||
new_state = RFKILL_STATE_SOFT_BLOCKED;
|
||||
|
||||
if (status & (1<<bit))
|
||||
*state = new_state;
|
||||
else
|
||||
*state = RFKILL_STATE_UNBLOCKED;
|
||||
|
||||
return 0;
|
||||
if (status & BIT(bit))
|
||||
rfkill_set_hw_state(rfkill, !!(status & BIT(16)));
|
||||
}
|
||||
|
||||
static int dell_wifi_get(void *data, enum rfkill_state *state)
|
||||
{
|
||||
return dell_rfkill_get(17, state);
|
||||
}
|
||||
|
||||
static int dell_bluetooth_get(void *data, enum rfkill_state *state)
|
||||
{
|
||||
return dell_rfkill_get(18, state);
|
||||
}
|
||||
|
||||
static int dell_wwan_get(void *data, enum rfkill_state *state)
|
||||
{
|
||||
return dell_rfkill_get(19, state);
|
||||
}
|
||||
static const struct rfkill_ops dell_rfkill_ops = {
|
||||
.set_block = dell_rfkill_set,
|
||||
.query = dell_rfkill_query,
|
||||
};
|
||||
|
||||
static int dell_setup_rfkill(void)
|
||||
{
|
||||
@@ -248,36 +217,37 @@ static int dell_setup_rfkill(void)
|
||||
status = buffer.output[1];
|
||||
|
||||
if ((status & (1<<2|1<<8)) == (1<<2|1<<8)) {
|
||||
wifi_rfkill = rfkill_allocate(NULL, RFKILL_TYPE_WLAN);
|
||||
if (!wifi_rfkill)
|
||||
wifi_rfkill = rfkill_alloc("dell-wifi", NULL, RFKILL_TYPE_WLAN,
|
||||
&dell_rfkill_ops, (void *) 1);
|
||||
if (!wifi_rfkill) {
|
||||
ret = -ENOMEM;
|
||||
goto err_wifi;
|
||||
wifi_rfkill->name = "dell-wifi";
|
||||
wifi_rfkill->toggle_radio = dell_wifi_set;
|
||||
wifi_rfkill->get_state = dell_wifi_get;
|
||||
}
|
||||
ret = rfkill_register(wifi_rfkill);
|
||||
if (ret)
|
||||
goto err_wifi;
|
||||
}
|
||||
|
||||
if ((status & (1<<3|1<<9)) == (1<<3|1<<9)) {
|
||||
bluetooth_rfkill = rfkill_allocate(NULL, RFKILL_TYPE_BLUETOOTH);
|
||||
if (!bluetooth_rfkill)
|
||||
bluetooth_rfkill = rfkill_alloc("dell-bluetooth", NULL,
|
||||
RFKILL_TYPE_BLUETOOTH,
|
||||
&dell_rfkill_ops, (void *) 2);
|
||||
if (!bluetooth_rfkill) {
|
||||
ret = -ENOMEM;
|
||||
goto err_bluetooth;
|
||||
bluetooth_rfkill->name = "dell-bluetooth";
|
||||
bluetooth_rfkill->toggle_radio = dell_bluetooth_set;
|
||||
bluetooth_rfkill->get_state = dell_bluetooth_get;
|
||||
}
|
||||
ret = rfkill_register(bluetooth_rfkill);
|
||||
if (ret)
|
||||
goto err_bluetooth;
|
||||
}
|
||||
|
||||
if ((status & (1<<4|1<<10)) == (1<<4|1<<10)) {
|
||||
wwan_rfkill = rfkill_allocate(NULL, RFKILL_TYPE_WWAN);
|
||||
if (!wwan_rfkill)
|
||||
wwan_rfkill = rfkill_alloc("dell-wwan", NULL, RFKILL_TYPE_WWAN,
|
||||
&dell_rfkill_ops, (void *) 3);
|
||||
if (!wwan_rfkill) {
|
||||
ret = -ENOMEM;
|
||||
goto err_wwan;
|
||||
wwan_rfkill->name = "dell-wwan";
|
||||
wwan_rfkill->toggle_radio = dell_wwan_set;
|
||||
wwan_rfkill->get_state = dell_wwan_get;
|
||||
}
|
||||
ret = rfkill_register(wwan_rfkill);
|
||||
if (ret)
|
||||
goto err_wwan;
|
||||
@@ -285,22 +255,15 @@ static int dell_setup_rfkill(void)
|
||||
|
||||
return 0;
|
||||
err_wwan:
|
||||
if (wwan_rfkill)
|
||||
rfkill_free(wwan_rfkill);
|
||||
if (bluetooth_rfkill) {
|
||||
rfkill_unregister(bluetooth_rfkill);
|
||||
bluetooth_rfkill = NULL;
|
||||
}
|
||||
err_bluetooth:
|
||||
rfkill_destroy(wwan_rfkill);
|
||||
if (bluetooth_rfkill)
|
||||
rfkill_free(bluetooth_rfkill);
|
||||
if (wifi_rfkill) {
|
||||
rfkill_unregister(wifi_rfkill);
|
||||
wifi_rfkill = NULL;
|
||||
}
|
||||
err_wifi:
|
||||
rfkill_unregister(bluetooth_rfkill);
|
||||
err_bluetooth:
|
||||
rfkill_destroy(bluetooth_rfkill);
|
||||
if (wifi_rfkill)
|
||||
rfkill_free(wifi_rfkill);
|
||||
rfkill_unregister(wifi_rfkill);
|
||||
err_wifi:
|
||||
rfkill_destroy(wifi_rfkill);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
@@ -299,39 +299,22 @@ static int update_bl_status(struct backlight_device *bd)
|
||||
* Rfkill helpers
|
||||
*/
|
||||
|
||||
static int eeepc_wlan_rfkill_set(void *data, enum rfkill_state state)
|
||||
{
|
||||
if (state == RFKILL_STATE_SOFT_BLOCKED)
|
||||
return set_acpi(CM_ASL_WLAN, 0);
|
||||
else
|
||||
return set_acpi(CM_ASL_WLAN, 1);
|
||||
}
|
||||
|
||||
static int eeepc_wlan_rfkill_state(void *data, enum rfkill_state *state)
|
||||
static bool eeepc_wlan_rfkill_blocked(void)
|
||||
{
|
||||
if (get_acpi(CM_ASL_WLAN) == 1)
|
||||
*state = RFKILL_STATE_UNBLOCKED;
|
||||
else
|
||||
*state = RFKILL_STATE_SOFT_BLOCKED;
|
||||
return 0;
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
static int eeepc_bluetooth_rfkill_set(void *data, enum rfkill_state state)
|
||||
static int eeepc_rfkill_set(void *data, bool blocked)
|
||||
{
|
||||
if (state == RFKILL_STATE_SOFT_BLOCKED)
|
||||
return set_acpi(CM_ASL_BLUETOOTH, 0);
|
||||
else
|
||||
return set_acpi(CM_ASL_BLUETOOTH, 1);
|
||||
unsigned long asl = (unsigned long)data;
|
||||
return set_acpi(asl, !blocked);
|
||||
}
|
||||
|
||||
static int eeepc_bluetooth_rfkill_state(void *data, enum rfkill_state *state)
|
||||
{
|
||||
if (get_acpi(CM_ASL_BLUETOOTH) == 1)
|
||||
*state = RFKILL_STATE_UNBLOCKED;
|
||||
else
|
||||
*state = RFKILL_STATE_SOFT_BLOCKED;
|
||||
return 0;
|
||||
}
|
||||
static const struct rfkill_ops eeepc_rfkill_ops = {
|
||||
.set_block = eeepc_rfkill_set,
|
||||
};
|
||||
|
||||
/*
|
||||
* Sys helpers
|
||||
@@ -531,9 +514,9 @@ static int notify_brn(void)
|
||||
|
||||
static void eeepc_rfkill_notify(acpi_handle handle, u32 event, void *data)
|
||||
{
|
||||
enum rfkill_state state;
|
||||
struct pci_dev *dev;
|
||||
struct pci_bus *bus = pci_find_bus(0, 1);
|
||||
bool blocked;
|
||||
|
||||
if (event != ACPI_NOTIFY_BUS_CHECK)
|
||||
return;
|
||||
@@ -543,9 +526,8 @@ static void eeepc_rfkill_notify(acpi_handle handle, u32 event, void *data)
|
||||
return;
|
||||
}
|
||||
|
||||
eeepc_wlan_rfkill_state(ehotk->eeepc_wlan_rfkill, &state);
|
||||
|
||||
if (state == RFKILL_STATE_UNBLOCKED) {
|
||||
blocked = eeepc_wlan_rfkill_blocked();
|
||||
if (!blocked) {
|
||||
dev = pci_get_slot(bus, 0);
|
||||
if (dev) {
|
||||
/* Device already present */
|
||||
@@ -566,7 +548,7 @@ static void eeepc_rfkill_notify(acpi_handle handle, u32 event, void *data)
|
||||
}
|
||||
}
|
||||
|
||||
rfkill_force_state(ehotk->eeepc_wlan_rfkill, state);
|
||||
rfkill_set_sw_state(ehotk->eeepc_wlan_rfkill, blocked);
|
||||
}
|
||||
|
||||
static void eeepc_hotk_notify(acpi_handle handle, u32 event, void *data)
|
||||
@@ -684,26 +666,17 @@ static int eeepc_hotk_add(struct acpi_device *device)
|
||||
eeepc_register_rfkill_notifier("\\_SB.PCI0.P0P7");
|
||||
|
||||
if (get_acpi(CM_ASL_WLAN) != -1) {
|
||||
ehotk->eeepc_wlan_rfkill = rfkill_allocate(&device->dev,
|
||||
RFKILL_TYPE_WLAN);
|
||||
ehotk->eeepc_wlan_rfkill = rfkill_alloc("eeepc-wlan",
|
||||
&device->dev,
|
||||
RFKILL_TYPE_WLAN,
|
||||
&eeepc_rfkill_ops,
|
||||
(void *)CM_ASL_WLAN);
|
||||
|
||||
if (!ehotk->eeepc_wlan_rfkill)
|
||||
goto wlan_fail;
|
||||
|
||||
ehotk->eeepc_wlan_rfkill->name = "eeepc-wlan";
|
||||
ehotk->eeepc_wlan_rfkill->toggle_radio = eeepc_wlan_rfkill_set;
|
||||
ehotk->eeepc_wlan_rfkill->get_state = eeepc_wlan_rfkill_state;
|
||||
if (get_acpi(CM_ASL_WLAN) == 1) {
|
||||
ehotk->eeepc_wlan_rfkill->state =
|
||||
RFKILL_STATE_UNBLOCKED;
|
||||
rfkill_set_default(RFKILL_TYPE_WLAN,
|
||||
RFKILL_STATE_UNBLOCKED);
|
||||
} else {
|
||||
ehotk->eeepc_wlan_rfkill->state =
|
||||
RFKILL_STATE_SOFT_BLOCKED;
|
||||
rfkill_set_default(RFKILL_TYPE_WLAN,
|
||||
RFKILL_STATE_SOFT_BLOCKED);
|
||||
}
|
||||
rfkill_set_global_sw_state(RFKILL_TYPE_WLAN,
|
||||
get_acpi(CM_ASL_WLAN) != 1);
|
||||
result = rfkill_register(ehotk->eeepc_wlan_rfkill);
|
||||
if (result)
|
||||
goto wlan_fail;
|
||||
@@ -711,28 +684,17 @@ static int eeepc_hotk_add(struct acpi_device *device)
|
||||
|
||||
if (get_acpi(CM_ASL_BLUETOOTH) != -1) {
|
||||
ehotk->eeepc_bluetooth_rfkill =
|
||||
rfkill_allocate(&device->dev, RFKILL_TYPE_BLUETOOTH);
|
||||
rfkill_alloc("eeepc-bluetooth",
|
||||
&device->dev,
|
||||
RFKILL_TYPE_BLUETOOTH,
|
||||
&eeepc_rfkill_ops,
|
||||
(void *)CM_ASL_BLUETOOTH);
|
||||
|
||||
if (!ehotk->eeepc_bluetooth_rfkill)
|
||||
goto bluetooth_fail;
|
||||
|
||||
ehotk->eeepc_bluetooth_rfkill->name = "eeepc-bluetooth";
|
||||
ehotk->eeepc_bluetooth_rfkill->toggle_radio =
|
||||
eeepc_bluetooth_rfkill_set;
|
||||
ehotk->eeepc_bluetooth_rfkill->get_state =
|
||||
eeepc_bluetooth_rfkill_state;
|
||||
if (get_acpi(CM_ASL_BLUETOOTH) == 1) {
|
||||
ehotk->eeepc_bluetooth_rfkill->state =
|
||||
RFKILL_STATE_UNBLOCKED;
|
||||
rfkill_set_default(RFKILL_TYPE_BLUETOOTH,
|
||||
RFKILL_STATE_UNBLOCKED);
|
||||
} else {
|
||||
ehotk->eeepc_bluetooth_rfkill->state =
|
||||
RFKILL_STATE_SOFT_BLOCKED;
|
||||
rfkill_set_default(RFKILL_TYPE_BLUETOOTH,
|
||||
RFKILL_STATE_SOFT_BLOCKED);
|
||||
}
|
||||
|
||||
rfkill_set_global_sw_state(RFKILL_TYPE_BLUETOOTH,
|
||||
get_acpi(CM_ASL_BLUETOOTH) != 1);
|
||||
result = rfkill_register(ehotk->eeepc_bluetooth_rfkill);
|
||||
if (result)
|
||||
goto bluetooth_fail;
|
||||
@@ -741,13 +703,10 @@ static int eeepc_hotk_add(struct acpi_device *device)
|
||||
return 0;
|
||||
|
||||
bluetooth_fail:
|
||||
if (ehotk->eeepc_bluetooth_rfkill)
|
||||
rfkill_free(ehotk->eeepc_bluetooth_rfkill);
|
||||
rfkill_destroy(ehotk->eeepc_bluetooth_rfkill);
|
||||
rfkill_unregister(ehotk->eeepc_wlan_rfkill);
|
||||
ehotk->eeepc_wlan_rfkill = NULL;
|
||||
wlan_fail:
|
||||
if (ehotk->eeepc_wlan_rfkill)
|
||||
rfkill_free(ehotk->eeepc_wlan_rfkill);
|
||||
rfkill_destroy(ehotk->eeepc_wlan_rfkill);
|
||||
eeepc_unregister_rfkill_notifier("\\_SB.PCI0.P0P6");
|
||||
eeepc_unregister_rfkill_notifier("\\_SB.PCI0.P0P7");
|
||||
ehotk_fail:
|
||||
|
@@ -154,58 +154,46 @@ static int hp_wmi_dock_state(void)
|
||||
return hp_wmi_perform_query(HPWMI_DOCK_QUERY, 0, 0);
|
||||
}
|
||||
|
||||
static int hp_wmi_wifi_set(void *data, enum rfkill_state state)
|
||||
static int hp_wmi_set_block(void *data, bool blocked)
|
||||
{
|
||||
if (state)
|
||||
return hp_wmi_perform_query(HPWMI_WIRELESS_QUERY, 1, 0x101);
|
||||
else
|
||||
return hp_wmi_perform_query(HPWMI_WIRELESS_QUERY, 1, 0x100);
|
||||
unsigned long b = (unsigned long) data;
|
||||
int query = BIT(b + 8) | ((!!blocked) << b);
|
||||
|
||||
return hp_wmi_perform_query(HPWMI_WIRELESS_QUERY, 1, query);
|
||||
}
|
||||
|
||||
static int hp_wmi_bluetooth_set(void *data, enum rfkill_state state)
|
||||
{
|
||||
if (state)
|
||||
return hp_wmi_perform_query(HPWMI_WIRELESS_QUERY, 1, 0x202);
|
||||
else
|
||||
return hp_wmi_perform_query(HPWMI_WIRELESS_QUERY, 1, 0x200);
|
||||
}
|
||||
static const struct rfkill_ops hp_wmi_rfkill_ops = {
|
||||
.set_block = hp_wmi_set_block,
|
||||
};
|
||||
|
||||
static int hp_wmi_wwan_set(void *data, enum rfkill_state state)
|
||||
{
|
||||
if (state)
|
||||
return hp_wmi_perform_query(HPWMI_WIRELESS_QUERY, 1, 0x404);
|
||||
else
|
||||
return hp_wmi_perform_query(HPWMI_WIRELESS_QUERY, 1, 0x400);
|
||||
}
|
||||
|
||||
static int hp_wmi_wifi_state(void)
|
||||
static bool hp_wmi_wifi_state(void)
|
||||
{
|
||||
int wireless = hp_wmi_perform_query(HPWMI_WIRELESS_QUERY, 0, 0);
|
||||
|
||||
if (wireless & 0x100)
|
||||
return RFKILL_STATE_UNBLOCKED;
|
||||
return false;
|
||||
else
|
||||
return RFKILL_STATE_SOFT_BLOCKED;
|
||||
return true;
|
||||
}
|
||||
|
||||
static int hp_wmi_bluetooth_state(void)
|
||||
static bool hp_wmi_bluetooth_state(void)
|
||||
{
|
||||
int wireless = hp_wmi_perform_query(HPWMI_WIRELESS_QUERY, 0, 0);
|
||||
|
||||
if (wireless & 0x10000)
|
||||
return RFKILL_STATE_UNBLOCKED;
|
||||
return false;
|
||||
else
|
||||
return RFKILL_STATE_SOFT_BLOCKED;
|
||||
return true;
|
||||
}
|
||||
|
||||
static int hp_wmi_wwan_state(void)
|
||||
static bool hp_wmi_wwan_state(void)
|
||||
{
|
||||
int wireless = hp_wmi_perform_query(HPWMI_WIRELESS_QUERY, 0, 0);
|
||||
|
||||
if (wireless & 0x1000000)
|
||||
return RFKILL_STATE_UNBLOCKED;
|
||||
return false;
|
||||
else
|
||||
return RFKILL_STATE_SOFT_BLOCKED;
|
||||
return true;
|
||||
}
|
||||
|
||||
static ssize_t show_display(struct device *dev, struct device_attribute *attr,
|
||||
@@ -347,14 +335,14 @@ static void hp_wmi_notify(u32 value, void *context)
|
||||
}
|
||||
} else if (eventcode == 0x5) {
|
||||
if (wifi_rfkill)
|
||||
rfkill_force_state(wifi_rfkill,
|
||||
hp_wmi_wifi_state());
|
||||
rfkill_set_sw_state(wifi_rfkill,
|
||||
hp_wmi_wifi_state());
|
||||
if (bluetooth_rfkill)
|
||||
rfkill_force_state(bluetooth_rfkill,
|
||||
hp_wmi_bluetooth_state());
|
||||
rfkill_set_sw_state(bluetooth_rfkill,
|
||||
hp_wmi_bluetooth_state());
|
||||
if (wwan_rfkill)
|
||||
rfkill_force_state(wwan_rfkill,
|
||||
hp_wmi_wwan_state());
|
||||
rfkill_set_sw_state(wwan_rfkill,
|
||||
hp_wmi_wwan_state());
|
||||
} else
|
||||
printk(KERN_INFO "HP WMI: Unknown key pressed - %x\n",
|
||||
eventcode);
|
||||
@@ -430,31 +418,34 @@ static int __init hp_wmi_bios_setup(struct platform_device *device)
|
||||
goto add_sysfs_error;
|
||||
|
||||
if (wireless & 0x1) {
|
||||
wifi_rfkill = rfkill_allocate(&device->dev, RFKILL_TYPE_WLAN);
|
||||
wifi_rfkill->name = "hp-wifi";
|
||||
wifi_rfkill->state = hp_wmi_wifi_state();
|
||||
wifi_rfkill->toggle_radio = hp_wmi_wifi_set;
|
||||
wifi_rfkill = rfkill_alloc("hp-wifi", &device->dev,
|
||||
RFKILL_TYPE_WLAN,
|
||||
&hp_wmi_rfkill_ops,
|
||||
(void *) 0);
|
||||
rfkill_set_sw_state(wifi_rfkill, hp_wmi_wifi_state());
|
||||
err = rfkill_register(wifi_rfkill);
|
||||
if (err)
|
||||
goto add_sysfs_error;
|
||||
goto register_wifi_error;
|
||||
}
|
||||
|
||||
if (wireless & 0x2) {
|
||||
bluetooth_rfkill = rfkill_allocate(&device->dev,
|
||||
RFKILL_TYPE_BLUETOOTH);
|
||||
bluetooth_rfkill->name = "hp-bluetooth";
|
||||
bluetooth_rfkill->state = hp_wmi_bluetooth_state();
|
||||
bluetooth_rfkill->toggle_radio = hp_wmi_bluetooth_set;
|
||||
bluetooth_rfkill = rfkill_alloc("hp-bluetooth", &device->dev,
|
||||
RFKILL_TYPE_BLUETOOTH,
|
||||
&hp_wmi_rfkill_ops,
|
||||
(void *) 1);
|
||||
rfkill_set_sw_state(bluetooth_rfkill,
|
||||
hp_wmi_bluetooth_state());
|
||||
err = rfkill_register(bluetooth_rfkill);
|
||||
if (err)
|
||||
goto register_bluetooth_error;
|
||||
}
|
||||
|
||||
if (wireless & 0x4) {
|
||||
wwan_rfkill = rfkill_allocate(&device->dev, RFKILL_TYPE_WWAN);
|
||||
wwan_rfkill->name = "hp-wwan";
|
||||
wwan_rfkill->state = hp_wmi_wwan_state();
|
||||
wwan_rfkill->toggle_radio = hp_wmi_wwan_set;
|
||||
wwan_rfkill = rfkill_alloc("hp-wwan", &device->dev,
|
||||
RFKILL_TYPE_WWAN,
|
||||
&hp_wmi_rfkill_ops,
|
||||
(void *) 2);
|
||||
rfkill_set_sw_state(wwan_rfkill, hp_wmi_wwan_state());
|
||||
err = rfkill_register(wwan_rfkill);
|
||||
if (err)
|
||||
goto register_wwan_err;
|
||||
@@ -462,11 +453,15 @@ static int __init hp_wmi_bios_setup(struct platform_device *device)
|
||||
|
||||
return 0;
|
||||
register_wwan_err:
|
||||
rfkill_destroy(wwan_rfkill);
|
||||
if (bluetooth_rfkill)
|
||||
rfkill_unregister(bluetooth_rfkill);
|
||||
register_bluetooth_error:
|
||||
rfkill_destroy(bluetooth_rfkill);
|
||||
if (wifi_rfkill)
|
||||
rfkill_unregister(wifi_rfkill);
|
||||
register_wifi_error:
|
||||
rfkill_destroy(wifi_rfkill);
|
||||
add_sysfs_error:
|
||||
cleanup_sysfs(device);
|
||||
return err;
|
||||
@@ -476,12 +471,18 @@ static int __exit hp_wmi_bios_remove(struct platform_device *device)
|
||||
{
|
||||
cleanup_sysfs(device);
|
||||
|
||||
if (wifi_rfkill)
|
||||
if (wifi_rfkill) {
|
||||
rfkill_unregister(wifi_rfkill);
|
||||
if (bluetooth_rfkill)
|
||||
rfkill_destroy(wifi_rfkill);
|
||||
}
|
||||
if (bluetooth_rfkill) {
|
||||
rfkill_unregister(bluetooth_rfkill);
|
||||
if (wwan_rfkill)
|
||||
rfkill_destroy(wifi_rfkill);
|
||||
}
|
||||
if (wwan_rfkill) {
|
||||
rfkill_unregister(wwan_rfkill);
|
||||
rfkill_destroy(wwan_rfkill);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@@ -128,11 +128,11 @@ enum sony_nc_rfkill {
|
||||
SONY_BLUETOOTH,
|
||||
SONY_WWAN,
|
||||
SONY_WIMAX,
|
||||
SONY_RFKILL_MAX,
|
||||
N_SONY_RFKILL,
|
||||
};
|
||||
|
||||
static struct rfkill *sony_rfkill_devices[SONY_RFKILL_MAX];
|
||||
static int sony_rfkill_address[SONY_RFKILL_MAX] = {0x300, 0x500, 0x700, 0x900};
|
||||
static struct rfkill *sony_rfkill_devices[N_SONY_RFKILL];
|
||||
static int sony_rfkill_address[N_SONY_RFKILL] = {0x300, 0x500, 0x700, 0x900};
|
||||
static void sony_nc_rfkill_update(void);
|
||||
|
||||
/*********** Input Devices ***********/
|
||||
@@ -1051,147 +1051,98 @@ static void sony_nc_rfkill_cleanup(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < SONY_RFKILL_MAX; i++) {
|
||||
if (sony_rfkill_devices[i])
|
||||
for (i = 0; i < N_SONY_RFKILL; i++) {
|
||||
if (sony_rfkill_devices[i]) {
|
||||
rfkill_unregister(sony_rfkill_devices[i]);
|
||||
rfkill_destroy(sony_rfkill_devices[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int sony_nc_rfkill_get(void *data, enum rfkill_state *state)
|
||||
{
|
||||
int result;
|
||||
int argument = sony_rfkill_address[(long) data];
|
||||
|
||||
sony_call_snc_handle(0x124, 0x200, &result);
|
||||
if (result & 0x1) {
|
||||
sony_call_snc_handle(0x124, argument, &result);
|
||||
if (result & 0xf)
|
||||
*state = RFKILL_STATE_UNBLOCKED;
|
||||
else
|
||||
*state = RFKILL_STATE_SOFT_BLOCKED;
|
||||
} else {
|
||||
*state = RFKILL_STATE_HARD_BLOCKED;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int sony_nc_rfkill_set(void *data, enum rfkill_state state)
|
||||
static int sony_nc_rfkill_set(void *data, bool blocked)
|
||||
{
|
||||
int result;
|
||||
int argument = sony_rfkill_address[(long) data] + 0x100;
|
||||
|
||||
if (state == RFKILL_STATE_UNBLOCKED)
|
||||
if (!blocked)
|
||||
argument |= 0xff0000;
|
||||
|
||||
return sony_call_snc_handle(0x124, argument, &result);
|
||||
}
|
||||
|
||||
static int sony_nc_setup_wifi_rfkill(struct acpi_device *device)
|
||||
static const struct rfkill_ops sony_rfkill_ops = {
|
||||
.set_block = sony_nc_rfkill_set,
|
||||
};
|
||||
|
||||
static int sony_nc_setup_rfkill(struct acpi_device *device,
|
||||
enum sony_nc_rfkill nc_type)
|
||||
{
|
||||
int err = 0;
|
||||
struct rfkill *sony_wifi_rfkill;
|
||||
struct rfkill *rfk;
|
||||
enum rfkill_type type;
|
||||
const char *name;
|
||||
|
||||
sony_wifi_rfkill = rfkill_allocate(&device->dev, RFKILL_TYPE_WLAN);
|
||||
if (!sony_wifi_rfkill)
|
||||
return -1;
|
||||
sony_wifi_rfkill->name = "sony-wifi";
|
||||
sony_wifi_rfkill->toggle_radio = sony_nc_rfkill_set;
|
||||
sony_wifi_rfkill->get_state = sony_nc_rfkill_get;
|
||||
sony_wifi_rfkill->data = (void *)SONY_WIFI;
|
||||
err = rfkill_register(sony_wifi_rfkill);
|
||||
if (err)
|
||||
rfkill_free(sony_wifi_rfkill);
|
||||
else {
|
||||
sony_rfkill_devices[SONY_WIFI] = sony_wifi_rfkill;
|
||||
sony_nc_rfkill_set(sony_wifi_rfkill->data,
|
||||
RFKILL_STATE_UNBLOCKED);
|
||||
switch (nc_type) {
|
||||
case SONY_WIFI:
|
||||
type = RFKILL_TYPE_WLAN;
|
||||
name = "sony-wifi";
|
||||
break;
|
||||
case SONY_BLUETOOTH:
|
||||
type = RFKILL_TYPE_BLUETOOTH;
|
||||
name = "sony-bluetooth";
|
||||
break;
|
||||
case SONY_WWAN:
|
||||
type = RFKILL_TYPE_WWAN;
|
||||
name = "sony-wwan";
|
||||
break;
|
||||
case SONY_WIMAX:
|
||||
type = RFKILL_TYPE_WIMAX;
|
||||
name = "sony-wimax";
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
static int sony_nc_setup_bluetooth_rfkill(struct acpi_device *device)
|
||||
{
|
||||
int err = 0;
|
||||
struct rfkill *sony_bluetooth_rfkill;
|
||||
rfk = rfkill_alloc(name, &device->dev, type,
|
||||
&sony_rfkill_ops, (void *)nc_type);
|
||||
if (!rfk)
|
||||
return -ENOMEM;
|
||||
|
||||
sony_bluetooth_rfkill = rfkill_allocate(&device->dev,
|
||||
RFKILL_TYPE_BLUETOOTH);
|
||||
if (!sony_bluetooth_rfkill)
|
||||
return -1;
|
||||
sony_bluetooth_rfkill->name = "sony-bluetooth";
|
||||
sony_bluetooth_rfkill->toggle_radio = sony_nc_rfkill_set;
|
||||
sony_bluetooth_rfkill->get_state = sony_nc_rfkill_get;
|
||||
sony_bluetooth_rfkill->data = (void *)SONY_BLUETOOTH;
|
||||
err = rfkill_register(sony_bluetooth_rfkill);
|
||||
if (err)
|
||||
rfkill_free(sony_bluetooth_rfkill);
|
||||
else {
|
||||
sony_rfkill_devices[SONY_BLUETOOTH] = sony_bluetooth_rfkill;
|
||||
sony_nc_rfkill_set(sony_bluetooth_rfkill->data,
|
||||
RFKILL_STATE_UNBLOCKED);
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
static int sony_nc_setup_wwan_rfkill(struct acpi_device *device)
|
||||
{
|
||||
int err = 0;
|
||||
struct rfkill *sony_wwan_rfkill;
|
||||
|
||||
sony_wwan_rfkill = rfkill_allocate(&device->dev, RFKILL_TYPE_WWAN);
|
||||
if (!sony_wwan_rfkill)
|
||||
return -1;
|
||||
sony_wwan_rfkill->name = "sony-wwan";
|
||||
sony_wwan_rfkill->toggle_radio = sony_nc_rfkill_set;
|
||||
sony_wwan_rfkill->get_state = sony_nc_rfkill_get;
|
||||
sony_wwan_rfkill->data = (void *)SONY_WWAN;
|
||||
err = rfkill_register(sony_wwan_rfkill);
|
||||
if (err)
|
||||
rfkill_free(sony_wwan_rfkill);
|
||||
else {
|
||||
sony_rfkill_devices[SONY_WWAN] = sony_wwan_rfkill;
|
||||
sony_nc_rfkill_set(sony_wwan_rfkill->data,
|
||||
RFKILL_STATE_UNBLOCKED);
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
static int sony_nc_setup_wimax_rfkill(struct acpi_device *device)
|
||||
{
|
||||
int err = 0;
|
||||
struct rfkill *sony_wimax_rfkill;
|
||||
|
||||
sony_wimax_rfkill = rfkill_allocate(&device->dev, RFKILL_TYPE_WIMAX);
|
||||
if (!sony_wimax_rfkill)
|
||||
return -1;
|
||||
sony_wimax_rfkill->name = "sony-wimax";
|
||||
sony_wimax_rfkill->toggle_radio = sony_nc_rfkill_set;
|
||||
sony_wimax_rfkill->get_state = sony_nc_rfkill_get;
|
||||
sony_wimax_rfkill->data = (void *)SONY_WIMAX;
|
||||
err = rfkill_register(sony_wimax_rfkill);
|
||||
if (err)
|
||||
rfkill_free(sony_wimax_rfkill);
|
||||
else {
|
||||
sony_rfkill_devices[SONY_WIMAX] = sony_wimax_rfkill;
|
||||
sony_nc_rfkill_set(sony_wimax_rfkill->data,
|
||||
RFKILL_STATE_UNBLOCKED);
|
||||
err = rfkill_register(rfk);
|
||||
if (err) {
|
||||
rfkill_destroy(rfk);
|
||||
return err;
|
||||
}
|
||||
sony_rfkill_devices[nc_type] = rfk;
|
||||
sony_nc_rfkill_set((void *)nc_type, false);
|
||||
return err;
|
||||
}
|
||||
|
||||
static void sony_nc_rfkill_update()
|
||||
{
|
||||
int i;
|
||||
enum rfkill_state state;
|
||||
enum sony_nc_rfkill i;
|
||||
int result;
|
||||
bool hwblock;
|
||||
|
||||
for (i = 0; i < SONY_RFKILL_MAX; i++) {
|
||||
if (sony_rfkill_devices[i]) {
|
||||
sony_rfkill_devices[i]->
|
||||
get_state(sony_rfkill_devices[i]->data,
|
||||
&state);
|
||||
rfkill_force_state(sony_rfkill_devices[i], state);
|
||||
sony_call_snc_handle(0x124, 0x200, &result);
|
||||
hwblock = !(result & 0x1);
|
||||
|
||||
for (i = 0; i < N_SONY_RFKILL; i++) {
|
||||
int argument = sony_rfkill_address[i];
|
||||
|
||||
if (!sony_rfkill_devices[i])
|
||||
continue;
|
||||
|
||||
if (hwblock) {
|
||||
if (rfkill_set_hw_state(sony_rfkill_devices[i], true))
|
||||
sony_nc_rfkill_set(sony_rfkill_devices[i],
|
||||
true);
|
||||
continue;
|
||||
}
|
||||
|
||||
sony_call_snc_handle(0x124, argument, &result);
|
||||
rfkill_set_states(sony_rfkill_devices[i],
|
||||
!(result & 0xf), false);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1210,13 +1161,13 @@ static int sony_nc_rfkill_setup(struct acpi_device *device)
|
||||
}
|
||||
|
||||
if (result & 0x1)
|
||||
sony_nc_setup_wifi_rfkill(device);
|
||||
sony_nc_setup_rfkill(device, SONY_WIFI);
|
||||
if (result & 0x2)
|
||||
sony_nc_setup_bluetooth_rfkill(device);
|
||||
sony_nc_setup_rfkill(device, SONY_BLUETOOTH);
|
||||
if (result & 0x1c)
|
||||
sony_nc_setup_wwan_rfkill(device);
|
||||
sony_nc_setup_rfkill(device, SONY_WWAN);
|
||||
if (result & 0x20)
|
||||
sony_nc_setup_wimax_rfkill(device);
|
||||
sony_nc_setup_rfkill(device, SONY_WIMAX);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
File diff suppressed because it is too large
Load Diff
@@ -45,7 +45,6 @@
|
||||
#include <linux/backlight.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/rfkill.h>
|
||||
#include <linux/input-polldev.h>
|
||||
|
||||
#include <asm/uaccess.h>
|
||||
|
||||
@@ -250,21 +249,15 @@ static acpi_status hci_read2(u32 reg, u32 *out1, u32 *out2, u32 *result)
|
||||
|
||||
struct toshiba_acpi_dev {
|
||||
struct platform_device *p_dev;
|
||||
struct rfkill *rfk_dev;
|
||||
struct input_polled_dev *poll_dev;
|
||||
struct rfkill *bt_rfk;
|
||||
|
||||
const char *bt_name;
|
||||
const char *rfk_name;
|
||||
|
||||
bool last_rfk_state;
|
||||
|
||||
struct mutex mutex;
|
||||
};
|
||||
|
||||
static struct toshiba_acpi_dev toshiba_acpi = {
|
||||
.bt_name = "Toshiba Bluetooth",
|
||||
.rfk_name = "Toshiba RFKill Switch",
|
||||
.last_rfk_state = false,
|
||||
};
|
||||
|
||||
/* Bluetooth rfkill handlers */
|
||||
@@ -283,21 +276,6 @@ static u32 hci_get_bt_present(bool *present)
|
||||
return hci_result;
|
||||
}
|
||||
|
||||
static u32 hci_get_bt_on(bool *on)
|
||||
{
|
||||
u32 hci_result;
|
||||
u32 value, value2;
|
||||
|
||||
value = 0;
|
||||
value2 = 0x0001;
|
||||
hci_read2(HCI_WIRELESS, &value, &value2, &hci_result);
|
||||
if (hci_result == HCI_SUCCESS)
|
||||
*on = (value & HCI_WIRELESS_BT_POWER) &&
|
||||
(value & HCI_WIRELESS_BT_ATTACH);
|
||||
|
||||
return hci_result;
|
||||
}
|
||||
|
||||
static u32 hci_get_radio_state(bool *radio_state)
|
||||
{
|
||||
u32 hci_result;
|
||||
@@ -311,70 +289,67 @@ static u32 hci_get_radio_state(bool *radio_state)
|
||||
return hci_result;
|
||||
}
|
||||
|
||||
static int bt_rfkill_toggle_radio(void *data, enum rfkill_state state)
|
||||
static int bt_rfkill_set_block(void *data, bool blocked)
|
||||
{
|
||||
struct toshiba_acpi_dev *dev = data;
|
||||
u32 result1, result2;
|
||||
u32 value;
|
||||
int err;
|
||||
bool radio_state;
|
||||
struct toshiba_acpi_dev *dev = data;
|
||||
|
||||
value = (state == RFKILL_STATE_UNBLOCKED);
|
||||
|
||||
if (hci_get_radio_state(&radio_state) != HCI_SUCCESS)
|
||||
return -EFAULT;
|
||||
|
||||
switch (state) {
|
||||
case RFKILL_STATE_UNBLOCKED:
|
||||
if (!radio_state)
|
||||
return -EPERM;
|
||||
break;
|
||||
case RFKILL_STATE_SOFT_BLOCKED:
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
value = (blocked == false);
|
||||
|
||||
mutex_lock(&dev->mutex);
|
||||
if (hci_get_radio_state(&radio_state) != HCI_SUCCESS) {
|
||||
err = -EBUSY;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (!radio_state) {
|
||||
err = 0;
|
||||
goto out;
|
||||
}
|
||||
|
||||
hci_write2(HCI_WIRELESS, value, HCI_WIRELESS_BT_POWER, &result1);
|
||||
hci_write2(HCI_WIRELESS, value, HCI_WIRELESS_BT_ATTACH, &result2);
|
||||
mutex_unlock(&dev->mutex);
|
||||
|
||||
if (result1 != HCI_SUCCESS || result2 != HCI_SUCCESS)
|
||||
return -EFAULT;
|
||||
|
||||
return 0;
|
||||
err = -EBUSY;
|
||||
else
|
||||
err = 0;
|
||||
out:
|
||||
mutex_unlock(&dev->mutex);
|
||||
return err;
|
||||
}
|
||||
|
||||
static void bt_poll_rfkill(struct input_polled_dev *poll_dev)
|
||||
static void bt_rfkill_poll(struct rfkill *rfkill, void *data)
|
||||
{
|
||||
bool state_changed;
|
||||
bool new_rfk_state;
|
||||
bool value;
|
||||
u32 hci_result;
|
||||
struct toshiba_acpi_dev *dev = poll_dev->private;
|
||||
struct toshiba_acpi_dev *dev = data;
|
||||
|
||||
mutex_lock(&dev->mutex);
|
||||
|
||||
hci_result = hci_get_radio_state(&value);
|
||||
if (hci_result != HCI_SUCCESS)
|
||||
return; /* Can't do anything useful */
|
||||
if (hci_result != HCI_SUCCESS) {
|
||||
/* Can't do anything useful */
|
||||
mutex_unlock(&dev->mutex);
|
||||
}
|
||||
|
||||
new_rfk_state = value;
|
||||
|
||||
mutex_lock(&dev->mutex);
|
||||
state_changed = new_rfk_state != dev->last_rfk_state;
|
||||
dev->last_rfk_state = new_rfk_state;
|
||||
mutex_unlock(&dev->mutex);
|
||||
|
||||
if (unlikely(state_changed)) {
|
||||
rfkill_force_state(dev->rfk_dev,
|
||||
new_rfk_state ?
|
||||
RFKILL_STATE_SOFT_BLOCKED :
|
||||
RFKILL_STATE_HARD_BLOCKED);
|
||||
input_report_switch(poll_dev->input, SW_RFKILL_ALL,
|
||||
new_rfk_state);
|
||||
input_sync(poll_dev->input);
|
||||
}
|
||||
if (rfkill_set_hw_state(rfkill, !new_rfk_state))
|
||||
bt_rfkill_set_block(data, true);
|
||||
}
|
||||
|
||||
static const struct rfkill_ops toshiba_rfk_ops = {
|
||||
.set_block = bt_rfkill_set_block,
|
||||
.poll = bt_rfkill_poll,
|
||||
};
|
||||
|
||||
static struct proc_dir_entry *toshiba_proc_dir /*= 0*/ ;
|
||||
static struct backlight_device *toshiba_backlight_device;
|
||||
static int force_fan;
|
||||
@@ -702,14 +677,11 @@ static struct backlight_ops toshiba_backlight_data = {
|
||||
|
||||
static void toshiba_acpi_exit(void)
|
||||
{
|
||||
if (toshiba_acpi.poll_dev) {
|
||||
input_unregister_polled_device(toshiba_acpi.poll_dev);
|
||||
input_free_polled_device(toshiba_acpi.poll_dev);
|
||||
if (toshiba_acpi.bt_rfk) {
|
||||
rfkill_unregister(toshiba_acpi.bt_rfk);
|
||||
rfkill_destroy(toshiba_acpi.bt_rfk);
|
||||
}
|
||||
|
||||
if (toshiba_acpi.rfk_dev)
|
||||
rfkill_unregister(toshiba_acpi.rfk_dev);
|
||||
|
||||
if (toshiba_backlight_device)
|
||||
backlight_device_unregister(toshiba_backlight_device);
|
||||
|
||||
@@ -728,8 +700,6 @@ static int __init toshiba_acpi_init(void)
|
||||
acpi_status status = AE_OK;
|
||||
u32 hci_result;
|
||||
bool bt_present;
|
||||
bool bt_on;
|
||||
bool radio_on;
|
||||
int ret = 0;
|
||||
|
||||
if (acpi_disabled)
|
||||
@@ -793,60 +763,21 @@ static int __init toshiba_acpi_init(void)
|
||||
|
||||
/* Register rfkill switch for Bluetooth */
|
||||
if (hci_get_bt_present(&bt_present) == HCI_SUCCESS && bt_present) {
|
||||
toshiba_acpi.rfk_dev = rfkill_allocate(&toshiba_acpi.p_dev->dev,
|
||||
RFKILL_TYPE_BLUETOOTH);
|
||||
if (!toshiba_acpi.rfk_dev) {
|
||||
toshiba_acpi.bt_rfk = rfkill_alloc(toshiba_acpi.bt_name,
|
||||
&toshiba_acpi.p_dev->dev,
|
||||
RFKILL_TYPE_BLUETOOTH,
|
||||
&toshiba_rfk_ops,
|
||||
&toshiba_acpi);
|
||||
if (!toshiba_acpi.bt_rfk) {
|
||||
printk(MY_ERR "unable to allocate rfkill device\n");
|
||||
toshiba_acpi_exit();
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
toshiba_acpi.rfk_dev->name = toshiba_acpi.bt_name;
|
||||
toshiba_acpi.rfk_dev->toggle_radio = bt_rfkill_toggle_radio;
|
||||
toshiba_acpi.rfk_dev->data = &toshiba_acpi;
|
||||
|
||||
if (hci_get_bt_on(&bt_on) == HCI_SUCCESS && bt_on) {
|
||||
toshiba_acpi.rfk_dev->state = RFKILL_STATE_UNBLOCKED;
|
||||
} else if (hci_get_radio_state(&radio_on) == HCI_SUCCESS &&
|
||||
radio_on) {
|
||||
toshiba_acpi.rfk_dev->state = RFKILL_STATE_SOFT_BLOCKED;
|
||||
} else {
|
||||
toshiba_acpi.rfk_dev->state = RFKILL_STATE_HARD_BLOCKED;
|
||||
}
|
||||
|
||||
ret = rfkill_register(toshiba_acpi.rfk_dev);
|
||||
ret = rfkill_register(toshiba_acpi.bt_rfk);
|
||||
if (ret) {
|
||||
printk(MY_ERR "unable to register rfkill device\n");
|
||||
toshiba_acpi_exit();
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
/* Register input device for kill switch */
|
||||
toshiba_acpi.poll_dev = input_allocate_polled_device();
|
||||
if (!toshiba_acpi.poll_dev) {
|
||||
printk(MY_ERR
|
||||
"unable to allocate kill-switch input device\n");
|
||||
toshiba_acpi_exit();
|
||||
return -ENOMEM;
|
||||
}
|
||||
toshiba_acpi.poll_dev->private = &toshiba_acpi;
|
||||
toshiba_acpi.poll_dev->poll = bt_poll_rfkill;
|
||||
toshiba_acpi.poll_dev->poll_interval = 1000; /* msecs */
|
||||
|
||||
toshiba_acpi.poll_dev->input->name = toshiba_acpi.rfk_name;
|
||||
toshiba_acpi.poll_dev->input->id.bustype = BUS_HOST;
|
||||
/* Toshiba USB ID */
|
||||
toshiba_acpi.poll_dev->input->id.vendor = 0x0930;
|
||||
set_bit(EV_SW, toshiba_acpi.poll_dev->input->evbit);
|
||||
set_bit(SW_RFKILL_ALL, toshiba_acpi.poll_dev->input->swbit);
|
||||
input_report_switch(toshiba_acpi.poll_dev->input,
|
||||
SW_RFKILL_ALL, TRUE);
|
||||
input_sync(toshiba_acpi.poll_dev->input);
|
||||
|
||||
ret = input_register_polled_device(toshiba_acpi.poll_dev);
|
||||
if (ret) {
|
||||
printk(MY_ERR
|
||||
"unable to register kill-switch input device\n");
|
||||
rfkill_destroy(toshiba_acpi.bt_rfk);
|
||||
toshiba_acpi_exit();
|
||||
return ret;
|
||||
}
|
||||
|
Reference in New Issue
Block a user