Industrial I/O is mostly a userspace interface, that has existed for 10 years now. This talk reviews where it came from, its architecture and community, and some of the mistakes it made.
IIO started with a personal itch of Jonathan. He was in an academic project that stuck sensors on athletes. It used an Intel IMote2, a Linux board with a kind of capes. They needed sensor drivers (accelerometers, ADCs) so they developed them, and they wanted to upstream it but where should it go? It’s something like hwmon, but you want to do efficient streaming. Input has an event system that is not too bad, but it’s really meant for human input. They asked LKML, and the answer was that it had to be something new.
When Jonathan started working in, a whole lot of other requirements came in from other users.
IIO started out with posts to LKML. There were long pauses between the feedback. At that time, the staging system was coming up, and IIO went through there because the userspace ABI wasn’t stable yet. Then they jumped out (together with a bunch of drivers) when the interface was stable enough. Now there are still some drivers in staging. Adding new drivers is slowing down now, because sensor manufacturers are finally standardizing their interfaces.
IIO is not a replacement for hwmon or input. First tried as a specific subsystem for ambient light sensor. But Linus said “it’s cray to start a new subsystem for every little thing”. So the definition of IIO ended up with anything that is a kind of ADC or DAC. Includes, actual ADCs and DACs, but also accelerometers, gyroscopers, magnetometers, IMUs, light sensors, chemical sensors, health sensors, rotation sensors.
Goal of IIO is to allow for generic userspace code: libiio, iio-sensor-proxy (Gnome), android-iio-sensors-hal. This interface should be consistent, ideally no need to read the docs. So they decided that all I/O would go through sysfs, and that it would be human readable, not binary. For high-speed FIFOs an events there are character devices.
The internal architecture of IIO has two possible use cases: either polled read, or triggers and buffers. The trigger causes a set of concurrent samples to be captures, which are then transferred into a FIFO.
Synchronous read is pretty straighforward. The IIO core is mainly involved for doing formatting and conversion. It also enforces the userspace ABI, so reviewers are not burdened with doublechecking that it’s consistent. The core also makes it possible to provide a kernel interface for free, so on top of an IIO device it’s possible to create a hwmon, thermal, battery or even other IIO device.
The asynchronous system is a bit more complicated. The trigger can come from a different device (for synchronous reading of different sensors, e.g. gyro and accelero). The data originally just went into a kfifo, but they inserted a demuxer in front of it so it’s possible to support in-kernel consumers as well.
However, there is still a tight coupling between the userspace interface and the driver. It’s not possible to not have a userspace interface, even if there is only a need for an in-kernel consumer (e.g. because it’s used as a hwmon device). That’s something that needs to be fixed. Also the userspace interface should be treated as just one more in-kernel user, instead of something special.
The subsystem is quite complicated, but that’s to make it flexible. Not all devices need to provide all of this.
The in-kernel interface allows to do cool things. For example, with a DAC and a comparator you can make an ADC.
Mistakes that were made:
Local simplicity which leads to general complexity. For example, an accelerometer typically has an axis instead of an index, so you should have either an axis (for accelero) or an index (for ADC). However, a more complex accelerometer will need both, but then userspace has to be adapted to support that.
Compatibility with existing ABI may make things more complicated. They reused units from hwmon instead of SI units, which leads to many mistakes because it’s not so consistent.
Counter drivers were introduced in IIO, but they actually don’t work well in IIO. Now it’s moving out into a separate subsystem, but the historic ABI has to be maintained.
A current problem is that the sysfs interface has no indication of interest, so if there is an ongoing stream, it’s hard to know that a channel has to be added for a single capture.
There is no support in mainline (core) at the moment for high-speed devices that have additional complexity, e.g. complex triggers or specific DMA requirements.
Community: a lot of drivers are contributed by companies, but also a lot by hobbyist. Also Outreachy and students. Reviewers are really important, also mentorship of new contributors. Why so many hobbyist? Because they are tangible, cheap devices that are relatively simple. There is also a history of new contributions, which serves as decent documentation of how to do things.