|
@@ -1,571 +1,136 @@
|
|
|
-rfkill - RF switch subsystem support
|
|
|
-====================================
|
|
|
+rfkill - RF kill switch support
|
|
|
+===============================
|
|
|
|
|
|
-1 Introduction
|
|
|
-2 Implementation details
|
|
|
-3 Kernel driver guidelines
|
|
|
-3.1 wireless device drivers
|
|
|
-3.2 platform/switch drivers
|
|
|
-3.3 input device drivers
|
|
|
-4 Kernel API
|
|
|
-5 Userspace support
|
|
|
+1. Introduction
|
|
|
+2. Implementation details
|
|
|
+3. Kernel driver guidelines
|
|
|
+4. Kernel API
|
|
|
+5. Userspace support
|
|
|
|
|
|
|
|
|
-1. Introduction:
|
|
|
+1. Introduction
|
|
|
|
|
|
-The rfkill switch subsystem exists to add a generic interface to circuitry that
|
|
|
-can enable or disable the signal output of a wireless *transmitter* of any
|
|
|
-type. By far, the most common use is to disable radio-frequency transmitters.
|
|
|
+The rfkill subsystem provides a generic interface to disabling any radio
|
|
|
+transmitter in the system. When a transmitter is blocked, it shall not
|
|
|
+radiate any power.
|
|
|
|
|
|
-Note that disabling the signal output means that the the transmitter is to be
|
|
|
-made to not emit any energy when "blocked". rfkill is not about blocking data
|
|
|
-transmissions, it is about blocking energy emission.
|
|
|
+The subsystem also provides the ability to react on button presses and
|
|
|
+disable all transmitters of a certain type (or all). This is intended for
|
|
|
+situations where transmitters need to be turned off, for example on
|
|
|
+aircraft.
|
|
|
|
|
|
-The rfkill subsystem offers support for keys and switches often found on
|
|
|
-laptops to enable wireless devices like WiFi and Bluetooth, so that these keys
|
|
|
-and switches actually perform an action in all wireless devices of a given type
|
|
|
-attached to the system.
|
|
|
|
|
|
-The buttons to enable and disable the wireless transmitters are important in
|
|
|
-situations where the user is for example using his laptop on a location where
|
|
|
-radio-frequency transmitters _must_ be disabled (e.g. airplanes).
|
|
|
|
|
|
-Because of this requirement, userspace support for the keys should not be made
|
|
|
-mandatory. Because userspace might want to perform some additional smarter
|
|
|
-tasks when the key is pressed, rfkill provides userspace the possibility to
|
|
|
-take over the task to handle the key events.
|
|
|
-
|
|
|
-===============================================================================
|
|
|
-2: Implementation details
|
|
|
+2. Implementation details
|
|
|
|
|
|
The rfkill subsystem is composed of various components: the rfkill class, the
|
|
|
rfkill-input module (an input layer handler), and some specific input layer
|
|
|
events.
|
|
|
|
|
|
-The rfkill class provides kernel drivers with an interface that allows them to
|
|
|
-know when they should enable or disable a wireless network device transmitter.
|
|
|
-This is enabled by the CONFIG_RFKILL Kconfig option.
|
|
|
-
|
|
|
-The rfkill class support makes sure userspace will be notified of all state
|
|
|
-changes on rfkill devices through uevents. It provides a notification chain
|
|
|
-for interested parties in the kernel to also get notified of rfkill state
|
|
|
-changes in other drivers. It creates several sysfs entries which can be used
|
|
|
-by userspace. See section "Userspace support".
|
|
|
-
|
|
|
-The rfkill-input module provides the kernel with the ability to implement a
|
|
|
-basic response when the user presses a key or button (or toggles a switch)
|
|
|
-related to rfkill functionality. It is an in-kernel implementation of default
|
|
|
-policy of reacting to rfkill-related input events and neither mandatory nor
|
|
|
-required for wireless drivers to operate. It is enabled by the
|
|
|
-CONFIG_RFKILL_INPUT Kconfig option.
|
|
|
-
|
|
|
-rfkill-input is a rfkill-related events input layer handler. This handler will
|
|
|
-listen to all rfkill key events and will change the rfkill state of the
|
|
|
-wireless devices accordingly. With this option enabled userspace could either
|
|
|
-do nothing or simply perform monitoring tasks.
|
|
|
-
|
|
|
-The rfkill-input module also provides EPO (emergency power-off) functionality
|
|
|
-for all wireless transmitters. This function cannot be overridden, and it is
|
|
|
-always active. rfkill EPO is related to *_RFKILL_ALL input layer events.
|
|
|
-
|
|
|
-
|
|
|
-Important terms for the rfkill subsystem:
|
|
|
-
|
|
|
-In order to avoid confusion, we avoid the term "switch" in rfkill when it is
|
|
|
-referring to an electronic control circuit that enables or disables a
|
|
|
-transmitter. We reserve it for the physical device a human manipulates
|
|
|
-(which is an input device, by the way):
|
|
|
-
|
|
|
-rfkill switch:
|
|
|
-
|
|
|
- A physical device a human manipulates. Its state can be perceived by
|
|
|
- the kernel either directly (through a GPIO pin, ACPI GPE) or by its
|
|
|
- effect on a rfkill line of a wireless device.
|
|
|
-
|
|
|
-rfkill controller:
|
|
|
-
|
|
|
- A hardware circuit that controls the state of a rfkill line, which a
|
|
|
- kernel driver can interact with *to modify* that state (i.e. it has
|
|
|
- either write-only or read/write access).
|
|
|
-
|
|
|
-rfkill line:
|
|
|
-
|
|
|
- An input channel (hardware or software) of a wireless device, which
|
|
|
- causes a wireless transmitter to stop emitting energy (BLOCK) when it
|
|
|
- is active. Point of view is extremely important here: rfkill lines are
|
|
|
- always seen from the PoV of a wireless device (and its driver).
|
|
|
-
|
|
|
-soft rfkill line/software rfkill line:
|
|
|
-
|
|
|
- A rfkill line the wireless device driver can directly change the state
|
|
|
- of. Related to rfkill_state RFKILL_STATE_SOFT_BLOCKED.
|
|
|
-
|
|
|
-hard rfkill line/hardware rfkill line:
|
|
|
-
|
|
|
- A rfkill line that works fully in hardware or firmware, and that cannot
|
|
|
- be overridden by the kernel driver. The hardware device or the
|
|
|
- firmware just exports its status to the driver, but it is read-only.
|
|
|
- Related to rfkill_state RFKILL_STATE_HARD_BLOCKED.
|
|
|
-
|
|
|
-The enum rfkill_state describes the rfkill state of a transmitter:
|
|
|
-
|
|
|
-When a rfkill line or rfkill controller is in the RFKILL_STATE_UNBLOCKED state,
|
|
|
-the wireless transmitter (radio TX circuit for example) is *enabled*. When the
|
|
|
-it 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
|
|
|
-entire system requesting that devices registered to the rfkill class change
|
|
|
-state. The way this interaction happens is not complex, but it is not obvious
|
|
|
-either:
|
|
|
-
|
|
|
-Kernel Input layer:
|
|
|
-
|
|
|
- * Generates KEY_WWAN, KEY_WLAN, KEY_BLUETOOTH, SW_RFKILL_ALL, and
|
|
|
- other such events when the user presses certain keys, buttons, or
|
|
|
- toggles certain physical switches.
|
|
|
-
|
|
|
- THE INPUT LAYER IS NEVER USED TO PROPAGATE STATUS, NOTIFICATIONS OR THE
|
|
|
- KIND OF STUFF AN ON-SCREEN-DISPLAY APPLICATION WOULD REPORT. It is
|
|
|
- used to issue *commands* for the system to change behaviour, and these
|
|
|
- commands may or may not be carried out by some kernel driver or
|
|
|
- userspace application. It follows that doing user feedback based only
|
|
|
- on input events is broken, as there is no guarantee that an input event
|
|
|
- will be acted upon.
|
|
|
-
|
|
|
- Most wireless communication device drivers implementing rfkill
|
|
|
- functionality MUST NOT generate these events, and have no reason to
|
|
|
- register themselves with the input layer. Doing otherwise is a common
|
|
|
- misconception. There is an API to propagate rfkill status change
|
|
|
- information, and it is NOT the input layer.
|
|
|
-
|
|
|
-rfkill class:
|
|
|
-
|
|
|
- * Calls a hook in a driver to effectively change the wireless
|
|
|
- transmitter state;
|
|
|
- * Keeps track of the wireless transmitter state (with help from
|
|
|
- the driver);
|
|
|
- * Generates userspace notifications (uevents) and a call to a
|
|
|
- notification chain (kernel) when there is a wireless transmitter
|
|
|
- state change;
|
|
|
- * Connects a wireless communications driver with the common rfkill
|
|
|
- control system, which, for example, allows actions such as
|
|
|
- "switch all bluetooth devices offline" to be carried out by
|
|
|
- userspace or by rfkill-input.
|
|
|
-
|
|
|
- THE RFKILL CLASS NEVER ISSUES INPUT EVENTS. THE RFKILL CLASS DOES
|
|
|
- NOT LISTEN TO INPUT EVENTS. NO DRIVER USING THE RFKILL CLASS SHALL
|
|
|
- EVER LISTEN TO, OR ACT ON RFKILL INPUT EVENTS. Doing otherwise is
|
|
|
- a layering violation.
|
|
|
-
|
|
|
- Most wireless data communication drivers in the kernel have just to
|
|
|
- implement the rfkill class API to work properly. Interfacing to the
|
|
|
- input layer is not often required (and is very often a *bug*) on
|
|
|
- wireless drivers.
|
|
|
-
|
|
|
- Platform drivers often have to attach to the input layer to *issue*
|
|
|
- (but never to listen to) rfkill events for rfkill switches, and also to
|
|
|
- the rfkill class to export a control interface for the platform rfkill
|
|
|
- controllers to the rfkill subsystem. This does NOT mean the rfkill
|
|
|
- switch is attached to a rfkill class (doing so is almost always wrong).
|
|
|
- It just means the same kernel module is the driver for different
|
|
|
- devices (rfkill switches and rfkill controllers).
|
|
|
-
|
|
|
-
|
|
|
-Userspace input handlers (uevents) or kernel input handlers (rfkill-input):
|
|
|
-
|
|
|
- * Implements the policy of what should happen when one of the input
|
|
|
- layer events related to rfkill operation is received.
|
|
|
- * Uses the sysfs interface (userspace) or private rfkill API calls
|
|
|
- to tell the devices registered with the rfkill class to change
|
|
|
- their state (i.e. translates the input layer event into real
|
|
|
- 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
|
|
|
- RFKILL_STATE_SOFT_BLOCKED state (including those which are already
|
|
|
- supposed to be BLOCKED).
|
|
|
- * rfkill EPO will remain active until rfkill-input receives an
|
|
|
- EV_SW SW_RFKILL_ALL 1 event. While the EPO is active, transmitters
|
|
|
- are locked in the blocked state (rfkill will refuse to unblock them).
|
|
|
- * rfkill-input implements different policies that the user can
|
|
|
- select for handling EV_SW SW_RFKILL_ALL 1. It will unlock rfkill,
|
|
|
- and either do nothing (leave transmitters blocked, but now unlocked),
|
|
|
- restore the transmitters to their state before the EPO, or unblock
|
|
|
- them all.
|
|
|
-
|
|
|
-Userspace uevent handler or kernel platform-specific drivers hooked to the
|
|
|
-rfkill notifier chain:
|
|
|
-
|
|
|
- * Taps into the rfkill notifier chain or to KOBJ_CHANGE uevents,
|
|
|
- in order to know when a device that is registered with the rfkill
|
|
|
- class changes state;
|
|
|
- * Issues feedback notifications to the user;
|
|
|
- * In the rare platforms where this is required, synthesizes an input
|
|
|
- event to command all *OTHER* rfkill devices to also change their
|
|
|
- statues when a specific rfkill device changes state.
|
|
|
-
|
|
|
-
|
|
|
-===============================================================================
|
|
|
-3: Kernel driver guidelines
|
|
|
-
|
|
|
-Remember: point-of-view is everything for a driver that connects to the rfkill
|
|
|
-subsystem. All the details below must be measured/perceived from the point of
|
|
|
-view of the specific driver being modified.
|
|
|
-
|
|
|
-The first thing one needs to know is whether his driver should be talking to
|
|
|
-the rfkill class or to the input layer. In rare cases (platform drivers), it
|
|
|
-could happen that you need to do both, as platform drivers often handle a
|
|
|
-variety of devices in the same driver.
|
|
|
-
|
|
|
-Do not mistake input devices for rfkill controllers. The only type of "rfkill
|
|
|
-switch" device that is to be registered with the rfkill class are those
|
|
|
-directly controlling the circuits that cause a wireless transmitter to stop
|
|
|
-working (or the software equivalent of them), i.e. what we call a rfkill
|
|
|
-controller. Every other kind of "rfkill switch" is just an input device and
|
|
|
-MUST NOT be registered with the rfkill class.
|
|
|
-
|
|
|
-A driver should register a device with the rfkill class when ALL of the
|
|
|
-following conditions are met (they define a rfkill controller):
|
|
|
-
|
|
|
-1. The device is/controls a data communications wireless transmitter;
|
|
|
-
|
|
|
-2. The kernel can interact with the hardware/firmware to CHANGE the wireless
|
|
|
- transmitter state (block/unblock TX operation);
|
|
|
-
|
|
|
-3. The transmitter can be made to not emit any energy when "blocked":
|
|
|
- rfkill is not about blocking data transmissions, it is about blocking
|
|
|
- energy emission;
|
|
|
-
|
|
|
-A driver should register a device with the input subsystem to issue
|
|
|
-rfkill-related events (KEY_WLAN, KEY_BLUETOOTH, KEY_WWAN, KEY_WIMAX,
|
|
|
-SW_RFKILL_ALL, etc) when ALL of the folowing conditions are met:
|
|
|
-
|
|
|
-1. It is directly related to some physical device the user interacts with, to
|
|
|
- command the O.S./firmware/hardware to enable/disable a data communications
|
|
|
- wireless transmitter.
|
|
|
-
|
|
|
- Examples of the physical device are: buttons, keys and switches the user
|
|
|
- will press/touch/slide/switch to enable or disable the wireless
|
|
|
- communication device.
|
|
|
-
|
|
|
-2. It is NOT slaved to another device, i.e. there is no other device that
|
|
|
- issues rfkill-related input events in preference to this one.
|
|
|
-
|
|
|
- Please refer to the corner cases and examples section for more details.
|
|
|
-
|
|
|
-When in doubt, do not issue input events. For drivers that should generate
|
|
|
-input events in some platforms, but not in others (e.g. b43), the best solution
|
|
|
-is to NEVER generate input events in the first place. That work should be
|
|
|
-deferred to a platform-specific kernel module (which will know when to generate
|
|
|
-events through the rfkill notifier chain) or to userspace. This avoids the
|
|
|
-usual maintenance problems with DMI whitelisting.
|
|
|
-
|
|
|
-
|
|
|
-Corner cases and examples:
|
|
|
-====================================
|
|
|
-
|
|
|
-1. If the device is an input device that, because of hardware or firmware,
|
|
|
-causes wireless transmitters to be blocked regardless of the kernel's will, it
|
|
|
-is still just an input device, and NOT to be registered with the rfkill class.
|
|
|
-
|
|
|
-2. If the wireless transmitter switch control is read-only, it is an input
|
|
|
-device and not to be registered with the rfkill class (and maybe not to be made
|
|
|
-an input layer event source either, see below).
|
|
|
-
|
|
|
-3. If there is some other device driver *closer* to the actual hardware the
|
|
|
-user interacted with (the button/switch/key) to issue an input event, THAT is
|
|
|
-the device driver that should be issuing input events.
|
|
|
-
|
|
|
-E.g:
|
|
|
- [RFKILL slider switch] -- [GPIO hardware] -- [WLAN card rf-kill input]
|
|
|
- (platform driver) (wireless card driver)
|
|
|
-
|
|
|
-The user is closer to the RFKILL slide switch plaform driver, so the driver
|
|
|
-which must issue input events is the platform driver looking at the GPIO
|
|
|
-hardware, and NEVER the wireless card driver (which is just a slave). It is
|
|
|
-very likely that there are other leaves than just the WLAN card rf-kill input
|
|
|
-(e.g. a bluetooth card, etc)...
|
|
|
-
|
|
|
-On the other hand, some embedded devices do this:
|
|
|
-
|
|
|
- [RFKILL slider switch] -- [WLAN card rf-kill input]
|
|
|
- (wireless card driver)
|
|
|
-
|
|
|
-In this situation, the wireless card driver *could* register itself as an input
|
|
|
-device and issue rf-kill related input events... but in order to AVOID the need
|
|
|
-for DMI whitelisting, the wireless card driver does NOT do it. Userspace (HAL)
|
|
|
-or a platform driver (that exists only on these embedded devices) will do the
|
|
|
-dirty job of issuing the input events.
|
|
|
-
|
|
|
-
|
|
|
-COMMON MISTAKES in kernel drivers, related to rfkill:
|
|
|
-====================================
|
|
|
-
|
|
|
-1. NEVER confuse input device keys and buttons with input device switches.
|
|
|
-
|
|
|
- 1a. Switches are always set or reset. They report the current state
|
|
|
- (on position or off position).
|
|
|
-
|
|
|
- 1b. Keys and buttons are either in the pressed or not-pressed state, and
|
|
|
- that's it. A "button" that latches down when you press it, and
|
|
|
- unlatches when you press it again is in fact a switch as far as input
|
|
|
- devices go.
|
|
|
-
|
|
|
-Add the SW_* events you need for switches, do NOT try to emulate a button using
|
|
|
-KEY_* events just because there is no such SW_* event yet. Do NOT try to use,
|
|
|
-for example, KEY_BLUETOOTH when you should be using SW_BLUETOOTH instead.
|
|
|
-
|
|
|
-2. Input device switches (sources of EV_SW events) DO store their current state
|
|
|
-(so you *must* initialize it by issuing a gratuitous input layer event on
|
|
|
-driver start-up and also when resuming from sleep), and that state CAN be
|
|
|
-queried from userspace through IOCTLs. There is no sysfs interface for this,
|
|
|
-but that doesn't mean you should break things trying to hook it to the rfkill
|
|
|
-class to get a sysfs interface :-)
|
|
|
-
|
|
|
-3. Do not issue *_RFKILL_ALL events by default, unless you are sure it is the
|
|
|
-correct event for your switch/button. These events are emergency power-off
|
|
|
-events when they are trying to turn the transmitters off. An example of an
|
|
|
-input device which SHOULD generate *_RFKILL_ALL events is the wireless-kill
|
|
|
-switch in a laptop which is NOT a hotkey, but a real sliding/rocker switch.
|
|
|
-An example of an input device which SHOULD NOT generate *_RFKILL_ALL events by
|
|
|
-default, is any sort of hot key that is type-specific (e.g. the one for WLAN).
|
|
|
-
|
|
|
-
|
|
|
-3.1 Guidelines for wireless device drivers
|
|
|
-------------------------------------------
|
|
|
-
|
|
|
-(in this text, rfkill->foo means the foo field of struct rfkill).
|
|
|
-
|
|
|
-1. Each independent transmitter in a wireless device (usually there is only one
|
|
|
-transmitter per device) should have a SINGLE rfkill class attached to it.
|
|
|
-
|
|
|
-2. If the device does not have any sort of hardware assistance to allow the
|
|
|
-driver to rfkill the device, the driver should emulate it by taking all actions
|
|
|
-required to silence the transmitter.
|
|
|
-
|
|
|
-3. If it is impossible to silence the transmitter (i.e. it still emits energy,
|
|
|
-even if it is just in brief pulses, when there is no data to transmit and there
|
|
|
-is no hardware support to turn it off) do NOT lie to the users. Do not attach
|
|
|
-it to a rfkill class. The rfkill subsystem does not deal with data
|
|
|
-transmission, it deals with energy emission. If the transmitter is emitting
|
|
|
-energy, it is not blocked in rfkill terms.
|
|
|
-
|
|
|
-4. It doesn't matter if the device has multiple rfkill input lines affecting
|
|
|
-the same transmitter, their combined state is to be exported as a single state
|
|
|
-per transmitter (see rule 1).
|
|
|
-
|
|
|
-This rule exists because users of the rfkill subsystem expect to get (and set,
|
|
|
-when possible) the overall transmitter rfkill state, not of a particular rfkill
|
|
|
-line.
|
|
|
-
|
|
|
-5. The wireless device driver MUST NOT leave the transmitter enabled during
|
|
|
-suspend and hibernation unless:
|
|
|
+The rfkill class is provided for kernel drivers to register their radio
|
|
|
+transmitter with the kernel, provide methods for turning it on and off and,
|
|
|
+optionally, letting the system know about hardware-disabled states that may
|
|
|
+be implemented on the device. This code is enabled with the CONFIG_RFKILL
|
|
|
+Kconfig option, which drivers can "select".
|
|
|
|
|
|
- 5.1. The transmitter has to be enabled for some sort of functionality
|
|
|
- like wake-on-wireless-packet or autonomous packed forwarding in a mesh
|
|
|
- network, and that functionality is enabled for this suspend/hibernation
|
|
|
- cycle.
|
|
|
+The rfkill class code also notifies userspace of state changes, this is
|
|
|
+achieved via uevents. It also provides some sysfs files for userspace to
|
|
|
+check the status of radio transmitters. See the "Userspace support" section
|
|
|
+below.
|
|
|
|
|
|
-AND
|
|
|
|
|
|
- 5.2. The device was not on a user-requested BLOCKED state before
|
|
|
- the suspend (i.e. the driver must NOT unblock a device, not even
|
|
|
- to support wake-on-wireless-packet or remain in the mesh).
|
|
|
+The rfkill-input code implements a basic response to rfkill buttons -- it
|
|
|
+implements turning on/off all devices of a certain class (or all).
|
|
|
|
|
|
-In other words, there is absolutely no allowed scenario where a driver can
|
|
|
-automatically take action to unblock a rfkill controller (obviously, this deals
|
|
|
-with scenarios where soft-blocking or both soft and hard blocking is happening.
|
|
|
-Scenarios where hardware rfkill lines are the only ones blocking the
|
|
|
-transmitter are outside of this rule, since the wireless device driver does not
|
|
|
-control its input hardware rfkill lines in the first place).
|
|
|
+When the device is hard-blocked (either by a call to rfkill_set_hw_state()
|
|
|
+or from query_hw_block) set_block() will be invoked but drivers can well
|
|
|
+ignore the method call since they can use the return value of the function
|
|
|
+rfkill_set_hw_state() to sync the software state instead of keeping track
|
|
|
+of calls to set_block().
|
|
|
|
|
|
-6. During resume, rfkill will try to restore its previous state.
|
|
|
|
|
|
-7. After a rfkill class is suspended, it will *not* call rfkill->toggle_radio
|
|
|
-until it is resumed.
|
|
|
+The entire functionality is spread over more than one subsystem:
|
|
|
|
|
|
+ * The kernel input layer generates KEY_WWAN, KEY_WLAN etc. and
|
|
|
+ SW_RFKILL_ALL -- when the user presses a button. Drivers for radio
|
|
|
+ transmitters generally do not register to the input layer, unless the
|
|
|
+ device really provides an input device (i.e. a button that has no
|
|
|
+ effect other than generating a button press event)
|
|
|
|
|
|
-Example of a WLAN wireless driver connected to the rfkill subsystem:
|
|
|
---------------------------------------------------------------------
|
|
|
+ * The rfkill-input code hooks up to these events and switches the soft-block
|
|
|
+ of the various radio transmitters, depending on the button type.
|
|
|
|
|
|
-A certain WLAN card has one input pin that causes it to block the transmitter
|
|
|
-and makes the status of that input pin available (only for reading!) to the
|
|
|
-kernel driver. This is a hard rfkill input line (it cannot be overridden by
|
|
|
-the kernel driver).
|
|
|
+ * The rfkill drivers turn off/on their transmitters as requested.
|
|
|
|
|
|
-The card also has one PCI register that, if manipulated by the driver, causes
|
|
|
-it to block the transmitter. This is a soft rfkill input line.
|
|
|
+ * The rfkill class will generate userspace notifications (uevents) to tell
|
|
|
+ userspace what the current state is.
|
|
|
|
|
|
-It has also a thermal protection circuitry that shuts down its transmitter if
|
|
|
-the card overheats, and makes the status of that protection available (only for
|
|
|
-reading!) to the kernel driver. This is also a hard rfkill input line.
|
|
|
|
|
|
-If either one of these rfkill lines are active, the transmitter is blocked by
|
|
|
-the hardware and forced offline.
|
|
|
|
|
|
-The driver should allocate and attach to its struct device *ONE* instance of
|
|
|
-the rfkill class (there is only one transmitter).
|
|
|
+3. Kernel driver guidelines
|
|
|
|
|
|
-It can implement the get_state() hook, and return RFKILL_STATE_HARD_BLOCKED if
|
|
|
-either one of its two hard rfkill input lines are active. If the two hard
|
|
|
-rfkill lines are inactive, it must return RFKILL_STATE_SOFT_BLOCKED if its soft
|
|
|
-rfkill input line is active. Only if none of the rfkill input lines are
|
|
|
-active, will it return RFKILL_STATE_UNBLOCKED.
|
|
|
|
|
|
-Since the device has a hardware rfkill line, it IS subject to state changes
|
|
|
-external to rfkill. Therefore, the driver must make sure that it calls
|
|
|
-rfkill_force_state() to keep the status always up-to-date, and it must do a
|
|
|
-rfkill_force_state() on resume from sleep.
|
|
|
+Drivers for radio transmitters normally implement only the rfkill class.
|
|
|
+These drivers may not unblock the transmitter based on own decisions, they
|
|
|
+should act on information provided by the rfkill class only.
|
|
|
|
|
|
-Every time the driver gets a notification from the card that one of its rfkill
|
|
|
-lines changed state (polling might be needed on badly designed cards that don't
|
|
|
-generate interrupts for such events), it recomputes the rfkill state as per
|
|
|
-above, and calls rfkill_force_state() to update it.
|
|
|
+Platform drivers might implement input devices if the rfkill button is just
|
|
|
+that, a button. If that button influences the hardware then you need to
|
|
|
+implement an rfkill class instead. This also applies if the platform provides
|
|
|
+a way to turn on/off the transmitter(s).
|
|
|
|
|
|
-The driver should implement the toggle_radio() hook, that:
|
|
|
+During suspend/hibernation, transmitters should only be left enabled when
|
|
|
+wake-on wlan or similar functionality requires it and the device wasn't
|
|
|
+blocked before suspend/hibernate. Note that it may be necessary to update
|
|
|
+the rfkill subsystem's idea of what the current state is at resume time if
|
|
|
+the state may have changed over suspend.
|
|
|
|
|
|
-1. Returns an error if one of the hardware rfkill lines are active, and the
|
|
|
-caller asked for RFKILL_STATE_UNBLOCKED.
|
|
|
|
|
|
-2. Activates the soft rfkill line if the caller asked for state
|
|
|
-RFKILL_STATE_SOFT_BLOCKED. It should do this even if one of the hard rfkill
|
|
|
-lines are active, effectively double-blocking the transmitter.
|
|
|
|
|
|
-3. Deactivates the soft rfkill line if none of the hardware rfkill lines are
|
|
|
-active and the caller asked for RFKILL_STATE_UNBLOCKED.
|
|
|
-
|
|
|
-===============================================================================
|
|
|
-4: Kernel API
|
|
|
+4. Kernel API
|
|
|
|
|
|
To build a driver with rfkill subsystem support, the driver should depend on
|
|
|
-(or select) the Kconfig symbol RFKILL; it should _not_ depend on RKFILL_INPUT.
|
|
|
+(or select) the Kconfig symbol RFKILL.
|
|
|
|
|
|
The hardware the driver talks to may be write-only (where the current state
|
|
|
of the hardware is unknown), or read-write (where the hardware can be queried
|
|
|
about its current state).
|
|
|
|
|
|
-The rfkill class will call the get_state hook of a device every time it needs
|
|
|
-to know the *real* current state of the hardware. This can happen often, but
|
|
|
-it does not do any polling, so it is not enough on hardware that is subject
|
|
|
-to state changes outside of the rfkill subsystem.
|
|
|
-
|
|
|
-Therefore, calling rfkill_force_state() when a state change happens is
|
|
|
-mandatory when the device has a hardware rfkill line, or when something else
|
|
|
-like the firmware could cause its state to be changed without going through the
|
|
|
-rfkill class.
|
|
|
-
|
|
|
-Some hardware provides events when its status changes. In these cases, it is
|
|
|
-best for the driver to not provide a get_state hook, and instead register the
|
|
|
-rfkill class *already* with the correct status, and keep it updated using
|
|
|
-rfkill_force_state() when it gets an event from the hardware.
|
|
|
-
|
|
|
-rfkill_force_state() must be used on the device resume handlers to update the
|
|
|
-rfkill status, should there be any chance of the device status changing during
|
|
|
-the sleep.
|
|
|
-
|
|
|
-There is no provision for a statically-allocated rfkill struct. You must
|
|
|
-use rfkill_allocate() to allocate one.
|
|
|
-
|
|
|
-You should:
|
|
|
- - rfkill_allocate()
|
|
|
- - modify rfkill fields (flags, name)
|
|
|
- - modify state to the current hardware state (THIS IS THE ONLY TIME
|
|
|
- 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().
|
|
|
+Calling rfkill_set_hw_state() when a state change happens is required from
|
|
|
+rfkill drivers that control devices that can be hard-blocked unless they also
|
|
|
+assign the poll_hw_block() callback (then the rfkill core will poll the
|
|
|
+device). Don't do this unless you cannot get the event in any other way.
|
|
|
|
|
|
-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.
|
|
|
-
|
|
|
-===============================================================================
|
|
|
-5: Userspace support
|
|
|
-
|
|
|
-rfkill devices issue uevents (with an action of "change"), with the following
|
|
|
-environment variables set:
|
|
|
-
|
|
|
-RFKILL_NAME
|
|
|
-RFKILL_STATE
|
|
|
-RFKILL_TYPE
|
|
|
|
|
|
-The ABI for these variables is defined by the sysfs attributes. It is best
|
|
|
-to take a quick look at the source to make sure of the possible values.
|
|
|
+5. Userspace support
|
|
|
|
|
|
-It is expected that HAL will trap those, and bridge them to DBUS, etc. These
|
|
|
-events CAN and SHOULD be used to give feedback to the user about the rfkill
|
|
|
-status of the system.
|
|
|
-
|
|
|
-Input devices may issue events that are related to rfkill. These are the
|
|
|
-various KEY_* events and SW_* events supported by rfkill-input.c.
|
|
|
-
|
|
|
-Userspace may not change the state of an rfkill switch in response to an
|
|
|
-input event, it should refrain from changing states entirely.
|
|
|
-
|
|
|
-Userspace cannot assume it is the only source of control for rfkill switches.
|
|
|
-Their state can change due to firmware actions, direct user actions, and the
|
|
|
-rfkill-input EPO override for *_RFKILL_ALL.
|
|
|
-
|
|
|
-When rfkill-input is not active, userspace must initiate a rfkill status
|
|
|
-change by writing to the "state" attribute in order for anything to happen.
|
|
|
-
|
|
|
-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
|
|
|
-RFKILL_STATE_SOFT_BLOCKED state, no questions asked.
|
|
|
-
|
|
|
-The following sysfs entries will be created:
|
|
|
+The following sysfs entries exist for every rfkill device:
|
|
|
|
|
|
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 transmitter
|
|
|
0: RFKILL_STATE_SOFT_BLOCKED
|
|
|
- transmitter is forced off, but one can override it
|
|
|
- by a write to the state attribute;
|
|
|
+ transmitter is turned off by software
|
|
|
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);
|
|
|
+ transmitter is (potentially) active
|
|
|
2: RFKILL_STATE_HARD_BLOCKED
|
|
|
transmitter is forced off by something outside of
|
|
|
- the driver's control. One 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
|
|
|
-this means that when 1 or 0 is written, the device rfkill state (if not yet in
|
|
|
-the requested state), will be will be toggled accordingly.
|
|
|
-
|
|
|
-For the "claim" entry writing 1 to it means that the kernel no longer handles
|
|
|
-key events even though RFKILL_INPUT input was enabled. When "claim" has been
|
|
|
-set to 0, userspace should make sure that it listens for the input events or
|
|
|
-check the sysfs "state" entry regularly to correctly perform the required tasks
|
|
|
-when the rkfill key is pressed.
|
|
|
-
|
|
|
-A note about input devices and EV_SW events:
|
|
|
-
|
|
|
-In order to know the current state of an input device switch (like
|
|
|
-SW_RFKILL_ALL), you will need to use an IOCTL. That information is not
|
|
|
-available through sysfs in a generic way at this time, and it is not available
|
|
|
-through the rfkill class AT ALL.
|
|
|
+ the driver's control.
|
|
|
+ claim: 0: Kernel handles events (currently always reads that value)
|
|
|
+
|
|
|
+rfkill devices also issue uevents (with an action of "change"), with the
|
|
|
+following environment variables set:
|
|
|
+
|
|
|
+RFKILL_NAME
|
|
|
+RFKILL_STATE
|
|
|
+RFKILL_TYPE
|
|
|
+
|
|
|
+The contents of these variables corresponds to the "name", "state" and
|
|
|
+"type" sysfs files explained above.
|
|
|
+
|
|
|
+An alternative userspace interface exists as a misc device /dev/rfkill,
|
|
|
+which allows userspace to obtain and set the state of rfkill devices and
|
|
|
+sets of devices. It also notifies userspace about device addition and
|
|
|
+removal. The API is a simple read/write API that is defined in
|
|
|
+linux/rfkill.h.
|