2 Writes give "Operation not supported on transport endpoint"
I was trying to get the examples in https://github.com/alexeden/adafruit-seesaw to work on linux but i kept getting errors
I managed to track down the problem to this MVP example
use embedded_hal::i2c::{Error, I2c, Operation};
use linux_embedded_hal::{Delay, I2CError, I2cdev, i2cdev::core::I2CDevice};
fn main() {
let mut i2c = I2cdev::new("/dev/i2c-10").unwrap();
let regester_num: &[u8] = &[0x00, 0x7F];
let mut data = [0xFF];
let mut ops = [Operation::Write(regester_num), Operation::Write(&data)];
i2c.transaction(0x36_u8, &mut ops).unwrap();
}
thread 'main' panicked at crates/rig/src/bin/gps.rs:10:40:
called `Result::unwrap()` on an `Err` value: I2CError { err: Errno(95) }
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
using https://www.adafruit.com/product/4471 and https://www.adafruit.com/product/5880 but i had the same issue with other i2c peripherals.
95 EOPNOTSUPP Operation not supported on transport endpoint
Please note that a single write of a longer array does not cause the same error.
It should be noted that a single write operation with a longer array does run, let mut ops = [Operation::Write(&[0x00, 0x7F, 0xFF ])]
I cant tell if im doing something wrong or if there is a bug some were.
I think this is an error the kernel might return if the driver for the i2cdev you are talking to doesn't support smbus or the particular transfer you are attempting. What's your host hardware and/or the device you're using to talk SPI to the seesaw?
I get this with both https://www.adafruit.com/product/4471 and https://thepihut.com/products/usb-uart-i2c-debugger which I think both use MCP2221
❯ lsusb
Bus 001 Device 057: ID 04d8:00dd Microchip Technology, Inc. MCP2221(a) UART/I2C Bridge
The data sheet seems to suggest that this does support smbus https://ww1.microchip.com/downloads/aemDocuments/documents/APID/ProductDocuments/DataSheets/MCP2221A-Data-Sheet-20005565E.pdf
I have tried two write operation with other non seasaw peripherals and get similar.
I can write then read eg
- let mut ops = [Operation::Write(regester_num), Operation::Write(data)];
+ let mut ops = [Operation::Write(regester_num), Operation::Read(data)];
Does anyone have a known good i2c adaptor that supports 2 write operations in series?
Here's the kernel code for the mcp https://github.com/torvalds/linux/blob/327579671a9becc43369f7c0637febe7e03d4003/drivers/hid/hid-mcp2221.c#L353-L405 which does indeed look off to me in that it assumes that you're going to do a write then a read.
I haven't used it, but I think you can reprogram a Pi Pico using i2c-pco-usb to emulate the i2c-tiny which has a driver in tree. I took a quick look and it seemed to not have similar quirks in its master_xfer code.
Looking at the datasheet it looks like the chip itself does support multiple writes in the same transaction. What isn't supported is a read followed by a write, so it can't implement all combinations supported by i2c.transaction(). The driver implemented in the linux kernel however only implements a single write followed by a single read.
There also is a rust driver for the device that seems to be talking to the USB bus directly, not using the hid-mcp2221 driver. Maybe you can use that instead of linux-embedded-hal, to circumvent the kernel limitations? https://docs.rs/mcp2221-hal/latest/mcp2221_hal/struct.MCP2221.html#i2c
Anyway, this doesn't look like an issue linux-embedded-hal could solve.