mirror of
https://github.com/genodelabs/genode.git
synced 2024-12-24 07:46:42 +00:00
parent
e69c01aad3
commit
50cc52a091
@ -68,7 +68,12 @@ append config {
|
|||||||
</default-route>
|
</default-route>
|
||||||
<default caps="100"/>
|
<default caps="100"/>
|
||||||
|
|
||||||
<start name="report_rom" caps="100">
|
<start name="timer">
|
||||||
|
<resource name="RAM" quantum="1M"/>
|
||||||
|
<provides><service name="Timer"/></provides>
|
||||||
|
</start>
|
||||||
|
|
||||||
|
<start name="report_rom" caps="100" priority="-1">
|
||||||
<resource name="RAM" quantum="2M"/>
|
<resource name="RAM" quantum="2M"/>
|
||||||
<provides>
|
<provides>
|
||||||
<service name="ROM" />
|
<service name="ROM" />
|
||||||
@ -87,7 +92,7 @@ append config {
|
|||||||
</route>
|
</route>
|
||||||
</start>
|
</start>
|
||||||
|
|
||||||
<start name="acpi" caps="250">
|
<start name="acpi" caps="250" priority="-1">
|
||||||
<resource name="RAM" quantum="6M"/>
|
<resource name="RAM" quantum="6M"/>
|
||||||
<route>
|
<route>
|
||||||
<service name="IO_MEM"> <parent/> </service>
|
<service name="IO_MEM"> <parent/> </service>
|
||||||
@ -100,7 +105,7 @@ append config {
|
|||||||
</route>
|
</route>
|
||||||
</start>
|
</start>
|
||||||
|
|
||||||
<start name="pci_decode" caps="350">
|
<start name="pci_decode" caps="350" priority="-1">
|
||||||
<resource name="RAM" quantum="2M"/>
|
<resource name="RAM" quantum="2M"/>
|
||||||
<route>
|
<route>
|
||||||
<service name="Report">
|
<service name="Report">
|
||||||
@ -116,7 +121,7 @@ append config {
|
|||||||
</route>
|
</route>
|
||||||
</start>
|
</start>
|
||||||
|
|
||||||
<start name="platform" caps="100" managing_system="yes">
|
<start name="platform" caps="100" managing_system="yes" priority="-1">
|
||||||
<resource name="RAM" quantum="2M"/>
|
<resource name="RAM" quantum="2M"/>
|
||||||
<provides> <service name="Platform"/> </provides>
|
<provides> <service name="Platform"/> </provides>
|
||||||
<route>
|
<route>
|
||||||
@ -143,14 +148,20 @@ append config {
|
|||||||
<pci class="USB"/>
|
<pci class="USB"/>
|
||||||
</policy>
|
</policy>
|
||||||
</config>
|
</config>
|
||||||
</start>
|
</start>}
|
||||||
|
|
||||||
<start name="timer">
|
append_if $use_top config {
|
||||||
<resource name="RAM" quantum="1M"/>
|
<start name="top" priority="-1">
|
||||||
<provides><service name="Timer"/></provides>
|
<resource name="RAM" quantum="2M"/>
|
||||||
</start>
|
<config period_ms="40000"/>
|
||||||
|
<route>
|
||||||
|
<service name="TRACE"> <parent label=""/> </service>
|
||||||
|
<any-service> <parent/> <any-child/> </any-service>
|
||||||
|
</route>
|
||||||
|
</start>}
|
||||||
|
|
||||||
<start name="init_dynamic" caps="10000">
|
append config {
|
||||||
|
<start name="init_dynamic" caps="10000" priority="-2">
|
||||||
<binary name="init"/>
|
<binary name="init"/>
|
||||||
<resource name="RAM" quantum="1000M"/>
|
<resource name="RAM" quantum="1000M"/>
|
||||||
<route>
|
<route>
|
||||||
@ -181,16 +192,6 @@ append config {
|
|||||||
<default caps="100"/>
|
<default caps="100"/>
|
||||||
<report init_ram="yes" child_ram="yes" delay_ms="10000"/>}
|
<report init_ram="yes" child_ram="yes" delay_ms="10000"/>}
|
||||||
|
|
||||||
append_if $use_top config {
|
|
||||||
<start name="top">
|
|
||||||
<resource name="RAM" quantum="2M"/>
|
|
||||||
<config period_ms="40000"/>
|
|
||||||
<route>
|
|
||||||
<service name="TRACE"> <parent label=""/> </service>
|
|
||||||
<any-service> <parent/> <any-child/> </any-service>
|
|
||||||
</route>
|
|
||||||
</start>}
|
|
||||||
|
|
||||||
append config {
|
append config {
|
||||||
<start name="report_rom" priority="-1">
|
<start name="report_rom" priority="-1">
|
||||||
<resource name="RAM" quantum="2M"/>
|
<resource name="RAM" quantum="2M"/>
|
||||||
@ -219,6 +220,13 @@ append config {
|
|||||||
<inline name="fb.config">
|
<inline name="fb.config">
|
||||||
<config ld_verbose="yes" apply_on_hotplug="} $apply_on_hotplug {">
|
<config ld_verbose="yes" apply_on_hotplug="} $apply_on_hotplug {">
|
||||||
<report connectors="yes"/>
|
<report connectors="yes"/>
|
||||||
|
<merge name="mirror">
|
||||||
|
<!-- all connectors in merge node gets mirrored -->
|
||||||
|
<!--
|
||||||
|
<connector name="DP-1"/>
|
||||||
|
<connector name="HDMI-A-1"/>
|
||||||
|
-->
|
||||||
|
</merge>
|
||||||
</config>
|
</config>
|
||||||
</inline>
|
</inline>
|
||||||
</import>
|
</import>
|
||||||
@ -266,7 +274,7 @@ append_if $use_gpu config {
|
|||||||
append config {
|
append config {
|
||||||
<start name="intel_fb" caps="1000">
|
<start name="intel_fb" caps="1000">
|
||||||
<binary name="pc_intel_fb"/>
|
<binary name="pc_intel_fb"/>
|
||||||
<resource name="RAM" quantum="90M"/>
|
<resource name="RAM" quantum="128M"/>
|
||||||
<route>}
|
<route>}
|
||||||
|
|
||||||
append_if $use_gpu config {
|
append_if $use_gpu config {
|
||||||
@ -276,6 +284,18 @@ append config {
|
|||||||
<service name="ROM" label="config">
|
<service name="ROM" label="config">
|
||||||
<child name="config_rom" label="fb.config"/> </service>
|
<child name="config_rom" label="fb.config"/> </service>
|
||||||
<service name="Report"> <child name="report_rom"/> </service>
|
<service name="Report"> <child name="report_rom"/> </service>
|
||||||
|
|
||||||
|
<service name="Capture" label="eDP-1"> <child name="test-framebuffer-eDP-1"/> </service>
|
||||||
|
<service name="Capture" label="HDMI-A-1"> <child name="test-framebuffer-HDMI-A-1"/> </service>
|
||||||
|
<service name="Capture" label="HDMI-A-2"> <child name="test-framebuffer-HDMI-A-2"/> </service>
|
||||||
|
<service name="Capture" label="HDMI-A-3"> <child name="test-framebuffer-HDMI-A-3"/> </service>
|
||||||
|
<service name="Capture" label="DP-1"> <child name="test-framebuffer-DP-1"/> </service>
|
||||||
|
<service name="Capture" label="DP-2"> <child name="test-framebuffer-DP-2"/> </service>
|
||||||
|
<service name="Capture" label="DP-3"> <child name="test-framebuffer-DP-3"/> </service>
|
||||||
|
<service name="Capture" label="DP-4"> <child name="test-framebuffer-DP-4"/> </service>
|
||||||
|
<service name="Capture" label="VGA-1"> <child name="test-framebuffer-VGA-1"/> </service>
|
||||||
|
<service name="Capture" label="mirror"> <child name="test-framebuffer-mirror"/> </service>
|
||||||
|
|
||||||
<any-service> <parent/> <any-child /> </any-service>
|
<any-service> <parent/> <any-child /> </any-service>
|
||||||
</route>
|
</route>
|
||||||
</start>}
|
</start>}
|
||||||
@ -309,7 +329,62 @@ append_if $use_fb_controller config {
|
|||||||
</start>}
|
</start>}
|
||||||
|
|
||||||
append config {
|
append config {
|
||||||
<start name="test-framebuffer" priority="-1">
|
<start name="test-framebuffer-eDP-1" priority="-1">
|
||||||
|
<binary name="test-framebuffer"/>
|
||||||
|
<resource name="RAM" quantum="10M"/>
|
||||||
|
<provides> <service name="Capture"/> </provides>
|
||||||
|
<config/>
|
||||||
|
</start>
|
||||||
|
<start name="test-framebuffer-HDMI-A-1" priority="-1">
|
||||||
|
<binary name="test-framebuffer"/>
|
||||||
|
<resource name="RAM" quantum="10M"/>
|
||||||
|
<provides> <service name="Capture"/> </provides>
|
||||||
|
<config/>
|
||||||
|
</start>
|
||||||
|
<start name="test-framebuffer-HDMI-A-2" priority="-1">
|
||||||
|
<binary name="test-framebuffer"/>
|
||||||
|
<resource name="RAM" quantum="10M"/>
|
||||||
|
<provides> <service name="Capture"/> </provides>
|
||||||
|
<config/>
|
||||||
|
</start>
|
||||||
|
<start name="test-framebuffer-HDMI-A-3" priority="-1">
|
||||||
|
<binary name="test-framebuffer"/>
|
||||||
|
<resource name="RAM" quantum="10M"/>
|
||||||
|
<provides> <service name="Capture"/> </provides>
|
||||||
|
<config/>
|
||||||
|
</start>
|
||||||
|
<start name="test-framebuffer-DP-1" priority="-1">
|
||||||
|
<binary name="test-framebuffer"/>
|
||||||
|
<resource name="RAM" quantum="10M"/>
|
||||||
|
<provides> <service name="Capture"/> </provides>
|
||||||
|
<config/>
|
||||||
|
</start>
|
||||||
|
<start name="test-framebuffer-DP-2" priority="-1">
|
||||||
|
<binary name="test-framebuffer"/>
|
||||||
|
<resource name="RAM" quantum="10M"/>
|
||||||
|
<provides> <service name="Capture"/> </provides>
|
||||||
|
<config/>
|
||||||
|
</start>
|
||||||
|
<start name="test-framebuffer-DP-3" priority="-1">
|
||||||
|
<binary name="test-framebuffer"/>
|
||||||
|
<resource name="RAM" quantum="10M"/>
|
||||||
|
<provides> <service name="Capture"/> </provides>
|
||||||
|
<config/>
|
||||||
|
</start>
|
||||||
|
<start name="test-framebuffer-DP-4" priority="-1">
|
||||||
|
<binary name="test-framebuffer"/>
|
||||||
|
<resource name="RAM" quantum="10M"/>
|
||||||
|
<provides> <service name="Capture"/> </provides>
|
||||||
|
<config/>
|
||||||
|
</start>
|
||||||
|
<start name="test-framebuffer-VGA-1" priority="-1">
|
||||||
|
<binary name="test-framebuffer"/>
|
||||||
|
<resource name="RAM" quantum="10M"/>
|
||||||
|
<provides> <service name="Capture"/> </provides>
|
||||||
|
<config/>
|
||||||
|
</start>
|
||||||
|
<start name="test-framebuffer-mirror" priority="-1">
|
||||||
|
<binary name="test-framebuffer"/>
|
||||||
<resource name="RAM" quantum="10M"/>
|
<resource name="RAM" quantum="10M"/>
|
||||||
<provides> <service name="Capture"/> </provides>
|
<provides> <service name="Capture"/> </provides>
|
||||||
<config/>
|
<config/>
|
||||||
|
@ -3,62 +3,22 @@ This driver is for Intel i915 compatible graphic cards.
|
|||||||
Default behaviour
|
Default behaviour
|
||||||
~~~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
When no configuration is provided to the driver, it will switch on all devices
|
When no configuration is provided to the driver, it will enable all connectors
|
||||||
connected to the graphics card. It will use the highest resolution as
|
with attached displays and allocate for each display a discrete framebuffer.
|
||||||
provided by the BIOS or EDID information from the display devices for each
|
It will use the highest resolution as provided by the BIOS or EDID information.
|
||||||
connector. The virtual resolution delivered to the client is the maximum in
|
For each connector a separate Capture connection will be requested labeled
|
||||||
width and height of the active connectors.
|
according to the connector name. When newly connected displays are detected
|
||||||
|
by the driver, the new connectors are enabled and another Capture session
|
||||||
|
labeled according to the connector will be requested.
|
||||||
|
|
||||||
When newly connected devices are detected by the hardware, the new connectors
|
By default, on hotplug of a display, the current config of the driver will be
|
||||||
are enabled, probed, and again the highest resolution across all active
|
re-parsed and re-applied. This behaviour can be disabled by
|
||||||
connectors will be chosen. By default, the current config of the driver will
|
|
||||||
be re-read and re-applied. This behaviour can be disabled by
|
|
||||||
|
|
||||||
! <config apply_on_hotplug="no"/>
|
! <config apply_on_hotplug="no"/>
|
||||||
|
|
||||||
Configuration
|
Configuration
|
||||||
~~~~~~~~~~~~~
|
~~~~~~~~~~~~~
|
||||||
|
|
||||||
Each of the connectors can be configured explicitly in terms of resolution and
|
|
||||||
whether it should be enabled or not. This looks like the following:
|
|
||||||
|
|
||||||
! <config>
|
|
||||||
! <connector name="eDP-1" width="1920" height="1080" hz="60" brightness="75" enabled="true"/>
|
|
||||||
! <connector name="DP-1" mode_id="2" enabled="true"/>
|
|
||||||
! </config>
|
|
||||||
|
|
||||||
The resolution can be configured exactly by the reported mode_id or by
|
|
||||||
the width/height/hz attributes. In the latter case the driver will take the
|
|
||||||
first matching mode out of multiple matching modes potentially.
|
|
||||||
|
|
||||||
When the configuration changes during runtime, the driver will adapt to it. In
|
|
||||||
this case, it will also change the current virtual resolution to the maximum of
|
|
||||||
the configured resolutions in width and height, and it will inform its client
|
|
||||||
about the change in resolution.
|
|
||||||
|
|
||||||
The brightness value is in percent and takes effect only if supported by
|
|
||||||
the hardware.
|
|
||||||
|
|
||||||
The maximal physical resolution can be enforced by:
|
|
||||||
|
|
||||||
! <config max_width="2560" max_height="1440">
|
|
||||||
! </config>
|
|
||||||
|
|
||||||
The virtual resolution can be enforced by:
|
|
||||||
|
|
||||||
! <config force_width="1024" force_height="768">
|
|
||||||
! </config>
|
|
||||||
|
|
||||||
The amount of memory used by the driver for the accounting of its available
|
|
||||||
buffer space is set by:
|
|
||||||
|
|
||||||
! <config max_framebuffer_memory="64M">
|
|
||||||
! </config>
|
|
||||||
|
|
||||||
The default and minimal value is '64M' and suffices for resolutions of at
|
|
||||||
least '3840x2160'. How much actual memory is used depends on the configured
|
|
||||||
resolution.
|
|
||||||
|
|
||||||
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 deliver a corresponding report, which can be enabled
|
the driver is able to deliver a corresponding report, which can be enabled
|
||||||
in the configuration as follows:
|
in the configuration as follows:
|
||||||
@ -89,5 +49,78 @@ in millimeter per connector and if available, also per mode. The values can
|
|||||||
be used as input to DPI calculations. The currently used mode of the connector
|
be used as input to DPI calculations. The currently used mode of the connector
|
||||||
is tagged in the report explicitly.
|
is tagged in the report explicitly.
|
||||||
|
|
||||||
The brightness attribute is reported only if the hardware supports it.
|
Each of the connectors can be configured a specific mode and
|
||||||
|
whether it should be enabled or not. This looks like the following:
|
||||||
|
|
||||||
|
! <config>
|
||||||
|
! <connector name="eDP-1" enabled="true" width="1920" height="1080" hz="60" brightness="75"/>
|
||||||
|
! <connector name="DP-1" enabled="true" mode_id="2"/>
|
||||||
|
! </config>
|
||||||
|
|
||||||
|
The resolution can be configured exactly by the reported mode_id or by
|
||||||
|
the width/height/hz attributes. In the latter case the driver will take the
|
||||||
|
first matching mode out of multiple matching modes potentially.
|
||||||
|
|
||||||
|
The brightness value is in percent and takes effect only if supported by
|
||||||
|
the hardware.
|
||||||
|
|
||||||
|
The maximal physical resolution across all connectors can be restricted by:
|
||||||
|
|
||||||
|
! <config max_width="2560" max_height="1440">
|
||||||
|
! </config>
|
||||||
|
|
||||||
|
Note: All larger modes still will be reported, but are marked as unusable
|
||||||
|
by an additional attribute 'unavailable' set to true.
|
||||||
|
|
||||||
|
The amount of memory used by the driver for the accounting of its available
|
||||||
|
buffer space is set by:
|
||||||
|
|
||||||
|
! <config max_framebuffer_memory="64M">
|
||||||
|
! </config>
|
||||||
|
|
||||||
|
The default and minimal value is '64M' and suffices for resolutions of at
|
||||||
|
least '3840x2160'. How much actual memory is used depends on the configured
|
||||||
|
resolution.
|
||||||
|
|
||||||
|
|
||||||
|
Non-discrete usage of connectors
|
||||||
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
Mirrored usage of connectors can be achieved by moving those connectors into
|
||||||
|
a sub node called 'merge' of the configuration. For all those connectors,
|
||||||
|
exactly one and the same framebuffer will be used internally by the driver.
|
||||||
|
The driver will allocate the framebuffer large enough to accommodate all
|
||||||
|
non-discrete connectors. If some of the modes of the connectors are smaller,
|
||||||
|
than only a subset of the content will be visible on those displays.
|
||||||
|
|
||||||
|
! <connectors>
|
||||||
|
!
|
||||||
|
! <connector name="eDP-1" ...> <!-- discrete, not mirrored -->
|
||||||
|
! ...
|
||||||
|
! </connector>
|
||||||
|
! <connector name="DP-1" ...> <!.. discrete, not mirrored -->
|
||||||
|
! ...
|
||||||
|
! </connector>
|
||||||
|
!
|
||||||
|
! <merge name="mirror">
|
||||||
|
! <connector name="HDMI-A-1" ...>
|
||||||
|
! ...
|
||||||
|
! </connector>
|
||||||
|
! <connector name="VGA--1" ...>
|
||||||
|
! ...
|
||||||
|
! </connector>
|
||||||
|
! </merge>
|
||||||
|
! </connectors>
|
||||||
|
|
||||||
|
Note: If connectors are configured as non-discrete, they will also be
|
||||||
|
reported inside a separate 'merge' node.
|
||||||
|
|
||||||
|
Additionally, the virtual resolution for non-discrete connectors may be
|
||||||
|
restricted via:
|
||||||
|
|
||||||
|
! <merge name="mirror" width="1024" height="768">
|
||||||
|
! ...
|
||||||
|
! </merge>
|
||||||
|
|
||||||
|
Thereby, the driver will open a Genode capture session to the
|
||||||
|
GUI multiplexer with this limited dimension.
|
||||||
|
@ -1,27 +0,0 @@
|
|||||||
/*
|
|
||||||
* \brief Linux kernel framebuffer device support
|
|
||||||
* \author Stefan Kalkowski
|
|
||||||
* \date 2021-05-03
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Copyright (C) 2021-2023 Genode Labs GmbH
|
|
||||||
*
|
|
||||||
* This file is distributed under the terms of the GNU General Public License
|
|
||||||
* version 2.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <linux/kernel.h>
|
|
||||||
#include <linux/slab.h>
|
|
||||||
#include <linux/fb.h>
|
|
||||||
#include <lx_emul/fb.h>
|
|
||||||
|
|
||||||
|
|
||||||
int register_framebuffer(struct fb_info * fb_info)
|
|
||||||
{
|
|
||||||
lx_emul_framebuffer_ready(fb_info->screen_base, fb_info->screen_size,
|
|
||||||
fb_info->var.xres_virtual, fb_info->var.yres_virtual,
|
|
||||||
fb_info->fix.line_length /
|
|
||||||
(fb_info->var.bits_per_pixel / 8), fb_info->var.yres);
|
|
||||||
return 0;
|
|
||||||
}
|
|
@ -1,29 +0,0 @@
|
|||||||
/**
|
|
||||||
* \brief Lx_emul support to register Linux kernel framebuffer
|
|
||||||
* \author Stefan Kalkowski
|
|
||||||
* \date 2021-05-17
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Copyright (C) 2021 Genode Labs GmbH
|
|
||||||
*
|
|
||||||
* This file is distributed under the terms of the GNU General Public License
|
|
||||||
* version 2.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef _LX_EMUL__FB_H_
|
|
||||||
#define _LX_EMUL__FB_H_
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
extern "C" {
|
|
||||||
#endif
|
|
||||||
|
|
||||||
void lx_emul_framebuffer_ready(void * base, unsigned long size,
|
|
||||||
unsigned xres, unsigned yres,
|
|
||||||
unsigned virtual_width, unsigned virtual_height);
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif /* _LX_EMUL__FB_H_ */
|
|
@ -29,11 +29,13 @@ struct genode_mode {
|
|||||||
unsigned preferred;
|
unsigned preferred;
|
||||||
unsigned inuse;
|
unsigned inuse;
|
||||||
unsigned id;
|
unsigned id;
|
||||||
|
char mirror;
|
||||||
char name[32];
|
char name[32];
|
||||||
};
|
};
|
||||||
|
|
||||||
int lx_emul_i915_blit(void);
|
int lx_emul_i915_blit(unsigned);
|
||||||
void lx_emul_i915_report(void * genode_xml);
|
void lx_emul_i915_report_discrete(void * genode_xml);
|
||||||
|
void lx_emul_i915_report_non_discrete(void * genode_xml);
|
||||||
void lx_emul_i915_hotplug_connector(void);
|
void lx_emul_i915_hotplug_connector(void);
|
||||||
void lx_emul_i915_report_connector(void * lx_data, void * genode_xml,
|
void lx_emul_i915_report_connector(void * lx_data, void * genode_xml,
|
||||||
char const *name, char connected,
|
char const *name, char connected,
|
||||||
@ -43,5 +45,14 @@ void lx_emul_i915_iterate_modes(void *lx_data, void * genode_data);
|
|||||||
void lx_emul_i915_report_modes(void * genode_xml, struct genode_mode *);
|
void lx_emul_i915_report_modes(void * genode_xml, struct genode_mode *);
|
||||||
void lx_emul_i915_connector_config(char * name, struct genode_mode *);
|
void lx_emul_i915_connector_config(char * name, struct genode_mode *);
|
||||||
int lx_emul_i915_config_done_and_block(void);
|
int lx_emul_i915_config_done_and_block(void);
|
||||||
|
void lx_emul_i915_framebuffer_ready(unsigned connector_id,
|
||||||
|
char const * const connector_name,
|
||||||
|
void * base,
|
||||||
|
unsigned long size,
|
||||||
|
unsigned xres, unsigned yres,
|
||||||
|
unsigned virtual_width,
|
||||||
|
unsigned virtual_height,
|
||||||
|
unsigned mm_width,
|
||||||
|
unsigned mm_height);
|
||||||
|
|
||||||
#endif /* _LX_I915_H_ */
|
#endif /* _LX_I915_H_ */
|
||||||
|
@ -28,14 +28,15 @@
|
|||||||
enum { MAX_BRIGHTNESS = 100, INVALID_BRIGHTNESS = MAX_BRIGHTNESS + 1 };
|
enum { MAX_BRIGHTNESS = 100, INVALID_BRIGHTNESS = MAX_BRIGHTNESS + 1 };
|
||||||
|
|
||||||
|
|
||||||
struct task_struct * lx_update_task = NULL;
|
|
||||||
struct task_struct * lx_user_task = NULL;
|
struct task_struct * lx_user_task = NULL;
|
||||||
|
static struct task_struct * lx_update_task = NULL;
|
||||||
static struct drm_client_dev * dev_client = NULL;
|
static struct drm_client_dev * dev_client = NULL;
|
||||||
|
|
||||||
|
|
||||||
static int user_register_fb(struct drm_client_dev const * const dev,
|
static int user_register_fb(struct drm_client_dev const * const dev,
|
||||||
struct fb_info * const info,
|
struct fb_info * const info,
|
||||||
struct drm_mode_fb_cmd2 const * const dumb_fb);
|
struct drm_mode_fb_cmd2 const * const dumb_fb,
|
||||||
|
unsigned width_mm, unsigned height_mm);
|
||||||
|
|
||||||
|
|
||||||
static int user_attach_fb_to_crtc(struct drm_client_dev * const dev,
|
static int user_attach_fb_to_crtc(struct drm_client_dev * const dev,
|
||||||
@ -85,9 +86,9 @@ static inline bool fb_smaller_mode(struct fb_info const * const info,
|
|||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Heuristic to calculate max resolution across all connectors
|
* Heuristic to calculate max resolution across all mirrored connectors
|
||||||
*/
|
*/
|
||||||
static void preferred_mode(struct drm_device const * const dev,
|
static void preferred_mirror(struct drm_device const * const dev,
|
||||||
struct drm_display_mode * const prefer,
|
struct drm_display_mode * const prefer,
|
||||||
struct drm_display_mode * const min_mode)
|
struct drm_display_mode * const min_mode)
|
||||||
{
|
{
|
||||||
@ -101,7 +102,7 @@ static void preferred_mode(struct drm_device const * const dev,
|
|||||||
drm_connector_list_iter_begin(dev, &conn_iter);
|
drm_connector_list_iter_begin(dev, &conn_iter);
|
||||||
drm_client_for_each_connector_iter(connector, &conn_iter) {
|
drm_client_for_each_connector_iter(connector, &conn_iter) {
|
||||||
struct drm_display_mode smallest = { .hdisplay = ~0, .vdisplay = ~0 };
|
struct drm_display_mode smallest = { .hdisplay = ~0, .vdisplay = ~0 };
|
||||||
struct genode_mode conf_mode = { .enabled = 1 };
|
struct genode_mode conf_mode = { };
|
||||||
unsigned mode_id = 0;
|
unsigned mode_id = 0;
|
||||||
|
|
||||||
/* check for connector configuration on Genode side */
|
/* check for connector configuration on Genode side */
|
||||||
@ -144,7 +145,9 @@ static void preferred_mode(struct drm_device const * const dev,
|
|||||||
if (mode_id && mode_larger(&smallest, min_mode))
|
if (mode_id && mode_larger(&smallest, min_mode))
|
||||||
*min_mode = smallest;
|
*min_mode = smallest;
|
||||||
|
|
||||||
if (conf_mode.force_width && conf_mode.force_height) {
|
if (conf_mode.mirror &&
|
||||||
|
conf_mode.force_width && conf_mode.force_height) {
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Even so the force_* mode is selected, a configured mode for
|
* Even so the force_* mode is selected, a configured mode for
|
||||||
* a connector is considered, effectively the framebuffer content
|
* a connector is considered, effectively the framebuffer content
|
||||||
@ -168,7 +171,7 @@ static void preferred_mode(struct drm_device const * const dev,
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!conf_mode.width || !conf_mode.height)
|
if (!conf_mode.width || !conf_mode.height || !conf_mode.mirror)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (conf_larger_mode(&conf_mode, prefer)) {
|
if (conf_larger_mode(&conf_mode, prefer)) {
|
||||||
@ -189,6 +192,11 @@ static void preferred_mode(struct drm_device const * const dev,
|
|||||||
/* if too large or nothing configured by Genode's config */
|
/* if too large or nothing configured by Genode's config */
|
||||||
drm_connector_list_iter_begin(dev, &conn_iter);
|
drm_connector_list_iter_begin(dev, &conn_iter);
|
||||||
drm_client_for_each_connector_iter(connector, &conn_iter) {
|
drm_client_for_each_connector_iter(connector, &conn_iter) {
|
||||||
|
|
||||||
|
struct genode_mode conf_mode = { };
|
||||||
|
/* check for connector configuration on Genode side */
|
||||||
|
lx_emul_i915_connector_config(connector->name, &conf_mode);
|
||||||
|
|
||||||
list_for_each_entry(mode, &connector->modes, head) {
|
list_for_each_entry(mode, &connector->modes, head) {
|
||||||
if (!mode)
|
if (!mode)
|
||||||
continue;
|
continue;
|
||||||
@ -201,6 +209,9 @@ static void preferred_mode(struct drm_device const * const dev,
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (conf_mode.enabled && !conf_mode.mirror)
|
||||||
|
continue;
|
||||||
|
|
||||||
if (mode_larger(mode, prefer)) {
|
if (mode_larger(mode, prefer)) {
|
||||||
prefer->hdisplay = mode->hdisplay;
|
prefer->hdisplay = mode->hdisplay;
|
||||||
prefer->vdisplay = mode->vdisplay;
|
prefer->vdisplay = mode->vdisplay;
|
||||||
@ -249,11 +260,279 @@ static unsigned get_brightness(struct drm_connector * const connector,
|
|||||||
return ret * MAX_BRIGHTNESS / panel->backlight.device->props.max_brightness;
|
return ret * MAX_BRIGHTNESS / panel->backlight.device->props.max_brightness;
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct drm_mode_fb_cmd2 dumb_fb = {};
|
|
||||||
|
static struct drm_mode_fb_cmd2 *mirror_fb_cmd;
|
||||||
|
|
||||||
|
|
||||||
|
static struct drm_framebuffer * lookup_framebuffer(struct drm_crtc *crtc,
|
||||||
|
struct drm_modeset_acquire_ctx *ctx)
|
||||||
|
{
|
||||||
|
struct drm_atomic_state *state;
|
||||||
|
struct drm_plane_state *plane;
|
||||||
|
struct drm_crtc_state *crtc_state;
|
||||||
|
|
||||||
|
state = drm_atomic_state_alloc(crtc->dev);
|
||||||
|
if (!state)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
state->acquire_ctx = ctx;
|
||||||
|
|
||||||
|
crtc_state = drm_atomic_get_crtc_state(state, crtc);
|
||||||
|
if (IS_ERR(crtc_state)) {
|
||||||
|
drm_atomic_state_put(state);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
plane = drm_atomic_get_plane_state(state, crtc->primary);
|
||||||
|
|
||||||
|
drm_atomic_state_put(state);
|
||||||
|
|
||||||
|
return plane ? plane->fb : NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
enum { MAX_FBS = 8 };
|
||||||
|
|
||||||
|
|
||||||
|
/* own data structure for tracking dumb buffers, e.g. GEM handles, flags, vma */
|
||||||
|
struct gem_dumb {
|
||||||
|
struct drm_mode_create_dumb fb_dumb;
|
||||||
|
struct drm_mode_fb_cmd2 fb_cmd;
|
||||||
|
struct i915_vma * vma;
|
||||||
|
unsigned long flags;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/* allocator and lookup helper for our own meta data */
|
||||||
|
static bool _meta_data(struct drm_client_dev const * const dev,
|
||||||
|
struct drm_framebuffer const * const fb,
|
||||||
|
struct drm_mode_create_dumb ** fb_dumb, /* out */
|
||||||
|
struct drm_mode_fb_cmd2 ** fb_cmd, /* out */
|
||||||
|
struct gem_dumb ** gem_dumb) /* out */
|
||||||
|
{
|
||||||
|
static struct gem_dumb gem_dumb_list [MAX_FBS] = { };
|
||||||
|
|
||||||
|
struct gem_dumb * free_slot = NULL;
|
||||||
|
|
||||||
|
if (!dev)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
for (unsigned i = 0; i < MAX_FBS; i++) {
|
||||||
|
struct gem_dumb * slot = &gem_dumb_list[i];
|
||||||
|
struct drm_framebuffer * cmp = NULL;
|
||||||
|
|
||||||
|
if (!slot->fb_cmd.fb_id) {
|
||||||
|
if (!free_slot)
|
||||||
|
free_slot = slot;
|
||||||
|
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!fb)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
cmp = drm_framebuffer_lookup(dev->dev, dev->file,
|
||||||
|
slot->fb_cmd.fb_id);
|
||||||
|
|
||||||
|
if (cmp)
|
||||||
|
drm_framebuffer_put(cmp);
|
||||||
|
|
||||||
|
/* lookup case */
|
||||||
|
if (cmp == fb) {
|
||||||
|
if (fb_dumb) *fb_dumb = &slot->fb_dumb;
|
||||||
|
if (fb_cmd) *fb_cmd = &slot->fb_cmd;
|
||||||
|
if (gem_dumb) *gem_dumb = slot;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* allocate case */
|
||||||
|
if (free_slot) {
|
||||||
|
if (fb_dumb) *fb_dumb = &free_slot->fb_dumb;
|
||||||
|
if (fb_cmd) *fb_cmd = &free_slot->fb_cmd;
|
||||||
|
if (gem_dumb) *gem_dumb = free_slot;
|
||||||
|
}
|
||||||
|
|
||||||
|
return !!free_slot;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static bool dumb_meta(struct drm_client_dev const * const dev,
|
||||||
|
struct drm_framebuffer const * const fb,
|
||||||
|
struct drm_mode_create_dumb ** fb_dumb, /* out */
|
||||||
|
struct drm_mode_fb_cmd2 ** fb_cmd) /* out */
|
||||||
|
{
|
||||||
|
return _meta_data(dev, fb, fb_dumb, fb_cmd, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static bool dumb_gem(struct drm_client_dev const * const dev,
|
||||||
|
struct drm_framebuffer const * const fb,
|
||||||
|
struct gem_dumb ** gem_dumb) /* out */
|
||||||
|
{
|
||||||
|
return _meta_data(dev, fb, NULL, NULL, gem_dumb);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void destroy_fb(struct drm_client_dev * const dev,
|
||||||
|
struct drm_mode_create_dumb * const gem_dumb,
|
||||||
|
struct drm_mode_fb_cmd2 * const dumb_fb)
|
||||||
|
{
|
||||||
|
int result = drm_mode_rmfb(dev->dev, dumb_fb->fb_id, dev->file);
|
||||||
|
|
||||||
|
if (result) {
|
||||||
|
drm_err(dev->dev, "%s: failed to remove framebuffer %d\n",
|
||||||
|
__func__, result);
|
||||||
|
}
|
||||||
|
|
||||||
|
result = drm_mode_destroy_dumb(dev->dev, gem_dumb->handle, dev->file);
|
||||||
|
|
||||||
|
if (result) {
|
||||||
|
drm_err(dev->dev, "%s: failed to destroy framebuffer %d\n",
|
||||||
|
__func__, result);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* frees the entry in _meta_data allocator */
|
||||||
|
memset(gem_dumb, 0, sizeof(*gem_dumb));
|
||||||
|
memset(dumb_fb, 0, sizeof(*dumb_fb));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int kernel_register_fb(struct fb_info const * const fb_info,
|
||||||
|
unsigned const width_mm,
|
||||||
|
unsigned const height_mm)
|
||||||
|
{
|
||||||
|
lx_emul_i915_framebuffer_ready(fb_info->node,
|
||||||
|
fb_info->par,
|
||||||
|
fb_info->screen_base,
|
||||||
|
fb_info->screen_size,
|
||||||
|
fb_info->var.xres_virtual,
|
||||||
|
fb_info->var.yres_virtual,
|
||||||
|
fb_info->fix.line_length /
|
||||||
|
(fb_info->var.bits_per_pixel / 8),
|
||||||
|
fb_info->var.yres,
|
||||||
|
width_mm, height_mm);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
struct drm_mode_fb_cmd2 fb_of_screen(struct drm_client_dev * const dev,
|
||||||
|
struct genode_mode const * const conf_mode,
|
||||||
|
struct fb_info * const fb_info,
|
||||||
|
struct drm_mode_fb_cmd2 const * const dumb_fb_mirror,
|
||||||
|
struct drm_display_mode const * const mode,
|
||||||
|
struct drm_framebuffer * fb,
|
||||||
|
struct drm_connector const * const connector)
|
||||||
|
{
|
||||||
|
int err = -EINVAL;
|
||||||
|
struct drm_mode_create_dumb *gem_dumb = NULL;
|
||||||
|
struct drm_mode_fb_cmd2 *fb_cmd = NULL;
|
||||||
|
struct drm_framebuffer *fb_mirror = drm_framebuffer_lookup(dev->dev,
|
||||||
|
dev->file,
|
||||||
|
dumb_fb_mirror->fb_id);
|
||||||
|
|
||||||
|
/* during hotplug the mirrored fb is used for non mirrored connectors temporarily */
|
||||||
|
if (fb && !conf_mode->mirror && fb == fb_mirror) {
|
||||||
|
fb = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!dumb_meta(dev, fb, &gem_dumb, &fb_cmd) || !gem_dumb || !fb_cmd) {
|
||||||
|
struct drm_mode_fb_cmd2 invalid = { };
|
||||||
|
printk("could not create dumb buffer\n");
|
||||||
|
return invalid;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* notify genode side about switch from connector specific fb to mirror fb */
|
||||||
|
if (fb && conf_mode->mirror && fb != fb_mirror) {
|
||||||
|
struct fb_info info = {};
|
||||||
|
|
||||||
|
info.var.bits_per_pixel = 32;
|
||||||
|
info.node = connector->index;
|
||||||
|
info.par = connector->name;
|
||||||
|
|
||||||
|
kernel_register_fb(&info, mode->width_mm, mode->height_mm);
|
||||||
|
|
||||||
|
destroy_fb(dev, gem_dumb, fb_cmd);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fb_mirror)
|
||||||
|
drm_framebuffer_put(fb_mirror);
|
||||||
|
|
||||||
|
fb_info->node = connector->index;
|
||||||
|
|
||||||
|
if (!conf_mode->enabled) {
|
||||||
|
struct drm_mode_fb_cmd2 invalid = { };
|
||||||
|
return invalid;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (conf_mode->mirror)
|
||||||
|
return *dumb_fb_mirror;
|
||||||
|
|
||||||
|
err = check_resize_fb(dev, gem_dumb, fb_cmd,
|
||||||
|
mode->hdisplay, mode->vdisplay);
|
||||||
|
|
||||||
|
if (err) {
|
||||||
|
printk("setting up framebuffer of %ux%u failed - error=%d\n",
|
||||||
|
mode->hdisplay, mode->vdisplay, err);
|
||||||
|
return *dumb_fb_mirror;
|
||||||
|
}
|
||||||
|
|
||||||
|
fb_info->var.xres = mode->hdisplay;
|
||||||
|
fb_info->var.yres = mode->vdisplay;
|
||||||
|
fb_info->var.xres_virtual = mode->hdisplay;
|
||||||
|
fb_info->var.yres_virtual = mode->vdisplay;
|
||||||
|
|
||||||
|
return *fb_cmd;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void close_unused_captures(struct drm_client_dev * const dev)
|
||||||
|
{
|
||||||
|
/* report disconnected connectors to close capture connections */
|
||||||
|
struct drm_connector_list_iter conn_iter;
|
||||||
|
struct drm_connector *connector = NULL;
|
||||||
|
|
||||||
|
drm_connector_list_iter_begin(dev->dev, &conn_iter);
|
||||||
|
drm_client_for_each_connector_iter(connector, &conn_iter) {
|
||||||
|
bool unused = connector->status != connector_status_connected;
|
||||||
|
|
||||||
|
if (!unused) {
|
||||||
|
unused = !connector->state || !connector->state->crtc;
|
||||||
|
|
||||||
|
if (!unused) {
|
||||||
|
struct drm_modeset_acquire_ctx ctx;
|
||||||
|
void * fb = NULL;
|
||||||
|
int err = -1;
|
||||||
|
|
||||||
|
DRM_MODESET_LOCK_ALL_BEGIN(dev->dev, ctx,
|
||||||
|
DRM_MODESET_ACQUIRE_INTERRUPTIBLE,
|
||||||
|
err);
|
||||||
|
|
||||||
|
fb = lookup_framebuffer(connector->state->crtc, &ctx);
|
||||||
|
|
||||||
|
DRM_MODESET_LOCK_ALL_END(dev->dev, ctx, err);
|
||||||
|
|
||||||
|
unused = !fb;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (unused) {
|
||||||
|
struct fb_info fb_info = {};
|
||||||
|
|
||||||
|
fb_info.var.bits_per_pixel = 32;
|
||||||
|
fb_info.node = connector->index;
|
||||||
|
|
||||||
|
kernel_register_fb(&fb_info, 0, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
drm_connector_list_iter_end(&conn_iter);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static bool reconfigure(struct drm_client_dev * const dev)
|
static bool reconfigure(struct drm_client_dev * const dev)
|
||||||
{
|
{
|
||||||
static struct drm_mode_create_dumb gem_dumb = {};
|
static struct drm_mode_create_dumb *gem_mirror = NULL;
|
||||||
|
|
||||||
struct drm_display_mode mode_preferred = {};
|
struct drm_display_mode mode_preferred = {};
|
||||||
struct drm_display_mode mode_minimum = {};
|
struct drm_display_mode mode_minimum = {};
|
||||||
@ -261,23 +540,33 @@ static bool reconfigure(struct drm_client_dev * const dev)
|
|||||||
struct drm_mode_modeinfo user_mode = {};
|
struct drm_mode_modeinfo user_mode = {};
|
||||||
struct drm_display_mode * mode = NULL;
|
struct drm_display_mode * mode = NULL;
|
||||||
struct drm_mode_set * mode_set = NULL;
|
struct drm_mode_set * mode_set = NULL;
|
||||||
struct fb_info report_fb_info = {};
|
struct fb_info info = {};
|
||||||
bool report_fb = false;
|
|
||||||
bool retry = false;
|
bool retry = false;
|
||||||
|
struct {
|
||||||
|
struct fb_info info;
|
||||||
|
unsigned width_mm;
|
||||||
|
unsigned height_mm;
|
||||||
|
bool report;
|
||||||
|
} mirror = { { }, 0, 0, false };
|
||||||
|
|
||||||
if (!dev || !dev->dev)
|
if (!gem_mirror) {
|
||||||
|
/* request storage for gem_mirror and mirror_fb_cmd */
|
||||||
|
dumb_meta(dev, NULL, &gem_mirror, &mirror_fb_cmd);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!dev || !dev->dev || !gem_mirror || !mirror_fb_cmd)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
preferred_mode(dev->dev, &mode_preferred, &mode_minimum);
|
preferred_mirror(dev->dev, &mode_preferred, &mode_minimum);
|
||||||
|
|
||||||
if (!mode_minimum.hdisplay || !mode_minimum.vdisplay) {
|
if (!mode_minimum.hdisplay || !mode_minimum.vdisplay) {
|
||||||
/* no valid modes on any connector on early boot */
|
/* no valid modes on any connector on early boot */
|
||||||
if (!dumb_fb.fb_id)
|
if (!mirror_fb_cmd->fb_id)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
/* valid connectors but all are disabled by config */
|
/* valid connectors but all are disabled by config */
|
||||||
mode_minimum.hdisplay = dumb_fb.width;
|
mode_minimum.hdisplay = mirror_fb_cmd->width;
|
||||||
mode_minimum.vdisplay = dumb_fb.height;
|
mode_minimum.vdisplay = mirror_fb_cmd->height;
|
||||||
mode_preferred = mode_minimum;
|
mode_preferred = mode_minimum;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -288,8 +577,8 @@ static bool reconfigure(struct drm_client_dev * const dev)
|
|||||||
|
|
||||||
{
|
{
|
||||||
int const err = check_resize_fb(dev,
|
int const err = check_resize_fb(dev,
|
||||||
&gem_dumb,
|
gem_mirror,
|
||||||
&dumb_fb,
|
mirror_fb_cmd,
|
||||||
framebuffer.hdisplay,
|
framebuffer.hdisplay,
|
||||||
framebuffer.vdisplay);
|
framebuffer.vdisplay);
|
||||||
|
|
||||||
@ -302,20 +591,19 @@ static bool reconfigure(struct drm_client_dev * const dev)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* without fb handle created by check_resize_fb we can't proceed */
|
/* without fb handle created by check_resize_fb we can't proceed */
|
||||||
if (!dumb_fb.fb_id)
|
if (!mirror_fb_cmd->fb_id)
|
||||||
return retry;
|
return retry;
|
||||||
|
|
||||||
/* prepare fb info for register_framebuffer() evaluated by Genode side */
|
/* prepare fb info for kernel_register_fb() evaluated by Genode side */
|
||||||
report_fb_info.var.xres = framebuffer.hdisplay;
|
info.var.xres = framebuffer.hdisplay;
|
||||||
report_fb_info.var.yres = framebuffer.vdisplay;
|
info.var.yres = framebuffer.vdisplay;
|
||||||
report_fb_info.var.xres_virtual = mode_preferred.hdisplay;
|
info.var.xres_virtual = mode_preferred.hdisplay;
|
||||||
report_fb_info.var.yres_virtual = mode_preferred.vdisplay;
|
info.var.yres_virtual = mode_preferred.vdisplay;
|
||||||
|
|
||||||
drm_client_for_each_modeset(mode_set, dev) {
|
drm_client_for_each_modeset(mode_set, dev) {
|
||||||
struct drm_display_mode * mode_match = NULL;
|
struct drm_display_mode * mode_match = NULL;
|
||||||
unsigned mode_id = 0;
|
unsigned mode_id = 0;
|
||||||
struct drm_connector * connector = NULL;
|
struct drm_connector * connector = NULL;
|
||||||
|
|
||||||
struct genode_mode conf_mode = {};
|
struct genode_mode conf_mode = {};
|
||||||
|
|
||||||
if (!mode_set->connectors || !*mode_set->connectors)
|
if (!mode_set->connectors || !*mode_set->connectors)
|
||||||
@ -337,7 +625,7 @@ static bool reconfigure(struct drm_client_dev * const dev)
|
|||||||
continue;
|
continue;
|
||||||
|
|
||||||
/* allocated framebuffer smaller than mode can't be used */
|
/* allocated framebuffer smaller than mode can't be used */
|
||||||
if (fb_smaller_mode(&report_fb_info, mode))
|
if (fb_smaller_mode(&info, mode))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
/* use mode id if configured and matches exactly */
|
/* use mode id if configured and matches exactly */
|
||||||
@ -374,19 +662,35 @@ static bool reconfigure(struct drm_client_dev * const dev)
|
|||||||
/* apply new mode */
|
/* apply new mode */
|
||||||
mode_id = 0;
|
mode_id = 0;
|
||||||
list_for_each_entry(mode, &connector->modes, head) {
|
list_for_each_entry(mode, &connector->modes, head) {
|
||||||
|
struct fb_info fb_info = info;
|
||||||
int err = -1;
|
int err = -1;
|
||||||
bool no_match = false;
|
bool no_match = false;
|
||||||
|
struct drm_mode_fb_cmd2 fb_cmd = *mirror_fb_cmd;
|
||||||
|
|
||||||
mode_id ++;
|
mode_id ++;
|
||||||
|
|
||||||
if (!mode)
|
if (!mode)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
/* use first mode for non mirrored connector in case of no match */
|
||||||
|
if (!mode_match && !conf_mode.mirror) {
|
||||||
|
|
||||||
|
struct drm_display_mode max = { .hdisplay = conf_mode.max_width,
|
||||||
|
.vdisplay = conf_mode.max_height };
|
||||||
|
|
||||||
|
if (conf_mode.max_width && conf_mode.max_height) {
|
||||||
|
if (conf_larger_mode(&conf_mode, &max))
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
mode_match = mode;
|
||||||
|
}
|
||||||
|
|
||||||
/* no matching mode ? */
|
/* no matching mode ? */
|
||||||
if (!mode_match) {
|
if (!mode_match) {
|
||||||
|
|
||||||
/* fb smaller than mode is denied by drm_mode_setcrtc */
|
/* fb smaller than mode is denied by drm_mode_setcrtc */
|
||||||
if (fb_smaller_mode(&report_fb_info, mode))
|
if (fb_smaller_mode(&fb_info, mode))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
/* use first smaller mode */
|
/* use first smaller mode */
|
||||||
@ -399,19 +703,34 @@ static bool reconfigure(struct drm_client_dev * const dev)
|
|||||||
if (mode_match != mode)
|
if (mode_match != mode)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
/* Genode side prefer to have a name for the connector */
|
||||||
|
fb_info.par = connector->name;
|
||||||
|
|
||||||
|
{
|
||||||
|
struct drm_modeset_acquire_ctx ctx;
|
||||||
|
struct drm_framebuffer *fb = NULL;
|
||||||
|
|
||||||
|
DRM_MODESET_LOCK_ALL_BEGIN(dev->dev, ctx,
|
||||||
|
DRM_MODESET_ACQUIRE_INTERRUPTIBLE,
|
||||||
|
err);
|
||||||
|
|
||||||
|
fb = lookup_framebuffer(mode_set->crtc, &ctx);
|
||||||
|
|
||||||
|
DRM_MODESET_LOCK_ALL_END(dev->dev, ctx, err);
|
||||||
|
|
||||||
|
/* check for mirrored fb or specific one for connector */
|
||||||
|
fb_cmd = fb_of_screen(dev, &conf_mode, &fb_info, mirror_fb_cmd,
|
||||||
|
mode, fb, connector);
|
||||||
|
}
|
||||||
|
|
||||||
/* convert kernel internal mode to user mode expectecd via ioctl */
|
/* convert kernel internal mode to user mode expectecd via ioctl */
|
||||||
drm_mode_convert_to_umode(&user_mode, mode);
|
drm_mode_convert_to_umode(&user_mode, mode);
|
||||||
|
|
||||||
/* assign fb & connector to crtc with specified mode */
|
/* assign fb & connector to crtc with specified mode */
|
||||||
err = user_attach_fb_to_crtc(dev, connector, mode_set->crtc,
|
err = user_attach_fb_to_crtc(dev, connector, mode_set->crtc,
|
||||||
&user_mode, dumb_fb.fb_id,
|
&user_mode, fb_cmd.fb_id,
|
||||||
conf_mode.enabled);
|
conf_mode.enabled);
|
||||||
|
|
||||||
if (err)
|
|
||||||
retry = true;
|
|
||||||
else
|
|
||||||
report_fb = true;
|
|
||||||
|
|
||||||
/* set brightness */
|
/* set brightness */
|
||||||
if (!err && conf_mode.enabled && conf_mode.brightness <= MAX_BRIGHTNESS) {
|
if (!err && conf_mode.enabled && conf_mode.brightness <= MAX_BRIGHTNESS) {
|
||||||
drm_modeset_lock(&dev->dev->mode_config.connection_mutex, NULL);
|
drm_modeset_lock(&dev->dev->mode_config.connection_mutex, NULL);
|
||||||
@ -420,13 +739,25 @@ static bool reconfigure(struct drm_client_dev * const dev)
|
|||||||
drm_modeset_unlock(&dev->dev->mode_config.connection_mutex);
|
drm_modeset_unlock(&dev->dev->mode_config.connection_mutex);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!retry)
|
||||||
|
retry = !!err;
|
||||||
|
|
||||||
|
if (!err && conf_mode.mirror && !mirror.report) {
|
||||||
|
/* use fb_info of first mirrored screen */
|
||||||
|
mirror.report = true;
|
||||||
|
mirror.width_mm = mode->width_mm;
|
||||||
|
mirror.height_mm = mode->height_mm;
|
||||||
|
mirror.info = fb_info;
|
||||||
|
}
|
||||||
|
|
||||||
/* diagnostics */
|
/* diagnostics */
|
||||||
printk("%10s: %s name='%9s' id=%u%s mode=%4ux%4u@%u%s fb=%4ux%4u%s",
|
printk("%10s: %s name='%9s' id=%u%s%s mode=%4ux%4u@%u%s fb=%4ux%4u%s",
|
||||||
connector->name ? connector->name : "unnamed",
|
connector->name ? connector->name : "unnamed",
|
||||||
conf_mode.enabled ? " enable" : "disable",
|
conf_mode.enabled ? " enable" : "disable",
|
||||||
mode->name ? mode->name : "noname",
|
mode->name ? mode->name : "noname",
|
||||||
mode_id, mode_id < 10 ? " " : "", mode->hdisplay,
|
mode_id, mode_id < 10 ? " " : "",
|
||||||
mode->vdisplay, drm_mode_vrefresh(mode),
|
conf_mode.mirror ? " mirror " : " discrete",
|
||||||
|
mode->hdisplay, mode->vdisplay, drm_mode_vrefresh(mode),
|
||||||
drm_mode_vrefresh(mode) < 100 ? " ": "",
|
drm_mode_vrefresh(mode) < 100 ? " ": "",
|
||||||
framebuffer.hdisplay, framebuffer.vdisplay,
|
framebuffer.hdisplay, framebuffer.vdisplay,
|
||||||
(err || no_match) ? "" : "\n");
|
(err || no_match) ? "" : "\n");
|
||||||
@ -438,12 +769,21 @@ static bool reconfigure(struct drm_client_dev * const dev)
|
|||||||
if (err)
|
if (err)
|
||||||
printk(" - failed, error=%d\n", err);
|
printk(" - failed, error=%d\n", err);
|
||||||
|
|
||||||
|
if (!err && !conf_mode.mirror)
|
||||||
|
user_register_fb(dev, &fb_info, &fb_cmd,
|
||||||
|
mode->width_mm, mode->height_mm);
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (report_fb)
|
if (mirror.report) {
|
||||||
user_register_fb(dev, &report_fb_info, &dumb_fb);
|
mirror.info.par = "mirror_capture";
|
||||||
|
user_register_fb(dev, &mirror.info, mirror_fb_cmd, mirror.width_mm,
|
||||||
|
mirror.height_mm);
|
||||||
|
}
|
||||||
|
|
||||||
|
close_unused_captures(dev);
|
||||||
|
|
||||||
return retry;
|
return retry;
|
||||||
}
|
}
|
||||||
@ -474,9 +814,8 @@ static int configure_connectors(void * data)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void framebuffer_dirty(void)
|
static void mark_framebuffer_dirty(struct drm_framebuffer * const fb)
|
||||||
{
|
{
|
||||||
struct drm_framebuffer *fb = NULL;
|
|
||||||
struct drm_clip_rect *clips = NULL;
|
struct drm_clip_rect *clips = NULL;
|
||||||
struct drm_mode_fb_dirty_cmd r = { };
|
struct drm_mode_fb_dirty_cmd r = { };
|
||||||
|
|
||||||
@ -484,12 +823,9 @@ void framebuffer_dirty(void)
|
|||||||
int num_clips = 0;
|
int num_clips = 0;
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
|
|
||||||
if (!dev_client || !dumb_fb.fb_id)
|
if (!dev_client)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
fb = drm_framebuffer_lookup(dev_client->dev, dev_client->file,
|
|
||||||
dumb_fb.fb_id);
|
|
||||||
|
|
||||||
if (!fb || !fb->funcs || !fb->funcs->dirty)
|
if (!fb || !fb->funcs || !fb->funcs->dirty)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
@ -504,9 +840,37 @@ void framebuffer_dirty(void)
|
|||||||
static int update_content(void *)
|
static int update_content(void *)
|
||||||
{
|
{
|
||||||
while (true) {
|
while (true) {
|
||||||
|
struct drm_connector_list_iter conn_iter;
|
||||||
|
struct drm_connector *connector = NULL;
|
||||||
|
struct drm_device const *dev = dev_client->dev;
|
||||||
|
|
||||||
if (lx_emul_i915_blit())
|
drm_connector_list_iter_begin(dev, &conn_iter);
|
||||||
framebuffer_dirty();
|
drm_client_for_each_connector_iter(connector, &conn_iter) {
|
||||||
|
struct drm_modeset_acquire_ctx ctx;
|
||||||
|
struct drm_framebuffer *fb = NULL;
|
||||||
|
int err = -1;
|
||||||
|
|
||||||
|
if (connector->status != connector_status_connected)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (!lx_emul_i915_blit(connector->index))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (!connector->state || !connector->state->crtc)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
DRM_MODESET_LOCK_ALL_BEGIN(dev, ctx,
|
||||||
|
DRM_MODESET_ACQUIRE_INTERRUPTIBLE,
|
||||||
|
err);
|
||||||
|
|
||||||
|
fb = lookup_framebuffer(connector->state->crtc, &ctx);
|
||||||
|
|
||||||
|
DRM_MODESET_LOCK_ALL_END(dev, ctx, err);
|
||||||
|
|
||||||
|
if (fb)
|
||||||
|
mark_framebuffer_dirty(fb);
|
||||||
|
}
|
||||||
|
drm_connector_list_iter_end(&conn_iter);
|
||||||
|
|
||||||
/* schedule_timeout(jiffes) or hrtimer or msleep */
|
/* schedule_timeout(jiffes) or hrtimer or msleep */
|
||||||
msleep(20);
|
msleep(20);
|
||||||
@ -523,12 +887,42 @@ void lx_user_init(void)
|
|||||||
int pid2 = kernel_thread(update_content, NULL, "lx_update",
|
int pid2 = kernel_thread(update_content, NULL, "lx_update",
|
||||||
CLONE_FS | CLONE_FILES);
|
CLONE_FS | CLONE_FILES);
|
||||||
|
|
||||||
lx_user_task = find_task_by_pid_ns(pid, NULL);;
|
lx_user_task = find_task_by_pid_ns(pid , NULL);
|
||||||
lx_update_task = find_task_by_pid_ns(pid2, NULL);;
|
lx_update_task = find_task_by_pid_ns(pid2, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void lx_emul_i915_report(void * genode_data)
|
static bool mirrored_fb(struct drm_client_dev * client,
|
||||||
|
struct drm_crtc const * const crtc)
|
||||||
|
{
|
||||||
|
struct drm_modeset_acquire_ctx ctx;
|
||||||
|
struct drm_framebuffer const * fb = NULL;
|
||||||
|
struct drm_framebuffer const * fb_mirror = NULL;
|
||||||
|
int result = -1;
|
||||||
|
|
||||||
|
if (mirror_fb_cmd && mirror_fb_cmd->fb_id)
|
||||||
|
fb_mirror = drm_framebuffer_lookup(client->dev, client->file,
|
||||||
|
mirror_fb_cmd->fb_id);
|
||||||
|
|
||||||
|
if (!fb_mirror || !crtc)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (fb_mirror)
|
||||||
|
drm_framebuffer_put(fb_mirror);
|
||||||
|
|
||||||
|
DRM_MODESET_LOCK_ALL_BEGIN(client->dev, ctx,
|
||||||
|
DRM_MODESET_ACQUIRE_INTERRUPTIBLE,
|
||||||
|
result);
|
||||||
|
|
||||||
|
fb = lookup_framebuffer(crtc, &ctx);
|
||||||
|
|
||||||
|
DRM_MODESET_LOCK_ALL_END(client->dev, ctx, result);
|
||||||
|
|
||||||
|
return fb && fb_mirror == fb;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void _report_connectors(void * genode_data, bool const discrete)
|
||||||
{
|
{
|
||||||
struct drm_connector_list_iter conn_iter;
|
struct drm_connector_list_iter conn_iter;
|
||||||
|
|
||||||
@ -537,6 +931,22 @@ void lx_emul_i915_report(void * genode_data)
|
|||||||
|
|
||||||
drm_connector_list_iter_begin(dev, &conn_iter);
|
drm_connector_list_iter_begin(dev, &conn_iter);
|
||||||
drm_client_for_each_connector_iter(connector, &conn_iter) {
|
drm_client_for_each_connector_iter(connector, &conn_iter) {
|
||||||
|
|
||||||
|
bool mirror = connector->state && connector->state->crtc &&
|
||||||
|
mirrored_fb(dev_client, connector->state->crtc);
|
||||||
|
|
||||||
|
if (!mirror && (!connector->state || !connector->state->crtc)) {
|
||||||
|
struct genode_mode conf_mode = { };
|
||||||
|
|
||||||
|
/* check for connector configuration on Genode side */
|
||||||
|
lx_emul_i915_connector_config(connector->name, &conf_mode);
|
||||||
|
|
||||||
|
mirror = conf_mode.mirror;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((discrete && mirror) || (!discrete && !mirror))
|
||||||
|
continue;
|
||||||
|
|
||||||
lx_emul_i915_report_connector(connector, genode_data,
|
lx_emul_i915_report_connector(connector, genode_data,
|
||||||
connector->name,
|
connector->name,
|
||||||
connector->status != connector_status_disconnected,
|
connector->status != connector_status_disconnected,
|
||||||
@ -548,6 +958,18 @@ void lx_emul_i915_report(void * genode_data)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void lx_emul_i915_report_discrete(void * genode_data)
|
||||||
|
{
|
||||||
|
_report_connectors(genode_data, true /* discrete */);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void lx_emul_i915_report_non_discrete(void * genode_data)
|
||||||
|
{
|
||||||
|
_report_connectors(genode_data, false /* non discrete */);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void lx_emul_i915_iterate_modes(void * lx_data, void * genode_data)
|
void lx_emul_i915_iterate_modes(void * lx_data, void * genode_data)
|
||||||
{
|
{
|
||||||
struct drm_connector *connector = lx_data;
|
struct drm_connector *connector = lx_data;
|
||||||
@ -582,6 +1004,8 @@ void lx_emul_i915_iterate_modes(void * lx_data, void * genode_data)
|
|||||||
bool const inuse = connector->state && connector->state->crtc &&
|
bool const inuse = connector->state && connector->state->crtc &&
|
||||||
connector->state->crtc->state &&
|
connector->state->crtc->state &&
|
||||||
drm_mode_equal(&connector->state->crtc->state->mode, mode);
|
drm_mode_equal(&connector->state->crtc->state->mode, mode);
|
||||||
|
bool const mirror = connector->state && connector->state->crtc &&
|
||||||
|
mirrored_fb(dev_client, connector->state->crtc);
|
||||||
|
|
||||||
struct genode_mode conf_mode = {
|
struct genode_mode conf_mode = {
|
||||||
.width = mode->hdisplay,
|
.width = mode->hdisplay,
|
||||||
@ -591,6 +1015,7 @@ void lx_emul_i915_iterate_modes(void * lx_data, void * genode_data)
|
|||||||
.preferred = mode->type & (DRM_MODE_TYPE_PREFERRED |
|
.preferred = mode->type & (DRM_MODE_TYPE_PREFERRED |
|
||||||
DRM_MODE_TYPE_DEFAULT),
|
DRM_MODE_TYPE_DEFAULT),
|
||||||
.inuse = inuse,
|
.inuse = inuse,
|
||||||
|
.mirror = mirror,
|
||||||
.hz = drm_mode_vrefresh(mode),
|
.hz = drm_mode_vrefresh(mode),
|
||||||
.id = mode_id,
|
.id = mode_id,
|
||||||
.enabled = !max_mode ||
|
.enabled = !max_mode ||
|
||||||
@ -623,11 +1048,12 @@ void i915_switcheroo_unregister(struct drm_i915_private *i915)
|
|||||||
static int fb_client_hotplug(struct drm_client_dev *client)
|
static int fb_client_hotplug(struct drm_client_dev *client)
|
||||||
{
|
{
|
||||||
struct drm_mode_set *modeset = NULL;
|
struct drm_mode_set *modeset = NULL;
|
||||||
struct drm_framebuffer *fb = NULL;
|
struct drm_framebuffer *fb_mirror = NULL;
|
||||||
int result = -EINVAL;
|
int result = -EINVAL;
|
||||||
|
|
||||||
if (dumb_fb.fb_id)
|
if (mirror_fb_cmd && mirror_fb_cmd->fb_id)
|
||||||
fb = drm_framebuffer_lookup(client->dev, client->file, dumb_fb.fb_id);
|
fb_mirror = drm_framebuffer_lookup(client->dev, client->file,
|
||||||
|
mirror_fb_cmd->fb_id);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Triggers set up of display pipelines for connectors and
|
* Triggers set up of display pipelines for connectors and
|
||||||
@ -644,22 +1070,75 @@ static int fb_client_hotplug(struct drm_client_dev *client)
|
|||||||
* (Re-)assign framebuffer to modeset (lost due to modeset_probe) and
|
* (Re-)assign framebuffer to modeset (lost due to modeset_probe) and
|
||||||
* commit the change.
|
* commit the change.
|
||||||
*/
|
*/
|
||||||
if (fb) {
|
if (fb_mirror) {
|
||||||
bool mode_too_large = false;
|
struct drm_framebuffer * free_fbs[MAX_FBS] = { };
|
||||||
|
struct drm_modeset_acquire_ctx ctx;
|
||||||
|
|
||||||
|
bool mode_too_large = false;
|
||||||
|
unsigned fb_count = 0;
|
||||||
|
|
||||||
|
DRM_MODESET_LOCK_ALL_BEGIN(client->dev, ctx,
|
||||||
|
DRM_MODESET_ACQUIRE_INTERRUPTIBLE,
|
||||||
|
result);
|
||||||
mutex_lock(&client->modeset_mutex);
|
mutex_lock(&client->modeset_mutex);
|
||||||
drm_client_for_each_modeset(modeset, client) {
|
drm_client_for_each_modeset(modeset, client) {
|
||||||
if (!modeset || !modeset->num_connectors)
|
struct drm_connector *connector = NULL;
|
||||||
|
struct drm_framebuffer *fb = NULL;
|
||||||
|
|
||||||
|
if (!modeset)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (!mode_too_large && modeset->mode &&
|
if (modeset->crtc)
|
||||||
|
fb = lookup_framebuffer(modeset->crtc, &ctx);
|
||||||
|
|
||||||
|
if (!mode_too_large && fb && modeset->mode &&
|
||||||
(modeset->mode->hdisplay > fb->width ||
|
(modeset->mode->hdisplay > fb->width ||
|
||||||
modeset->mode->vdisplay > fb->height))
|
modeset->mode->vdisplay > fb->height))
|
||||||
mode_too_large = true;
|
mode_too_large = true;
|
||||||
|
|
||||||
modeset->fb = fb;
|
if (!modeset->num_connectors || !modeset->connectors || !*modeset->connectors) {
|
||||||
|
|
||||||
|
struct drm_mode_fb_cmd2 *fb_cmd = NULL;
|
||||||
|
struct drm_mode_create_dumb *fb_dumb = NULL;
|
||||||
|
|
||||||
|
if (!fb || fb == fb_mirror)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (!dumb_meta(client, fb, &fb_dumb, &fb_cmd) || !fb_dumb || !fb_cmd)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (fb_count >= MAX_FBS) {
|
||||||
|
printk("leaking framebuffer memory\n");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
free_fbs[fb_count++] = fb;
|
||||||
|
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* set connector */
|
||||||
|
connector = *modeset->connectors;
|
||||||
|
|
||||||
|
modeset->fb = fb ? fb : fb_mirror;
|
||||||
}
|
}
|
||||||
mutex_unlock(&client->modeset_mutex);
|
mutex_unlock(&client->modeset_mutex);
|
||||||
|
DRM_MODESET_LOCK_ALL_END(client->dev, ctx, result);
|
||||||
|
|
||||||
|
for (unsigned i = 0; i < fb_count; i++) {
|
||||||
|
struct drm_mode_fb_cmd2 *fb_cmd = NULL;
|
||||||
|
struct drm_mode_create_dumb *fb_dumb = NULL;
|
||||||
|
|
||||||
|
if (!free_fbs[i])
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (!dumb_meta(client, free_fbs[i], &fb_dumb, &fb_cmd) || !fb_dumb || !fb_cmd)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
destroy_fb(client, fb_dumb, fb_cmd);
|
||||||
|
|
||||||
|
free_fbs[i] = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
/* triggers disablement of encoders attached to disconnected ports */
|
/* triggers disablement of encoders attached to disconnected ports */
|
||||||
result = drm_client_modeset_commit(client);
|
result = drm_client_modeset_commit(client);
|
||||||
@ -673,8 +1152,8 @@ static int fb_client_hotplug(struct drm_client_dev *client)
|
|||||||
/* notify Genode side */
|
/* notify Genode side */
|
||||||
lx_emul_i915_hotplug_connector();
|
lx_emul_i915_hotplug_connector();
|
||||||
|
|
||||||
if (fb)
|
if (fb_mirror)
|
||||||
drm_framebuffer_put(fb);
|
drm_framebuffer_put(fb_mirror);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -755,15 +1234,16 @@ int user_attach_fb_to_crtc(struct drm_client_dev * const dev,
|
|||||||
|
|
||||||
static int user_register_fb(struct drm_client_dev const * const dev,
|
static int user_register_fb(struct drm_client_dev const * const dev,
|
||||||
struct fb_info * const info,
|
struct fb_info * const info,
|
||||||
struct drm_mode_fb_cmd2 const * const dumb_fb)
|
struct drm_mode_fb_cmd2 const * const dumb_fb,
|
||||||
|
unsigned const width_mm,
|
||||||
|
unsigned const height_mm)
|
||||||
{
|
{
|
||||||
intel_wakeref_t wakeref;
|
intel_wakeref_t wakeref;
|
||||||
|
|
||||||
int result = -EINVAL;
|
int result = -EINVAL;
|
||||||
struct i915_gtt_view const view = { .type = I915_GTT_VIEW_NORMAL };
|
struct i915_gtt_view const view = { .type = I915_GTT_VIEW_NORMAL };
|
||||||
static struct i915_vma *vma = NULL;
|
|
||||||
static unsigned long flags = 0;
|
|
||||||
void __iomem *vaddr = NULL;
|
void __iomem *vaddr = NULL;
|
||||||
|
struct gem_dumb *gem_dumb = NULL;
|
||||||
struct drm_i915_private *dev_priv = to_i915(dev->dev);
|
struct drm_i915_private *dev_priv = to_i915(dev->dev);
|
||||||
struct drm_framebuffer *fb = drm_framebuffer_lookup(dev->dev,
|
struct drm_framebuffer *fb = drm_framebuffer_lookup(dev->dev,
|
||||||
dev->file,
|
dev->file,
|
||||||
@ -774,49 +1254,61 @@ static int user_register_fb(struct drm_client_dev const * const dev,
|
|||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
}
|
}
|
||||||
|
|
||||||
wakeref = intel_runtime_pm_get(&dev_priv->runtime_pm);
|
if (!dumb_gem(dev, fb, &gem_dumb) || !gem_dumb) {
|
||||||
|
printk("%s:%u error looking up fb and vma\n", __func__, __LINE__);
|
||||||
if (vma) {
|
return -ENODEV;
|
||||||
intel_unpin_fb_vma(vma, flags);
|
|
||||||
|
|
||||||
vma = NULL;
|
|
||||||
flags = 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (gem_dumb->vma) {
|
||||||
|
intel_unpin_fb_vma(gem_dumb->vma, gem_dumb->flags);
|
||||||
|
|
||||||
|
gem_dumb->vma = NULL;
|
||||||
|
gem_dumb->flags = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
wakeref = intel_runtime_pm_get(&dev_priv->runtime_pm);
|
||||||
|
|
||||||
/* Pin the GGTT vma for our access via info->screen_base.
|
/* Pin the GGTT vma for our access via info->screen_base.
|
||||||
* This also validates that any existing fb inherited from the
|
* This also validates that any existing fb inherited from the
|
||||||
* BIOS is suitable for own access.
|
* BIOS is suitable for own access.
|
||||||
*/
|
*/
|
||||||
vma = intel_pin_and_fence_fb_obj(fb, false /* phys_cursor */,
|
gem_dumb->vma = intel_pin_and_fence_fb_obj(fb, false /* phys_cursor */,
|
||||||
&view, false /* use fences */,
|
&view, false /* use fences */,
|
||||||
&flags);
|
&gem_dumb->flags);
|
||||||
|
|
||||||
if (IS_ERR(vma)) {
|
if (IS_ERR(gem_dumb->vma)) {
|
||||||
intel_runtime_pm_put(&dev_priv->runtime_pm, wakeref);
|
intel_runtime_pm_put(&dev_priv->runtime_pm, wakeref);
|
||||||
|
|
||||||
result = PTR_ERR(vma);
|
result = PTR_ERR(gem_dumb->vma);
|
||||||
|
|
||||||
printk("%s:%u error setting vma %d\n", __func__, __LINE__, result);
|
printk("%s:%u error setting vma %d\n", __func__, __LINE__, result);
|
||||||
|
|
||||||
|
gem_dumb->vma = NULL;
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
vaddr = i915_vma_pin_iomap(vma);
|
vaddr = i915_vma_pin_iomap(gem_dumb->vma);
|
||||||
if (IS_ERR(vaddr)) {
|
if (IS_ERR(vaddr)) {
|
||||||
intel_runtime_pm_put(&dev_priv->runtime_pm, wakeref);
|
intel_runtime_pm_put(&dev_priv->runtime_pm, wakeref);
|
||||||
|
|
||||||
result = PTR_ERR(vaddr);
|
result = PTR_ERR(vaddr);
|
||||||
printk("%s:%u error pin iomap %d\n", __func__, __LINE__, result);
|
printk("%s:%u error pin iomap %d\n", __func__, __LINE__, result);
|
||||||
|
|
||||||
|
intel_unpin_fb_vma(gem_dumb->vma, gem_dumb->flags);
|
||||||
|
gem_dumb->vma = NULL;
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* fill framebuffer info for register_framebuffer */
|
/* fill framebuffer info for kernel_register_fb */
|
||||||
info->screen_base = vaddr;
|
info->screen_base = vaddr;
|
||||||
info->screen_size = vma->size;
|
info->screen_size = gem_dumb->vma->size;
|
||||||
info->fix.line_length = fb->pitches[0];
|
info->fix.line_length = fb->pitches[0];
|
||||||
info->var.bits_per_pixel = drm_format_info_bpp(fb->format, 0);
|
info->var.bits_per_pixel = drm_format_info_bpp(fb->format, 0);
|
||||||
|
|
||||||
intel_runtime_pm_put(&dev_priv->runtime_pm, wakeref);
|
intel_runtime_pm_put(&dev_priv->runtime_pm, wakeref);
|
||||||
|
|
||||||
register_framebuffer(info);
|
kernel_register_fb(info, width_mm, height_mm);
|
||||||
|
|
||||||
if (fb)
|
if (fb)
|
||||||
drm_framebuffer_put(fb);
|
drm_framebuffer_put(fb);
|
||||||
@ -841,20 +1333,7 @@ static int check_resize_fb(struct drm_client_dev * const dev,
|
|||||||
if (gem_dumb->width && gem_dumb->height &&
|
if (gem_dumb->width && gem_dumb->height &&
|
||||||
(gem_dumb->width < width || gem_dumb->height < height)) {
|
(gem_dumb->width < width || gem_dumb->height < height)) {
|
||||||
|
|
||||||
result = drm_mode_rmfb(dev->dev, dumb_fb->fb_id, dev->file);
|
destroy_fb(dev, gem_dumb, dumb_fb);
|
||||||
if (result) {
|
|
||||||
drm_err(dev->dev, "%s: failed to remove framebufer %d\n",
|
|
||||||
__func__, result);
|
|
||||||
}
|
|
||||||
|
|
||||||
result = drm_mode_destroy_dumb(dev->dev, gem_dumb->handle, dev->file);
|
|
||||||
if (result) {
|
|
||||||
drm_err(dev->dev, "%s: failed to destroy framebuffer %d\n",
|
|
||||||
__func__, result);
|
|
||||||
}
|
|
||||||
|
|
||||||
memset(gem_dumb, 0, sizeof(*gem_dumb));
|
|
||||||
memset(dumb_fb, 0, sizeof(*dumb_fb));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* allocate dumb framebuffer, on success a GEM object handle is returned */
|
/* allocate dumb framebuffer, on success a GEM object handle is returned */
|
||||||
|
@ -20,7 +20,6 @@
|
|||||||
|
|
||||||
/* emulation includes */
|
/* emulation includes */
|
||||||
#include <lx_emul/init.h>
|
#include <lx_emul/init.h>
|
||||||
#include <lx_emul/fb.h>
|
|
||||||
#include <lx_emul/task.h>
|
#include <lx_emul/task.h>
|
||||||
#include <lx_kit/env.h>
|
#include <lx_kit/env.h>
|
||||||
#include <lx_kit/init.h>
|
#include <lx_kit/init.h>
|
||||||
@ -45,6 +44,7 @@ struct Framebuffer::Driver
|
|||||||
using Attached_rom_system = Constructible<Attached_rom_dataspace>;
|
using Attached_rom_system = Constructible<Attached_rom_dataspace>;
|
||||||
|
|
||||||
Env &env;
|
Env &env;
|
||||||
|
Heap heap { env.ram(), env.rm() };
|
||||||
Attached_rom_dataspace config { env, "config" };
|
Attached_rom_dataspace config { env, "config" };
|
||||||
Attached_rom_system system { };
|
Attached_rom_system system { };
|
||||||
Expanding_reporter reporter { env, "connectors", "connectors" };
|
Expanding_reporter reporter { env, "connectors", "connectors" };
|
||||||
@ -61,67 +61,88 @@ struct Framebuffer::Driver
|
|||||||
bool disable_all { false };
|
bool disable_all { false };
|
||||||
bool disable_report_once { false };
|
bool disable_report_once { false };
|
||||||
|
|
||||||
class Fb
|
Capture::Connection::Label merge_label { "mirror" };
|
||||||
{
|
|
||||||
private:
|
|
||||||
|
|
||||||
Capture::Connection _capture;
|
struct Connector {
|
||||||
Capture::Area const _size;
|
using Space = Id_space<Connector>;
|
||||||
Capture::Area const _size_phys;
|
using Id = Space::Id;
|
||||||
Capture::Connection::Screen _captured_screen;
|
|
||||||
void * _base;
|
|
||||||
|
|
||||||
/*
|
Space::Element id_element;
|
||||||
* Non_copyable
|
|
||||||
*/
|
|
||||||
Fb(const Fb&);
|
|
||||||
Fb & operator=(const Fb&);
|
|
||||||
|
|
||||||
public:
|
Connector(Space &space, Id id) : id_element(*this, space, id) { }
|
||||||
|
|
||||||
bool paint()
|
addr_t base { };
|
||||||
|
Capture::Area size { };
|
||||||
|
Capture::Area size_phys { };
|
||||||
|
Capture::Area size_mm { };
|
||||||
|
|
||||||
|
Constructible<Capture::Connection> capture { };
|
||||||
|
Constructible<Capture::Connection::Screen> screen { };
|
||||||
|
};
|
||||||
|
|
||||||
|
Connector::Space ids { };
|
||||||
|
|
||||||
|
bool capture(Connector::Space &ids, Connector::Id const &id)
|
||||||
{
|
{
|
||||||
using Pixel = Capture::Pixel;
|
using Pixel = Capture::Pixel;
|
||||||
|
|
||||||
bool dirty = false;
|
bool dirty = false;
|
||||||
|
|
||||||
_captured_screen.with_texture([&] (Texture<Pixel> const &texture) {
|
ids.apply<Connector>(id, [&](Connector &connector) {
|
||||||
|
|
||||||
auto const affected = _capture.capture_at(Capture::Point(0, 0));
|
if (!connector.capture.constructed() ||
|
||||||
|
!connector.screen.constructed())
|
||||||
|
return;
|
||||||
|
|
||||||
|
connector.screen->with_texture([&] (Texture<Pixel> const &texture) {
|
||||||
|
|
||||||
|
auto const affected = connector.capture->capture_at({ 0, 0});
|
||||||
|
|
||||||
affected.for_each_rect([&] (Capture::Rect const rect) {
|
affected.for_each_rect([&] (Capture::Rect const rect) {
|
||||||
|
|
||||||
Surface<Pixel> surface((Pixel*)_base, _size_phys);
|
Surface<Pixel> surface((Pixel*)connector.base,
|
||||||
|
connector.size_phys);
|
||||||
|
|
||||||
surface.clip(rect);
|
surface.clip(rect);
|
||||||
|
|
||||||
Blit_painter::paint(surface, texture, Capture::Point(0, 0));
|
Blit_painter::paint(surface, texture, Capture::Point(0, 0));
|
||||||
|
|
||||||
dirty = true;
|
dirty = true;
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
}, [&](){ /* unknown connector id */ });
|
||||||
|
|
||||||
return dirty;
|
return dirty;
|
||||||
}
|
}
|
||||||
|
|
||||||
Fb(Env & env, void * base, Capture::Area size,
|
bool update(Connector &conn, addr_t const base,
|
||||||
Capture::Area size_phys)
|
Capture::Area &size, Capture::Area &size_phys,
|
||||||
:
|
Capture::Area const mm,
|
||||||
_capture(env),
|
auto const &label)
|
||||||
_size(size),
|
|
||||||
_size_phys(size_phys),
|
|
||||||
_captured_screen(_capture, env.rm(), { .px = _size, .mm = { } }),
|
|
||||||
_base(base) {}
|
|
||||||
|
|
||||||
bool same_setup(void * base, Capture::Area &size,
|
|
||||||
Capture::Area &size_phys)
|
|
||||||
{
|
{
|
||||||
return ((base == _base) && (size == _size) &&
|
bool same = (base == conn.base) &&
|
||||||
(size_phys == _size_phys));
|
(size == conn.size) &&
|
||||||
}
|
(size_phys == conn.size_phys) &&
|
||||||
};
|
(mm == conn.size_mm);
|
||||||
|
|
||||||
Constructible<Fb> fb {};
|
if (same)
|
||||||
|
return same;
|
||||||
|
|
||||||
|
conn.base = base;
|
||||||
|
conn.size = size;
|
||||||
|
conn.size_phys = size_phys;
|
||||||
|
conn.size_mm = mm;
|
||||||
|
|
||||||
|
if (conn.size.valid()) {
|
||||||
|
Capture::Connection::Screen::Attr attr = { .px = conn.size, .mm = conn.size_mm };
|
||||||
|
conn.capture.construct(env, label);
|
||||||
|
conn.screen .construct(*conn.capture, env.rm(), attr);
|
||||||
|
} else {
|
||||||
|
conn.screen .destruct();
|
||||||
|
conn.capture.destruct();
|
||||||
|
}
|
||||||
|
|
||||||
|
return same;
|
||||||
|
}
|
||||||
|
|
||||||
void config_update();
|
void config_update();
|
||||||
void system_update();
|
void system_update();
|
||||||
@ -178,8 +199,7 @@ struct Framebuffer::Driver
|
|||||||
return apply_config;
|
return apply_config;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
void with_max_enforcement(auto const &fn) const
|
||||||
void with_max_enforcement(T const &fn) const
|
|
||||||
{
|
{
|
||||||
unsigned max_width = config.xml().attribute_value("max_width", 0u);
|
unsigned max_width = config.xml().attribute_value("max_width", 0u);
|
||||||
unsigned max_height = config.xml().attribute_value("max_height",0u);
|
unsigned max_height = config.xml().attribute_value("max_height",0u);
|
||||||
@ -188,11 +208,10 @@ struct Framebuffer::Driver
|
|||||||
fn(max_width, max_height);
|
fn(max_width, max_height);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
void with_force(auto const &node, auto const &fn) const
|
||||||
void with_force(T const &fn) const
|
|
||||||
{
|
{
|
||||||
unsigned force_width = config.xml().attribute_value("force_width", 0u);
|
unsigned force_width = node.attribute_value("width", 0u);
|
||||||
unsigned force_height = config.xml().attribute_value("force_height", 0u);
|
unsigned force_height = node.attribute_value("height", 0u);
|
||||||
|
|
||||||
if (force_width && force_height)
|
if (force_width && force_height)
|
||||||
fn(force_width, force_height);
|
fn(force_width, force_height);
|
||||||
@ -247,6 +266,11 @@ void Framebuffer::Driver::config_update()
|
|||||||
if (!config.valid() || !lx_user_task)
|
if (!config.valid() || !lx_user_task)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
config.xml().with_optional_sub_node("merge", [&](auto const &node) {
|
||||||
|
if (node.has_attribute("name"))
|
||||||
|
merge_label = node.attribute_value("name", String<160>(merge_label));
|
||||||
|
});
|
||||||
|
|
||||||
if (config.xml().attribute_value("system", false)) {
|
if (config.xml().attribute_value("system", false)) {
|
||||||
system.construct(Lx_kit::env().env, "system");
|
system.construct(Lx_kit::env().env, "system");
|
||||||
system->sigh(system_handler);
|
system->sigh(system_handler);
|
||||||
@ -310,12 +334,18 @@ void Framebuffer::Driver::generate_report()
|
|||||||
xml.attribute("max_height", height);
|
xml.attribute("max_height", height);
|
||||||
});
|
});
|
||||||
|
|
||||||
with_force([&](unsigned width, unsigned height) {
|
lx_emul_i915_report_discrete(&xml);
|
||||||
xml.attribute("force_width", width);
|
|
||||||
xml.attribute("force_height", height);
|
xml.node("merge", [&] () {
|
||||||
|
node.with_optional_sub_node("merge", [&](auto const &merge) {
|
||||||
|
with_force(merge, [&](unsigned width, unsigned height) {
|
||||||
|
xml.attribute("width", width);
|
||||||
|
xml.attribute("height", height);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
lx_emul_i915_report(&xml);
|
lx_emul_i915_report_non_discrete(&xml);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -326,38 +356,60 @@ void Framebuffer::Driver::generate_report()
|
|||||||
void Framebuffer::Driver::lookup_config(char const * const name,
|
void Framebuffer::Driver::lookup_config(char const * const name,
|
||||||
struct genode_mode &mode)
|
struct genode_mode &mode)
|
||||||
{
|
{
|
||||||
|
bool mirror_node = false;
|
||||||
|
|
||||||
/* default settings, possibly overridden by explicit configuration below */
|
/* default settings, possibly overridden by explicit configuration below */
|
||||||
mode.enabled = !disable_all;
|
mode.enabled = !disable_all;
|
||||||
mode.brightness = 70 /* percent */;
|
mode.brightness = 70; /* percent */
|
||||||
|
mode.mirror = false;
|
||||||
|
|
||||||
if (!config.valid() || disable_all)
|
if (!config.valid() || disable_all)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
/* iterate independently of force* ever to get brightness and hz */
|
auto for_each_node = [&](auto const &node, bool const mirror){
|
||||||
config.xml().for_each_sub_node("connector", [&] (Xml_node &node) {
|
|
||||||
using Name = String<32>;
|
using Name = String<32>;
|
||||||
Name const con_policy = node.attribute_value("name", Name());
|
Name const con_policy = node.attribute_value("name", Name());
|
||||||
if (con_policy != name)
|
if (con_policy != name)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
mode.mirror = mirror;
|
||||||
mode.enabled = node.attribute_value("enabled", true);
|
mode.enabled = node.attribute_value("enabled", true);
|
||||||
|
|
||||||
if (!mode.enabled)
|
if (!mode.enabled)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
mode.brightness = node.attribute_value("brightness",
|
|
||||||
unsigned(MAX_BRIGHTNESS + 1));
|
|
||||||
|
|
||||||
mode.width = node.attribute_value("width" , 0U);
|
mode.width = node.attribute_value("width" , 0U);
|
||||||
mode.height = node.attribute_value("height" , 0U);
|
mode.height = node.attribute_value("height" , 0U);
|
||||||
mode.hz = node.attribute_value("hz" , 0U);
|
mode.hz = node.attribute_value("hz" , 0U);
|
||||||
mode.id = node.attribute_value("mode_id", 0U);
|
mode.id = node.attribute_value("mode_id", 0U);
|
||||||
|
mode.brightness = node.attribute_value("brightness",
|
||||||
|
unsigned(MAX_BRIGHTNESS + 1));
|
||||||
|
};
|
||||||
|
|
||||||
|
/* lookup config of discrete connectors */
|
||||||
|
config.xml().for_each_sub_node("connector", [&] (Xml_node const &conn) {
|
||||||
|
for_each_node(conn, false);
|
||||||
});
|
});
|
||||||
|
|
||||||
with_force([&](unsigned const width, unsigned const height) {
|
/* lookup config of mirrored connectors */
|
||||||
|
config.xml().for_each_sub_node("merge", [&] (Xml_node const &merge) {
|
||||||
|
if (mirror_node) {
|
||||||
|
error("only one mirror node supported");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
merge.for_each_sub_node("connector", [&] (Xml_node const &conn) {
|
||||||
|
for_each_node(conn, true);
|
||||||
|
});
|
||||||
|
|
||||||
|
with_force(merge, [&](unsigned const width, unsigned const height) {
|
||||||
mode.force_width = width;
|
mode.force_width = width;
|
||||||
mode.force_height = height;
|
mode.force_height = height;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
mirror_node = true;
|
||||||
|
});
|
||||||
|
|
||||||
with_max_enforcement([&](unsigned const width, unsigned const height) {
|
with_max_enforcement([&](unsigned const width, unsigned const height) {
|
||||||
mode.max_width = width;
|
mode.max_width = width;
|
||||||
mode.max_height = height;
|
mode.max_height = height;
|
||||||
@ -372,41 +424,72 @@ unsigned long long driver_max_framebuffer_memory(void)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
void lx_emul_i915_framebuffer_ready(unsigned const connector_id,
|
||||||
* Can be called already as side-effect of `lx_emul_start_kernel`,
|
char const * const conn_name,
|
||||||
* that's why the Driver object needs to be constructed already here.
|
void * const base,
|
||||||
*/
|
unsigned long,
|
||||||
extern "C" void lx_emul_framebuffer_ready(void * base, unsigned long,
|
unsigned const xres,
|
||||||
unsigned xres, unsigned yres,
|
unsigned const yres,
|
||||||
unsigned phys_width,
|
unsigned const phys_width,
|
||||||
unsigned phys_height)
|
unsigned const phys_height,
|
||||||
|
unsigned const mm_width,
|
||||||
|
unsigned const mm_height)
|
||||||
{
|
{
|
||||||
auto &env = Lx_kit::env().env;
|
auto &env = Lx_kit::env().env;
|
||||||
auto &drv = driver(env);
|
auto &drv = driver(env);
|
||||||
auto &fb = drv.fb;
|
|
||||||
|
using namespace Genode;
|
||||||
|
|
||||||
|
typedef Framebuffer::Driver::Connector Connector;
|
||||||
|
|
||||||
|
auto const id = Connector::Id { connector_id };
|
||||||
|
|
||||||
|
/* allocate new id for new connector */
|
||||||
|
drv.ids.apply<Connector>(id, [&](Connector &) { /* known id */ }, [&](){
|
||||||
|
/* ignore unused connector - don't need a object for it */
|
||||||
|
if (!base)
|
||||||
|
return;
|
||||||
|
|
||||||
|
new (drv.heap) Connector (drv.ids, id);
|
||||||
|
});
|
||||||
|
|
||||||
|
drv.ids.apply<Connector>(id, [&](Connector &conn) {
|
||||||
|
|
||||||
Capture::Area area (xres, yres);
|
Capture::Area area (xres, yres);
|
||||||
Capture::Area area_phys(phys_width, phys_height);
|
Capture::Area area_phys(phys_width, phys_height);
|
||||||
|
|
||||||
if (fb.constructed()) {
|
auto const prev_size = conn.size;
|
||||||
if (fb->same_setup(base, area, area_phys))
|
|
||||||
|
auto label = !conn_name
|
||||||
|
? Capture::Connection::Label(conn.id_element)
|
||||||
|
: Capture::Connection::Label(conn_name) == "mirror_capture"
|
||||||
|
? drv.merge_label
|
||||||
|
: Capture::Connection::Label(conn_name);
|
||||||
|
|
||||||
|
bool const same = drv.update(conn, Genode::addr_t(base), area,
|
||||||
|
area_phys, { mm_width, mm_height}, label);
|
||||||
|
|
||||||
|
if (same)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
fb.destruct();
|
|
||||||
}
|
|
||||||
|
|
||||||
/* clear artefacts */
|
/* clear artefacts */
|
||||||
if (area != area_phys)
|
if (base && (area != area_phys))
|
||||||
Genode::memset(base, 0, area_phys.count() * 4);
|
Genode::memset(base, 0, area_phys.count() * 4);
|
||||||
|
|
||||||
fb.construct(env, base, area, area_phys);
|
if (conn.size.valid())
|
||||||
|
log("setup - framebuffer ",
|
||||||
Genode::log("framebuffer reconstructed - virtual=", xres, "x", yres,
|
" - connector id=", conn.id_element.id().value,
|
||||||
" physical=", phys_width, "x", phys_height);
|
", virtual=", xres, "x", yres,
|
||||||
|
", physical=", phys_width, "x", phys_height);
|
||||||
|
else
|
||||||
|
log("free - framebuffer ",
|
||||||
|
" - connector id=", conn.id_element.id().value,
|
||||||
|
", ", prev_size);
|
||||||
|
}, [](){ /* unknown id */ });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
extern "C" void lx_emul_i915_hotplug_connector()
|
void lx_emul_i915_hotplug_connector()
|
||||||
{
|
{
|
||||||
Genode::Env &env = Lx_kit::env().env;
|
Genode::Env &env = Lx_kit::env().env;
|
||||||
driver(env).generate_report();
|
driver(env).generate_report();
|
||||||
@ -422,8 +505,8 @@ void lx_emul_i915_report_connector(void * lx_data, void * genode_xml,
|
|||||||
|
|
||||||
xml.node("connector", [&] ()
|
xml.node("connector", [&] ()
|
||||||
{
|
{
|
||||||
xml.attribute("name", name);
|
|
||||||
xml.attribute("connected", !!connected);
|
xml.attribute("connected", !!connected);
|
||||||
|
xml.attribute("name", name);
|
||||||
if (width_mm)
|
if (width_mm)
|
||||||
xml.attribute("width_mm" , width_mm);
|
xml.attribute("width_mm" , width_mm);
|
||||||
if (height_mm)
|
if (height_mm)
|
||||||
@ -466,14 +549,13 @@ void lx_emul_i915_report_modes(void * genode_xml, struct genode_mode *mode)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
int lx_emul_i915_blit()
|
int lx_emul_i915_blit(unsigned connector_id)
|
||||||
{
|
{
|
||||||
auto &drv = driver(Lx_kit::env().env);
|
auto &drv = driver(Lx_kit::env().env);
|
||||||
|
|
||||||
if (!drv.fb.constructed())
|
auto const id = Framebuffer::Driver::Connector::Id { connector_id };
|
||||||
return false;
|
|
||||||
|
|
||||||
return drv.fb->paint();
|
return drv.capture(drv.ids, id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -15,7 +15,6 @@ SRC_C += dummies.c
|
|||||||
SRC_C += pci.c
|
SRC_C += pci.c
|
||||||
SRC_C += lx_emul.c
|
SRC_C += lx_emul.c
|
||||||
SRC_C += $(notdir $(wildcard $(REL_PRG_DIR)/generated_dummies.c))
|
SRC_C += $(notdir $(wildcard $(REL_PRG_DIR)/generated_dummies.c))
|
||||||
SRC_C += fb.c
|
|
||||||
SRC_C += lx_user.c
|
SRC_C += lx_user.c
|
||||||
SRC_C += gem.c
|
SRC_C += gem.c
|
||||||
SRC_C += lx_emul/common_dummies.c
|
SRC_C += lx_emul/common_dummies.c
|
||||||
|
Loading…
Reference in New Issue
Block a user