2007-10-21 18:19:59

by Jonathan McDowell

[permalink] [raw]
Subject: [PATCH] Add bluetooth support to toshiba-acpi driver

This patch adds bluetooth support to the toshiba-acpi driver. I have
tried to follow the same format for the /proc/acpi/toshiba/bluetooth
file as followed in the thinkpad-acpi driver. In the long term the
rfkill infrastructure looks like the way forward for this functionality,
but at present it doesn't seem to be suitable.

Traditionally the userland "toshset" program would have been used to
enable bluetooth, but this requires either CONFIG_TOSHIBA or a patched
toshiba-acpi to emulate the /dev/toshiba device. Also toshset doesn't
currently run in 64bit mode.

Patch has been successfully tested on a Port?g? R200 (in 32bit mode) and
an R500 (in 64bit mode).

Signed-Off-By: Jonathan McDowell <[email protected]>

-----
--- drivers/acpi/toshiba_acpi.c.orig 2007-10-21 18:29:01.000000000 +0100
+++ drivers/acpi/toshiba_acpi.c 2007-10-21 18:15:34.000000000 +0100
@@ -33,7 +33,7 @@
*
*/

-#define TOSHIBA_ACPI_VERSION "0.18"
+#define TOSHIBA_ACPI_VERSION "0.19"
#define PROC_INTERFACE_VERSION 1

#include <linux/kernel.h>
@@ -55,6 +55,7 @@ MODULE_LICENSE("GPL");
#define MY_ERR KERN_ERR MY_LOGPREFIX
#define MY_NOTICE KERN_NOTICE MY_LOGPREFIX
#define MY_INFO KERN_INFO MY_LOGPREFIX
+#define strlencmp(a,b) (strncmp((a), (b), strlen(b)))

/* Toshiba ACPI method paths */
#define METHOD_LCD_BRIGHTNESS "\\_SB_.PCI0.VGA_.LCD_._BCM"
@@ -90,6 +91,7 @@ MODULE_LICENSE("GPL");
#define HCI_VIDEO_OUT 0x001c
#define HCI_HOTKEY_EVENT 0x001e
#define HCI_LCD_BRIGHTNESS 0x002a
+#define HCI_BLUETOOTH 0x0056

/* field definitions */
#define HCI_LCD_BRIGHTNESS_BITS 3
@@ -482,6 +484,129 @@ static unsigned long write_keys(const ch
return count;
}

