Skip to content

Commit ea45ea7

Browse files
committed
Merge tag 'acpi-video-3.11' of git://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm
Pull ACPI video support fixes from Rafael Wysocki: "I'm sending a separate pull request for this as it may be somewhat controversial. The breakage addressed here is not really new and the fixes may not satisfy all users of the affected systems, but we've had so much back and forth dance in this area over the last several weeks that I think it's time to actually make some progress. The source of the problem is that about a year ago we started to tell BIOSes that we're compatible with Windows 8, which we really need to do, because some systems shipping with Windows 8 are tested with it and nothing else, so if we tell their BIOSes that we aren't compatible with Windows 8, we expose our users to untested BIOS/AML code paths. However, as it turns out, some Windows 8-specific AML code paths are not tested either, because Windows 8 actually doesn't use the ACPI methods containing them, so if we declare Windows 8 compatibility and attempt to use those ACPI methods, things break. That occurs mostly in the backlight support area where in particular the _BCM and _BQC methods are plain unusable on some systems if the OS declares Windows 8 compatibility. [ The additional twist is that they actually become usable if the OS says it is not compatible with Windows 8, but that may cause problems to show up elsewhere ] Investigation carried out by Matthew Garrett indicates that what Windows 8 does about backlight is to leave backlight control up to individual graphics drivers. At least there's evidence that it does that if the Intel graphics driver is used, so we've decided to follow Windows 8 in that respect and allow i915 to control backlight (Daniel likes that part). The first commit from Aaron Lu makes ACPICA export the variable from which we can infer whether or not the BIOS believes that we are compatible with Windows 8. The second commit from Matthew Garrett prepares the ACPI video driver by making it initialize the ACPI backlight even if it is not going to be used afterward (that is needed for backlight control to work on Thinkpads). The third commit implements the actual workaround making i915 take over backlight control if the firmware thinks it's dealing with Windows 8 and is based on the work of multiple developers, including Matthew Garrett, Chun-Yi Lee, Seth Forshee, and Aaron Lu. The final commit from Aaron Lu makes us follow Windows 8 by informing the firmware through the _DOS method that it should not carry out automatic brightness changes, so that brightness can be controlled by GUI. Hopefully, this approach will allow us to avoid using blacklists of systems that should not declare Windows 8 compatibility just to avoid backlight control problems in the future. - Change from Aaron Lu makes ACPICA export a variable which can be used by driver code to determine whether or not the BIOS believes that we are compatible with Windows 8. - Change from Matthew Garrett makes the ACPI video driver initialize the ACPI backlight even if it is not going to be used afterward (that is needed for backlight control to work on Thinkpads). - Fix from Rafael J Wysocki implements Windows 8 backlight support workaround making i915 take over bakclight control if the firmware thinks it's dealing with Windows 8. Based on the work of multiple developers including Matthew Garrett, Chun-Yi Lee, Seth Forshee, and Aaron Lu. - Fix from Aaron Lu makes the kernel follow Windows 8 by informing the firmware through the _DOS method that it should not carry out automatic brightness changes, so that brightness can be controlled by GUI" * tag 'acpi-video-3.11' of git://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm: ACPI / video: no automatic brightness changes by win8-compatible firmware ACPI / video / i915: No ACPI backlight if firmware expects Windows 8 ACPI / video: Always call acpi_video_init_brightness() on init ACPICA: expose OSI version
2 parents 90db76e + efaa14c commit ea45ea7

File tree

9 files changed

+137
-28
lines changed

9 files changed

+137
-28
lines changed

drivers/acpi/acpica/aclocal.h

