142class Virtio_gpio :
public L4virtio::Svr::Device,
154 using Gpio_request_handler = Request_handler;
171 : _gpio(gpio), _q(q), _head(head), _status(status)
176 *_status = Gpio_irq_status_valid;
177 _q->finish(_head, _gpio,
sizeof(Gpio_irq_response));
182 *_status = Gpio_irq_status_invalid;
183 _q->finish(_head, _gpio,
sizeof(Gpio_irq_response));
200 explicit Host_irq(Virtio_gpio *gpio)
204 { _gpio->handle_queue(); }
217 : _q(q), _req_handler(hndlr), _gpio(gpio), _head(), _req()
223 auto r = _q->next_avail();
228 _head =
start(_gpio->mem_info(), r, &_req);
240 template <
typename T>
244 req.in_hdr =
reinterpret_cast<decltype(T::in_hdr)
>(_req.pos);
250 req.out_hdr =
reinterpret_cast<decltype(T::out_hdr)
>(_req.pos);
263 Data_buffer(L4virtio::Svr::Driver_mem_region
const *r,
274 Gpio_request_handler *_req_handler;
283 using Request_processor::Request_processor;
285 void handle_request()
288 if (!this->init_queue())
291 using Consumed_entry =
292 cxx::Pair<L4virtio::Svr::Virtqueue::Head_desc, l4_uint32_t>;
293 std::vector<Consumed_entry> consumed;
298 if (!req.in_hdr || !req.out_hdr)
300 this->_gpio->device_error();
305 req.out_hdr->status = Gpio_status_err;
306 switch (req.in_hdr->type)
308 case Gpio_msg_get_line_names:
311 case Gpio_msg_get_direction:
313 if (this->_req_handler->get_direction(req.in_hdr->gpio,
314 &req.out_hdr->value))
315 req.out_hdr->status = Gpio_status_ok;
318 case Gpio_msg_set_direction:
320 if (req.in_hdr->value == Gpio_direction_none ||
321 req.in_hdr->value == Gpio_direction_out ||
322 req.in_hdr->value == Gpio_direction_in)
324 if (this->_req_handler->set_direction(req.in_hdr->gpio,
326 req.out_hdr->status = Gpio_status_ok;
330 case Gpio_msg_get_value:
332 if (this->_req_handler->get_value(req.in_hdr->gpio,
333 &req.out_hdr->value))
334 req.out_hdr->status = Gpio_status_ok;
337 case Gpio_msg_set_value:
339 if (req.in_hdr->value == Gpio_low ||
340 req.in_hdr->value == Gpio_high)
342 if (this->_req_handler->set_value(req.in_hdr->gpio,
344 req.out_hdr->status = Gpio_status_ok;
348 case Gpio_msg_set_irq_type:
350 if (req.in_hdr->value == Gpio_irq_type_none ||
351 req.in_hdr->value == Gpio_irq_type_edge_rising ||
352 req.in_hdr->value == Gpio_irq_type_edge_falling ||
353 req.in_hdr->value == Gpio_irq_type_edge_both ||
354 req.in_hdr->value == Gpio_irq_type_level_high ||
355 req.in_hdr->value == Gpio_irq_type_level_low)
357 if (this->_req_handler->set_irq_type(req.in_hdr->gpio,
359 req.out_hdr->status = Gpio_status_ok;
366 consumed.emplace_back(this->_head,
sizeof(Gpio_response));
368 if (!this->init_queue())
374 this->_q->finish(consumed.begin(), consumed.end(), this->_gpio);
376 this->_head = Virtqueue::Head_desc();
383 using Request_processor::Request_processor;
385 void handle_request()
388 if (!this->init_queue())
395 Gpio_irq_request_msg req = this->
template get_request<Gpio_irq_request_msg>();
396 if (!req.in_hdr || !req.out_hdr)
398 this->_gpio->device_error();
405 this->_req_handler->enable_irq(req.in_hdr->gpio,
406 std::make_shared<Irq_handler>(this->_gpio,
409 &req.out_hdr->status));
411 if (!this->init_queue())
415 this->_head = Virtqueue::Head_desc();
419 struct Features :
public L4virtio::Svr::Dev_config::Features
421 Features() =
default;
422 Features(
l4_uint32_t raw) : L4virtio::Svr::Dev_config::Features(raw) {}
424 CXX_BITFIELD_MEMBER(0, 0, gpio_f_irq, raw);
427 struct Gpio_config_space
434 Virtio_gpio(Gpio_request_handler *hndlr,
435 L4Re::Util::Object_registry *registry,
437 : L4virtio::Svr::Device(&_dev_config),
441 _req_processor(&_q[0], hndlr, this),
442 _irq_req_processor(&_q[1], hndlr, this)
446 for (
size_t i = 0; i < 2; i++)
455 hf.ring_indirect_desc() =
true;
456 hf.gpio_f_irq() =
true;
457 _dev_config.host_features(0) = hf.raw;
461 _dev_config.priv_config()->ngpio = ngpio;
462 _dev_config.priv_config()->gpio_names_size = 0;
464 _dev_config.reset_hdr();
468 { _registry->unregister_obj(&_host_irq); }
470 void notify_queue(L4virtio::Svr::Virtqueue *queue)
476 L4Re::chkipc(_notify_guest_irq->trigger(),
"trigger guest irq");
481 _req_processor.handle_request();
482 _irq_req_processor.handle_request();
493 if (idx >=
sizeof(_q) /
sizeof(_q[0]))
502 _notify_guest_irq->trigger();
508 long op_set_status(L4virtio::Device::Rights r,
unsigned status)
509 {
return L4virtio::Svr::Device::op_set_status(r, status); }
511 long op_config_queue(L4virtio::Device::Rights r,
unsigned queue)
512 {
return L4virtio::Svr::Device::op_config_queue(r, queue); }
514 long op_device_config(L4virtio::Device::Rights r,
515 L4::Ipc::Cap<L4Re::Dataspace> &config_ds,
517 {
return L4virtio::Svr::Device::op_device_config(r, config_ds, ds_offset); }
532 L4virtio::Svr::Dev_config_t<Gpio_config_space> _dev_config;
536 Req_processor _req_processor;
537 Irq_req_processor _irq_req_processor;