aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/acpi/video_detect.c
diff options
context:
space:
mode:
authorThomas Renninger <trenn@suse.de>2008-08-01 11:37:55 -0400
committerLen Brown <len.brown@intel.com>2008-11-07 23:57:55 -0500
commitc3d6de698c84efdbdd3781b7058bcc339ab43da8 (patch)
tree07e08d88bbaaef8a5a1dd58b9d19f7c860442d3a /drivers/acpi/video_detect.c
parent22c13f9d8179f4c9caecfcb60a95214562b9addc (diff)
ACPI video: if no ACPI backlight support, use vendor drivers
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" Prever vendor driver over ACPI driver for backlight. "acpi_backlight=video" (default) Prever ACPI driver over vendor driver for backlight. Signed-off-by: Thomas Renninger <trenn@suse.de> Acked-by: Zhang Rui <rui.zhang@intel.com> Signed-off-by: Andi Kleen <ak@linux.intel.com> Signed-off-by: Len Brown <len.brown@intel.com>
Diffstat (limited to 'drivers/acpi/video_detect.c')
-rw-r--r--drivers/acpi/video_detect.c268
1 files changed, 268 insertions, 0 deletions
diff --git a/drivers/acpi/video_detect.c b/drivers/acpi/video_detect.c
new file mode 100644
index 000000000000..70b1e91ae2ab
--- /dev/null
+++ b/drivers/acpi/video_detect.c
@@ -0,0 +1,268 @@
1/*
2 * Copyright (C) 2008 SuSE Linux Products GmbH
3 * Thomas Renninger <trenn@suse.de>
4 *
5 * May be copied or modified under the terms of the GNU General Public License
6 *
7 * video_detect.c:
8 * Provides acpi_is_video_device() for early scanning of ACPI devices in scan.c
9 * There a Linux specific (Spec does not provide a HID for video devices) is
10 * assinged
11 *
12 * After PCI devices are glued with ACPI devices
13 * acpi_get_physical_pci_device() can be called to identify ACPI graphics
14 * devices for which a real graphics card is plugged in
15 *
16 * Now acpi_video_get_capabilities() can be called to check which
17 * capabilities the graphics cards plugged in support. The check for general
18 * video capabilities will be triggered by the first caller of
19 * acpi_video_get_capabilities(NULL); which will happen when the first
20 * backlight (or display output) switching supporting driver calls:
21 * acpi_video_backlight_support();
22 *
23 * Depending on whether ACPI graphics extensions (cmp. ACPI spec Appendix B)
24 * are available, video.ko should be used to handle the device.
25 *
26 * Otherwise vendor specific drivers like thinkpad_acpi, asus_acpi,
27 * sony_acpi,... can take care about backlight brightness and display output
28 * switching.
29 *
30 * If CONFIG_ACPI_VIDEO is neither set as "compiled in" (y) nor as a module (m)
31 * this file will not be compiled, acpi_video_get_capabilities() and
32 * acpi_video_backlight_support() will always return 0 and vendor specific
33 * drivers always can handle backlight.
34 *
35 */
36
37#include <linux/acpi.h>
38#include <linux/dmi.h>
39
40ACPI_MODULE_NAME("video");
41#define ACPI_VIDEO_COMPONENT 0x08000000
42#define _COMPONENT ACPI_VIDEO_COMPONENT
43
44static long acpi_video_support;
45static bool acpi_video_caps_checked;
46
47static acpi_status
48acpi_backlight_cap_match(acpi_handle handle, u32 level, void *context,
49 void **retyurn_value)
50{
51 long *cap = context;
52 acpi_handle h_dummy;
53
54 if (ACPI_SUCCESS(acpi_get_handle(handle, "_BCM", &h_dummy)) &&
55 ACPI_SUCCESS(acpi_get_handle(handle, "_BCL", &h_dummy))) {
56 ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Found generic backlight "
57 "support\n"));
58 *cap |= ACPI_VIDEO_BACKLIGHT;
59 /* We have backlight support, no need to scan further */
60 return AE_CTRL_TERMINATE;
61 }
62 return 0;
63}
64
65/* Returns true if the device is a video device which can be handled by
66 * video.ko.
67 * The device will get a Linux specific CID added in scan.c to
68 * identify the device as an ACPI graphics device
69 * Be aware that the graphics device may not be physically present
70 * Use acpi_video_get_capabilities() to detect general ACPI video
71 * capabilities of present cards
72 */
73long acpi_is_video_device(struct acpi_device *device)
74{
75 acpi_handle h_dummy;
76 long video_caps = 0;
77
78 if (!device)
79 return 0;
80
81 /* Does this device able to support video switching ? */
82 if (ACPI_SUCCESS(acpi_get_handle(device->handle, "_DOD", &h_dummy)) &&
83 ACPI_SUCCESS(acpi_get_handle(device->handle, "_DOS", &h_dummy)))
84 video_caps |= ACPI_VIDEO_OUTPUT_SWITCHING;
85
86 /* Does this device able to retrieve a video ROM ? */
87 if (ACPI_SUCCESS(acpi_get_handle(device->handle, "_ROM", &h_dummy)))
88 video_caps |= ACPI_VIDEO_ROM_AVAILABLE;
89
90 /* Does this device able to configure which video head to be POSTed ? */
91 if (ACPI_SUCCESS(acpi_get_handle(device->handle, "_VPO", &h_dummy)) &&
92 ACPI_SUCCESS(acpi_get_handle(device->handle, "_GPD", &h_dummy)) &&
93 ACPI_SUCCESS(acpi_get_handle(device->handle, "_SPD", &h_dummy)))
94 video_caps |= ACPI_VIDEO_DEVICE_POSTING;
95
96 /* Only check for backlight functionality if one of the above hit. */
97 if (video_caps)
98 acpi_walk_namespace(ACPI_TYPE_DEVICE, device->handle,
99 ACPI_UINT32_MAX, acpi_backlight_cap_match,
100 &video_caps, NULL);
101
102 return video_caps;
103}
104EXPORT_SYMBOL(acpi_is_video_device);
105
106static acpi_status
107find_video(acpi_handle handle, u32 lvl, void *context, void **rv)
108{
109 long *cap = context;
110 struct device *dev;
111 struct acpi_device *acpi_dev;
112
113 const struct acpi_device_id video_ids[] = {
114 {ACPI_VIDEO_HID, 0},
115 {"", 0},
116 };
117 if (acpi_bus_get_device(handle, &acpi_dev))
118 return AE_OK;
119
120 if (!acpi_match_device_ids(acpi_dev, video_ids)) {
121 dev = acpi_get_physical_pci_device(handle);
122 if (!dev)
123 return AE_OK;
124 put_device(dev);
125 *cap |= acpi_is_video_device(acpi_dev);
126 }
127 return AE_OK;
128}
129
130/*
131 * Returns the video capabilities of a specific ACPI graphics device
132 *
133 * if NULL is passed as argument all ACPI devices are enumerated and
134 * all graphics capabilities of physically present devices are
135 * summerized and returned. This is cached and done only once.
136 */
137long acpi_video_get_capabilities(acpi_handle graphics_handle)
138{
139 long caps = 0;
140 struct acpi_device *tmp_dev;
141 acpi_status status;
142
143 if (acpi_video_caps_checked && graphics_handle == NULL)
144 return acpi_video_support;
145
146 if (!graphics_handle) {
147 /* Only do the global walk through all graphics devices once */
148 acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT,
149 ACPI_UINT32_MAX, find_video,
150 &caps, NULL);
151 /* There might be boot param flags set already... */
152 acpi_video_support |= caps;
153 acpi_video_caps_checked = 1;
154 /* Add blacklists here. Be careful to use the right *DMI* bits
155 * to still be able to override logic via boot params, e.g.:
156 *
157 * if (dmi_name_in_vendors("XY")) {
158 * acpi_video_support |=
159 * ACPI_VIDEO_OUTPUT_SWITCHING_DMI_VENDOR;
160 * acpi_video_support |=
161 * ACPI_VIDEO_BACKLIGHT_DMI_VENDOR;
162 *}
163 */
164 } else {
165 status = acpi_bus_get_device(graphics_handle, &tmp_dev);
166 if (ACPI_FAILURE(status)) {
167 ACPI_EXCEPTION((AE_INFO, status, "Invalid device"));
168 return 0;
169 }
170 acpi_walk_namespace(ACPI_TYPE_DEVICE, graphics_handle,
171 ACPI_UINT32_MAX, find_video,
172 &caps, NULL);
173 }
174 ACPI_DEBUG_PRINT((ACPI_DB_INFO, "We have 0x%lX video support %s %s\n",
175 graphics_handle ? caps : acpi_video_support,
176 graphics_handle ? "on device " : "in general",
177 graphics_handle ? acpi_device_bid(tmp_dev) : ""));
178 return caps;
179}
180EXPORT_SYMBOL(acpi_video_get_capabilities);
181
182/* Returns true if video.ko can do backlight switching */
183int acpi_video_backlight_support(void)
184{
185 /*
186 * We must check whether the ACPI graphics device is physically plugged
187 * in. Therefore this must be called after binding PCI and ACPI devices
188 */
189 if (!acpi_video_caps_checked)
190 acpi_video_get_capabilities(NULL);
191
192 /* First check for boot param -> highest prio */
193 if (acpi_video_support & ACPI_VIDEO_BACKLIGHT_FORCE_VENDOR)
194 return 0;
195 else if (acpi_video_support & ACPI_VIDEO_BACKLIGHT_FORCE_VIDEO)
196 return 1;
197
198 /* Then check for DMI blacklist -> second highest prio */
199 if (acpi_video_support & ACPI_VIDEO_BACKLIGHT_DMI_VENDOR)
200 return 0;
201 else if (acpi_video_support & ACPI_VIDEO_BACKLIGHT_DMI_VIDEO)
202 return 1;
203
204 /* Then go the default way */
205 return acpi_video_support & ACPI_VIDEO_BACKLIGHT;
206}
207EXPORT_SYMBOL(acpi_video_backlight_support);
208
209/*
210 * Returns true if video.ko can do display output switching.
211 * This does not work well/at all with binary graphics drivers
212 * which disable system io ranges and do it on their own.
213 */
214int acpi_video_display_switch_support(void)
215{
216 if (!acpi_video_caps_checked)
217 acpi_video_get_capabilities(NULL);
218
219 if (acpi_video_support & ACPI_VIDEO_OUTPUT_SWITCHING_FORCE_VENDOR)
220 return 0;
221 else if (acpi_video_support & ACPI_VIDEO_OUTPUT_SWITCHING_FORCE_VIDEO)
222 return 1;
223
224 if (acpi_video_support & ACPI_VIDEO_OUTPUT_SWITCHING_DMI_VENDOR)
225 return 0;
226 else if (acpi_video_support & ACPI_VIDEO_OUTPUT_SWITCHING_DMI_VIDEO)
227 return 1;
228
229 return acpi_video_support & ACPI_VIDEO_OUTPUT_SWITCHING;
230}
231EXPORT_SYMBOL(acpi_video_display_switch_support);
232
233/*
234 * Use acpi_display_output=vendor/video or acpi_backlight=vendor/video
235 * To force that backlight or display output switching is processed by vendor
236 * specific acpi drivers or video.ko driver.
237 */
238int __init acpi_backlight(char *str)
239{
240 if (str == NULL || *str == '\0')
241 return 1;
242 else {
243 if (!strcmp("vendor", str))
244 acpi_video_support |=
245 ACPI_VIDEO_BACKLIGHT_FORCE_VENDOR;
246 if (!strcmp("video", str))
247 acpi_video_support |=
248 ACPI_VIDEO_OUTPUT_SWITCHING_FORCE_VIDEO;
249 }
250 return 1;
251}
252__setup("acpi_backlight=", acpi_backlight);
253
254int __init acpi_display_output(char *str)
255{
256 if (str == NULL || *str == '\0')
257 return 1;
258 else {
259 if (!strcmp("vendor", str))
260 acpi_video_support |=
261 ACPI_VIDEO_OUTPUT_SWITCHING_FORCE_VENDOR;
262 if (!strcmp("video", str))
263 acpi_video_support |=
264 ACPI_VIDEO_OUTPUT_SWITCHING_FORCE_VIDEO;
265 }
266 return 1;
267}
268__setup("acpi_display_output=", acpi_display_output);