Re: [PATCH 02/10] Check for ACPI backlight support otherwise use vendor ACPI drivers

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Fri, 2008-08-01 at 23:37 +0800, Thomas Renninger wrote:
> If an ACPI graphics device supports backlight brightness functions
> (cmp. with
> latest ACPI spec Appendix B), let the ACPI video driver control
> backlight and
> switch backlight control off in vendor specific ACPI drivers
> (asus_acpi,
> thinkpad_acpi, eeepc, fujitsu_laptop, msi_laptop, sony_laptop,
> acer-wmi).
> 
> Currently it is possible to load above drivers and let both poke on
> the
> brightness HW registers, the video and vendor specific ACPI drivers ->
> bad.
> 
> This patch provides the basic support to check for BIOS capabilities
> before
> driver loading time. Driver specific modifications are in separate
> follow up
> patches.
> 
> acpi_backlight=vendor/video
>       boot params forces video.ko or vendor specific drivers to keep
> its
>       fingers off backlight control even it would find needed
> functions.
>       The corresponding vendor specific driver be used then.
> 
> Signed-off-by: Thomas Renninger <trenn@xxxxxxx>
Acked-by: Zhang Rui <rui.zhang@xxxxxxxxx>

> ---
>  Documentation/kernel-parameters.txt |   13 ++
>  drivers/acpi/Makefile               |    5 +
>  drivers/acpi/scan.c                 |   32 +----
>  drivers/acpi/video.c                |   28 ++--
>  drivers/acpi/video_detect.c         |  268
> +++++++++++++++++++++++++++++++++++
>  include/linux/acpi.h                |   44 ++++++
>  6 files changed, 347 insertions(+), 43 deletions(-)
>  create mode 100644 drivers/acpi/video_detect.c
> 
> diff --git a/Documentation/kernel-parameters.txt
> b/Documentation/kernel-parameters.txt
> index 09ad745..0fea7c2 100644
> --- a/Documentation/kernel-parameters.txt
> +++ b/Documentation/kernel-parameters.txt
> @@ -194,6 +194,19 @@ and is between 256 and 4096 characters. It is
> defined in the file
>                         that require a timer override, but don't have
>                         HPET
> 
> +       acpi_backlight= [HW,ACPI]
> +                       acpi_backlight=vendor
> +                       acpi_backlight=video
> +                       If set to vendor, it enforces the use of a
> +                       vendor specific ACPI driver for backlight
> switching
> +                       (e.g. thinkpad_acpi, sony_acpi, etc.) instead
> +                       of the video.ko driver.
> +
> +       acpi_display_output=    [HW,ACPI]
> +                       acpi_display_output=vendor
> +                       acpi_display_output=video
> +                       See above.
> +
>         acpi.debug_layer=       [HW,ACPI]
>                         Format: <int>
>                         Each bit of the <int> indicates an ACPI debug
> layer,
> diff --git a/drivers/acpi/Makefile b/drivers/acpi/Makefile
> index 52a4cd4..6b7ad0f 100644
> --- a/drivers/acpi/Makefile
> +++ b/drivers/acpi/Makefile
> @@ -46,7 +46,12 @@ obj-$(CONFIG_ACPI_BUTTON)    += button.o
>  obj-$(CONFIG_ACPI_FAN)         += fan.o
>  obj-$(CONFIG_ACPI_DOCK)                += dock.o
>  obj-$(CONFIG_ACPI_BAY)         += bay.o
> +
>  obj-$(CONFIG_ACPI_VIDEO)       += video.o
> +ifdef CONFIG_ACPI_VIDEO
> +obj-y                          += video_detect.o
> +endif
> +
>  obj-y                          += pci_root.o pci_link.o pci_irq.o
> pci_bind.o
>  obj-$(CONFIG_ACPI_PCI_SLOT)    += pci_slot.o
>  obj-$(CONFIG_ACPI_POWER)       += power.o
> diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c
> index f3132aa..2dcb953 100644
> --- a/drivers/acpi/scan.c
> +++ b/drivers/acpi/scan.c
> @@ -901,36 +901,6 @@ static void acpi_device_get_busid(struct
> acpi_device *device,
>         }
>  }
> 
> -static int
> -acpi_video_bus_match(struct acpi_device *device)
> -{
> -       acpi_handle h_dummy;
> -
> -       if (!device)
> -               return -EINVAL;
> -
> -       /* Since there is no HID, CID for ACPI Video drivers, we have
> -        * to check well known required nodes for each feature we
> support.
> -        */
> -
> -       /* Does this device able to support video switching ? */
> -       if (ACPI_SUCCESS(acpi_get_handle(device->handle, "_DOD",
> &h_dummy)) &&
> -           ACPI_SUCCESS(acpi_get_handle(device->handle, "_DOS",
> &h_dummy)))
> -               return 0;
> -
> -       /* Does this device able to retrieve a video ROM ? */
> -       if (ACPI_SUCCESS(acpi_get_handle(device->handle, "_ROM",
> &h_dummy)))
> -               return 0;
> -
> -       /* Does this device able to configure which video head to be
> POSTed ? */
> -       if (ACPI_SUCCESS(acpi_get_handle(device->handle, "_VPO",
> &h_dummy)) &&
> -           ACPI_SUCCESS(acpi_get_handle(device->handle, "_GPD",
> &h_dummy)) &&
> -           ACPI_SUCCESS(acpi_get_handle(device->handle, "_SPD",
> &h_dummy)))
> -               return 0;
> -
> -       return -ENODEV;
> -}
> -
>  /*
>   * acpi_bay_match - see if a device is an ejectable driver bay
>   *
> @@ -1013,7 +983,7 @@ static void acpi_device_set_id(struct acpi_device
> *device,
>                    will get autoloaded and the device might still
> match
>                    against another driver.
>                 */
> -               if (ACPI_SUCCESS(acpi_video_bus_match(device)))
> +               if (acpi_is_video_device(device))
>                         cid_add = ACPI_VIDEO_HID;
>                 else if (ACPI_SUCCESS(acpi_bay_match(device)))
>                         cid_add = ACPI_BAY_HID;
> diff --git a/drivers/acpi/video.c b/drivers/acpi/video.c
> index 649888a..7abd326 100644
> --- a/drivers/acpi/video.c
> +++ b/drivers/acpi/video.c
> @@ -739,7 +739,8 @@ static void acpi_video_device_find_cap(struct
> acpi_video_device *device)
>                 device->cap._DSS = 1;
>         }
> 
> -       max_level = acpi_video_init_brightness(device);
> +       if (acpi_video_backlight_support())
> +               max_level = acpi_video_init_brightness(device);
> 
>         if (device->cap._BCL && device->cap._BCM && max_level > 0) {
>                 int result;
> @@ -786,18 +787,21 @@ static void acpi_video_device_find_cap(struct
> acpi_video_device *device)
>                         printk(KERN_ERR PREFIX "Create sysfs link\n");
> 
>         }
> -       if (device->cap._DCS && device->cap._DSS){
> -               static int count = 0;
> -               char *name;
> -               name = kzalloc(MAX_NAME_LEN, GFP_KERNEL);
> -               if (!name)
> -                       return;
> -               sprintf(name, "acpi_video%d", count++);
> -               device->output_dev = video_output_register(name,
> -                               NULL, device,
> &acpi_output_properties);
> -               kfree(name);
> +
> +       if (acpi_video_display_switch_support()) {
> +
> +               if (device->cap._DCS && device->cap._DSS) {
> +                       static int count;
> +                       char *name;
> +                       name = kzalloc(MAX_NAME_LEN, GFP_KERNEL);
> +                       if (!name)
> +                               return;
> +                       sprintf(name, "acpi_video%d", count++);
> +                       device->output_dev =
> video_output_register(name,
> +                                       NULL, device,
> &acpi_output_properties);
> +                       kfree(name);
> +               }
>         }
> -       return;
>  }
> 
>  /*
> diff --git a/drivers/acpi/video_detect.c b/drivers/acpi/video_detect.c
> new file mode 100644
> index 0000000..85c3d2c
> --- /dev/null
> +++ b/drivers/acpi/video_detect.c
> @@ -0,0 +1,268 @@
> +/*
> + *  Copyright (C) 2008       SuSE Linux Products GmbH
> + *                           Thomas Renninger <trenn@xxxxxxx>
> + *
> + *  May be copied or modified under the terms of the GNU General
> Public License
> + *
> + * video_detect.c:
> + * Provides acpi_is_video_device() for early scanning of ACPI devices
> in scan.c
> + * There a Linux specific (Spec does not provide a HID for video
> devices) is
> + * assinged
> + *
> + * After PCI devices are glued with ACPI devices
> + * acpi_get_physical_pci_device() can be called to identify ACPI
> graphics
> + * devices for which a real graphics card is plugged in
> + *
> + * Now acpi_video_get_capabilities() can be called to check which
> + * capabilities the graphics cards plugged in support. The check for
> general
> + * video capabilities will be triggered by the first caller of
> + * acpi_video_get_capabilities(NULL); which will happen when the
> first
> + * backlight (or display output) switching supporting driver calls:
> + * acpi_video_backlight_support();
> + *
> + * Depending on whether ACPI graphics extensions (cmp. ACPI spec
> Appendix B)
> + * are available, video.ko should be used to handle the device.
> + *
> + * Otherwise vendor specific drivers like thinkpad_acpi, asus_acpi,
> + * sony_acpi,... can take care about backlight brightness and display
> output
> + * switching.
> + *
> + * If CONFIG_ACPI_VIDEO is neither set as "compiled in" (y) nor as a
> module (m)
> + * this file will not be compiled, acpi_video_get_capabilities() and
> + * acpi_video_backlight_support() will always return 0 and vendor
> specific
> + * drivers always can handle backlight.
> + *
> + */
> +
> +#include <linux/acpi.h>
> +#include <linux/dmi.h>
> +
> +ACPI_MODULE_NAME("video");
> +#define ACPI_VIDEO_COMPONENT           0x08000000
> +#define _COMPONENT             ACPI_VIDEO_COMPONENT
> +
> +static long acpi_video_support;
> +static bool acpi_video_caps_checked;
> +
> +static acpi_status
> +acpi_backlight_cap_match(acpi_handle handle, u32 level, void
> *context,
> +                         void **retyurn_value)
> +{
> +       long *cap = context;
> +       acpi_handle h_dummy;
> +
> +       if (ACPI_SUCCESS(acpi_get_handle(handle, "_BCM", &h_dummy)) &&
> +           ACPI_SUCCESS(acpi_get_handle(handle, "_BCL", &h_dummy))) {
> +               ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Found generic
> backlight "
> +                                 "support\n"));
> +               *cap |= ACPI_VIDEO_BACKLIGHT;
> +               /* We have backlight support, no need to scan further
> */
> +               return AE_CTRL_TERMINATE;
> +       }
> +       return 0;
> +}
> +
> +/* Returns true if the device is a video device which can be handled
> by
> + * video.ko.
> + * The device will get a Linux specific CID added in scan.c to
> + * identify the device as an ACPI graphics device
> + * Be aware that the graphics device may not be physically present
> + * Use acpi_video_get_capabilities() to detect general ACPI video
> + * capabilities of present cards
> + */
> +long acpi_is_video_device(struct acpi_device *device)
> +{
> +       acpi_handle h_dummy;
> +       long video_caps = 0;
> +
> +       if (!device)
> +               return 0;
> +
> +       /* Does this device able to support video switching ? */
> +       if (ACPI_SUCCESS(acpi_get_handle(device->handle, "_DOD",
> &h_dummy)) &&
> +           ACPI_SUCCESS(acpi_get_handle(device->handle, "_DOS",
> &h_dummy)))
> +               video_caps |= ACPI_VIDEO_OUTPUT_SWITCHING;
> +
> +       /* Does this device able to retrieve a video ROM ? */
> +       if (ACPI_SUCCESS(acpi_get_handle(device->handle, "_ROM",
> &h_dummy)))
> +               video_caps |= ACPI_VIDEO_ROM_AVAILABLE;
> +
> +       /* Does this device able to configure which video head to be
> POSTed ? */
> +       if (ACPI_SUCCESS(acpi_get_handle(device->handle, "_VPO",
> &h_dummy)) &&
> +           ACPI_SUCCESS(acpi_get_handle(device->handle, "_GPD",
> &h_dummy)) &&
> +           ACPI_SUCCESS(acpi_get_handle(device->handle, "_SPD",
> &h_dummy)))
> +               video_caps |= ACPI_VIDEO_DEVICE_POSTING;
> +
> +       /* Only check for backlight functionality if one of the above
> hit. */
> +       if (video_caps)
> +               acpi_walk_namespace(ACPI_TYPE_DEVICE, device->handle,
> +                                   ACPI_UINT32_MAX,
> acpi_backlight_cap_match,
> +                                   &video_caps, NULL);
> +
> +       return video_caps;
> +}
> +EXPORT_SYMBOL(acpi_is_video_device);
> +
> +static acpi_status
> +find_video(acpi_handle handle, u32 lvl, void *context, void **rv)
> +{
> +       long *cap = context;
> +       struct device *dev;
> +       struct acpi_device *acpi_dev;
> +
> +       const struct acpi_device_id video_ids[] = {
> +               {ACPI_VIDEO_HID, 0},
> +               {"", 0},
> +       };
> +       if (acpi_bus_get_device(handle, &acpi_dev))
> +               return AE_OK;
> +
> +       if (!acpi_match_device_ids(acpi_dev, video_ids)) {
> +               dev = acpi_get_physical_pci_device(handle);
> +               if (!dev)
> +                       return AE_OK;
> +               put_device(dev);
> +               *cap |= acpi_is_video_device(acpi_dev);
> +       }
> +       return AE_OK;
> +}
> +
> +/*
> + * Returns the video capabilities of a specific ACPI graphics device
> + *
> + * if NULL is passed as argument all ACPI devices are enumerated and
> + * all graphics capabilities of physically present devices are
> + * summerized and returned. This is cached and done only once.
> + */
> +long acpi_video_get_capabilities(acpi_handle graphics_handle)
> +{
> +       long caps = 0;
> +       struct acpi_device *tmp_dev;
> +       acpi_status status;
> +
> +       if (acpi_video_caps_checked && graphics_handle == NULL)
> +               return acpi_video_support;
> +
> +       if (!graphics_handle) {
> +               /* Only do the global walk through all graphics
> devices once */
> +               acpi_walk_namespace(ACPI_TYPE_DEVICE,
> ACPI_ROOT_OBJECT,
> +                                   ACPI_UINT32_MAX, find_video,
> +                                   &caps, NULL);
> +               /* There might be boot param flags set already... */
> +               acpi_video_support |= caps;
> +               acpi_video_caps_checked = 1;
> +               /* Add blacklists here. Be careful to use the right
> *DMI* bits
> +                * to still be able to override logic via boot params,
> e.g.:
> +                *
> +                *   if (dmi_name_in_vendors("XY")) {
> +                *      acpi_video_support |=
> +                *
> ACPI_VIDEO_OUTPUT_SWITCHING_DMI_VENDOR;
> +                *      acpi_video_support |=
> +                *              ACPI_VIDEO_BACKLIGHT_DMI_VENDOR;
> +                *}
> +                */
> +       } else {
> +               status = acpi_bus_get_device(graphics_handle,
> &tmp_dev);
> +               if (ACPI_FAILURE(status)) {
> +                       ACPI_EXCEPTION((AE_INFO, status, "Invalid
> device"));
> +                       return 0;
> +               }
> +               acpi_walk_namespace(ACPI_TYPE_DEVICE, graphics_handle,
> +                                   ACPI_UINT32_MAX, find_video,
> +                                   &caps, NULL);
> +       }
> +       ACPI_DEBUG_PRINT((ACPI_DB_INFO, "We have 0x%lX video support %
> s %s\n",
> +                         graphics_handle ? caps : acpi_video_support,
> +                         graphics_handle ? "on device " : "in
> general",
> +                         graphics_handle ? acpi_device_bid(tmp_dev) :
> ""));
> +       return caps;
> +}
> +EXPORT_SYMBOL(acpi_video_get_capabilities);
> +
> +/* Returns true if video.ko can do backlight switching */
> +int acpi_video_backlight_support(void)
> +{
> +       /*
> +        * We must check whether the ACPI graphics device is
> physically plugged
> +        * in. Therefore this must be called after binding PCI and
> ACPI devices
> +        */
> +       if (!acpi_video_caps_checked)
> +               acpi_video_get_capabilities(NULL);
> +
> +       /* First check for boot param -> highest prio */
> +       if (acpi_video_support & ACPI_VIDEO_BACKLIGHT_FORCE_VENDOR)
> +               return 0;
> +       else if (acpi_video_support &
> ACPI_VIDEO_BACKLIGHT_FORCE_VIDEO)
> +               return 1;
> +
> +       /* Then check for DMI blacklist -> second highest prio */
> +       if (acpi_video_support & ACPI_VIDEO_BACKLIGHT_DMI_VENDOR)
> +               return 0;
> +       else if (acpi_video_support & ACPI_VIDEO_BACKLIGHT_DMI_VIDEO)
> +               return 1;
> +
> +       /* Then go the default way */
> +       return acpi_video_support & ACPI_VIDEO_BACKLIGHT;
> +}
> +EXPORT_SYMBOL(acpi_video_backlight_support);
> +
> +/*
> + * Returns true if video.ko can do display output switching.
> + * This does not work well/at all with binary graphics drivers
> + * which disable system io ranges and do it on their own.
> + */
> +int acpi_video_display_switch_support(void)
> +{
> +       if (!acpi_video_caps_checked)
> +               acpi_video_get_capabilities(NULL);
> +
> +       if (acpi_video_support &
> ACPI_VIDEO_OUTPUT_SWITCHING_FORCE_VENDOR)
> +               return 0;
> +       else if (acpi_video_support &
> ACPI_VIDEO_OUTPUT_SWITCHING_FORCE_VIDEO)
> +               return 1;
> +
> +       if (acpi_video_support &
> ACPI_VIDEO_OUTPUT_SWITCHING_DMI_VENDOR)
> +               return 0;
> +       else if (acpi_video_support &
> ACPI_VIDEO_OUTPUT_SWITCHING_DMI_VIDEO)
> +               return 1;
> +
> +       return acpi_video_support & ACPI_VIDEO_OUTPUT_SWITCHING;
> +}
> +EXPORT_SYMBOL(acpi_video_display_switch_support);
> +
> +/*
> + * Use acpi_display_output=vendor/video or
> acpi_backlight=vendor/video
> + * To force that backlight or display output switching is processed
> by vendor
> + * specific acpi drivers or video.ko driver.
> + */
> +int __init acpi_backlight(char *str)
> +{
> +       if (str == NULL || *str == '\0')
> +               return 1;
> +       else {
> +               if (!strcmp("vendor", str))
> +                       acpi_video_support |=
> +                               ACPI_VIDEO_BACKLIGHT_FORCE_VENDOR;
> +               if (!strcmp("video", str))
> +                       acpi_video_support |=
> +
> ACPI_VIDEO_OUTPUT_SWITCHING_FORCE_VIDEO;
> +       }
> +       return 1;
> +}
> +__setup("acpi_backlight=", acpi_backlight);
> +
> +int __init acpi_display_output(char *str)
> +{
> +       if (str == NULL || *str == '\0')
> +               return 1;
> +       else {
> +               if (!strcmp("vendor", str))
> +                       acpi_video_support |=
> +
> ACPI_VIDEO_OUTPUT_SWITCHING_FORCE_VENDOR;
> +               if (!strcmp("video", str))
> +                       acpi_video_support |=
> +
> ACPI_VIDEO_OUTPUT_SWITCHING_FORCE_VIDEO;
> +       }
> +       return 1;
> +}
> +__setup("acpi_display_output=", acpi_display_output);
> diff --git a/include/linux/acpi.h b/include/linux/acpi.h
> index a171776..eb51726 100644
> --- a/include/linux/acpi.h
> +++ b/include/linux/acpi.h
> @@ -202,6 +202,50 @@ extern bool wmi_has_guid(const char *guid);
> 
>  #endif /* CONFIG_ACPI_WMI */
> 
> +#define ACPI_VIDEO_OUTPUT_SWITCHING                    0x0001
> +#define ACPI_VIDEO_DEVICE_POSTING                      0x0002
> +#define ACPI_VIDEO_ROM_AVAILABLE                       0x0004
> +#define ACPI_VIDEO_BACKLIGHT                           0x0008
> +#define ACPI_VIDEO_BACKLIGHT_FORCE_VENDOR              0x0010
> +#define ACPI_VIDEO_BACKLIGHT_FORCE_VIDEO               0x0020
> +#define ACPI_VIDEO_OUTPUT_SWITCHING_FORCE_VENDOR       0x0040
> +#define ACPI_VIDEO_OUTPUT_SWITCHING_FORCE_VIDEO                0x0080
> +#define ACPI_VIDEO_BACKLIGHT_DMI_VENDOR                        0x0100
> +#define ACPI_VIDEO_BACKLIGHT_DMI_VIDEO                 0x0200
> +#define ACPI_VIDEO_OUTPUT_SWITCHING_DMI_VENDOR         0x0400
> +#define ACPI_VIDEO_OUTPUT_SWITCHING_DMI_VIDEO          0x0800
> +
> +#if defined(CONFIG_ACPI_VIDEO) || defined(CONFIG_ACPI_VIDEO_MODULE)
> +
> +extern long acpi_video_get_capabilities(acpi_handle
> graphics_dev_handle);
> +extern long acpi_is_video_device(struct acpi_device *device);
> +extern int acpi_video_backlight_support(void);
> +extern int acpi_video_display_switch_support(void);
> +
> +#else
> +
> +static inline long acpi_video_get_capabilities(acpi_handle
> graphics_dev_handle)
> +{
> +       return 0;
> +}
> +
> +static inline long acpi_is_video_device(struct acpi_device *device)
> +{
> +       return 0;
> +}
> +
> +static inline int acpi_video_backlight_support(void)
> +{
> +       return 0;
> +}
> +
> +static inline int acpi_video_display_switch_support(void)
> +{
> +       return 0;
> +}
> +
> +#endif /* defined(CONFIG_ACPI_VIDEO) ||
> defined(CONFIG_ACPI_VIDEO_MODULE) */
> +
>  extern int acpi_blacklisted(void);
>  #ifdef CONFIG_DMI
>  extern void acpi_dmi_osi_linux(int enable, const struct dmi_system_id
> *d);
> --
> 1.5.4.5
> 
> 
> 

--
To unsubscribe from this list: send the line "unsubscribe linux-acpi" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html

[Index of Archives]     [Linux IBM ACPI]     [Linux Power Management]     [Linux Kernel]     [Linux Laptop]     [Kernel Newbies]     [Share Photos]     [Security]     [Netfilter]     [Bugtraq]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Samba]     [Video 4 Linux]     [Device Mapper]     [Linux Resources]

  Powered by Linux