* [PATCH] Make userspace tools accept device file paths
@ 2026-02-19 3:28 Brigham Campbell
2026-02-23 0:52 ` Brigham Campbell
0 siblings, 1 reply; 2+ messages in thread
From: Brigham Campbell @ 2026-02-19 3:28 UTC (permalink / raw)
To: Jean Delvare, linux-i2c
Cc: Wolfram Sang, Brigham Campbell, Gero Schwäricke
The userspace i2c utilities already allow the user to select an i2c bus
controller via either ID or the bus's unique name (as shown by
`i2cdetect -l`). It would be convenient to also be able to specify the
device file path. This would allow system administrators to create a
stable symlink to any particular i2c controller and pass the symlink to
i2cget, i2cset, etc... directly.
This commit changes lookup_i2c_bus to also allow for device file paths.
The i2cbus_arg string is now treated as follows:
If it can be parsed as a number, return that number directly.
Otherwise, if it can be stat'ed as a path and is a character device file
of major device type 89, return the character device's minor number.
Otherwise, parse the string as an i2c bus controller name.
This will likely incur a small performance hit for users that pass the
i2c bus name, but users concerned with performance should be linking
against libi2c anyways.
Suggested-by: Gero Schwäricke <gero.schwaericke@sevenlab.de>
Signed-off-by: Brigham Campbell <me@brighamcampbell.com>
---
I tested these changes by compiling and running i2cget and i2cset,
passing in i2c bus IDs, device file paths, and names.
Gero suggested this change on the linux-i2c mailing list recently.
Link: https://lore.kernel.org/linux-i2c/DE53PTBTBBBY.24N093ZM03IKQ@sevenlab.de/
Yikes. I better go finish my homework before it's late... Thanks for
reading this far!
---
tools/i2cbusses.c | 31 +++++++++++++++++++++++++------
tools/i2cdetect.8 | 12 ++++++------
tools/i2cdetect.c | 2 +-
tools/i2cdump.8 | 7 ++++---
tools/i2cdump.c | 2 +-
tools/i2cget.8 | 6 +++---
tools/i2cget.c | 2 +-
tools/i2cset.8 | 6 +++---
tools/i2cset.c | 2 +-
tools/i2ctransfer.8 | 6 +++---
tools/i2ctransfer.c | 2 +-
11 files changed, 49 insertions(+), 29 deletions(-)
diff --git a/tools/i2cbusses.c b/tools/i2cbusses.c
index d687615..32f51bf 100644
--- a/tools/i2cbusses.c
+++ b/tools/i2cbusses.c
@@ -23,6 +23,7 @@
#include <sys/types.h>
#include <sys/stat.h>
+#include <sys/sysmacros.h>
#include <sys/param.h> /* for NAME_MAX */
#include <sys/ioctl.h>
#include <string.h>
@@ -348,15 +349,24 @@ static int lookup_i2c_bus_by_name(const char *bus_name)
}
}
- if (i2cbus == -1)
- fprintf(stderr, "Error: I2C bus name doesn't match any "
- "bus present!\n");
-
done:
free_adapters(adapters);
return i2cbus;
}
+static int lookup_i2c_bus_by_path(const char *path)
+{
+ struct stat stat_buf;
+
+ if (stat(path, &stat_buf))
+ return -1;
+
+ if ((!S_ISCHR(stat_buf.st_mode)) || (major(stat_buf.st_rdev) != 89))
+ return -2;
+
+ return minor(stat_buf.st_rdev);
+}
+
/*
* Parse an I2CBUS command line argument and return the corresponding
* bus number, or a negative value if the bus is invalid.
@@ -365,11 +375,20 @@ int lookup_i2c_bus(const char *i2cbus_arg)
{
unsigned long i2cbus;
char *end;
+ int char_dev = 0;
i2cbus = strtoul(i2cbus_arg, &end, 0);
if (*end || !*i2cbus_arg) {
- /* Not a number, maybe a name? */
- return lookup_i2c_bus_by_name(i2cbus_arg);
+ /* Not a number, maybe a path? */
+ char_dev = lookup_i2c_bus_by_path(i2cbus_arg);
+ if (char_dev >= 0)
+ return char_dev;
+ /* Not a character device file path, maybe a name? */
+ char_dev = lookup_i2c_bus_by_name(i2cbus_arg);
+ if (char_dev == -1)
+ fprintf(stderr, "Error: I2C bus argument doesn't match"
+ " any bus name or character device file!\n");
+ return char_dev;
}
if (i2cbus > 0xFFFFF) {
fprintf(stderr, "Error: I2C bus out of range!\n");
diff --git a/tools/i2cdetect.8 b/tools/i2cdetect.8
index 5935b2b..034476c 100644
--- a/tools/i2cdetect.8
+++ b/tools/i2cdetect.8
@@ -24,12 +24,12 @@ i2cdetect \- detect I2C chips
.I -l
.SH DESCRIPTION
-i2cdetect is a userspace program to scan an I2C bus for devices. It
-outputs a table with the list of detected devices on the specified bus.
-\fIi2cbus\fR indicates the number or name of the I2C bus to be scanned, and
-should correspond to one of the busses listed by \fIi2cdetect -l\fR.
-The optional parameters \fIfirst\fR and \fIlast\fR restrict the scanning
-range (default: from 0x08 to 0x77).
+i2cdetect is a userspace program to scan an I2C bus for devices. It outputs a
+table with the list of detected devices on the specified bus. \fIi2cbus\fR
+indicates the number, name, or device file path of the I2C bus to be scanned
+(\fIi2cdetect -l\fR may be used to display I2C bus numbers and names). The
+optional parameters \fIfirst\fR and \fIlast\fR restrict the scanning range
+(default: from 0x08 to 0x77).
.PP
As there is no standard I2C detection command, i2cdetect uses arbitrary
SMBus commands (namely SMBus quick write and SMBus receive byte) to probe
diff --git a/tools/i2cdetect.c b/tools/i2cdetect.c
index bb2f146..6cc34ff 100644
--- a/tools/i2cdetect.c
+++ b/tools/i2cdetect.c
@@ -38,7 +38,7 @@ static void help(void)
"Usage: i2cdetect [-y] [-a] [-q|-r] I2CBUS [FIRST LAST]\n"
" i2cdetect -F I2CBUS\n"
" i2cdetect -l\n"
- " I2CBUS is an integer or an I2C bus name\n"
+ " I2CBUS is an integer, I2C bus name, or I2C character device file path\n"
" If provided, FIRST and LAST limit the probing range.\n");
}
diff --git a/tools/i2cdump.8 b/tools/i2cdump.8
index 6ede625..e1ce463 100644
--- a/tools/i2cdump.8
+++ b/tools/i2cdump.8
@@ -52,9 +52,10 @@ scripts.
Allow using addresses between 0x00 - 0x07 and 0x78 - 0x7f. Not recommended.
.PP
At least two options must be provided to i2cdump. \fIi2cbus\fR indicates the
-number or name of the I2C bus to be scanned. This number should correspond to one
-of the busses listed by \fIi2cdetect -l\fR. \fIaddress\fR indicates the
-address to be scanned on that bus, and is an integer between 0x08 and 0x77.
+number, name, or device file path of the I2C bus to be scanned (\fIi2cdetect
+-l\fR may be used to display I2C bus numbers and names). \fIaddress\fR
+indicates the address to be scanned on that bus, and is an integer between 0x08
+and 0x77.
.PP
The \fImode\fR parameter, if specified, is one of the letters \fBb\fP, \fBw\fP,
or \fBi\fP, corresponding to a read size of a single byte, a 16-bit
diff --git a/tools/i2cdump.c b/tools/i2cdump.c
index d315e2f..491ca56 100644
--- a/tools/i2cdump.c
+++ b/tools/i2cdump.c
@@ -32,7 +32,7 @@ static void help(void)
{
fprintf(stderr,
"Usage: i2cdump [-f] [-y] [-r first-last] [-a] I2CBUS ADDRESS [MODE [BANK [BANKREG]]]\n"
- " I2CBUS is an integer or an I2C bus name\n"
+ " I2CBUS is an integer, I2C bus name, or I2C character device file path\n"
" ADDRESS is an integer (0x08 - 0x77, or 0x00 - 0x7f if -a is given)\n"
" MODE is one of:\n"
" b (byte, default)\n"
diff --git a/tools/i2cget.8 b/tools/i2cget.8
index 69586cc..0e7e8df 100644
--- a/tools/i2cget.8
+++ b/tools/i2cget.8
@@ -45,9 +45,9 @@ scripts. Use with caution.
.B -a
Allow using addresses between 0x00 - 0x07 and 0x78 - 0x7f. Not recommended.
.PP
-There are two required options to i2cget. \fIi2cbus\fR indicates the number
-or name of the I2C bus to be scanned. This number should correspond to one of
-the busses listed by \fIi2cdetect -l\fR. \fIchip-address\fR specifies the
+There are two required options to i2cget. \fIi2cbus\fR indicates the number,
+name, or device file path of the I2C bus to be scanned (\fIi2cdetect -l\fR may
+be used to display I2C bus numbers and names). \fIchip-address\fR specifies the
address of the chip on that bus, and is an integer between 0x08 and 0x77.
.PP
\fIdata-address\fR specifies the address on that chip to read from, and is
diff --git a/tools/i2cget.c b/tools/i2cget.c
index 17d78bf..1707fbd 100644
--- a/tools/i2cget.c
+++ b/tools/i2cget.c
@@ -35,7 +35,7 @@ static void __attribute__ ((noreturn)) help(int status)
{
fprintf(stderr,
"Usage: i2cget [-f] [-y] [-a] I2CBUS CHIP-ADDRESS [DATA-ADDRESS [MODE [LENGTH]]]\n"
- " I2CBUS is an integer or an I2C bus name\n"
+ " I2CBUS is an integer, I2C bus name, or I2C character device file path\n"
" ADDRESS is an integer (0x08 - 0x77, or 0x00 - 0x7f if -a is given)\n"
" MODE is one of:\n"
" b (read byte data, default)\n"
diff --git a/tools/i2cset.8 b/tools/i2cset.8
index e4e1870..3b53d9e 100644
--- a/tools/i2cset.8
+++ b/tools/i2cset.8
@@ -65,9 +65,9 @@ apply as those of option \fB-m\fR.
.B -a
Allow using addresses between 0x00 - 0x07 and 0x78 - 0x7f. Not recommended.
.PP
-There are three required options to i2cset. \fIi2cbus\fR indicates the number
-or name of the I2C bus to be scanned. This number should correspond to one of
-the busses listed by \fIi2cdetect -l\fR. \fIchip-address\fR specifies the
+There are three required options to i2cset. \fIi2cbus\fR indicates the number,
+name, or device file path of the I2C bus to be scanned (\fIi2cdetect -l\fR may
+be used to display I2C bus numbers and names). \fIchip-address\fR specifies the
address of the chip on that bus, and is an integer between 0x08 and 0x77.
\fIdata-address\fR specifies the address on that chip to write to, and is an
integer between 0x00 and 0xFF.
diff --git a/tools/i2cset.c b/tools/i2cset.c
index aaf7faf..68ce9b6 100644
--- a/tools/i2cset.c
+++ b/tools/i2cset.c
@@ -32,7 +32,7 @@ static void __attribute__ ((noreturn)) help(int status)
{
fprintf(stderr,
"Usage: i2cset [-f] [-y] [-m MASK] [-r] [-a] I2CBUS CHIP-ADDRESS DATA-ADDRESS [VALUE] ... [MODE]\n"
- " I2CBUS is an integer or an I2C bus name\n"
+ " I2CBUS is an integer, I2C bus name, or I2C character device file path\n"
" ADDRESS is an integer (0x08 - 0x77, or 0x00 - 0x7f if -a is given)\n"
" MODE is one of:\n"
" c (byte, no value)\n"
diff --git a/tools/i2ctransfer.8 b/tools/i2ctransfer.8
index 4bdf436..51a3e58 100644
--- a/tools/i2ctransfer.8
+++ b/tools/i2ctransfer.8
@@ -84,9 +84,9 @@ This is mainly meant to be used in scripts.
.PP
The first parameter
.I i2cbus
-indicates the number or name of the I2C bus to be used.
-This number should correspond to one of the busses listed by
-.B i2cdetect -l.
+indicates the number, name, or device file path of the I2C bus to be used.
+.B i2cdetect -l
+may be used to display I2C bus numbers and names.
.PP
The next parameter is one or multiple
diff --git a/tools/i2ctransfer.c b/tools/i2ctransfer.c
index 4db98e3..4ab37a6 100644
--- a/tools/i2ctransfer.c
+++ b/tools/i2ctransfer.c
@@ -51,7 +51,7 @@ static void help(void)
" -v verbose mode\n"
" -V version info\n"
" -y yes to all confirmations\n"
- " I2CBUS is an integer or an I2C bus name\n"
+ " I2CBUS is an integer, I2C bus name, or I2C character device file path\n"
" DESC describes the transfer in the form: {r|w}LENGTH[@address]\n"
" 1) read/write-flag 2) LENGTH (range 0-65535, or '?')\n"
" 3) I2C address (use last one if omitted)\n"
base-commit: c1b0305972e89aae048068a3b228f35ef0206243
--
2.52.0
^ permalink raw reply related [flat|nested] 2+ messages in thread* Re: [PATCH] Make userspace tools accept device file paths
2026-02-19 3:28 [PATCH] Make userspace tools accept device file paths Brigham Campbell
@ 2026-02-23 0:52 ` Brigham Campbell
0 siblings, 0 replies; 2+ messages in thread
From: Brigham Campbell @ 2026-02-23 0:52 UTC (permalink / raw)
To: Brigham Campbell, Jean Delvare, linux-i2c
Cc: Wolfram Sang, Gero Schwäricke
On Wed Feb 18, 2026 at 8:28 PM MST, Brigham Campbell wrote:
> if it can be stat'ed as a path and is a character device file
> of major device type 89, return the character device's minor number.
After stewing on it while driving down Interstate 15, I think I've taken
the wrong approach with this patch. Specifically, the I2C device major
number is _not_ a part of the stable ABI (as suggested by I2C_MAJOR
being present in /include/linux/i2c-dev.h instead of /include/uapi/...).
Because it's not a part of the stable ABI, I shouldn't be relying on it
to identify I2C character devices.
If I simply remove the check against the magic value 89, then that opens
up some very unexpected edge cases. For example, a user could invoke
`i2cget /dev/video0 ...`, which would cause the code to recognize
/dev/video0 as a character device and use its device minor number to
construct a new file path of /dev/i2c-0. I fear that users would
(rightfully) curse my name if they stumbled upon this "clever" kind of
behavior.
So either I need to switch up this patch to make lookup_i2c_bus return a
file path instead of an integer or I2C_MAJOR needs to become a part of
the stable ABI (Are most major numbers intentionally excluded from the
ABI?).
Making lookup_i2c_bus return more than just the minor device number as
an integer requires some more invasive changes and more design thought
(particularly because the current code will try to open both
/dev/i2c-<N> and /dev/i2c/<N>, which suggests that lookup_i2c_bus should
either return a list of paths or some sort of new `i2c_path_hints`
struct).
I'll go ahead and whip up a new revision soon. After I've finished my
homework, that is...
Brigham
^ permalink raw reply [flat|nested] 2+ messages in thread
end of thread, other threads:[~2026-02-23 0:52 UTC | newest]
Thread overview: 2+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-02-19 3:28 [PATCH] Make userspace tools accept device file paths Brigham Campbell
2026-02-23 0:52 ` Brigham Campbell
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox