13#include <l4/sys/cxx/ipc_epiface>
15#include <l4/l4virtio/server/virtio>
16#include <l4/l4virtio/server/l4virtio>
17#include <l4/l4virtio/l4virtio>
20#include <l4/re/util/object_registry>
21#include <l4/re/util/br_manager>
22#include <l4/sys/cxx/ipc_epiface>
52struct Spi_transfer_head
67static_assert(
sizeof(Spi_transfer_head) == 32,
68 "Spi_transfer_head contains padding bytes.");
70struct Spi_transfer_req
72 struct Spi_transfer_head head;
75 Spi_transfer_result *result =
nullptr;
80 void set_result(Spi_transfer_result res)
99template <
typename Spi_request_handler,
typename Epiface = L4virtio::Device>
101:
public L4virtio::Svr::Device,
102 public L4::Epiface_t<Virtio_spi<Spi_request_handler, Epiface>, Epiface>
107 Num_request_queues = 1,
124 _spi->handle_queue();
147 Data_buffer(L4virtio::Svr::Driver_mem_region
const *r,
159 : _q(q), _req_handler(hndlr), _spi(spi), _head(), _req()
164 auto r = _q->next_avail();
169 _head =
start(_spi->mem_info(), r, &_req);
186 Spi_transfer_req request;
187 memcpy(&request.head, _req.pos,
sizeof(Spi_transfer_head));
190 if (!
next(_spi->mem_info(), &_req))
198 request.rx_buf =
reinterpret_cast<l4_uint8_t *
>(_req.pos);
199 request.rx_size = _req.left;
203 request.tx_buf =
reinterpret_cast<l4_uint8_t *
>(_req.pos);
204 request.tx_size = _req.left;
208 if (!
next(_spi->mem_info(), &_req))
221 request.rx_buf =
reinterpret_cast<l4_uint8_t *
>(_req.pos);
222 request.rx_size = _req.left;
223 next(_spi->mem_info(), &_req);
226 request.result =
reinterpret_cast<Spi_transfer_result *
>(_req.pos);
231 void handle_request()
237 using Consumed_entry =
239 std::vector<Consumed_entry> consumed;
244 Spi_transfer_result res;
245 if (r.tx_buf && r.rx_buf && (r.tx_size != r.rx_size))
249 _req_handler->handle_transfer(r.head, r.tx_buf, r.rx_buf,
250 r.tx_size ? r.tx_size : r.rx_size);
254 if (res == Spi_trans_ok)
255 written += r.rx_size;
257 consumed.emplace_back(_head, written);
262 _q->
finish(consumed.begin(), consumed.end(), _spi);
269 Spi_request_handler *_req_handler;
276 :
L4virtio::Svr::Device(&_dev_config),
280 _request_processor(&_q, hndlr, this)
287 Spi_config
volatile *pc = _dev_config.priv_config();
289 pc->cs_max_number = hndlr->cs_max_number();
290 pc->cs_change_supported = 0;
291 pc->tx_nbits_supported = 0;
292 pc->rx_nbits_supported = 0;
293 pc->bits_per_word_mask = 0x80;
294 pc->mode_func_supported = hndlr->mode_func_supported();
296 pc->max_word_delay_ns = 0;
297 pc->max_cs_setup_ns = 0;
298 pc->max_cs_hold_ns = 0;
299 pc->max_cs_inactive_ns = 0;
301 L4virtio::Svr::Dev_config::Features hf(0);
302 _dev_config.host_features(0) = hf.raw;
307 void notify_queue(L4virtio::Svr::Virtqueue *)
309 if (_q.no_notify_guest())
313 L4Re::chkipc(_notify_guest_irq->trigger(),
"trigger guest irq");
318 _request_processor.handle_request();
343 _notify_guest_irq->trigger();
351 long op_set_status(L4virtio::Device::Rights r,
unsigned status)
353 return L4virtio::Svr::Device::op_set_status(r, status);
356 long op_config_queue(L4virtio::Device::Rights r,
unsigned queue)
358 return L4virtio::Svr::Device::op_config_queue(r, queue);
361 long op_device_config(L4virtio::Device::Rights r,
362 L4::Ipc::Cap<L4Re::Dataspace> &config_ds,
365 return L4virtio::Svr::Device::op_device_config(r, config_ds, ds_offset);
383 L4virtio::Svr::Dev_config_t<Spi_config> _dev_config;
384 Spi_request_handler *_req_handler;
A registry that manages server objects and their attached IPC gates for a single server loop for a sp...
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.
void reset_hdr(bool inc_generation=false) const
Reset the config header to the initial contents.
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)
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.
Virtqueue::Desc::Flags current_flags() const
Get the flags of the currently processed descriptor.
bool has_more() const
Are there more chained descriptors?
void start(DESC_MAN *dm, Virtqueue *ring, Virtqueue::Head_desc const &request, ARGS... args)
Start processing a new request.
Spi_transfer_req get_request()
Linux prepares the SPI request in three or four data parts: 1st: transfer_head 2nd: TX buffer (not pr...
void register_single_driver_irq() override
callback for registering a single guest IRQ for all queues (old-style)
void trigger_driver_config_irq() override
callback for triggering configuration change notification IRQ
int reconfig_queue(unsigned idx) override
callback for client queue-config request
bool check_queues() override
callback for checking if the queues at DRIVER_OK transition
void reset() override
reset callback, called for doing a device reset
L4::Cap< L4::Irq > device_notify_irq() const override
callback to gather the device notification IRQ (old-style)
VIRTIO request, essentially a descriptor from the available ring.
Virtqueue implementation for the device.
void finish(Head_desc &d, QUEUE_OBSERVER *o, l4_uint32_t len=0)
Add a descriptor to the used ring, and notify an observer.
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.
#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_SPI
SPI device.
@ L4VIRTIO_IRQ_STATUS_VRING
VRING IRQ pending flag.
@ L4VIRTIO_IRQ_STATUS_CONFIG
CONFIG IRQ pending flag.
long chksys(long err, char const *extra="", long ret=0)
Generate C++ exception on error.
T chkcap(T &&cap, char const *extra="", long err=-L4_ENOMEM)
Check for valid capability or raise C++ exception.
l4_msgtag_t chkipc(l4_msgtag_t tag, char const *extra="", l4_utcb_t *utcb=l4_utcb())
Test a message tag for IPC errors.
void throw_error(long err, char const *extra="")
Generate C++ exception.
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.