all rfkill key events and will toggle the radio accordingly.  With this option
 enabled userspace could either do nothing or simply perform monitoring tasks.
 
-When a rfkill switch is in the RFKILL_STATE_ON, the wireless transmitter (radio
-TX circuit for example) is *enabled*.  When the rfkill switch is in the
-RFKILL_STATE_OFF, the wireless transmitter is to be *blocked* from operating.
+When a rfkill switch is in the RFKILL_STATE_UNBLOCKED, the wireless transmitter
+(radio TX circuit for example) is *enabled*.  When the rfkill switch is in the
+RFKILL_STATE_SOFT_BLOCKED or RFKILL_STATE_HARD_BLOCKED, the wireless
+transmitter is to be *blocked* from operating.
+
+RFKILL_STATE_SOFT_BLOCKED indicates that a call to toggle_radio() can change
+that state.  RFKILL_STATE_HARD_BLOCKED indicates that a call to toggle_radio()
+will not be able to change the state and will return with a suitable error if
+attempts are made to set the state to RFKILL_STATE_UNBLOCKED.
+
+RFKILL_STATE_HARD_BLOCKED is used by drivers to signal that the device is
+locked in the BLOCKED state by a hardwire rfkill line (typically an input pin
+that, when active, forces the transmitter to be disabled) which the driver
+CANNOT override.
 
 Full rfkill functionality requires two different subsystems to cooperate: the
 input layer and the rfkill class.  The input layer issues *commands* to the
          action).
        * rfkill-input implements EPO by handling EV_SW SW_RFKILL_ALL 0
          (power off all transmitters) in a special way: it ignores any
-         overrides and local state cache and forces all transmitters to
-         the OFF state (including those which are already supposed to be
-         OFF).  Note that the opposite event (power on all transmitters)
-         is handled normally.
+         overrides and local state cache and forces all transmitters to the
+         RFKILL_STATE_SOFT_BLOCKED state (including those which are already
+         supposed to be BLOCKED).  Note that the opposite event (power on all
+         transmitters) is handled normally.
 
 Userspace uevent handler or kernel platform-specific drivers hooked to the
 rfkill notifier chain:
          YOU CAN ACCESS state DIRECTLY)
        - rfkill_register()
 
+The only way to set a device to the RFKILL_STATE_HARD_BLOCKED state is through
+a suitable return of get_state() or through rfkill_force_state().
+
+When a device is in the RFKILL_STATE_HARD_BLOCKED state, the only way to switch
+it to a different state is through a suitable return of get_state() or through
+rfkill_force_state().
+
+If toggle_radio() is called to set a device to state RFKILL_STATE_SOFT_BLOCKED
+when that device is already at the RFKILL_STATE_HARD_BLOCKED state, it should
+not return an error.  Instead, it should try to double-block the transmitter,
+so that its state will change from RFKILL_STATE_HARD_BLOCKED to
+RFKILL_STATE_SOFT_BLOCKED should the hardware blocking cease.
+
 Please refer to the source for more documentation.
 
 ===============================================================================
 
 Take particular care to implement EV_SW SW_RFKILL_ALL properly.  When that
 switch is set to OFF, *every* rfkill device *MUST* be immediately put into the
-OFF state, no questions asked.
+RFKILL_STATE_SOFT_BLOCKED state, no questions asked.
 
 The following sysfs entries will be created:
 
        name: Name assigned by driver to this key (interface or driver name).
        type: Name of the key type ("wlan", "bluetooth", etc).