Lines changed: 0 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -931,19 +931,6 @@ struct acpi_bit_register_info {
931931

932932
/* Structs and definitions for _OSI support and I/O port validation */
933933

934-
#define ACPI_OSI_WIN_2000 0x01
935-
#define ACPI_OSI_WIN_XP 0x02
936-
#define ACPI_OSI_WIN_XP_SP1 0x03
937-
#define ACPI_OSI_WINSRV_2003 0x04
938-
#define ACPI_OSI_WIN_XP_SP2 0x05
939-
#define ACPI_OSI_WINSRV_2003_SP1 0x06
940-
#define ACPI_OSI_WIN_VISTA 0x07
941-
#define ACPI_OSI_WINSRV_2008 0x08
942-
#define ACPI_OSI_WIN_VISTA_SP1 0x09
943-
#define ACPI_OSI_WIN_VISTA_SP2 0x0A
944-
#define ACPI_OSI_WIN_7 0x0B
945-
#define ACPI_OSI_WIN_8 0x0C
946-
947934
#define ACPI_ALWAYS_ILLEGAL 0x00
948935

949936
struct acpi_interface_info {

drivers/acpi/internal.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -164,4 +164,15 @@ struct platform_device;
164164
int acpi_create_platform_device(struct acpi_device *adev,
165165
const struct acpi_device_id *id);
166166

167+
/*--------------------------------------------------------------------------
168+
Video
169+
-------------------------------------------------------------------------- */
170+
#if defined(CONFIG_ACPI_VIDEO) || defined(CONFIG_ACPI_VIDEO_MODULE)
171+
bool acpi_video_backlight_quirks(void);
172+
bool acpi_video_verify_backlight_support(void);
173+
#else
174+
static inline bool acpi_video_backlight_quirks(void) { return false; }
175+
static inline bool acpi_video_verify_backlight_support(void) { return false; }
176+
#endif
177+
167178
#endif /* _ACPI_INTERNAL_H_ */

drivers/acpi/video.c

Lines changed: 77 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,8 @@
4444
#include <linux/suspend.h>
4545
#include <acpi/video.h>
4646

47+
#include "internal.h"
48+
4749
#define PREFIX "ACPI: "
4850

4951
#define ACPI_VIDEO_BUS_NAME "Video Bus"
@@ -906,7 +908,10 @@ static void acpi_video_device_find_cap(struct acpi_video_device *device)
906908
device->cap._DDC = 1;
907909
}
908910

909-
if (acpi_video_backlight_support()) {
911+
if (acpi_video_init_brightness(device))
912+
return;
913+
914+
if (acpi_video_verify_backlight_support()) {
910915
struct backlight_properties props;
911916
struct pci_dev *pdev;
912917
acpi_handle acpi_parent;
@@ -915,9 +920,6 @@ static void acpi_video_device_find_cap(struct acpi_video_device *device)
915920
static int count = 0;
916921
char *name;
917922

918-
result = acpi_video_init_brightness(device);
919-
if (result)
920-
return;
921923
name = kasprintf(GFP_KERNEL, "acpi_video%d", count);
922924
if (!name)
923925
return;
@@ -977,6 +979,11 @@ static void acpi_video_device_find_cap(struct acpi_video_device *device)
977979
if (result)
978980
printk(KERN_ERR PREFIX "Create sysfs link\n");
979981

982+
} else {
983+
/* Remove the brightness object. */
984+
kfree(device->brightness->levels);
985+
kfree(device->brightness);
986+
device->brightness = NULL;
980987
}
981988
}
982989

@@ -1359,8 +1366,8 @@ acpi_video_switch_brightness(struct acpi_video_device *device, int event)
13591366
unsigned long long level_current, level_next;
13601367
int result = -EINVAL;
13611368

1362-
/* no warning message if acpi_backlight=vendor is used */
1363-
if (!acpi_video_backlight_support())
1369+
/* no warning message if acpi_backlight=vendor or a quirk is used */
1370+
if (!acpi_video_verify_backlight_support())
13641371
return 0;
13651372

13661373
if (!device->brightness)
@@ -1540,14 +1547,20 @@ static int acpi_video_bus_put_devices(struct acpi_video_bus *video)
15401547

15411548
/* acpi_video interface */
15421549

1550+
/*
1551+
* Win8 requires setting bit2 of _DOS to let firmware know it shouldn't
1552+
* preform any automatic brightness change on receiving a notification.
1553+
*/
15431554
static int acpi_video_bus_start_devices(struct acpi_video_bus *video)
15441555
{
1545-
return acpi_video_bus_DOS(video, 0, 0);
1556+
return acpi_video_bus_DOS(video, 0,
1557+
acpi_video_backlight_quirks() ? 1 : 0);
15461558
}
15471559

15481560
static int acpi_video_bus_stop_devices(struct acpi_video_bus *video)
15491561
{
1550-
return acpi_video_bus_DOS(video, 0, 1);
1562+
return acpi_video_bus_DOS(video, 0,
1563+
acpi_video_backlight_quirks() ? 0 : 1);
15511564
}
15521565

15531566
static void acpi_video_bus_notify(struct acpi_device *device, u32 event)
@@ -1862,6 +1875,46 @@ static int acpi_video_bus_remove(struct acpi_device *device)
18621875
return 0;
18631876
}
18641877

