ENXIO 对于 i2c ioctl 意味着什么?
What does ENXIO mean for an i2c ioctl?
我有一个 i2c 适配器作为 /dev/i2c-0
暴露给用户空间。当我在该适配器上使用 i2c-tools 包中的 i2cdetect
时,我看到我的设备列在该适配器上并且我能够从命令行对其执行获取、设置和转储操作。
我有一些 C 代码尝试使用 ioctl I2C_RDWR
操作对其执行写入。
这是我正在使用的精简代码(仅为上下文提供,运行回答问题并不重要)。
fd = open ("/dev/i2c-0", O_RDWR | O_NONBLOCK);
/* other stuff happens here */
if (ioctl (fd, I2C_FUNCS, &funcs) != 0)
return -1;
if (!(funcs & I2C_FUNC_I2C))
return -1;
/* i added this bit of debug just to be sure fd didn't
* get inadvertently closed along the way.
*/
if (fcntl (fd, F_GETFD) != 0) {
return -1;
}
/* build the ioctl message payload */
ret = ioctl (fd, I2C_RDWR, &payload)
if (ret) {
fprintf (stderr, "ioctl returned %d. Reason: %s (errno=%d).",
ret, strerror(errno), errno);
return -1;
}
return 0;
我也试过使用 smbus ioctl 函数,看起来像这样。
fd = open ("/dev/i2c-0", O_RDWR | O_NONBLOCK);
/* other stuff happens here */
if (ioctl (fd, I2C_FUNCS, &funcs) != 0)
return -1;
if (!(funcs & I2C_FUNC_SMBUS_WORD_DATA))
return -1;
/* i added this bit of debug just to be sure fd didn't
* get inadvertently closed along the way.
*/
if (fcntl (fd, F_GETFD) != 0) {
return -1;
}
/* build the ioctl smbus message payload */
if (ioctl (fd, I2C_SLAVE_FORCE, dev) != 0)
return -1;
ret = ioctl (fd, I2C_SMBUS, &payload);
if (ret) {
fprintf (stderr, "ioctl returned %d. Reason: %s (errno=%d).",
ret, strerror(errno), errno);
return -1;
}
return 0;
在所有情况下,程序总是命中 fprintf
,这是输出:
ioctl returned -1. Reason: No such device or address (errno=6).
根据 man 3 ioctl
,ENXIO 错误的 "generic" 原因是:
ENXIO The request and arg arguments are valid for this device driver, but the service requested cannot be performed on this particular sub-device.
然而,正如 Ian 在评论中指出的那样,上述手册页中有关 STREAMS 的信息与 Linux 无关,我应该使用 man 2 ioctl
—— 不幸的是,大多数只是说 ioctl 并不真正符合任何标准,而且什么都行。
这提出了三个问题。
- 这对 i2c 适配器意味着什么?难道这个设备的驱动不支持用这种方式读写?
- 手册页包含 I_ 前缀操作的 return 代码的具体描述,但不包含其他操作。我可以在其他地方查找特定于 I2C ioctl 操作的信息吗?
- 在哪里可以找到 i2c ioctl 函数的源代码?
通常是设备没有响应。具体取决于您的硬件。
通用 I2C ioctl 代码是 i2c-dev 包的一部分,它是 lm-sensors 项目的一部分。这些 ioctl 没有自己的手册页,但有 documentation in the kernel source tree.
在内核中,实现都保存在drivers/i2c/i2c-dev.c
and drivers/i2c/i2c-core.c
. The entry point is i2cdev_ioctl()
中。 None 这个常用代码 returns ENXIO.
最终,这个公共代码需要向下调用i2c总线上的硬件级驱动函数。 i2c 总线的硬件驱动程序存储在 drivers/i2c/busses/
中。这些驱动程序中的每一个都可以实现 master_xfer
(用于 I2C_RDWR
ioctls)或 smbus_xfer
(用于 I2C_SMBUS
)功能中的一个或两个。
在我的例子中,该设备实际上没有专用的 i2c 硬件,并且使用的似乎是在函数 bit_xfer
of drivers/i2c/algos/i2c-algo-bit.c
. The ENXIO came from function bit_doAddress
.
中实现的位爆炸软件仿真。
我有一个 i2c 适配器作为 /dev/i2c-0
暴露给用户空间。当我在该适配器上使用 i2c-tools 包中的 i2cdetect
时,我看到我的设备列在该适配器上并且我能够从命令行对其执行获取、设置和转储操作。
我有一些 C 代码尝试使用 ioctl I2C_RDWR
操作对其执行写入。
这是我正在使用的精简代码(仅为上下文提供,运行回答问题并不重要)。
fd = open ("/dev/i2c-0", O_RDWR | O_NONBLOCK);
/* other stuff happens here */
if (ioctl (fd, I2C_FUNCS, &funcs) != 0)
return -1;
if (!(funcs & I2C_FUNC_I2C))
return -1;
/* i added this bit of debug just to be sure fd didn't
* get inadvertently closed along the way.
*/
if (fcntl (fd, F_GETFD) != 0) {
return -1;
}
/* build the ioctl message payload */
ret = ioctl (fd, I2C_RDWR, &payload)
if (ret) {
fprintf (stderr, "ioctl returned %d. Reason: %s (errno=%d).",
ret, strerror(errno), errno);
return -1;
}
return 0;
我也试过使用 smbus ioctl 函数,看起来像这样。
fd = open ("/dev/i2c-0", O_RDWR | O_NONBLOCK);
/* other stuff happens here */
if (ioctl (fd, I2C_FUNCS, &funcs) != 0)
return -1;
if (!(funcs & I2C_FUNC_SMBUS_WORD_DATA))
return -1;
/* i added this bit of debug just to be sure fd didn't
* get inadvertently closed along the way.
*/
if (fcntl (fd, F_GETFD) != 0) {
return -1;
}
/* build the ioctl smbus message payload */
if (ioctl (fd, I2C_SLAVE_FORCE, dev) != 0)
return -1;
ret = ioctl (fd, I2C_SMBUS, &payload);
if (ret) {
fprintf (stderr, "ioctl returned %d. Reason: %s (errno=%d).",
ret, strerror(errno), errno);
return -1;
}
return 0;
在所有情况下,程序总是命中 fprintf
,这是输出:
ioctl returned -1. Reason: No such device or address (errno=6).
根据 man 3 ioctl
,ENXIO 错误的 "generic" 原因是:
ENXIO The request and arg arguments are valid for this device driver, but the service requested cannot be performed on this particular sub-device.
然而,正如 Ian 在评论中指出的那样,上述手册页中有关 STREAMS 的信息与 Linux 无关,我应该使用 man 2 ioctl
—— 不幸的是,大多数只是说 ioctl 并不真正符合任何标准,而且什么都行。
这提出了三个问题。
- 这对 i2c 适配器意味着什么?难道这个设备的驱动不支持用这种方式读写?
- 手册页包含 I_ 前缀操作的 return 代码的具体描述,但不包含其他操作。我可以在其他地方查找特定于 I2C ioctl 操作的信息吗?
- 在哪里可以找到 i2c ioctl 函数的源代码?
通常是设备没有响应。具体取决于您的硬件。
通用 I2C ioctl 代码是 i2c-dev 包的一部分,它是 lm-sensors 项目的一部分。这些 ioctl 没有自己的手册页,但有 documentation in the kernel source tree.
在内核中,实现都保存在drivers/i2c/i2c-dev.c
and drivers/i2c/i2c-core.c
. The entry point is i2cdev_ioctl()
中。 None 这个常用代码 returns ENXIO.
最终,这个公共代码需要向下调用i2c总线上的硬件级驱动函数。 i2c 总线的硬件驱动程序存储在 drivers/i2c/busses/
中。这些驱动程序中的每一个都可以实现 master_xfer
(用于 I2C_RDWR
ioctls)或 smbus_xfer
(用于 I2C_SMBUS
)功能中的一个或两个。
在我的例子中,该设备实际上没有专用的 i2c 硬件,并且使用的似乎是在函数 bit_xfer
of drivers/i2c/algos/i2c-algo-bit.c
. The ENXIO came from function bit_doAddress
.