dde_linux: allow GPIO state access

To complement the GPIO support allow for setting and reading input
pins. So far this is needed by drivers that attempt to perform I2C
bit-banging via GPIO pins.

Fixes #4624.
This commit is contained in:
Josef Söntgen 2022-08-04 11:12:04 +02:00 committed by Christian Helmuth
parent 85f98d7038
commit b03059b933
2 changed files with 42 additions and 0 deletions

View File

@ -25,6 +25,13 @@ extern "C" {
*/ */
void lx_emul_pin_control(char const *pin_name, bool enabled); void lx_emul_pin_control(char const *pin_name, bool enabled);
/**
* Get input state of GPIO pin
*
* \pin_name GPIO name used as label for corresponding 'Pin_state' session
*/
int lx_emul_pin_sense(char const *pin_name);
/** /**
* Request interrupt backed by an IRQ session * Request interrupt backed by an IRQ session
*/ */

View File

@ -14,6 +14,7 @@
/* Genode includes */ /* Genode includes */
#include <base/registry.h> #include <base/registry.h>
#include <pin_control_session/connection.h> #include <pin_control_session/connection.h>
#include <pin_state_session/connection.h>
#include <irq_session/connection.h> #include <irq_session/connection.h>
#include <lx_emul/pin.h> #include <lx_emul/pin.h>
@ -75,10 +76,13 @@ namespace {
Name const name; Name const name;
Constructible<Pin_control::Connection> _control { }; Constructible<Pin_control::Connection> _control { };
Constructible<Pin_state::Connection> _state { };
Constructible<Irq_connection> _irq { }; Constructible<Irq_connection> _irq { };
Io_signal_handler<Pin> _irq_handler { _env.ep(), *this, &Pin::_handle_irq }; Io_signal_handler<Pin> _irq_handler { _env.ep(), *this, &Pin::_handle_irq };
enum class Direction { IN, OUT } _direction { Direction::IN };
void _handle_irq() void _handle_irq()
{ {
_pin_irq_handler.handle_pin_irq(_irq_info); _pin_irq_handler.handle_pin_irq(_irq_info);
@ -100,6 +104,25 @@ namespace {
_control.construct(_env, name.string()); _control.construct(_env, name.string());
_control->state(enabled); _control->state(enabled);
_direction = Direction::OUT;
}
bool sense()
{
if (_irq.constructed()) {
error("attempt to drive interrupt pin ", name, " as input");
return false;
}
if (_control.constructed() && (_direction == Direction::OUT)) {
_control->yield();
_direction = Direction::IN;
}
if (!_state.constructed())
_state.construct(_env, name.string());
return _state->state();
} }
void associate_with_gic_and_unmask_irq(Irq_info irq_info) void associate_with_gic_and_unmask_irq(Irq_info irq_info)
@ -200,6 +223,18 @@ extern "C" void lx_emul_pin_control(char const *pin_name, bool enabled)
} }
extern "C" void lx_emul_backtrace(void);
extern "C" int lx_emul_pin_sense(char const *pin_name)
{
bool result = false;
pins().with_pin(pin_name, [&] (Pin &pin) {
result = pin.sense(); });
return result;
}
extern "C" void lx_emul_pin_irq_unmask(unsigned gic_irq, unsigned pin_irq, extern "C" void lx_emul_pin_irq_unmask(unsigned gic_irq, unsigned pin_irq,
char const *pin_name) char const *pin_name)
{ {