1878+
static acpi_status video_unregister_backlight(acpi_handle handle, u32 lvl,
1879+
void *context, void **rv)
1880+
{
1881+
struct acpi_device *acpi_dev;
1882+
struct acpi_video_bus *video;
1883+
struct acpi_video_device *dev, *next;
1884+
1885+
if (acpi_bus_get_device(handle, &acpi_dev))
1886+
return AE_OK;
1887+
1888+
if (acpi_match_device_ids(acpi_dev, video_device_ids))
1889+
return AE_OK;
1890+
1891+
video = acpi_driver_data(acpi_dev);
1892+
if (!video)
1893+
return AE_OK;
1894+
1895+
acpi_video_bus_stop_devices(video);
1896+
mutex_lock(&video->device_list_lock);
1897+
list_for_each_entry_safe(dev, next, &video->video_device_list, entry) {
1898+
if (dev->backlight) {
1899+
backlight_device_unregister(dev->backlight);
1900+
dev->backlight = NULL;
1901+
kfree(dev->brightness->levels);
1902+
kfree(dev->brightness);
1903+
}
1904+
if (dev->cooling_dev) {
1905+
sysfs_remove_link(&dev->dev->dev.kobj,
1906+
"thermal_cooling");
1907+
sysfs_remove_link(&dev->cooling_dev->device.kobj,
1908+
"device");
1909+
thermal_cooling_device_unregister(dev->cooling_dev);
1910+
dev->cooling_dev = NULL;
1911+
}
1912+
}
1913+
mutex_unlock(&video->device_list_lock);
1914+
acpi_video_bus_start_devices(video);
1915+
return AE_OK;
1916+
}
1917+
18651918
static int __init is_i740(struct pci_dev *dev)
18661919
{
18671920
if (dev->device == 0x00D1)
@@ -1893,14 +1946,25 @@ static int __init intel_opregion_present(void)
18931946
return opregion;
18941947
}
18951948

1896-
int acpi_video_register(void)
1949+
int __acpi_video_register(bool backlight_quirks)
18971950
{
1898-
int result = 0;
1951+
bool no_backlight;
1952+
int result;
1953+
1954+
no_backlight = backlight_quirks ? acpi_video_backlight_quirks() : false;
1955+
18991956
if (register_count) {
19001957
/*
1901-
* if the function of acpi_video_register is already called,
1902-
* don't register the acpi_vide_bus again and return no error.
1958+
* If acpi_video_register() has been called already, don't try
1959+
* to register acpi_video_bus, but unregister backlight devices
1960+
* if no backlight support is requested.
19031961
*/
1962+
if (no_backlight)
1963+
acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT,
1964+
ACPI_UINT32_MAX,
1965+
video_unregister_backlight,
1966+
NULL, NULL, NULL);
1967+
19041968
return 0;
19051969
}
19061970

@@ -1916,7 +1980,7 @@ int acpi_video_register(void)
19161980

19171981
return 0;
19181982
}
1919-
EXPORT_SYMBOL(acpi_video_register);
1983+
EXPORT_SYMBOL(__acpi_video_register);
19201984

19211985
void acpi_video_unregister(void)
19221986
{

drivers/acpi/video_detect.c

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,8 @@
3838
#include <linux/dmi.h>
3939
#include <linux/pci.h>
4040

41+
#include "internal.h"
42+
4143
#define PREFIX "ACPI: "
4244

4345
ACPI_MODULE_NAME("video");
@@ -234,6 +236,17 @@ static void acpi_video_caps_check(void)
234236
acpi_video_get_capabilities(NULL);
235237
}
236238

