Return-Path: Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1756638AbZLDPjU (ORCPT ); Fri, 4 Dec 2009 10:39:20 -0500 Received: (majordomo@vger.kernel.org) by vger.kernel.org id S1754081AbZLDPjT (ORCPT ); Fri, 4 Dec 2009 10:39:19 -0500 Received: from mail-ew0-f219.google.com ([209.85.219.219]:55567 "EHLO mail-ew0-f219.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1752160AbZLDPjR (ORCPT ); Fri, 4 Dec 2009 10:39:17 -0500 DomainKey-Signature: a=rsa-sha1; c=nofws; d=gmail.com; s=gamma; h=message-id:date:from:user-agent:mime-version:to:cc:subject :content-type; b=Qo4IihVWe2JsZG7GNPXfTy2O5yqJPO73P8WKN7RdjyB1qz1RG768DpMbDDInxap4f2 62zGLV4NtGCAv2k9sEuzfEIbhciwNZ6LSmYFRHClzPY6XoTjVipRKe0nySMYusX9SAri ivJqwlxb+1/YKN1aTmfA2WLiAl93jJnJbBcSw= Message-ID: <4B192D08.9080608@gmail.com> Date: Fri, 04 Dec 2009 16:38:48 +0100 From: Jes Sorensen User-Agent: Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.1.4pre) Gecko/20090922 Fedora/3.0-3.9.b4.fc12 Thunderbird/3.0b4 MIME-Version: 1.0 To: linux-acpi@vger.kernel.org CC: linux-kernel , lenb@kernel.org, Matthew Garrett Subject: [PATCH] Toshiba Bluetooth enabler (rfkill) Content-Type: multipart/mixed; boundary="------------030202000404080802000001" Sender: linux-kernel-owner@vger.kernel.org List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Length: 6932 Lines: 222 This is a multi-part message in MIME format. --------------030202000404080802000001 Content-Type: text/plain; charset=ISO-8859-1; format=flowed Content-Transfer-Encoding: 7bit Hi, This patch adds a new driver to catch RFKill events to the Bluetooth device on modern Toshiba laptops. Without it, the Bluetooth device is simply lost on my Portege R500 when the RFKill switch is flipped, and doesn't come back until after a reboot. It binds to the TOS6205 ACPI device and doesn't touch any existing code. Cheers, Jes --------------030202000404080802000001 Content-Type: text/plain; name="0002-toshiba-bluetooth.patch" Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename="0002-toshiba-bluetooth.patch" Toshiba Bluetooth Enabling driver (RFKill handler) This patch adds support for the ACPI events generated by the RFKill switch on modern Toshiba laptops, and re-enables the Bluetooth USB device when the switch is flipped back to the 'on' position. The RFKill switch brute force pulls out the USB device when flipped to 'off', but it doesn't automatically re-enable it. Without this driver, the Bluetooth is gone until after a reboot on my Portege R500. Signed-off-by: Jes Sorensen Reviewed-by: Matthew Garrett --- Index: linux-2.6/drivers/platform/x86/toshiba_bluetooth.c =================================================================== --- /dev/null +++ linux-2.6/drivers/platform/x86/toshiba_bluetooth.c @@ -0,0 +1,135 @@ +/* + * Toshiba Bluetooth Enable Driver + * + * Copyright (C) 2009 Jes Sorensen + * + * Thanks to Matthew Garrett for background info on ACPI innards which + * normal people aren't meant to understand :-) + * + * 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 + * 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. + */ + +#include +#include +#include +#include +#include +#include + +MODULE_AUTHOR("Jes Sorensen "); +MODULE_DESCRIPTION("Toshiba Laptop ACPI Bluetooth Enable Driver"); +MODULE_LICENSE("GPL"); + + +static int toshiba_bt_rfkill_add(struct acpi_device *device); +static int toshiba_bt_rfkill_remove(struct acpi_device *device, int type); +static void toshiba_bt_rfkill_notify(struct acpi_device *device, u32 event); +static int toshiba_bt_resume(struct acpi_device *device); + +static const struct acpi_device_id bt_device_ids[] = { + { "TOS6205", 0}, + { "", 0}, +}; +MODULE_DEVICE_TABLE(acpi, bt_device_ids); + +static struct acpi_driver toshiba_bt_rfkill_driver = { + .name = "Toshiba BT", + .class = "Toshiba", + .ids = bt_device_ids, + .ops = { + .add = toshiba_bt_rfkill_add, + .remove = toshiba_bt_rfkill_remove, + .notify = toshiba_bt_rfkill_notify, + .resume = toshiba_bt_resume, + }, +}; + + +static int toshiba_bluetooth_enable(acpi_handle handle) +{ + acpi_status res1, res2; + acpi_integer result; + + /* Query ACPI to verify RFKill switch is set to on */ + res1 = acpi_evaluate_integer(handle, "BTST", NULL, &result); + if (ACPI_FAILURE(res1) || !(result & 0x01)) + return -EBUSY; + + printk(KERN_INFO "toshiba_bluetooth: Re-enabling Toshiba Bluetooth\n"); + res1 = acpi_evaluate_object(handle, "AUSB", NULL, NULL); + res2 = acpi_evaluate_object(handle, "BTPO", NULL, NULL); + if (!ACPI_FAILURE(res1) || !ACPI_FAILURE(res2)) { + return 0; + } + printk(KERN_WARNING "toshiba_bluetooth: Failed to re-enable " + "Toshiba Bluetooth\n"); + + return -ENODEV; +} + +static void toshiba_bt_rfkill_notify(struct acpi_device *device, u32 event) +{ + toshiba_bluetooth_enable(device->handle); +} + +static int toshiba_bt_resume(struct acpi_device *device) +{ + return toshiba_bluetooth_enable(device->handle); +} + +static int toshiba_bt_rfkill_add(struct acpi_device *device) +{ + acpi_status status; + acpi_integer bt_present; + int result = -ENODEV; + + status = acpi_evaluate_integer(device->handle, "_STA", NULL, + &bt_present); + + if (!ACPI_FAILURE(status) && bt_present) { + printk(KERN_INFO "Detected Toshiba ACPI Bluetooth device - " + "installing RFKill handler\n"); + result = toshiba_bluetooth_enable(device->handle); + } + + return result; +} + +static int __init toshiba_bt_rfkill_init(void) +{ + int result = 0; + + if (acpi_disabled) + return -ENODEV; + + result = acpi_bus_register_driver(&toshiba_bt_rfkill_driver); + if (result < 0) { + ACPI_DEBUG_PRINT((ACPI_DB_ERROR, + "Error registering driver\n")); + return -ENODEV; + } + + return 0; +} + +static int toshiba_bt_rfkill_remove(struct acpi_device *device, int type) +{ + /* clean up */ + return 0; +} + +static void __exit toshiba_bt_rfkill_exit(void) +{ + acpi_bus_unregister_driver(&toshiba_bt_rfkill_driver); +} + +module_init(toshiba_bt_rfkill_init); +module_exit(toshiba_bt_rfkill_exit); Index: linux-2.6/drivers/platform/x86/Makefile =================================================================== --- linux-2.6.orig/drivers/platform/x86/Makefile +++ linux-2.6/drivers/platform/x86/Makefile @@ -21,3 +21,4 @@ obj-$(CONFIG_ACPI_WMI) += wmi.o obj-$(CONFIG_ACPI_ASUS) += asus_acpi.o obj-$(CONFIG_TOPSTAR_LAPTOP) += topstar-laptop.o obj-$(CONFIG_ACPI_TOSHIBA) += toshiba_acpi.o +obj-$(CONFIG_TOSHIBA_BT_RFKILL) += toshiba_bluetooth.o Index: linux-2.6/drivers/platform/x86/Kconfig =================================================================== --- linux-2.6.orig/drivers/platform/x86/Kconfig +++ linux-2.6/drivers/platform/x86/Kconfig @@ -435,4 +435,21 @@ config ACPI_TOSHIBA If you have a legacy free Toshiba laptop (such as the Libretto L1 series), say Y. + +config TOSHIBA_BT_RFKILL + tristate "Toshiba Bluetooth RFKill switch support" + depends on ACPI + depends on RFKILL + depends on BT + ---help--- + This driver adds support for Bluetooth events for the RFKill + switch on modern Toshiba laptops with full ACPI support and + an RFKill switch. + + This driver handles RFKill events for the TOS6205 Bluetooth, + and re-enables it when the switch is set back to the 'on' + position. + + If you have a modern Toshiba laptop with a Bluetooth and an + RFKill switch (such as the Portege R500), say Y. endif # X86_PLATFORM_DEVICES --------------030202000404080802000001-- -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/