diff options
author | Hans de Goede <hdegoede@redhat.com> | 2015-06-16 10:27:48 -0400 |
---|---|---|
committer | Rafael J. Wysocki <rafael.j.wysocki@intel.com> | 2015-06-18 19:10:44 -0400 |
commit | 87521e16a7abbf3fa337f56cb4d1e18247f15e8a (patch) | |
tree | 63ae44bbc4a4aaf0b48f03536c825d36baaf4238 /drivers/acpi/video_detect.c | |
parent | 14ca7a47d0ab2a7a35faab130e6d9682f8ff1a46 (diff) |
acpi-video-detect: Rewrite backlight interface selection logic
Currently we have 2 kernel commandline options + dmi-quirks in 3 places all
interacting (in interesting ways) to select which which backlight interface
to use. On the commandline we've acpi_backlight=[video|vendor] and
video.use_native_backlight=[0|1]. DMI quirks we have in
acpi/video-detect.c, acpi/video.c and drivers/platform/x86/*.c .
This commit is the first step to cleaning this up, replacing the 2 cmdline
options with just acpi_backlight=[video|vendor|native|none], and adds a
new API to video_detect.c to reflect this.
Follow up commits will also move other related code, like unregistering the
acpi_video backlight interface if it was registered before other drivers
which take priority over it are loaded, to video_detect.c where this
logic really belongs.
Signed-off-by: Hans de Goede <hdegoede@redhat.com>
Acked-by: Darren Hart <dvhart@linux.intel.com>
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
Diffstat (limited to 'drivers/acpi/video_detect.c')
-rw-r--r-- | drivers/acpi/video_detect.c | 171 |
1 files changed, 83 insertions, 88 deletions
diff --git a/drivers/acpi/video_detect.c b/drivers/acpi/video_detect.c index bb6133c60175..0f9586b7f3d1 100644 --- a/drivers/acpi/video_detect.c +++ b/drivers/acpi/video_detect.c | |||
@@ -1,4 +1,6 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (C) 2015 Red Hat Inc. | ||
3 | * Hans de Goede <hdegoede@redhat.com> | ||
2 | * Copyright (C) 2008 SuSE Linux Products GmbH | 4 | * Copyright (C) 2008 SuSE Linux Products GmbH |
3 | * Thomas Renninger <trenn@suse.de> | 5 | * Thomas Renninger <trenn@suse.de> |
4 | * | 6 | * |
@@ -9,44 +11,45 @@ | |||
9 | * acpi_get_pci_dev() can be called to identify ACPI graphics | 11 | * acpi_get_pci_dev() can be called to identify ACPI graphics |
10 | * devices for which a real graphics card is plugged in | 12 | * devices for which a real graphics card is plugged in |
11 | * | 13 | * |
12 | * Now acpi_video_get_capabilities() can be called to check which | ||
13 | * capabilities the graphics cards plugged in support. The check for general | ||
14 | * video capabilities will be triggered by the first caller of | ||
15 | * acpi_video_get_capabilities(NULL); which will happen when the first | ||
16 | * backlight switching supporting driver calls: | ||
17 | * acpi_video_backlight_support(); | ||
18 | * | ||
19 | * Depending on whether ACPI graphics extensions (cmp. ACPI spec Appendix B) | 14 | * Depending on whether ACPI graphics extensions (cmp. ACPI spec Appendix B) |
20 | * are available, video.ko should be used to handle the device. | 15 | * are available, video.ko should be used to handle the device. |
21 | * | 16 | * |
22 | * Otherwise vendor specific drivers like thinkpad_acpi, asus-laptop, | 17 | * Otherwise vendor specific drivers like thinkpad_acpi, asus-laptop, |
23 | * sony_acpi,... can take care about backlight brightness. | 18 | * sony_acpi,... can take care about backlight brightness. |
24 | * | 19 | * |
25 | * If CONFIG_ACPI_VIDEO is neither set as "compiled in" (y) nor as a module (m) | 20 | * Backlight drivers can use acpi_video_get_backlight_type() to determine |
26 | * this file will not be compiled, acpi_video_get_capabilities() and | 21 | * which driver should handle the backlight. |
27 | * acpi_video_backlight_support() will always return 0 and vendor specific | ||
28 | * drivers always can handle backlight. | ||
29 | * | 22 | * |
23 | * If CONFIG_ACPI_VIDEO is neither set as "compiled in" (y) nor as a module (m) | ||
24 | * this file will not be compiled and acpi_video_get_backlight_type() will | ||
25 | * always return acpi_backlight_vendor. | ||
30 | */ | 26 | */ |
31 | 27 | ||
32 | #include <linux/export.h> | 28 | #include <linux/export.h> |
33 | #include <linux/acpi.h> | 29 | #include <linux/acpi.h> |
30 | #include <linux/backlight.h> | ||
34 | #include <linux/dmi.h> | 31 | #include <linux/dmi.h> |
35 | #include <linux/module.h> | 32 | #include <linux/module.h> |
36 | #include <linux/pci.h> | 33 | #include <linux/pci.h> |
34 | #include <linux/types.h> | ||
35 | #include <acpi/video.h> | ||
37 | 36 | ||
38 | ACPI_MODULE_NAME("video"); | 37 | ACPI_MODULE_NAME("video"); |
39 | #define _COMPONENT ACPI_VIDEO_COMPONENT | 38 | #define _COMPONENT ACPI_VIDEO_COMPONENT |
40 | 39 | ||
41 | static long acpi_video_support; | 40 | static enum acpi_backlight_type acpi_backlight_cmdline = acpi_backlight_undef; |
42 | static bool acpi_video_caps_checked; | 41 | static enum acpi_backlight_type acpi_backlight_dmi = acpi_backlight_undef; |
43 | 42 | ||
44 | static void acpi_video_parse_cmdline(void) | 43 | static void acpi_video_parse_cmdline(void) |
45 | { | 44 | { |
46 | if (!strcmp("vendor", acpi_video_backlight_string)) | 45 | if (!strcmp("vendor", acpi_video_backlight_string)) |
47 | acpi_video_support |= ACPI_VIDEO_BACKLIGHT_FORCE_VENDOR; | 46 | acpi_backlight_cmdline = acpi_backlight_vendor; |
48 | if (!strcmp("video", acpi_video_backlight_string)) | 47 | if (!strcmp("video", acpi_video_backlight_string)) |
49 | acpi_video_support |= ACPI_VIDEO_BACKLIGHT_FORCE_VIDEO; | 48 | acpi_backlight_cmdline = acpi_backlight_video; |
49 | if (!strcmp("native", acpi_video_backlight_string)) | ||
50 | acpi_backlight_cmdline = acpi_backlight_native; | ||
51 | if (!strcmp("none", acpi_video_backlight_string)) | ||
52 | acpi_backlight_cmdline = acpi_backlight_none; | ||
50 | } | 53 | } |
51 | 54 | ||
52 | static acpi_status | 55 | static acpi_status |
@@ -77,7 +80,7 @@ find_video(acpi_handle handle, u32 lvl, void *context, void **rv) | |||
77 | * buggy */ | 80 | * buggy */ |
78 | static int video_detect_force_vendor(const struct dmi_system_id *d) | 81 | static int video_detect_force_vendor(const struct dmi_system_id *d) |
79 | { | 82 | { |
80 | acpi_video_support |= ACPI_VIDEO_BACKLIGHT_DMI_VENDOR; | 83 | acpi_backlight_dmi = acpi_backlight_vendor; |
81 | return 0; | 84 | return 0; |
82 | } | 85 | } |
83 | 86 | ||
@@ -125,99 +128,91 @@ static const struct dmi_system_id video_detect_dmi_table[] = { | |||
125 | }; | 128 | }; |
126 | 129 | ||
127 | /* | 130 | /* |
128 | * Returns the video capabilities of a specific ACPI graphics device | 131 | * Determine which type of backlight interface to use on this system, |
132 | * First check cmdline, then dmi quirks, then do autodetect. | ||
133 | * | ||
134 | * The autodetect order is: | ||
135 | * 1) Is the acpi-video backlight interface supported -> | ||
136 | * no, use a vendor interface | ||
137 | * 2) Is this a win8 "ready" BIOS and do we have a native interface -> | ||
138 | * yes, use a native interface | ||
139 | * 3) Else use the acpi-video interface | ||
129 | * | 140 | * |
130 | * if NULL is passed as argument all ACPI devices are enumerated and | 141 | * Arguably the native on win8 check should be done first, but that would |
131 | * all graphics capabilities of physically present devices are | 142 | * be a behavior change, which may causes issues. |
132 | * summarized and returned. This is cached and done only once. | ||
133 | */ | 143 | */ |
134 | static long acpi_video_get_capabilities(acpi_handle graphics_handle) | 144 | enum acpi_backlight_type acpi_video_get_backlight_type(void) |
135 | { | 145 | { |
136 | long caps = 0; | 146 | static DEFINE_MUTEX(init_mutex); |
137 | struct acpi_device *tmp_dev; | 147 | static bool init_done; |
138 | acpi_status status; | 148 | static long video_caps; |
139 | |||
140 | if (acpi_video_caps_checked && graphics_handle == NULL) | ||
141 | return acpi_video_support; | ||
142 | |||
143 | if (!graphics_handle) { | ||
144 | /* Only do the global walk through all graphics devices once */ | ||
145 | acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT, | ||
146 | ACPI_UINT32_MAX, find_video, NULL, | ||
147 | &caps, NULL); | ||
148 | /* There might be boot param flags set already... */ | ||
149 | acpi_video_support |= caps; | ||
150 | acpi_video_caps_checked = 1; | ||
151 | /* Add blacklists here. Be careful to use the right *DMI* bits | ||
152 | * to still be able to override logic via boot params, e.g.: | ||
153 | * | ||
154 | * if (dmi_name_in_vendors("XY")) { | ||
155 | * acpi_video_support |= | ||
156 | * ACPI_VIDEO_BACKLIGHT_DMI_VENDOR; | ||
157 | *} | ||
158 | */ | ||
159 | 149 | ||
150 | /* Parse cmdline, dmi and acpi only once */ | ||
151 | mutex_lock(&init_mutex); | ||
152 | if (!init_done) { | ||
153 | acpi_video_parse_cmdline(); | ||
160 | dmi_check_system(video_detect_dmi_table); | 154 | dmi_check_system(video_detect_dmi_table); |
161 | } else { | 155 | acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT, |
162 | status = acpi_bus_get_device(graphics_handle, &tmp_dev); | ||
163 | if (ACPI_FAILURE(status)) { | ||
164 | ACPI_EXCEPTION((AE_INFO, status, "Invalid device")); | ||
165 | return 0; | ||
166 | } | ||
167 | acpi_walk_namespace(ACPI_TYPE_DEVICE, graphics_handle, | ||
168 | ACPI_UINT32_MAX, find_video, NULL, | 156 | ACPI_UINT32_MAX, find_video, NULL, |
169 | &caps, NULL); | 157 | &video_caps, NULL); |
158 | init_done = true; | ||
170 | } | 159 | } |
171 | ACPI_DEBUG_PRINT((ACPI_DB_INFO, "We have 0x%lX video support %s %s\n", | 160 | mutex_unlock(&init_mutex); |
172 | graphics_handle ? caps : acpi_video_support, | 161 | |
173 | graphics_handle ? "on device " : "in general", | 162 | if (acpi_backlight_cmdline != acpi_backlight_undef) |
174 | graphics_handle ? acpi_device_bid(tmp_dev) : "")); | 163 | return acpi_backlight_cmdline; |
175 | return caps; | 164 | |
165 | if (acpi_backlight_dmi != acpi_backlight_undef) | ||
166 | return acpi_backlight_dmi; | ||
167 | |||
168 | if (!(video_caps & ACPI_VIDEO_BACKLIGHT)) | ||
169 | return acpi_backlight_vendor; | ||
170 | |||
171 | if (acpi_osi_is_win8() && backlight_device_registered(BACKLIGHT_RAW)) | ||
172 | return acpi_backlight_native; | ||
173 | |||
174 | return acpi_backlight_video; | ||
176 | } | 175 | } |
176 | EXPORT_SYMBOL(acpi_video_get_backlight_type); | ||
177 | 177 | ||
178 | static void acpi_video_caps_check(void) | 178 | /* |
179 | * Set the preferred backlight interface type based on DMI info. | ||
180 | * This function allows DMI blacklists to be implemented by external | ||
181 | * platform drivers instead of putting a big blacklist in video_detect.c | ||
182 | */ | ||
183 | void acpi_video_set_dmi_backlight_type(enum acpi_backlight_type type) | ||
179 | { | 184 | { |
180 | /* | 185 | acpi_backlight_dmi = type; |
181 | * We must check whether the ACPI graphics device is physically plugged | ||
182 | * in. Therefore this must be called after binding PCI and ACPI devices | ||
183 | */ | ||
184 | if (!acpi_video_caps_checked) { | ||
185 | acpi_video_parse_cmdline(); | ||
186 | acpi_video_get_capabilities(NULL); | ||
187 | } | ||
188 | } | 186 | } |
187 | EXPORT_SYMBOL(acpi_video_set_dmi_backlight_type); | ||
189 | 188 | ||
190 | /* Promote the vendor interface instead of the generic video module. | 189 | /* |
191 | * This function allow DMI blacklists to be implemented by externals | 190 | * Compatiblity function, this is going away as soon as all drivers are |
192 | * platform drivers instead of putting a big blacklist in video_detect.c | 191 | * converted to acpi_video_set_dmi_backlight_type(). |
192 | * | ||
193 | * Promote the vendor interface instead of the generic video module. | ||
193 | * After calling this function you will probably want to call | 194 | * After calling this function you will probably want to call |
194 | * acpi_video_unregister() to make sure the video module is not loaded | 195 | * acpi_video_unregister() to make sure the video module is not loaded |
195 | */ | 196 | */ |
196 | void acpi_video_dmi_promote_vendor(void) | 197 | void acpi_video_dmi_promote_vendor(void) |
197 | { | 198 | { |
198 | acpi_video_caps_check(); | 199 | acpi_video_set_dmi_backlight_type(acpi_backlight_vendor); |
199 | acpi_video_support |= ACPI_VIDEO_BACKLIGHT_DMI_VENDOR; | ||
200 | } | 200 | } |
201 | EXPORT_SYMBOL(acpi_video_dmi_promote_vendor); | 201 | EXPORT_SYMBOL(acpi_video_dmi_promote_vendor); |
202 | 202 | ||
203 | /* Returns true if video.ko can do backlight switching */ | 203 | /* |
204 | * Compatiblity function, this is going away as soon as all drivers are | ||
205 | * converted to acpi_video_get_backlight_type(). | ||
206 | * | ||
207 | * Returns true if video.ko can do backlight switching. | ||
208 | */ | ||
204 | int acpi_video_backlight_support(void) | 209 | int acpi_video_backlight_support(void) |
205 | { | 210 | { |
206 | acpi_video_caps_check(); | 211 | /* |
207 | 212 | * This is done this way since vendor drivers call this to see | |
208 | /* First check for boot param -> highest prio */ | 213 | * if they should load, and we do not want them to load for both |
209 | if (acpi_video_support & ACPI_VIDEO_BACKLIGHT_FORCE_VENDOR) | 214 | * the acpi_backlight_video and acpi_backlight_native cases. |
210 | return 0; | 215 | */ |
211 | else if (acpi_video_support & ACPI_VIDEO_BACKLIGHT_FORCE_VIDEO) | 216 | return acpi_video_get_backlight_type() != acpi_backlight_vendor; |
212 | return 1; | ||
213 | |||
214 | /* Then check for DMI blacklist -> second highest prio */ | ||
215 | if (acpi_video_support & ACPI_VIDEO_BACKLIGHT_DMI_VENDOR) | ||
216 | return 0; | ||
217 | else if (acpi_video_support & ACPI_VIDEO_BACKLIGHT_DMI_VIDEO) | ||
218 | return 1; | ||
219 | |||
220 | /* Then go the default way */ | ||
221 | return acpi_video_support & ACPI_VIDEO_BACKLIGHT; | ||
222 | } | 217 | } |
223 | EXPORT_SYMBOL(acpi_video_backlight_support); | 218 | EXPORT_SYMBOL(acpi_video_backlight_support); |