-       state: Current state of the key. 1: On, 0: Off.
+       state: Current state of the transmitter
+               0: RFKILL_STATE_SOFT_BLOCKED
+                       transmitter is forced off, but you can override it
+                       by a write to the state attribute, or through input
+                       events (if rfkill-input is loaded).
+               1: RFKILL_STATE_UNBLOCKED
+                       transmiter is NOT forced off, and may operate if
+                       all other conditions for such operation are met
+                       (such as interface is up and configured, etc).
+               2: RFKILL_STATE_HARD_BLOCKED
+                       transmitter is forced off by something outside of
+                       the driver's control.
+
+                       You cannot set a device to this state through
+                       writes to the state attribute.
        claim: 1: Userspace handles events, 0: Kernel handles events
 
 Both the "state" and "claim" entries are also writable. For the "state" entry
 
 };
 
 enum rfkill_state {
-       RFKILL_STATE_OFF        = 0,    /* Radio output blocked */
-       RFKILL_STATE_ON         = 1,    /* Radio output active */
+       RFKILL_STATE_SOFT_BLOCKED = 0,  /* Radio output blocked */
+       RFKILL_STATE_UNBLOCKED    = 1,  /* Radio output allowed */
+       RFKILL_STATE_HARD_BLOCKED = 2,  /* Output blocked, non-overrideable */
 };
 
+/*
+ * These are DEPRECATED, drivers using them should be verified to
+ * comply with the rfkill usage guidelines in Documentation/rfkill.txt
+ * and then converted to use the new names for rfkill_state
+ */
+#define RFKILL_STATE_OFF RFKILL_STATE_SOFT_BLOCKED
+#define RFKILL_STATE_ON  RFKILL_STATE_UNBLOCKED
+
 /**
  * struct rfkill - rfkill control structure.
  * @name: Name of the switch.
  * @type: Radio type which the button controls, the value stored
  *     here should be a value from enum rfkill_type.
- * @state: State of the switch, "ON" means radio can operate.
+ * @state: State of the switch, "UNBLOCKED" means radio can operate.
  * @user_claim_unsupported: Whether the hardware supports exclusive
  *     RF-kill control by userspace. Set this before registering.
  * @user_claim: Set when the switch is controlled exlusively by userspace.
  * @data: Pointer to the RF button drivers private data which will be
  *     passed along when toggling radio state.
  * @toggle_radio(): Mandatory handler to control state of the radio.
+ *     only RFKILL_STATE_SOFT_BLOCKED and RFKILL_STATE_UNBLOCKED are
+ *     valid parameters.
  * @get_state(): handler to read current radio state from hardware,
  *      may be called from atomic context, should return 0 on success.
+ *      Either this handler OR judicious use of rfkill_force_state() is
+ *      MANDATORY for any driver capable of RFKILL_STATE_HARD_BLOCKED.
  * @led_trigger: A LED trigger for this button's LED.
  * @dev: Device structure integrating the switch into device tree.
  * @node: Used to place switch into list of all switches known to the
 
 int rfkill_force_state(struct rfkill *rfkill, enum rfkill_state state);
 
+/**
+ * rfkill_state_complement - return complementar state
+ * @state: state to return the complement of
+ *
+ * Returns RFKILL_STATE_SOFT_BLOCKED if @state is RFKILL_STATE_UNBLOCKED,
+ * returns RFKILL_STATE_UNBLOCKED otherwise.
+ */
+static inline enum rfkill_state rfkill_state_complement(enum rfkill_state state)
+{
+       return (state == RFKILL_STATE_UNBLOCKED) ?
+               RFKILL_STATE_SOFT_BLOCKED : RFKILL_STATE_UNBLOCKED;
+}
+
 /**
  * rfkill_get_led_name - Get the LED trigger name for the button's LED.
  * This function might return a NULL pointer if registering of the
 
        spin_lock_irqsave(&task->lock, flags);
 
        if (time_after(jiffies, task->last + msecs_to_jiffies(200))) {
-               task->desired_state = !task->desired_state;
+               task->desired_state =
+                               rfkill_state_complement(task->desired_state);
                task->last = jiffies;
                schedule_work(&task->work);
        }
        spin_unlock_irqrestore(&task->lock, flags);
 }
 
-#define DEFINE_RFKILL_TASK(n, t)                       \
-       struct rfkill_task n = {                        \
-               .work = __WORK_INITIALIZER(n.work,      \
-                               rfkill_task_handler),   \
-               .type = t,                              \
-               .mutex = __MUTEX_INITIALIZER(n.mutex),  \
-               .lock = __SPIN_LOCK_UNLOCKED(n.lock),   \
-               .desired_state = RFKILL_STATE_ON,       \
+#define DEFINE_RFKILL_TASK(n, t)                               \
+       struct rfkill_task n = {                                \
+               .work = __WORK_INITIALIZER(n.work,              \
+                               rfkill_task_handler),           \
+               .type = t,                                      \
+               .mutex = __MUTEX_INITIALIZER(n.mutex),          \
+               .lock = __SPIN_LOCK_UNLOCKED(n.lock),           \
+               .desired_state = RFKILL_STATE_UNBLOCKED,        \
        }
 
 static DEFINE_RFKILL_TASK(rfkill_wlan, RFKILL_TYPE_WLAN);
                        /* handle EPO (emergency power off) through shortcut */
                        if (data) {
                                rfkill_schedule_set(&rfkill_wwan,
-                                                   RFKILL_STATE_ON);
+                                                   RFKILL_STATE_UNBLOCKED);
                                rfkill_schedule_set(&rfkill_wimax,
-                                                   RFKILL_STATE_ON);
+                                                   RFKILL_STATE_UNBLOCKED);
                                rfkill_schedule_set(&rfkill_uwb,
-                                                   RFKILL_STATE_ON);
+                                                   RFKILL_STATE_UNBLOCKED);
                                rfkill_schedule_set(&rfkill_bt,
-                                                   RFKILL_STATE_ON);
+                                                   RFKILL_STATE_UNBLOCKED);
                                rfkill_schedule_set(&rfkill_wlan,
-                                                   RFKILL_STATE_ON);
+                                                   RFKILL_STATE_UNBLOCKED);
                        } else
                                rfkill_schedule_epo();
                        break;
 
 static LIST_HEAD(rfkill_list); /* list of registered rf switches */
 static DEFINE_MUTEX(rfkill_mutex);
 
-static unsigned int rfkill_default_state = RFKILL_STATE_ON;
+static unsigned int rfkill_default_state = RFKILL_STATE_UNBLOCKED;
 module_param_named(default_state, rfkill_default_state, uint, 0444);
 MODULE_PARM_DESC(default_state,
                 "Default initial state for all radio types, 0 = radio off");
 
        if (!led->name)
                return;
-       if (state == RFKILL_STATE_OFF)
+       if (state != RFKILL_STATE_UNBLOCKED)
                led_trigger_event(led, LED_OFF);
        else
                led_trigger_event(led, LED_FULL);
        }
 }
 
+/**
+ * rfkill_toggle_radio - wrapper for toggle_radio hook
+ * calls toggle_radio taking into account a lot of "small"
+ * details.
+ * @rfkill: the rfkill struct to use
+ * @force: calls toggle_radio even if cache says it is not needed,
+ *     and also makes sure notifications of the state will be
+ *     sent even if it didn't change
+ * @state: the new state to call toggle_radio() with
+ *
+ * This wrappen protects and enforces the API for toggle_radio
+ * calls.  Note that @force cannot override a (possibly cached)
+ * state of RFKILL_STATE_HARD_BLOCKED.  Any device making use of
+ * RFKILL_STATE_HARD_BLOCKED implements either get_state() or
+ * rfkill_force_state(), so the cache either is bypassed or valid.
+ *
+ * Note that we do call toggle_radio for RFKILL_STATE_SOFT_BLOCKED
+ * even if the radio is in RFKILL_STATE_HARD_BLOCKED state, so as to
+ * give the driver a hint that it should double-BLOCK the transmitter.
+ *
+ * Caller must have aquired rfkill_mutex.
+ */
 static int rfkill_toggle_radio(struct rfkill *rfkill,
                                enum rfkill_state state,
                                int force)
            !rfkill->get_state(rfkill->data, &newstate))
                rfkill->state = newstate;
 
