free linux device drivers course
free linux kernel development course
free embedded linux course
iio_device_register
Getting IIO buffer setup right is what separates a driver that only exposes raw sysfs values from one that can stream real sensor data to user space at speed. In this lecture of our free Linux device drivers course, we pick up right where Part 2 left off and open up the fields inside struct iio_dev that control triggered buffers, then walk through how an IIO device is actually allocated and registered with the kernel, and finally introduce the iio_info and iio_chan_spec structures that every IIO driver depends on.
Everything here targets a current 6.x mainline kernel, uses original example code written for this course, and avoids the outdated APIs you’ll still find in older textbooks.
What You Will Learn
- Every field inside
iio_devthat supports triggered buffer capture - How
iio_buffer_setup_opshooks into the enable/disable lifecycle - The modern, devm-managed way to allocate and register an IIO device
- What changed in
struct iio_infoon recent kernels - The first fields of
iio_chan_specand why channels matter - How to build, load, and test a working IIO driver on a real board or QEMU
Prerequisites
- Part 1 and Part 2 of this IIO Framework series (device/channel model, sysfs vs chardev,
read_raw/write_raw) - Comfort writing and building an out-of-tree kernel module
- Basic familiarity with sysfs attributes and
devm_*managed resources
Recap: From Single Values to Buffered Capture
In Part 1 we built a driver that returned one voltage sample per read_raw() call. That’s fine for a slow-changing value, but most real sensors — accelerometers, gyroscopes, ADCs sampling at kilohertz rates — need to stream many samples continuously. That’s exactly what IIO’s triggered buffer mode is for, and it’s controlled by a set of fields living inside iio_dev that we’ll unpack next.
Fields That Drive IIO Buffer Setup
The table below summarizes the fields you’ll touch when wiring up triggered buffer support in your driver. This is the core of IIO buffer setup linux kernel work, so take your time here.
| Field | Purpose |
|---|---|
buffer |
The kfifo/dmaengine data buffer pushed to user space; allocated automatically once you call iio_triggered_buffer_setup() |
scan_bytes |
Total bytes captured per scan cycle; the user-space read buffer must be at least this large |
available_scan_masks |
An optional list of the channel-enable combinations your hardware actually supports |
active_scan_mask |
A bitmask showing which channels are currently enabled for capture |
scan_timestamp |
Whether a 64-bit timestamp is appended as the last element of every scan |
trig |
The trigger currently driving this device, when buffer mode is active |
pollfunc |
The function invoked each time the trigger fires |
channels / num_channels |
The channel specification table and its length |
setup_ops |
Callbacks run around buffer enable/disable — see below |
available_scan_masks in Practice
Say you’re driving a 3-axis accelerometer with X, Y, and Z channels. If your hardware can only capture all three axes together or none at all, you’d restrict the mask so users can’t cherry-pick just X and Y. In bit terms, that means allowing 0b111 (all three) and 0b000 (none), and rejecting anything in between.
The iio_buffer_setup_ops Callbacks
Whenever a triggered buffer is enabled or disabled from user space, the IIO core calls back into your driver through setup_ops:
preenable— runs before the buffer starts; good place to power up hardwarepostenable— runs after buffer state is ready; often used to attach the poll functionpredisable— runs before the buffer is torn downpostdisable— runs after teardown; a natural place to power hardware back downvalidate_scan_mask— lets you reject a scan mask combination your hardware can’t honor
If you don’t supply setup_ops at all, the IIO core falls back to its own default triggered-buffer setup ops, which is enough for the simplest drivers.
power up hardware
attach poll function
samples pushed to user space
detach poll function
power hardware down
Allocating and Registering an IIO Device
Before any of the fields above matter, you need a live iio_dev instance. On a modern kernel the resource-managed helper is what you want almost every time:
struct my_sensor_priv {
struct mutex lock;
int gain;
};
static int my_sensor_probe(struct i2c_client *client)
{
struct iio_dev *indio_dev;
struct my_sensor_priv *priv;
indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*priv));
if (!indio_dev)
return -ENOMEM;
priv = iio_priv(indio_dev);
mutex_init(&priv->lock);
indio_dev->name = "my_sensor";
indio_dev->info = &my_sensor_info;
indio_dev->channels = my_sensor_channels;
indio_dev->num_channels = ARRAY_SIZE(my_sensor_channels);
indio_dev->modes = INDIO_DIRECT_MODE;
return devm_iio_device_register(&client->dev, indio_dev);
}
devm_iio_device_alloc() reserves memory for both the iio_dev structure and your own private data block in one call, and iio_priv() hands back a pointer to that private block. Because both calls are devm_-managed, the kernel tears everything down automatically when the device is removed — you don’t write a matching remove() cleanup path at all for these two steps.
Legacy vs Modern Allocation and Registration
| Step | Legacy Approach | Modern Kernel 6.x Approach |
|---|---|---|
| Allocate | iio_device_alloc(sizeof_priv), manual iio_device_free() in remove |
devm_iio_device_alloc(dev, sizeof_priv), auto-freed |
| Register | iio_device_register(indio_dev), manual iio_device_unregister() in remove |
devm_iio_device_register(dev, indio_dev), auto-unregistered |
| Error handling | Manual unwind ordering required | Handled by the devm core in reverse order |
Tip: The plain (non-devm) iio_device_alloc() and iio_device_register() calls still exist and still work, but every new driver merged into mainline today uses the devm variants unless there’s a very specific reason not to.
The iio_info Structure on Current Kernels
Every IIO device points to one iio_info structure, which the core uses to find your driver’s callbacks:
static const struct iio_info my_sensor_info = {
.read_raw = my_sensor_read_raw,
.write_raw = my_sensor_write_raw,
};
If you’ve seen older training material reference a .driver_module = THIS_MODULE line inside this structure, skip it — that field was removed from struct iio_info years ago and no longer exists on any supported kernel. Trying to set it will fail to build.
attrs— an optional sysfs attribute group for extra device attributesread_raw— called when user space reads a channel attribute; themaskparameter tells you whether the raw value, scale, or something else is being requestedwrite_raw— the write-side counterpart, used for things like setting sampling frequency or gain
Introducing iio_chan_spec
Every entry in your channels array is one iio_chan_spec describing a single acquisition line — an accelerometer with X, Y, and Z axes has three of these. The fields you’ll use immediately are:
type— the physical quantity, such asIIO_VOLTAGEorIIO_ACCELchannel— the index number assigned to this channelchannel2— a second index, used for differential channelsscan_index— position of this channel’s data inside a triggered buffer scaninfo_mask_separate— which per-channel attributes (raw, scale, and so on) are exposed to sysfs
A minimal single-channel voltage spec looks like this:
static const struct iio_chan_spec my_sensor_channels[] = {
{
.type = IIO_VOLTAGE,
.indexed = 1,
.channel = 0,
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
BIT(IIO_CHAN_INFO_SCALE),
},
};
We’ll go much deeper into iio_chan_spec — including scan_type, the full info_mask_* family, and modifiers — in the next lecture.
Build and Test Walkthrough
Compile and load your module against a running 6.x kernel tree, then confirm registration:
make -C /lib/modules/$(uname -r)/build M=$PWD modules
sudo insmod my_sensor.ko
dmesg | tail -n 5
ls /sys/bus/iio/devices/
Expected dmesg output on a successful probe:
my_sensor 1-0048: iio device registered as iio:device0
my_sensor 1-0048: probe complete
And you should see a new entry such as iio:device0 under /sys/bus/iio/devices/, with in_voltage0_raw and in_voltage0_scale attribute files inside it.
Common Mistakes and Troubleshooting
| Mistake | Symptom | Fix |
|---|---|---|
Forgetting to set indio_dev->info |
Null pointer dereference on first sysfs read | Always assign info before calling iio_device_register() |
Using plain iio_device_alloc() without a matching free |
Memory leak on module unload | Switch to devm_iio_device_alloc() |
Copying old .driver_module line into iio_info |
Build failure — no such member | Remove the field; it isn’t needed on modern kernels |
Mismatched scan_bytes and actual buffer size |
Truncated or garbled samples in user space | Size the read buffer to at least indio_dev->scan_bytes |
Best Practices
- Prefer
devm_iio_device_alloc()anddevm_iio_device_register()for new drivers - Keep
iio_chan_spectablesstatic const— they never change at runtime - Use
available_scan_maskswhenever your hardware can’t capture arbitrary channel combinations - Protect any shared private state with a mutex, as shown in earlier lectures of this course
Performance Considerations
Buffered, trigger-driven capture is far more CPU-efficient than polling sysfs in a tight user-space loop, since samples are pushed to a kernel-side buffer and read in bulk. Keep your pollfunc handler short — heavy work there adds latency to every single trigger event.
Security Considerations
Validate any scan mask or channel combination requested from user space inside validate_scan_mask rather than trusting it blindly; a malformed or unsupported mask should be rejected, not silently truncated.
Summary and Key Takeaways
iio_devcarries dedicated fields —buffer,scan_bytes,active_scan_mask,trig,pollfunc— purely for triggered buffer capturesetup_opsgives you five lifecycle hooks around buffer enable/disable- Modern IIO buffer setup relies on
devm_iio_device_alloc()anddevm_iio_device_register()instead of manual alloc/free pairs struct iio_infono longer has adriver_modulefield on current kernelsiio_chan_specis where each channel’s identity and sysfs exposure is declared
Conclusion
With the buffer-related fields of iio_dev, the modern allocation and registration flow, and the first layer of iio_chan_spec now covered, you have everything needed to register a working, modern IIO device. The next lecture in this free Linux kernel development course goes deep into the rest of iio_chan_spec — scan types, the full info_mask family, and channel modifiers — so you can describe real multi-channel hardware precisely.
Frequently Asked Questions
What is IIO buffer setup used for in Linux drivers?
It lets a driver stream many samples per trigger event into a kernel buffer that user space reads in bulk, instead of one value per sysfs read.
Do I need setup_ops for every IIO driver?
No. If you don’t supply it, the IIO core uses a sensible default triggered-buffer setup, which is enough for simple devices.
Is iio_device_alloc() still valid on kernel 6.x?
Yes, it still compiles and works, but new drivers should use the devm-managed devm_iio_device_alloc() so cleanup is automatic.
Why did my driver fail to build with a driver_module error?
That field was removed from struct iio_info years ago. Delete the line — it isn’t part of the current struct.
What does active_scan_mask actually contain?
A bitmask where each set bit corresponds to one channel currently enabled for buffered capture.
What is iio_priv() for?
It returns a pointer to the private data block reserved alongside the iio_dev when you called devm_iio_device_alloc(), so you can store per-device state.
Can I mix legacy and devm-managed IIO calls in one driver?
Technically yes, but it’s easy to create mismatched cleanup paths. Stick to one approach — devm-managed is recommended.
What is scan_index used for in iio_chan_spec?
It defines where a channel’s data lands inside the buffer during a triggered scan, which matters once you have more than one channel.
Where can I try this without real hardware?
You can build and load the demo driver in a QEMU virtual machine running a 6.x kernel with the IIO subsystem enabled, and test sysfs attributes the same way as on real hardware.
What comes after this lecture in the course?
The next lecture covers the remaining iio_chan_spec fields in depth — scan_type, the info_mask_* family, and channel modifiers — with a new original driver example.
Continue the Free Linux Kernel Development Course
More IIO framework lectures, device driver tutorials, and Bluetooth stack guides — all free on EmbeddedPathashala.
