mirror of
https://github.com/genodelabs/genode.git
synced 2024-12-23 23:42:32 +00:00
intel_fb: enable polling for connector changes
To circumvent problems on platforms with shaky hotplug interrupt notification introduce a "poll" configuration option to the driver, which enables polling for connector changes. Fix #2004
This commit is contained in:
parent
11bead1811
commit
0c13effaa8
@ -35,6 +35,15 @@ configuration like this:
|
||||
|
||||
! <config buffered="yes"/>
|
||||
|
||||
If you experience problems like hotplugging of connectors does not work, you
|
||||
can force the driver to poll frequently for hotplug events by defining a period
|
||||
in milliseconds like this:
|
||||
|
||||
! <config poll="1000"/>
|
||||
|
||||
If you define a period of zero, the driver won't poll at all, which is the
|
||||
default value.
|
||||
|
||||
To present all available connectors and their possible resolutions to the user
|
||||
the driver is able to export a corresponding report ROM. This has to be
|
||||
configured too, like in the following:
|
||||
|
@ -15,6 +15,7 @@
|
||||
#define __COMPONENT_H__
|
||||
|
||||
/* Genode includes */
|
||||
#include <base/component.h>
|
||||
#include <base/rpc_server.h>
|
||||
#include <root/component.h>
|
||||
#include <dataspace/capability.h>
|
||||
@ -41,21 +42,28 @@ class Framebuffer::Driver
|
||||
{
|
||||
private:
|
||||
|
||||
Session_component &_session;
|
||||
int _height = 0;
|
||||
int _width = 0;
|
||||
static constexpr unsigned _bytes_per_pixel = 2;
|
||||
void *_new_fb_ds_base = nullptr;
|
||||
void *_cur_fb_ds_base = nullptr;
|
||||
Genode::uint64_t _cur_fb_ds_size = 0;
|
||||
drm_framebuffer *_new_fb = nullptr;
|
||||
drm_framebuffer *_cur_fb = nullptr;
|
||||
Session_component &_session;
|
||||
Timer::Connection _timer;
|
||||
Genode::Signal_handler<Driver> _poll_handler;
|
||||
int _height = 0;
|
||||
int _width = 0;
|
||||
static constexpr unsigned _bytes_per_pixel = 2;
|
||||
void *_new_fb_ds_base = nullptr;
|
||||
void *_cur_fb_ds_base = nullptr;
|
||||
Genode::uint64_t _cur_fb_ds_size = 0;
|
||||
drm_framebuffer *_new_fb = nullptr;
|
||||
drm_framebuffer *_cur_fb = nullptr;
|
||||
unsigned long _poll_ms = false;
|
||||
|
||||
drm_display_mode * _preferred_mode(drm_connector *connector);
|
||||
|
||||
void _poll();
|
||||
|
||||
public:
|
||||
|
||||
Driver(Session_component &session) : _session(session) {}
|
||||
Driver(Genode::Env & env, Session_component &session)
|
||||
: _session(session), _timer(env),
|
||||
_poll_handler(env.ep(), *this, &Driver::_poll) {}
|
||||
|
||||
int width() const { return _width; }
|
||||
int height() const { return _height; }
|
||||
@ -65,6 +73,7 @@ class Framebuffer::Driver
|
||||
return _width * _height * _bytes_per_pixel; }
|
||||
|
||||
void finish_initialization();
|
||||
void set_polling(unsigned long poll);
|
||||
bool mode_changed();
|
||||
void generate_report();
|
||||
void free_framebuffer();
|
||||
@ -90,6 +99,9 @@ class Framebuffer::Session_component : public Genode::Rpc_object<Session>
|
||||
bool _buffered_from_config() {
|
||||
return _config.xml().attribute_value("buffered", false); }
|
||||
|
||||
unsigned long _polling_from_config() {
|
||||
return _config.xml().attribute_value<unsigned long>("poll", 0); }
|
||||
|
||||
void _refresh_buffered(int x, int y, int w, int h)
|
||||
{
|
||||
using namespace Genode;
|
||||
@ -114,8 +126,9 @@ class Framebuffer::Session_component : public Genode::Rpc_object<Session>
|
||||
|
||||
public:
|
||||
|
||||
Session_component(Genode::Attached_rom_dataspace &config)
|
||||
: _driver(*this), _config(config),
|
||||
Session_component(Genode::Env &env,
|
||||
Genode::Attached_rom_dataspace &config)
|
||||
: _driver(env, *this), _config(config), _timer(env),
|
||||
_buffered(_buffered_from_config()) {}
|
||||
|
||||
Driver & driver() { return _driver; }
|
||||
@ -127,6 +140,7 @@ class Framebuffer::Session_component : public Genode::Rpc_object<Session>
|
||||
|
||||
_in_update = true;
|
||||
_buffered = _buffered_from_config();
|
||||
_driver.set_polling(_polling_from_config());
|
||||
if (_driver.mode_changed() && _mode_sigh.valid())
|
||||
Genode::Signal_transmitter(_mode_sigh).submit();
|
||||
else
|
||||
@ -191,11 +205,11 @@ struct Framebuffer::Root
|
||||
Session_component *_create_session(const char *args) override {
|
||||
return &session; }
|
||||
|
||||
Root(Genode::Entrypoint &ep, Genode::Allocator &alloc,
|
||||
Root(Genode::Env &env, Genode::Allocator &alloc,
|
||||
Genode::Attached_rom_dataspace &config)
|
||||
: Genode::Root_component<Session_component,
|
||||
Genode::Single_client>(ep, alloc),
|
||||
session(config) { }
|
||||
Genode::Single_client>(env.ep(), alloc),
|
||||
session(env, config) { }
|
||||
};
|
||||
|
||||
#endif /* __COMPONENT_H__ */
|
||||
|
@ -137,9 +137,34 @@ void Framebuffer::Driver::finish_initialization()
|
||||
{
|
||||
dde_c_set_driver(dde_drm_device, (void*)this);
|
||||
generate_report();
|
||||
mode_changed();
|
||||
_session.config_changed();
|
||||
}
|
||||
|
||||
|
||||
#include <lx_kit/irq.h>
|
||||
|
||||
void Framebuffer::Driver::_poll()
|
||||
{
|
||||
Lx::Pci_dev * pci_dev = (Lx::Pci_dev*) dde_drm_device->pdev->bus;
|
||||
Lx::Irq::irq().inject_irq(pci_dev->client());
|
||||
}
|
||||
|
||||
|
||||
void Framebuffer::Driver::set_polling(unsigned long poll)
|
||||
{
|
||||
if (poll == _poll_ms) return;
|
||||
|
||||
_poll_ms = poll;
|
||||
|
||||
if (_poll_ms) {
|
||||
_timer.sigh(_poll_handler);
|
||||
_timer.trigger_periodic(_poll_ms * 1000);
|
||||
} else {
|
||||
_timer.sigh(Genode::Signal_context_capability());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool Framebuffer::Driver::mode_changed()
|
||||
{
|
||||
using namespace Genode;
|
||||
@ -920,8 +945,6 @@ int drm_get_pci_dev(struct pci_dev *pdev, const struct pci_device_id *ent,
|
||||
}
|
||||
|
||||
|
||||
#include <lx_kit/irq.h>
|
||||
|
||||
int request_irq(unsigned int irq, irq_handler_t handler, unsigned long flags,
|
||||
const char *name, void *dev)
|
||||
{
|
||||
|
@ -41,11 +41,11 @@ unsigned long jiffies;
|
||||
|
||||
struct Main
|
||||
{
|
||||
Genode::Entrypoint &ep;
|
||||
Genode::Attached_rom_dataspace config;
|
||||
Genode::Heap heap;
|
||||
|
||||
Framebuffer::Root root { ep, heap, config };
|
||||
Genode::Env &env;
|
||||
Genode::Entrypoint &ep { env.ep() };
|
||||
Genode::Attached_rom_dataspace config { env, "config" };
|
||||
Genode::Heap heap { env.ram(), env.rm() };
|
||||
Framebuffer::Root root { env, heap, config };
|
||||
|
||||
/* init singleton Lx::Timer */
|
||||
Lx::Timer &timer = Lx::timer(&ep, &jiffies);
|
||||
@ -60,8 +60,7 @@ struct Main
|
||||
Lx::Task linux { run_linux, reinterpret_cast<void*>(this), "linux",
|
||||
Lx::Task::PRIORITY_0, Lx::scheduler() };
|
||||
|
||||
Main(Genode::Env &env)
|
||||
: ep(env.ep()), config(env, "config"), heap(env.ram(), env.rm())
|
||||
Main(Genode::Env &env) : env(env)
|
||||
{
|
||||
Genode::log("--- intel framebuffer driver ---");
|
||||
|
||||
|
@ -35,6 +35,8 @@ class Lx::Irq
|
||||
*/
|
||||
virtual void request_irq(Platform::Device &dev, irq_handler_t handler,
|
||||
void *dev_id, irq_handler_t thread_fn = 0) = 0;
|
||||
|
||||
virtual void inject_irq(Platform::Device &dev) = 0;
|
||||
};
|
||||
|
||||
#endif /* _LX_KIT__IRQ_H_ */
|
||||
|
@ -96,18 +96,7 @@ class Lx_kit::Irq : public Lx::Irq
|
||||
Lx_kit::List<Handler> _handler;
|
||||
Lx::Task _task;
|
||||
|
||||
Genode::Signal_rpc_member<Context> _dispatcher;
|
||||
|
||||
/**
|
||||
* Signal handler
|
||||
*/
|
||||
void _handle(unsigned)
|
||||
{
|
||||
_task.unblock();
|
||||
|
||||
/* kick off scheduling */
|
||||
Lx::scheduler().schedule();
|
||||
}
|
||||
Genode::Signal_handler<Context> _dispatcher;
|
||||
|
||||
static void _run_irq(void *args)
|
||||
{
|
||||
@ -131,7 +120,7 @@ class Lx_kit::Irq : public Lx::Irq
|
||||
_dev(dev),
|
||||
_irq_sess(dev.irq(0)),
|
||||
_task(_run_irq, this, _name.name, Lx::Task::PRIORITY_3, Lx::scheduler()),
|
||||
_dispatcher(ep, *this, &Context::_handle)
|
||||
_dispatcher(ep, *this, &Context::unblock)
|
||||
{
|
||||
_irq_sess.sigh(_dispatcher);
|
||||
|
||||
@ -139,6 +128,17 @@ class Lx_kit::Irq : public Lx::Irq
|
||||
_irq_sess.ack_irq();
|
||||
}
|
||||
|
||||
/**
|
||||
* Unblock this context, e.g., as result of an IRQ signal
|
||||
*/
|
||||
void unblock()
|
||||
{
|
||||
_task.unblock();
|
||||
|
||||
/* kick off scheduling */
|
||||
Lx::scheduler().schedule();
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle IRQ
|
||||
*/
|
||||
@ -214,6 +214,12 @@ class Lx_kit::Irq : public Lx::Irq
|
||||
Handler(dev_id, handler, thread_fn);
|
||||
ctx->add_handler(h);
|
||||
}
|
||||
|
||||
void inject_irq(Platform::Device &dev)
|
||||
{
|
||||
Context *ctx = _find_context(dev);
|
||||
if (ctx) ctx->unblock();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user