Search Linux Wireless

Re: [PATCH 2/2] rfkill: improve documentation for kernel drivers

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Monday 23 June 2008, Henrique de Moraes Holschuh wrote:
> 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: Henrique de Moraes Holschuh <hmh@xxxxxxxxxx>
> Cc: Ivo van Doorn <IvDoorn@xxxxxxxxx>

Acked-by: Ivo van Doorn <IvDoorn@xxxxxxxxx>

> ---
>  Documentation/rfkill.txt |  261 +++++++++++++++++++++++++++++++++++-----------
>  1 files changed, 201 insertions(+), 60 deletions(-)
> 
> diff --git a/Documentation/rfkill.txt b/Documentation/rfkill.txt
> index 5316cea..0843ed0 100644
> --- a/Documentation/rfkill.txt
> +++ b/Documentation/rfkill.txt
> @@ -4,6 +4,9 @@ rfkill - RF switch subsystem 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
>  
> @@ -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
>  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
> -laptops to enable wireless devices like WiFi and Bluetooth to actually perform
> -an action.
> +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 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
> @@ -30,40 +38,81 @@ take over the task to handle the key events.
>  ===============================================================================
>  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.
> +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 overriden, and it is
> -always active.  rfkill EPO is related to *_RFKILL_ALL input events.
> +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:
>  
> -All state changes on rfkill devices are propagated by the rfkill class to a
> -notification chain and also to userspace through uevents.
> +	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).
>  
> -The system inside the kernel has been split into 2 separate sections:
> -	1 - RFKILL
> -	2 - RFKILL_INPUT
> +rfkill line:
>  
> -The first option enables rfkill support and will make sure userspace will be
> -notified of any events 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".
> +	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).
>  
> -The second option provides an rfkill input handler. This handler will listen to
> -all rfkill key events and will toggle the radio accordingly.  With this option
> -enabled userspace could either do nothing or simply perform monitoring tasks.
> +soft rfkill line/software rfkill line:
>  
> -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.
> +	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()
> @@ -92,12 +141,12 @@ Kernel Input layer:
>  	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, 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.
>  
>  	Most wireless communication device drivers implementing rfkill
>  	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
>  	information, and it is NOT the input layer.
>  
> @@ -117,11 +166,22 @@ rfkill class:
>  
>  	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.
> +	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*).
> +	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):
>  
> @@ -153,24 +213,34 @@ rfkill notifier chain:
>  ===============================================================================
>  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.
> +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
>  directly controlling the circuits that cause a wireless transmitter to stop
> -working (or the software equivalent of them).  Every other kind of "rfkill
> -switch" is just an input device and MUST NOT be registered with the rfkill
> -class.
> +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:
> +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:
> @@ -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
>     issues rfkill-related input events in preference to this one.
>  
> -   Typically, the ACPI "radio kill" switch of a laptop is the master input
> -   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.
> +   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
> @@ -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,
>  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, 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 :-)
> +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 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
>  
>  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
>  of the hardware is unknown), or read-write (where the hardware can be queried
> @@ -338,10 +482,10 @@ is *absolute*; do NOT violate it.
>  ******IMPORTANT******
>  
>  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
> -user actions, and the rfkill-input EPO override for *_RFKILL_ALL.
> +Their state CAN and WILL 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 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.
>  
>  Take particular care to implement EV_SW SW_RFKILL_ALL properly.  When that
> @@ -354,19 +498,16 @@ The following sysfs entries will be created:
>  	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 you can override it
> -			by a write to the state attribute, or through input
> -			events (if rfkill-input is loaded).
> +			transmitter is forced off, but one can override it
> +			by a write to the state attribute;
>  		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).
> +			(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.
> +			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


--
To unsubscribe from this list: send the line "unsubscribe linux-wireless" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html

[Index of Archives]     [Linux Host AP]     [ATH6KL]     [Linux Bluetooth]     [Linux Netdev]     [Kernel Newbies]     [Linux Kernel]     [IDE]     [Security]     [Git]     [Netfilter]     [Bugtraq]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Linux ATA RAID]     [Samba]     [Device Mapper]
  Powered by Linux