On 7/22/26 14:57, Ilya Chichkov wrote:
Add a "remote-i2c-master" device that exposes a QEMU I2C bus to the
host system through a FUSE/CUSE character device. This lets external
host programs and standard i2c-tools interact with I2C slaves emulated
inside QEMU as if they were real devices attached to the host.

The implementation is split into three layers:

   - A non-blocking finite state machine that drives the QEMU I2C
     master. It is pumped by a QEMU Bottom Half and uses virtual timers
     to yield during long transfers and to model clock stretching for
     asynchronous slaves, so the main loop is never blocked. The FSM
     walks IDLE -> ADDR -> SEND/RECV -> WAIT_STRETCH -> END -> FINISHED
     and handles NACKs (ENXIO), lost arbitration (EBUSY, with optional
     back-off and retry), stretch timeouts, and manual abort/reset.

   - An abstract RemoteI2CBackend QOM base class that decouples the
     internal I2C hardware state machine (the frontend) from any
     host-specific transport, exposing on_tx_complete and on_tx_error
     virtual callbacks.

   - A concrete remote-i2c-backend-cuse backend implementing that
     transport over CUSE. It manages the FUSE session and integrates
     its file descriptors into QEMU's main AioContext event loop,
     translates Linux I2C_RDWR, I2C_SMBUS and I2C_SLAVE ioctls into
     generic byte streams for the FSM, and formats responses back into
     Linux I2C/SMBus structures for the FUSE driver. SMBus repeated
     start is supported for atomic write-then-read operations.

Example usage:

   -device remote-i2c-master,i2cbus=i2c-bus.0,devname=i2c-33
   -object remote-i2c-backend-cuse,id=b0,devname=i2c-33

This creates /dev/i2c-33 on the host, usable with i2c-tools:

   i2cdetect -y -l
   i2cget -y <bus_id> <addr> <reg>

Acked-by: Markus Armbruster <[email protected]>
Signed-off-by: Ilya Chichkov <[email protected]>
---
v2:
   - docs/system/devices/remote-i2c-master.rst: Documented concurrent
     bus access details and the 'raise-arbitrage-lost' property.
---
v3:
   - qapi/qom.json: Fix RemoteI2CBackendCuseProperties formatting and
     expand member documentation (devname, fuse-opts, debug).
   - tests/qtest: Add remote-i2c-cuse-test covering capabilities,
     functional smoke test, synchronous sensor read/write.
---
v4:
  - qapi: reference the rst doc via :doc:
  - qapi: fuse-opts is now ['str'] instead of a space-separated string
  - qapi: drop redundant 'debug' property (pass -d via fuse-opts)
---
v5:
  - docs/system/device-emulation.rst: add remote-i2c-master.rst to
    the toctree under "Emulated Devices"
  - qapi/qom.json: move RemoteI2CBackendCuseProperties definition
    before RemoteObjectProperties as requested; change "for usage
    information" to "for detailed usage information"
---
---
  docs/system/device-emulation.rst          |    1 +
  docs/system/devices/remote-i2c-master.rst |  217 ++++
  hw/i2c/Kconfig                            |    5 +
  hw/i2c/meson.build                        |    6 +
  hw/i2c/remote-i2c-backend.c               |   30 +
  hw/i2c/remote-i2c-cuse.c                  | 1173 +++++++++++++++++++++
  hw/i2c/remote-i2c-fsm.c                   |  521 +++++++++
  hw/i2c/remote-i2c-master.c                |  145 +++
  hw/i2c/trace-events                       |   29 +
  include/hw/i2c/remote-i2c-backend.h       |   70 ++
  include/hw/i2c/remote-i2c-cuse.h          |   93 ++
  include/hw/i2c/remote-i2c-master.h        |   77 ++
  qapi/qom.json                             |   29 +
  tests/qtest/meson.build                   |    2 +
  tests/qtest/remote-i2c-cuse-test.c        |  326 ++++++
  15 files changed, 2724 insertions(+)
  create mode 100644 docs/system/devices/remote-i2c-master.rst
  create mode 100644 hw/i2c/remote-i2c-backend.c
  create mode 100644 hw/i2c/remote-i2c-cuse.c
  create mode 100644 hw/i2c/remote-i2c-fsm.c
  create mode 100644 hw/i2c/remote-i2c-master.c
  create mode 100644 include/hw/i2c/remote-i2c-backend.h
  create mode 100644 include/hw/i2c/remote-i2c-cuse.h
  create mode 100644 include/hw/i2c/remote-i2c-master.h
  create mode 100644 tests/qtest/remote-i2c-cuse-test.c

If I understand this proposal correctly, it lets host-side i2c
tools talk to emulated I2C devices. The example is i2cdetect/i2cget
against a tmp105 on an Aspeed bus.

QEMU already has mechanisms for this though. qtest can read/write I2C
registers programmatically, QMP can query device state, and the guest
OS itself sees the I2C bus natively.

The dependency cost seems high for the use case: libfuse3 + the cuse
kernel module pulled into the system emulator build. It's also ~3K
lines of new code, three QOM types, FUSE session management, etc.
The surface area for bugs is large. It's a heavy burden for what it
gives.

I think a lighter QMP-based approach would serve the same purpose,
maybe better, and fit in better in QEMU, without the dependency and
maintenance cost:

- No host kernel dependency
- Works remotely (QMP over socket)
- Fits QEMU's existing management model
- Much less code
- Testable without root or kernel modules

Have you considered extending QMP with an I2C transaction command
instead? Something like:

  { 'command': 'i2c-transfer',
    'data': { 'bus': 'str',
              'address': 'uint8',
              'read': 'bool',
              '*data': ['uint8'],
              '*length': 'uint16' },
    'returns': { '*data': ['uint8'] } }


Thanks,

C.


Reply via email to