]> git.proxmox.com Git - mirror_ubuntu-bionic-kernel.git/blobdiff - net/rfkill/core.c
rfkill: rfkill_set_block() when suspended nitpick
[mirror_ubuntu-bionic-kernel.git] / net / rfkill / core.c
index 91e9168b5447389d197fb71020181996a8c05579..868d79f8ac1d0181abc95092798ab64259026903 100644 (file)
@@ -57,6 +57,7 @@ struct rfkill {
 
        bool                    registered;
        bool                    suspended;
+       bool                    persistent;
 
        const struct rfkill_ops *ops;
        void                    *data;
@@ -116,11 +117,9 @@ MODULE_PARM_DESC(default_state,
                 "Default initial state for all radio types, 0 = radio off");
 
 static struct {
-       bool cur, def;
+       bool cur, sav;
 } rfkill_global_states[NUM_RFKILL_TYPES];
 
-static unsigned long rfkill_states_default_locked;
-
 static bool rfkill_epo_lock_active;
 
 
@@ -271,6 +270,9 @@ static void rfkill_set_block(struct rfkill *rfkill, bool blocked)
        unsigned long flags;
        int err;
 
+       if (unlikely(rfkill->dev.power.power_state.event & PM_EVENT_SLEEP))
+               return;
+
        /*
         * Some platforms (...!) generate input events which affect the
         * _hard_ kill state -- whenever something tries to change the
@@ -293,9 +295,6 @@ static void rfkill_set_block(struct rfkill *rfkill, bool blocked)
        rfkill->state |= RFKILL_BLOCK_SW_SETCALL;
        spin_unlock_irqrestore(&rfkill->lock, flags);
 
-       if (unlikely(rfkill->dev.power.power_state.event & PM_EVENT_SLEEP))
-               return;
-
        err = rfkill->ops->set_block(rfkill->data, blocked);
 
        spin_lock_irqsave(&rfkill->lock, flags);
@@ -392,7 +391,7 @@ void rfkill_epo(void)
                rfkill_set_block(rfkill, true);
 
        for (i = 0; i < NUM_RFKILL_TYPES; i++) {
-               rfkill_global_states[i].def = rfkill_global_states[i].cur;
+               rfkill_global_states[i].sav = rfkill_global_states[i].cur;
                rfkill_global_states[i].cur = true;
        }
 
@@ -417,7 +416,7 @@ void rfkill_restore_states(void)
 
        rfkill_epo_lock_active = false;
        for (i = 0; i < NUM_RFKILL_TYPES; i++)
-               __rfkill_switch_all(i, rfkill_global_states[i].def);
+               __rfkill_switch_all(i, rfkill_global_states[i].sav);
        mutex_unlock(&rfkill_global_mutex);
 }
 
@@ -464,29 +463,6 @@ bool rfkill_get_global_sw_state(const enum rfkill_type type)
 }
 #endif
 
-void rfkill_set_global_sw_state(const enum rfkill_type type, bool blocked)
-{
-       BUG_ON(type == RFKILL_TYPE_ALL);
-
-       mutex_lock(&rfkill_global_mutex);
-
-       /* don't allow unblock when epo */
-       if (rfkill_epo_lock_active && !blocked)
-               goto out;
-
-       /* too late */
-       if (rfkill_states_default_locked & BIT(type))
-               goto out;
-
-       rfkill_states_default_locked |= BIT(type);
-
-       rfkill_global_states[type].cur = blocked;
-       rfkill_global_states[type].def = blocked;
- out:
-       mutex_unlock(&rfkill_global_mutex);
-}
-EXPORT_SYMBOL(rfkill_set_global_sw_state);
-
 
 bool rfkill_set_hw_state(struct rfkill *rfkill, bool blocked)
 {
@@ -532,13 +508,14 @@ bool rfkill_set_sw_state(struct rfkill *rfkill, bool blocked)
        blocked = blocked || hwblock;
        spin_unlock_irqrestore(&rfkill->lock, flags);
 
-       if (!rfkill->registered)
-               return blocked;
-
-       if (prev != blocked && !hwblock)
-               schedule_work(&rfkill->uevent_work);
+       if (!rfkill->registered) {
+               rfkill->persistent = true;
+       } else {
+               if (prev != blocked && !hwblock)
+                       schedule_work(&rfkill->uevent_work);
 
-       rfkill_led_trigger_event(rfkill);
+               rfkill_led_trigger_event(rfkill);
+       }
 
        return blocked;
 }
@@ -563,13 +540,14 @@ void rfkill_set_states(struct rfkill *rfkill, bool sw, bool hw)
 
        spin_unlock_irqrestore(&rfkill->lock, flags);
 
