ACPI video: remove output switching control
[GitHub/mt8127/android_kernel_alcatel_ttab.git] / drivers / acpi / video.c
CommitLineData
1da177e4
LT
1/*
2 * video.c - ACPI Video Driver ($Revision:$)
3 *
4 * Copyright (C) 2004 Luming Yu <luming.yu@intel.com>
5 * Copyright (C) 2004 Bruno Ducrot <ducrot@poupinou.org>
f4715189 6 * Copyright (C) 2006 Thomas Tuttle <linux-kernel@ttuttle.net>
1da177e4
LT
7 *
8 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or (at
13 * your option) any later version.
14 *
15 * This program is distributed in the hope that it will be useful, but
16 * WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 * General Public License for more details.
19 *
20 * You should have received a copy of the GNU General Public License along
21 * with this program; if not, write to the Free Software Foundation, Inc.,
22 * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
23 *
24 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
25 */
26
27#include <linux/kernel.h>
28#include <linux/module.h>
29#include <linux/init.h>
30#include <linux/types.h>
31#include <linux/list.h>
bbac81f5 32#include <linux/mutex.h>
e9dab196 33#include <linux/input.h>
2f3d000a 34#include <linux/backlight.h>
702ed512 35#include <linux/thermal.h>
935e5f29 36#include <linux/sort.h>
74a365b3
MG
37#include <linux/pci.h>
38#include <linux/pci_ids.h>
5a0e3ad6 39#include <linux/slab.h>
1da177e4 40#include <asm/uaccess.h>
eb27cae8 41#include <linux/dmi.h>
1da177e4
LT
42#include <acpi/acpi_bus.h>
43#include <acpi/acpi_drivers.h>
ac7729da 44#include <linux/suspend.h>
e92a7162 45#include <acpi/video.h>
1da177e4 46
a192a958
LB
47#define PREFIX "ACPI: "
48
1da177e4 49#define ACPI_VIDEO_CLASS "video"
1da177e4
LT
50#define ACPI_VIDEO_BUS_NAME "Video Bus"
51#define ACPI_VIDEO_DEVICE_NAME "Video Device"
52#define ACPI_VIDEO_NOTIFY_SWITCH 0x80
53#define ACPI_VIDEO_NOTIFY_PROBE 0x81
54#define ACPI_VIDEO_NOTIFY_CYCLE 0x82
55#define ACPI_VIDEO_NOTIFY_NEXT_OUTPUT 0x83
56#define ACPI_VIDEO_NOTIFY_PREV_OUTPUT 0x84
57
f4715189
TT
58#define ACPI_VIDEO_NOTIFY_CYCLE_BRIGHTNESS 0x85
59#define ACPI_VIDEO_NOTIFY_INC_BRIGHTNESS 0x86
60#define ACPI_VIDEO_NOTIFY_DEC_BRIGHTNESS 0x87
61#define ACPI_VIDEO_NOTIFY_ZERO_BRIGHTNESS 0x88
62#define ACPI_VIDEO_NOTIFY_DISPLAY_OFF 0x89
1da177e4 63
2f3d000a 64#define MAX_NAME_LEN 20
1da177e4 65
1da177e4 66#define _COMPONENT ACPI_VIDEO_COMPONENT
f52fd66d 67ACPI_MODULE_NAME("video");
1da177e4 68
f52fd66d 69MODULE_AUTHOR("Bruno Ducrot");
7cda93e0 70MODULE_DESCRIPTION("ACPI Video Driver");
1da177e4
LT
71MODULE_LICENSE("GPL");
72
8a681a4d
ZR
73static int brightness_switch_enabled = 1;
74module_param(brightness_switch_enabled, bool, 0644);
75
c504f8cb
ZR
76/*
77 * By default, we don't allow duplicate ACPI video bus devices
78 * under the same VGA controller
79 */
80static int allow_duplicates;
81module_param(allow_duplicates, bool, 0644);
82
86e437f0 83static int register_count = 0;
4be44fcd
LB
84static int acpi_video_bus_add(struct acpi_device *device);
85static int acpi_video_bus_remove(struct acpi_device *device, int type);
7015558f 86static void acpi_video_bus_notify(struct acpi_device *device, u32 event);
1da177e4 87
1ba90e3a
TR
88static const struct acpi_device_id video_device_ids[] = {
89 {ACPI_VIDEO_HID, 0},
90 {"", 0},
91};
92MODULE_DEVICE_TABLE(acpi, video_device_ids);
93
1da177e4 94static struct acpi_driver acpi_video_bus = {
c2b6705b 95 .name = "video",
1da177e4 96 .class = ACPI_VIDEO_CLASS,
1ba90e3a 97 .ids = video_device_ids,
1da177e4
LT
98 .ops = {
99 .add = acpi_video_bus_add,
100 .remove = acpi_video_bus_remove,
7015558f 101 .notify = acpi_video_bus_notify,
4be44fcd 102 },
1da177e4
LT
103};
104
105struct acpi_video_bus_flags {
4be44fcd
LB
106 u8 multihead:1; /* can switch video heads */
107 u8 rom:1; /* can retrieve a video rom */
108 u8 post:1; /* can configure the head to */
109 u8 reserved:5;
1da177e4
LT
110};
111
112struct acpi_video_bus_cap {
4be44fcd
LB
113 u8 _DOS:1; /*Enable/Disable output switching */
114 u8 _DOD:1; /*Enumerate all devices attached to display adapter */
115 u8 _ROM:1; /*Get ROM Data */
116 u8 _GPD:1; /*Get POST Device */
117 u8 _SPD:1; /*Set POST Device */
118 u8 _VPO:1; /*Video POST Options */
119 u8 reserved:2;
1da177e4
LT
120};
121
4be44fcd
LB
122struct acpi_video_device_attrib {
123 u32 display_index:4; /* A zero-based instance of the Display */
98fb8fe1 124 u32 display_port_attachment:4; /*This field differentiates the display type */
4be44fcd 125 u32 display_type:4; /*Describe the specific type in use */
98fb8fe1 126 u32 vendor_specific:4; /*Chipset Vendor Specific */
4be44fcd
LB
127 u32 bios_can_detect:1; /*BIOS can detect the device */
128 u32 depend_on_vga:1; /*Non-VGA output device whose power is related to
129 the VGA device. */
130 u32 pipe_id:3; /*For VGA multiple-head devices. */
131 u32 reserved:10; /*Must be 0 */
132 u32 device_id_scheme:1; /*Device ID Scheme */
1da177e4
LT
133};
134
135struct acpi_video_enumerated_device {
136 union {
137 u32 int_val;
4be44fcd 138 struct acpi_video_device_attrib attrib;
1da177e4
LT
139 } value;
140 struct acpi_video_device *bind_info;
141};
142
143struct acpi_video_bus {
e6afa0de 144 struct acpi_device *device;
4be44fcd 145 u8 dos_setting;
1da177e4 146 struct acpi_video_enumerated_device *attached_array;
4be44fcd
LB
147 u8 attached_count;
148 struct acpi_video_bus_cap cap;
1da177e4 149 struct acpi_video_bus_flags flags;
4be44fcd 150 struct list_head video_device_list;
bbac81f5 151 struct mutex device_list_lock; /* protects video_device_list */
e9dab196
LY
152 struct input_dev *input;
153 char phys[32]; /* for input device */
ac7729da 154 struct notifier_block pm_nb;
1da177e4
LT
155};
156
157struct acpi_video_device_flags {
4be44fcd
LB
158 u8 crt:1;
159 u8 lcd:1;
160 u8 tvout:1;
82cae999 161 u8 dvi:1;
4be44fcd
LB
162 u8 bios:1;
163 u8 unknown:1;
82cae999 164 u8 reserved:2;
1da177e4
LT
165};
166
167struct acpi_video_device_cap {
4be44fcd
LB
168 u8 _ADR:1; /*Return the unique ID */
169 u8 _BCL:1; /*Query list of brightness control levels supported */
170 u8 _BCM:1; /*Set the brightness level */
2f3d000a 171 u8 _BQC:1; /* Get current brightness level */
c60d638e 172 u8 _BCQ:1; /* Some buggy BIOS uses _BCQ instead of _BQC */
4be44fcd 173 u8 _DDC:1; /*Return the EDID for this device */
1da177e4
LT
174};
175
d32f6947
ZR
176struct acpi_video_brightness_flags {
177 u8 _BCL_no_ac_battery_levels:1; /* no AC/Battery levels in _BCL */
d80fb99f 178 u8 _BCL_reversed:1; /* _BCL package is in a reversed order*/
1a7c618a
ZR
179 u8 _BCL_use_index:1; /* levels in _BCL are index values */
180 u8 _BCM_use_index:1; /* input of _BCM is an index value */
181 u8 _BQC_use_index:1; /* _BQC returns an index value */
d32f6947
ZR
182};
183
1da177e4 184struct acpi_video_device_brightness {
4be44fcd
LB
185 int curr;
186 int count;
187 int *levels;
d32f6947 188 struct acpi_video_brightness_flags flags;
1da177e4
LT
189};
190
191struct acpi_video_device {
4be44fcd
LB
192 unsigned long device_id;
193 struct acpi_video_device_flags flags;
194 struct acpi_video_device_cap cap;
195 struct list_head entry;
196 struct acpi_video_bus *video;
197 struct acpi_device *dev;
1da177e4 198 struct acpi_video_device_brightness *brightness;
2f3d000a 199 struct backlight_device *backlight;
4a703a8f 200 struct thermal_cooling_device *cooling_dev;
1da177e4
LT
201};
202
b7171ae7 203static const char device_decode[][30] = {
1da177e4
LT
204 "motherboard VGA device",
205 "PCI VGA device",
206 "AGP VGA device",
207 "UNKNOWN",
208};
209
4be44fcd
LB
210static void acpi_video_device_notify(acpi_handle handle, u32 event, void *data);
211static void acpi_video_device_rebind(struct acpi_video_bus *video);
212static void acpi_video_device_bind(struct acpi_video_bus *video,
213 struct acpi_video_device *device);
1da177e4 214static int acpi_video_device_enumerate(struct acpi_video_bus *video);
2f3d000a
YL
215static int acpi_video_device_lcd_set_level(struct acpi_video_device *device,
216 int level);
217static int acpi_video_device_lcd_get_level_current(
218 struct acpi_video_device *device,
70287db8 219 unsigned long long *level, int init);
4be44fcd
LB
220static int acpi_video_get_next_level(struct acpi_video_device *device,
221 u32 level_current, u32 event);
c8890f90 222static int acpi_video_switch_brightness(struct acpi_video_device *device,
4be44fcd 223 int event);
1da177e4 224
2f3d000a
YL
225/*backlight device sysfs support*/
226static int acpi_video_get_brightness(struct backlight_device *bd)
227{
27663c58 228 unsigned long long cur_level;
38531e6f 229 int i;
2f3d000a 230 struct acpi_video_device *vd =
655bfd7a 231 (struct acpi_video_device *)bl_get_data(bd);
c8890f90 232
70287db8 233 if (acpi_video_device_lcd_get_level_current(vd, &cur_level, 0))
c8890f90 234 return -EINVAL;
38531e6f
MG
235 for (i = 2; i < vd->brightness->count; i++) {
236 if (vd->brightness->levels[i] == cur_level)
237 /* The first two entries are special - see page 575
238 of the ACPI spec 3.0 */
239 return i-2;
240 }
241 return 0;
2f3d000a
YL
242}
243
244static int acpi_video_set_brightness(struct backlight_device *bd)
245{
24450c7a 246 int request_level = bd->props.brightness + 2;
2f3d000a 247 struct acpi_video_device *vd =
655bfd7a 248 (struct acpi_video_device *)bl_get_data(bd);
24450c7a
ZR
249
250 return acpi_video_device_lcd_set_level(vd,
251 vd->brightness->levels[request_level]);
2f3d000a
YL
252}
253
599a52d1
RP
254static struct backlight_ops acpi_backlight_ops = {
255 .get_brightness = acpi_video_get_brightness,
256 .update_status = acpi_video_set_brightness,
257};
258
702ed512 259/* thermal cooling device callbacks */
4a703a8f 260static int video_get_max_state(struct thermal_cooling_device *cooling_dev, unsigned
6503e5df 261 long *state)
702ed512 262{
4a703a8f 263 struct acpi_device *device = cooling_dev->devdata;
702ed512
ZR
264 struct acpi_video_device *video = acpi_driver_data(device);
265
6503e5df
MG
266 *state = video->brightness->count - 3;
267 return 0;
702ed512
ZR
268}
269
4a703a8f 270static int video_get_cur_state(struct thermal_cooling_device *cooling_dev, unsigned
6503e5df 271 long *state)
702ed512 272{
4a703a8f 273 struct acpi_device *device = cooling_dev->devdata;
702ed512 274 struct acpi_video_device *video = acpi_driver_data(device);
27663c58 275 unsigned long long level;
6503e5df 276 int offset;
702ed512 277
70287db8 278 if (acpi_video_device_lcd_get_level_current(video, &level, 0))
c8890f90 279 return -EINVAL;
6503e5df
MG
280 for (offset = 2; offset < video->brightness->count; offset++)
281 if (level == video->brightness->levels[offset]) {
282 *state = video->brightness->count - offset - 1;
283 return 0;
284 }
702ed512
ZR
285
286 return -EINVAL;
287}
288
289static int
4a703a8f 290video_set_cur_state(struct thermal_cooling_device *cooling_dev, unsigned long state)
702ed512 291{
4a703a8f 292 struct acpi_device *device = cooling_dev->devdata;
702ed512
ZR
293 struct acpi_video_device *video = acpi_driver_data(device);
294 int level;
295
296 if ( state >= video->brightness->count - 2)
297 return -EINVAL;
298
299 state = video->brightness->count - state;
300 level = video->brightness->levels[state -1];
301 return acpi_video_device_lcd_set_level(video, level);
302}
303
304static struct thermal_cooling_device_ops video_cooling_ops = {
305 .get_max_state = video_get_max_state,
306 .get_cur_state = video_get_cur_state,
307 .set_cur_state = video_set_cur_state,
308};
309
1da177e4
LT
310/* --------------------------------------------------------------------------
311 Video Management
312 -------------------------------------------------------------------------- */
313
1da177e4 314static int
4be44fcd
LB
315acpi_video_device_lcd_query_levels(struct acpi_video_device *device,
316 union acpi_object **levels)
1da177e4 317{
4be44fcd
LB
318 int status;
319 struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
320 union acpi_object *obj;
1da177e4 321
1da177e4
LT
322
323 *levels = NULL;
324
90130268 325 status = acpi_evaluate_object(device->dev->handle, "_BCL", NULL, &buffer);
1da177e4 326 if (!ACPI_SUCCESS(status))
d550d98d 327 return status;
4be44fcd 328 obj = (union acpi_object *)buffer.pointer;
6665bda7 329 if (!obj || (obj->type != ACPI_TYPE_PACKAGE)) {
6468463a 330 printk(KERN_ERR PREFIX "Invalid _BCL data\n");
1da177e4
LT
331 status = -EFAULT;
332 goto err;
333 }
334
335 *levels = obj;
336
d550d98d 337 return 0;
1da177e4 338
4be44fcd 339 err:
6044ec88 340 kfree(buffer.pointer);
1da177e4 341
d550d98d 342 return status;
1da177e4
LT
343}
344
345static int
4be44fcd 346acpi_video_device_lcd_set_level(struct acpi_video_device *device, int level)
1da177e4 347{
24450c7a 348 int status;
4be44fcd
LB
349 union acpi_object arg0 = { ACPI_TYPE_INTEGER };
350 struct acpi_object_list args = { 1, &arg0 };
9e6dada9 351 int state;
1da177e4 352
1da177e4 353 arg0.integer.value = level;
1da177e4 354
24450c7a
ZR
355 status = acpi_evaluate_object(device->dev->handle, "_BCM",
356 &args, NULL);
357 if (ACPI_FAILURE(status)) {
358 ACPI_ERROR((AE_INFO, "Evaluating _BCM failed"));
359 return -EIO;
360 }
361
4500ca8e 362 device->brightness->curr = level;
9e6dada9 363 for (state = 2; state < device->brightness->count; state++)
24450c7a 364 if (level == device->brightness->levels[state]) {
1a7c618a
ZR
365 if (device->backlight)
366 device->backlight->props.brightness = state - 2;
24450c7a
ZR
367 return 0;
368 }
9e6dada9 369
24450c7a
ZR
370 ACPI_ERROR((AE_INFO, "Current brightness invalid"));
371 return -EINVAL;
1da177e4
LT
372}
373
45cb50e6
ZR
374/*
375 * For some buggy _BQC methods, we need to add a constant value to
376 * the _BQC return value to get the actual current brightness level
377 */
378
379static int bqc_offset_aml_bug_workaround;
380static int __init video_set_bqc_offset(const struct dmi_system_id *d)
381{
382 bqc_offset_aml_bug_workaround = 9;
383 return 0;
384}
385
386static struct dmi_system_id video_dmi_table[] __initdata = {
387 /*
388 * Broken _BQC workaround http://bugzilla.kernel.org/show_bug.cgi?id=13121
389 */
390 {
391 .callback = video_set_bqc_offset,
392 .ident = "Acer Aspire 5720",
393 .matches = {
394 DMI_MATCH(DMI_BOARD_VENDOR, "Acer"),
395 DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5720"),
396 },
397 },
5afc4abe
LB
398 {
399 .callback = video_set_bqc_offset,
400 .ident = "Acer Aspire 5710Z",
401 .matches = {
402 DMI_MATCH(DMI_BOARD_VENDOR, "Acer"),
403 DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5710Z"),
404 },
405 },
34ac272b
ZR
406 {
407 .callback = video_set_bqc_offset,
408 .ident = "eMachines E510",
409 .matches = {
410 DMI_MATCH(DMI_BOARD_VENDOR, "EMACHINES"),
411 DMI_MATCH(DMI_PRODUCT_NAME, "eMachines E510"),
412 },
413 },
93bcece2
ZR
414 {
415 .callback = video_set_bqc_offset,
416 .ident = "Acer Aspire 5315",
417 .matches = {
418 DMI_MATCH(DMI_BOARD_VENDOR, "Acer"),
419 DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5315"),
420 },
421 },
152a4e63
ZR
422 {
423 .callback = video_set_bqc_offset,
424 .ident = "Acer Aspire 7720",
425 .matches = {
426 DMI_MATCH(DMI_BOARD_VENDOR, "Acer"),
427 DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 7720"),
428 },
429 },
45cb50e6
ZR
430 {}
431};
432
1da177e4 433static int
4be44fcd 434acpi_video_device_lcd_get_level_current(struct acpi_video_device *device,
70287db8 435 unsigned long long *level, int init)
1da177e4 436{
c8890f90 437 acpi_status status = AE_OK;
4e231fa4 438 int i;
c8890f90 439
c60d638e
ZR
440 if (device->cap._BQC || device->cap._BCQ) {
441 char *buf = device->cap._BQC ? "_BQC" : "_BCQ";
442
443 status = acpi_evaluate_integer(device->dev->handle, buf,
c8890f90
ZR
444 NULL, level);
445 if (ACPI_SUCCESS(status)) {
1a7c618a
ZR
446 if (device->brightness->flags._BQC_use_index) {
447 if (device->brightness->flags._BCL_reversed)
448 *level = device->brightness->count
449 - 3 - (*level);
450 *level = device->brightness->levels[*level + 2];
451
452 }
45cb50e6 453 *level += bqc_offset_aml_bug_workaround;
4e231fa4
VS
454 for (i = 2; i < device->brightness->count; i++)
455 if (device->brightness->levels[i] == *level) {
456 device->brightness->curr = *level;
457 return 0;
458 }
70287db8
MG
459 if (!init) {
460 /*
461 * BQC returned an invalid level.
462 * Stop using it.
463 */
464 ACPI_WARNING((AE_INFO,
465 "%s returned an invalid level",
466 buf));
467 device->cap._BQC = device->cap._BCQ = 0;
468 }
c8890f90
ZR
469 } else {
470 /* Fixme:
471 * should we return an error or ignore this failure?
472 * dev->brightness->curr is a cached value which stores
473 * the correct current backlight level in most cases.
474 * ACPI video backlight still works w/ buggy _BQC.
475 * http://bugzilla.kernel.org/show_bug.cgi?id=12233
476 */
c60d638e
ZR
477 ACPI_WARNING((AE_INFO, "Evaluating %s failed", buf));
478 device->cap._BQC = device->cap._BCQ = 0;
c8890f90
ZR
479 }
480 }
481
4500ca8e 482 *level = device->brightness->curr;
c8890f90 483 return 0;
1da177e4
LT
484}
485
486static int
4be44fcd
LB
487acpi_video_device_EDID(struct acpi_video_device *device,
488 union acpi_object **edid, ssize_t length)
1da177e4 489{
4be44fcd
LB
490 int status;
491 struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
492 union acpi_object *obj;
493 union acpi_object arg0 = { ACPI_TYPE_INTEGER };
494 struct acpi_object_list args = { 1, &arg0 };
1da177e4 495
1da177e4
LT
496
497 *edid = NULL;
498
499 if (!device)
d550d98d 500 return -ENODEV;
1da177e4
LT
501 if (length == 128)
502 arg0.integer.value = 1;
503 else if (length == 256)
504 arg0.integer.value = 2;
505 else
d550d98d 506 return -EINVAL;
1da177e4 507
90130268 508 status = acpi_evaluate_object(device->dev->handle, "_DDC", &args, &buffer);
1da177e4 509 if (ACPI_FAILURE(status))
d550d98d 510 return -ENODEV;
1da177e4 511
50dd0969 512 obj = buffer.pointer;
1da177e4
LT
513
514 if (obj && obj->type == ACPI_TYPE_BUFFER)
515 *edid = obj;
516 else {
6468463a 517 printk(KERN_ERR PREFIX "Invalid _DDC data\n");
1da177e4
LT
518 status = -EFAULT;
519 kfree(obj);
520 }
521
d550d98d 522 return status;
1da177e4
LT
523}
524
1da177e4
LT
525/* bus */
526
1da177e4
LT
527/*
528 * Arg:
529 * video : video bus device pointer
530 * bios_flag :
531 * 0. The system BIOS should NOT automatically switch(toggle)
532 * the active display output.
533 * 1. The system BIOS should automatically switch (toggle) the
98fb8fe1 534 * active display output. No switch event.
1da177e4
LT
535 * 2. The _DGS value should be locked.
536 * 3. The system BIOS should not automatically switch (toggle) the
537 * active display output, but instead generate the display switch
538 * event notify code.
539 * lcd_flag :
540 * 0. The system BIOS should automatically control the brightness level
98fb8fe1 541 * of the LCD when the power changes from AC to DC
1da177e4 542 * 1. The system BIOS should NOT automatically control the brightness
98fb8fe1 543 * level of the LCD when the power changes from AC to DC.
1da177e4
LT
544 * Return Value:
545 * -1 wrong arg.
546 */
547
548static int
4be44fcd 549acpi_video_bus_DOS(struct acpi_video_bus *video, int bios_flag, int lcd_flag)
1da177e4 550{
439913ff 551 u64 status = 0;
4be44fcd
LB
552 union acpi_object arg0 = { ACPI_TYPE_INTEGER };
553 struct acpi_object_list args = { 1, &arg0 };
1da177e4 554
1da177e4 555
4be44fcd 556 if (bios_flag < 0 || bios_flag > 3 || lcd_flag < 0 || lcd_flag > 1) {
1da177e4
LT
557 status = -1;
558 goto Failed;
559 }
560 arg0.integer.value = (lcd_flag << 2) | bios_flag;
561 video->dos_setting = arg0.integer.value;
90130268 562 acpi_evaluate_object(video->device->handle, "_DOS", &args, NULL);
1da177e4 563
4be44fcd 564 Failed:
d550d98d 565 return status;
1da177e4
LT
566}
567
935e5f29
ZR
568/*
569 * Simple comparison function used to sort backlight levels.
570 */
571
572static int
573acpi_video_cmp_level(const void *a, const void *b)
574{
575 return *(int *)a - *(int *)b;
576}
577
1da177e4
LT
578/*
579 * Arg:
580 * device : video output device (LCD, CRT, ..)
581 *
582 * Return Value:
469778c1
JJ
583 * Maximum brightness level
584 *
585 * Allocate and initialize device->brightness.
586 */
587
588static int
589acpi_video_init_brightness(struct acpi_video_device *device)
590{
591 union acpi_object *obj = NULL;
d32f6947 592 int i, max_level = 0, count = 0, level_ac_battery = 0;
1a7c618a 593 unsigned long long level, level_old;
469778c1
JJ
594 union acpi_object *o;
595 struct acpi_video_device_brightness *br = NULL;
1a7c618a 596 int result = -EINVAL;
469778c1
JJ
597
598 if (!ACPI_SUCCESS(acpi_video_device_lcd_query_levels(device, &obj))) {
599 ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Could not query available "
600 "LCD brightness level\n"));
601 goto out;
602 }
603
604 if (obj->package.count < 2)
605 goto out;
606
607 br = kzalloc(sizeof(*br), GFP_KERNEL);
608 if (!br) {
609 printk(KERN_ERR "can't allocate memory\n");
1a7c618a 610 result = -ENOMEM;
469778c1
JJ
611 goto out;
612 }
613
d32f6947 614 br->levels = kmalloc((obj->package.count + 2) * sizeof *(br->levels),
469778c1 615 GFP_KERNEL);
1a7c618a
ZR
616 if (!br->levels) {
617 result = -ENOMEM;
469778c1 618 goto out_free;
1a7c618a 619 }
469778c1
JJ
620
621 for (i = 0; i < obj->package.count; i++) {
622 o = (union acpi_object *)&obj->package.elements[i];
623 if (o->type != ACPI_TYPE_INTEGER) {
624 printk(KERN_ERR PREFIX "Invalid data\n");
625 continue;
626 }
627 br->levels[count] = (u32) o->integer.value;
628
629 if (br->levels[count] > max_level)
630 max_level = br->levels[count];
631 count++;
632 }
633
d32f6947
ZR
634 /*
635 * some buggy BIOS don't export the levels
636 * when machine is on AC/Battery in _BCL package.
637 * In this case, the first two elements in _BCL packages
638 * are also supported brightness levels that OS should take care of.
639 */
90af2cf6
ZR
640 for (i = 2; i < count; i++) {
641 if (br->levels[i] == br->levels[0])
d32f6947 642 level_ac_battery++;
90af2cf6
ZR
643 if (br->levels[i] == br->levels[1])
644 level_ac_battery++;
645 }
d32f6947
ZR
646
647 if (level_ac_battery < 2) {
648 level_ac_battery = 2 - level_ac_battery;
649 br->flags._BCL_no_ac_battery_levels = 1;
650 for (i = (count - 1 + level_ac_battery); i >= 2; i--)
651 br->levels[i] = br->levels[i - level_ac_battery];
652 count += level_ac_battery;
653 } else if (level_ac_battery > 2)
654 ACPI_ERROR((AE_INFO, "Too many duplicates in _BCL package\n"));
655
d80fb99f
ZR
656 /* Check if the _BCL package is in a reversed order */
657 if (max_level == br->levels[2]) {
658 br->flags._BCL_reversed = 1;
659 sort(&br->levels[2], count - 2, sizeof(br->levels[2]),
660 acpi_video_cmp_level, NULL);
661 } else if (max_level != br->levels[count - 1])
662 ACPI_ERROR((AE_INFO,
663 "Found unordered _BCL package\n"));
469778c1
JJ
664
665 br->count = count;
666 device->brightness = br;
1a7c618a
ZR
667
668 /* Check the input/output of _BQC/_BCL/_BCM */
669 if ((max_level < 100) && (max_level <= (count - 2)))
670 br->flags._BCL_use_index = 1;
671
672 /*
673 * _BCM is always consistent with _BCL,
674 * at least for all the laptops we have ever seen.
675 */
676 br->flags._BCM_use_index = br->flags._BCL_use_index;
677
678 /* _BQC uses INDEX while _BCL uses VALUE in some laptops */
90c53ca4 679 br->curr = level = max_level;
e047cca6
ZR
680
681 if (!device->cap._BQC)
682 goto set_level;
683
70287db8 684 result = acpi_video_device_lcd_get_level_current(device, &level_old, 1);
1a7c618a
ZR
685 if (result)
686 goto out_free_levels;
687
e047cca6
ZR
688 /*
689 * Set the level to maximum and check if _BQC uses indexed value
690 */
691 result = acpi_video_device_lcd_set_level(device, max_level);
1a7c618a
ZR
692 if (result)
693 goto out_free_levels;
694
70287db8 695 result = acpi_video_device_lcd_get_level_current(device, &level, 0);
1a7c618a
ZR
696 if (result)
697 goto out_free_levels;
698
e047cca6
ZR
699 br->flags._BQC_use_index = (level == max_level ? 0 : 1);
700
90c53ca4
ZR
701 if (!br->flags._BQC_use_index) {
702 /*
703 * Set the backlight to the initial state.
704 * On some buggy laptops, _BQC returns an uninitialized value
705 * when invoked for the first time, i.e. level_old is invalid.
706 * set the backlight to max_level in this case
707 */
708 for (i = 2; i < br->count; i++)
709 if (level_old == br->levels[i])
710 level = level_old;
e047cca6 711 goto set_level;
90c53ca4 712 }
e047cca6
ZR
713
714 if (br->flags._BCL_reversed)
715 level_old = (br->count - 1) - level_old;
90c53ca4 716 level = br->levels[level_old];
e047cca6
ZR
717
718set_level:
90c53ca4 719 result = acpi_video_device_lcd_set_level(device, level);
e047cca6
ZR
720 if (result)
721 goto out_free_levels;
1a7c618a 722
d32f6947
ZR
723 ACPI_DEBUG_PRINT((ACPI_DB_INFO,
724 "found %d brightness levels\n", count - 2));
469778c1 725 kfree(obj);
1a7c618a 726 return result;
469778c1
JJ
727
728out_free_levels:
729 kfree(br->levels);
730out_free:
731 kfree(br);
732out:
733 device->brightness = NULL;
734 kfree(obj);
1a7c618a 735 return result;
469778c1
JJ
736}
737
738/*
739 * Arg:
740 * device : video output device (LCD, CRT, ..)
741 *
742 * Return Value:
1da177e4
LT
743 * None
744 *
98fb8fe1 745 * Find out all required AML methods defined under the output
1da177e4
LT
746 * device.
747 */
748
4be44fcd 749static void acpi_video_device_find_cap(struct acpi_video_device *device)
1da177e4 750{
1da177e4 751 acpi_handle h_dummy1;
1da177e4 752
90130268 753 if (ACPI_SUCCESS(acpi_get_handle(device->dev->handle, "_ADR", &h_dummy1))) {
1da177e4
LT
754 device->cap._ADR = 1;
755 }
90130268 756 if (ACPI_SUCCESS(acpi_get_handle(device->dev->handle, "_BCL", &h_dummy1))) {
4be44fcd 757 device->cap._BCL = 1;
1da177e4 758 }
90130268 759 if (ACPI_SUCCESS(acpi_get_handle(device->dev->handle, "_BCM", &h_dummy1))) {
4be44fcd 760 device->cap._BCM = 1;
1da177e4 761 }
2f3d000a
YL
762 if (ACPI_SUCCESS(acpi_get_handle(device->dev->handle,"_BQC",&h_dummy1)))
763 device->cap._BQC = 1;
c60d638e
ZR
764 else if (ACPI_SUCCESS(acpi_get_handle(device->dev->handle, "_BCQ",
765 &h_dummy1))) {
766 printk(KERN_WARNING FW_BUG "_BCQ is used instead of _BQC\n");
767 device->cap._BCQ = 1;
768 }
769
90130268 770 if (ACPI_SUCCESS(acpi_get_handle(device->dev->handle, "_DDC", &h_dummy1))) {
4be44fcd 771 device->cap._DDC = 1;
1da177e4 772 }
1da177e4 773
1a7c618a 774 if (acpi_video_backlight_support()) {
a19a6ee6 775 struct backlight_properties props;
702ed512 776 int result;
2f3d000a
YL
777 static int count = 0;
778 char *name;
1a7c618a
ZR
779
780 result = acpi_video_init_brightness(device);
781 if (result)
782 return;
aeb834d9 783 name = kasprintf(GFP_KERNEL, "acpi_video%d", count);
2f3d000a
YL
784 if (!name)
785 return;
aeb834d9 786 count++;
2f3d000a 787
a19a6ee6
MG
788 memset(&props, 0, sizeof(struct backlight_properties));
789 props.max_brightness = device->brightness->count - 3;
790 device->backlight = backlight_device_register(name, NULL, device,
791 &acpi_backlight_ops,
792 &props);
2f3d000a 793 kfree(name);
e01ce79b
ZR
794 if (IS_ERR(device->backlight))
795 return;
702ed512 796
ac7729da
RW
797 /*
798 * Save current brightness level in case we have to restore it
799 * before acpi_video_device_lcd_set_level() is called next time.
800 */
801 device->backlight->props.brightness =
802 acpi_video_get_brightness(device->backlight);
702ed512 803
056c308d
ZR
804 result = sysfs_create_link(&device->backlight->dev.kobj,
805 &device->dev->dev.kobj, "device");
806 if (result)
807 printk(KERN_ERR PREFIX "Create sysfs link\n");
808
4a703a8f 809 device->cooling_dev = thermal_cooling_device_register("LCD",
702ed512 810 device->dev, &video_cooling_ops);
4a703a8f 811 if (IS_ERR(device->cooling_dev)) {
4b4fe3b6 812 /*
4a703a8f 813 * Set cooling_dev to NULL so we don't crash trying to
4b4fe3b6
DT
814 * free it.
815 * Also, why the hell we are returning early and
816 * not attempt to register video output if cooling
817 * device registration failed?
818 * -- dtor
819 */
4a703a8f 820 device->cooling_dev = NULL;
43ff39f2 821 return;
4b4fe3b6 822 }
43ff39f2 823
fc3a8828 824 dev_info(&device->dev->dev, "registered as cooling_device%d\n",
4a703a8f 825 device->cooling_dev->id);
9030062f 826 result = sysfs_create_link(&device->dev->dev.kobj,
4a703a8f 827 &device->cooling_dev->device.kobj,
9030062f
JL
828 "thermal_cooling");
829 if (result)
830 printk(KERN_ERR PREFIX "Create sysfs link\n");
4a703a8f 831 result = sysfs_create_link(&device->cooling_dev->device.kobj,
9030062f
JL
832 &device->dev->dev.kobj, "device");
833 if (result)
834 printk(KERN_ERR PREFIX "Create sysfs link\n");
835
2f3d000a 836 }
1da177e4
LT
837}
838
839/*
840 * Arg:
841 * device : video output device (VGA)
842 *
843 * Return Value:
844 * None
845 *
98fb8fe1 846 * Find out all required AML methods defined under the video bus device.
1da177e4
LT
847 */
848
4be44fcd 849static void acpi_video_bus_find_cap(struct acpi_video_bus *video)
1da177e4 850{
4be44fcd 851 acpi_handle h_dummy1;
1da177e4 852
90130268 853 if (ACPI_SUCCESS(acpi_get_handle(video->device->handle, "_DOS", &h_dummy1))) {
1da177e4
LT
854 video->cap._DOS = 1;
855 }
90130268 856 if (ACPI_SUCCESS(acpi_get_handle(video->device->handle, "_DOD", &h_dummy1))) {
1da177e4
LT
857 video->cap._DOD = 1;
858 }
90130268 859 if (ACPI_SUCCESS(acpi_get_handle(video->device->handle, "_ROM", &h_dummy1))) {
1da177e4
LT
860 video->cap._ROM = 1;
861 }
90130268 862 if (ACPI_SUCCESS(acpi_get_handle(video->device->handle, "_GPD", &h_dummy1))) {
1da177e4
LT
863 video->cap._GPD = 1;
864 }
90130268 865 if (ACPI_SUCCESS(acpi_get_handle(video->device->handle, "_SPD", &h_dummy1))) {
1da177e4
LT
866 video->cap._SPD = 1;
867 }
90130268 868 if (ACPI_SUCCESS(acpi_get_handle(video->device->handle, "_VPO", &h_dummy1))) {
1da177e4
LT
869 video->cap._VPO = 1;
870 }
871}
872
873/*
874 * Check whether the video bus device has required AML method to
875 * support the desired features
876 */
877
4be44fcd 878static int acpi_video_bus_check(struct acpi_video_bus *video)
1da177e4 879{
4be44fcd 880 acpi_status status = -ENOENT;
1e4cffe7 881 struct pci_dev *dev;
1da177e4
LT
882
883 if (!video)
d550d98d 884 return -EINVAL;
1da177e4 885
1e4cffe7 886 dev = acpi_get_pci_dev(video->device->handle);
22c13f9d
TR
887 if (!dev)
888 return -ENODEV;
1e4cffe7 889 pci_dev_put(dev);
22c13f9d 890
1da177e4
LT
891 /* Since there is no HID, CID and so on for VGA driver, we have
892 * to check well known required nodes.
893 */
894
98fb8fe1 895 /* Does this device support video switching? */
3a1151e3
SB
896 if (video->cap._DOS || video->cap._DOD) {
897 if (!video->cap._DOS) {
898 printk(KERN_WARNING FW_BUG
899 "ACPI(%s) defines _DOD but not _DOS\n",
900 acpi_device_bid(video->device));
901 }
1da177e4
LT
902 video->flags.multihead = 1;
903 status = 0;
904 }
905
98fb8fe1 906 /* Does this device support retrieving a video ROM? */
4be44fcd 907 if (video->cap._ROM) {
1da177e4
LT
908 video->flags.rom = 1;
909 status = 0;
910 }
911
98fb8fe1 912 /* Does this device support configuring which video device to POST? */
4be44fcd 913 if (video->cap._GPD && video->cap._SPD && video->cap._VPO) {
1da177e4
LT
914 video->flags.post = 1;
915 status = 0;
916 }
917
d550d98d 918 return status;
1da177e4
LT
919}
920
1da177e4
LT
921/* --------------------------------------------------------------------------
922 Driver Interface
923 -------------------------------------------------------------------------- */
924
925/* device interface */
82cae999
RZ
926static struct acpi_video_device_attrib*
927acpi_video_get_device_attr(struct acpi_video_bus *video, unsigned long device_id)
928{
78eed028
DT
929 struct acpi_video_enumerated_device *ids;
930 int i;
931
932 for (i = 0; i < video->attached_count; i++) {
933 ids = &video->attached_array[i];
934 if ((ids->value.int_val & 0xffff) == device_id)
935 return &ids->value.attrib;
936 }
82cae999 937
82cae999
RZ
938 return NULL;
939}
1da177e4 940
e92a7162
MG
941static int
942acpi_video_get_device_type(struct acpi_video_bus *video,
943 unsigned long device_id)
944{
945 struct acpi_video_enumerated_device *ids;
946 int i;
947
948 for (i = 0; i < video->attached_count; i++) {
949 ids = &video->attached_array[i];
950 if ((ids->value.int_val & 0xffff) == device_id)
951 return ids->value.int_val;
952 }
953
954 return 0;
955}
956
1da177e4 957static int
4be44fcd
LB
958acpi_video_bus_get_one_device(struct acpi_device *device,
959 struct acpi_video_bus *video)
1da177e4 960{
27663c58 961 unsigned long long device_id;
e92a7162 962 int status, device_type;
4be44fcd 963 struct acpi_video_device *data;
82cae999 964 struct acpi_video_device_attrib* attribute;
1da177e4
LT
965
966 if (!device || !video)
d550d98d 967 return -EINVAL;
1da177e4 968
4be44fcd
LB
969 status =
970 acpi_evaluate_integer(device->handle, "_ADR", NULL, &device_id);
1da177e4
LT
971 if (ACPI_SUCCESS(status)) {
972
36bcbec7 973 data = kzalloc(sizeof(struct acpi_video_device), GFP_KERNEL);
1da177e4 974 if (!data)
d550d98d 975 return -ENOMEM;
1da177e4 976
1da177e4
LT
977 strcpy(acpi_device_name(device), ACPI_VIDEO_DEVICE_NAME);
978 strcpy(acpi_device_class(device), ACPI_VIDEO_CLASS);
db89b4f0 979 device->driver_data = data;
1da177e4
LT
980
981 data->device_id = device_id;
982 data->video = video;
983 data->dev = device;
984
82cae999
RZ
985 attribute = acpi_video_get_device_attr(video, device_id);
986
987 if((attribute != NULL) && attribute->device_id_scheme) {
988 switch (attribute->display_type) {
989 case ACPI_VIDEO_DISPLAY_CRT:
990 data->flags.crt = 1;
991 break;
992 case ACPI_VIDEO_DISPLAY_TV:
993 data->flags.tvout = 1;
994 break;
995 case ACPI_VIDEO_DISPLAY_DVI:
996 data->flags.dvi = 1;
997 break;
998 case ACPI_VIDEO_DISPLAY_LCD:
999 data->flags.lcd = 1;
1000 break;
1001 default:
1002 data->flags.unknown = 1;
1003 break;
1004 }
1005 if(attribute->bios_can_detect)
1006 data->flags.bios = 1;
e92a7162
MG
1007 } else {
1008 /* Check for legacy IDs */
1009 device_type = acpi_video_get_device_type(video,
1010 device_id);
1011 /* Ignore bits 16 and 18-20 */
1012 switch (device_type & 0xffe2ffff) {
1013 case ACPI_VIDEO_DISPLAY_LEGACY_MONITOR:
1014 data->flags.crt = 1;
1015 break;
1016 case ACPI_VIDEO_DISPLAY_LEGACY_PANEL:
1017 data->flags.lcd = 1;
1018 break;
1019 case ACPI_VIDEO_DISPLAY_LEGACY_TV:
1020 data->flags.tvout = 1;
1021 break;
1022 default:
1023 data->flags.unknown = 1;
1024 }
1025 }
4be44fcd 1026
1da177e4
LT
1027 acpi_video_device_bind(video, data);
1028 acpi_video_device_find_cap(data);
1029
90130268 1030 status = acpi_install_notify_handler(device->handle,
4be44fcd
LB
1031 ACPI_DEVICE_NOTIFY,
1032 acpi_video_device_notify,
1033 data);
1da177e4 1034 if (ACPI_FAILURE(status)) {
55ac9a01
LM
1035 printk(KERN_ERR PREFIX
1036 "Error installing notify handler\n");
973bf491
YL
1037 if(data->brightness)
1038 kfree(data->brightness->levels);
1039 kfree(data->brightness);
1040 kfree(data);
1041 return -ENODEV;
1da177e4
LT
1042 }
1043
bbac81f5 1044 mutex_lock(&video->device_list_lock);
1da177e4 1045 list_add_tail(&data->entry, &video->video_device_list);
bbac81f5 1046 mutex_unlock(&video->device_list_lock);
1da177e4 1047
d550d98d 1048 return 0;
1da177e4
LT
1049 }
1050
d550d98d 1051 return -ENOENT;
1da177e4
LT
1052}
1053
1054/*
1055 * Arg:
1056 * video : video bus device
1057 *
1058 * Return:
1059 * none
1060 *
1061 * Enumerate the video device list of the video bus,
1062 * bind the ids with the corresponding video devices
1063 * under the video bus.
4be44fcd 1064 */
1da177e4 1065
4be44fcd 1066static void acpi_video_device_rebind(struct acpi_video_bus *video)
1da177e4 1067{
ff102ea9
DT
1068 struct acpi_video_device *dev;
1069
bbac81f5 1070 mutex_lock(&video->device_list_lock);
ff102ea9
DT
1071
1072 list_for_each_entry(dev, &video->video_device_list, entry)
4be44fcd 1073 acpi_video_device_bind(video, dev);
ff102ea9 1074
bbac81f5 1075 mutex_unlock(&video->device_list_lock);
1da177e4
LT
1076}
1077
1078/*
1079 * Arg:
1080 * video : video bus device
1081 * device : video output device under the video
1082 * bus
1083 *
1084 * Return:
1085 * none
1086 *
1087 * Bind the ids with the corresponding video devices
1088 * under the video bus.
4be44fcd 1089 */
1da177e4
LT
1090
1091static void
4be44fcd
LB
1092acpi_video_device_bind(struct acpi_video_bus *video,
1093 struct acpi_video_device *device)
1da177e4 1094{
78eed028 1095 struct acpi_video_enumerated_device *ids;
4be44fcd 1096 int i;
1da177e4 1097
78eed028
DT
1098 for (i = 0; i < video->attached_count; i++) {
1099 ids = &video->attached_array[i];
1100 if (device->device_id == (ids->value.int_val & 0xffff)) {
1101 ids->bind_info = device;
1da177e4
LT
1102 ACPI_DEBUG_PRINT((ACPI_DB_INFO, "device_bind %d\n", i));
1103 }
1104 }
1da177e4
LT
1105}
1106
1107/*
1108 * Arg:
1109 * video : video bus device
1110 *
1111 * Return:
1112 * < 0 : error
1113 *
1114 * Call _DOD to enumerate all devices attached to display adapter
1115 *
4be44fcd 1116 */
1da177e4
LT
1117
1118static int acpi_video_device_enumerate(struct acpi_video_bus *video)
1119{
4be44fcd
LB
1120 int status;
1121 int count;
1122 int i;
78eed028 1123 struct acpi_video_enumerated_device *active_list;
4be44fcd
LB
1124 struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
1125 union acpi_object *dod = NULL;
1126 union acpi_object *obj;
1da177e4 1127
90130268 1128 status = acpi_evaluate_object(video->device->handle, "_DOD", NULL, &buffer);
1da177e4 1129 if (!ACPI_SUCCESS(status)) {
a6fc6720 1130 ACPI_EXCEPTION((AE_INFO, status, "Evaluating _DOD"));
d550d98d 1131 return status;
1da177e4
LT
1132 }
1133
50dd0969 1134 dod = buffer.pointer;
1da177e4 1135 if (!dod || (dod->type != ACPI_TYPE_PACKAGE)) {
a6fc6720 1136 ACPI_EXCEPTION((AE_INFO, status, "Invalid _DOD data"));
1da177e4
LT
1137 status = -EFAULT;
1138 goto out;
1139 }
1140
1141 ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Found %d video heads in _DOD\n",
4be44fcd 1142 dod->package.count));
1da177e4 1143
78eed028
DT
1144 active_list = kcalloc(1 + dod->package.count,
1145 sizeof(struct acpi_video_enumerated_device),
1146 GFP_KERNEL);
1147 if (!active_list) {
1da177e4
LT
1148 status = -ENOMEM;
1149 goto out;
1150 }
1151
1152 count = 0;
1153 for (i = 0; i < dod->package.count; i++) {
50dd0969 1154 obj = &dod->package.elements[i];
1da177e4
LT
1155
1156 if (obj->type != ACPI_TYPE_INTEGER) {
78eed028
DT
1157 printk(KERN_ERR PREFIX
1158 "Invalid _DOD data in element %d\n", i);
1159 continue;
1da177e4 1160 }
78eed028
DT
1161
1162 active_list[count].value.int_val = obj->integer.value;
1163 active_list[count].bind_info = NULL;
4be44fcd
LB
1164 ACPI_DEBUG_PRINT((ACPI_DB_INFO, "dod element[%d] = %d\n", i,
1165 (int)obj->integer.value));
1da177e4
LT
1166 count++;
1167 }
1da177e4 1168
6044ec88 1169 kfree(video->attached_array);
4be44fcd 1170
78eed028 1171 video->attached_array = active_list;
1da177e4 1172 video->attached_count = count;
78eed028
DT
1173
1174 out:
02438d87 1175 kfree(buffer.pointer);
d550d98d 1176 return status;
1da177e4
LT
1177}
1178
4be44fcd
LB
1179static int
1180acpi_video_get_next_level(struct acpi_video_device *device,
1181 u32 level_current, u32 event)
1da177e4 1182{
63f0edfc 1183 int min, max, min_above, max_below, i, l, delta = 255;
f4715189
TT
1184 max = max_below = 0;
1185 min = min_above = 255;
63f0edfc 1186 /* Find closest level to level_current */
0a3db1ce 1187 for (i = 2; i < device->brightness->count; i++) {
63f0edfc
AS
1188 l = device->brightness->levels[i];
1189 if (abs(l - level_current) < abs(delta)) {
1190 delta = l - level_current;
1191 if (!delta)
1192 break;
1193 }
1194 }
1195 /* Ajust level_current to closest available level */
1196 level_current += delta;
0a3db1ce 1197 for (i = 2; i < device->brightness->count; i++) {
f4715189
TT
1198 l = device->brightness->levels[i];
1199 if (l < min)
1200 min = l;
1201 if (l > max)
1202 max = l;
1203 if (l < min_above && l > level_current)
1204 min_above = l;
1205 if (l > max_below && l < level_current)
1206 max_below = l;
1207 }
1208
1209 switch (event) {
1210 case ACPI_VIDEO_NOTIFY_CYCLE_BRIGHTNESS:
1211 return (level_current < max) ? min_above : min;
1212 case ACPI_VIDEO_NOTIFY_INC_BRIGHTNESS:
1213 return (level_current < max) ? min_above : max;
1214 case ACPI_VIDEO_NOTIFY_DEC_BRIGHTNESS:
1215 return (level_current > min) ? max_below : min;
1216 case ACPI_VIDEO_NOTIFY_ZERO_BRIGHTNESS:
1217 case ACPI_VIDEO_NOTIFY_DISPLAY_OFF:
1218 return 0;
1219 default:
1220 return level_current;
1221 }
1da177e4
LT
1222}
1223
c8890f90 1224static int
4be44fcd 1225acpi_video_switch_brightness(struct acpi_video_device *device, int event)
1da177e4 1226{
27663c58 1227 unsigned long long level_current, level_next;
c8890f90
ZR
1228 int result = -EINVAL;
1229
28c32e99
ZR
1230 /* no warning message if acpi_backlight=vendor is used */
1231 if (!acpi_video_backlight_support())
1232 return 0;
1233
469778c1 1234 if (!device->brightness)
c8890f90
ZR
1235 goto out;
1236
1237 result = acpi_video_device_lcd_get_level_current(device,
70287db8 1238 &level_current, 0);
c8890f90
ZR
1239 if (result)
1240 goto out;
1241
1da177e4 1242 level_next = acpi_video_get_next_level(device, level_current, event);
c8890f90 1243
24450c7a 1244 result = acpi_video_device_lcd_set_level(device, level_next);
c8890f90 1245
36342742
MG
1246 if (!result)
1247 backlight_force_update(device->backlight,
1248 BACKLIGHT_UPDATE_HOTKEY);
1249
c8890f90
ZR
1250out:
1251 if (result)
1252 printk(KERN_ERR PREFIX "Failed to switch the brightness\n");
1253
1254 return result;
1da177e4
LT
1255}
1256
e92a7162
MG
1257int acpi_video_get_edid(struct acpi_device *device, int type, int device_id,
1258 void **edid)
1259{
1260 struct acpi_video_bus *video;
1261 struct acpi_video_device *video_device;
1262 union acpi_object *buffer = NULL;
1263 acpi_status status;
1264 int i, length;
1265
1266 if (!device || !acpi_driver_data(device))
1267 return -EINVAL;
1268
1269 video = acpi_driver_data(device);
1270
1271 for (i = 0; i < video->attached_count; i++) {
1272 video_device = video->attached_array[i].bind_info;
1273 length = 256;
1274
1275 if (!video_device)
1276 continue;
1277
1278 if (type) {
1279 switch (type) {
1280 case ACPI_VIDEO_DISPLAY_CRT:
1281 if (!video_device->flags.crt)
1282 continue;
1283 break;
1284 case ACPI_VIDEO_DISPLAY_TV:
1285 if (!video_device->flags.tvout)
1286 continue;
1287 break;
1288 case ACPI_VIDEO_DISPLAY_DVI:
1289 if (!video_device->flags.dvi)
1290 continue;
1291 break;
1292 case ACPI_VIDEO_DISPLAY_LCD:
1293 if (!video_device->flags.lcd)
1294 continue;
1295 break;
1296 }
1297 } else if (video_device->device_id != device_id) {
1298 continue;
1299 }
1300
1301 status = acpi_video_device_EDID(video_device, &buffer, length);
1302
1303 if (ACPI_FAILURE(status) || !buffer ||
1304 buffer->type != ACPI_TYPE_BUFFER) {
1305 length = 128;
1306 status = acpi_video_device_EDID(video_device, &buffer,
1307 length);
1308 if (ACPI_FAILURE(status) || !buffer ||
1309 buffer->type != ACPI_TYPE_BUFFER) {
1310 continue;
1311 }
1312 }
1313
1314 *edid = buffer->buffer.pointer;
1315 return length;
1316 }
1317
1318 return -ENODEV;
1319}
1320EXPORT_SYMBOL(acpi_video_get_edid);
1321
1da177e4 1322static int
4be44fcd
LB
1323acpi_video_bus_get_devices(struct acpi_video_bus *video,
1324 struct acpi_device *device)
1da177e4 1325{
4be44fcd 1326 int status = 0;
ff102ea9 1327 struct acpi_device *dev;
1da177e4
LT
1328
1329 acpi_video_device_enumerate(video);
1330
ff102ea9 1331 list_for_each_entry(dev, &device->children, node) {
1da177e4
LT
1332
1333 status = acpi_video_bus_get_one_device(dev, video);
1334 if (ACPI_FAILURE(status)) {
55ac9a01 1335 printk(KERN_WARNING PREFIX
cfa806f0 1336 "Cant attach device\n");
1da177e4
LT
1337 continue;
1338 }
1da177e4 1339 }
d550d98d 1340 return status;
1da177e4
LT
1341}
1342
4be44fcd 1343static int acpi_video_bus_put_one_device(struct acpi_video_device *device)
1da177e4 1344{
031ec77b 1345 acpi_status status;
1da177e4
LT
1346
1347 if (!device || !device->video)
d550d98d 1348 return -ENOENT;
1da177e4 1349
90130268 1350 status = acpi_remove_notify_handler(device->dev->handle,
4be44fcd
LB
1351 ACPI_DEVICE_NOTIFY,
1352 acpi_video_device_notify);
cfa806f0
AK
1353 if (ACPI_FAILURE(status)) {
1354 printk(KERN_WARNING PREFIX
1355 "Cant remove video notify handler\n");
1356 }
e29b3ee3
KP
1357 if (device->backlight) {
1358 sysfs_remove_link(&device->backlight->dev.kobj, "device");
1359 backlight_device_unregister(device->backlight);
1360 device->backlight = NULL;
1361 }
4a703a8f 1362 if (device->cooling_dev) {
702ed512
ZR
1363 sysfs_remove_link(&device->dev->dev.kobj,
1364 "thermal_cooling");
4a703a8f 1365 sysfs_remove_link(&device->cooling_dev->device.kobj,
702ed512 1366 "device");
4a703a8f
DT
1367 thermal_cooling_device_unregister(device->cooling_dev);
1368 device->cooling_dev = NULL;
702ed512 1369 }
ff102ea9 1370
d550d98d 1371 return 0;
1da177e4
LT
1372}
1373
4be44fcd 1374static int acpi_video_bus_put_devices(struct acpi_video_bus *video)
1da177e4 1375{
4be44fcd 1376 int status;
ff102ea9 1377 struct acpi_video_device *dev, *next;
1da177e4 1378
bbac81f5 1379 mutex_lock(&video->device_list_lock);
1da177e4 1380
ff102ea9 1381 list_for_each_entry_safe(dev, next, &video->video_device_list, entry) {
1da177e4 1382
ff102ea9 1383 status = acpi_video_bus_put_one_device(dev);
4be44fcd
LB
1384 if (ACPI_FAILURE(status))
1385 printk(KERN_WARNING PREFIX
1386 "hhuuhhuu bug in acpi video driver.\n");
1da177e4 1387
ff102ea9
DT
1388 if (dev->brightness) {
1389 kfree(dev->brightness->levels);
1390 kfree(dev->brightness);
1391 }
1392 list_del(&dev->entry);
1393 kfree(dev);
1da177e4
LT
1394 }
1395
bbac81f5 1396 mutex_unlock(&video->device_list_lock);
ff102ea9 1397
d550d98d 1398 return 0;
1da177e4
LT
1399}
1400
1401/* acpi_video interface */
1402
4be44fcd 1403static int acpi_video_bus_start_devices(struct acpi_video_bus *video)
1da177e4 1404{
a21101c4 1405 return acpi_video_bus_DOS(video, 0, 0);
1da177e4
LT
1406}
1407
4be44fcd 1408static int acpi_video_bus_stop_devices(struct acpi_video_bus *video)
1da177e4
LT
1409{
1410 return acpi_video_bus_DOS(video, 0, 1);
1411}
1412
7015558f 1413static void acpi_video_bus_notify(struct acpi_device *device, u32 event)
1da177e4 1414{
7015558f 1415 struct acpi_video_bus *video = acpi_driver_data(device);
e9dab196 1416 struct input_dev *input;
17c452f9 1417 int keycode = 0;
e9dab196 1418
1da177e4 1419 if (!video)
d550d98d 1420 return;
1da177e4 1421
e9dab196 1422 input = video->input;
1da177e4
LT
1423
1424 switch (event) {
98fb8fe1 1425 case ACPI_VIDEO_NOTIFY_SWITCH: /* User requested a switch,
1da177e4 1426 * most likely via hotkey. */
14e04fb3 1427 acpi_bus_generate_proc_event(device, event, 0);
e9dab196 1428 keycode = KEY_SWITCHVIDEOMODE;
1da177e4
LT
1429 break;
1430
98fb8fe1 1431 case ACPI_VIDEO_NOTIFY_PROBE: /* User plugged in or removed a video
1da177e4
LT
1432 * connector. */
1433 acpi_video_device_enumerate(video);
1434 acpi_video_device_rebind(video);
14e04fb3 1435 acpi_bus_generate_proc_event(device, event, 0);
e9dab196 1436 keycode = KEY_SWITCHVIDEOMODE;
1da177e4
LT
1437 break;
1438
4be44fcd 1439 case ACPI_VIDEO_NOTIFY_CYCLE: /* Cycle Display output hotkey pressed. */
25c87f7f 1440 acpi_bus_generate_proc_event(device, event, 0);
e9dab196
LY
1441 keycode = KEY_SWITCHVIDEOMODE;
1442 break;
4be44fcd 1443 case ACPI_VIDEO_NOTIFY_NEXT_OUTPUT: /* Next Display output hotkey pressed. */
25c87f7f 1444 acpi_bus_generate_proc_event(device, event, 0);
e9dab196
LY
1445 keycode = KEY_VIDEO_NEXT;
1446 break;
4be44fcd 1447 case ACPI_VIDEO_NOTIFY_PREV_OUTPUT: /* previous Display output hotkey pressed. */
14e04fb3 1448 acpi_bus_generate_proc_event(device, event, 0);
e9dab196 1449 keycode = KEY_VIDEO_PREV;
1da177e4
LT
1450 break;
1451
1452 default:
1453 ACPI_DEBUG_PRINT((ACPI_DB_INFO,
4be44fcd 1454 "Unsupported event [0x%x]\n", event));
1da177e4
LT
1455 break;
1456 }
1457
7761f638 1458 acpi_notifier_call_chain(device, event, 0);
17c452f9
MG
1459
1460 if (keycode) {
1461 input_report_key(input, keycode, 1);
1462 input_sync(input);
1463 input_report_key(input, keycode, 0);
1464 input_sync(input);
1465 }
e9dab196 1466
d550d98d 1467 return;
1da177e4
LT
1468}
1469
4be44fcd 1470static void acpi_video_device_notify(acpi_handle handle, u32 event, void *data)
1da177e4 1471{
50dd0969 1472 struct acpi_video_device *video_device = data;
4be44fcd 1473 struct acpi_device *device = NULL;
e9dab196
LY
1474 struct acpi_video_bus *bus;
1475 struct input_dev *input;
17c452f9 1476 int keycode = 0;
1da177e4 1477
1da177e4 1478 if (!video_device)
d550d98d 1479 return;
1da177e4 1480
e6afa0de 1481 device = video_device->dev;
e9dab196
LY
1482 bus = video_device->video;
1483 input = bus->input;
1da177e4
LT
1484
1485 switch (event) {
4be44fcd 1486 case ACPI_VIDEO_NOTIFY_CYCLE_BRIGHTNESS: /* Cycle brightness */
8a681a4d
ZR
1487 if (brightness_switch_enabled)
1488 acpi_video_switch_brightness(video_device, event);
14e04fb3 1489 acpi_bus_generate_proc_event(device, event, 0);
e9dab196
LY
1490 keycode = KEY_BRIGHTNESS_CYCLE;
1491 break;
4be44fcd 1492 case ACPI_VIDEO_NOTIFY_INC_BRIGHTNESS: /* Increase brightness */
8a681a4d
ZR
1493 if (brightness_switch_enabled)
1494 acpi_video_switch_brightness(video_device, event);
25c87f7f 1495 acpi_bus_generate_proc_event(device, event, 0);
e9dab196
LY
1496 keycode = KEY_BRIGHTNESSUP;
1497 break;
4be44fcd 1498 case ACPI_VIDEO_NOTIFY_DEC_BRIGHTNESS: /* Decrease brightness */
8a681a4d
ZR
1499 if (brightness_switch_enabled)
1500 acpi_video_switch_brightness(video_device, event);
25c87f7f 1501 acpi_bus_generate_proc_event(device, event, 0);
e9dab196
LY
1502 keycode = KEY_BRIGHTNESSDOWN;
1503 break;
4be44fcd 1504 case ACPI_VIDEO_NOTIFY_ZERO_BRIGHTNESS: /* zero brightnesss */
8a681a4d
ZR
1505 if (brightness_switch_enabled)
1506 acpi_video_switch_brightness(video_device, event);
25c87f7f 1507 acpi_bus_generate_proc_event(device, event, 0);
e9dab196
LY
1508 keycode = KEY_BRIGHTNESS_ZERO;
1509 break;
4be44fcd 1510 case ACPI_VIDEO_NOTIFY_DISPLAY_OFF: /* display device off */
8a681a4d
ZR
1511 if (brightness_switch_enabled)
1512 acpi_video_switch_brightness(video_device, event);
14e04fb3 1513 acpi_bus_generate_proc_event(device, event, 0);
e9dab196 1514 keycode = KEY_DISPLAY_OFF;
1da177e4
LT
1515 break;
1516 default:
1517 ACPI_DEBUG_PRINT((ACPI_DB_INFO,
4be44fcd 1518 "Unsupported event [0x%x]\n", event));
1da177e4
LT
1519 break;
1520 }
e9dab196 1521
7761f638 1522 acpi_notifier_call_chain(device, event, 0);
17c452f9
MG
1523
1524 if (keycode) {
1525 input_report_key(input, keycode, 1);
1526 input_sync(input);
1527 input_report_key(input, keycode, 0);
1528 input_sync(input);
1529 }
e9dab196 1530
d550d98d 1531 return;
1da177e4
LT
1532}
1533
ac7729da
RW
1534static int acpi_video_resume(struct notifier_block *nb,
1535 unsigned long val, void *ign)
863c1490
MG
1536{
1537 struct acpi_video_bus *video;
1538 struct acpi_video_device *video_device;
1539 int i;
1540
ac7729da
RW
1541 switch (val) {
1542 case PM_HIBERNATION_PREPARE:
1543 case PM_SUSPEND_PREPARE:
1544 case PM_RESTORE_PREPARE:
1545 return NOTIFY_DONE;
1546 }
863c1490 1547
ac7729da
RW
1548 video = container_of(nb, struct acpi_video_bus, pm_nb);
1549
1550 dev_info(&video->device->dev, "Restoring backlight state\n");
863c1490
MG
1551
1552 for (i = 0; i < video->attached_count; i++) {
1553 video_device = video->attached_array[i].bind_info;
1554 if (video_device && video_device->backlight)
1555 acpi_video_set_brightness(video_device->backlight);
1556 }
ac7729da
RW
1557
1558 return NOTIFY_OK;
863c1490
MG
1559}
1560
c504f8cb
ZR
1561static acpi_status
1562acpi_video_bus_match(acpi_handle handle, u32 level, void *context,
1563 void **return_value)
1564{
1565 struct acpi_device *device = context;
1566 struct acpi_device *sibling;
1567 int result;
1568
1569 if (handle == device->handle)
1570 return AE_CTRL_TERMINATE;
1571
1572 result = acpi_bus_get_device(handle, &sibling);
1573 if (result)
1574 return AE_OK;
1575
1576 if (!strcmp(acpi_device_name(sibling), ACPI_VIDEO_BUS_NAME))
1577 return AE_ALREADY_EXISTS;
1578
1579 return AE_OK;
1580}
1581
ac7729da
RW
1582static int instance;
1583
4be44fcd 1584static int acpi_video_bus_add(struct acpi_device *device)
1da177e4 1585{
f51e8391 1586 struct acpi_video_bus *video;
e9dab196 1587 struct input_dev *input;
f51e8391 1588 int error;
c504f8cb
ZR
1589 acpi_status status;
1590
1591 status = acpi_walk_namespace(ACPI_TYPE_DEVICE,
1592 device->parent->handle, 1,
1593 acpi_video_bus_match, NULL,
1594 device, NULL);
1595 if (status == AE_ALREADY_EXISTS) {
1596 printk(KERN_WARNING FW_BUG
1597 "Duplicate ACPI video bus devices for the"
1598 " same VGA controller, please try module "
1599 "parameter \"video.allow_duplicates=1\""
1600 "if the current driver doesn't work.\n");
1601 if (!allow_duplicates)
1602 return -ENODEV;
1603 }
1da177e4 1604
36bcbec7 1605 video = kzalloc(sizeof(struct acpi_video_bus), GFP_KERNEL);
1da177e4 1606 if (!video)
d550d98d 1607 return -ENOMEM;
1da177e4 1608
e6d9da1d
ZR
1609 /* a hack to fix the duplicate name "VID" problem on T61 */
1610 if (!strcmp(device->pnp.bus_id, "VID")) {
1611 if (instance)
1612 device->pnp.bus_id[3] = '0' + instance;
1613 instance ++;
1614 }
f3b39f13
ZY
1615 /* a hack to fix the duplicate name "VGA" problem on Pa 3553 */
1616 if (!strcmp(device->pnp.bus_id, "VGA")) {
1617 if (instance)
1618 device->pnp.bus_id[3] = '0' + instance;
1619 instance++;
1620 }
e6d9da1d 1621
e6afa0de 1622 video->device = device;
1da177e4
LT
1623 strcpy(acpi_device_name(device), ACPI_VIDEO_BUS_NAME);
1624 strcpy(acpi_device_class(device), ACPI_VIDEO_CLASS);
db89b4f0 1625 device->driver_data = video;
1da177e4
LT
1626
1627 acpi_video_bus_find_cap(video);
f51e8391
DT
1628 error = acpi_video_bus_check(video);
1629 if (error)
1630 goto err_free_video;
1da177e4 1631
bbac81f5 1632 mutex_init(&video->device_list_lock);
1da177e4
LT
1633 INIT_LIST_HEAD(&video->video_device_list);
1634
1635 acpi_video_bus_get_devices(video, device);
1636 acpi_video_bus_start_devices(video);
1637
e9dab196 1638 video->input = input = input_allocate_device();
f51e8391
DT
1639 if (!input) {
1640 error = -ENOMEM;
7015558f 1641 goto err_stop_video;
f51e8391 1642 }
e9dab196
LY
1643
1644 snprintf(video->phys, sizeof(video->phys),
1645 "%s/video/input0", acpi_device_hid(video->device));
1646
1647 input->name = acpi_device_name(video->device);
1648 input->phys = video->phys;
1649 input->id.bustype = BUS_HOST;
1650 input->id.product = 0x06;
91c05c66 1651 input->dev.parent = &device->dev;
e9dab196
LY
1652 input->evbit[0] = BIT(EV_KEY);
1653 set_bit(KEY_SWITCHVIDEOMODE, input->keybit);
1654 set_bit(KEY_VIDEO_NEXT, input->keybit);
1655 set_bit(KEY_VIDEO_PREV, input->keybit);
1656 set_bit(KEY_BRIGHTNESS_CYCLE, input->keybit);
1657 set_bit(KEY_BRIGHTNESSUP, input->keybit);
1658 set_bit(KEY_BRIGHTNESSDOWN, input->keybit);
1659 set_bit(KEY_BRIGHTNESS_ZERO, input->keybit);
1660 set_bit(KEY_DISPLAY_OFF, input->keybit);
e9dab196 1661
f51e8391
DT
1662 error = input_register_device(input);
1663 if (error)
1664 goto err_free_input_dev;
e9dab196 1665
1da177e4 1666 printk(KERN_INFO PREFIX "%s [%s] (multi-head: %s rom: %s post: %s)\n",
4be44fcd
LB
1667 ACPI_VIDEO_DEVICE_NAME, acpi_device_bid(device),
1668 video->flags.multihead ? "yes" : "no",
1669 video->flags.rom ? "yes" : "no",
1670 video->flags.post ? "yes" : "no");
1da177e4 1671
ac7729da
RW
1672 video->pm_nb.notifier_call = acpi_video_resume;
1673 video->pm_nb.priority = 0;
1674 register_pm_notifier(&video->pm_nb);
1675
f51e8391
DT
1676 return 0;
1677
1678 err_free_input_dev:
1679 input_free_device(input);
f51e8391
DT
1680 err_stop_video:
1681 acpi_video_bus_stop_devices(video);
1682 acpi_video_bus_put_devices(video);
1683 kfree(video->attached_array);
f51e8391
DT
1684 err_free_video:
1685 kfree(video);
db89b4f0 1686 device->driver_data = NULL;
1da177e4 1687
f51e8391 1688 return error;
1da177e4
LT
1689}
1690
4be44fcd 1691static int acpi_video_bus_remove(struct acpi_device *device, int type)
1da177e4 1692{
4be44fcd 1693 struct acpi_video_bus *video = NULL;
1da177e4 1694
1da177e4
LT
1695
1696 if (!device || !acpi_driver_data(device))
d550d98d 1697 return -EINVAL;
1da177e4 1698
50dd0969 1699 video = acpi_driver_data(device);
1da177e4 1700
ac7729da
RW
1701 unregister_pm_notifier(&video->pm_nb);
1702
1da177e4 1703 acpi_video_bus_stop_devices(video);
1da177e4 1704 acpi_video_bus_put_devices(video);
1da177e4 1705
e9dab196 1706 input_unregister_device(video->input);
6044ec88 1707 kfree(video->attached_array);
1da177e4
LT
1708 kfree(video);
1709
d550d98d 1710 return 0;
1da177e4
LT
1711}
1712
74a365b3
MG
1713static int __init intel_opregion_present(void)
1714{
1715#if defined(CONFIG_DRM_I915) || defined(CONFIG_DRM_I915_MODULE)
1716 struct pci_dev *dev = NULL;
1717 u32 address;
1718
1719 for_each_pci_dev(dev) {
1720 if ((dev->class >> 8) != PCI_CLASS_DISPLAY_VGA)
1721 continue;
1722 if (dev->vendor != PCI_VENDOR_ID_INTEL)
1723 continue;
1724 pci_read_config_dword(dev, 0xfc, &address);
1725 if (!address)
1726 continue;
1727 return 1;
1728 }
1729#endif
1730 return 0;
1731}
1732
1733int acpi_video_register(void)
1da177e4 1734{
4be44fcd 1735 int result = 0;
86e437f0
ZY
1736 if (register_count) {
1737 /*
1738 * if the function of acpi_video_register is already called,
1739 * don't register the acpi_vide_bus again and return no error.
1740 */
1741 return 0;
1742 }
1da177e4 1743
1da177e4 1744 result = acpi_bus_register_driver(&acpi_video_bus);
39fe394d 1745 if (result < 0)
d550d98d 1746 return -ENODEV;
1da177e4 1747
86e437f0
ZY
1748 /*
1749 * When the acpi_video_bus is loaded successfully, increase
1750 * the counter reference.
1751 */
1752 register_count = 1;
1753
d550d98d 1754 return 0;
1da177e4 1755}
74a365b3
MG
1756EXPORT_SYMBOL(acpi_video_register);
1757
86e437f0
ZY
1758void acpi_video_unregister(void)
1759{
1760 if (!register_count) {
1761 /*
1762 * If the acpi video bus is already unloaded, don't
1763 * unload it again and return directly.
1764 */
1765 return;
1766 }
1767 acpi_bus_unregister_driver(&acpi_video_bus);
1768
86e437f0
ZY
1769 register_count = 0;
1770
1771 return;
1772}
1773EXPORT_SYMBOL(acpi_video_unregister);
1774
74a365b3
MG
1775/*
1776 * This is kind of nasty. Hardware using Intel chipsets may require
1777 * the video opregion code to be run first in order to initialise
1778 * state before any ACPI video calls are made. To handle this we defer
1779 * registration of the video class until the opregion code has run.
1780 */
1781
1782static int __init acpi_video_init(void)
1783{
45cb50e6
ZR
1784 dmi_check_system(video_dmi_table);
1785
74a365b3
MG
1786 if (intel_opregion_present())
1787 return 0;
1788
1789 return acpi_video_register();
1790}
1da177e4 1791
86e437f0 1792static void __exit acpi_video_exit(void)
1da177e4 1793{
86e437f0 1794 acpi_video_unregister();
1da177e4 1795
d550d98d 1796 return;
1da177e4
LT
1797}
1798
1799module_init(acpi_video_init);
1800module_exit(acpi_video_exit);