+       switch (state) {
+       case RFKILL_STATE_HARD_BLOCKED:
+               /* typically happens when refreshing hardware state,
+                * such as on resume */
+               state = RFKILL_STATE_SOFT_BLOCKED;
+               break;
+       case RFKILL_STATE_UNBLOCKED:
+               /* force can't override this, only rfkill_force_state() can */
+               if (rfkill->state == RFKILL_STATE_HARD_BLOCKED)
+                       return -EPERM;
+               break;
+       case RFKILL_STATE_SOFT_BLOCKED:
+               /* nothing to do, we want to give drivers the hint to double
+                * BLOCK even a transmitter that is already in state
+                * RFKILL_STATE_HARD_BLOCKED */
+               break;
+       }
+
        if (force || state != rfkill->state) {
                retval = rfkill->toggle_radio(rfkill->data, state);
-               if (!retval)
+               /* never allow a HARD->SOFT downgrade! */
+               if (!retval && rfkill->state != RFKILL_STATE_HARD_BLOCKED)
                        rfkill->state = state;
        }
 
 /**
  * rfkill_epo - emergency power off all transmitters
  *
- * This kicks all rfkill devices to RFKILL_STATE_OFF, ignoring
+ * This kicks all rfkill devices to RFKILL_STATE_SOFT_BLOCKED, ignoring
  * everything in its path but rfkill_mutex.
  */
 void rfkill_epo(void)
 
        mutex_lock(&rfkill_mutex);
        list_for_each_entry(rfkill, &rfkill_list, node) {
-               rfkill_toggle_radio(rfkill, RFKILL_STATE_OFF, 1);
+               rfkill_toggle_radio(rfkill, RFKILL_STATE_SOFT_BLOCKED, 1);
        }
        mutex_unlock(&rfkill_mutex);
 }
 {
        enum rfkill_state oldstate;
 
-       if (state != RFKILL_STATE_OFF &&
-           state != RFKILL_STATE_ON)
+       if (state != RFKILL_STATE_SOFT_BLOCKED &&
+           state != RFKILL_STATE_UNBLOCKED &&
+           state != RFKILL_STATE_HARD_BLOCKED)
                return -EINVAL;
 
        mutex_lock(&rfkill->mutex);
        if (!capable(CAP_NET_ADMIN))
                return -EPERM;
 
+       /* RFKILL_STATE_HARD_BLOCKED is illegal here... */
+       if (state != RFKILL_STATE_UNBLOCKED &&
+           state != RFKILL_STATE_SOFT_BLOCKED)
+               return -EINVAL;
+
        if (mutex_lock_interruptible(&rfkill->mutex))
                return -ERESTARTSYS;
-       error = rfkill_toggle_radio(rfkill,
-                       state ? RFKILL_STATE_ON : RFKILL_STATE_OFF,
-                       0);
+       error = rfkill_toggle_radio(rfkill, state, 0);
        mutex_unlock(&rfkill->mutex);
 
        return error ? error : count;
                        update_rfkill_state(rfkill);
 
                        mutex_lock(&rfkill->mutex);
-                       rfkill->toggle_radio(rfkill->data, RFKILL_STATE_OFF);
+                       rfkill->toggle_radio(rfkill->data,
+                                               RFKILL_STATE_SOFT_BLOCKED);
                        mutex_unlock(&rfkill->mutex);
                }
 
 {
        mutex_lock(&rfkill_mutex);
        list_del_init(&rfkill->node);
-       rfkill_toggle_radio(rfkill, RFKILL_STATE_OFF, 1);
+       rfkill_toggle_radio(rfkill, RFKILL_STATE_SOFT_BLOCKED, 1);
        mutex_unlock(&rfkill_mutex);
 }
 
        int error;
        int i;
 
-       if (rfkill_default_state != RFKILL_STATE_OFF &&
-           rfkill_default_state != RFKILL_STATE_ON)
+       /* RFKILL_STATE_HARD_BLOCKED is illegal here... */
+       if (rfkill_default_state != RFKILL_STATE_SOFT_BLOCKED &&
+           rfkill_default_state != RFKILL_STATE_UNBLOCKED)
                return -EINVAL;
 
        for (i = 0; i < ARRAY_SIZE(rfkill_states); i++)