Linux IIO Buffer Sysfs Interface
Free Linux Kernel Development Course — IIO Framework, Lecture 8
| ← PREV_LEC | NEXT_LEC → |
In lddch10_7 we learned how a trigger tells a device “capture now.” This lecture completes the picture with the other side of continuous data capture in the IIO framework: the buffer itself, and the three sysfs attributes — length, enable, and watermark — that every triggered-buffer driver in this free Linux device drivers course needs to understand. By the end, you will know exactly what each attribute controls and how your driver code should respond to it.
This Lecture Covers
free embedded systems course
free linux development course
iio buffer sysfs interface
iio watermark attribute
What You Will Learn
- Where the IIO buffer’s sysfs attributes live and how they relate to
/dev/iio:deviceX - What
length,enable, andwatermarkeach control from user space - How a driver fills the buffer using
iio_push_to_buffers_with_timestamp() - How to build an original watermark-aware demo driver,
ep_iio_watermark_demo - How to test blocking reads against the watermark attribute, with expected output
Prerequisites
- Completed lddch10_6 (triggered buffer setup) and lddch10_7 (trigger sysfs interface)
- Familiarity with
poll()orselect()from user space - A kernel 6.x build tree with IIO buffer support enabled
Where the Buffer Lives
An IIO buffer provides continuous capture of more than one channel at once, and user space reads the captured samples through a character device node, /dev/iio:deviceX. Everything that controls how that buffer behaves, though, is exposed separately as plain sysfs attribute files under the device’s buffer directory.
/sys/bus/iio/devices/iio:device0/ /dev/iio:device0
+– buffer/
+– length (capacity) |
+– enable (start/stop) v
+– watermark (blocking read size) [ samples flow out ]
Inside the kernel, the function a driver calls from its trigger handler to push one sample into the buffer is iio_push_to_buffers_with_timestamp(), and the buffer itself is allocated for the device with iio_triggered_buffer_setup() or its resource-managed form, devm_iio_triggered_buffer_setup(), which we already used in lddch10_6.
The length Attribute
buffer/length sets the total number of scans (samples) the buffer can hold — its capacity. This must be set before the buffer is enabled, and it directly affects how much data can accumulate before user space needs to read it out.
# Check current buffer capacity
$ cat /sys/bus/iio/devices/iio:device0/buffer/length
0
# Set capacity to 128 scans
$ echo 128 > /sys/bus/iio/devices/iio:device0/buffer/length
The enable Attribute
Writing 1 to buffer/enable starts capture; writing 0 stops it. This is the switch that actually calls into your driver’s preenable/postenable callbacks from the iio_buffer_setup_ops structure we covered in lddch10_3.
# Start capture
$ echo 1 > /sys/bus/iio/devices/iio:device0/buffer/enable
# Stop capture
$ echo 0 > /sys/bus/iio/devices/iio:device0/buffer/enable
The watermark Attribute
This is the attribute most students find confusing, so let’s be precise about what it does. watermark is a positive integer specifying how many scans a blocking read (or a poll() call) should wait for before it returns. It only matters when the watermark value is greater than what a single read() call is requesting — and it has no effect at all on non-blocking reads.
# Ask poll()/blocking read to wait for 32 scans before returning
$ echo 32 > /sys/bus/iio/devices/iio:device0/buffer/watermark
In practice, this lets you trade latency for efficiency: a low watermark returns data quickly but wakes your application often; a high watermark batches more samples per wakeup, which is friendlier to power consumption on a battery-powered embedded system.
Buffer Attributes at a Glance
| Attribute | Purpose | Typical Value |
|---|---|---|
length |
Total buffer capacity in scans | 64–256 |
enable |
Starts or stops capture | 0 or 1 |
watermark |
Scans to wait for on a blocking read | 1–length |
Building ep_iio_watermark_demo
Let’s put this together in an original driver that extends ep_iio_trigbuf_demo from lddch10_6 with an explicit watermark-aware buffer setup. The interesting part is in preenable, where we read back the watermark the user requested and size our internal handling around it.
#include <linux/iio/iio.h>
#include <linux/iio/buffer.h>
#include <linux/iio/triggered_buffer.h>
#include <linux/iio/trigger_consumer.h>
struct ep_watermark_priv {
struct iio_dev *indio_dev;
s64 timestamp;
};
static irqreturn_t ep_watermark_trigger_handler(int irq, void *p)
{
struct iio_poll_func *pf = p;
struct iio_dev *indio_dev = pf->indio_dev;
struct ep_watermark_priv *priv = iio_priv(indio_dev);
s16 sample_buf[8]; /* room for channel data + padding */
/* Example: read one raw channel value from our simulated sensor */
sample_buf[0] = 0x014d; /* placeholder sample value */
priv->timestamp = iio_get_time_ns(indio_dev);
iio_push_to_buffers_with_timestamp(indio_dev, sample_buf, priv->timestamp);
iio_trigger_notify_done(indio_dev->trig);
return IRQ_HANDLED;
}
static int ep_watermark_preenable(struct iio_dev *indio_dev)
{
unsigned int watermark = indio_dev->buffer->watermark;
dev_info(&indio_dev->dev,
"ep_iio_watermark_demo: buffer enabled, watermark=%u scans\n",
watermark);
return 0;
}
static const struct iio_buffer_setup_ops ep_watermark_buffer_ops = {
.preenable = ep_watermark_preenable,
};
static int ep_watermark_probe(struct platform_device *pdev)
{
struct iio_dev *indio_dev;
struct ep_watermark_priv *priv;
int ret;
indio_dev = devm_iio_device_alloc(&pdev->dev, sizeof(*priv));
if (!indio_dev)
return -ENOMEM;
priv = iio_priv(indio_dev);
priv->indio_dev = indio_dev;
indio_dev->name = "ep_iio_watermark_demo";
indio_dev->modes = INDIO_BUFFER_TRIGGERED;
ret = devm_iio_triggered_buffer_setup(&pdev->dev, indio_dev,
NULL,
ep_watermark_trigger_handler,
&ep_watermark_buffer_ops);
if (ret)
return ret;
return devm_iio_device_register(&pdev->dev, indio_dev);
}
The key line for this lecture is indio_dev->buffer->watermark inside preenable — this is exactly the value that was written to the watermark sysfs file, and reading it back lets your driver log or adapt to it. Everything else in this driver follows the same triggered-buffer pattern from lddch10_6, using the modern resource-managed devm_iio_triggered_buffer_setup() API rather than the legacy manual-cleanup version.
Testing the Watermark With a Blocking Read
# Load the driver
$ sudo insmod ep_iio_watermark_demo.ko
# Configure buffer: capacity 64, wait for 16 scans before unblocking
$ echo 64 > /sys/bus/iio/devices/iio:device0/buffer/length
$ echo 16 > /sys/bus/iio/devices/iio:device0/buffer/watermark
$ echo sysfstrig5 > /sys/bus/iio/devices/iio:device0/trigger/current_trigger
$ echo 1 > /sys/bus/iio/devices/iio:device0/buffer/enable
# Fire the trigger 16 times in a loop from another terminal
$ for i in $(seq 16); do echo 1 > /sys/bus/iio/devices/trigger5/trigger_now; done
# A blocking read only returns once all 16 scans have arrived
$ dd if=/dev/iio:device0 bs=32 count=1 2>/dev/null | hexdump -C | head -1
00000000 4d 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00
Expected behaviour: the dd command appears to hang until the sixteenth trigger_now write completes, then returns immediately with the accumulated data — exactly what the watermark attribute is designed to control.
Common Mistakes and Troubleshooting
- Setting watermark after enable — most drivers only read the watermark once, during
preenable; change it before enabling the buffer. - watermark greater than length — the buffer can never reach a watermark bigger than its own capacity; keep
watermark <= length. - Blocking read that never returns — usually means the trigger is not actually firing; verify with the trigger sysfs steps from lddch10_7 first.
- enable fails with “Device or resource busy” — a trigger must be attached via
current_triggerbefore you can enable the buffer.
Best Practices
- Always set
lengthandwatermarkbefore writing1toenable, in that order. - Pick a watermark that balances responsiveness against how often your user-space application can afford to wake up.
- Log the watermark value in
preenableduring development — it is the fastest way to confirm user space configured the buffer the way you expect.
Key Takeaways
length,enable, andwatermarkare the three sysfs attributes that control every IIO buffer- Data itself never goes through sysfs — it flows through the
/dev/iio:deviceXcharacter device watermarkonly affects blocking reads andpoll(), never non-blocking reads- A driver reads the watermark back from
indio_dev->buffer->watermark, typically insidepreenable
Conclusion
With triggers (lddch10_7) and the buffer’s own length/enable/watermark attributes covered here, you now have the complete picture of continuous data capture in the IIO framework — from user-space configuration all the way down to the trigger handler pushing samples with iio_push_to_buffers_with_timestamp(). This closes out the buffer sysfs interface topic in this free Linux kernel development course; the next lecture moves on to IIO events, the mechanism IIO uses for threshold and one-shot notifications rather than continuous streams.
Frequently Asked Questions
What is the difference between buffer/length and buffer/watermark?
length is the total capacity of the buffer in scans. watermark is how many of those scans a blocking read should wait to accumulate before returning — it must always be less than or equal to length.
Does the watermark attribute affect non-blocking reads?
No. Non-blocking reads return immediately with whatever data is currently available, regardless of the watermark setting.
Which kernel version introduced the watermark attribute?
The watermark attribute has been available since Linux kernel version 4.2, and it remains part of the standard IIO buffer sysfs interface in current kernels.
Can I change length while the buffer is enabled?
No. Disable the buffer first with echo 0 > buffer/enable, change length, then re-enable it.
What function does a driver call to push a sample into the buffer?
iio_push_to_buffers_with_timestamp(), typically called from the bottom-half trigger handler registered during devm_iio_triggered_buffer_setup().
Why does my read() call block forever even after enabling the buffer?
The buffer only fills when its attached trigger actually fires. Confirm a trigger is attached via current_trigger and is firing, as covered in lddch10_7, before troubleshooting the buffer itself.
Is /dev/iio:deviceX always present once IIO is loaded?
The character device node appears once the IIO device is registered, but it only produces data once a buffer is configured (length set) and enabled with a working trigger attached.
Continue the Free Linux Kernel Development Course
Next up: IIO events — threshold and one-shot notifications in the IIO framework.
| ← PREV_LEC | NEXT_LEC → |
