Merge tag 'nfc-next-3.9-1' of git://git.kernel.org/pub/scm/linux/kernel/git/sameo...
[firefly-linux-kernel-4.4.55.git] / net / nfc / core.c
index aa64ea441676a1ce9fc8c2417cc4487eaecf2cec..25522e56d3507645e6aa4d89bc692da91263dad9 100644 (file)
@@ -338,7 +338,7 @@ int nfc_activate_target(struct nfc_dev *dev, u32 target_idx, u32 protocol)
                dev->active_target = target;
                dev->rf_mode = NFC_RF_INITIATOR;
 
-               if (dev->ops->check_presence)
+               if (dev->ops->check_presence && !dev->shutting_down)
                        mod_timer(&dev->check_pres_timer, jiffies +
                                  msecs_to_jiffies(NFC_CHECK_PRES_FREQ_MS));
        }
@@ -429,7 +429,7 @@ int nfc_data_exchange(struct nfc_dev *dev, u32 target_idx, struct sk_buff *skb,
                rc = dev->ops->im_transceive(dev, dev->active_target, skb, cb,
                                             cb_context);
 
-               if (!rc && dev->ops->check_presence)
+               if (!rc && dev->ops->check_presence && !dev->shutting_down)
                        mod_timer(&dev->check_pres_timer, jiffies +
                                  msecs_to_jiffies(NFC_CHECK_PRES_FREQ_MS));
        } else if (dev->rf_mode == NFC_RF_TARGET && dev->ops->tm_send != NULL) {
@@ -684,11 +684,6 @@ static void nfc_release(struct device *d)
 
        pr_debug("dev_name=%s\n", dev_name(&dev->dev));
 
-       if (dev->ops->check_presence) {
-               del_timer_sync(&dev->check_pres_timer);
-               cancel_work_sync(&dev->check_pres_work);
-       }
-
        nfc_genl_data_exit(&dev->genl_data);
        kfree(dev->targets);
        kfree(dev);
@@ -706,15 +701,16 @@ static void nfc_check_pres_work(struct work_struct *work)
                rc = dev->ops->check_presence(dev, dev->active_target);
                if (rc == -EOPNOTSUPP)
                        goto exit;
-               if (!rc) {
-                       mod_timer(&dev->check_pres_timer, jiffies +
-                                 msecs_to_jiffies(NFC_CHECK_PRES_FREQ_MS));
-               } else {
+               if (rc) {
                        u32 active_target_idx = dev->active_target->idx;
                        device_unlock(&dev->dev);
                        nfc_target_lost(dev, active_target_idx);
                        return;
                }
+
+               if (!dev->shutting_down)
+                       mod_timer(&dev->check_pres_timer, jiffies +
+                                 msecs_to_jiffies(NFC_CHECK_PRES_FREQ_MS));
        }
 
 exit:
@@ -761,6 +757,7 @@ struct nfc_dev *nfc_get_device(unsigned int idx)
  */
 struct nfc_dev *nfc_allocate_device(struct nfc_ops *ops,
                                    u32 supported_protocols,
+                                   u32 supported_se,
                                    int tx_headroom, int tx_tailroom)
 {
        struct nfc_dev *dev;
@@ -778,6 +775,8 @@ struct nfc_dev *nfc_allocate_device(struct nfc_ops *ops,
 
        dev->ops = ops;
        dev->supported_protocols = supported_protocols;
+       dev->supported_se = supported_se;
+       dev->active_se = NFC_SE_NONE;
        dev->tx_headroom = tx_headroom;
        dev->tx_tailroom = tx_tailroom;
 
@@ -853,26 +852,27 @@ void nfc_unregister_device(struct nfc_dev *dev)
 
        id = dev->idx;
 
-       mutex_lock(&nfc_devlist_mutex);
-       nfc_devlist_generation++;
-
-       /* lock to avoid unregistering a device while an operation
-          is in progress */
-       device_lock(&dev->dev);
-       device_del(&dev->dev);
-       device_unlock(&dev->dev);
+       if (dev->ops->check_presence) {
+               device_lock(&dev->dev);
+               dev->shutting_down = true;
+               device_unlock(&dev->dev);
+               del_timer_sync(&dev->check_pres_timer);
+               cancel_work_sync(&dev->check_pres_work);
+       }
 
-       mutex_unlock(&nfc_devlist_mutex);
+       rc = nfc_genl_device_removed(dev);
+       if (rc)
+               pr_debug("The userspace won't be notified that the device %s "
+                        "was removed\n", dev_name(&dev->dev));
 
        nfc_llcp_unregister_device(dev);
 
-       rc = nfc_genl_device_removed(dev);
-       if (rc)
-               pr_debug("The userspace won't be notified that the device %s was removed\n",
-                        dev_name(&dev->dev));
+       mutex_lock(&nfc_devlist_mutex);
+       nfc_devlist_generation++;
+       device_del(&dev->dev);
+       mutex_unlock(&nfc_devlist_mutex);
 
        ida_simple_remove(&nfc_index_ida, id);
-
 }
 EXPORT_SYMBOL(nfc_unregister_device);