239+
bool acpi_video_backlight_quirks(void)
240+
{
241+
if (acpi_gbl_osi_data >= ACPI_OSI_WIN_8) {
242+
acpi_video_caps_check();
243+
acpi_video_support |= ACPI_VIDEO_SKIP_BACKLIGHT;
244+
return true;
245+
}
246+
return false;
247+
}
248+
EXPORT_SYMBOL(acpi_video_backlight_quirks);
249+
237250
/* Promote the vendor interface instead of the generic video module.
238251
* This function allow DMI blacklists to be implemented by externals
239252
* platform drivers instead of putting a big blacklist in video_detect.c
@@ -278,6 +291,14 @@ int acpi_video_backlight_support(void)
278291
}
279292
EXPORT_SYMBOL(acpi_video_backlight_support);
280293

294+
/* For the ACPI video driver use only. */
295+
bool acpi_video_verify_backlight_support(void)
296+
{
297+
return (acpi_video_support & ACPI_VIDEO_SKIP_BACKLIGHT) ?
298+
false : acpi_video_backlight_support();
299+
}
300+
EXPORT_SYMBOL(acpi_video_verify_backlight_support);
301+
281302
/*
282303
* Use acpi_backlight=vendor/video to force that backlight switching
283304
* is processed by vendor specific acpi drivers or video.ko driver.

drivers/gpu/drm/i915/i915_dma.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1648,7 +1648,7 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags)
16481648
if (INTEL_INFO(dev)->num_pipes) {
16491649
/* Must be done after probing outputs */
16501650
intel_opregion_init(dev);
1651-
acpi_video_register();
1651+
acpi_video_register_with_quirks();
16521652
}
16531653

16541654
if (IS_GEN5(dev))

include/acpi/acpixf.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@ extern u32 acpi_current_gpe_count;
6262
extern struct acpi_table_fadt acpi_gbl_FADT;
6363
extern u8 acpi_gbl_system_awake_and_running;
6464
extern u8 acpi_gbl_reduced_hardware; /* ACPI 5.0 */
65+
extern u8 acpi_gbl_osi_data;
6566

6667
/* Runtime configuration of debug print levels */
6768

include/acpi/actypes.h

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1144,4 +1144,19 @@ struct acpi_memory_list {
11441144
#endif
11451145
};
11461146

1147+
/* Definitions for _OSI support */
1148+
1149+
#define ACPI_OSI_WIN_2000 0x01
1150+
#define ACPI_OSI_WIN_XP 0x02
1151+
#define ACPI_OSI_WIN_XP_SP1 0x03
1152+
#define ACPI_OSI_WINSRV_2003 0x04
1153+
#define ACPI_OSI_WIN_XP_SP2 0x05
1154+
#define ACPI_OSI_WINSRV_2003_SP1 0x06
1155+
#define ACPI_OSI_WIN_VISTA 0x07
1156+
#define ACPI_OSI_WINSRV_2008 0x08
1157+
#define ACPI_OSI_WIN_VISTA_SP1 0x09
1158+
#define ACPI_OSI_WIN_VISTA_SP2 0x0A
1159+
#define ACPI_OSI_WIN_7 0x0B
1160+
#define ACPI_OSI_WIN_8 0x0C
1161+
11471162
#endif /* __ACTYPES_H__ */

include/acpi/video.h

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,12 +17,21 @@ struct acpi_device;
1717
#define ACPI_VIDEO_DISPLAY_LEGACY_TV 0x0200
1818

1919
#if (defined CONFIG_ACPI_VIDEO || defined CONFIG_ACPI_VIDEO_MODULE)
20-
extern int acpi_video_register(void);
20+
extern int __acpi_video_register(bool backlight_quirks);
21+
static inline int acpi_video_register(void)
22+
{
23+
return __acpi_video_register(false);
24+
}
25+
static inline int acpi_video_register_with_quirks(void)
26+
{
27+
return __acpi_video_register(true);
28+
}
2129
extern void acpi_video_unregister(void);
2230
extern int acpi_video_get_edid(struct acpi_device *device, int type,
2331
int device_id, void **edid);
2432
#else
2533
static inline int acpi_video_register(void) { return 0; }
34+
static inline int acpi_video_register_with_quirks(void) { return 0; }
2635
static inline void acpi_video_unregister(void) { return; }
2736
static inline int acpi_video_get_edid(struct acpi_device *device, int type,
2837
int device_id, void **edid)

include/linux/acpi.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -191,6 +191,7 @@ extern bool wmi_has_guid(const char *guid);
191191
#define ACPI_VIDEO_BACKLIGHT_DMI_VIDEO 0x0200
192192
#define ACPI_VIDEO_OUTPUT_SWITCHING_DMI_VENDOR 0x0400
193193
#define ACPI_VIDEO_OUTPUT_SWITCHING_DMI_VIDEO 0x0800
194+
#define ACPI_VIDEO_SKIP_BACKLIGHT 0x1000
194195

195196
#if defined(CONFIG_ACPI_VIDEO) || defined(CONFIG_ACPI_VIDEO_MODULE)
196197

0 commit comments

Comments
 (0)