Jesse Keating 2f82dda
diff --git a/drivers/input/input.c b/drivers/input/input.c
Jesse Keating 2f82dda
index 7c237e6..80f1e48 100644
Jesse Keating 2f82dda
--- a/drivers/input/input.c
Jesse Keating 2f82dda
+++ b/drivers/input/input.c
Jesse Keating 2f82dda
@@ -88,19 +88,26 @@ static int input_defuzz_abs_event(int value, int old_val, int fuzz)
Jesse Keating 2f82dda
  */
Jesse Keating 2f82dda
 static void input_pass_event(struct input_dev *dev,
Jesse Keating 2f82dda
 			     unsigned int type, unsigned int code, int value)
Jesse Keating 2f82dda
-{
Jesse Keating 2f82dda
-	struct input_handle *handle;
Jesse Keating 2f82dda
+
Jesse Keating 2f82dda
+{	struct input_handle *handle;
Jesse Keating 2f82dda
 
Jesse Keating 2f82dda
 	rcu_read_lock();
Jesse Keating 2f82dda
 
Jesse Keating 2f82dda
 	handle = rcu_dereference(dev->grab);
Jesse Keating 2f82dda
-	if (handle)
Jesse Keating 2f82dda
+	if (handle) {
Jesse Keating 2f82dda
 		handle->handler->event(handle, type, code, value);
Jesse Keating 2f82dda
-	else
Jesse Keating 2f82dda
-		list_for_each_entry_rcu(handle, &dev->h_list, d_node)
Jesse Keating 2f82dda
-			if (handle->open)
Jesse Keating 2f82dda
-				handle->handler->event(handle,
Jesse Keating 2f82dda
-							type, code, value);
Jesse Keating 2f82dda
+		goto out;
Jesse Keating 2f82dda
+	}
Jesse Keating 2f82dda
+
Jesse Keating 2f82dda
+	handle = rcu_dereference(dev->filter);
Jesse Keating 2f82dda
+	if (handle && handle->handler->filter(handle, type, code, value))
Jesse Keating 2f82dda
+		goto out;
Jesse Keating 2f82dda
+
Jesse Keating 2f82dda
+	list_for_each_entry_rcu(handle, &dev->h_list, d_node)
Jesse Keating 2f82dda
+		if (handle->open)
Jesse Keating 2f82dda
+			handle->handler->event(handle,
Jesse Keating 2f82dda
+					       type, code, value);
Jesse Keating 2f82dda
+out:
Jesse Keating 2f82dda
 	rcu_read_unlock();
Jesse Keating 2f82dda
 }
Jesse Keating 2f82dda
 
Jesse Keating 2f82dda
@@ -375,12 +382,15 @@ int input_grab_device(struct input_handle *handle)
Jesse Keating 2f82dda
 }
Jesse Keating 2f82dda
 EXPORT_SYMBOL(input_grab_device);
Jesse Keating 2f82dda
 
