From 523574dd0a28554cce7d9c03eca0bf37142198b6 Mon Sep 17 00:00:00 2001
From: Sascha Wildner <saw@online.de>
Date: Sat, 16 Jan 2016 14:28:41 +0100
Subject: [PATCH] WIP

---
 sys/dev/acpica/acpi_toshiba/acpi_toshiba.c | 113 ++++++++++++++++++++++++++++-
 1 file changed, 112 insertions(+), 1 deletion(-)

diff --git a/sys/dev/acpica/acpi_toshiba/acpi_toshiba.c b/sys/dev/acpica/acpi_toshiba/acpi_toshiba.c
index 58b0bb3..bb328e5 100644
--- a/sys/dev/acpica/acpi_toshiba/acpi_toshiba.c
+++ b/sys/dev/acpica/acpi_toshiba/acpi_toshiba.c
@@ -124,6 +124,7 @@ ACPI_MODULE_NAME("Toshiba")
 struct acpi_toshiba_softc {
 	device_t	dev;
 	ACPI_HANDLE	handle;
+	ACPI_HANDLE	bt_handle;
 	ACPI_HANDLE	video_handle;
 	struct		sysctl_ctx_list sysctl_ctx;
 	struct		sysctl_oid *sysctl_tree;
@@ -146,6 +147,12 @@ static void	hci_key_action(struct acpi_toshiba_softc *sc, ACPI_HANDLE h,
 		    UINT32 key);
 static void	acpi_toshiba_notify(ACPI_HANDLE h, UINT32 notify,
 		    void *context);
+static int	acpi_toshiba_bt_probe(device_t dev);
+static int	acpi_toshiba_bt_attach(device_t dev);
+static int	acpi_toshiba_bt_detach(device_t dev);
+static int	acpi_toshiba_bt_enable(device_t dev);
+static void	acpi_toshiba_bt_notify(ACPI_HANDLE h, UINT32 notify,
+		    void *context);
 static int	acpi_toshiba_video_probe(device_t dev);
 static int	acpi_toshiba_video_attach(device_t dev);
 
@@ -184,6 +191,25 @@ DRIVER_MODULE(acpi_toshiba, acpi, acpi_toshiba_driver, acpi_toshiba_devclass,
     NULL, NULL);
 MODULE_DEPEND(acpi_toshiba, acpi, 1, 1, 1);
 
+static device_method_t acpi_toshiba_bt_methods[] = {
+	DEVMETHOD(device_probe,		acpi_toshiba_bt_probe),
+	DEVMETHOD(device_attach,	acpi_toshiba_bt_attach),
+	DEVMETHOD(device_detach,	acpi_toshiba_bt_detach),
+
+	DEVMETHOD_END
+};
+
+static driver_t acpi_toshiba_bt_driver = {
+	"acpi_toshiba_bt",
+	acpi_toshiba_bt_methods,
+	0,
+};
+
+static devclass_t acpi_toshiba_bt_devclass;
+DRIVER_MODULE(acpi_toshiba_bt, acpi, acpi_toshiba_bt_driver,
+    acpi_toshiba_bt_devclass, NULL, NULL);
+MODULE_DEPEND(acpi_toshiba_bt, acpi, 1, 1, 1);
+
 static device_method_t acpi_toshiba_video_methods[] = {
 	DEVMETHOD(device_probe,		acpi_toshiba_video_probe),
 	DEVMETHOD(device_attach,	acpi_toshiba_video_attach),
@@ -533,6 +559,91 @@ acpi_toshiba_notify(ACPI_HANDLE h, UINT32 notify, void *context)
 }
 
 /*
+ * Toshiba bluetooth support.
+ * per https://lwn.net/Articles/367630/
+ *
+ * HID      Model
+ * -------------------------------------
+ * TOS6205  Toshiba Satellite L50-B etc.
+ */
+static int
+acpi_toshiba_bt_probe(device_t dev)
+{
+	static char	*bt_ids[] = { "TOS6205", NULL };
+
+	if (acpi_disabled("toshiba") ||
+	    ACPI_ID_PROBE(device_get_parent(dev), dev, bt_ids) == 0 ||
+	    device_get_unit(dev) != 0)
+		return (ENXIO);
+
+	device_quiet(dev);
+	device_set_desc(dev, "Toshiba Bluetooth");
+	return (0);
+}
+
+static int
+acpi_toshiba_bt_attach(device_t dev)
+{
+	struct		acpi_toshiba_softc *sc;
+
+	sc = devclass_get_softc(acpi_toshiba_devclass, 0);
+	if (sc == NULL)
+		return (ENXIO);
+	sc->bt_handle = acpi_get_handle(dev);
+	AcpiInstallNotifyHandler(sc->bt_handle, ACPI_DEVICE_NOTIFY,
+	    acpi_toshiba_bt_notify, sc);
+	return (0);
+}
+
+static int
+acpi_toshiba_bt_detach(device_t dev)
+{
+	struct		acpi_toshiba_softc *sc;
+
+	sc = device_get_softc(dev);
+	AcpiRemoveNotifyHandler(sc->bt_handle, ACPI_DEVICE_NOTIFY,
+	    acpi_toshiba_bt_notify);
+
+	return (0);
+}
+
+static int
+acpi_toshiba_bt_enable(device_t dev)
+{
+	struct acpi_toshiba_softc *sc;
+	ACPI_STATUS	status;
+
+	sc = device_get_softc(dev);
+	status = AcpiEvaluateObject(sc->bt_handle, "AUSB", NULL, NULL);
+	if (ACPI_FAILURE(status)) {
+		device_printf(dev, "failed to attach bluetooth (AUSB)\n");
+		return (status);
+	}
+	status = AcpiEvaluateObject(sc->bt_handle, "BTPO", NULL, NULL);
+	if (ACPI_FAILURE(status))
+		device_printf(dev, "failed to power on bluetooth (BTPO)\n");
+
+	return (status);
+}
+
+static void
+acpi_toshiba_bt_notify(ACPI_HANDLE h, UINT32 notify, void *context)
+{
+	struct acpi_toshiba_softc *sc;
+
+	sc = (struct acpi_toshiba_softc *)context;
+
+	switch (notify) {
+	case 0x90:
+		acpi_toshiba_bt_enable(sc->dev);
+		break;
+	default:
+		device_printf(sc->dev, "unknown notify: %#x\n", notify);
+		break;
+	}
+}
+
+/*
  * Toshiba video pseudo-device to provide the DSSX method.
  *
  * HID      Model
@@ -542,7 +653,7 @@ acpi_toshiba_notify(ACPI_HANDLE h, UINT32 notify, void *context)
 static int
 acpi_toshiba_video_probe(device_t dev)
 {
-	static char *vid_ids[] = { "TOS6201", NULL };
+	static char	*vid_ids[] = { "TOS6201", NULL };
 
 	if (acpi_disabled("toshiba") ||
 	    ACPI_ID_PROBE(device_get_parent(dev), dev, vid_ids) == NULL ||
-- 
2.6.4

