1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36#include <linux/export.h>
37#include <linux/acpi.h>
38#include <linux/dmi.h>
39#include <linux/pci.h>
40
41#include "internal.h"
42
43#define PREFIX "ACPI: "
44
45ACPI_MODULE_NAME("video");
46#define _COMPONENT ACPI_VIDEO_COMPONENT
47
48static long acpi_video_support;
49static bool acpi_video_caps_checked;
50
51static acpi_status
52acpi_backlight_cap_match(acpi_handle handle, u32 level, void *context,
53 void **retyurn_value)
54{
55 long *cap = context;
56
57 if (acpi_has_method(handle, "_BCM") &&
58 acpi_has_method(handle, "_BCL")) {
59 ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Found generic backlight "
60 "support\n"));
61 *cap |= ACPI_VIDEO_BACKLIGHT;
62 if (!acpi_has_method(handle, "_BQC"))
63 printk(KERN_WARNING FW_BUG PREFIX "No _BQC method, "
64 "cannot determine initial brightness\n");
65
66 return AE_CTRL_TERMINATE;
67 }
68 return 0;
69}
70
71
72
73
74
75
76
77
78
79long acpi_is_video_device(acpi_handle handle)
80{
81 long video_caps = 0;
82
83
84 if (acpi_has_method(handle, "_DOD") || acpi_has_method(handle, "_DOS"))
85 video_caps |= ACPI_VIDEO_OUTPUT_SWITCHING;
86
87
88 if (acpi_has_method(handle, "_ROM"))
89 video_caps |= ACPI_VIDEO_ROM_AVAILABLE;
90
91
92 if (acpi_has_method(handle, "_VPO") &&
93 acpi_has_method(handle, "_GPD") &&
94 acpi_has_method(handle, "_SPD"))
95 video_caps |= ACPI_VIDEO_DEVICE_POSTING;
96
97
98 if (video_caps)
99 acpi_walk_namespace(ACPI_TYPE_DEVICE, handle,
100 ACPI_UINT32_MAX, acpi_backlight_cap_match, NULL,
101 &video_caps, NULL);
102
103 return video_caps;
104}
105EXPORT_SYMBOL(acpi_is_video_device);
106
107static acpi_status
108find_video(acpi_handle handle, u32 lvl, void *context, void **rv)
109{
110 long *cap = context;
111 struct pci_dev *dev;
112 struct acpi_device *acpi_dev;
113
114 const struct acpi_device_id video_ids[] = {
115 {ACPI_VIDEO_HID, 0},
116 {"", 0},
117 };
118 if (acpi_bus_get_device(handle, &acpi_dev))
119 return AE_OK;
120
121 if (!acpi_match_device_ids(acpi_dev, video_ids)) {
122 dev = acpi_get_pci_dev(handle);
123 if (!dev)
124 return AE_OK;
125 pci_dev_put(dev);
126 *cap |= acpi_is_video_device(handle);
127 }
128 return AE_OK;
129}
130
131
132
133static int video_detect_force_vendor(const struct dmi_system_id *d)
134{
135 acpi_video_support |= ACPI_VIDEO_BACKLIGHT_DMI_VENDOR;
136 return 0;
137}
138
139static struct dmi_system_id video_detect_dmi_table[] = {
140
141
142
143
144
145
146 {
147 .callback = video_detect_force_vendor,
148 .ident = "X360",
149 .matches = {
150 DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."),
151 DMI_MATCH(DMI_PRODUCT_NAME, "X360"),
152 DMI_MATCH(DMI_BOARD_NAME, "X360"),
153 },
154 },
155 {
156 .callback = video_detect_force_vendor,
157 .ident = "Asus UL30VT",
158 .matches = {
159 DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK Computer Inc."),
160 DMI_MATCH(DMI_PRODUCT_NAME, "UL30VT"),
161 },
162 },
163 {
164 .callback = video_detect_force_vendor,
165 .ident = "Asus UL30A",
166 .matches = {
167 DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK Computer Inc."),
168 DMI_MATCH(DMI_PRODUCT_NAME, "UL30A"),
169 },
170 },
171 { },
172};
173
174
175
176
177
178
179
180
181long acpi_video_get_capabilities(acpi_handle graphics_handle)
182{
183 long caps = 0;
184 struct acpi_device *tmp_dev;
185 acpi_status status;
186
187 if (acpi_video_caps_checked && graphics_handle == NULL)
188 return acpi_video_support;
189
190 if (!graphics_handle) {
191
192 acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT,
193 ACPI_UINT32_MAX, find_video, NULL,
194 &caps, NULL);
195
196 acpi_video_support |= caps;
197 acpi_video_caps_checked = 1;
198
199
200
201
202
203
204
205
206
207 dmi_check_system(video_detect_dmi_table);
208 } else {
209 status = acpi_bus_get_device(graphics_handle, &tmp_dev);
210 if (ACPI_FAILURE(status)) {
211 ACPI_EXCEPTION((AE_INFO, status, "Invalid device"));
212 return 0;
213 }
214 acpi_walk_namespace(ACPI_TYPE_DEVICE, graphics_handle,
215 ACPI_UINT32_MAX, find_video, NULL,
216 &caps, NULL);
217 }
218 ACPI_DEBUG_PRINT((ACPI_DB_INFO, "We have 0x%lX video support %s %s\n",
219 graphics_handle ? caps : acpi_video_support,
220 graphics_handle ? "on device " : "in general",
221 graphics_handle ? acpi_device_bid(tmp_dev) : ""));
222 return caps;
223}
224EXPORT_SYMBOL(acpi_video_get_capabilities);
225
226static void acpi_video_caps_check(void)
227{
228
229
230
231
232 if (!acpi_video_caps_checked)
233 acpi_video_get_capabilities(NULL);
234}
235
236bool acpi_video_backlight_quirks(void)
237{
238 return acpi_gbl_osi_data >= ACPI_OSI_WIN_8;
239}
240EXPORT_SYMBOL(acpi_video_backlight_quirks);
241
242
243
244
245
246
247
248void acpi_video_dmi_promote_vendor(void)
249{
250 acpi_video_caps_check();
251 acpi_video_support |= ACPI_VIDEO_BACKLIGHT_DMI_VENDOR;
252}
253EXPORT_SYMBOL(acpi_video_dmi_promote_vendor);
254
255
256
257void acpi_video_dmi_demote_vendor(void)
258{
259 acpi_video_caps_check();
260 acpi_video_support &= ~ACPI_VIDEO_BACKLIGHT_DMI_VENDOR;
261}
262EXPORT_SYMBOL(acpi_video_dmi_demote_vendor);
263
264
265int acpi_video_backlight_support(void)
266{
267 acpi_video_caps_check();
268
269
270 if (acpi_video_support & ACPI_VIDEO_BACKLIGHT_FORCE_VENDOR)
271 return 0;
272 else if (acpi_video_support & ACPI_VIDEO_BACKLIGHT_FORCE_VIDEO)
273 return 1;
274
275
276 if (acpi_video_support & ACPI_VIDEO_BACKLIGHT_DMI_VENDOR)
277 return 0;
278 else if (acpi_video_support & ACPI_VIDEO_BACKLIGHT_DMI_VIDEO)
279 return 1;
280
281
282 return acpi_video_support & ACPI_VIDEO_BACKLIGHT;
283}
284EXPORT_SYMBOL(acpi_video_backlight_support);
285
286
287
288
289
290static int __init acpi_backlight(char *str)
291{
292 if (str == NULL || *str == '\0')
293 return 1;
294 else {
295 if (!strcmp("vendor", str))
296 acpi_video_support |=
297 ACPI_VIDEO_BACKLIGHT_FORCE_VENDOR;
298 if (!strcmp("video", str))
299 acpi_video_support |=
300 ACPI_VIDEO_BACKLIGHT_FORCE_VIDEO;
301 }
302 return 1;
303}
304__setup("acpi_backlight=", acpi_backlight);
305