Jesse Keating 2f82dda
-static void __input_release_device(struct input_handle *handle)
Jesse Keating 2f82dda
+static void __input_release_device(struct input_handle *handle, bool filter)
Jesse Keating 2f82dda
 {
Jesse Keating 2f82dda
 	struct input_dev *dev = handle->dev;
Jesse Keating 2f82dda
 
Jesse Keating 2f82dda
-	if (dev->grab == handle) {
Jesse Keating 2f82dda
-		rcu_assign_pointer(dev->grab, NULL);
Jesse Keating 2f82dda
+	if (handle == (filter ? dev->filter : dev->grab)) {
Jesse Keating 2f82dda
+		if (filter)
Jesse Keating 2f82dda
+			rcu_assign_pointer(dev->filter, NULL);
Jesse Keating 2f82dda
+		else
Jesse Keating 2f82dda
+			rcu_assign_pointer(dev->grab, NULL);
Jesse Keating 2f82dda
 		/* Make sure input_pass_event() notices that grab is gone */
Jesse Keating 2f82dda
 		synchronize_rcu();
Jesse Keating 2f82dda
 
Jesse Keating 2f82dda
@@ -404,12 +414,65 @@ void input_release_device(struct input_handle *handle)
Jesse Keating 2f82dda
 	struct input_dev *dev = handle->dev;
Jesse Keating 2f82dda
 
Jesse Keating 2f82dda
 	mutex_lock(&dev->mutex);
Jesse Keating 2f82dda
-	__input_release_device(handle);
Jesse Keating 2f82dda
+	__input_release_device(handle, false);
Jesse Keating 2f82dda
 	mutex_unlock(&dev->mutex);
Jesse Keating 2f82dda
 }
Jesse Keating 2f82dda
 EXPORT_SYMBOL(input_release_device);
Jesse Keating 2f82dda
 
Jesse Keating 2f82dda
 /**
Jesse Keating 2f82dda
+ * input_filter_device - allow input events to be filtered from higher layers
Jesse Keating 2f82dda
+ * @handle: input handle that wants to filter the device
Jesse Keating 2f82dda
+ *
Jesse Keating 2f82dda
+ * When a device is filtered by an input handle all events generated by
Jesse Keating 2f82dda
+ * the device are to this handle. If the filter function returns true then
Jesse Keating 2f82dda
+ * the event is discarded rather than being passed to any other input handles,
Jesse Keating 2f82dda
+ * otherwise it is passed to them as normal. Grabs will be handled before
Jesse Keating 2f82dda
+ * filters, so a grabbed device will not deliver events to a filter function.
Jesse Keating 2f82dda
+ */
Jesse Keating 2f82dda
+int input_filter_device(struct input_handle *handle)
Jesse Keating 2f82dda
+{
Jesse Keating 2f82dda
+	struct input_dev *dev = handle->dev;
Jesse Keating 2f82dda
+	int retval;
Jesse Keating 2f82dda
+
Jesse Keating 2f82dda
+	retval = mutex_lock_interruptible(&dev->mutex);
Jesse Keating 2f82dda
+	if (retval)
Jesse Keating 2f82dda
+		return retval;
Jesse Keating 2f82dda
+
Jesse Keating 2f82dda
+	if (dev->filter) {
Jesse Keating 2f82dda
+		retval = -EBUSY;
Jesse Keating 2f82dda
+		goto out;
Jesse Keating 2f82dda
+	}
Jesse Keating 2f82dda
+
Jesse Keating 2f82dda
+	rcu_assign_pointer(dev->filter, handle);
Jesse Keating 2f82dda
+	synchronize_rcu();
Jesse Keating 2f82dda
+
Jesse Keating 2f82dda
+ out:
Jesse Keating 2f82dda
+	mutex_unlock(&dev->mutex);
Jesse Keating 2f82dda
+	return retval;
Jesse Keating 2f82dda
+}
Jesse Keating 2f82dda
+EXPORT_SYMBOL(input_filter_device);
Jesse Keating 2f82dda
+
Jesse Keating 2f82dda
+/**
Jesse Keating 2f82dda
+ * input_unfilter_device - removes a filter from a device
Jesse Keating 2f82dda
+ * @handle: input handle that owns the device
Jesse Keating 2f82dda
+ *
Jesse Keating 2f82dda
+ * Removes the filter from a device so that other input handles can
Jesse Keating 2f82dda
+ * start receiving unfiltered input events. Upon release all handlers
Jesse Keating 2f82dda
+ * attached to the device have their start() method called so they
Jesse Keating 2f82dda
+ * have a change to synchronize device state with the rest of the
Jesse Keating 2f82dda
+ * system.
Jesse Keating 2f82dda
+ */
Jesse Keating 2f82dda
+void input_unfilter_device(struct input_handle *handle)
Jesse Keating 2f82dda
+{
Jesse Keating 2f82dda
+	struct input_dev *dev = handle->dev;
Jesse Keating 2f82dda
+
Jesse Keating 2f82dda
+	mutex_lock(&dev->mutex);
Jesse Keating 2f82dda
+	__input_release_device(handle, true);
Jesse Keating 2f82dda
+	mutex_unlock(&dev->mutex);
Jesse Keating 2f82dda
+}
Jesse Keating 2f82dda
+EXPORT_SYMBOL(input_unfilter_device);
Jesse Keating 2f82dda
+
Jesse Keating 2f82dda
+/**
Jesse Keating 2f82dda
  * input_open_device - open input device
Jesse Keating 2f82dda
  * @handle: handle through which device is being accessed
Jesse Keating 2f82dda
  *
Jesse Keating 2f82dda
@@ -482,7 +545,9 @@ void input_close_device(struct input_handle *handle)
Jesse Keating 2f82dda
 
Jesse Keating 2f82dda
 	mutex_lock(&dev->mutex);
Jesse Keating 2f82dda
 
Jesse Keating 2f82dda
-	__input_release_device(handle);
Jesse Keating 2f82dda
+	/* Release both grabs and filters */
Jesse Keating 2f82dda
+	__input_release_device(handle, false);
Jesse Keating 2f82dda
+	__input_release_device(handle, true);
Jesse Keating 2f82dda
 
Jesse Keating 2f82dda
 	if (!--dev->users && dev->close)
Jesse Keating 2f82dda
 		dev->close(dev);
Jesse Keating 2f82dda
diff --git a/include/linux/input.h b/include/linux/input.h
Jesse Keating 2f82dda
index 8b3bc3e..e28f116 100644
Jesse Keating 2f82dda
--- a/include/linux/input.h
Jesse Keating 2f82dda
+++ b/include/linux/input.h
Jesse Keating 2f82dda
@@ -1118,6 +1118,7 @@ struct input_dev {
Jesse Keating 2f82dda
 	int (*event)(struct input_dev *dev, unsigned int type, unsigned int code, int value);
Jesse Keating 2f82dda
 
Jesse Keating 2f82dda
 	struct input_handle *grab;
Jesse Keating 2f82dda
+	struct input_handle *filter;
Jesse Keating 2f82dda
 
Jesse Keating 2f82dda
 	spinlock_t event_lock;
Jesse Keating 2f82dda
 	struct mutex mutex;
Jesse Keating 2f82dda
@@ -1218,6 +1219,7 @@ struct input_handler {
Jesse Keating 2f82dda
 	void *private;
Jesse Keating 2f82dda
 
Jesse Keating 2f82dda
 	void (*event)(struct input_handle *handle, unsigned int type, unsigned int code, int value);
Jesse Keating 2f82dda
+	bool (*filter)(struct input_handle *handle, unsigned int type, unsigned int code, int value);
Jesse Keating 2f82dda
 	int (*connect)(struct input_handler *handler, struct input_dev *dev, const struct input_device_id *id);
Jesse Keating 2f82dda
 	void (*disconnect)(struct input_handle *handle);
Jesse Keating 2f82dda
 	void (*start)(struct input_handle *handle);
Jesse Keating 2f82dda
@@ -1295,6 +1297,9 @@ void input_unregister_handle(struct input_handle *);
Jesse Keating 2f82dda
 int input_grab_device(struct input_handle *);
Jesse Keating 2f82dda
 void input_release_device(struct input_handle *);
Jesse Keating 2f82dda
 
Jesse Keating 2f82dda
+int input_filter_device(struct input_handle *);
Jesse Keating 2f82dda
+void input_unfilter_device(struct input_handle *);
Jesse Keating 2f82dda
+
Jesse Keating 2f82dda
 int input_open_device(struct input_handle *);
Jesse Keating 2f82dda
 void input_close_device(struct input_handle *);
Jesse Keating 2f82dda
 
Jesse Keating 2f82dda
diff --git a/drivers/platform/x86/dell-laptop.c b/drivers/platform/x86/dell-laptop.c
Jesse Keating 2f82dda
index 74909c4..71a4149 100644
Jesse Keating 2f82dda
--- a/drivers/platform/x86/dell-laptop.c
Jesse Keating 2f82dda
+++ b/drivers/platform/x86/dell-laptop.c
Jesse Keating 2f82dda
@@ -22,6 +22,7 @@
Jesse Keating 2f82dda
 #include <linux/rfkill.h>
Jesse Keating 2f82dda
 #include <linux/power_supply.h>
Jesse Keating 2f82dda
 #include <linux/acpi.h>
Jesse Keating 2f82dda
+#include <linux/input.h>
Jesse Keating 2f82dda
 #include "../../firmware/dcdbas.h"
Jesse Keating 2f82dda
 
Jesse Keating 2f82dda
 #define BRIGHTNESS_TOKEN 0x7d
Jesse Keating 2f82dda
@@ -206,6 +207,16 @@ static const struct rfkill_ops dell_rfkill_ops = {
Jesse Keating 2f82dda
 	.query = dell_rfkill_query,
Jesse Keating 2f82dda
 };
Jesse Keating 2f82dda
 
Jesse Keating 2f82dda
+static void dell_rfkill_update(void)
Jesse Keating 2f82dda
+{
Jesse Keating 2f82dda
+	if (wifi_rfkill)
Jesse Keating 2f82dda
+		dell_rfkill_query(wifi_rfkill, (void *)1);
Jesse Keating 2f82dda
+	if (bluetooth_rfkill)
Jesse Keating 2f82dda
+		dell_rfkill_query(bluetooth_rfkill, (void *)2);
Jesse Keating 2f82dda
+	if (wwan_rfkill)
Jesse Keating 2f82dda
+		dell_rfkill_query(wwan_rfkill, (void *)3);
Jesse Keating 2f82dda
+}
Jesse Keating 2f82dda
+
Jesse Keating 2f82dda
 static int dell_setup_rfkill(void)
Jesse Keating 2f82dda
 {
Jesse Keating 2f82dda
 	struct calling_interface_buffer buffer;
Jesse Keating 2f82dda
@@ -310,6 +321,90 @@ static struct backlight_ops dell_ops = {
Jesse Keating 2f82dda
 	.update_status  = dell_send_intensity,
Jesse Keating 2f82dda
 };
Jesse Keating 2f82dda
 
Jesse Keating 2f82dda
+static const struct input_device_id dell_input_ids[] = {
Jesse Keating 2f82dda
+	{
Jesse Keating 2f82dda
+		.bustype = 0x11,
Jesse Keating 2f82dda
+		.vendor = 0x01,
Jesse Keating 2f82dda
+		.product = 0x01,
Jesse Keating 2f82dda
+		.version = 0xab41,
Jesse Keating 2f82dda
+		.flags = INPUT_DEVICE_ID_MATCH_BUS |
Jesse Keating 2f82dda
+			 INPUT_DEVICE_ID_MATCH_VENDOR |
Jesse Keating 2f82dda
+			 INPUT_DEVICE_ID_MATCH_PRODUCT |
Jesse Keating 2f82dda
+			 INPUT_DEVICE_ID_MATCH_VERSION
Jesse Keating 2f82dda
+	},
Jesse Keating 2f82dda
+	{ },
Jesse Keating 2f82dda
+};
Jesse Keating 2f82dda
+
Jesse Keating 2f82dda
+static bool dell_input_filter(struct input_handle *handle, unsigned int type,
Jesse Keating 2f82dda
+			     unsigned int code, int value)
Jesse Keating 2f82dda
+{
Jesse Keating 2f82dda
+	if (type == EV_KEY && code == KEY_WLAN && value == 1) {
Jesse Keating 2f82dda
+		dell_rfkill_update();
Jesse Keating 2f82dda
+		return 1;
Jesse Keating 2f82dda
+	}
Jesse Keating 2f82dda
+
Jesse Keating 2f82dda
+	return 0;
Jesse Keating 2f82dda
+}
Jesse Keating 2f82dda
+
Jesse Keating 2f82dda
+static void dell_input_event(struct input_handle *handle, unsigned int type,
Jesse Keating 2f82dda
+			     unsigned int code, int value)
Jesse Keating 2f82dda
+{
Jesse Keating 2f82dda
+}
Jesse Keating 2f82dda
+
Jesse Keating 2f82dda
+static int dell_input_connect(struct input_handler *handler,
Jesse Keating 2f82dda
+			      struct input_dev *dev,
Jesse Keating 2f82dda
+			      const struct input_device_id *id)
Jesse Keating 2f82dda
+{
Jesse Keating 2f82dda
+	struct input_handle *handle;
Jesse Keating 2f82dda
+	int error;
Jesse Keating 2f82dda
+
Jesse Keating 2f82dda
+	handle = kzalloc(sizeof(struct input_handle), GFP_KERNEL);
Jesse Keating 2f82dda
+	if (!handle)
Jesse Keating 2f82dda
+		return -ENOMEM;
Jesse Keating 2f82dda
+
Jesse Keating 2f82dda
+	handle->dev = dev;
Jesse Keating 2f82dda
+	handle->handler = handler;
Jesse Keating 2f82dda
+	handle->name = "dell-laptop";
Jesse Keating 2f82dda
+
Jesse Keating 2f82dda
+	error = input_register_handle(handle);
Jesse Keating 2f82dda
+	if (error)
Jesse Keating 2f82dda
+		goto err_free_handle;
Jesse Keating 2f82dda
+
Jesse Keating 2f82dda
+	error = input_open_device(handle);
Jesse Keating 2f82dda
+	if (error)
Jesse Keating 2f82dda
+		goto err_unregister_handle;
Jesse Keating 2f82dda
+
Jesse Keating 2f82dda
+	error = input_filter_device(handle);
Jesse Keating 2f82dda
+	if (error)
Jesse Keating 2f82dda
+		goto err_close_handle;
Jesse Keating 2f82dda
+
Jesse Keating 2f82dda
+	return 0;
Jesse Keating 2f82dda
+
Jesse Keating 2f82dda
+err_close_handle:
Jesse Keating 2f82dda
+	input_close_device(handle);
Jesse Keating 2f82dda
+err_unregister_handle:
Jesse Keating 2f82dda
+	input_unregister_handle(handle);
Jesse Keating 2f82dda
+err_free_handle:
Jesse Keating 2f82dda
+	kfree(handle);
Jesse Keating 2f82dda
+	return error;
Jesse Keating 2f82dda
+}
Jesse Keating 2f82dda
+
Jesse Keating 2f82dda
+static void dell_input_disconnect(struct input_handle *handle)
Jesse Keating 2f82dda
+{
Jesse Keating 2f82dda
+	input_close_device(handle);
Jesse Keating 2f82dda
+	input_unregister_handle(handle);
Jesse Keating 2f82dda
+	kfree(handle);
Jesse Keating 2f82dda
+}
Jesse Keating 2f82dda
+
Jesse Keating 2f82dda
+static struct input_handler dell_input_handler = {
Jesse Keating 2f82dda
+	.name = "dell-laptop",
Jesse Keating 2f82dda
+	.filter = dell_input_filter,
Jesse Keating 2f82dda
+	.event = dell_input_event,
Jesse Keating 2f82dda
+	.connect = dell_input_connect,
Jesse Keating 2f82dda
+	.disconnect = dell_input_disconnect,
Jesse Keating 2f82dda
+	.id_table = dell_input_ids,
Jesse Keating 2f82dda
+};
Jesse Keating 2f82dda
+
Jesse Keating 2f82dda
 static int __init dell_init(void)
Jesse Keating 2f82dda
 {
Jesse Keating 2f82dda
 	struct calling_interface_buffer buffer;
Jesse Keating 2f82dda
@@ -333,6 +428,10 @@ static int __init dell_init(void)
Jesse Keating 2f82dda
 		goto out;
Jesse Keating 2f82dda
 	}
Jesse Keating 2f82dda
 
Jesse Keating 2f82dda
+	if (input_register_handler(&dell_input_handler))
Jesse Keating 2f82dda
+		printk(KERN_INFO
Jesse Keating 2f82dda
+		       "dell-laptop: Could not register input filter\n");
Jesse Keating 2f82dda
+
Jesse Keating 2f82dda
 #ifdef CONFIG_ACPI
Jesse Keating 2f82dda
 	/* In the event of an ACPI backlight being available, don't
Jesse Keating 2f82dda
 	 * register the platform controller.
Jesse Keating 2f82dda
@@ -388,6 +487,7 @@ static void __exit dell_exit(void)
Jesse Keating 2f82dda
 		rfkill_unregister(bluetooth_rfkill);
Jesse Keating 2f82dda
 	if (wwan_rfkill)
Jesse Keating 2f82dda
 		rfkill_unregister(wwan_rfkill);
Jesse Keating 2f82dda
+	input_unregister_handler(&dell_input_handler);
Jesse Keating 2f82dda
 }
Jesse Keating 2f82dda
 
Jesse Keating 2f82dda
 module_init(dell_init);
Jesse Keating 2f82dda
diff --git a/drivers/platform/x86/dell-laptop.c b/drivers/platform/x86/dell-laptop.c
Jesse Keating 2f82dda
index 71a4149..e559fa1 100644
Jesse Keating 2f82dda
--- a/drivers/platform/x86/dell-laptop.c
Jesse Keating 2f82dda
+++ b/drivers/platform/x86/dell-laptop.c
Jesse Keating 2f82dda
@@ -198,8 +198,8 @@ static void dell_rfkill_query(struct rfkill *rfkill, void *data)
Jesse Keating 2f82dda
 	dell_send_request(&buffer, 17, 11);
Jesse Keating 2f82dda
 	status = buffer.output[1];
Jesse Keating 2f82dda
 
Jesse Keating 2f82dda
-	if (status & BIT(bit))
Jesse Keating 2f82dda
-		rfkill_set_hw_state(rfkill, !!(status & BIT(16)));
Jesse Keating 2f82dda
+	rfkill_set_sw_state(rfkill, !!(status & BIT(bit)));
Jesse Keating 2f82dda
+	rfkill_set_hw_state(rfkill, !(status & BIT(16)));
Jesse Keating 2f82dda
 }
Jesse Keating 2f82dda
 
Jesse Keating 2f82dda
 static const struct rfkill_ops dell_rfkill_ops = {
Jesse Keating 2f82dda
-- 
Jesse Keating 2f82dda
1.6.3.3
Jesse Keating 2f82dda