Commit f7983f73 authored by Henrique de Moraes Holschuh's avatar Henrique de Moraes Holschuh Committed by John W. Linville

rfkill: improve documentation for kernel drivers

Improve the documentation of how to use the rfkill class in kernel drivers,
based on the doubts that came up in a thread in linux-wireless.
Signed-off-by: default avatarHenrique de Moraes Holschuh <hmh@hmh.eng.br>
Acked-by: default avatarIvo van Doorn <IvDoorn@gmail.com>
Signed-off-by: default avatarJohn W. Linville <linville@tuxdriver.com>
parent 5005657c
...@@ -4,6 +4,9 @@ rfkill - RF switch subsystem support ...@@ -4,6 +4,9 @@ rfkill - RF switch subsystem support
1 Introduction 1 Introduction
2 Implementation details 2 Implementation details
3 Kernel driver guidelines 3 Kernel driver guidelines
3.1 wireless device drivers
3.2 platform/switch drivers
3.3 input device drivers
4 Kernel API 4 Kernel API
5 Userspace support 5 Userspace support
...@@ -14,9 +17,14 @@ The rfkill switch subsystem exists to add a generic interface to circuitry that ...@@ -14,9 +17,14 @@ 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 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. type. By far, the most common use is to disable radio-frequency transmitters.
The rfkill switch subsystem offers support for keys and switches often found on Note that disabling the signal output means that the the transmitter is to be
laptops to enable wireless devices like WiFi and Bluetooth to actually perform made to not emit any energy when "blocked". rfkill is not about blocking data
an action. transmissions, it is about blocking energy emission.
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 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 situations where the user is for example using his laptop on a location where
...@@ -30,40 +38,81 @@ take over the task to handle the key events. ...@@ -30,40 +38,81 @@ 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 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. 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 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) 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 related to rfkill functionality. It is an in-kernel implementation of default
policy of reacting to rfkill-related input events and neither mandatory nor policy of reacting to rfkill-related input events and neither mandatory nor
required for wireless drivers to operate. 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 The rfkill-input module also provides EPO (emergency power-off) functionality
for all wireless transmitters. This function cannot be overriden, and it is for all wireless transmitters. This function cannot be overridden, and it is
always active. rfkill EPO is related to *_RFKILL_ALL input events. 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:
All state changes on rfkill devices are propagated by the rfkill class to a A hardware circuit that controls the state of a rfkill line, which a
notification chain and also to userspace through uevents. kernel driver can interact with *to modify* that state (i.e. it has
either write-only or read/write access).
The system inside the kernel has been split into 2 separate sections: rfkill line:
1 - RFKILL
2 - RFKILL_INPUT
The first option enables rfkill support and will make sure userspace will be An input channel (hardware or software) of a wireless device, which
notified of any events through uevents. It provides a notification chain for causes a wireless transmitter to stop emitting energy (BLOCK) when it
interested parties in the kernel to also get notified of rfkill state changes is active. Point of view is extremely important here: rfkill lines are
in other drivers. It creates several sysfs entries which can be used by always seen from the PoV of a wireless device (and its driver).
userspace. See section "Userspace support".
The second option provides an rfkill input handler. This handler will listen to soft rfkill line/software rfkill line:
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_UNBLOCKED, the wireless transmitter A rfkill line the wireless device driver can directly change the state
(radio TX circuit for example) is *enabled*. When the rfkill switch is in the of. Related to rfkill_state RFKILL_STATE_SOFT_BLOCKED.
RFKILL_STATE_SOFT_BLOCKED or RFKILL_STATE_HARD_BLOCKED, the wireless
transmitter is to be *blocked* from operating. 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 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() that state. RFKILL_STATE_HARD_BLOCKED indicates that a call to toggle_radio()
...@@ -92,12 +141,12 @@ Kernel Input layer: ...@@ -92,12 +141,12 @@ Kernel Input layer:
used to issue *commands* for the system to change behaviour, and these 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 commands may or may not be carried out by some kernel driver or
userspace application. It follows that doing user feedback based only userspace application. It follows that doing user feedback based only
on input events is broken, there is no guarantee that an input event on input events is broken, as there is no guarantee that an input event
will be acted upon. will be acted upon.
Most wireless communication device drivers implementing rfkill Most wireless communication device drivers implementing rfkill
functionality MUST NOT generate these events, and have no reason to functionality MUST NOT generate these events, and have no reason to
register themselves with the input layer. This is a common register themselves with the input layer. Doing otherwise is a common
misconception. There is an API to propagate rfkill status change misconception. There is an API to propagate rfkill status change
information, and it is NOT the input layer. information, and it is NOT the input layer.
...@@ -117,11 +166,22 @@ rfkill class: ...@@ -117,11 +166,22 @@ rfkill class:
THE RFKILL CLASS NEVER ISSUES INPUT EVENTS. THE RFKILL CLASS DOES THE RFKILL CLASS NEVER ISSUES INPUT EVENTS. THE RFKILL CLASS DOES
NOT LISTEN TO INPUT EVENTS. NO DRIVER USING THE RFKILL CLASS SHALL NOT LISTEN TO INPUT EVENTS. NO DRIVER USING THE RFKILL CLASS SHALL
EVER LISTEN TO, OR ACT ON RFKILL INPUT EVENTS. 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 Most wireless data communication drivers in the kernel have just to
implement the rfkill class API to work properly. Interfacing to the implement the rfkill class API to work properly. Interfacing to the
input layer is not often required (and is very often a *bug*). 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): Userspace input handlers (uevents) or kernel input handlers (rfkill-input):
...@@ -153,24 +213,34 @@ rfkill notifier chain: ...@@ -153,24 +213,34 @@ rfkill notifier chain:
=============================================================================== ===============================================================================
3: Kernel driver guidelines 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 first thing one needs to know is whether his driver should be talking to
the rfkill class or to the input layer. 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 devices. The only type of "rfkill 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 switch" device that is to be registered with the rfkill class are those
directly controlling the circuits that cause a wireless transmitter to stop directly controlling the circuits that cause a wireless transmitter to stop
working (or the software equivalent of them). Every other kind of "rfkill working (or the software equivalent of them), i.e. what we call a rfkill
switch" is just an input device and MUST NOT be registered with the rfkill controller. Every other kind of "rfkill switch" is just an input device and
class. MUST NOT be registered with the rfkill class.
A driver should register a device with the rfkill class when ALL of the A driver should register a device with the rfkill class when ALL of the
following conditions are met: following conditions are met (they define a rfkill controller):
1. The device is/controls a data communications wireless transmitter; 1. The device is/controls a data communications wireless transmitter;
2. The kernel can interact with the hardware/firmware to CHANGE the wireless 2. The kernel can interact with the hardware/firmware to CHANGE the wireless
transmitter state (block/unblock TX operation); 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 A driver should register a device with the input subsystem to issue
rfkill-related events (KEY_WLAN, KEY_BLUETOOTH, KEY_WWAN, KEY_WIMAX, rfkill-related events (KEY_WLAN, KEY_BLUETOOTH, KEY_WWAN, KEY_WIMAX,
SW_RFKILL_ALL, etc) when ALL of the folowing conditions are met: SW_RFKILL_ALL, etc) when ALL of the folowing conditions are met:
...@@ -186,9 +256,7 @@ SW_RFKILL_ALL, etc) when ALL of the folowing conditions are met: ...@@ -186,9 +256,7 @@ SW_RFKILL_ALL, etc) when ALL of the folowing conditions are met:
2. It is NOT slaved to another device, i.e. there is no other device that 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. issues rfkill-related input events in preference to this one.
Typically, the ACPI "radio kill" switch of a laptop is the master input Please refer to the corner cases and examples section for more details.
device to issue rfkill events, and, e.g., the WLAN card is just a slave
device that gets disabled by its hardware radio-kill input pin.
When in doubt, do not issue input events. For drivers that should generate 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 input events in some platforms, but not in others (e.g. b43), the best solution
...@@ -252,26 +320,102 @@ Add the SW_* events you need for switches, do NOT try to emulate a button using ...@@ -252,26 +320,102 @@ 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, 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. 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 2. Input device switches (sources of EV_SW events) DO store their current state
state, and that state CAN be queried from userspace through IOCTLs. There is (so you *must* initialize it by issuing a gratuitous input layer event on
no sysfs interface for this, but that doesn't mean you should break things driver start-up and also when resuming from sleep), and that state CAN be
trying to hook it to the rfkill class to get a sysfs interface :-) 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 switch that kills radios
in hardware, even if the O.S. has gone to lunch. An example of an input device
which SHOULD NOT generate *_RFKILL_ALL events by default, is any sort of hot
key that does nothing by itself, as well as any hot key that is type-specific
(e.g. the one for WLAN).
3. Do not issue *_RFKILL_ALL events, 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 switch that kills radios in hardware,
even if the O.S. has gone to lunch. An example of an input device which SHOULD
NOT generate *_RFKILL_ALL events is any sort of hot key that does nothing by
itself, as well as any hot key that is type-specific (e.g. the one for WLAN).
3.1 Guidelines for wireless device drivers
------------------------------------------
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.
Example of a WLAN wireless driver connected to the rfkill subsystem:
--------------------------------------------------------------------
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 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.
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).
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.
If it doesn't implement the get_state() hook, it must make sure that its calls
to rfkill_force_state() are enough to keep the status always up-to-date, and it
must do a rfkill_force_state() on resume from sleep.
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.
The driver should implement the toggle_radio() hook, that:
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 To build a driver with rfkill subsystem support, the driver should depend on
the Kconfig symbol RFKILL; it should _not_ depend on RKFILL_INPUT. (or select) the Kconfig symbol RFKILL; it should _not_ depend on RKFILL_INPUT.
The hardware the driver talks to may be write-only (where the current state 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 of the hardware is unknown), or read-write (where the hardware can be queried
...@@ -338,10 +482,10 @@ is *absolute*; do NOT violate it. ...@@ -338,10 +482,10 @@ is *absolute*; do NOT violate it.
******IMPORTANT****** ******IMPORTANT******
Userspace must not assume it is the only source of control for rfkill switches. Userspace must not assume it is the only source of control for rfkill switches.
Their state CAN and WILL change on its own, due to firmware actions, direct Their state CAN and WILL change due to firmware actions, direct user actions,
user actions, and the rfkill-input EPO override for *_RFKILL_ALL. and the rfkill-input EPO override for *_RFKILL_ALL.
When rfkill-input is not active, userspace must initiate an rfkill status 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. 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 Take particular care to implement EV_SW SW_RFKILL_ALL properly. When that
...@@ -354,19 +498,16 @@ The following sysfs entries will be created: ...@@ -354,19 +498,16 @@ The following sysfs entries will be created:
type: Name of the key type ("wlan", "bluetooth", etc). type: Name of the key type ("wlan", "bluetooth", etc).
state: Current state of the transmitter state: Current state of the transmitter
0: RFKILL_STATE_SOFT_BLOCKED 0: RFKILL_STATE_SOFT_BLOCKED
transmitter is forced off, but you can override it transmitter is forced off, but one can override it
by a write to the state attribute, or through input by a write to the state attribute;
events (if rfkill-input is loaded).
1: RFKILL_STATE_UNBLOCKED 1: RFKILL_STATE_UNBLOCKED
transmiter is NOT forced off, and may operate if transmiter is NOT forced off, and may operate if
all other conditions for such operation are met all other conditions for such operation are met
(such as interface is up and configured, etc). (such as interface is up and configured, etc);
2: RFKILL_STATE_HARD_BLOCKED 2: RFKILL_STATE_HARD_BLOCKED
transmitter is forced off by something outside of transmitter is forced off by something outside of
the driver's control. the driver's control. One cannot set a device to
this state through writes to the state attribute;
You cannot set a device to this state through
writes to the state attribute.
claim: 1: Userspace handles events, 0: Kernel handles events claim: 1: Userspace handles events, 0: Kernel handles events
Both the "state" and "claim" entries are also writable. For the "state" entry Both the "state" and "claim" entries are also writable. For the "state" entry
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment