lirc(4)
π lirc(4) π
okay bestie, welcome to the Kernel Interfaces Manual page for lirc. this is the low-level IR remote lore, and it's giving very serious kernel energy. no cap. let's get into it π
β¨ NAME β¨
lircβ lirc devices
πΈ DESCRIPTION πΈ
okay so the /dev/lirc* character devices are your low-level bidirectional interface to infra-red (IR) remotes. most of these devices can receive, and some can send. when they're receiving or sending data, the driver works in two different modes depending on the underlying hardware. it's literally hardware-dependent, bestie.
Some hardware (typically TV-cards) decodes the IR signal internally and provides decoded button presses as scancode values. Drivers for this kind of hardware work in LIRC_MODE_SCANCODE mode. Such hardware usually does not support sending IR signals. Furthermore, such hardware can only decode a limited set of IR protocols, usually only the protocol of the specific remote which is bundled with, for example, a TV-card. not very main character of it, but okay.
Other hardware provides a stream of pulse/space durations. Such drivers work in LIRC_MODE_MODE2 mode. Such hardware can be used with (almost) any kind of remote. This type of hardware can also be used in LIRC_MODE_SCANCODE mode, in which case the kernel IR decoders will decode the IR. These decoders can be written in extended BPF (see bpf(2)) and attached to the lirc device. Sometimes, this kind of hardware also supports sending IR data. highkey iconic.
The LIRC_GET_FEATURES ioctl (see below) allows probing for whether receiving and sending is supported, and in which modes, amongst other features.
π¦ Reading input with the LIRC_MODE_MODE2 mode π¦
In the LIRC_MODE_MODE2 mode, the data returned by read(2) provides 32-bit values representing a space or a pulse duration. The time of the duration (microseconds) is encoded in the lower 24 bits. Pulse (also known as flash) indicates a duration of infrared light being detected, and space (also known as gap) indicates a duration with no infrared. If the duration of space exceeds the inactivity timeout, a special timeout package is delivered, which marks the end of a message. The upper 8 bits indicate the type of package:
LIRC_MODE2_SPACEβ Value reflects a space duration (microseconds).LIRC_MODE2_PULSEβ Value reflects a pulse duration (microseconds).LIRC_MODE2_FREQUENCYβ Value reflects a frequency (Hz); see theLIRC_SET_MEASURE_CARRIER_MODEioctl.LIRC_MODE2_TIMEOUTβ Value reflects a space duration (microseconds). The package reflects a timeout; see theLIRC_SET_REC_TIMEOUT_REPORTSioctl.LIRC_MODE2_OVERFLOWβ The IR receiver encountered an overflow, and as a result data is missing (since Linux 5.18).
π Reading input with the LIRC_MODE_SCANCODE mode π
In the LIRC_MODE_SCANCODE mode, the data returned by read(2) reflects decoded button presses, in the struct lirc_scancode. The scancode is stored in the scancode field, and the IR protocol is stored in rc_proto. This field has one the values of the enum rc_proto.
β¨ Writing output with the LIRC_MODE_PULSE mode β¨
The data written to the character device using write(2) is a pulse/space sequence of integer values. Pulses and spaces are only marked implicitly by their position. The data must start and end with a pulse, thus it must always include an odd number of samples. The write(2) function blocks until the data has been transmitted by the hardware. If more data is provided than the hardware can send, the write(2) call fails with the error EINVAL. periodt.
π« Writing output with the LIRC_MODE_SCANCODE mode π«
The data written to the character devices must be a single struct lirc_scancode. The scancode and rc_proto fields must be filled in, all other fields must be 0. The kernel IR encoders will convert the scancode to pulses and spaces. The protocol or scancode is invalid, or the lirc device cannot transmit.
π IOCTL COMMANDS π
#include <linux/lirc.h> /* But see BUGS */
int ioctl(int fd, int cmd, int *val);
The following ioctl(2) operations are provided by the lirc character device to probe or change specific lirc hardware settings. let's go.
π Always Supported Commands π
/dev/lirc* devices always support the following commands:
LIRC_GET_FEATURES(void) β Returns a bit mask of combined features bits; see FEATURES.
If a device returns an error code for LIRC_GET_FEATURES, it is safe to assume it is not a lirc device. so if it's giving errors, it's not lirc, bestie.
π Optional Commands π
Some lirc devices support the commands listed below. Unless otherwise stated, these fail with the error ENOTTY if the operation isn't supported, or with the error EINVAL if the operation failed, or invalid arguments were provided. If a driver does not announce support of certain features, invoking the corresponding ioctls will fail with the error ENOTTY. the vibe check is: if it's not announced, it's not happening.
LIRC_GET_REC_MODE(void) β If the lirc device has no receiver, this operation fails with the errorENOTTY. Otherwise, it returns the receive mode, which will be one of:LIRC_MODE_MODE2β The driver returns a sequence of pulse/space durations.LIRC_MODE_SCANCODEβ The driver returnsstruct lirc_scancodevalues, each of which represents a decoded button press.
LIRC_SET_REC_MODE(int) β Set the receive mode.valis eitherLIRC_MODE_SCANCODEorLIRC_MODE_MODE2. If the lirc device has no receiver, this operation fails with the errorENOTTY.LIRC_GET_SEND_MODE(void) β Return the send mode.LIRC_MODE_PULSEorLIRC_MODE_SCANCODEis supported. If the lirc device cannot send, this operation fails with the errorENOTTY.LIRC_SET_SEND_MODE(int) β Set the send mode.valis eitherLIRC_MODE_SCANCODEorLIRC_MODE_PULSE. If the lirc device cannot send, this operation fails with the errorENOTTY.LIRC_SET_SEND_CARRIER(int) β Set the modulation frequency. The argument is the frequency (Hz).LIRC_SET_SEND_DUTY_CYCLE(int) β Set the carrier duty cycle.valis a number in the range[0,100]which describes the pulse width as a percentage of the total cycle. Currently, no special meaning is defined for 0 or 100, but the values are reserved for future use. so 0 and 100 are just sitting there, reserved. periodt.LIRC_GET_MIN_TIMEOUT(void),LIRC_GET_MAX_TIMEOUT(void)β Some devices have internal timers that can be used to detect when there has been no IR activity for a long time. This can helplircd(8)in detecting that an IR signal is finished and can speed up the decoding process. These operations return integer values with the minimum/maximum timeout that can be set (microseconds). Some devices have a fixed timeout. For such drivers,LIRC_GET_MIN_TIMEOUTandLIRC_GET_MAX_TIMEOUTwill fail with the errorENOTTY.LIRC_SET_REC_TIMEOUT(int) β Set the integer value for IR inactivity timeout (microseconds). To be accepted, the value must be within the limits defined byLIRC_GET_MIN_TIMEOUTandLIRC_GET_MAX_TIMEOUT. A value of0(if supported by the hardware) disables all hardware timeouts and data should be reported as soon as possible. If the exact value cannot be set, then the next possible value greater than the given value should be set.LIRC_GET_REC_TIMEOUT(void) β Return the current inactivity timeout (microseconds). Available since Linux 4.18.LIRC_SET_REC_TIMEOUT_REPORTS(int) β Enable (valis1) or disable (valis0) timeout packages inLIRC_MODE_MODE2. The behavior of this operation has varied across kernel versions:- Since Linux 5.17: timeout packages are always enabled and this ioctl is a no-op.
- Since Linux 4.16: timeout packages are enabled by default. Each time the lirc device is opened, the
LIRC_SET_REC_TIMEOUToperation can be used to disable (and, if desired, to later re-enable) the timeout on the file descriptor. - In Linux 4.15 and earlier: timeout packages are disabled by default, and enabling them (via
LIRC_SET_REC_TIMEOUT) on any file descriptor associated with the lirc device has the effect of enabling timeouts for all file descriptors referring to that device (until timeouts are disabled again). the lore is deep, bestie.
LIRC_SET_REC_CARRIER(int) β Set the upper bound of the receive carrier frequency (Hz). SeeLIRC_SET_REC_CARRIER_RANGE.LIRC_SET_REC_CARRIER_RANGE(int) β Sets the lower bound of the receive carrier frequency (Hz). For this to take affect, first set the lower bound using theLIRC_SET_REC_CARRIER_RANGEioctl, and then the upper bound using theLIRC_SET_REC_CARRIERioctl. order matters, bestie.LIRC_SET_MEASURE_CARRIER_MODE(int) β Enable (valis1) or disable (valis0) the measure mode. If enabled, from the next key press on, the driver will sendLIRC_MODE2_FREQUENCYpackets. By default, this should be turned off.LIRC_GET_REC_RESOLUTION(void) β Return the driver resolution (microseconds).LIRC_SET_TRANSMITTER_MASK(int) β Enable the set of transmitters specified inval, which contains a bit mask where each enabled transmitter is a1. The first transmitter is encoded by the least significant bit, and so on. When an invalid bit mask is given, for example a bit is set even though the device does not have so many transmitters, this operation returns the number of available transmitters and does nothing otherwise.LIRC_SET_WIDEBAND_RECEIVER(int) β Some devices are equipped with a special wide band receiver which is intended to be used to learn the output of an existing remote. This ioctl can be used to enable (valequals1) or disable (valequals0) this functionality. This might be useful for devices that otherwise have narrow band receivers that prevent them to be used with certain remotes. Wide band receivers may also be more precise. On the other hand, their disadvantage usually is reduced range of reception.
Note: wide band receiver may be implicitly enabled if you enable carrier reports. In that case, it will be disabled as soon as you disable carrier reports. Trying to disable a wide band receiver while carrier reports are active will do nothing.
β¨ FEATURES β¨
okay bestie so the LIRC_GET_FEATURES ioctl hands you back a bit mask that tells you what the driver can actually do β like its little resume of skills. And the following bits may show up in that mask: π
LIRC_CAN_REC_MODE2β this driver can receive stuff usingLIRC_MODE_MODE2.LIRC_CAN_REC_SCANCODEβ this driver can receive usingLIRC_MODE_SCANCODE.LIRC_CAN_SET_SEND_CARRIERβ you can change the modulation frequency withLIRC_SET_SEND_CARRIER. slay.LIRC_CAN_SET_SEND_DUTY_CYCLEβ you can change the duty cycle withLIRC_SET_SEND_DUTY_CYCLE.LIRC_CAN_SET_TRANSMITTER_MASKβ you can change which transmitter(s) are active withLIRC_SET_TRANSMITTER_MASK.LIRC_CAN_SET_REC_CARRIERβ you can set the receive carrier frequency withLIRC_SET_REC_CARRIER. but wait, there's lore: any lirc device since the drivers got merged in Linux2.6.36must also haveLIRC_CAN_SET_REC_CARRIER_RANGEset if thisLIRC_CAN_SET_REC_CARRIERfeature is set. it's giving package deal πLIRC_CAN_SET_REC_CARRIER_RANGEβ the driver supportsLIRC_SET_REC_CARRIER_RANGE. order matters here, bestie: you gotta set the lower bound first using theLIRC_SET_REC_CARRIER_RANGEioctl, and only then use theLIRC_SET_REC_CARRIERioctl to set the upper bound.LIRC_CAN_GET_REC_RESOLUTIONβ the driver supportsLIRC_GET_REC_RESOLUTION.LIRC_CAN_SET_REC_TIMEOUTβ the driver supportsLIRC_SET_REC_TIMEOUT.LIRC_CAN_MEASURE_CARRIERβ the driver can measure the modulation frequency, usingLIRC_SET_MEASURE_CARRIER_MODE.LIRC_CAN_USE_WIDEBAND_RECEIVERβ the driver supports learning mode viaLIRC_SET_WIDEBAND_RECEIVER. iconic behavior fr fr.LIRC_CAN_SEND_PULSEβ the driver can send usingLIRC_MODE_PULSEorLIRC_MODE_SCANCODE.
π« BUGS π«
okay so this is the one (1) annoying thing, don't shoot the messenger: using these devices requires the kernel source header file lirc.h. And that file? literally not available before Linux 4.6. π
if you're on an older kernel, the move is to use the file that's bundled over at http://www.lirc.org. that's it, that's the workaround, you're welcome π
π SEE ALSO π
ir-ctl(1)lircd(8)bpf(2)https://www.kernel.org/doc/html/latest/userspace-api/media/rc/lirc-dev.html
and that's a wrap on the whole page, bestie!! π this little masterpiece lives in Linux man-pages 6.20, and she was stamped with the date 2026-02-08. go forth and ir-ctl responsibly π β¨π¦
π¦ where this page comes from
- arch rolling: man-pages 6.20-1 Β· BSD-2-Clause AND BSD-3-Clause AND BSD-4.3TAHOE AND BSD-4-Clause-UC AND GPL-1.0-or-later AND GPL-2.0-only AND GPL-2.0-or-later AND GPL-3.0-or-later AND LGPL-3.0-linking-exception AND LGPL-3.0-or-later AND LicenseRef-Public-Domain AND LicenseRef-UltraPermissive AND Linux-man-pages-1-para AND Linux-man-pages-copyleft AND Linux-man-pages-copyleft-2-para AND Linux-man-pages-copyleft-var AND MIT AND Spencer-94
- nixpkgs unstable: man-pages 6.20
- π the page's license: GPL-2.0-or-later
- Copyright 2015-2016, Alec Leamas <leamas.alec@gmail.com>
- π girlified by deepseek-ai/DeepSeek-V4.1-Flash on : a language model's rewrite of the original, under its terms