Skip to contentSkip to conversation

Add bluetooth support to toshiba-acpi driver

PATCH In review Jonathan McDowell 4 participants 6 messages Oct 21, 2007 – Oct 22, 2007 ACPI

lore
Share & tools
lore
#0 lore raw

PATCH 1/1 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).

-----

acpi/toshiba_acpi.c renamed from acpi/toshiba_acpi.c.orig +127 -1
@@ -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.

Signature · 5 lines
One-seventh of your life is spent on Monday.
-
To unsubscribe from this list: send the line "unsubscribe linux-acpi" in
the body of a message to [email protected]
More majordomo info at  http://vger.kernel.org/majordomo-info.html
#1 lore raw
Quoted 6 lines · Jonathan McDowell

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

Quoted 180 lines

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).

-----

acpi/toshiba_acpi.c 2007-10-21 18:15:34.000000000 +0100 renamed from acpi/toshiba_acpi.c.orig 2007-10-21 18:29:01.000000000 +0100 +126 -2
@@ -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.

#2 lore raw
Quoted 10 lines · Andrey Borzenkov
Quoted 6 lines · Jonathan McDowell

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.

Signature · 1 line
The truth is out there, but also in here.
#3 lore raw
In reply to Jonathan McDowell
Quoted 11 lines

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.

Quoted 4 lines

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

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
-
To unsubscribe from this list: send the line "unsubscribe linux-acpi" in the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html

#4 lore raw
Quoted 14 lines · John Belmonte
Quoted 14 lines

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).

Quoted 6 lines
Quoted 1 line

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.

Signature · 3 lines
                                            jid: [email protected]
I had a life once... but now I have a
                                            modem.
#5 lore raw
In reply to John Belmonte
Quoted 4 lines · John Belmonte

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.

Signature · 1 line
Matthew Garrett | [email protected]