As of 2015 (nearly 10 years ago!) over half the code in the Linux kernel concerns itself with "devices".
I've been worrying over an issue for the past few days, and doing some reading in an effort to find a solution. The statement above was taken from a really good article in LWN written by Neil Brown. It's one of the many "postings" I've read on the subject of udev
, sysfs
and "devices".
Unfortunately for all of us, there don't seem to be many really good articles on the subject of udev, sysfs & i2c devices
! In fact, I'll opine that far too much of the documentation is the completely brain-dead products of wastrels. For some objective evidence to support that opinion, I'll suggest that you do a search on linux hwmon subsystem. When I did my search, the "Linux hwmon Subsystem Wiki" appeared in the very first spot in my search results. I tried following the advice in the FAQ under Installation and Management. That dismal experience led me to post this issue on the lm-sensor
GitHub site: Is lm-sensors
completely useless - or am I doing something wrong?#502. If they haven't deleted it yet, you might get a laugh :)
So now you know what my opinion is of much (not all) of the corpus of Linux documentation on the subject of udev, sysfs & i2c devices
. And it's just as Neil Brown described it in his article; the fundamental problem is a lack of clear definitions of the terminology used. Is computer science an oxymoron? How would the real sciences have gotten on with such sloppy habits?
I had a problem with this recipe! The problem was that the folder containing the 'sht3x' sensor data (temperature & humidity) changed names after a reboot
, or if another sensor was added. An inconsistent device folder name meant that my script would need to grep
(or find
) the new folder location at each invocation - or cache it in /tmp
. This was a "shell game" I did not want to play!
I found an article titled 'Rules on how to access information in sysfs' published as an element of documentation for the Linux kernel. The article was reasonably straightforward AFAICT - except that some of the "rules" made no sense to me (that terminology problem again). But there was also this:
To minimize the risk of breaking users of sysfs, which are in most cases low-level userspace applications, with a new kernel release, the users of sysfs must follow some rules to use an as-abstract-as-possible way to access this filesystem. The current udev and HAL programs already implement this and users are encouraged to plug, if possible, into the abstractions these programs provide instead of accessing sysfs directly.
And so I launched into reading about udev
. I'd heard of it, but had never actually used it (big difference!). I've listed below some "How-To" references for udev
that I found useful, but in fairly short order I had cobbled together a .rule
file. Following is my initial result at a .rules
file:
ACTION=="add", SUBSYSTEM=="hwmon", ATTR{name}=="sht3x", KERNELS=="0-0044", SUBSYSTEMS=="i2c", SYMLINK+="i2c_sht3x"
For those who've never mucked around w/ udev
, the "rule" consists mainly of match keys and assignment keys. In general, match keys use the ==
test to determine a match, and assignment keys use =
or +=
to designate something that is to be done in the event of a match. NB: This is a gross simplification, but hopefully communicates the basic idea of the "rule".
You might be wondering, "where did you get all of this jargon for the rule?", and you would be right to wonder! The answer is I asked for it with this command:
$ udevadm info --attribute-walk --path=/sys/bus/i2c/devices/0-0044/hwmon/hwmon3
I won't clutter this recipe with the output of this command (it's fairly verbose), but I've posted a couple of samples at pastebin that you can review if you'd like. The terms/parameters chosen for the match keys were mostly trial-and-error, but I had some examples to use as go-bys.
I tested the rule (following this idea) by replacing the SYMLINK
assignment key with a command to run a shell script that wrote to a file. The rule file was named /etc/udev/rules.d/80-local.rules
ACTION=="add", SUBSYSTEM=="hwmon", ATTR{name}=="sht3x", KERNELS=="0-0044", SUBSYSTEMS=="i2c", RUN+="/bin/sh -c 'echo "success" > /tmp/udev_test.txt'"
This actually worked, which told me I was probably on the right track. At least I knew my match keys were filtering some thing out of the stream, and I thought it likely it was the right thing based on the parameters.
I changed my rule again to restore the SYMLINK+="i2c_sht3x"
assignment key, and I had great confidence that I would find a symlink named i2c_sht3x
in my /dev
folder after the next reboot
. But I was disappointed... No such symlink appeared. I spent a fruitless couple of hours searching for an explanation. Then it occurred to me to try some thing else - the following rule was put in place, and IT WORKED:
See the complete, fully-commented 80-local.rules
file here in the source
folder.
ACTION=="add", SUBSYSTEM=="hwmon", ATTR{name}=="sht3x", KERNELS=="0-0044", SUBSYSTEMS=="i2c", RUN+="/bin/sh -c 'ln -s /sys$devpath /dev/hwmon_sht3x'"
As I write this, I still do not know why the SYMLINK+="i2c_sht3x"
assignment key did not work. However, I do have some confidence in the WORKING RULE. I hope you'll try it, and would like to get your feedback.
- An introduction to Udev: The Linux subsystem for managing device events
- Writing udev rules; a bit dated, but still useful!
- Monitor Device Events in Linux; a Baeldung article
- Scripting with udev; if you need to invoke
systemd
fromudev
- The Linux Hardware Monitoring kernel API - Linux Kernel documentation; i.e. what is
hwmon
? - Linux I2C Sysfs - Linux Kernel documentation
- Rules on how to access information in sysfs - Linux Kernel documentation
- How to instantiate I2C from the userspace
- Naming and data format standards for sysfs files - Linux Kernel documentation
- kernel.org/doc/Documentation/hwmon/sysfs-interface; could this be any more disorganized?