mirror of
https://github.com/genodelabs/genode.git
synced 2025-06-01 15:10:56 +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"/>
|
! <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
|
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
|
the driver is able to export a corresponding report ROM. This has to be
|
||||||
configured too, like in the following:
|
configured too, like in the following:
|
||||||
|
@ -15,6 +15,7 @@
|
|||||||
#define __COMPONENT_H__
|
#define __COMPONENT_H__
|
||||||
|
|
||||||
/* Genode includes */
|
/* Genode includes */
|
||||||
|
#include <base/component.h>
|
||||||
#include <base/rpc_server.h>
|
#include <base/rpc_server.h>
|
||||||
#include <root/component.h>
|
#include <root/component.h>
|
||||||
#include <dataspace/capability.h>
|
#include <dataspace/capability.h>
|
||||||
@ -41,21 +42,28 @@ class Framebuffer::Driver
|
|||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
|
|
||||||
Session_component &_session;
|
Session_component &_session;
|
||||||
int _height = 0;
|
Timer::Connection _timer;
|
||||||
int _width = 0;
|
Genode::Signal_handler<Driver> _poll_handler;
|
||||||
static constexpr unsigned _bytes_per_pixel = 2;
|
int _height = 0;
|
||||||
void *_new_fb_ds_base = nullptr;
|
int _width = 0;
|
||||||
void *_cur_fb_ds_base = nullptr;
|
static constexpr unsigned _bytes_per_pixel = 2;
|
||||||
Genode::uint64_t _cur_fb_ds_size = 0;
|
void *_new_fb_ds_base = nullptr;
|
||||||
drm_framebuffer *_new_fb = nullptr;
|
void *_cur_fb_ds_base = nullptr;
|
||||||
drm_framebuffer *_cur_fb = 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);
|
drm_display_mode * _preferred_mode(drm_connector *connector);
|
||||||
|
|
||||||
|
void _poll();
|
||||||
|
|
||||||
public:
|
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 width() const { return _width; }
|
||||||
int height() const { return _height; }
|
int height() const { return _height; }
|
||||||
@ -65,6 +73,7 @@ class Framebuffer::Driver
|
|||||||
return _width * _height * _bytes_per_pixel; }
|
return _width * _height * _bytes_per_pixel; }
|
||||||
|
|
||||||
void finish_initialization();
|
void finish_initialization();
|
||||||
|
void set_polling(unsigned long poll);
|
||||||
bool mode_changed();
|
bool mode_changed();
|
||||||
void generate_report();
|
void generate_report();
|
||||||
void free_framebuffer();
|
void free_framebuffer();
|
||||||
@ -90,6 +99,9 @@ class Framebuffer::Session_component : public Genode::Rpc_object<Session>
|
|||||||
bool _buffered_from_config() {
|
bool _buffered_from_config() {
|
||||||
return _config.xml().attribute_value("buffered", false); }
|
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)
|
void _refresh_buffered(int x, int y, int w, int h)
|
||||||
{
|
{
|
||||||
using namespace Genode;
|
using namespace Genode;
|
||||||
@ -114,8 +126,9 @@ class Framebuffer::Session_component : public Genode::Rpc_object<Session>
|
|||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
Session_component(Genode::Attached_rom_dataspace &config)
|
Session_component(Genode::Env &env,
|
||||||
: _driver(*this), _config(config),
|
Genode::Attached_rom_dataspace &config)
|
||||||
|
: _driver(env, *this), _config(config), _timer(env),
|
||||||
_buffered(_buffered_from_config()) {}
|
_buffered(_buffered_from_config()) {}
|
||||||
|
|
||||||
Driver & driver() { return _driver; }
|
Driver & driver() { return _driver; }
|
||||||
@ -127,6 +140,7 @@ class Framebuffer::Session_component : public Genode::Rpc_object<Session>
|
|||||||
|
|
||||||
_in_update = true;
|
_in_update = true;
|
||||||
_buffered = _buffered_from_config();
|
_buffered = _buffered_from_config();
|
||||||
|
_driver.set_polling(_polling_from_config());
|
||||||
if (_driver.mode_changed() && _mode_sigh.valid())
|
if (_driver.mode_changed() && _mode_sigh.valid())
|
||||||
Genode::Signal_transmitter(_mode_sigh).submit();
|
Genode::Signal_transmitter(_mode_sigh).submit();
|
||||||
else
|
else
|
||||||
@ -191,11 +205,11 @@ struct Framebuffer::Root
|
|||||||
Session_component *_create_session(const char *args) override {
|
Session_component *_create_session(const char *args) override {
|
||||||
return &session; }
|
return &session; }
|
||||||
|
|
||||||
Root(Genode::Entrypoint &ep, Genode::Allocator &alloc,
|
Root(Genode::Env &env, Genode::Allocator &alloc,
|
||||||
Genode::Attached_rom_dataspace &config)
|
Genode::Attached_rom_dataspace &config)
|
||||||
: Genode::Root_component<Session_component,
|
: Genode::Root_component<Session_component,
|
||||||
Genode::Single_client>(ep, alloc),
|
Genode::Single_client>(env.ep(), alloc),
|
||||||
session(config) { }
|
session(env, config) { }
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif /* __COMPONENT_H__ */
|
#endif /* __COMPONENT_H__ */
|
||||||
|
@ -137,9 +137,34 @@ void Framebuffer::Driver::finish_initialization()
|
|||||||
{
|
{
|
||||||
dde_c_set_driver(dde_drm_device, (void*)this);
|
dde_c_set_driver(dde_drm_device, (void*)this);
|
||||||
generate_report();
|
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()
|
bool Framebuffer::Driver::mode_changed()
|
||||||
{
|
{
|
||||||
using namespace Genode;
|
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,
|
int request_irq(unsigned int irq, irq_handler_t handler, unsigned long flags,
|
||||||
const char *name, void *dev)
|
const char *name, void *dev)
|
||||||
{
|
{
|
||||||
|
@ -41,11 +41,11 @@ unsigned long jiffies;
|
|||||||
|
|
||||||
struct Main
|
struct Main
|
||||||
{
|
{
|
||||||
Genode::Entrypoint &ep;
|
Genode::Env &env;
|
||||||
Genode::Attached_rom_dataspace config;
|
Genode::Entrypoint &ep { env.ep() };
|
||||||
Genode::Heap heap;
|
Genode::Attached_rom_dataspace config { env, "config" };
|
||||||
|
Genode::Heap heap { env.ram(), env.rm() };
|
||||||
Framebuffer::Root root { ep, heap, config };
|
Framebuffer::Root root { env, heap, config };
|
||||||
|
|
||||||
/* init singleton Lx::Timer */
|
/* init singleton Lx::Timer */
|
||||||
Lx::Timer &timer = Lx::timer(&ep, &jiffies);
|
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 linux { run_linux, reinterpret_cast<void*>(this), "linux",
|
||||||
Lx::Task::PRIORITY_0, Lx::scheduler() };
|
Lx::Task::PRIORITY_0, Lx::scheduler() };
|
||||||
|
|
||||||
Main(Genode::Env &env)
|
Main(Genode::Env &env) : env(env)
|
||||||
: ep(env.ep()), config(env, "config"), heap(env.ram(), env.rm())
|
|
||||||
{
|
{
|
||||||
Genode::log("--- intel framebuffer driver ---");
|
Genode::log("--- intel framebuffer driver ---");
|
||||||
|
|
||||||
|
@ -35,6 +35,8 @@ class Lx::Irq
|
|||||||
*/
|
*/
|
||||||
virtual void request_irq(Platform::Device &dev, irq_handler_t handler,
|
virtual void request_irq(Platform::Device &dev, irq_handler_t handler,
|
||||||
void *dev_id, irq_handler_t thread_fn = 0) = 0;
|
void *dev_id, irq_handler_t thread_fn = 0) = 0;
|
||||||
|
|
||||||
|
virtual void inject_irq(Platform::Device &dev) = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif /* _LX_KIT__IRQ_H_ */
|
#endif /* _LX_KIT__IRQ_H_ */
|
||||||
|
@ -96,18 +96,7 @@ class Lx_kit::Irq : public Lx::Irq
|
|||||||
Lx_kit::List<Handler> _handler;
|
Lx_kit::List<Handler> _handler;
|
||||||
Lx::Task _task;
|
Lx::Task _task;
|
||||||
|
|
||||||
Genode::Signal_rpc_member<Context> _dispatcher;
|
Genode::Signal_handler<Context> _dispatcher;
|
||||||
|
|
||||||
/**
|
|
||||||
* Signal handler
|
|
||||||
*/
|
|
||||||
void _handle(unsigned)
|
|
||||||
{
|
|
||||||
_task.unblock();
|
|
||||||
|
|
||||||
/* kick off scheduling */
|
|
||||||
Lx::scheduler().schedule();
|
|
||||||
}
|
|
||||||
|
|
||||||
static void _run_irq(void *args)
|
static void _run_irq(void *args)
|
||||||
{
|
{
|
||||||
@ -131,7 +120,7 @@ class Lx_kit::Irq : public Lx::Irq
|
|||||||
_dev(dev),
|
_dev(dev),
|
||||||
_irq_sess(dev.irq(0)),
|
_irq_sess(dev.irq(0)),
|
||||||
_task(_run_irq, this, _name.name, Lx::Task::PRIORITY_3, Lx::scheduler()),
|
_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);
|
_irq_sess.sigh(_dispatcher);
|
||||||
|
|
||||||
@ -139,6 +128,17 @@ class Lx_kit::Irq : public Lx::Irq
|
|||||||
_irq_sess.ack_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
|
* Handle IRQ
|
||||||
*/
|
*/
|
||||||
@ -214,6 +214,12 @@ class Lx_kit::Irq : public Lx::Irq
|
|||||||
Handler(dev_id, handler, thread_fn);
|
Handler(dev_id, handler, thread_fn);
|
||||||
ctx->add_handler(h);
|
ctx->add_handler(h);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void inject_irq(Platform::Device &dev)
|
||||||
|
{
|
||||||
|
Context *ctx = _find_context(dev);
|
||||||
|
if (ctx) ctx->unblock();
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user