On Thu, 2008-07-17 at 19:32 +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. > > 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> > --- > Documentation/kernel-parameters.txt | 13 ++ > drivers/acpi/Makefile | 5 + > drivers/acpi/scan.c | 32 +---- > drivers/acpi/video.c | 28 ++-- > drivers/acpi/video_detect.c | 267 +++++++++++++++++++++++++++++++++++ > include/linux/acpi.h | 44 ++++++ > 6 files changed, 346 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/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..e90a5dc > --- /dev/null > +++ b/drivers/acpi/video_detect.c > @@ -0,0 +1,267 @@ > +/* > + * 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; > + return 0; > + } > + return -ENODEV; > +} > + > +/* 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; > + > + /* 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; > + > + 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; > + *} > + */ so this is for the thinkpad laptops which patch 01 breaks, right? why don't you add the thinkpad dmi entries directly? If we don't blacklist them, this patch set still causes regressions on these laptops, unless the IGD OpRegion patches are upstream. thanks, rui -- 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