12#include <l4/sys/cxx/ipc_epiface>
14#include <l4/l4virtio/server/virtio>
15#include <l4/l4virtio/server/l4virtio>
16#include <l4/l4virtio/l4virtio>
19#include <l4/re/util/object_registry>
20#include <l4/re/util/br_manager>
21#include <l4/sys/cxx/ipc_epiface>
36struct I2c_request_flags
40 CXX_BITFIELD_MEMBER(0, 0, fail_next, raw);
41 CXX_BITFIELD_MEMBER(1, 1, m_rd, raw);
43static_assert(
sizeof(I2c_request_flags) == 4,
44 "I2c_request_flags contains padding bytes.");
50 I2c_request_flags flags;
52static_assert(
sizeof(I2c_out_hdr) == 8,
"I2c_out_hdr contains padding bytes.");
58static_assert(
sizeof(I2c_in_hdr) == 1,
"I2c_in_hdr contains padding bytes.");
62 struct I2c_out_hdr out_hdr;
65 struct I2c_in_hdr *in_hdr;
66 L4virtio::Svr::Virtqueue::Head_desc head;
70 void set_status(I2c_transfer_result status)
72 in_hdr->status =
static_cast<l4_uint8_t>(status);
87template <
typename Request_handler,
88 typename Epiface = L4virtio::Device>
89class Virtio_i2c :
public L4virtio::Svr::Device,
97 Num_request_queues = 1,
102 using I2c_request_handler = Request_handler;
116 _i2c->handle_queue();
138 Data_buffer(L4virtio::Svr::Driver_mem_region
const *r,
150 : _q(q), _req_handler(hndlr), _i2c(i2c), _fail_next(
false)
165 if (_pending_req.has_value())
167 request = _pending_req.value();
168 _pending_req.reset();
172 auto r = _q->next_avail();
180 request.head =
start(_i2c->mem_info(), r, &req);
181 memcpy(&request.out_hdr, req.
pos,
sizeof(I2c_out_hdr));
184 request.write_size =
sizeof(I2c_in_hdr);
188 if (
next(_i2c->mem_info(), &req))
191 request.buf_len += req.
left;
196 if (
next(_i2c->mem_info(), &req))
199 if (request.out_hdr.flags.m_rd())
200 request.write_size += request.buf_len;
203 request.in_hdr =
reinterpret_cast<I2c_in_hdr *
>(req.
pos);
208 request.in_hdr =
reinterpret_cast<I2c_in_hdr *
>(request.buf);
209 request.buf =
nullptr;
216 void handle_requests()
218 using Consumed_entry =
220 std::vector<Consumed_entry> consumed;
230 r.set_status(I2c_transfer_result::I2c_msg_err);
231 _fail_next = r.out_hdr.flags.fail_next();
235 std::optional<bool> ok;
237 if (r.out_hdr.flags.m_rd())
238 ok = _req_handler->handle_read(i2c_addr, r.buf, r.buf_len);
240 ok = _req_handler->handle_write(i2c_addr, r.buf, r.buf_len);
245 r.set_status(I2c_transfer_result::I2c_msg_ok);
250 r.set_status(I2c_transfer_result::I2c_msg_err);
251 _fail_next = r.out_hdr.flags.fail_next();
260 consumed.emplace_back(r.head, r.write_size);
263 if (!consumed.empty())
264 _q->finish(consumed.begin(), consumed.end(), _i2c);
268 L4virtio::Svr::Virtqueue *_q;
269 I2c_request_handler *_req_handler;
272 std::optional<I2c_req> _pending_req;
275 struct Features :
public L4virtio::Svr::Dev_config::Features
277 Features() =
default;
282 CXX_BITFIELD_MEMBER(0, 0, zero_length_request,
raw);
285 Virtio_i2c(I2c_request_handler *hndlr, L4Re::Util::Object_registry *registry)
286 : L4virtio::Svr::Device(&_dev_config),
290 _request_processor(&_q, hndlr, this)
298 hf.ring_indirect_desc() =
true;
299 hf.zero_length_request() =
true;
300 _dev_config.host_features(0) = hf.raw;
302 _dev_config.reset_hdr();
305 void notify_queue(L4virtio::Svr::Virtqueue *)
307 if (_q.no_notify_guest())
311 L4Re::chkipc(_notify_guest_irq->trigger(),
"trigger guest irq");
316 _request_processor.handle_requests();
341 _notify_guest_irq->trigger();
349 long op_set_status(L4virtio::Device::Rights r,
unsigned status)
351 return L4virtio::Svr::Device::op_set_status(r, status);
354 long op_config_queue(L4virtio::Device::Rights r,
unsigned queue)
356 return L4virtio::Svr::Device::op_config_queue(r, queue);
359 long op_device_config(L4virtio::Device::Rights r,
360 L4::Ipc::Cap<L4Re::Dataspace> &config_ds,
363 return L4virtio::Svr::Device::op_device_config(r, config_ds, ds_offset);
381 L4virtio::Svr::Dev_config_t<L4virtio::Svr::No_custom_data>_dev_config;
382 I2c_request_handler *_req_handler;
L4::Cap< L4::Irq > register_irq_obj(L4::Epiface *o) override
Register a handler for an interrupt.
C++ interface for capabilities.
Interface for server-loop related functions.
bool setup_queue(Virtqueue *q, unsigned qn, unsigned num_max)
void init_mem_info(unsigned num)
void reset_queue_config(unsigned idx, unsigned num_max, bool inc_generation=false, unsigned device_notify_index=0)
T * local(Ptr< T > p) const
Get the local address for driver address p.
Encapsulate the state for processing a VIRTIO request.
bool next(DESC_MAN *dm, ARGS... args)
Switch to the next descriptor in a descriptor chain.
void start(DESC_MAN *dm, Virtqueue *ring, Virtqueue::Head_desc const &request, ARGS... args)
Start processing a new request.
I2c_req get_request()
Linux prepares the I2C request in three data parts: 1st: out_hdr 2nd: buffer (optional) 3rd: in_hdr.
void trigger_driver_config_irq() override
callback for triggering configuration change notification IRQ
void register_single_driver_irq() override
callback for registering a single guest IRQ for all queues (old-style)
void reset() override
reset callback, called for doing a device reset
bool check_queues() override
callback for checking if the queues at DRIVER_OK transition
L4::Cap< L4::Irq > device_notify_irq() const override
callback to gather the device notification IRQ (old-style)
int reconfig_queue(unsigned idx) override
callback for client queue-config request
VIRTIO request, essentially a descriptor from the available ring.
Virtqueue implementation for the device.
Descriptor in the descriptor table.
l4_uint32_t len
Length of described buffer.
Ptr< void > addr
Address stored in descriptor.
unsigned long l4_addr_t
Address type.
unsigned char l4_uint8_t
Unsigned 8bit value.
unsigned int l4_uint32_t
Unsigned 32bit value.
unsigned short int l4_uint16_t
Unsigned 16bit value.
#define L4_UNLIKELY(x)
Expression is unlikely to execute.
@ L4VIRTIO_FEATURE_VERSION_1
Virtio protocol version 1 supported. Must be 1 for L4virtio.
@ L4VIRTIO_ID_I2C
I2C device.
@ L4VIRTIO_IRQ_STATUS_VRING
VRING IRQ pending flag.
@ L4VIRTIO_IRQ_STATUS_CONFIG
CONFIG IRQ pending flag.
T chkcap(T &&cap, char const *extra="", l4_ret_t err=-L4_ENOMEM)
Check for valid capability or raise C++ exception.
l4_ret_t chksys(l4_ret_t err, char const *extra="", l4_ret_t ret=0)
Generate C++ exception on error.
l4_msgtag_t chkipc(l4_msgtag_t tag, char const *extra="", l4_utcb_t *utcb=l4_utcb())
Test a message tag for IPC errors.
Cap< T > cap_cast(Cap< F > const &c) noexcept
static_cast for capabilities.
L4-VIRTIO Transport C++ API.
Epiface implementation for Kobject-based interface implementations.
Server_iface * server_iface() const
Get pointer to server interface at which the object is currently registered.
Epiface implementation for interrupt handlers.
l4_uint32_t left
Bytes left in buffer.
char * pos
Current buffer position.
l4_uint32_t raw
The raw value of the features bitmap.