[PATCH] dell-rbtn: add keycode for Dell's toggle switch

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



When Method(CRBT) returns 0 and 1, BIOS will not change hardware pin. As a
result, a keycode KEY_RFKILL is required when wireless hotkey is pressed.

Signed-off-by: Alex Hung <alex.hung@xxxxxxxxxxxxx>
---
 drivers/platform/x86/dell-rbtn.c |   99 ++++++++++++++++++++++++++++++++++++--
 1 file changed, 94 insertions(+), 5 deletions(-)

diff --git a/drivers/platform/x86/dell-rbtn.c b/drivers/platform/x86/dell-rbtn.c
index 69c17e8..517747b 100644
--- a/drivers/platform/x86/dell-rbtn.c
+++ b/drivers/platform/x86/dell-rbtn.c
@@ -16,22 +16,73 @@
 #include <linux/module.h>
 #include <linux/acpi.h>
 #include <linux/rfkill.h>
+#include <linux/input.h>
 
 /*** helper functions ***/
 
+enum wireless_config_type {
+	DELL_TOGGLE_SWITCH,
+	DELL_SLIDER_SWITCH
+};
+
+static int switch_type;
+static struct input_dev *dellwl_input_dev;
+
+static int dell_wireless_input_setup(void)
+{
+	int err;
+
+	dellwl_input_dev = input_allocate_device();
+	if (!dellwl_input_dev)
+		return -ENOMEM;
+
+	dellwl_input_dev->name = "DELL Wireless hotkeys";
+	dellwl_input_dev->phys = "dellabce/input0";
+	dellwl_input_dev->id.bustype = BUS_HOST;
+	dellwl_input_dev->evbit[0] = BIT(EV_KEY);
+	set_bit(KEY_RFKILL, dellwl_input_dev->keybit);
+
+	err = input_register_device(dellwl_input_dev);
+	if (err)
+		goto err_free_dev;
+
+	return 0;
+
+err_free_dev:
+	input_free_device(dellwl_input_dev);
+	return err;
+}
+
+static void dell_wireless_input_destroy(void)
+{
+	input_unregister_device(dellwl_input_dev);
+}
 static int rbtn_check(struct acpi_device *device)
 {
 	acpi_status status;
 	unsigned long long output;
+	int err = 0;
 
 	status = acpi_evaluate_integer(device->handle, "CRBT", NULL, &output);
+	pr_info("switch type = %x\n", switch_type);
 	if (ACPI_FAILURE(status))
 		return -EINVAL;
 
-	if (output > 3)
-		return -EINVAL;
+	switch (output) {
+	case 0:
+	case 1:
+		switch_type = DELL_TOGGLE_SWITCH;
+		err = dell_wireless_input_setup();
+		break;
+	case 2:
+	case 3:
+		switch_type = DELL_SLIDER_SWITCH;
+		break;
+	default:
+		err = -EINVAL;
+	}
 
-	return 0;
+	return err;
 }
 
 
@@ -198,6 +249,20 @@ EXPORT_SYMBOL_GPL(dell_rbtn_notifier_unregister);
 
 /*** acpi driver functions ***/
 
+static int rbtn_radio_switch_enable(struct acpi_device *device, int enable)
+{
+	acpi_status status;
+	union acpi_object arg0 = { ACPI_TYPE_INTEGER };
+	struct acpi_object_list args = { 1, &arg0 };
+
+	arg0.integer.value = enable;
+	status = acpi_evaluate_object(device->handle, "ARBT", &args, NULL);
+	if (!ACPI_SUCCESS(status))
+		return -EINVAL;
+
+	return 0;
+}
+
 static int rbtn_add(struct acpi_device *device)
 {
 	int ret;
@@ -209,12 +274,27 @@ static int rbtn_add(struct acpi_device *device)
 	if (auto_remove_rfkill && rbtn_chain_head.head)
 		return 0;
 
+
+	ret = rbtn_radio_switch_enable(device, 1);
+	if (ret < 0)
+		return ret;
+
 	return rbtn_enable(device);
 }
 
 static int rbtn_remove(struct acpi_device *device)
 {
+	int ret;
+
+	if (switch_type == DELL_TOGGLE_SWITCH)
+		dell_wireless_input_destroy();
+
 	rbtn_disable(device);
+
+	ret = rbtn_radio_switch_enable(device, 0);
+	if (ret < 0)
+		return ret;
+
 	return 0;
 }
 
@@ -222,8 +302,17 @@ static void rbtn_notify(struct acpi_device *device, u32 event)
 {
 	struct rfkill *rfkill = device->driver_data;
 
-	if (rfkill && event == 0x80)
-		rbtn_query(rfkill, device);
+	if (event == 0x80) {
+		if (rfkill)
+			rbtn_query(rfkill, device);
+
+		if (switch_type == DELL_TOGGLE_SWITCH) {
+			input_report_key(dellwl_input_dev, KEY_RFKILL, 1);
+			input_sync(dellwl_input_dev);
+			input_report_key(dellwl_input_dev, KEY_RFKILL, 0);
+			input_sync(dellwl_input_dev);
+		}
+	}
 
 	if (!rbtn_chain_head.head && event != 0x80)
 		dev_info(&device->dev, "Received unknown event (0x%x)\n", event);
-- 
1.7.9.5

--
To unsubscribe from this list: send the line "unsubscribe platform-driver-x86" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html




[Index of Archives]     [Linux Kernel Development]     [Linux USB Devel]     [Video for Linux]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]

  Powered by Linux