NFC: RFKILL support
authorSamuel Ortiz <sameo@linux.intel.com>
Thu, 11 Apr 2013 09:52:20 +0000 (11:52 +0200)
committerSamuel Ortiz <sameo@linux.intel.com>
Fri, 12 Apr 2013 14:54:45 +0000 (16:54 +0200)
All NFC devices will now get proper RFKILL support as long as they provide
some dev_up and dev_down hooks. Rfkilling an NFC device will bring it down
while it is left to userspace to bring it back up when being rfkill unblocked.
This is very similar to what Bluetooth does.

Acked-by: Marcel Holtmann <marcel@holtmann.org>
Signed-off-by: Samuel Ortiz <sameo@linux.intel.com>
include/net/nfc/nfc.h
net/nfc/core.c

index 87a6417fc934487acb2c734f53af3b78fb09d013..5eb80bb3cbb233f02401cec1f1ee8103119f3da0 100644 (file)
@@ -122,6 +122,8 @@ struct nfc_dev {
 
        bool shutting_down;
 
+       struct rfkill *rfkill;
+
        struct nfc_ops *ops;
 };
 #define to_nfc_dev(_dev) container_of(_dev, struct nfc_dev, dev)
index c571ca9a960cfe29b54d5bcac9d8fe524fb33cdd..40d2527693da8170b4edd9d0d50837255387f1eb 100644 (file)
@@ -27,6 +27,7 @@
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/slab.h>
+#include <linux/rfkill.h>
 #include <linux/nfc.h>
 
 #include <net/genetlink.h>
@@ -58,6 +59,11 @@ int nfc_dev_up(struct nfc_dev *dev)
 
        device_lock(&dev->dev);
 
+       if (dev->rfkill && rfkill_blocked(dev->rfkill)) {
+               rc = -ERFKILL;
+               goto error;
+       }
+
        if (!device_is_registered(&dev->dev)) {
                rc = -ENODEV;
                goto error;
@@ -117,6 +123,24 @@ error:
        return rc;
 }
 
+static int nfc_rfkill_set_block(void *data, bool blocked)
+{
+       struct nfc_dev *dev = data;
+
+       pr_debug("%s blocked %d", dev_name(&dev->dev), blocked);
+
+       if (!blocked)
+               return 0;
+
+       nfc_dev_down(dev);
+
+       return 0;
+}
+
+static const struct rfkill_ops nfc_rfkill_ops = {
+       .set_block = nfc_rfkill_set_block,
+};
+
 /**
  * nfc_start_poll - start polling for nfc targets
  *
@@ -840,6 +864,15 @@ int nfc_register_device(struct nfc_dev *dev)
                pr_debug("The userspace won't be notified that the device %s was added\n",
                         dev_name(&dev->dev));
 
+       dev->rfkill = rfkill_alloc(dev_name(&dev->dev), &dev->dev,
+                                  RFKILL_TYPE_NFC, &nfc_rfkill_ops, dev);
+       if (dev->rfkill) {
+               if (rfkill_register(dev->rfkill) < 0) {
+                       rfkill_destroy(dev->rfkill);
+                       dev->rfkill = NULL;
+               }
+       }
+
        return 0;
 }
 EXPORT_SYMBOL(nfc_register_device);
@@ -857,6 +890,11 @@ void nfc_unregister_device(struct nfc_dev *dev)
 
        id = dev->idx;
 
+       if (dev->rfkill) {
+               rfkill_unregister(dev->rfkill);
+               rfkill_destroy(dev->rfkill);
+       }
+
        if (dev->ops->check_presence) {
                device_lock(&dev->dev);
                dev->shutting_down = true;