aboutsummaryrefslogtreecommitdiffstats
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
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>
-rw-r--r--Documentation/kernel-parameters.txt12
-rw-r--r--drivers/acpi/Makefile4
-rw-r--r--drivers/acpi/scan.c32
-rw-r--r--drivers/acpi/video.c28
-rw-r--r--drivers/acpi/video_detect.c268
-rw-r--r--include/linux/acpi.h44
6 files changed, 345 insertions, 43 deletions
diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt
index c86c07459712..dd5013f974d8 100644
--- a/Documentation/kernel-parameters.txt
+++ b/Documentation/kernel-parameters.txt
@@ -198,6 +198,18 @@ and is between 256 and 4096 characters. It is defined in the file
198 that require a timer override, but don't have 198 that require a timer override, but don't have
199 HPET 199 HPET
200 200
201 acpi_backlight= [HW,ACPI]
202 acpi_backlight=vendor
203 acpi_backlight=video
204 If set to vendor, prefer vendor specific driver
205 (e.g. thinkpad_acpi, sony_acpi, etc.) instead
206 of the ACPI video.ko driver.
207
208 acpi_display_output= [HW,ACPI]
209 acpi_display_output=vendor
210 acpi_display_output=video
211 See above.
212
201 acpi.debug_layer= [HW,ACPI] 213 acpi.debug_layer= [HW,ACPI]
202 Format: <int> 214 Format: <int>
203 Each bit of the <int> indicates an ACPI debug layer, 215 Each bit of the <int> indicates an ACPI debug layer,
diff --git a/drivers/acpi/Makefile b/drivers/acpi/Makefile
index d91c027ece8f..c03810aa19c0 100644
--- a/drivers/acpi/Makefile
+++ b/drivers/acpi/Makefile
@@ -46,6 +46,10 @@ obj-$(CONFIG_ACPI_BUTTON) += button.o
46obj-$(CONFIG_ACPI_FAN) += fan.o 46obj-$(CONFIG_ACPI_FAN) += fan.o
47obj-$(CONFIG_ACPI_DOCK) += dock.o 47obj-$(CONFIG_ACPI_DOCK) += dock.o
48obj-$(CONFIG_ACPI_VIDEO) += video.o 48obj-$(CONFIG_ACPI_VIDEO) += video.o
49ifdef CONFIG_ACPI_VIDEO
50obj-y += video_detect.o
51endif
52
49obj-y += pci_root.o pci_link.o pci_irq.o pci_bind.o 53obj-y += pci_root.o pci_link.o pci_irq.o pci_bind.o
50obj-$(CONFIG_ACPI_PCI_SLOT) += pci_slot.o 54obj-$(CONFIG_ACPI_PCI_SLOT) += pci_slot.o
51obj-$(CONFIG_ACPI_PROCESSOR) += processor.o 55obj-$(CONFIG_ACPI_PROCESSOR) += processor.o
diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c
index a9dda8e0f9f9..556b182001ca 100644
--- a/drivers/acpi/scan.c
+++ b/drivers/acpi/scan.c
@@ -919,36 +919,6 @@ static void acpi_device_get_busid(struct acpi_device *device,
919 } 919 }
920} 920}
921 921
922static int
923acpi_video_bus_match(struct acpi_device *device)
924{
925 acpi_handle h_dummy;
926
927 if (!device)
928 return -EINVAL;
929
930 /* Since there is no HID, CID for ACPI Video drivers, we have
931 * to check well known required nodes for each feature we support.
932 */
933
934 /* Does this device able to support video switching ? */
935 if (ACPI_SUCCESS(acpi_get_handle(device->handle, "_DOD", &h_dummy)) &&
936 ACPI_SUCCESS(acpi_get_handle(device->handle, "_DOS", &h_dummy)))
937 return 0;
938
939 /* Does this device able to retrieve a video ROM ? */
940 if (ACPI_SUCCESS(acpi_get_handle(device->handle, "_ROM", &h_dummy)))
941 return 0;
942
943 /* Does this device able to configure which video head to be POSTed ? */
944 if (ACPI_SUCCESS(acpi_get_handle(device->handle, "_VPO", &h_dummy)) &&
945 ACPI_SUCCESS(acpi_get_handle(device->handle, "_GPD", &h_dummy)) &&
946 ACPI_SUCCESS(acpi_get_handle(device->handle, "_SPD", &h_dummy)))
947 return 0;
948
949 return -ENODEV;
950}
951
952/* 922/*
953 * acpi_bay_match - see if a device is an ejectable driver bay 923 * acpi_bay_match - see if a device is an ejectable driver bay
954 * 924 *
@@ -1031,7 +1001,7 @@ static void acpi_device_set_id(struct acpi_device *device,
1031 will get autoloaded and the device might still match 1001 will get autoloaded and the device might still match
1032 against another driver. 1002 against another driver.
1033 */ 1003 */
1034 if (ACPI_SUCCESS(acpi_video_bus_match(device))) 1004 if (acpi_is_video_device(device))
1035 cid_add = ACPI_VIDEO_HID; 1005 cid_add = ACPI_VIDEO_HID;
1036 else if (ACPI_SUCCESS(acpi_bay_match(device))) 1006 else if (ACPI_SUCCESS(acpi_bay_match(device)))
1037 cid_add = ACPI_BAY_HID; 1007 cid_add = ACPI_BAY_HID;
diff --git a/drivers/acpi/video.c b/drivers/acpi/video.c
index 6597c2a37c36..2097c399dd06 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)
739 device->cap._DSS = 1; 739 device->cap._DSS = 1;
740 } 740 }
741 741
742 max_level = acpi_video_init_brightness(device); 742 if (acpi_video_backlight_support())
743 max_level = acpi_video_init_brightness(device);
743 744
744 if (device->cap._BCL && device->cap._BCM && max_level > 0) { 745 if (device->cap._BCL && device->cap._BCM && max_level > 0) {
745 int result; 746 int result;
@@ -785,18 +786,21 @@ static void acpi_video_device_find_cap(struct acpi_video_device *device)
785 printk(KERN_ERR PREFIX "Create sysfs link\n"); 786 printk(KERN_ERR PREFIX "Create sysfs link\n");
786 787
787 } 788 }
788 if (device->cap._DCS && device->cap._DSS){ 789
789 static int count = 0; 790 if (acpi_video_display_switch_support()) {
790 char *name; 791
791 name = kzalloc(MAX_NAME_LEN, GFP_KERNEL); 792 if (device->cap._DCS && device->cap._DSS) {
792 if (!name) 793 static int count;
793 return; 794 char *name;
794 sprintf(name, "acpi_video%d", count++); 795 name = kzalloc(MAX_NAME_LEN, GFP_KERNEL);
795 device->output_dev = video_output_register(name, 796 if (!name)
796 NULL, device, &acpi_output_properties); 797 return;
797 kfree(name); 798 sprintf(name, "acpi_video%d", count++);
799 device->output_dev = video_output_register(name,
800 NULL, device, &acpi_output_properties);
801 kfree(name);
802 }
798 } 803 }
799 return;
800} 804}
801 805
802/* 806/*
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);
diff --git a/include/linux/acpi.h b/include/linux/acpi.h
index fd6a452b0ceb..7f23761ace35 100644
--- a/include/linux/acpi.h
+++ b/include/linux/acpi.h
@@ -194,6 +194,50 @@ extern bool wmi_has_guid(const char *guid);
194 194
195#endif /* CONFIG_ACPI_WMI */ 195#endif /* CONFIG_ACPI_WMI */
196 196
197#define ACPI_VIDEO_OUTPUT_SWITCHING 0x0001
198#define ACPI_VIDEO_DEVICE_POSTING 0x0002
199#define ACPI_VIDEO_ROM_AVAILABLE 0x0004
200#define ACPI_VIDEO_BACKLIGHT 0x0008
201#define ACPI_VIDEO_BACKLIGHT_FORCE_VENDOR 0x0010
202#define ACPI_VIDEO_BACKLIGHT_FORCE_VIDEO 0x0020
203#define ACPI_VIDEO_OUTPUT_SWITCHING_FORCE_VENDOR 0x0040
204#define ACPI_VIDEO_OUTPUT_SWITCHING_FORCE_VIDEO 0x0080
205#define ACPI_VIDEO_BACKLIGHT_DMI_VENDOR 0x0100
206#define ACPI_VIDEO_BACKLIGHT_DMI_VIDEO 0x0200
207#define ACPI_VIDEO_OUTPUT_SWITCHING_DMI_VENDOR 0x0400
208#define ACPI_VIDEO_OUTPUT_SWITCHING_DMI_VIDEO 0x0800
209
210#if defined(CONFIG_ACPI_VIDEO) || defined(CONFIG_ACPI_VIDEO_MODULE)
211
212extern long acpi_video_get_capabilities(acpi_handle graphics_dev_handle);
213extern long acpi_is_video_device(struct acpi_device *device);
214extern int acpi_video_backlight_support(void);
215extern int acpi_video_display_switch_support(void);
216
217#else
218
219static inline long acpi_video_get_capabilities(acpi_handle graphics_dev_handle)
220{
221 return 0;
222}
223
224static inline long acpi_is_video_device(struct acpi_device *device)
225{
226 return 0;
227}
228
229static inline int acpi_video_backlight_support(void)
230{
231 return 0;
232}
233
234static inline int acpi_video_display_switch_support(void)
235{
236 return 0;
237}
238
239#endif /* defined(CONFIG_ACPI_VIDEO) || defined(CONFIG_ACPI_VIDEO_MODULE) */
240
197extern int acpi_blacklisted(void); 241extern int acpi_blacklisted(void);
198#ifdef CONFIG_DMI 242#ifdef CONFIG_DMI
199extern void acpi_dmi_osi_linux(int enable, const struct dmi_system_id *d); 243extern void acpi_dmi_osi_linux(int enable, const struct dmi_system_id *d);