+static int toshiba_bluetooth_present(void)
+{
+ u32 hci_result;
+ u32 value;
+
+ hci_read1(HCI_BLUETOOTH, &value, &hci_result);
+ if (hci_result == HCI_SUCCESS) {
+ return (value & 0x0f) == 0x0f;
+ } else
+ return -EFAULT;
+}
+
+static int toshiba_bluetooth_get(void)
+{
+ u32 in[HCI_WORDS];
+ u32 out[HCI_WORDS];
+ acpi_status status;
+
+ in[0] = HCI_GET;
+ in[1] = HCI_BLUETOOTH;
+ in[2] = 0;
+ in[3] = 1;
+ status = hci_raw(in, out);
+ if (status != AE_OK) {
+ printk(MY_ERR "Error checking Bluetooth device status.\n");
+ return -EIO;
+ }
+
+ /* 0x1 == switch on, 0x40 == attached, 0x80 == power on */
+ return (out[2] & 0xC1) == 0xC1;
+}
+
+static int toshiba_bluetooth_set(int state)
+{
+ u32 in[HCI_WORDS];
+ u32 out[HCI_WORDS];
+ acpi_status status;
+
+ switch (state) {
+ case 0:
+ in[0] = HCI_SET;
+ in[1] = HCI_BLUETOOTH;
+ in[2] = 0;
+ in[3] = 0x40;
+ status = hci_raw(in, out);
+ if (status != AE_OK) {
+ printk(MY_ERR "Error detaching Bluetooth device.\n");
+ return -EIO;
+ }
+
+ in[0] = HCI_SET;
+ in[1] = HCI_BLUETOOTH;
+ in[2] = 0;
+ in[3] = 0x80;
+ status = hci_raw(in, out);
+ if (status != AE_OK) {
+ printk(MY_ERR "Error deactivating Bluetooth device.\n");
+ return -EIO;
+ }
+ break;
+ case 1:
+ in[0] = HCI_SET;
+ in[1] = HCI_BLUETOOTH;
+ in[2] = 1;
+ in[3] = 0x80;
+ status = hci_raw(in, out);
+ if (status != AE_OK) {
+ printk(MY_ERR "Error activating Bluetooth device.\n");
+ return -EIO;
+ }
+
+ in[0] = HCI_SET;
+ in[1] = HCI_BLUETOOTH;
+ in[2] = 1;
+ in[3] = 0x40;
+ status = hci_raw(in, out);
+ if (status != AE_OK) {
+ printk(MY_ERR "Error attaching Bluetooth device.\n");
+ return -EIO;
+ }
+ break;
+ default:
+ printk(MY_ERR "Unknown state for Bluetooth.\n");
+ };
+
+ return 0;
+}
+
+static char *read_bluetooth(char *p)
+{
+ int value = toshiba_bluetooth_get();
+
+ if (!toshiba_bluetooth_present()) {
+ p += sprintf(p, "status:\t\tnot supported\n");
+ } else if (value >= 0) {
+ p += sprintf(p, "status:\t\t%s\n",
+ value ? "enabled" : "disabled");
+ p += sprintf(p, "commands:\tenable, disable\n");
+ } else {
+ printk(MY_ERR "Error reading bluetooth status.\n");
+ }
+
+ return p;
+}
+
+static unsigned long write_bluetooth(const char *buffer, unsigned long count)
+{
+ int ret ;
+
+ if (!toshiba_bluetooth_present()) {
+ ret = -ENODEV;
+ } else if (strlencmp(buffer, "enable") == 0) {
+ toshiba_bluetooth_set(1);
+ ret = count;
+ } else if (strlencmp(buffer, "disable") == 0) {
+ toshiba_bluetooth_set(0);
+ ret = count;
+ } else {
+ ret = -EINVAL;
+ }
+ return ret;
+}
+
static char *read_version(char *p)
{
p += sprintf(p, "driver: %s\n", TOSHIBA_ACPI_VERSION);
@@ -496,6 +621,7 @@ static char *read_version(char *p)
#define PROC_TOSHIBA "toshiba"

static ProcItem proc_items[] = {
+ {"bluetooth", read_bluetooth, write_bluetooth},
{"lcd", read_lcd, write_lcd},
{"video", read_video, write_video},
{"fan", read_fan, write_fan},
-----

J.

--
One-seventh of your life is spent on Monday.


2007-10-22 02:30:34

by Andrey Borzenkov

[permalink] [raw]
Subject: Re: [PATCH] Add bluetooth support to toshiba-acpi driver

Jonathan McDowell wrote:

> This patch adds bluetooth support to the toshiba-acpi driver. I have
> tried to follow the same format for the /proc/acpi/toshiba/bluetooth
> file as followed in the thinkpad-acpi driver. In the long term the
> rfkill infrastructure looks like the way forward for this functionality,
> but at present it doesn't seem to be suitable.
>

Would it be possible (make sense) to add config option for that? There are
probably a bunch of older models out there that do not have BT at all (I am
owner of such one).

Thank you

-andrey

> Traditionally the userland "toshset" program would have been used to
> enable bluetooth, but this requires either CONFIG_TOSHIBA or a patched
> toshiba-acpi to emulate the /dev/toshiba device. Also toshset doesn't
> currently run in 64bit mode.
>
> Patch has been successfully tested on a Port?g? R200 (in 32bit mode) and
> an R500 (in 64bit mode).
>
> Signed-Off-By: Jonathan McDowell <[email protected]>
>
> -----
> --- drivers/acpi/toshiba_acpi.c.orig 2007-10-21 18:29:01.000000000 +0100
> +++ drivers/acpi/toshiba_acpi.c 2007-10-21 18:15:34.000000000 +0100
> @@ -33,7 +33,7 @@
> *
> */
>
> -#define TOSHIBA_ACPI_VERSION "0.18"
> +#define TOSHIBA_ACPI_VERSION "0.19"
> #define PROC_INTERFACE_VERSION 1
>
> #include <linux/kernel.h>
> @@ -55,6 +55,7 @@ MODULE_LICENSE("GPL");
> #define MY_ERR KERN_ERR MY_LOGPREFIX
> #define MY_NOTICE KERN_NOTICE MY_LOGPREFIX
> #define MY_INFO KERN_INFO MY_LOGPREFIX
> +#define strlencmp(a,b) (strncmp((a), (b), strlen(b)))
>
> /* Toshiba ACPI method paths */
> #define METHOD_LCD_BRIGHTNESS "\\_SB_.PCI0.VGA_.LCD_._BCM"
> @@ -90,6 +91,7 @@ MODULE_LICENSE("GPL");
> #define HCI_VIDEO_OUT 0x001c
> #define HCI_HOTKEY_EVENT 0x001e
> #define HCI_LCD_BRIGHTNESS 0x002a
> +#define HCI_BLUETOOTH 0x0056
>
> /* field definitions */
> #define HCI_LCD_BRIGHTNESS_BITS 3
> @@ -482,6 +484,129 @@ static unsigned long write_keys(const ch
> return count;
> }
>
> +static int toshiba_bluetooth_present(void)
> +{
> + u32 hci_result;
> + u32 value;
> +
> + hci_read1(HCI_BLUETOOTH, &value, &hci_result);
> + if (hci_result == HCI_SUCCESS) {
> + return (value & 0x0f) == 0x0f;
> + } else
> + return -EFAULT;
> +}
> +
> +static int toshiba_bluetooth_get(void)
> +{
> + u32 in[HCI_WORDS];
> + u32 out[HCI_WORDS];
> + acpi_status status;
> +
> + in[0] = HCI_GET;
> + in[1] = HCI_BLUETOOTH;
> + in[2] = 0;
> + in[3] = 1;
> + status = hci_raw(in, out);
> + if (status != AE_OK) {
> + printk(MY_ERR "Error checking Bluetooth device status.\n");
> + return -EIO;
> + }
> +
> + /* 0x1 == switch on, 0x40 == attached, 0x80 == power on */
> + return (out[2] & 0xC1) == 0xC1;
> +}
> +
> +static int toshiba_bluetooth_set(int state)
> +{
> + u32 in[HCI_WORDS];
> + u32 out[HCI_WORDS];
> + acpi_status status;
> +
> + switch (state) {
> + case 0:
> + in[0] = HCI_SET;
> + in[1] = HCI_BLUETOOTH;
> + in[2] = 0;
> + in[3] = 0x40;
> + status = hci_raw(in, out);
> + if (status != AE_OK) {
> + printk(MY_ERR "Error detaching Bluetooth device.\n");
> + return -EIO;
> + }
> +
> + in[0] = HCI_SET;
> + in[1] = HCI_BLUETOOTH;
> + in[2] = 0;
> + in[3] = 0x80;
> + status = hci_raw(in, out);
> + if (status != AE_OK) {
> + printk(MY_ERR "Error deactivating Bluetooth device.\n");
> + return -EIO;
> + }
> + break;
> + case 1:
> + in[0] = HCI_SET;
> + in[1] = HCI_BLUETOOTH;
> + in[2] = 1;
> + in[3] = 0x80;
> + status = hci_raw(in, out);
> + if (status != AE_OK) {
> + printk(MY_ERR "Error activating Bluetooth device.\n");
> + return -EIO;
> + }
> +
> + in[0] = HCI_SET;
> + in[1] = HCI_BLUETOOTH;
> + in[2] = 1;
> + in[3] = 0x40;
> + status = hci_raw(in, out);
> + if (status != AE_OK) {
> + printk(MY_ERR "Error attaching Bluetooth device.\n");
> + return -EIO;
> + }
> + break;
> + default:
> + printk(MY_ERR "Unknown state for Bluetooth.\n");
> + };
> +
> + return 0;
> +}
> +
> +static char *read_bluetooth(char *p)
> +{
> + int value = toshiba_bluetooth_get();
> +
> + if (!toshiba_bluetooth_present()) {
> + p += sprintf(p, "status:\t\tnot supported\n");
> + } else if (value >= 0) {
> + p += sprintf(p, "status:\t\t%s\n",
> + value ? "enabled" : "disabled");
> + p += sprintf(p, "commands:\tenable, disable\n");
> + } else {
> + printk(MY_ERR "Error reading bluetooth status.\n");
> + }
> +
> + return p;
> +}
> +
> +static unsigned long write_bluetooth(const char *buffer, unsigned long
> count) +{
> + int ret ;
> +
> + if (!toshiba_bluetooth_present()) {
> + ret = -ENODEV;
> + } else if (strlencmp(buffer, "enable") == 0) {
> + toshiba_bluetooth_set(1);
> + ret = count;
> + } else if (strlencmp(buffer, "disable") == 0) {
> + toshiba_bluetooth_set(0);
> + ret = count;
> + } else {
> + ret = -EINVAL;
> + }
> + return ret;
> +}
> +
> static char *read_version(char *p)
> {
> p += sprintf(p, "driver: %s\n", TOSHIBA_ACPI_VERSION);
> @@ -496,6 +621,7 @@ static char *read_version(char *p)
> #define PROC_TOSHIBA "toshiba"
>
> static ProcItem proc_items[] = {
> + {"bluetooth", read_bluetooth, write_bluetooth},
> {"lcd", read_lcd, write_lcd},
> {"video", read_video, write_video},
> {"fan", read_fan, write_fan},
> -----
>
> J.
>


2007-10-22 08:11:50

by Jonathan McDowell

[permalink] [raw]
Subject: Re: [PATCH] Add bluetooth support to toshiba-acpi driver

On Mon, Oct 22, 2007 at 06:30:19AM +0400, Andrey Borzenkov wrote:
> Jonathan McDowell wrote:
> > This patch adds bluetooth support to the toshiba-acpi driver. I have
> > tried to follow the same format for the /proc/acpi/toshiba/bluetooth
> > file as followed in the thinkpad-acpi driver. In the long term the
> > rfkill infrastructure looks like the way forward for this
> > functionality, but at present it doesn't seem to be suitable.
> >
> Would it be possible (make sense) to add config option for that? There
> are probably a bunch of older models out there that do not have BT at
> all (I am owner of such one).

For models without bluetooth the /proc/acpi/toshiba/bluetooth file
should end up with "status: not supported" in it. I don't have such a
laptop to test that this happens though; perhaps you could test the
patch and confirm it works as expected?

J.

--
The truth is out there, but also in here.

2007-10-22 11:31:40

by John Belmonte

[permalink] [raw]
Subject: Re: [PATCH] Add bluetooth support to toshiba-acpi driver

> This patch adds bluetooth support to the toshiba-acpi driver. I have
> tried to follow the same format for the /proc/acpi/toshiba/bluetooth
> file as followed in the thinkpad-acpi driver. In the long term the
> rfkill infrastructure looks like the way forward for this functionality,
> but at present it doesn't seem to be suitable.
>
> Traditionally the userland "toshset" program would have been used to
> enable bluetooth, but this requires either CONFIG_TOSHIBA or a patched
> toshiba-acpi to emulate the /dev/toshiba device. Also toshset doesn't
> currently run in 64bit mode.
>
> Patch has been successfully tested on a Port?g? R200 (in 32bit mode) and
> an R500 (in 64bit mode).
>
> Signed-Off-By: Jonathan McDowell <[email protected]>

The /proc/acpi/toshiba interface should not be expanded-- do not apply
this patch. If any patch is applied, it would be to optionally
implement the generic /dev/toshiba interface so that user space tools
like toshset can operate.

--John Belmonte

2007-10-22 14:28:56

by Jonathan McDowell

[permalink] [raw]
Subject: Re: [PATCH] Add bluetooth support to toshiba-acpi driver

On Mon, Oct 22, 2007 at 07:26:26AM -0400, John Belmonte wrote:
> > This patch adds bluetooth support to the toshiba-acpi driver. I have
> > tried to follow the same format for the /proc/acpi/toshiba/bluetooth
> > file as followed in the thinkpad-acpi driver. In the long term the
> > rfkill infrastructure looks like the way forward for this functionality,
> > but at present it doesn't seem to be suitable.
> >
> > Traditionally the userland "toshset" program would have been used to
> > enable bluetooth, but this requires either CONFIG_TOSHIBA or a patched
> > toshiba-acpi to emulate the /dev/toshiba device. Also toshset doesn't
> > currently run in 64bit mode.
> >
> > Patch has been successfully tested on a Port?g? R200 (in 32bit mode) and
> > an R500 (in 64bit mode).
> >
> > Signed-Off-By: Jonathan McDowell <[email protected]>
>
> The /proc/acpi/toshiba interface should not be expanded-- do not apply
> this patch. If any patch is applied, it would be to optionally
> implement the generic /dev/toshiba interface so that user space tools
> like toshset can operate.

There's been a patch to add the /dev/toshiba functionality floating
around for at least a year or two. Is there a reason it hasn't already
been applied?

I'm not entirely convinced that userland is the right way to do this
though. In the long run rfkill appears to be the correct generic
infrastructure, but at present it's not able to cope with devices that
don't exist when switched off and I can't find any other users in
mainline anyway. Assuming that changes, would you accept a patch adding
support for it to toshiba-acpi?

J.

--
jid: [email protected]
I had a life once... but now I have a
modem.

2007-10-22 14:54:39

by Matthew Garrett

[permalink] [raw]
Subject: Re: [PATCH] Add bluetooth support to toshiba-acpi driver

On Mon, Oct 22, 2007 at 07:26:26AM -0400, John Belmonte wrote:

> The /proc/acpi/toshiba interface should not be expanded-- do not apply
> this patch. If any patch is applied, it would be to optionally
> implement the generic /dev/toshiba interface so that user space tools
> like toshset can operate.

The correct interface is rfkill, which will require this functionality
to be in-kernel anyway. I can see the argument against implementing it
in /proc/acpi/toshiba (further proc interface bloat), but not against
doing it in-kernel.

--
Matthew Garrett | [email protected]