Bug in i2cset with mask and size = I2C_SMBUS_BYTE

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



There's a bug in i2cset when using mask and a simple command
(I2C_SMBUS_BYTE).  I'm currently using this with a single byte 8-bit
I/O expander device (PCF8574). but this is not device dependent.

With and without a mask option, the byte to be written (argv[flags +
3]) is stored in "daddress" for later use.

When argc == flags + 4, it's an implicit "c" and I2C_SMBUS_BYTE mode is set.

In the case of I2C_SMBUS_BYTE, the write is perfomed with
"i2c_smbus_write_byte(file, daddress)", which works fine as long as a
mask was not set.

If a mask is set (vmask), then the new value to write is constructed
with the old value and the mask, and stored in "value" to be written
back to the part, but this doesn't work for I2C_SMBUS_BYTE case, as it
writes a single byte using "daddress" instead of "value" (which had
the mask applied).

The problem is that if the user is providing a mask and just the bits
to be set or cleared according to the mask, then the only those bits
will be set / cleared as the data on the command line, which is stored
in daddress, and then written without any masking (e.g. the vmask
routine to create "value").

The readback check succeeds because in the I2C_SMBUS_BYTE case, right
after the read (to get "res"), it sets the vmask constructed "value"
equal to the original "daddress" (which was just the bits to set
without mask), and the "res" back from the device will be equal to
that, never compared to the "value" that correctly constructed with
the mask since it was just overwritten with the original "daddress"

For now, I'm doing the reads / masks / writes via the calling script,
as a workaround, but with 4.x in works, looks like a good opportunity
to fix.

Here is an example of the problem - note that I am trying to just set
bit 4 on this device.  You can see the bit pattern was properly
constructed in the confirmation, but it goes off the rails when it
talks about writing to a particular register (that's "daddress" in the
printf).

root@x:~# i2cset -r -m 0x10 2 0x21 0x10
WARNING! This program can confuse your I2C bus, cause data loss and worse!
I will write to device file /dev/i2c-2, chip address 0x21, data address
0x10, no data.
Continue? [Y/n] y
Old value 0xe1, write mask 0x10: Will write 0xf1 to register 0x10
Continue? [Y/n] y
Value 0x10 written, readback matched
root@x:~# i2cget 2 0x21
WARNING! This program can confuse your I2C bus, cause data loss and worse!
I will read from device file /dev/i2c-2, chip address 0x21, current data
address, using read byte.
Continue? [Y/n] y
0x10
root@x:



[Index of Archives]     [Linux GPIO]     [Linux SPI]     [Linux Hardward Monitoring]     [LM Sensors]     [Linux USB Devel]     [Linux Media]     [Video for Linux]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]

  Powered by Linux