Understanding the Significance of ENXIO in i2c ioctl

The man page provides detailed explanations of the return codes associated with I_-prefixed operations, but not for other operations. In this instance, the device lacked dedicated i2c hardware and instead relied on a software emulation implemented in function of what seems to be bit-banging.

Question:

I’ve made my
i2c adapter
available to userspace as

/dev/i2c-0

. By utilizing the i2c-tools package on the adapter, my
device listed
is visible and can be manipulated via command line operations such as get, set, and dump.

My C code attempts to use the ioctl

I2C_RDWR

operation to perform a write on it.

I am sharing the code in its bare minimum form for context purposes only. Running it is not necessary to answer the questions.

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;

I have attempted utilizing the ioctl functions of smbus, which were represented as follows.

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_****_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;

The program consistently reaches

fprintf

in every scenario, resulting in the following output.

The reason for the -1 return value of ioctl is that there is no device or address available, as indicated by errno=6.

As per

man 3 ioctl

, the common cause behind an ENXIO error is referred to as “generic”.

The service request made with the given request and arg parameters is not possible to be executed on this specific sub-device, even though the arguments are valid for the device driver. This is indicated by the ENXIO error message.

According to Ian’s comment, the STREAMS information mentioned in the previous man page is not applicable on Linux. Therefore, I should utilize

man 2 ioctl

instead. Regrettably, this command mostly indicates that ioctls do not follow any particular standard, and there are no set rules to follow.

This raises three questions.

  1. Considering this, could it be concluded that the i2c adapter is not compatible with the method of reading and writing supported by its driver?
  2. Are there any alternate resources available to obtain details about return codes for I2C ioctl operations other than the I_ prefixed operations, since the man page only provides descriptions for the latter?
  3. Do you know where I can locate the origin of the i2c ioctl functions?



Solution:

The reason for the lack of response is typically hardware-dependent.

The I2C ioctl code is included in the i2c-dev bundle, which is a component of the lm-sensors initiative. These ioctls lack a dedicated manual page, but are documented within the kernel source directory.

The kernel’s implementation is contained within

drivers/i2c/i2c-dev.c

and

drivers/i2c/i2c-core.c

, with the entry point being

i2cdev_ioctl()

. It should be noted that none of this shared code results in an ENXIO return.

In due course, the shared code is required to invoke i2c bus driver functions on
hardware-level
. The i2c bus hardware drivers are kept in

drivers/i2c/busses/

. The drivers can support the

master_xfer

(utilized for

I2C_RDWR

ioctl) or

smbus_xfer

(used for

I2C_SMBUS

) functions, or both.

The device I was working with lacked dedicated i2c hardware and instead relied on a software emulation, which seemed to be implemented within the function

bit_xfer

of

drivers/i2c/algos/i2c-algo-bit.c

. The error message ENXIO was generated by function

bit_doAddress

.

Frequently Asked Questions