-       if (!rfkill->registered)
-               return;
-
-       if (swprev != sw || hwprev != hw)
-               schedule_work(&rfkill->uevent_work);
+       if (!rfkill->registered) {
+               rfkill->persistent = true;
+       } else {
+               if (swprev != sw || hwprev != hw)
+                       schedule_work(&rfkill->uevent_work);
 
-       rfkill_led_trigger_event(rfkill);
+               rfkill_led_trigger_event(rfkill);
+       }
 }
 EXPORT_SYMBOL(rfkill_set_states);
 
@@ -750,15 +728,11 @@ static int rfkill_resume(struct device *dev)
        struct rfkill *rfkill = to_rfkill(dev);
        bool cur;
 
-       mutex_lock(&rfkill_global_mutex);
-       cur = rfkill_global_states[rfkill->type].cur;
+       cur = !!(rfkill->state & RFKILL_BLOCK_SW);
        rfkill_set_block(rfkill, cur);
-       mutex_unlock(&rfkill_global_mutex);
 
        rfkill->suspended = false;
 
-       schedule_work(&rfkill->uevent_work);
-
        rfkill_resume_polling(rfkill);
 
        return 0;
@@ -888,15 +862,6 @@ int __must_check rfkill_register(struct rfkill *rfkill)
        dev_set_name(dev, "rfkill%lu", rfkill_no);
        rfkill_no++;
 
-       if (!(rfkill_states_default_locked & BIT(rfkill->type))) {
-               /* first of its kind */
-               BUILD_BUG_ON(NUM_RFKILL_TYPES >
-                       sizeof(rfkill_states_default_locked) * 8);
-               rfkill_states_default_locked |= BIT(rfkill->type);
-               rfkill_global_states[rfkill->type].cur =
-                       rfkill_global_states[rfkill->type].def;
-       }
-
        list_add_tail(&rfkill->node, &rfkill_list);
 
        error = device_add(dev);
@@ -909,16 +874,25 @@ int __must_check rfkill_register(struct rfkill *rfkill)
 
        rfkill->registered = true;
 
-       if (rfkill->ops->poll) {
-               INIT_DELAYED_WORK(&rfkill->poll_work, rfkill_poll);
+       INIT_DELAYED_WORK(&rfkill->poll_work, rfkill_poll);
+       INIT_WORK(&rfkill->uevent_work, rfkill_uevent_work);
+       INIT_WORK(&rfkill->sync_work, rfkill_sync_work);
+
+       if (rfkill->ops->poll)
                schedule_delayed_work(&rfkill->poll_work,
                        round_jiffies_relative(POLL_INTERVAL));
-       }
 
-       INIT_WORK(&rfkill->uevent_work, rfkill_uevent_work);
+       if (!rfkill->persistent || rfkill_epo_lock_active) {
+               schedule_work(&rfkill->sync_work);
+       } else {
+#ifdef CONFIG_RFKILL_INPUT
+               bool soft_blocked = !!(rfkill->state & RFKILL_BLOCK_SW);
+
+               if (!atomic_read(&rfkill_input_disabled))
+                       __rfkill_switch_all(rfkill->type, soft_blocked);
+#endif
+       }
 
-       INIT_WORK(&rfkill->sync_work, rfkill_sync_work);
-       schedule_work(&rfkill->sync_work);
        rfkill_send_events(rfkill, RFKILL_OP_ADD);
 
        mutex_unlock(&rfkill_global_mutex);
@@ -1135,7 +1109,8 @@ static int rfkill_fop_release(struct inode *inode, struct file *file)
 
 #ifdef CONFIG_RFKILL_INPUT
        if (data->input_handler)
-               atomic_dec(&rfkill_input_disabled);
+               if (atomic_dec_return(&rfkill_input_disabled) == 0)
+                       printk(KERN_DEBUG "rfkill: input handler enabled\n");
 #endif
 
        kfree(data);
@@ -1158,7 +1133,8 @@ static long rfkill_fop_ioctl(struct file *file, unsigned int cmd,
        mutex_lock(&data->mtx);
 
        if (!data->input_handler) {
-               atomic_inc(&rfkill_input_disabled);
+               if (atomic_inc_return(&rfkill_input_disabled) == 1)
+                       printk(KERN_DEBUG "rfkill: input handler disabled\n");
                data->input_handler = true;
        }
 
@@ -1192,7 +1168,7 @@ static int __init rfkill_init(void)
        int i;
 
        for (i = 0; i < NUM_RFKILL_TYPES; i++)
-               rfkill_global_states[i].def = !rfkill_default_state;
+               rfkill_global_states[i].cur = !rfkill_default_state;
 
        error = class_register(&rfkill_class);
        if (error)