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

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

 



On Wed, 2008-07-16 at 12:52 +0200, 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.

IMO this is OK and reasonable.
> 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>
> Signed-off-by: Thomas Renninger <trenn@xxxxxxxxxxxxxxxxxx>
> ---
>  Documentation/kernel-parameters.txt |   13 ++
>  drivers/acpi/Makefile               |    5 +
>  drivers/acpi/pci_root.c             |    6 +
>  drivers/acpi/scan.c                 |   32 +----
>  drivers/acpi/video.c                |   28 ++--
>  drivers/acpi/video_detect.c         |  258 +++++++++++++++++++++++++++++++++++
>  include/linux/acpi.h                |   45 ++++++
>  7 files changed, 344 insertions(+), 43 deletions(-)
>  create mode 100644 drivers/acpi/video_detect.c
> 
> diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt
> index 6acfe8e..56392f8 100644
> --- a/Documentation/kernel-parameters.txt
> +++ b/Documentation/kernel-parameters.txt
> @@ -191,6 +191,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 4efbe59..d91dc80 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_POWER)	+= power.o
>  obj-$(CONFIG_ACPI_PROCESSOR)	+= processor.o
> diff --git a/drivers/acpi/pci_root.c b/drivers/acpi/pci_root.c
> index c3fed31..0a6d5e0 100644
> --- a/drivers/acpi/pci_root.c
> +++ b/drivers/acpi/pci_root.c
> @@ -388,6 +388,12 @@ static int __init acpi_pci_root_init(void)
>  	if (acpi_bus_register_driver(&acpi_pci_root_driver) < 0)
>  		return -ENODEV;
>  
> +	/* We must check whether the ACPI graphics device is physically plugged
> +	 * in. Therefore this must be called after binding PCI and ACPI devices,
> +	 * but before modules are loaded, so that we know which module should
> +	 * be responsible depending on what the BIOS provides us.
> +	 */
> +	acpi_video_get_capabilities(NULL);
>  	return 0;
>  }
>  
> diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c
> index 5b049cd..fb8e2df 100644
> --- a/drivers/acpi/scan.c
> +++ b/drivers/acpi/scan.c
> @@ -931,36 +931,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
>   *
> @@ -1043,7 +1013,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 767d9b9..0533e0d 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 && device->cap._BQC && max_level > 0){
>  		int result;
> @@ -776,18 +777,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..68abba7
> --- /dev/null
> +++ b/drivers/acpi/video_detect.c
> @@ -0,0 +1,258 @@
> +/*
> + * 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.
> + *
> + * 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.
> + *
> + * Copyright 2008   Thomas Renninger <trenn@xxxxxxx>
> + */
> +
> +/* If video.ko is not selected, we do not need to protect vendor acpi drivers */
> +
> +#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;
> +		return 0;
> +	}
> +	return -ENODEV;
> +}
> +
> +/* Returns true if the device is a video device which can be handled by
> + * video.ko.
> + * The device will get aacpi_is_video_device 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;
> +
> +	/* 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)))
> +		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;
> +
> +	/* IGD detection is not perfect. It should use the same method as done
> +	 * to identify an IGD device in the dri parts or video.ko
> +	*/
> +	if (ACPI_SUCCESS(acpi_get_handle(device->handle, "DRDY", &h_dummy))) {
> +		ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Found IGD device\n"));
> +		video_caps |= ACPI_VIDEO_IGD;
> +	}
> +
> +	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)
> +{
> +
> +	/* 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.
> + *
> + * It should work well when we have an IGD driver for Intel
> + * graphics cards.
> + */
> +int acpi_video_display_switch_support(void)
> +{
> +	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 41f7ce7..7e4e5bc 100644
> --- a/include/linux/acpi.h
> +++ b/include/linux/acpi.h
> @@ -201,6 +201,51 @@ extern bool wmi_has_guid(const char *guid);
>  
>  #endif	/* CONFIG_ACPI_WMI */
>  
> +#define ACPI_VIDEO_OUTPUT_SWITCHING			1
> +#define ACPI_VIDEO_DEVICE_POSTING			2
> +#define ACPI_VIDEO_ROM_AVAILABLE			4
> +#define ACPI_VIDEO_BACKLIGHT				8
> +#define ACPI_VIDEO_IGD					16
> +#define ACPI_VIDEO_BACKLIGHT_FORCE_VENDOR		32
> +#define ACPI_VIDEO_BACKLIGHT_FORCE_VIDEO		64
> +#define ACPI_VIDEO_OUTPUT_SWITCHING_FORCE_VENDOR	128
> +#define ACPI_VIDEO_OUTPUT_SWITCHING_FORCE_VIDEO		256
> +#define ACPI_VIDEO_BACKLIGHT_DMI_VENDOR			512
> +#define ACPI_VIDEO_BACKLIGHT_DMI_VIDEO			1024
> +#define ACPI_VIDEO_OUTPUT_SWITCHING_DMI_VENDOR		2048
> +#define ACPI_VIDEO_OUTPUT_SWITCHING_DMI_VIDEO		4096
> +
> +#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);

--
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