* Re: [PATCH] pwm-backlight: add regulator and GPIO support
From: Sascha Hauer @ 2012-07-05 6:47 UTC (permalink / raw)
To: Alex Courbot
Cc: Mark Brown, Thierry Reding,
linux-tegra-u79uwXL29TY76Z2rM5mHXA@public.gmane.org,
linux-kernel-u79uwXL29TY76Z2rM5mHXA@public.gmane.org,
linux-fbdev-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
In-Reply-To: <4FF53368.6090805-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
On Thu, Jul 05, 2012 at 03:25:44PM +0900, Alex Courbot wrote:
> On 07/05/2012 03:20 PM, Sascha Hauer wrote:
> >>Oh, that is a mistake of mine then. Driver probe should continue if
> >>no regulator is declared (but should fail if some other error
> >>occured). I want to maintain backward compatibility with current
> >>users of the driver, so regulator/gpio specification should be
> >>optional.
> >
> >I think the only way doing this is to add a flag to platform_data. I
> >don't know if that's accepted though.
>
> I thought about just checking if devm_get_regulator returned -ENODEV
> and happily continue if that was the case, assuming no regulator was
> declared.
And that's the problem. The get_regulator won't return -ENODEV. It will
return -EPROBE_DEFER which tells you nothing about whether a regulator
will ever be available or not.
Having a flag in platform data would be fine with me, but I know other
people think differently.
BTW in devicetree this flag implicitely exists with the power-supply
property. The regulator core could look if a power-supply property
is given and
- if it is given, a regulator is mandatory and the core either
returns the regulator or -EPROBE_DEFER if it cannot find one.
- If it is not given, there is no regulator and the core could either
return a special error code or a dummy regulator.
Right now the regulator core will just return -EPROBE_DEFER in both
cases. This could easily be changed in the regulator core.
Sascha
--
Pengutronix e.K. | |
Industrial Linux Solutions | http://www.pengutronix.de/ |
Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0 |
Amtsgericht Hildesheim, HRA 2686 | Fax: +49-5121-206917-5555 |
^ permalink raw reply
* Re: [PATCH] pwm-backlight: add regulator and GPIO support
From: Alex Courbot @ 2012-07-05 7:43 UTC (permalink / raw)
To: Sascha Hauer
Cc: Mark Brown, Thierry Reding,
linux-tegra-u79uwXL29TY76Z2rM5mHXA@public.gmane.org,
linux-kernel-u79uwXL29TY76Z2rM5mHXA@public.gmane.org,
linux-fbdev-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
In-Reply-To: <20120705064742.GL30009-bIcnvbaLZ9MEGnE8C9+IrQ@public.gmane.org>
On 07/05/2012 03:47 PM, Sascha Hauer wrote:
>> I thought about just checking if devm_get_regulator returned -ENODEV
>> and happily continue if that was the case, assuming no regulator was
>> declared.
>
> And that's the problem. The get_regulator won't return -ENODEV. It will
> return -EPROBE_DEFER which tells you nothing about whether a regulator
> will ever be available or not.
>
> Having a flag in platform data would be fine with me, but I know other
> people think differently.
>
> BTW in devicetree this flag implicitely exists with the power-supply
> property.
One could actually question whether the whole regulator/gpio thing
should be supported at all with platform data. The platform interface
can use the function hooks in order to implement whatever behavior it
wants when the light needs to be powered on and off. The reason for
introducing optional regulator/gpio parameters is because the DT cannot
use these. Since I have no plan to remove these function hooks, making
the regulator/gpio option available in platform data might be redundant.
Any thought about this?
> Right now the regulator core will just return -EPROBE_DEFER in both
> cases. This could easily be changed in the regulator core.
Could this be because the regulator core cannot make the difference
between a not-yet-available regulator and a missing one?
Alex.
^ permalink raw reply
* Re: [PATCH] pwm-backlight: add regulator and GPIO support
From: Thierry Reding @ 2012-07-05 7:57 UTC (permalink / raw)
To: Alex Courbot
Cc: Sascha Hauer, Mark Brown,
linux-tegra-u79uwXL29TY76Z2rM5mHXA@public.gmane.org,
linux-kernel-u79uwXL29TY76Z2rM5mHXA@public.gmane.org,
linux-fbdev-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
In-Reply-To: <4FF5459F.5090201-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
[-- Attachment #1: Type: text/plain, Size: 2430 bytes --]
On Thu, Jul 05, 2012 at 04:43:27PM +0900, Alex Courbot wrote:
> On 07/05/2012 03:47 PM, Sascha Hauer wrote:
> >>I thought about just checking if devm_get_regulator returned -ENODEV
> >>and happily continue if that was the case, assuming no regulator was
> >>declared.
> >
> >And that's the problem. The get_regulator won't return -ENODEV. It will
> >return -EPROBE_DEFER which tells you nothing about whether a regulator
> >will ever be available or not.
> >
> >Having a flag in platform data would be fine with me, but I know other
> >people think differently.
> >
> >BTW in devicetree this flag implicitely exists with the power-supply
> >property.
>
> One could actually question whether the whole regulator/gpio thing
> should be supported at all with platform data. The platform
> interface can use the function hooks in order to implement whatever
> behavior it wants when the light needs to be powered on and off. The
> reason for introducing optional regulator/gpio parameters is because
> the DT cannot use these. Since I have no plan to remove these
> function hooks, making the regulator/gpio option available in
> platform data might be redundant. Any thought about this?
I agree. Non-DT platforms have always used the callbacks to execute this
kind of code. As you've said before there are situations where it isn't
just about setting a GPIO or enabling a regulator but it also requires a
specific timing. Representing this in the platform data would become
tedious.
So I think for the DT case you can parse the power-on and power-off
sequences directly and execute code based on it, while in non-DT cases
the init and exit callbacks should be used instead. I think it even
makes sense to reuse the platform data's init and exit functions in the
DT case and implement the parser/interpreter within those.
> >Right now the regulator core will just return -EPROBE_DEFER in both
> >cases. This could easily be changed in the regulator core.
>
> Could this be because the regulator core cannot make the difference
> between a not-yet-available regulator and a missing one?
I case where the regulator comes from a DT it should assume that it will
become available at some point, so -EPROBE_DEFER is correct. However if
the DT doesn't even contain the power-supply property, then EPROBE_DEFER
will never work because there's no regulator to become available.
Thierry
[-- Attachment #2: Type: application/pgp-signature, Size: 836 bytes --]
^ permalink raw reply
* Re: [PATCH] pwm-backlight: add regulator and GPIO support
From: Sascha Hauer @ 2012-07-05 8:02 UTC (permalink / raw)
To: Alex Courbot
Cc: Mark Brown, Thierry Reding,
linux-tegra-u79uwXL29TY76Z2rM5mHXA@public.gmane.org,
linux-kernel-u79uwXL29TY76Z2rM5mHXA@public.gmane.org,
linux-fbdev-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
In-Reply-To: <4FF5459F.5090201-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
On Thu, Jul 05, 2012 at 04:43:27PM +0900, Alex Courbot wrote:
> On 07/05/2012 03:47 PM, Sascha Hauer wrote:
> >>I thought about just checking if devm_get_regulator returned -ENODEV
> >>and happily continue if that was the case, assuming no regulator was
> >>declared.
> >
> >And that's the problem. The get_regulator won't return -ENODEV. It will
> >return -EPROBE_DEFER which tells you nothing about whether a regulator
> >will ever be available or not.
> >
> >Having a flag in platform data would be fine with me, but I know other
> >people think differently.
> >
> >BTW in devicetree this flag implicitely exists with the power-supply
> >property.
>
> One could actually question whether the whole regulator/gpio thing
> should be supported at all with platform data. The platform
> interface can use the function hooks in order to implement whatever
> behavior it wants when the light needs to be powered on and off. The
> reason for introducing optional regulator/gpio parameters is because
> the DT cannot use these. Since I have no plan to remove these
> function hooks, making the regulator/gpio option available in
> platform data might be redundant. Any thought about this?
sounds good.
>
> >Right now the regulator core will just return -EPROBE_DEFER in both
> >cases. This could easily be changed in the regulator core.
>
> Could this be because the regulator core cannot make the difference
> between a not-yet-available regulator and a missing one?
It could. In regulator_dev_lookup we have:
if (node) {
...
} else {
/*
* If we couldn't even get the node then it's
* not just that the device didn't register
* yet, there's no node and we'll never
* succeed.
*/
*ret = -ENODEV;
}
So here the regulator core knows that there is no regulator and never
will be. All that needs to be done is to make _regulator_get look at
that value.
There may be some side effects if we just return ERR_PTR(-ENODEV) when
regulator_dev_lookup returns -ENODEV. Maybe Mark has some comments to
this.
Sascha
--
Pengutronix e.K. | |
Industrial Linux Solutions | http://www.pengutronix.de/ |
Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0 |
Amtsgericht Hildesheim, HRA 2686 | Fax: +49-5121-206917-5555 |
^ permalink raw reply
* Re: [PATCH] pwm-backlight: add regulator and GPIO support
From: Alex Courbot @ 2012-07-05 8:12 UTC (permalink / raw)
To: Thierry Reding
Cc: Sascha Hauer, Mark Brown, linux-tegra@vger.kernel.org,
linux-kernel@vger.kernel.org, linux-fbdev@vger.kernel.org
In-Reply-To: <20120705075714.GA26428@avionic-0098.mockup.avionic-design.de>
On 07/05/2012 04:57 PM, Thierry Reding wrote:
> I agree. Non-DT platforms have always used the callbacks to execute this
> kind of code. As you've said before there are situations where it isn't
> just about setting a GPIO or enabling a regulator but it also requires a
> specific timing. Representing this in the platform data would become
> tedious.
That will settle the whole issue then.
> So I think for the DT case you can parse the power-on and power-off
> sequences directly and execute code based on it, while in non-DT cases
> the init and exit callbacks should be used instead. I think it even
> makes sense to reuse the platform data's init and exit functions in the
> DT case and implement the parser/interpreter within those.
It totally makes sense indeed.
> I case where the regulator comes from a DT it should assume that it will
> become available at some point, so -EPROBE_DEFER is correct. However if
> the DT doesn't even contain the power-supply property, then EPROBE_DEFER
> will never work because there's no regulator to become available.
Indeed. And as Sascha mentionned this could easily be fixed. Guess I can
also submit a patch for that while I am at it.
Alex.
^ permalink raw reply
* Re: [PATCH] pwm-backlight: add regulator and GPIO support
From: Mark Brown @ 2012-07-05 10:37 UTC (permalink / raw)
To: Alex Courbot
Cc: Sascha Hauer, Thierry Reding, linux-tegra@vger.kernel.org,
linux-kernel@vger.kernel.org, linux-fbdev@vger.kernel.org
In-Reply-To: <4FF53368.6090805@nvidia.com>
[-- Attachment #1: Type: text/plain, Size: 536 bytes --]
On Thu, Jul 05, 2012 at 03:25:44PM +0900, Alex Courbot wrote:
> On 07/05/2012 03:20 PM, Sascha Hauer wrote:
> >I think the only way doing this is to add a flag to platform_data. I
> >don't know if that's accepted though.
> I thought about just checking if devm_get_regulator returned -ENODEV
> and happily continue if that was the case, assuming no regulator was
> declared.
No, that's really not a good idea - as I keep saying if we really want
to go down that line we should remove all error checking instead, it's
the end result.
[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 836 bytes --]
^ permalink raw reply
* Re: [PATCH] pwm-backlight: add regulator and GPIO support
From: Mark Brown @ 2012-07-05 10:39 UTC (permalink / raw)
To: Alex Courbot
Cc: Sascha Hauer, Thierry Reding,
linux-tegra-u79uwXL29TY76Z2rM5mHXA@public.gmane.org,
linux-kernel-u79uwXL29TY76Z2rM5mHXA@public.gmane.org,
linux-fbdev-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
In-Reply-To: <4FF5459F.5090201-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
[-- Attachment #1: Type: text/plain, Size: 1201 bytes --]
On Thu, Jul 05, 2012 at 04:43:27PM +0900, Alex Courbot wrote:
> One could actually question whether the whole regulator/gpio thing
> should be supported at all with platform data. The platform
> interface can use the function hooks in order to implement whatever
> behavior it wants when the light needs to be powered on and off. The
> reason for introducing optional regulator/gpio parameters is because
> the DT cannot use these. Since I have no plan to remove these
> function hooks, making the regulator/gpio option available in
> platform data might be redundant. Any thought about this?
Well, no - it's also done because even if you're not using device tree
(as on most of the architectures we support...) it's not good to have to
cut'n'paste code everywhere. This means that we want to be able to
provide things like GPIOs and regulators via data which means we have
exactly the same situation as we do with device tree.
> >Right now the regulator core will just return -EPROBE_DEFER in both
> >cases. This could easily be changed in the regulator core.
> Could this be because the regulator core cannot make the difference
> between a not-yet-available regulator and a missing one?
Yes.
[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 836 bytes --]
^ permalink raw reply
* Re: [PATCH] pwm-backlight: add regulator and GPIO support
From: Mark Brown @ 2012-07-05 10:41 UTC (permalink / raw)
To: Sascha Hauer
Cc: Alex Courbot, Thierry Reding, linux-tegra@vger.kernel.org,
linux-kernel@vger.kernel.org, linux-fbdev@vger.kernel.org
In-Reply-To: <20120705080234.GQ30009@pengutronix.de>
[-- Attachment #1: Type: text/plain, Size: 522 bytes --]
On Thu, Jul 05, 2012 at 10:02:34AM +0200, Sascha Hauer wrote:
> So here the regulator core knows that there is no regulator and never
> will be. All that needs to be done is to make _regulator_get look at
> that value.
> There may be some side effects if we just return ERR_PTR(-ENODEV) when
> regulator_dev_lookup returns -ENODEV. Maybe Mark has some comments to
> this.
I'm concerned about how this is going to interact with all the plans
people have for dynamically loading device tree fragments during
enumeration.
[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 836 bytes --]
^ permalink raw reply
* Re: [PATCH v2] of: Add videomode helper
From: Laurent Pinchart @ 2012-07-05 14:08 UTC (permalink / raw)
To: Sascha Hauer
Cc: linux-fbdev, devicetree-discuss, dri-devel, Grant Likely, kernel,
Mitch Bradley, Anatolij Gustschin
In-Reply-To: <1341388595-30672-1-git-send-email-s.hauer@pengutronix.de>
Hi Sascha,
Thanks for the patch.
On Wednesday 04 July 2012 09:56:35 Sascha Hauer wrote:
> This patch adds a helper function for parsing videomodes from the
> devicetree. The videomode can be either converted to a struct
> drm_display_mode or a struct fb_videomode.
>
> Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
> ---
>
> changes since v1:
> - use hyphens instead of underscores for property names
>
> .../devicetree/bindings/video/displaymode | 40 ++++++++
> drivers/of/Kconfig | 5 +
> drivers/of/Makefile | 1 +
> drivers/of/of_videomode.c | 108 +++++++++++++++++
> include/linux/of_videomode.h | 19 ++++
> 5 files changed, 173 insertions(+)
> create mode 100644 Documentation/devicetree/bindings/video/displaymode
> create mode 100644 drivers/of/of_videomode.c
> create mode 100644 include/linux/of_videomode.h
>
> diff --git a/Documentation/devicetree/bindings/video/displaymode
> b/Documentation/devicetree/bindings/video/displaymode new file mode 100644
> index 0000000..43cc17d
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/video/displaymode
> @@ -0,0 +1,40 @@
> +videomode bindings
> +=========
> +
> +Required properties:
> + - xres, yres: Display resolution
> + - left-margin, right-margin, hsync-len: Horizontal Display timing
> parameters + in pixels
> + upper-margin, lower-margin, vsync-len: Vertical display timing
> parameters in + lines
> + - clock: displayclock in Hz
> +
> +Optional properties:
> + - width-mm, height-mm: Display dimensions in mm
I've always had mixed feelings about the physical display dimension being part
of the display mode. Those are properties of the panel/display instead of the
mode. Storing them as part of the mode can be convenient, but we then run into
consistency issues (developers have to remember in which display mode
instances the values are available, and in which instances they're set to 0
for instance). If we want to clean this up, this patch would be a good
occasion.
> + - hsync-active-high (bool): Hsync pulse is active high
> + - vsync-active-high (bool): Vsync pulse is active high
> + - interlaced (bool): This is an interlaced mode
> + - doublescan (bool): This is a doublescan mode
> +
> +There are different ways of describing a display mode. The devicetree
> representation +corresponds to the one used by the Linux Framebuffer
> framework described here in +Documentation/fb/framebuffer.txt. This
> representation has been chosen because it's +the only format which does not
> allow for inconsistent parameters.Unlike the Framebuffer +framework the
> devicetree has the clock in Hz instead of ps.
> +
> +Example:
> +
> + display@0 {
> + /* 1920x1080p24 */
> + clock = <52000000>;
> + xres = <1920>;
> + yres = <1080>;
> + left-margin = <25>;
> + right-margin = <25>;
> + hsync-len = <25>;
> + lower-margin = <2>;
> + upper-margin = <2>;
> + vsync-len = <2>;
> + hsync-active-high;
> + };
> +
--
Regards,
Laurent Pinchart
^ permalink raw reply
* Re: [PATCH v2] of: Add videomode helper
From: Rob Herring @ 2012-07-05 14:51 UTC (permalink / raw)
To: Sascha Hauer
Cc: kernel-bIcnvbaLZ9MEGnE8C9+IrQ,
devicetree-discuss-uLR06cmDAlY/bJ5BZ2RsiQ,
linux-fbdev-u79uwXL29TY76Z2rM5mHXA,
dri-devel-PD4FTy7X32lNgt0PjOBp9y5qC8QIuHrW, Laurent Pinchart
In-Reply-To: <1341388595-30672-1-git-send-email-s.hauer-bIcnvbaLZ9MEGnE8C9+IrQ@public.gmane.org>
On 07/04/2012 02:56 AM, Sascha Hauer wrote:
> This patch adds a helper function for parsing videomodes from the devicetree.
> The videomode can be either converted to a struct drm_display_mode or a
> struct fb_videomode.
>
> Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
> ---
>
> changes since v1:
> - use hyphens instead of underscores for property names
>
> .../devicetree/bindings/video/displaymode | 40 ++++++++
> drivers/of/Kconfig | 5 +
> drivers/of/Makefile | 1 +
> drivers/of/of_videomode.c | 108 ++++++++++++++++++++
> include/linux/of_videomode.h | 19 ++++
> 5 files changed, 173 insertions(+)
> create mode 100644 Documentation/devicetree/bindings/video/displaymode
> create mode 100644 drivers/of/of_videomode.c
> create mode 100644 include/linux/of_videomode.h
>
> diff --git a/Documentation/devicetree/bindings/video/displaymode b/Documentation/devicetree/bindings/video/displaymode
> new file mode 100644
> index 0000000..43cc17d
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/video/displaymode
> @@ -0,0 +1,40 @@
> +videomode bindings
> +=========
> +
> +Required properties:
> + - xres, yres: Display resolution
> + - left-margin, right-margin, hsync-len: Horizontal Display timing parameters
> + in pixels
> + upper-margin, lower-margin, vsync-len: Vertical display timing parameters in
> + lines
> + - clock: displayclock in Hz
> +
> +Optional properties:
> + - width-mm, height-mm: Display dimensions in mm
> + - hsync-active-high (bool): Hsync pulse is active high
> + - vsync-active-high (bool): Vsync pulse is active high
> + - interlaced (bool): This is an interlaced mode
> + - doublescan (bool): This is a doublescan mode
> +
> +There are different ways of describing a display mode. The devicetree representation
> +corresponds to the one used by the Linux Framebuffer framework described here in
> +Documentation/fb/framebuffer.txt. This representation has been chosen because it's
> +the only format which does not allow for inconsistent parameters.Unlike the Framebuffer
> +framework the devicetree has the clock in Hz instead of ps.
This implies you are putting linux settings into DT rather than
describing the h/w. I'm not saying the binding is wrong, but documenting
it this way makes it seem so.
One important piece missing (and IIRC linux doesn't really support) is
defining the pixel format of the interface.
> +Example:
> +
> + display@0 {
> + /* 1920x1080p24 */
> + clock = <52000000>;
Should this use the clock binding? You probably need both constraints
and clock binding though.
Often you don't know the frequency up front and/or have limited control
of the frequency (i.e. integer dividers). Then you have to adjust the
margins to get the desired refresh rate. To do that, you need to know
the ranges of values a panel can support. Perhaps you just assume you
can increase the right-margin and lower-margins as I think you will hit
pixel clock frequency max before any limit on margins.
Rob
> + xres = <1920>;
> + yres = <1080>;
> + left-margin = <25>;
> + right-margin = <25>;
> + hsync-len = <25>;
> + lower-margin = <2>;
> + upper-margin = <2>;
> + vsync-len = <2>;
> + hsync-active-high;
> + };
> +
> diff --git a/drivers/of/Kconfig b/drivers/of/Kconfig
> index dfba3e6..a3acaa3 100644
> --- a/drivers/of/Kconfig
> +++ b/drivers/of/Kconfig
> @@ -83,4 +83,9 @@ config OF_MTD
> depends on MTD
> def_bool y
>
> +config OF_VIDEOMODE
> + def_bool y
> + help
> + helper to parse videomodes from the devicetree
> +
> endmenu # OF
> diff --git a/drivers/of/Makefile b/drivers/of/Makefile
> index e027f44..80e6db3 100644
> --- a/drivers/of/Makefile
> +++ b/drivers/of/Makefile
> @@ -11,3 +11,4 @@ obj-$(CONFIG_OF_MDIO) += of_mdio.o
> obj-$(CONFIG_OF_PCI) += of_pci.o
> obj-$(CONFIG_OF_PCI_IRQ) += of_pci_irq.o
> obj-$(CONFIG_OF_MTD) += of_mtd.o
> +obj-$(CONFIG_OF_VIDEOMODE) += of_videomode.o
> diff --git a/drivers/of/of_videomode.c b/drivers/of/of_videomode.c
> new file mode 100644
> index 0000000..50d3bd2
> --- /dev/null
> +++ b/drivers/of/of_videomode.c
> @@ -0,0 +1,108 @@
> +/*
> + * OF helpers for parsing display modes
> + *
> + * Copyright (c) 2012 Sascha Hauer <s.hauer@pengutronix.de>, Pengutronix
> + *
> + * This file is released under the GPLv2
> + */
> +#include <linux/of.h>
> +#include <linux/fb.h>
> +#include <linux/export.h>
> +#include <drm/drmP.h>
> +#include <drm/drm_crtc.h>
> +
> +int of_get_video_mode(struct device_node *np, struct drm_display_mode *dmode,
> + struct fb_videomode *fbmode)
> +{
> + int ret = 0;
> + u32 left_margin, xres, right_margin, hsync_len;
> + u32 upper_margin, yres, lower_margin, vsync_len;
> + u32 width_mm = 0, height_mm = 0;
> + u32 clock;
> + bool hah = false, vah = false, interlaced = false, doublescan = false;
> +
> + if (!np)
> + return -EINVAL;
> +
> + ret |= of_property_read_u32(np, "left-margin", &left_margin);
> + ret |= of_property_read_u32(np, "xres", &xres);
> + ret |= of_property_read_u32(np, "right-margin", &right_margin);
> + ret |= of_property_read_u32(np, "hsync-len", &hsync_len);
> + ret |= of_property_read_u32(np, "upper-margin", &upper_margin);
> + ret |= of_property_read_u32(np, "yres", &yres);
> + ret |= of_property_read_u32(np, "lower-margin", &lower_margin);
> + ret |= of_property_read_u32(np, "vsync-len", &vsync_len);
> + ret |= of_property_read_u32(np, "clock", &clock);
> + if (ret)
> + return -EINVAL;
> +
> + of_property_read_u32(np, "width-mm", &width_mm);
> + of_property_read_u32(np, "height-mm", &height_mm);
> +
> + hah = of_property_read_bool(np, "hsync-active-high");
> + vah = of_property_read_bool(np, "vsync-active-high");
> + interlaced = of_property_read_bool(np, "interlaced");
> + doublescan = of_property_read_bool(np, "doublescan");
> +
> + if (dmode) {
> + memset(dmode, 0, sizeof(*dmode));
> +
> + dmode->hdisplay = xres;
> + dmode->hsync_start = xres + right_margin;
> + dmode->hsync_end = xres + right_margin + hsync_len;
> + dmode->htotal = xres + right_margin + hsync_len + left_margin;
> +
> + dmode->vdisplay = yres;
> + dmode->vsync_start = yres + lower_margin;
> + dmode->vsync_end = yres + lower_margin + vsync_len;
> + dmode->vtotal = yres + lower_margin + vsync_len + upper_margin;
> +
> + dmode->width_mm = width_mm;
> + dmode->height_mm = height_mm;
> +
> + dmode->clock = clock / 1000;
> +
> + if (hah)
> + dmode->flags |= DRM_MODE_FLAG_PHSYNC;
> + else
> + dmode->flags |= DRM_MODE_FLAG_NHSYNC;
> + if (vah)
> + dmode->flags |= DRM_MODE_FLAG_PVSYNC;
> + else
> + dmode->flags |= DRM_MODE_FLAG_NVSYNC;
> + if (interlaced)
> + dmode->flags |= DRM_MODE_FLAG_INTERLACE;
> + if (doublescan)
> + dmode->flags |= DRM_MODE_FLAG_DBLSCAN;
> +
> + drm_mode_set_name(dmode);
> + }
> +
> + if (fbmode) {
> + memset(fbmode, 0, sizeof(*fbmode));
> +
> + fbmode->xres = xres;
> + fbmode->left_margin = left_margin;
> + fbmode->right_margin = right_margin;
> + fbmode->hsync_len = hsync_len;
> +
> + fbmode->yres = yres;
> + fbmode->upper_margin = upper_margin;
> + fbmode->lower_margin = lower_margin;
> + fbmode->vsync_len = vsync_len;
> +
> + fbmode->pixclock = KHZ2PICOS(clock / 1000);
> +
> + if (hah)
> + fbmode->sync |= FB_SYNC_HOR_HIGH_ACT;
> + if (vah)
> + fbmode->sync |= FB_SYNC_VERT_HIGH_ACT;
> + if (interlaced)
> + fbmode->vmode |= FB_VMODE_INTERLACED;
> + if (doublescan)
> + fbmode->vmode |= FB_VMODE_DOUBLE;
> + }
> +
> + return 0;
> +}
> +EXPORT_SYMBOL_GPL(of_get_video_mode);
> diff --git a/include/linux/of_videomode.h b/include/linux/of_videomode.h
> new file mode 100644
> index 0000000..a988429
> --- /dev/null
> +++ b/include/linux/of_videomode.h
> @@ -0,0 +1,19 @@
> +/*
> + * Copyright 2012 Sascha Hauer <s.hauer@pengutronix.de>
> + *
> + * OF helpers for videomodes.
> + *
> + * This file is released under the GPLv2
> + */
> +
> +#ifndef __LINUX_OF_VIDEOMODE_H
> +#define __LINUX_OF_VIDEOMODE_H
> +
> +struct device_node;
> +struct fb_videomode;
> +struct drm_display_mode;
> +
> +int of_get_video_mode(struct device_node *np, struct drm_display_mode *dmode,
> + struct fb_videomode *fbmode);
> +
> +#endif /* __LINUX_OF_VIDEOMODE_H */
>
^ permalink raw reply
* Re: [PATCH] pwm-backlight: add regulator and GPIO support
From: Stephen Warren @ 2012-07-05 16:03 UTC (permalink / raw)
To: Alex Courbot
Cc: Thierry Reding, Sascha Hauer, Mark Brown,
linux-tegra@vger.kernel.org, linux-kernel@vger.kernel.org,
linux-fbdev@vger.kernel.org
In-Reply-To: <4FF54C6C.1060700@nvidia.com>
On 07/05/2012 02:12 AM, Alex Courbot wrote:
> On 07/05/2012 04:57 PM, Thierry Reding wrote:
>> I agree. Non-DT platforms have always used the callbacks to execute this
>> kind of code. As you've said before there are situations where it isn't
>> just about setting a GPIO or enabling a regulator but it also requires a
>> specific timing. Representing this in the platform data would become
>> tedious.
>
> That will settle the whole issue then.
>
>> So I think for the DT case you can parse the power-on and power-off
>> sequences directly and execute code based on it, while in non-DT cases
>> the init and exit callbacks should be used instead. I think it even
>> makes sense to reuse the platform data's init and exit functions in the
>> DT case and implement the parser/interpreter within those.
>
> It totally makes sense indeed.
I don't agree here. It'd be best if non-DT and DT cases worked as
similarly as possible. Relying on callbacks in one case and
data-parsed-from-DT in the other isn't consistent with that. After all,
in the DT case, you parse some data out of the DT and into some data
structure. In the non-DT case, you can have that data structure passed
in directly using platform data. Now, there's certainly a need to
continue to support callbacks for backwards compatibility, at the very
least temporarily before all clients are converted to the new model, but
requiring different models rather than simply allowing it seems like a
bad idea to me.
^ permalink raw reply
* Re: [PATCH v2] of: Add videomode helper
From: Sascha Hauer @ 2012-07-05 16:50 UTC (permalink / raw)
To: Laurent Pinchart
Cc: linux-fbdev-u79uwXL29TY76Z2rM5mHXA,
devicetree-discuss-uLR06cmDAlY/bJ5BZ2RsiQ,
dri-devel-PD4FTy7X32lNgt0PjOBp9y5qC8QIuHrW,
kernel-bIcnvbaLZ9MEGnE8C9+IrQ
In-Reply-To: <3714247.L7zNpJpvuy@avalon>
On Thu, Jul 05, 2012 at 04:08:07PM +0200, Laurent Pinchart wrote:
> Hi Sascha,
>
> Thanks for the patch.
>
> > +++ b/Documentation/devicetree/bindings/video/displaymode
> > @@ -0,0 +1,40 @@
> > +videomode bindings
> > +=========
> > +
> > +Required properties:
> > + - xres, yres: Display resolution
> > + - left-margin, right-margin, hsync-len: Horizontal Display timing
> > parameters + in pixels
> > + upper-margin, lower-margin, vsync-len: Vertical display timing
> > parameters in + lines
> > + - clock: displayclock in Hz
> > +
> > +Optional properties:
> > + - width-mm, height-mm: Display dimensions in mm
>
> I've always had mixed feelings about the physical display dimension being part
> of the display mode. Those are properties of the panel/display instead of the
> mode. Storing them as part of the mode can be convenient, but we then run into
> consistency issues (developers have to remember in which display mode
> instances the values are available, and in which instances they're set to 0
> for instance). If we want to clean this up, this patch would be a good
> occasion.
This sounds like a display node with one or more node subnodes, like:
display {
width_mm = <>;
height_mm = <>;
mode {
xres = <>;
yres = <>;
...
};
};
Is that what you mean or are you thinking of something else?
Sascha
--
Pengutronix e.K. | |
Industrial Linux Solutions | http://www.pengutronix.de/ |
Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0 |
Amtsgericht Hildesheim, HRA 2686 | Fax: +49-5121-206917-5555 |
^ permalink raw reply
* Re: [PATCH v2] of: Add videomode helper
From: Sascha Hauer @ 2012-07-05 18:39 UTC (permalink / raw)
To: Rob Herring
Cc: kernel-bIcnvbaLZ9MEGnE8C9+IrQ,
devicetree-discuss-uLR06cmDAlY/bJ5BZ2RsiQ,
linux-fbdev-u79uwXL29TY76Z2rM5mHXA,
dri-devel-PD4FTy7X32lNgt0PjOBp9y5qC8QIuHrW, Laurent Pinchart
In-Reply-To: <4FF5A9FB.7010004-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
On Thu, Jul 05, 2012 at 09:51:39AM -0500, Rob Herring wrote:
> On 07/04/2012 02:56 AM, Sascha Hauer wrote:
> > +
> > +There are different ways of describing a display mode. The devicetree representation
> > +corresponds to the one used by the Linux Framebuffer framework described here in
> > +Documentation/fb/framebuffer.txt. This representation has been chosen because it's
> > +the only format which does not allow for inconsistent parameters.Unlike the Framebuffer
> > +framework the devicetree has the clock in Hz instead of ps.
>
> This implies you are putting linux settings into DT rather than
> describing the h/w. I'm not saying the binding is wrong, but documenting
> it this way makes it seem so.
The major reason to use these values was that they do not allow for
inconsistent values (as opposed to for example with hsync_start which you
would have to check for hsync_start >= xres).
I could rephrase this if it looks too much like modelled-after-Linux
instead of modelled-after-hardware.
>
> One important piece missing (and IIRC linux doesn't really support) is
> defining the pixel format of the interface.
I could use this aswell. I think this can be specified as additional
properties later, right? I'm afraid this needs a lot of discussion so
we should delay this to the next round.
>
> > +Example:
> > +
> > + display@0 {
> > + /* 1920x1080p24 */
> > + clock = <52000000>;
>
> Should this use the clock binding? You probably need both constraints
> and clock binding though.
Is the clock binding suitable for this? Here we are not interested where
the clock comes from, but instead which range is allowed.
>
> Often you don't know the frequency up front and/or have limited control
> of the frequency (i.e. integer dividers). Then you have to adjust the
> margins to get the desired refresh rate. To do that, you need to know
> the ranges of values a panel can support. Perhaps you just assume you
> can increase the right-margin and lower-margins as I think you will hit
> pixel clock frequency max before any limit on margins.
Most datasheets specify min,typ,max triplets. We could do this instead
of using single fixed values for the margins:
left_margin = <0 10 40>;
Right now we have nothing in the kernel that could handle this, but
getting the interface to the devicetree right seems indeed important.
Sascha
--
Pengutronix e.K. | |
Industrial Linux Solutions | http://www.pengutronix.de/ |
Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0 |
Amtsgericht Hildesheim, HRA 2686 | Fax: +49-5121-206917-5555 |
^ permalink raw reply
* [PATCH] [resend] s3fb: Add Virge/MX (86C260)
From: Ondrej Zary @ 2012-07-06 13:12 UTC (permalink / raw)
To: Florian Tobias Schandinat
Cc: Ondrej Zajicek, linux-fbdev, Kernel development list
Add support for Virge/MX (86C260) chip. Although this is a laptop chip,
there's an AGP card with this chip too.
Tested with AGP card, will probably not work correctly with laptops.
DDC does not work on this card (even in DOS or Windows).
Signed-off-by: Ondrej Zary <linux@rainbow-software.org>
--- a/drivers/video/s3fb.c
+++ b/drivers/video/s3fb.c
@@ -84,7 +84,7 @@ static const char * const s3_names[] = {"S3 Unknown", "S3 Trio32", "S3 Trio64",
"S3 Virge/VX", "S3 Virge/DX", "S3 Virge/GX",
"S3 Virge/GX2", "S3 Virge/GX2+", "",
"S3 Trio3D/1X", "S3 Trio3D/2X", "S3 Trio3D/2X",
- "S3 Trio3D"};
+ "S3 Trio3D", "S3 Virge/MX"};
#define CHIP_UNKNOWN 0x00
#define CHIP_732_TRIO32 0x01
@@ -105,6 +105,7 @@ static const char * const s3_names[] = {"S3 Unknown", "S3 Trio32", "S3 Trio64",
#define CHIP_362_TRIO3D_2X 0x11
#define CHIP_368_TRIO3D_2X 0x12
#define CHIP_365_TRIO3D 0x13
+#define CHIP_260_VIRGE_MX 0x14
#define CHIP_XXX_TRIO 0x80
#define CHIP_XXX_TRIO64V2_DXGX 0x81
@@ -280,7 +281,8 @@ static int __devinit s3fb_setup_ddc_bus(struct fb_info *info)
*/
/* vga_wseq(par->state.vgabase, 0x08, 0x06); - not needed, already unlocked */
if (par->chip = CHIP_357_VIRGE_GX2 ||
- par->chip = CHIP_359_VIRGE_GX2P)
+ par->chip = CHIP_359_VIRGE_GX2P ||
+ par->chip = CHIP_260_VIRGE_MX)
svga_wseq_mask(par->state.vgabase, 0x0d, 0x01, 0x03);
else
svga_wseq_mask(par->state.vgabase, 0x0d, 0x00, 0x03);
@@ -487,7 +489,8 @@ static void s3_set_pixclock(struct fb_info *info, u32 pixclock)
par->chip = CHIP_359_VIRGE_GX2P ||
par->chip = CHIP_360_TRIO3D_1X ||
par->chip = CHIP_362_TRIO3D_2X ||
- par->chip = CHIP_368_TRIO3D_2X) {
+ par->chip = CHIP_368_TRIO3D_2X ||
+ par->chip = CHIP_260_VIRGE_MX) {
vga_wseq(par->state.vgabase, 0x12, (n - 2) | ((r & 3) << 6)); /* n and two bits of r */
vga_wseq(par->state.vgabase, 0x29, r >> 2); /* remaining highest bit of r */
} else
@@ -690,7 +693,8 @@ static int s3fb_set_par(struct fb_info *info)
par->chip != CHIP_359_VIRGE_GX2P &&
par->chip != CHIP_360_TRIO3D_1X &&
par->chip != CHIP_362_TRIO3D_2X &&
- par->chip != CHIP_368_TRIO3D_2X) {
+ par->chip != CHIP_368_TRIO3D_2X &&
+ par->chip != CHIP_260_VIRGE_MX) {
vga_wcrt(par->state.vgabase, 0x54, 0x18); /* M parameter */
vga_wcrt(par->state.vgabase, 0x60, 0xff); /* N parameter */
vga_wcrt(par->state.vgabase, 0x61, 0xff); /* L parameter */
@@ -739,7 +743,8 @@ static int s3fb_set_par(struct fb_info *info)
par->chip = CHIP_368_TRIO3D_2X ||
par->chip = CHIP_365_TRIO3D ||
par->chip = CHIP_375_VIRGE_DX ||
- par->chip = CHIP_385_VIRGE_GX) {
+ par->chip = CHIP_385_VIRGE_GX ||
+ par->chip = CHIP_260_VIRGE_MX) {
dbytes = info->var.xres * ((bpp+7)/8);
vga_wcrt(par->state.vgabase, 0x91, (dbytes + 7) / 8);
vga_wcrt(par->state.vgabase, 0x90, (((dbytes + 7) / 8) >> 8) | 0x80);
@@ -751,7 +756,8 @@ static int s3fb_set_par(struct fb_info *info)
par->chip = CHIP_359_VIRGE_GX2P ||
par->chip = CHIP_360_TRIO3D_1X ||
par->chip = CHIP_362_TRIO3D_2X ||
- par->chip = CHIP_368_TRIO3D_2X)
+ par->chip = CHIP_368_TRIO3D_2X ||
+ par->chip = CHIP_260_VIRGE_MX)
vga_wcrt(par->state.vgabase, 0x34, 0x00);
else /* enable Data Transfer Position Control (DTPC) */
vga_wcrt(par->state.vgabase, 0x34, 0x10);
@@ -807,7 +813,8 @@ static int s3fb_set_par(struct fb_info *info)
par->chip = CHIP_359_VIRGE_GX2P ||
par->chip = CHIP_360_TRIO3D_1X ||
par->chip = CHIP_362_TRIO3D_2X ||
- par->chip = CHIP_368_TRIO3D_2X)
+ par->chip = CHIP_368_TRIO3D_2X ||
+ par->chip = CHIP_260_VIRGE_MX)
svga_wcrt_mask(par->state.vgabase, 0x67, 0x00, 0xF0);
else {
svga_wcrt_mask(par->state.vgabase, 0x67, 0x10, 0xF0);
@@ -837,7 +844,8 @@ static int s3fb_set_par(struct fb_info *info)
par->chip != CHIP_359_VIRGE_GX2P &&
par->chip != CHIP_360_TRIO3D_1X &&
par->chip != CHIP_362_TRIO3D_2X &&
- par->chip != CHIP_368_TRIO3D_2X)
+ par->chip != CHIP_368_TRIO3D_2X &&
+ par->chip != CHIP_260_VIRGE_MX)
hmul = 2;
}
break;
@@ -864,7 +872,8 @@ static int s3fb_set_par(struct fb_info *info)
par->chip != CHIP_359_VIRGE_GX2P &&
par->chip != CHIP_360_TRIO3D_1X &&
par->chip != CHIP_362_TRIO3D_2X &&
- par->chip != CHIP_368_TRIO3D_2X)
+ par->chip != CHIP_368_TRIO3D_2X &&
+ par->chip != CHIP_260_VIRGE_MX)
hmul = 2;
}
break;
@@ -1208,7 +1217,8 @@ static int __devinit s3_pci_probe(struct pci_dev *dev, const struct pci_device_i
break;
}
} else if (par->chip = CHIP_357_VIRGE_GX2 ||
- par->chip = CHIP_359_VIRGE_GX2P) {
+ par->chip = CHIP_359_VIRGE_GX2P ||
+ par->chip = CHIP_260_VIRGE_MX) {
switch ((regval & 0xC0) >> 6) {
case 1: /* 4MB */
info->screen_size = 4 << 20;
@@ -1515,6 +1525,7 @@ static struct pci_device_id s3_devices[] __devinitdata = {
{PCI_DEVICE(PCI_VENDOR_ID_S3, 0x8A12), .driver_data = CHIP_359_VIRGE_GX2P},
{PCI_DEVICE(PCI_VENDOR_ID_S3, 0x8A13), .driver_data = CHIP_36X_TRIO3D_1X_2X},
{PCI_DEVICE(PCI_VENDOR_ID_S3, 0x8904), .driver_data = CHIP_365_TRIO3D},
+ {PCI_DEVICE(PCI_VENDOR_ID_S3, 0x8C01), .driver_data = CHIP_260_VIRGE_MX},
{0, 0, 0, 0, 0, 0, 0}
};
--
Ondrej Zary
^ permalink raw reply
* [PATCH v2] da8xx-fb: add missing FB_BLANK operations
From: yegorslists @ 2012-07-06 14:01 UTC (permalink / raw)
To: linux-arm-kernel
From: Yegor Yefremov <yegorslists@googlemail.com>
add FB_BLANK_NORMAL, FB_BLANK_VSYNC_SUSPEND and FB_BLANK_HSYNC_SUSPEND
modes (copy drivers/video/omap2/omapfb/omapfb-main.c implementation).
Otherwise X-server will complain about invalid parameter.
Signed-off-by: Yegor Yefremov <yegorslists@googlemail.com>
---
v2: add linux-fbdev as recipient
drivers/video/da8xx-fb.c | 3 +++
1 files changed, 3 insertions(+), 0 deletions(-)
diff --git a/drivers/video/da8xx-fb.c b/drivers/video/da8xx-fb.c
index 47118c7..8d745bf 100644
--- a/drivers/video/da8xx-fb.c
+++ b/drivers/video/da8xx-fb.c
@@ -1026,6 +1026,9 @@ static int cfb_blank(int blank, struct fb_info *info)
lcd_enable_raster();
break;
+ case FB_BLANK_NORMAL:
+ case FB_BLANK_VSYNC_SUSPEND:
+ case FB_BLANK_HSYNC_SUSPEND:
case FB_BLANK_POWERDOWN:
if (par->panel_power_ctrl)
par->panel_power_ctrl(0);
--
1.7.7
^ permalink raw reply related
* [PATCH v2 00/11] fblog: framebuffer kernel log driver
From: David Herrmann @ 2012-07-08 21:56 UTC (permalink / raw)
To: linux-serial
Cc: linux-kernel, florianschandinat, linux-fbdev, gregkh, alan,
bonbons, David Herrmann
Hi
This is version 2 of the fblog driver. The fblog driver allows showing the
kernel console on all available framebuffers. It's a replacement for CONFIG_VT
and fbcon that is much, much smaller and simpler. It should be used for
debugging purposes only, therefore, it is currently not optimized for speed.
Three patches extract update_attr(), bit_putcs() and get/put_fb_info() so they
can be used from fblog, the other patches actually implement fblog.
Version 2 addresses the issues from the last series. I extracted bit_putcs()
into fbdraw_font() so we have a single function shared between fbcon and fblog
to draw text. Furthermore, I reworked the framebuffer-registration logic inside
of fblog so there shouldn't be any more races with fbmem.c fb registration.
There is also a new configuration parameter that allows enabling fblog only on
specific framebuffers as requested from several people.
I also redid the whole patch-split so it should be much easier to follow. I am
using this driver on my x86_64 machine without any problems. If you remove the
"!VT" line in Kconfig then this can even be used with VTs enabled (even though
this is kind of racy between fbcon and fblog, obviously). Unloading the module
still has to be done with "rmmod -f fblog" as we still have a reference to our
own module. I haven't found a way to avoid this.
The reason why I wrote this driver is to make CONFIG_VT obsolete. This way I can
drop a lot of code from the kernel and make it much smaller. In combination with
user-space terminals like "kmscon" there is actually no need for in-kernel
terminals anymore.
This patchset is built based on linux-next as I have no idea whose tree this is
going through.
Feedback is appreciated.
Regards
David
David Herrmann (11):
fbcon: move update_attr() into separate source file
fbcon: move bit_putcs() into separate source file
fblog: new framebuffer kernel log dummy driver
fbdev: export get_fb_info()/put_fb_info()
fblog: register one fblog object per framebuffer
fblog: open fb on registration
fblog: allow selecting fbs via sysfs
fblog: cache framebuffer BLANK and SUSPEND states
fblog: register console driver
fblog: draw console to framebuffers
MAINTAINERS: add fblog entry
MAINTAINERS | 6 +
drivers/video/Kconfig | 5 +-
drivers/video/Makefile | 2 +-
drivers/video/console/Kconfig | 37 ++-
drivers/video/console/Makefile | 4 +-
drivers/video/console/bitblit.c | 149 +--------
drivers/video/console/fbcon.h | 5 +-
drivers/video/console/fbdraw.c | 171 +++++++++++
drivers/video/console/fbdraw.h | 30 ++
drivers/video/console/fblog.c | 665 ++++++++++++++++++++++++++++++++++++++++
drivers/video/fbmem.c | 6 +-
include/linux/fb.h | 3 +
12 files changed, 925 insertions(+), 158 deletions(-)
create mode 100644 drivers/video/console/fbdraw.c
create mode 100644 drivers/video/console/fbdraw.h
create mode 100644 drivers/video/console/fblog.c
--
1.7.11.1
^ permalink raw reply
* [PATCH v2 01/11] fbcon: move update_attr() into separate source file
From: David Herrmann @ 2012-07-08 21:56 UTC (permalink / raw)
To: linux-serial
Cc: linux-kernel, florianschandinat, linux-fbdev, gregkh, alan,
bonbons, David Herrmann
In-Reply-To: <1341784614-2797-1-git-send-email-dh.herrmann@googlemail.com>
If we want to use update_attr() independently from fbcon, we need to split
it off from bitblit.c and fbcon.h. Therefore, introduce a new header and
source file (fbdraw.[ch]) which does not depende on vc_* and fbcon_*
structures in any way.
This does not introduce any new code nor does it make the paths deeper,
it simply splits the function off.
The other update_attr() functions (inside the rotation sources) seem
similar but are significantly different and I haven't found a way to merge
them efficiently (which is probably the reason why they are split off
now). Furthermore, I do not intend to use them in the coming code so there
is no need to split them off.
Signed-off-by: David Herrmann <dh.herrmann@googlemail.com>
---
drivers/video/console/Makefile | 3 ++-
drivers/video/console/bitblit.c | 26 +++--------------------
drivers/video/console/fbcon.h | 5 +----
drivers/video/console/fbdraw.c | 46 +++++++++++++++++++++++++++++++++++++++++
drivers/video/console/fbdraw.h | 26 +++++++++++++++++++++++
5 files changed, 78 insertions(+), 28 deletions(-)
create mode 100644 drivers/video/console/fbdraw.c
create mode 100644 drivers/video/console/fbdraw.h
diff --git a/drivers/video/console/Makefile b/drivers/video/console/Makefile
index a862e91..9a52226 100644
--- a/drivers/video/console/Makefile
+++ b/drivers/video/console/Makefile
@@ -25,7 +25,8 @@ obj-$(CONFIG_SGI_NEWPORT_CONSOLE) += newport_con.o font.o
obj-$(CONFIG_STI_CONSOLE) += sticon.o sticore.o font.o
obj-$(CONFIG_VGA_CONSOLE) += vgacon.o
obj-$(CONFIG_MDA_CONSOLE) += mdacon.o
-obj-$(CONFIG_FRAMEBUFFER_CONSOLE) += fbcon.o bitblit.o font.o softcursor.o
+obj-$(CONFIG_FRAMEBUFFER_CONSOLE) += fbcon.o bitblit.o font.o softcursor.o \
+ fbdraw.o
ifeq ($(CONFIG_FB_TILEBLITTING),y)
obj-$(CONFIG_FRAMEBUFFER_CONSOLE) += tileblit.o
endif
diff --git a/drivers/video/console/bitblit.c b/drivers/video/console/bitblit.c
index 28b1a83..6ec2905 100644
--- a/drivers/video/console/bitblit.c
+++ b/drivers/video/console/bitblit.c
@@ -22,26 +22,6 @@
/*
* Accelerated handlers.
*/
-static void update_attr(u8 *dst, u8 *src, int attribute,
- struct vc_data *vc)
-{
- int i, offset = (vc->vc_font.height < 10) ? 1 : 2;
- int width = DIV_ROUND_UP(vc->vc_font.width, 8);
- unsigned int cellsize = vc->vc_font.height * width;
- u8 c;
-
- offset = cellsize - (offset * width);
- for (i = 0; i < cellsize; i++) {
- c = src[i];
- if (attribute & FBCON_ATTRIBUTE_UNDERLINE && i >= offset)
- c = 0xff;
- if (attribute & FBCON_ATTRIBUTE_BOLD)
- c |= c >> 1;
- if (attribute & FBCON_ATTRIBUTE_REVERSE)
- c = ~c;
- dst[i] = c;
- }
-}
static void bit_bmove(struct vc_data *vc, struct fb_info *info, int sy,
int sx, int dy, int dx, int height, int width)
@@ -88,7 +68,7 @@ static inline void bit_putcs_aligned(struct vc_data *vc, struct fb_info *info,
charmask)*cellsize;
if (attr) {
- update_attr(buf, src, attr, vc);
+ fbdraw_update_attr(buf, src, attr, &vc->vc_font);
src = buf;
}
@@ -123,7 +103,7 @@ static inline void bit_putcs_unaligned(struct vc_data *vc,
charmask)*cellsize;
if (attr) {
- update_attr(buf, src, attr, vc);
+ fbdraw_update_attr(buf, src, attr, &vc->vc_font);
src = buf;
}
@@ -275,7 +255,7 @@ static void bit_cursor(struct vc_data *vc, struct fb_info *info, int mode,
return;
kfree(ops->cursor_data);
ops->cursor_data = dst;
- update_attr(dst, src, attribute, vc);
+ fbdraw_update_attr(dst, src, attribute, &vc->vc_font);
src = dst;
}
diff --git a/drivers/video/console/fbcon.h b/drivers/video/console/fbcon.h
index 6bd2e0c..8623bac 100644
--- a/drivers/video/console/fbcon.h
+++ b/drivers/video/console/fbcon.h
@@ -16,6 +16,7 @@
#include <linux/vt_kern.h>
#include <asm/io.h>
+#include "fbdraw.h"
#define FBCON_FLAGS_INIT 1
#define FBCON_FLAGS_CURSOR_TIMER 2
@@ -219,10 +220,6 @@ extern void fbcon_set_tileops(struct vc_data *vc, struct fb_info *info);
extern void fbcon_set_bitops(struct fbcon_ops *ops);
extern int soft_cursor(struct fb_info *info, struct fb_cursor *cursor);
-#define FBCON_ATTRIBUTE_UNDERLINE 1
-#define FBCON_ATTRIBUTE_REVERSE 2
-#define FBCON_ATTRIBUTE_BOLD 4
-
static inline int real_y(struct display *p, int ypos)
{
int rows = p->vrows;
diff --git a/drivers/video/console/fbdraw.c b/drivers/video/console/fbdraw.c
new file mode 100644
index 0000000..65e7003
--- /dev/null
+++ b/drivers/video/console/fbdraw.c
@@ -0,0 +1,46 @@
+/*
+ * Framebuffer helpers for image draw-operations
+ *
+ * Copyright (c) 2004 Antonino Daplas <adaplas @pol.net>
+ * Copyright (c) 2012 David Herrmann <dh.herrmann@googlemail.com>
+ *
+ * Originally from drivers/video/console/bitblit.c which itself originally is
+ * from the 'accel_*' routines in drivers/video/console/fbcon.c.
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file COPYING in the main directory of this archive for
+ * more details.
+ */
+
+#include <linux/console.h>
+#include <linux/fb.h>
+#include <linux/kd.h>
+#include <linux/module.h>
+#include <linux/string.h>
+#include "fbdraw.h"
+
+void fbdraw_update_attr(u8 *dst, const u8 *src, int attribute,
+ struct console_font *font)
+{
+ int i, offset = (font->height < 10) ? 1 : 2;
+ int width = DIV_ROUND_UP(font->width, 8);
+ unsigned int cellsize = font->height * width;
+ u8 c;
+
+ offset = cellsize - (offset * width);
+ for (i = 0; i < cellsize; i++) {
+ c = src[i];
+ if (attribute & FBCON_ATTRIBUTE_UNDERLINE && i >= offset)
+ c = 0xff;
+ if (attribute & FBCON_ATTRIBUTE_BOLD)
+ c |= c >> 1;
+ if (attribute & FBCON_ATTRIBUTE_REVERSE)
+ c = ~c;
+ dst[i] = c;
+ }
+}
+EXPORT_SYMBOL(fbdraw_update_attr);
+
+MODULE_LICENSE("GPL v2");
+MODULE_AUTHOR("David Herrmann <dh.herrmann@googlemail.com>");
+MODULE_DESCRIPTION("Framebuffer helpers for image draw-operations");
diff --git a/drivers/video/console/fbdraw.h b/drivers/video/console/fbdraw.h
new file mode 100644
index 0000000..77edd7f
--- /dev/null
+++ b/drivers/video/console/fbdraw.h
@@ -0,0 +1,26 @@
+/*
+ * Framebuffer helpers for image draw-operations
+ *
+ * Copyright (c) 2012 David Herrmann <dh.herrmann@googlemail.com>
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file COPYING in the main directory of this archive for
+ * more details.
+ */
+
+#ifndef _VIDEO_FBDRAW_H
+#define _VIDEO_FBDRAW_H
+
+#include <linux/console.h>
+#include <linux/fb.h>
+#include <linux/kd.h>
+
+/* fbcon character attributes */
+#define FBCON_ATTRIBUTE_UNDERLINE 1
+#define FBCON_ATTRIBUTE_REVERSE 2
+#define FBCON_ATTRIBUTE_BOLD 4
+
+void fbdraw_update_attr(u8 *dst, const u8 *src, int attribute,
+ struct console_font *font);
+
+#endif /* _VIDEO_FBDRAW_H */
--
1.7.11.1
^ permalink raw reply related
* [PATCH v2 02/11] fbcon: move bit_putcs() into separate source file
From: David Herrmann @ 2012-07-08 21:56 UTC (permalink / raw)
To: linux-serial
Cc: linux-kernel, florianschandinat, linux-fbdev, gregkh, alan,
bonbons, David Herrmann
In-Reply-To: <1341784614-2797-1-git-send-email-dh.herrmann@googlemail.com>
If we want to use font-draw-operations in other modules than fbcon, we
need to split this function off of fbcon headers and sources. This also
makes bit_putcs() totally independent of vc_* and fbcon_* structures.
As scr_read() cannot be called inside of non-fbcon/vt functions, we need
to assemble the buffer before passing it to fbdraw_font(). This slows down
this operations a little bit but my rough benchmark showed that it didn't
really matter. Anyway, if it does, we can still put it into VT_BUF_HAVE_RW
conditions so platforms that don't use it won't be affected. And for other
platforms we can add the buffer to the vc-struct so we can reuse it.
Signed-off-by: David Herrmann <dh.herrmann@googlemail.com>
---
drivers/video/console/bitblit.c | 127 ++++------------------------------------
drivers/video/console/fbdraw.c | 125 +++++++++++++++++++++++++++++++++++++++
drivers/video/console/fbdraw.h | 4 ++
3 files changed, 139 insertions(+), 117 deletions(-)
diff --git a/drivers/video/console/bitblit.c b/drivers/video/console/bitblit.c
index 6ec2905..c5d897b 100644
--- a/drivers/video/console/bitblit.c
+++ b/drivers/video/console/bitblit.c
@@ -54,132 +54,25 @@ static void bit_clear(struct vc_data *vc, struct fb_info *info, int sy,
info->fbops->fb_fillrect(info, ®ion);
}
-static inline void bit_putcs_aligned(struct vc_data *vc, struct fb_info *info,
- const u16 *s, u32 attr, u32 cnt,
- u32 d_pitch, u32 s_pitch, u32 cellsize,
- struct fb_image *image, u8 *buf, u8 *dst)
-{
- u16 charmask = vc->vc_hi_font_mask ? 0x1ff : 0xff;
- u32 idx = vc->vc_font.width >> 3;
- u8 *src;
-
- while (cnt--) {
- src = vc->vc_font.data + (scr_readw(s++)&
- charmask)*cellsize;
-
- if (attr) {
- fbdraw_update_attr(buf, src, attr, &vc->vc_font);
- src = buf;
- }
-
- if (likely(idx = 1))
- __fb_pad_aligned_buffer(dst, d_pitch, src, idx,
- image->height);
- else
- fb_pad_aligned_buffer(dst, d_pitch, src, idx,
- image->height);
-
- dst += s_pitch;
- }
-
- info->fbops->fb_imageblit(info, image);
-}
-
-static inline void bit_putcs_unaligned(struct vc_data *vc,
- struct fb_info *info, const u16 *s,
- u32 attr, u32 cnt, u32 d_pitch,
- u32 s_pitch, u32 cellsize,
- struct fb_image *image, u8 *buf,
- u8 *dst)
-{
- u16 charmask = vc->vc_hi_font_mask ? 0x1ff : 0xff;
- u32 shift_low = 0, mod = vc->vc_font.width % 8;
- u32 shift_high = 8;
- u32 idx = vc->vc_font.width >> 3;
- u8 *src;
-
- while (cnt--) {
- src = vc->vc_font.data + (scr_readw(s++)&
- charmask)*cellsize;
-
- if (attr) {
- fbdraw_update_attr(buf, src, attr, &vc->vc_font);
- src = buf;
- }
-
- fb_pad_unaligned_buffer(dst, d_pitch, src, idx,
- image->height, shift_high,
- shift_low, mod);
- shift_low += mod;
- dst += (shift_low >= 8) ? s_pitch : s_pitch - 1;
- shift_low &= 7;
- shift_high = 8 - shift_low;
- }
-
- info->fbops->fb_imageblit(info, image);
-
-}
-
static void bit_putcs(struct vc_data *vc, struct fb_info *info,
const unsigned short *s, int count, int yy, int xx,
int fg, int bg)
{
- struct fb_image image;
- u32 width = DIV_ROUND_UP(vc->vc_font.width, 8);
- u32 cellsize = width * vc->vc_font.height;
- u32 maxcnt = info->pixmap.size/cellsize;
- u32 scan_align = info->pixmap.scan_align - 1;
- u32 buf_align = info->pixmap.buf_align - 1;
- u32 mod = vc->vc_font.width % 8, cnt, pitch, size;
+ u16 *buf;
+ int i;
u32 attribute = get_attribute(info, scr_readw(s));
- u8 *dst, *buf = NULL;
- image.fg_color = fg;
- image.bg_color = bg;
- image.dx = xx * vc->vc_font.width;
- image.dy = yy * vc->vc_font.height;
- image.height = vc->vc_font.height;
- image.depth = 1;
+ buf = kmalloc(sizeof(*buf) * count, GFP_KERNEL);
+ if (!buf)
+ return;
- if (attribute) {
- buf = kmalloc(cellsize, GFP_KERNEL);
- if (!buf)
- return;
- }
-
- while (count) {
- if (count > maxcnt)
- cnt = maxcnt;
- else
- cnt = count;
-
- image.width = vc->vc_font.width * cnt;
- pitch = DIV_ROUND_UP(image.width, 8) + scan_align;
- pitch &= ~scan_align;
- size = pitch * image.height + buf_align;
- size &= ~buf_align;
- dst = fb_get_buffer_offset(info, &info->pixmap, size);
- image.data = dst;
-
- if (!mod)
- bit_putcs_aligned(vc, info, s, attribute, cnt, pitch,
- width, cellsize, &image, buf, dst);
- else
- bit_putcs_unaligned(vc, info, s, attribute, cnt,
- pitch, width, cellsize, &image,
- buf, dst);
-
- image.dx += cnt * vc->vc_font.width;
- count -= cnt;
- s += cnt;
- }
+ for (i = 0; i < count; ++i)
+ buf[i] = scr_readw(s++);
- /* buf is always NULL except when in monochrome mode, so in this case
- it's a gain to check buf against NULL even though kfree() handles
- NULL pointers just fine */
- if (unlikely(buf))
- kfree(buf);
+ fbdraw_font(info, &vc->vc_font, vc->vc_hi_font_mask, xx, yy, fg, bg,
+ attribute, buf, count);
+ kfree(buf);
}
static void bit_clear_margins(struct vc_data *vc, struct fb_info *info,
diff --git a/drivers/video/console/fbdraw.c b/drivers/video/console/fbdraw.c
index 65e7003..e2e0661 100644
--- a/drivers/video/console/fbdraw.c
+++ b/drivers/video/console/fbdraw.c
@@ -41,6 +41,131 @@ void fbdraw_update_attr(u8 *dst, const u8 *src, int attribute,
}
EXPORT_SYMBOL(fbdraw_update_attr);
+static inline void bit_putcs_aligned(struct fb_info *info, bool hi_font,
+ struct console_font *font, u32 attribute,
+ u32 d_pitch, u32 s_pitch, u32 cellsize,
+ struct fb_image *image, u8 *buf, u8 *dst,
+ const u16 *chars, size_t cnt)
+{
+ u16 charmask = hi_font ? 0x1ff : 0xff;
+ u32 idx = font->width >> 3;
+ u8 *src;
+
+ while (cnt--) {
+ src = font->data + ((*chars++) & charmask) * cellsize;
+
+ if (attribute) {
+ fbdraw_update_attr(buf, src, attribute, font);
+ src = buf;
+ }
+
+ if (likely(idx = 1))
+ __fb_pad_aligned_buffer(dst, d_pitch, src, idx,
+ image->height);
+ else
+ fb_pad_aligned_buffer(dst, d_pitch, src, idx,
+ image->height);
+
+ dst += s_pitch;
+ }
+
+ info->fbops->fb_imageblit(info, image);
+}
+
+static inline void bit_putcs_unaligned(struct fb_info *info, bool hi_font,
+ struct console_font *font, u32 attribute,
+ u32 d_pitch, u32 s_pitch, u32 cellsize,
+ struct fb_image *image, u8 *buf, u8 *dst,
+ const u16 *chars, size_t cnt)
+{
+ u16 charmask = hi_font ? 0x1ff : 0xff;
+ u32 shift_low = 0, mod = font->width % 8;
+ u32 shift_high = 8;
+ u32 idx = font->width >> 3;
+ u8 *src;
+
+ while (cnt--) {
+ src = font->data + ((*chars++) & charmask) * cellsize;
+
+ if (attribute) {
+ fbdraw_update_attr(buf, src, attribute, font);
+ src = buf;
+ }
+
+ fb_pad_unaligned_buffer(dst, d_pitch, src, idx,
+ image->height, shift_high,
+ shift_low, mod);
+ shift_low += mod;
+ dst += (shift_low >= 8) ? s_pitch : s_pitch - 1;
+ shift_low &= 7;
+ shift_high = 8 - shift_low;
+ }
+
+ info->fbops->fb_imageblit(info, image);
+}
+
+void fbdraw_font(struct fb_info *info, struct console_font *font, bool hi_font,
+ unsigned int xpos, unsigned int ypos, int fg, int bg,
+ u32 attribute, const u16 *chars, size_t count)
+{
+ struct fb_image image;
+ u32 width = DIV_ROUND_UP(font->width, 8);
+ u32 cellsize = width * font->height;
+ u32 maxcnt = info->pixmap.size / cellsize;
+ u32 scan_align = info->pixmap.scan_align - 1;
+ u32 buf_align = info->pixmap.buf_align - 1;
+ u32 mod = font->width % 8, cnt, pitch, size;
+ u8 *dst, *buf = NULL;
+
+ image.fg_color = fg;
+ image.bg_color = bg;
+ image.dx = xpos * font->width;
+ image.dy = ypos * font->height;
+ image.height = font->height;
+ image.depth = 1;
+
+ if (attribute) {
+ buf = kmalloc(cellsize, GFP_KERNEL);
+ if (!buf)
+ return;
+ }
+
+ while (count) {
+ if (count > maxcnt)
+ cnt = maxcnt;
+ else
+ cnt = count;
+
+ image.width = font->width * cnt;
+ pitch = DIV_ROUND_UP(image.width, 8) + scan_align;
+ pitch &= ~scan_align;
+ size = pitch * image.height + buf_align;
+ size &= ~buf_align;
+ dst = fb_get_buffer_offset(info, &info->pixmap, size);
+ image.data = dst;
+
+ if (!mod)
+ bit_putcs_aligned(info, hi_font, font, attribute,
+ pitch, width, cellsize, &image, buf,
+ dst, chars, cnt);
+ else
+ bit_putcs_unaligned(info, hi_font, font, attribute,
+ pitch, width, cellsize, &image, buf,
+ dst, chars, cnt);
+
+ image.dx += cnt * font->width;
+ count -= cnt;
+ chars += cnt;
+ }
+
+ /* buf is always NULL except when in monochrome mode, so in this case
+ it's a gain to check buf against NULL even though kfree() handles
+ NULL pointers just fine */
+ if (unlikely(buf))
+ kfree(buf);
+}
+EXPORT_SYMBOL(fbdraw_font);
+
MODULE_LICENSE("GPL v2");
MODULE_AUTHOR("David Herrmann <dh.herrmann@googlemail.com>");
MODULE_DESCRIPTION("Framebuffer helpers for image draw-operations");
diff --git a/drivers/video/console/fbdraw.h b/drivers/video/console/fbdraw.h
index 77edd7f..b9f1ffa 100644
--- a/drivers/video/console/fbdraw.h
+++ b/drivers/video/console/fbdraw.h
@@ -23,4 +23,8 @@
void fbdraw_update_attr(u8 *dst, const u8 *src, int attribute,
struct console_font *font);
+void fbdraw_font(struct fb_info *info, struct console_font *font, bool hi_font,
+ unsigned int xpos, unsigned int ypos, int fg, int bg,
+ u32 attribute, const u16 *chars, size_t count);
+
#endif /* _VIDEO_FBDRAW_H */
--
1.7.11.1
^ permalink raw reply related
* [PATCH v2 03/11] fblog: new framebuffer kernel log dummy driver
From: David Herrmann @ 2012-07-08 21:56 UTC (permalink / raw)
To: linux-serial
Cc: linux-kernel, florianschandinat, linux-fbdev, gregkh, alan,
bonbons, David Herrmann
In-Reply-To: <1341784614-2797-1-git-send-email-dh.herrmann@googlemail.com>
Fblog displays all kernel log messages on all connected framebuffers. It
replaces fbcon when CONFIG_VT=n is selected. Its main purpose is to debug
boot problems by displaying the whole boot log on the screen. This patch
provides the first dummy module-init/deinit functions.
As it uses all the font and fb functions I placed it in
drivers/video/console. However, this means that we need to move the check
for CONFIG_VT in Makefile/Kconfig from drivers/video into
drivers/video/console as fblog does not depend on CONFIG_VT.
Signed-off-by: David Herrmann <dh.herrmann@googlemail.com>
---
drivers/video/Kconfig | 5 +----
drivers/video/Makefile | 2 +-
drivers/video/console/Kconfig | 37 +++++++++++++++++++++++++++++--------
drivers/video/console/Makefile | 1 +
drivers/video/console/fblog.c | 41 +++++++++++++++++++++++++++++++++++++++++
5 files changed, 73 insertions(+), 13 deletions(-)
create mode 100644 drivers/video/console/fblog.c
diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig
index 0217f74..e8fd53d 100644
--- a/drivers/video/Kconfig
+++ b/drivers/video/Kconfig
@@ -2448,10 +2448,7 @@ source "drivers/video/omap/Kconfig"
source "drivers/video/omap2/Kconfig"
source "drivers/video/exynos/Kconfig"
source "drivers/video/backlight/Kconfig"
-
-if VT
- source "drivers/video/console/Kconfig"
-endif
+source "drivers/video/console/Kconfig"
if FB || SGI_NEWPORT_CONSOLE
source "drivers/video/logo/Kconfig"
diff --git a/drivers/video/Makefile b/drivers/video/Makefile
index ee8dafb..9f8a7f0 100644
--- a/drivers/video/Makefile
+++ b/drivers/video/Makefile
@@ -11,7 +11,7 @@ fb-y := fbmem.o fbmon.o fbcmap.o fbsysfs.o \
modedb.o fbcvt.o
fb-objs := $(fb-y)
-obj-$(CONFIG_VT) += console/
+obj-y += console/
obj-$(CONFIG_LOGO) += logo/
obj-y += backlight/
diff --git a/drivers/video/console/Kconfig b/drivers/video/console/Kconfig
index e2c96d0..7374362 100644
--- a/drivers/video/console/Kconfig
+++ b/drivers/video/console/Kconfig
@@ -6,7 +6,7 @@ menu "Console display driver support"
config VGA_CONSOLE
bool "VGA text console" if EXPERT || !X86
- depends on !4xx && !8xx && !SPARC && !M68K && !PARISC && !FRV && !SUPERH && !BLACKFIN && !AVR32 && !MN10300 && (!ARM || ARCH_FOOTBRIDGE || ARCH_INTEGRATOR || ARCH_NETWINDER)
+ depends on VT && !4xx && !8xx && !SPARC && !M68K && !PARISC && !FRV && !SUPERH && !BLACKFIN && !AVR32 && !MN10300 && (!ARM || ARCH_FOOTBRIDGE || ARCH_INTEGRATOR || ARCH_NETWINDER)
default y
help
Saying Y here will allow you to use Linux in text mode through a
@@ -45,7 +45,7 @@ config VGACON_SOFT_SCROLLBACK_SIZE
screenfuls of scrollback buffer
config MDA_CONSOLE
- depends on !M68K && !PARISC && ISA
+ depends on VT && !M68K && !PARISC && ISA
tristate "MDA text console (dual-headed) (EXPERIMENTAL)"
---help---
Say Y here if you have an old MDA or monochrome Hercules graphics
@@ -61,14 +61,14 @@ config MDA_CONSOLE
config SGI_NEWPORT_CONSOLE
tristate "SGI Newport Console support"
- depends on SGI_IP22
+ depends on VT && SGI_IP22
help
Say Y here if you want the console on the Newport aka XL graphics
card of your Indy. Most people say Y here.
config DUMMY_CONSOLE
bool
- depends on VGA_CONSOLE!=y || SGI_NEWPORT_CONSOLE!=y
+ depends on VT && (VGA_CONSOLE!=y || SGI_NEWPORT_CONSOLE!=y)
default y
config DUMMY_CONSOLE_COLUMNS
@@ -89,7 +89,7 @@ config DUMMY_CONSOLE_ROWS
config FRAMEBUFFER_CONSOLE
tristate "Framebuffer Console support"
- depends on FB
+ depends on VT && FB
select CRC32
help
Low-level framebuffer-based console driver.
@@ -122,16 +122,37 @@ config FRAMEBUFFER_CONSOLE_ROTATION
config STI_CONSOLE
bool "STI text console"
- depends on PARISC
+ depends on VT && PARISC
default y
help
The STI console is the builtin display/keyboard on HP-PARISC
machines. Say Y here to build support for it into your kernel.
The alternative is to use your primary serial port as a console.
+config FBLOG
+ tristate "Framebuffer Kernel Log Driver"
+ depends on !VT && FB
+ default n
+ help
+ This driver displays all kernel log messages on all connected
+ framebuffers. It is mutually exclusive with CONFIG_FRAMEBUFFER_CONSOLE
+ and CONFIG_VT. It was mainly created for debugging purposes when
+ CONFIG_VT is not selected but you still want kernel boot messages on
+ the screen.
+
+ This driver overwrites all other graphics output on the framebuffer as
+ long as it is active so the kernel log will always be visible. You
+ need to disable this driver via sysfs to be able to start another
+ graphics application.
+
+ If unsure, say N.
+
+ To compile this driver as a module, choose M here: the module will
+ be called fblog.
+
config FONTS
bool "Select compiled-in fonts"
- depends on FRAMEBUFFER_CONSOLE || STI_CONSOLE
+ depends on FRAMEBUFFER_CONSOLE || STI_CONSOLE || FBLOG
help
Say Y here if you would like to use fonts other than the default
your frame buffer console usually use.
@@ -158,7 +179,7 @@ config FONT_8x8
config FONT_8x16
bool "VGA 8x16 font" if FONTS
- depends on FRAMEBUFFER_CONSOLE || SGI_NEWPORT_CONSOLE || STI_CONSOLE || USB_SISUSBVGA_CON
+ depends on FRAMEBUFFER_CONSOLE || SGI_NEWPORT_CONSOLE || STI_CONSOLE || USB_SISUSBVGA_CON || FBLOG
default y if !SPARC && !FONTS
help
This is the "high resolution" font for the VGA frame buffer (the one
diff --git a/drivers/video/console/Makefile b/drivers/video/console/Makefile
index 9a52226..ec0e155 100644
--- a/drivers/video/console/Makefile
+++ b/drivers/video/console/Makefile
@@ -20,6 +20,7 @@ font-objs += $(font-objs-y)
# Each configuration option enables a list of files.
+obj-$(CONFIG_FBLOG) += fblog.o font.o
obj-$(CONFIG_DUMMY_CONSOLE) += dummycon.o
obj-$(CONFIG_SGI_NEWPORT_CONSOLE) += newport_con.o font.o
obj-$(CONFIG_STI_CONSOLE) += sticon.o sticore.o font.o
diff --git a/drivers/video/console/fblog.c b/drivers/video/console/fblog.c
new file mode 100644
index 0000000..fb39737
--- /dev/null
+++ b/drivers/video/console/fblog.c
@@ -0,0 +1,41 @@
+/*
+ * Framebuffer Kernel Log Driver
+ * Copyright (c) 2012 David Herrmann <dh.herrmann@googlemail.com>
+ */
+
+/*
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ */
+
+/*
+ * Framebuffer Kernel Log
+ * This driver prints the kernel log to all connected display devices. It
+ * replaces CONFIG_VT and cannot run simultaneously with it. It does not provide
+ * any virtual-terminal, though. It should only be used to get kernel boot
+ * messages to debug kernel errors.
+ * Hence, this driver is neither optimized for speed, nor does it provide any
+ * fancy features like colored text output.
+ * This driver forcibly writes to the framebuffer while active, therefore, you
+ * cannot run other graphics applications simultaneously. You need to disable
+ * all fblog instances before running other graphics applications.
+ */
+
+#include <linux/module.h>
+
+static int __init fblog_init(void)
+{
+ return 0;
+}
+
+static void __exit fblog_exit(void)
+{
+}
+
+module_init(fblog_init);
+module_exit(fblog_exit);
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("David Herrmann <dh.herrmann@googlemail.com>");
+MODULE_DESCRIPTION("Framebuffer Kernel Log Driver");
--
1.7.11.1
^ permalink raw reply related
* [PATCH v2 04/11] fbdev: export get_fb_info()/put_fb_info()
From: David Herrmann @ 2012-07-08 21:56 UTC (permalink / raw)
To: linux-serial
Cc: linux-kernel, florianschandinat, linux-fbdev, gregkh, alan,
bonbons, David Herrmann
In-Reply-To: <1341784614-2797-1-git-send-email-dh.herrmann@googlemail.com>
When adding other internal users of the framebuffer subsystem, we need a
way to get references to framebuffers. These two functions already exist
so export them.
Signed-off-by: David Herrmann <dh.herrmann@googlemail.com>
---
drivers/video/fbmem.c | 6 ++++--
include/linux/fb.h | 3 +++
2 files changed, 7 insertions(+), 2 deletions(-)
diff --git a/drivers/video/fbmem.c b/drivers/video/fbmem.c
index 0dff12a..474460c 100644
--- a/drivers/video/fbmem.c
+++ b/drivers/video/fbmem.c
@@ -46,7 +46,7 @@ static DEFINE_MUTEX(registration_lock);
struct fb_info *registered_fb[FB_MAX] __read_mostly;
int num_registered_fb __read_mostly;
-static struct fb_info *get_fb_info(unsigned int idx)
+struct fb_info *get_fb_info(unsigned int idx)
{
struct fb_info *fb_info;
@@ -61,14 +61,16 @@ static struct fb_info *get_fb_info(unsigned int idx)
return fb_info;
}
+EXPORT_SYMBOL(get_fb_info);
-static void put_fb_info(struct fb_info *fb_info)
+void put_fb_info(struct fb_info *fb_info)
{
if (!atomic_dec_and_test(&fb_info->count))
return;
if (fb_info->fbops->fb_destroy)
fb_info->fbops->fb_destroy(fb_info);
}
+EXPORT_SYMBOL(put_fb_info);
int lock_fb_info(struct fb_info *info)
{
diff --git a/include/linux/fb.h b/include/linux/fb.h
index ac3f1c6..2d51c0e 100644
--- a/include/linux/fb.h
+++ b/include/linux/fb.h
@@ -1033,6 +1033,9 @@ static inline void unlock_fb_info(struct fb_info *info)
mutex_unlock(&info->lock);
}
+extern struct fb_info *get_fb_info(unsigned int idx);
+extern void put_fb_info(struct fb_info *fb_info);
+
static inline void __fb_pad_aligned_buffer(u8 *dst, u32 d_pitch,
u8 *src, u32 s_pitch, u32 height)
{
--
1.7.11.1
^ permalink raw reply related
* [PATCH v2 05/11] fblog: register one fblog object per framebuffer
From: David Herrmann @ 2012-07-08 21:56 UTC (permalink / raw)
To: linux-serial
Cc: linux-kernel, florianschandinat, linux-fbdev, gregkh, alan,
bonbons, David Herrmann
In-Reply-To: <1341784614-2797-1-git-send-email-dh.herrmann@googlemail.com>
One fblog object is associated to each registered framebuffer. This way,
we can draw the console to each framebuffer. When a framebuffer driver
unregisters a framebuffer, we also unregister our fblog object. That is,
our lifetime is coupled to the lifetime of the framebuffer. However, this
does not mean that we are always active. On the contrary, we do not even
own a reference to the framebuffer. We don't need it as we are notified
_before_ the last reference is dropped.
However, if other users have a reference to our object, we simply mark it
as dead when the associated framebuffer dies and leave it alone. When the
last reference is dropped, it will be automatically freed.
Signed-off-by: David Herrmann <dh.herrmann@googlemail.com>
---
drivers/video/console/fblog.c | 189 ++++++++++++++++++++++++++++++++++++++++++
1 file changed, 189 insertions(+)
diff --git a/drivers/video/console/fblog.c b/drivers/video/console/fblog.c
index fb39737..3e0b471 100644
--- a/drivers/video/console/fblog.c
+++ b/drivers/video/console/fblog.c
@@ -23,15 +23,204 @@
* all fblog instances before running other graphics applications.
*/
+#include <linux/device.h>
+#include <linux/fb.h>
#include <linux/module.h>
+#include <linux/mutex.h>
+
+enum fblog_flags {
+ FBLOG_KILLED,
+};
+
+struct fblog_fb {
+ unsigned long flags;
+ struct fb_info *info;
+ struct device dev;
+};
+
+static DEFINE_MUTEX(fblog_registration_lock);
+static struct fblog_fb *fblog_fbs[FB_MAX];
+
+#define to_fblog_dev(_d) container_of(_d, struct fblog_fb, dev)
+
+/*
+ * fblog framebuffer list
+ * The fblog_fbs[] array contains all currently registered framebuffers. If a
+ * framebuffer is in that list, we always must make sure that we own a reference
+ * to it. If it is added through the notifier callbacks, then this is always
+ * guaranteed.
+ * We are only interested in registered framebuffers. That is, if a driver calls
+ * unregister_framebuffer() we directly unlink it from our list. This guarantees
+ * that the associated fb_info is always valid. However, we might still have
+ * pending users so we mark it as dead so no further framebuffer actions are
+ * done. If the last user then drops a reference, the memory gets freed
+ * automatically.
+ */
+
+static void fblog_release(struct device *dev)
+{
+ struct fblog_fb *fb = to_fblog_dev(dev);
+
+ kfree(fb);
+ module_put(THIS_MODULE);
+}
+
+static void fblog_do_unregister(struct fb_info *info)
+{
+ struct fblog_fb *fb;
+
+ fb = fblog_fbs[info->node];
+ if (!fb || fb->info != info)
+ return;
+
+ fblog_fbs[info->node] = NULL;
+
+ device_del(&fb->dev);
+ put_device(&fb->dev);
+}
+
+static void fblog_do_register(struct fb_info *info, bool force)
+{
+ struct fblog_fb *fb;
+ int ret;
+
+ fb = fblog_fbs[info->node];
+ if (fb && fb->info != info) {
+ if (!force)
+ return;
+
+ fblog_do_unregister(fb->info);
+ }
+
+ fb = kzalloc(sizeof(*fb), GFP_KERNEL);
+ if (!fb)
+ return;
+
+ fb->info = info;
+ __module_get(THIS_MODULE);
+ device_initialize(&fb->dev);
+ fb->dev.class = fb_class;
+ fb->dev.release = fblog_release;
+ dev_set_name(&fb->dev, "fblog%d", info->node);
+ fblog_fbs[info->node] = fb;
+
+ ret = device_add(&fb->dev);
+ if (ret) {
+ fblog_fbs[info->node] = NULL;
+ set_bit(FBLOG_KILLED, &fb->flags);
+ put_device(&fb->dev);
+ return;
+ }
+}
+
+static void fblog_register(struct fb_info *info, bool force)
+{
+ mutex_lock(&fblog_registration_lock);
+ fblog_do_register(info, force);
+ mutex_unlock(&fblog_registration_lock);
+}
+
+static void fblog_unregister(struct fb_info *info)
+{
+ mutex_lock(&fblog_registration_lock);
+ fblog_do_unregister(info);
+ mutex_unlock(&fblog_registration_lock);
+}
+
+static int fblog_event(struct notifier_block *self, unsigned long action,
+ void *data)
+{
+ struct fb_event *event = data;
+ struct fb_info *info = event->info;
+
+ switch(action) {
+ case FB_EVENT_FB_REGISTERED:
+ /* This is called when a low-level system driver registers a new
+ * framebuffer. The registration lock is held but the console
+ * lock might not be held when this is called. */
+ fblog_register(info, true);
+ break;
+ case FB_EVENT_FB_UNREGISTERED:
+ /* This is called when a low-level system driver unregisters a
+ * framebuffer. The registration lock is held but the console
+ * lock might not be held. */
+ fblog_unregister(info);
+ break;
+ }
+
+ return 0;
+}
+
+static void fblog_scan(void)
+{
+ unsigned int i;
+ struct fb_info *info, *tmp;
+
+ for (i = 0; i < FB_MAX; ++i) {
+ info = get_fb_info(i);
+ if (!info || IS_ERR(info))
+ continue;
+
+ fblog_register(info, false);
+
+ /* There is a very subtle race-condition. Even though we might
+ * own a reference to the fb, it may still get unregistered
+ * between our call from get_fb_info() and fblog_register().
+ * Therefore, we simply check whether the same fb still is
+ * registered by calling get_fb_info() again. Only if they
+ * differ we know that it got unregistered, therefore, we
+ * call fblog_unregister() with the old pointer. */
+
+ tmp = get_fb_info(i);
+ if (tmp && !IS_ERR(tmp))
+ put_fb_info(tmp);
+ if (tmp != info)
+ fblog_unregister(info);
+
+ /* Here we either called fblog_unregister() and therefore do not
+ * need any reference to the fb, or we can be sure that the FB
+ * is registered and FB_EVENT_FB_UNREGISTERED will be called
+ * before the last reference is dropped. Hence, we can drop our
+ * reference here. */
+
+ put_fb_info(info);
+ }
+}
+
+static struct notifier_block fblog_notifier = {
+ .notifier_call = fblog_event,
+};
static int __init fblog_init(void)
{
+ int ret;
+
+ ret = fb_register_client(&fblog_notifier);
+ if (ret) {
+ pr_err("fblog: cannot register framebuffer notifier");
+ return ret;
+ }
+
+ fblog_scan();
+
return 0;
}
static void __exit fblog_exit(void)
{
+ unsigned int i;
+ struct fb_info *info;
+
+ fb_unregister_client(&fblog_notifier);
+
+ for (i = 0; i < FB_MAX; ++i) {
+ info = get_fb_info(i);
+ if (!info || IS_ERR(info))
+ continue;
+
+ fblog_unregister(info);
+ put_fb_info(info);
+ }
}
module_init(fblog_init);
--
1.7.11.1
^ permalink raw reply related
* [PATCH v2 06/11] fblog: open fb on registration
From: David Herrmann @ 2012-07-08 21:56 UTC (permalink / raw)
To: linux-serial
Cc: linux-kernel, florianschandinat, linux-fbdev, gregkh, alan,
bonbons, David Herrmann
In-Reply-To: <1341784614-2797-1-git-send-email-dh.herrmann@googlemail.com>
This opens the framebuffer upon registration so we can use it for
drawing-operations. On unregistration we close it again.
To avoid deadlocks, we need to tell fblog_open/close() whether the
framebuffer is currently locked. This is because some fb-notifiers are
called with the lock held and others without it. We cannot release it in
the notifier as this might confuse other registered callbacks if they
actually depend on the lock to be continously held (such a callback is
currently no available in the kernel, but may be added some time later).
Signed-off-by: David Herrmann <dh.herrmann@googlemail.com>
---
drivers/video/console/fblog.c | 91 +++++++++++++++++++++++++++++++++++++++++++
1 file changed, 91 insertions(+)
diff --git a/drivers/video/console/fblog.c b/drivers/video/console/fblog.c
index 3e0b471..113be36 100644
--- a/drivers/video/console/fblog.c
+++ b/drivers/video/console/fblog.c
@@ -30,12 +30,14 @@
enum fblog_flags {
FBLOG_KILLED,
+ FBLOG_OPEN,
};
struct fblog_fb {
unsigned long flags;
struct fb_info *info;
struct device dev;
+ struct mutex lock;
};
static DEFINE_MUTEX(fblog_registration_lock);
@@ -43,6 +45,77 @@ static struct fblog_fb *fblog_fbs[FB_MAX];
#define to_fblog_dev(_d) container_of(_d, struct fblog_fb, dev)
+static int fblog_open(struct fblog_fb *fb, bool locked)
+{
+ int ret;
+
+ mutex_lock(&fb->lock);
+
+ if (test_bit(FBLOG_KILLED, &fb->flags)) {
+ ret = -ENODEV;
+ goto unlock;
+ }
+
+ if (test_bit(FBLOG_OPEN, &fb->flags)) {
+ ret = 0;
+ goto unlock;
+ }
+
+ if (!locked)
+ mutex_lock(&fb->info->lock);
+
+ if (!try_module_get(fb->info->fbops->owner)) {
+ ret = -ENODEV;
+ goto out_killed;
+ }
+
+ if (fb->info->fbops->fb_open && fb->info->fbops->fb_open(fb->info, 0)) {
+ ret = -EIO;
+ goto out_unref;
+ }
+
+ if (!locked)
+ mutex_unlock(&fb->info->lock);
+
+ set_bit(FBLOG_OPEN, &fb->flags);
+ mutex_unlock(&fb->lock);
+ return 0;
+
+out_unref:
+ module_put(fb->info->fbops->owner);
+out_killed:
+ if (!locked)
+ mutex_unlock(&fb->info->lock);
+ set_bit(FBLOG_KILLED, &fb->flags);
+unlock:
+ mutex_unlock(&fb->lock);
+ return ret;
+}
+
+static void fblog_close(struct fblog_fb *fb, bool kill_dev, bool locked)
+{
+ mutex_lock(&fb->lock);
+
+ if (test_bit(FBLOG_OPEN, &fb->flags)) {
+ if (!locked)
+ mutex_lock(&fb->info->lock);
+
+ if (fb->info->fbops->fb_release)
+ fb->info->fbops->fb_release(fb->info, 0);
+ module_put(fb->info->fbops->owner);
+
+ if (!locked)
+ mutex_unlock(&fb->info->lock);
+
+ clear_bit(FBLOG_OPEN, &fb->flags);
+ }
+
+ if (kill_dev)
+ set_bit(FBLOG_KILLED, &fb->flags);
+
+ mutex_unlock(&fb->lock);
+}
+
/*
* fblog framebuffer list
* The fblog_fbs[] array contains all currently registered framebuffers. If a
@@ -75,6 +148,7 @@ static void fblog_do_unregister(struct fb_info *info)
fblog_fbs[info->node] = NULL;
+ fblog_close(fb, true, false);
device_del(&fb->dev);
put_device(&fb->dev);
}
@@ -97,6 +171,7 @@ static void fblog_do_register(struct fb_info *info, bool force)
return;
fb->info = info;
+ mutex_init(&fb->lock);
__module_get(THIS_MODULE);
device_initialize(&fb->dev);
fb->dev.class = fb_class;
@@ -111,6 +186,8 @@ static void fblog_do_register(struct fb_info *info, bool force)
put_device(&fb->dev);
return;
}
+
+ fblog_open(fb, true);
}
static void fblog_register(struct fb_info *info, bool force)
@@ -132,6 +209,7 @@ static int fblog_event(struct notifier_block *self, unsigned long action,
{
struct fb_event *event = data;
struct fb_info *info = event->info;
+ struct fblog_fb *fb;
switch(action) {
case FB_EVENT_FB_REGISTERED:
@@ -146,6 +224,17 @@ static int fblog_event(struct notifier_block *self, unsigned long action,
* lock might not be held. */
fblog_unregister(info);
break;
+ case FB_EVENT_FB_UNBIND:
+ /* Called directly before unregistering an FB. The FB is still
+ * valid here and the registration lock is held but the console
+ * lock might not be held (really?). */
+ mutex_lock(&fblog_registration_lock);
+ fb = fblog_fbs[info->node];
+ mutex_unlock(&fblog_registration_lock);
+
+ if (fb)
+ fblog_close(fb, true, true);
+ break;
}
return 0;
@@ -161,7 +250,9 @@ static void fblog_scan(void)
if (!info || IS_ERR(info))
continue;
+ mutex_lock(&info->lock);
fblog_register(info, false);
+ mutex_unlock(&info->lock);
/* There is a very subtle race-condition. Even though we might
* own a reference to the fb, it may still get unregistered
--
1.7.11.1
^ permalink raw reply related
* [PATCH v2 07/11] fblog: allow selecting fbs via sysfs
From: David Herrmann @ 2012-07-08 21:56 UTC (permalink / raw)
To: linux-serial
Cc: linux-kernel, florianschandinat, linux-fbdev, gregkh, alan,
bonbons, David Herrmann
In-Reply-To: <1341784614-2797-1-git-send-email-dh.herrmann@googlemail.com>
fblog is mainly useful during boot, reboot, panics and maintenance. In all
cases you often want to control which monitors are used for console
output. Moreover, in multi-seat environments it is desireable to reduce
system-overhead by not drawing the console to all framebuffers. Two
mechanisms to select framebuffers for fblog are added:
1) "active" module parameter: This parameter selects whether new
framebuffers are opened automatically. By default this is on, that is, all
framebuffers are automatically used by fblog during boot. By passing
fblog.active=0 you can deactivate this.
The init process can set this to 0 via
/sys/modules/fblog/parameters/active, too. However, this does not affect
already available and used framebuffers in any way.
2) "active" sysfs attribute for each fblog object. Reading this value
returns whether a framebuffer is currently active. Writing it opens/closes
the framebuffer. This allows runtime control which fbs are used. For
instance, init can set these to 0 after bootup.
Signed-off-by: David Herrmann <dh.herrmann@googlemail.com>
---
drivers/video/console/fblog.c | 50 ++++++++++++++++++++++++++++++++++++++++++-
1 file changed, 49 insertions(+), 1 deletion(-)
diff --git a/drivers/video/console/fblog.c b/drivers/video/console/fblog.c
index 113be36..b490dba 100644
--- a/drivers/video/console/fblog.c
+++ b/drivers/video/console/fblog.c
@@ -42,6 +42,7 @@ struct fblog_fb {
static DEFINE_MUTEX(fblog_registration_lock);
static struct fblog_fb *fblog_fbs[FB_MAX];
+static bool active = 1;
#define to_fblog_dev(_d) container_of(_d, struct fblog_fb, dev)
@@ -116,6 +117,37 @@ static void fblog_close(struct fblog_fb *fb, bool kill_dev, bool locked)
mutex_unlock(&fb->lock);
}
+static ssize_t fblog_dev_active_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct fblog_fb *fb = to_fblog_dev(dev);
+
+ return snprintf(buf, PAGE_SIZE, "%d\n",
+ !!test_bit(FBLOG_OPEN, &fb->flags));
+}
+
+static ssize_t fblog_dev_active_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf,
+ size_t count)
+{
+ struct fblog_fb *fb = to_fblog_dev(dev);
+ unsigned long num;
+ int ret = 0;
+
+ num = simple_strtoul(buf, NULL, 10);
+ if (num)
+ ret = fblog_open(fb, false);
+ else
+ fblog_close(fb, false, false);
+
+ return ret ? ret : count;
+}
+
+static DEVICE_ATTR(active, S_IRUGO | S_IWUSR | S_IWGRP, fblog_dev_active_show,
+ fblog_dev_active_store);
+
/*
* fblog framebuffer list
* The fblog_fbs[] array contains all currently registered framebuffers. If a
@@ -149,6 +181,7 @@ static void fblog_do_unregister(struct fb_info *info)
fblog_fbs[info->node] = NULL;
fblog_close(fb, true, false);
+ device_remove_file(&fb->dev, &dev_attr_active);
device_del(&fb->dev);
put_device(&fb->dev);
}
@@ -157,6 +190,7 @@ static void fblog_do_register(struct fb_info *info, bool force)
{
struct fblog_fb *fb;
int ret;
+ bool do_open = true;
fb = fblog_fbs[info->node];
if (fb && fb->info != info) {
@@ -187,7 +221,18 @@ static void fblog_do_register(struct fb_info *info, bool force)
return;
}
- fblog_open(fb, true);
+ ret = device_create_file(&fb->dev, &dev_attr_active);
+ if (ret) {
+ pr_err("fblog: cannot create sysfs entry");
+ /* do not open fb if we cannot create control file */
+ do_open = false;
+ }
+
+ if (!active)
+ do_open = false;
+
+ if (do_open)
+ fblog_open(fb, true);
}
static void fblog_register(struct fb_info *info, bool force)
@@ -314,6 +359,9 @@ static void __exit fblog_exit(void)
}
}
+module_param(active, bool, S_IRUGO);
+MODULE_PARM_DESC(active, "Activate fblog by default");
+
module_init(fblog_init);
module_exit(fblog_exit);
MODULE_LICENSE("GPL");
--
1.7.11.1
^ permalink raw reply related
* [PATCH v2 08/11] fblog: cache framebuffer BLANK and SUSPEND states
From: David Herrmann @ 2012-07-08 21:56 UTC (permalink / raw)
To: linux-serial
Cc: linux-kernel, florianschandinat, linux-fbdev, gregkh, alan,
bonbons, David Herrmann
In-Reply-To: <1341784614-2797-1-git-send-email-dh.herrmann@googlemail.com>
We must cache these states so we will never draw to the framebuffer while
it is suspended or blanked.
Signed-off-by: David Herrmann <dh.herrmann@googlemail.com>
---
drivers/video/console/fblog.c | 41 +++++++++++++++++++++++++++++++++++++++++
1 file changed, 41 insertions(+)
diff --git a/drivers/video/console/fblog.c b/drivers/video/console/fblog.c
index b490dba..fd1f3d6 100644
--- a/drivers/video/console/fblog.c
+++ b/drivers/video/console/fblog.c
@@ -31,6 +31,8 @@
enum fblog_flags {
FBLOG_KILLED,
FBLOG_OPEN,
+ FBLOG_SUSPENDED,
+ FBLOG_BLANKED,
};
struct fblog_fb {
@@ -255,6 +257,7 @@ static int fblog_event(struct notifier_block *self, unsigned long action,
struct fb_event *event = data;
struct fb_info *info = event->info;
struct fblog_fb *fb;
+ int *blank;
switch(action) {
case FB_EVENT_FB_REGISTERED:
@@ -280,6 +283,44 @@ static int fblog_event(struct notifier_block *self, unsigned long action,
if (fb)
fblog_close(fb, true, true);
break;
+ case FB_EVENT_SUSPEND:
+ /* This is called when the low-level display driver suspends the
+ * video system. We should not access the video system while it
+ * is suspended. This is called with the console lock held. */
+ mutex_lock(&fblog_registration_lock);
+ fb = fblog_fbs[info->node];
+ mutex_unlock(&fblog_registration_lock);
+
+ if (fb)
+ set_bit(FBLOG_SUSPENDED, &fb->flags);
+ break;
+ case FB_EVENT_RESUME:
+ /* This is called when the low-level display driver resumes
+ * operating. It is called with the console lock held. */
+ mutex_lock(&fblog_registration_lock);
+ fb = fblog_fbs[info->node];
+ mutex_unlock(&fblog_registration_lock);
+
+ if (fb)
+ clear_bit(FBLOG_SUSPENDED, &fb->flags);
+ break;
+ case FB_EVENT_BLANK:
+ /* This gets called _after_ the framebuffer was successfully
+ * blanked. The console-lock is always held while fb_blank is
+ * called and during this callback. */
+ mutex_lock(&fblog_registration_lock);
+ fb = fblog_fbs[info->node];
+ mutex_unlock(&fblog_registration_lock);
+
+ if (!fb)
+ break;
+
+ blank = (int*)event->data;
+ if (*blank = FB_BLANK_UNBLANK)
+ clear_bit(FBLOG_BLANKED, &fb->flags);
+ else
+ set_bit(FBLOG_BLANKED, &fb->flags);
+ break;
}
return 0;
--
1.7.11.1
^ permalink raw reply related
* [PATCH v2 09/11] fblog: register console driver
From: David Herrmann @ 2012-07-08 21:56 UTC (permalink / raw)
To: linux-serial
Cc: linux-kernel, florianschandinat, linux-fbdev, gregkh, alan,
bonbons, David Herrmann
In-Reply-To: <1341784614-2797-1-git-send-email-dh.herrmann@googlemail.com>
We want to print the kernel log to all FBs so we need a console driver.
This registers the driver on startup and writes all messages to all
registered fblog instances.
We cannot share a console buffer between FBs because they might have
different resolutions. Therefore, we create one buffer per object. We
destroy the buffer during close() so we do not waste memory if it is not
used.
Signed-off-by: David Herrmann <dh.herrmann@googlemail.com>
---
drivers/video/console/fblog.c | 150 ++++++++++++++++++++++++++++++++++++++++++
1 file changed, 150 insertions(+)
diff --git a/drivers/video/console/fblog.c b/drivers/video/console/fblog.c
index fd1f3d6..e447f98 100644
--- a/drivers/video/console/fblog.c
+++ b/drivers/video/console/fblog.c
@@ -23,11 +23,34 @@
* all fblog instances before running other graphics applications.
*/
+#include <linux/console.h>
#include <linux/device.h>
#include <linux/fb.h>
#include <linux/module.h>
#include <linux/mutex.h>
+/**
+ * struct fblog_buf: Console text buffer
+ *
+ * Each framebuffer has its own text buffer which contains all characters that
+ * are currently printed on screen. The buffers might have different sizes and
+ * can be resized during runtime. When the buffer content changes, we redraw the
+ * screen.
+ *
+ * width: Width of buffer in characters
+ * height: Height of buffer in characters
+ * lines: Array of lines
+ * pos_x: Cursor x-position
+ * pos_y: Cursor y-position
+ */
+struct fblog_buf {
+ size_t width;
+ size_t height;
+ u16 **lines;
+ size_t pos_x;
+ size_t pos_y;
+};
+
enum fblog_flags {
FBLOG_KILLED,
FBLOG_OPEN,
@@ -40,6 +63,7 @@ struct fblog_fb {
struct fb_info *info;
struct device dev;
struct mutex lock;
+ struct fblog_buf buf;
};
static DEFINE_MUTEX(fblog_registration_lock);
@@ -47,6 +71,107 @@ static struct fblog_fb *fblog_fbs[FB_MAX];
static bool active = 1;
#define to_fblog_dev(_d) container_of(_d, struct fblog_fb, dev)
+#define FBLOG_STR(x) x, sizeof(x) - 1
+
+static void fblog_buf_resize(struct fblog_buf *buf, size_t width,
+ size_t height)
+{
+ u16 **lines = NULL;
+ size_t i, j, minw, minh;
+
+ if (buf->height = height && buf->width = width)
+ return;
+
+ if (width && height) {
+ lines = kzalloc(height * sizeof(char*), GFP_KERNEL);
+ if (!lines)
+ return;
+
+ for (i = 0; i < height; ++i) {
+ lines[i] = kzalloc(width * sizeof(u16), GFP_KERNEL);
+ if (!lines[i]) {
+ while (i--)
+ kfree(lines[i]);
+ return;
+ }
+ }
+
+ /* copy old lines */
+ minw = min(width, buf->width);
+ minh = min(height, buf->height);
+ if (height >= buf->height)
+ i = 0;
+ else
+ i = buf->height - height;
+
+ for (j = 0; j < minh; ++i, ++j)
+ memcpy(lines[j], buf->lines[i], minw * sizeof(u16));
+ } else {
+ width = 0;
+ height = 0;
+ }
+
+ for (i = 0; i < buf->height; ++i)
+ kfree(buf->lines[i]);
+ kfree(buf->lines);
+
+ buf->lines = lines;
+ buf->width = width;
+ buf->height = height;
+}
+
+static void fblog_buf_deinit(struct fblog_buf *buf)
+{
+ fblog_buf_resize(buf, 0, 0);
+}
+
+static void fblog_buf_rotate(struct fblog_buf *buf)
+{
+ u16 *line;
+
+ if (!buf->height)
+ return;
+
+ line = buf->lines[0];
+ memset(line, 0, sizeof(u16) * buf->width);
+
+ memmove(buf->lines, &buf->lines[1], sizeof(char*) * (buf->height - 1));
+ buf->lines[buf->height - 1] = line;
+}
+
+static void fblog_buf_write(struct fblog_buf *buf, const char *str, size_t len)
+{
+ char c;
+
+ if (!buf->height)
+ return;
+
+ while (len--) {
+ c = *str++;
+
+ if (c = 0)
+ c = '?';
+
+ if (c = '\n') {
+ buf->pos_x = 0;
+ if (++buf->pos_y >= buf->height) {
+ buf->pos_y = buf->height - 1;
+ fblog_buf_rotate(buf);
+ }
+ } else {
+ if (buf->pos_x >= buf->width) {
+ buf->pos_x = 0;
+ ++buf->pos_y;
+ }
+ if (buf->pos_y >= buf->height) {
+ buf->pos_y = buf->height - 1;
+ fblog_buf_rotate(buf);
+ }
+
+ buf->lines[buf->pos_y][buf->pos_x++] = c;
+ }
+ }
+}
static int fblog_open(struct fblog_fb *fb, bool locked)
{
@@ -80,6 +205,8 @@ static int fblog_open(struct fblog_fb *fb, bool locked)
if (!locked)
mutex_unlock(&fb->info->lock);
+ fblog_buf_resize(&fb->buf, 80, 24);
+ fblog_buf_write(&fb->buf, FBLOG_STR("Framebuffer log initialized\n"));
set_bit(FBLOG_OPEN, &fb->flags);
mutex_unlock(&fb->lock);
return 0;
@@ -111,6 +238,7 @@ static void fblog_close(struct fblog_fb *fb, bool kill_dev, bool locked)
mutex_unlock(&fb->info->lock);
clear_bit(FBLOG_OPEN, &fb->flags);
+ fblog_buf_deinit(&fb->buf);
}
if (kill_dev)
@@ -368,6 +496,26 @@ static struct notifier_block fblog_notifier = {
.notifier_call = fblog_event,
};
+static void fblog_con_write(struct console *con, const char *buf,
+ unsigned int len)
+{
+ int i;
+
+ mutex_lock(&fblog_registration_lock);
+ for (i = 0; i < FB_MAX; ++i) {
+ if (fblog_fbs[i]) {
+ fblog_buf_write(&fblog_fbs[i]->buf, buf, len);
+ }
+ }
+ mutex_unlock(&fblog_registration_lock);
+}
+
+static struct console fblog_con_driver = {
+ .name = "fblog",
+ .write = fblog_con_write,
+ .flags = CON_PRINTBUFFER | CON_ENABLED,
+};
+
static int __init fblog_init(void)
{
int ret;
@@ -379,6 +527,7 @@ static int __init fblog_init(void)
}
fblog_scan();
+ register_console(&fblog_con_driver);
return 0;
}
@@ -388,6 +537,7 @@ static void __exit fblog_exit(void)
unsigned int i;
struct fb_info *info;
+ unregister_console(&fblog_con_driver);
fb_unregister_client(&fblog_notifier);
for (i = 0; i < FB_MAX; ++i) {
--
1.7.11.1
^ permalink raw reply related
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox