blob: 990ff5b0aeb875d919efad799aa36fb6d5183f8e [file] [log] [blame]
Thomas Gleixnerc942fdd2019-05-27 08:55:06 +02001// SPDX-License-Identifier: GPL-2.0-or-later
Linus Torvalds1da177e2005-04-16 15:20:36 -07002/*
Felipe Contreras21fcb342013-08-01 18:43:59 -05003 * video.c - ACPI Video Driver
Linus Torvalds1da177e2005-04-16 15:20:36 -07004 *
5 * Copyright (C) 2004 Luming Yu <luming.yu@intel.com>
6 * Copyright (C) 2004 Bruno Ducrot <ducrot@poupinou.org>
Thomas Tuttlef4715182006-12-19 12:56:14 -08007 * Copyright (C) 2006 Thomas Tuttle <linux-kernel@ttuttle.net>
Linus Torvalds1da177e2005-04-16 15:20:36 -07008 */
9
Rafael J. Wysocki2924d2f2021-02-03 19:48:33 +010010#define pr_fmt(fmt) "ACPI: video: " fmt
11
Linus Torvalds1da177e2005-04-16 15:20:36 -070012#include <linux/kernel.h>
13#include <linux/module.h>
14#include <linux/init.h>
15#include <linux/types.h>
16#include <linux/list.h>
Dmitry Torokhovbbac81f2007-11-05 11:43:32 -050017#include <linux/mutex.h>
Luming Yue9dab192007-08-20 18:23:53 +080018#include <linux/input.h>
Yu Luming2f3d0002006-11-11 02:40:34 +080019#include <linux/backlight.h>
Zhang Rui702ed512008-01-17 15:51:22 +080020#include <linux/thermal.h>
Zhang Rui935e5f22008-12-11 16:24:52 -050021#include <linux/sort.h>
Matthew Garrett74a365b2009-03-19 21:35:39 +000022#include <linux/pci.h>
23#include <linux/pci_ids.h>
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090024#include <linux/slab.h>
Len Browneb27cae2009-07-06 23:40:19 -040025#include <linux/dmi.h>
Rafael J. Wysockiac7729d2010-04-05 01:43:51 +020026#include <linux/suspend.h>
Lv Zheng8b484632013-12-03 08:49:16 +080027#include <linux/acpi.h>
Matthew Garrette92a7162010-01-12 14:17:03 -050028#include <acpi/video.h>
Linus Torvalds7c0f6ba2016-12-24 11:46:01 -080029#include <linux/uaccess.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070030
Linus Torvalds1da177e2005-04-16 15:20:36 -070031#define ACPI_VIDEO_BUS_NAME "Video Bus"
32#define ACPI_VIDEO_DEVICE_NAME "Video Device"
Linus Torvalds1da177e2005-04-16 15:20:36 -070033
Yu Luming2f3d0002006-11-11 02:40:34 +080034#define MAX_NAME_LEN 20
Linus Torvalds1da177e2005-04-16 15:20:36 -070035
Len Brownf52fd662007-02-12 22:42:12 -050036MODULE_AUTHOR("Bruno Ducrot");
Len Brown7cda93e2007-02-12 23:50:02 -050037MODULE_DESCRIPTION("ACPI Video Driver");
Linus Torvalds1da177e2005-04-16 15:20:36 -070038MODULE_LICENSE("GPL");
39
Gustavo A. R. Silva97e45dd2018-01-23 09:59:20 -060040static bool brightness_switch_enabled = true;
Zhang Rui8a681a42008-01-25 14:47:49 +080041module_param(brightness_switch_enabled, bool, 0644);
42
Zhang Ruic504f8c2009-12-30 15:59:23 +080043/*
44 * By default, we don't allow duplicate ACPI video bus devices
45 * under the same VGA controller
46 */
Rusty Russell90ab5ee2012-01-13 09:32:20 +103047static bool allow_duplicates;
Zhang Ruic504f8c2009-12-30 15:59:23 +080048module_param(allow_duplicates, bool, 0644);
49
Hans de Goede654a1822015-06-09 10:32:25 +020050static int disable_backlight_sysfs_if = -1;
51module_param(disable_backlight_sysfs_if, int, 0444);
52
Hans de Goede05bc59a2015-12-22 19:09:51 +010053#define REPORT_OUTPUT_KEY_EVENTS 0x01
54#define REPORT_BRIGHTNESS_KEY_EVENTS 0x02
55static int report_key_events = -1;
56module_param(report_key_events, int, 0644);
57MODULE_PARM_DESC(report_key_events,
58 "0: none, 1: output changes, 2: brightness changes, 3: all");
59
Hans de Goede4f7f9642019-07-12 12:00:33 +020060static int hw_changes_brightness = -1;
61module_param(hw_changes_brightness, int, 0644);
62MODULE_PARM_DESC(hw_changes_brightness,
63 "Set this to 1 on buggy hw which changes the brightness itself when "
64 "a hotkey is pressed: -1: auto, 0: normal 1: hw-changes-brightness");
65
Dmitry Frank592c8092017-04-19 13:36:18 +030066/*
67 * Whether the struct acpi_video_device_attrib::device_id_scheme bit should be
68 * assumed even if not actually set.
69 */
Aaron Lue50b9be2015-10-28 15:09:23 +080070static bool device_id_scheme = false;
71module_param(device_id_scheme, bool, 0444);
72
Hans de Goede5928c282017-12-23 19:41:47 +010073static int only_lcd = -1;
74module_param(only_lcd, int, 0444);
Aaron Lue50b9be2015-10-28 15:09:23 +080075
Hans de Goede970530c2016-01-14 09:41:45 +010076static int register_count;
77static DEFINE_MUTEX(register_count_mutex);
Hans de Goede14e93552016-01-14 09:41:46 +010078static DEFINE_MUTEX(video_list_lock);
79static LIST_HEAD(video_bus_head);
Len Brown4be44fc2005-08-05 00:44:28 -040080static int acpi_video_bus_add(struct acpi_device *device);
Rafael J. Wysocki51fac832013-01-24 00:24:48 +010081static int acpi_video_bus_remove(struct acpi_device *device);
Bjorn Helgaas70155582009-04-07 15:37:11 +000082static void acpi_video_bus_notify(struct acpi_device *device, u32 event);
Hans de Goede93a291d2015-06-16 16:27:52 +020083void acpi_video_detect_exit(void);
Linus Torvalds1da177e2005-04-16 15:20:36 -070084
Dmitry Frankd485ef42017-04-19 12:48:07 +030085/*
86 * Indices in the _BCL method response: the first two items are special,
87 * the rest are all supported levels.
88 *
89 * See page 575 of the ACPI spec 3.0
90 */
91enum acpi_video_level_idx {
92 ACPI_VIDEO_AC_LEVEL, /* level when machine has full power */
93 ACPI_VIDEO_BATTERY_LEVEL, /* level when machine is on batteries */
94 ACPI_VIDEO_FIRST_LEVEL, /* actual supported levels begin here */
95};
96
Thomas Renninger1ba90e32007-07-23 14:44:41 +020097static const struct acpi_device_id video_device_ids[] = {
98 {ACPI_VIDEO_HID, 0},
99 {"", 0},
100};
101MODULE_DEVICE_TABLE(acpi, video_device_ids);
102
Linus Torvalds1da177e2005-04-16 15:20:36 -0700103static struct acpi_driver acpi_video_bus = {
Len Brownc2b67052007-02-12 23:33:40 -0500104 .name = "video",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700105 .class = ACPI_VIDEO_CLASS,
Thomas Renninger1ba90e32007-07-23 14:44:41 +0200106 .ids = video_device_ids,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700107 .ops = {
108 .add = acpi_video_bus_add,
109 .remove = acpi_video_bus_remove,
Bjorn Helgaas70155582009-04-07 15:37:11 +0000110 .notify = acpi_video_bus_notify,
Len Brown4be44fc2005-08-05 00:44:28 -0400111 },
Linus Torvalds1da177e2005-04-16 15:20:36 -0700112};
113
114struct acpi_video_bus_flags {
Len Brown4be44fc2005-08-05 00:44:28 -0400115 u8 multihead:1; /* can switch video heads */
116 u8 rom:1; /* can retrieve a video rom */
117 u8 post:1; /* can configure the head to */
118 u8 reserved:5;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700119};
120
121struct acpi_video_bus_cap {
Felipe Contreras21fcb342013-08-01 18:43:59 -0500122 u8 _DOS:1; /* Enable/Disable output switching */
123 u8 _DOD:1; /* Enumerate all devices attached to display adapter */
124 u8 _ROM:1; /* Get ROM Data */
125 u8 _GPD:1; /* Get POST Device */
126 u8 _SPD:1; /* Set POST Device */
127 u8 _VPO:1; /* Video POST Options */
Len Brown4be44fc2005-08-05 00:44:28 -0400128 u8 reserved:2;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700129};
130
Len Brown4be44fc2005-08-05 00:44:28 -0400131struct acpi_video_device_attrib {
132 u32 display_index:4; /* A zero-based instance of the Display */
Felipe Contreras21fcb342013-08-01 18:43:59 -0500133 u32 display_port_attachment:4; /* This field differentiates the display type */
134 u32 display_type:4; /* Describe the specific type in use */
135 u32 vendor_specific:4; /* Chipset Vendor Specific */
136 u32 bios_can_detect:1; /* BIOS can detect the device */
137 u32 depend_on_vga:1; /* Non-VGA output device whose power is related to
Len Brown4be44fc2005-08-05 00:44:28 -0400138 the VGA device. */
Felipe Contreras21fcb342013-08-01 18:43:59 -0500139 u32 pipe_id:3; /* For VGA multiple-head devices. */
140 u32 reserved:10; /* Must be 0 */
Dmitry Frank592c8092017-04-19 13:36:18 +0300141
142 /*
143 * The device ID might not actually follow the scheme described by this
144 * struct acpi_video_device_attrib. If it does, then this bit
145 * device_id_scheme is set; otherwise, other fields should be ignored.
146 *
147 * (but also see the global flag device_id_scheme)
148 */
149 u32 device_id_scheme:1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700150};
151
152struct acpi_video_enumerated_device {
153 union {
154 u32 int_val;
Len Brown4be44fc2005-08-05 00:44:28 -0400155 struct acpi_video_device_attrib attrib;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700156 } value;
157 struct acpi_video_device *bind_info;
158};
159
160struct acpi_video_bus {
Patrick Mochele6afa0d2006-05-19 16:54:40 -0400161 struct acpi_device *device;
Hans de Goede99678ed2014-05-15 13:22:33 +0200162 bool backlight_registered;
Len Brown4be44fc2005-08-05 00:44:28 -0400163 u8 dos_setting;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700164 struct acpi_video_enumerated_device *attached_array;
Len Brown4be44fc2005-08-05 00:44:28 -0400165 u8 attached_count;
Aaron Lub4df4632014-12-15 16:01:29 +0800166 u8 child_count;
Len Brown4be44fc2005-08-05 00:44:28 -0400167 struct acpi_video_bus_cap cap;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700168 struct acpi_video_bus_flags flags;
Len Brown4be44fc2005-08-05 00:44:28 -0400169 struct list_head video_device_list;
Dmitry Torokhovbbac81f2007-11-05 11:43:32 -0500170 struct mutex device_list_lock; /* protects video_device_list */
Aaron Lu67b662e2013-10-11 21:27:44 +0800171 struct list_head entry;
Luming Yue9dab192007-08-20 18:23:53 +0800172 struct input_dev *input;
173 char phys[32]; /* for input device */
Rafael J. Wysockiac7729d2010-04-05 01:43:51 +0200174 struct notifier_block pm_nb;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700175};
176
177struct acpi_video_device_flags {
Len Brown4be44fc2005-08-05 00:44:28 -0400178 u8 crt:1;
179 u8 lcd:1;
180 u8 tvout:1;
Rui Zhang82cae992007-01-03 23:40:53 -0500181 u8 dvi:1;
Len Brown4be44fc2005-08-05 00:44:28 -0400182 u8 bios:1;
183 u8 unknown:1;
Aaron Lu91e13aa2013-04-25 02:47:49 +0000184 u8 notify:1;
185 u8 reserved:1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700186};
187
188struct acpi_video_device_cap {
Felipe Contreras21fcb342013-08-01 18:43:59 -0500189 u8 _ADR:1; /* Return the unique ID */
190 u8 _BCL:1; /* Query list of brightness control levels supported */
191 u8 _BCM:1; /* Set the brightness level */
Yu Luming2f3d0002006-11-11 02:40:34 +0800192 u8 _BQC:1; /* Get current brightness level */
Zhang Ruic60d6382009-03-18 16:27:18 +0800193 u8 _BCQ:1; /* Some buggy BIOS uses _BCQ instead of _BQC */
Felipe Contreras21fcb342013-08-01 18:43:59 -0500194 u8 _DDC:1; /* Return the EDID for this device */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700195};
196
Linus Torvalds1da177e2005-04-16 15:20:36 -0700197struct acpi_video_device {
Len Brown4be44fc2005-08-05 00:44:28 -0400198 unsigned long device_id;
199 struct acpi_video_device_flags flags;
200 struct acpi_video_device_cap cap;
201 struct list_head entry;
Linus Torvalds8ab58e82014-07-18 14:32:51 +0200202 struct delayed_work switch_brightness_work;
203 int switch_brightness_event;
Len Brown4be44fc2005-08-05 00:44:28 -0400204 struct acpi_video_bus *video;
205 struct acpi_device *dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700206 struct acpi_video_device_brightness *brightness;
Yu Luming2f3d0002006-11-11 02:40:34 +0800207 struct backlight_device *backlight;
Dmitry Torokhov4a703a82009-08-29 23:03:16 -0400208 struct thermal_cooling_device *cooling_dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700209};
210
Len Brown4be44fc2005-08-05 00:44:28 -0400211static void acpi_video_device_notify(acpi_handle handle, u32 event, void *data);
212static void acpi_video_device_rebind(struct acpi_video_bus *video);
213static void acpi_video_device_bind(struct acpi_video_bus *video,
214 struct acpi_video_device *device);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700215static int acpi_video_device_enumerate(struct acpi_video_bus *video);
Yu Luming2f3d0002006-11-11 02:40:34 +0800216static int acpi_video_device_lcd_set_level(struct acpi_video_device *device,
217 int level);
218static int acpi_video_device_lcd_get_level_current(
219 struct acpi_video_device *device,
Danny Baumanna89803d2013-03-19 16:22:50 +0000220 unsigned long long *level, bool raw);
Len Brown4be44fc2005-08-05 00:44:28 -0400221static int acpi_video_get_next_level(struct acpi_video_device *device,
222 u32 level_current, u32 event);
Linus Torvalds8ab58e82014-07-18 14:32:51 +0200223static void acpi_video_switch_brightness(struct work_struct *work);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700224
Felipe Contreras21fcb342013-08-01 18:43:59 -0500225/* backlight device sysfs support */
Yu Luming2f3d0002006-11-11 02:40:34 +0800226static int acpi_video_get_brightness(struct backlight_device *bd)
227{
Matthew Wilcox27663c52008-10-10 02:22:59 -0400228 unsigned long long cur_level;
Matthew Garrett38531e62007-12-26 02:03:26 +0000229 int i;
Felipe Contreras7c364e72013-08-03 22:15:21 +0200230 struct acpi_video_device *vd = bl_get_data(bd);
Zhang Ruic8890f92009-03-18 16:27:08 +0800231
Danny Baumanna89803d2013-03-19 16:22:50 +0000232 if (acpi_video_device_lcd_get_level_current(vd, &cur_level, false))
Zhang Ruic8890f92009-03-18 16:27:08 +0800233 return -EINVAL;
Dmitry Frankd485ef42017-04-19 12:48:07 +0300234 for (i = ACPI_VIDEO_FIRST_LEVEL; i < vd->brightness->count; i++) {
Matthew Garrett38531e62007-12-26 02:03:26 +0000235 if (vd->brightness->levels[i] == cur_level)
Dmitry Frankd485ef42017-04-19 12:48:07 +0300236 return i - ACPI_VIDEO_FIRST_LEVEL;
Matthew Garrett38531e62007-12-26 02:03:26 +0000237 }
238 return 0;
Yu Luming2f3d0002006-11-11 02:40:34 +0800239}
240
241static int acpi_video_set_brightness(struct backlight_device *bd)
242{
Dmitry Frankd485ef42017-04-19 12:48:07 +0300243 int request_level = bd->props.brightness + ACPI_VIDEO_FIRST_LEVEL;
Felipe Contreras7c364e72013-08-03 22:15:21 +0200244 struct acpi_video_device *vd = bl_get_data(bd);
Zhang Rui24450c72009-03-18 16:27:10 +0800245
Linus Torvalds8ab58e82014-07-18 14:32:51 +0200246 cancel_delayed_work(&vd->switch_brightness_work);
Zhang Rui24450c72009-03-18 16:27:10 +0800247 return acpi_video_device_lcd_set_level(vd,
248 vd->brightness->levels[request_level]);
Yu Luming2f3d0002006-11-11 02:40:34 +0800249}
250
Lionel Debrouxacc24722010-11-16 14:14:02 +0100251static const struct backlight_ops acpi_backlight_ops = {
Richard Purdie599a52d2007-02-10 23:07:48 +0000252 .get_brightness = acpi_video_get_brightness,
253 .update_status = acpi_video_set_brightness,
254};
255
Zhang Rui702ed512008-01-17 15:51:22 +0800256/* thermal cooling device callbacks */
Dmitry Frankd485ef42017-04-19 12:48:07 +0300257static int video_get_max_state(struct thermal_cooling_device *cooling_dev,
258 unsigned long *state)
Zhang Rui702ed512008-01-17 15:51:22 +0800259{
Dmitry Torokhov4a703a82009-08-29 23:03:16 -0400260 struct acpi_device *device = cooling_dev->devdata;
Zhang Rui702ed512008-01-17 15:51:22 +0800261 struct acpi_video_device *video = acpi_driver_data(device);
262
Dmitry Frankd485ef42017-04-19 12:48:07 +0300263 *state = video->brightness->count - ACPI_VIDEO_FIRST_LEVEL - 1;
Matthew Garrett6503e5d2008-11-27 17:48:13 +0000264 return 0;
Zhang Rui702ed512008-01-17 15:51:22 +0800265}
266
Dmitry Frankd485ef42017-04-19 12:48:07 +0300267static int video_get_cur_state(struct thermal_cooling_device *cooling_dev,
268 unsigned long *state)
Zhang Rui702ed512008-01-17 15:51:22 +0800269{
Dmitry Torokhov4a703a82009-08-29 23:03:16 -0400270 struct acpi_device *device = cooling_dev->devdata;
Zhang Rui702ed512008-01-17 15:51:22 +0800271 struct acpi_video_device *video = acpi_driver_data(device);
Matthew Wilcox27663c52008-10-10 02:22:59 -0400272 unsigned long long level;
Matthew Garrett6503e5d2008-11-27 17:48:13 +0000273 int offset;
Zhang Rui702ed512008-01-17 15:51:22 +0800274
Danny Baumanna89803d2013-03-19 16:22:50 +0000275 if (acpi_video_device_lcd_get_level_current(video, &level, false))
Zhang Ruic8890f92009-03-18 16:27:08 +0800276 return -EINVAL;
Dmitry Frankd485ef42017-04-19 12:48:07 +0300277 for (offset = ACPI_VIDEO_FIRST_LEVEL; offset < video->brightness->count;
278 offset++)
Matthew Garrett6503e5d2008-11-27 17:48:13 +0000279 if (level == video->brightness->levels[offset]) {
280 *state = video->brightness->count - offset - 1;
281 return 0;
282 }
Zhang Rui702ed512008-01-17 15:51:22 +0800283
284 return -EINVAL;
285}
286
287static int
Dmitry Torokhov4a703a82009-08-29 23:03:16 -0400288video_set_cur_state(struct thermal_cooling_device *cooling_dev, unsigned long state)
Zhang Rui702ed512008-01-17 15:51:22 +0800289{
Dmitry Torokhov4a703a82009-08-29 23:03:16 -0400290 struct acpi_device *device = cooling_dev->devdata;
Zhang Rui702ed512008-01-17 15:51:22 +0800291 struct acpi_video_device *video = acpi_driver_data(device);
292 int level;
293
Dmitry Frankd485ef42017-04-19 12:48:07 +0300294 if (state >= video->brightness->count - ACPI_VIDEO_FIRST_LEVEL)
Zhang Rui702ed512008-01-17 15:51:22 +0800295 return -EINVAL;
296
297 state = video->brightness->count - state;
Felipe Contreras915ea7e2013-08-03 22:12:50 +0200298 level = video->brightness->levels[state - 1];
Zhang Rui702ed512008-01-17 15:51:22 +0800299 return acpi_video_device_lcd_set_level(video, level);
300}
301
Vasiliy Kulikov9c8b04b2011-06-25 21:07:52 +0400302static const struct thermal_cooling_device_ops video_cooling_ops = {
Zhang Rui702ed512008-01-17 15:51:22 +0800303 .get_max_state = video_get_max_state,
304 .get_cur_state = video_get_cur_state,
305 .set_cur_state = video_set_cur_state,
306};
307
Felipe Contreras21fcb342013-08-01 18:43:59 -0500308/*
309 * --------------------------------------------------------------------------
310 * Video Management
311 * --------------------------------------------------------------------------
312 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700313
Linus Torvalds1da177e2005-04-16 15:20:36 -0700314static int
Aaron Lu05950092016-04-27 20:45:04 +0800315acpi_video_device_lcd_query_levels(acpi_handle handle,
Len Brown4be44fc2005-08-05 00:44:28 -0400316 union acpi_object **levels)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700317{
Len Brown4be44fc2005-08-05 00:44:28 -0400318 int status;
319 struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
320 union acpi_object *obj;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700321
Linus Torvalds1da177e2005-04-16 15:20:36 -0700322
323 *levels = NULL;
324
Aaron Lu05950092016-04-27 20:45:04 +0800325 status = acpi_evaluate_object(handle, "_BCL", NULL, &buffer);
Rafael J. Wysocki2924d2f2021-02-03 19:48:33 +0100326 if (ACPI_FAILURE(status))
Patrick Mocheld550d982006-06-27 00:41:40 -0400327 return status;
Len Brown4be44fc2005-08-05 00:44:28 -0400328 obj = (union acpi_object *)buffer.pointer;
Adrian Bunk6665bda2006-03-11 10:12:00 -0500329 if (!obj || (obj->type != ACPI_TYPE_PACKAGE)) {
Rafael J. Wysocki2924d2f2021-02-03 19:48:33 +0100330 acpi_handle_info(handle, "Invalid _BCL data\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700331 status = -EFAULT;
332 goto err;
333 }
334
335 *levels = obj;
336
Patrick Mocheld550d982006-06-27 00:41:40 -0400337 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700338
Felipe Contreras915ea7e2013-08-03 22:12:50 +0200339err:
Jesper Juhl6044ec82005-11-07 01:01:32 -0800340 kfree(buffer.pointer);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700341
Patrick Mocheld550d982006-06-27 00:41:40 -0400342 return status;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700343}
344
345static int
Len Brown4be44fc2005-08-05 00:44:28 -0400346acpi_video_device_lcd_set_level(struct acpi_video_device *device, int level)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700347{
Zhang Rui24450c72009-03-18 16:27:10 +0800348 int status;
Zhang Rui9e6dada2008-12-31 10:58:48 +0800349 int state;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700350
Jiang Liu0db98202013-06-29 00:24:39 +0800351 status = acpi_execute_simple_method(device->dev->handle,
352 "_BCM", level);
Zhang Rui24450c72009-03-18 16:27:10 +0800353 if (ACPI_FAILURE(status)) {
Rafael J. Wysocki2924d2f2021-02-03 19:48:33 +0100354 acpi_handle_info(device->dev->handle, "_BCM evaluation failed\n");
Zhang Rui24450c72009-03-18 16:27:10 +0800355 return -EIO;
356 }
357
Alexey Starikovskiy4500ca82007-09-03 16:29:58 +0400358 device->brightness->curr = level;
Dmitry Frankd485ef42017-04-19 12:48:07 +0300359 for (state = ACPI_VIDEO_FIRST_LEVEL; state < device->brightness->count;
360 state++)
Zhang Rui24450c72009-03-18 16:27:10 +0800361 if (level == device->brightness->levels[state]) {
Zhang Rui1a7c6182009-03-18 16:27:16 +0800362 if (device->backlight)
Dmitry Frankd485ef42017-04-19 12:48:07 +0300363 device->backlight->props.brightness =
364 state - ACPI_VIDEO_FIRST_LEVEL;
Zhang Rui24450c72009-03-18 16:27:10 +0800365 return 0;
366 }
Zhang Rui9e6dada2008-12-31 10:58:48 +0800367
Rafael J. Wysocki2924d2f2021-02-03 19:48:33 +0100368 acpi_handle_info(device->dev->handle, "Current brightness invalid\n");
Zhang Rui24450c72009-03-18 16:27:10 +0800369 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700370}
371
Zhang Rui45cb50e2009-04-24 12:13:18 -0400372/*
373 * For some buggy _BQC methods, we need to add a constant value to
374 * the _BQC return value to get the actual current brightness level
375 */
376
377static int bqc_offset_aml_bug_workaround;
Hans de Goede7ee33ba2015-06-16 16:27:53 +0200378static int video_set_bqc_offset(const struct dmi_system_id *d)
Zhang Rui45cb50e2009-04-24 12:13:18 -0400379{
380 bqc_offset_aml_bug_workaround = 9;
381 return 0;
382}
383
Hans de Goede7ee33ba2015-06-16 16:27:53 +0200384static int video_disable_backlight_sysfs_if(
Hans de Goede654a1822015-06-09 10:32:25 +0200385 const struct dmi_system_id *d)
386{
387 if (disable_backlight_sysfs_if == -1)
388 disable_backlight_sysfs_if = 1;
389 return 0;
390}
391
Aaron Lue50b9be2015-10-28 15:09:23 +0800392static int video_set_device_id_scheme(const struct dmi_system_id *d)
393{
394 device_id_scheme = true;
395 return 0;
396}
397
398static int video_enable_only_lcd(const struct dmi_system_id *d)
399{
400 only_lcd = true;
401 return 0;
402}
403
Hans de Goede4b4b3b22015-12-22 19:09:52 +0100404static int video_set_report_key_events(const struct dmi_system_id *id)
405{
406 if (report_key_events == -1)
407 report_key_events = (uintptr_t)id->driver_data;
408 return 0;
409}
410
Hans de Goede4f7f9642019-07-12 12:00:33 +0200411static int video_hw_changes_brightness(
412 const struct dmi_system_id *d)
413{
414 if (hw_changes_brightness == -1)
415 hw_changes_brightness = 1;
416 return 0;
417}
418
Christoph Hellwig6faadbb2017-09-14 11:59:30 +0200419static const struct dmi_system_id video_dmi_table[] = {
Zhang Rui45cb50e2009-04-24 12:13:18 -0400420 /*
421 * Broken _BQC workaround http://bugzilla.kernel.org/show_bug.cgi?id=13121
422 */
423 {
424 .callback = video_set_bqc_offset,
425 .ident = "Acer Aspire 5720",
426 .matches = {
427 DMI_MATCH(DMI_BOARD_VENDOR, "Acer"),
428 DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5720"),
429 },
430 },
Len Brown5afc4ab2009-05-07 21:11:56 -0400431 {
432 .callback = video_set_bqc_offset,
433 .ident = "Acer Aspire 5710Z",
434 .matches = {
435 DMI_MATCH(DMI_BOARD_VENDOR, "Acer"),
436 DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5710Z"),
437 },
438 },
Zhang Rui34ac2722009-05-26 23:35:34 -0400439 {
440 .callback = video_set_bqc_offset,
441 .ident = "eMachines E510",
442 .matches = {
443 DMI_MATCH(DMI_BOARD_VENDOR, "EMACHINES"),
444 DMI_MATCH(DMI_PRODUCT_NAME, "eMachines E510"),
445 },
446 },
Zhang Rui93bcece2009-05-19 15:08:41 -0400447 {
448 .callback = video_set_bqc_offset,
449 .ident = "Acer Aspire 5315",
450 .matches = {
451 DMI_MATCH(DMI_BOARD_VENDOR, "Acer"),
452 DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5315"),
453 },
454 },
Zhang Rui152a4e62009-06-22 11:31:18 +0800455 {
456 .callback = video_set_bqc_offset,
457 .ident = "Acer Aspire 7720",
458 .matches = {
459 DMI_MATCH(DMI_BOARD_VENDOR, "Acer"),
460 DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 7720"),
461 },
462 },
Hans de Goede5f240792014-08-28 10:20:46 +0200463
464 /*
Hans de Goede654a1822015-06-09 10:32:25 +0200465 * Some machines have a broken acpi-video interface for brightness
466 * control, but still need an acpi_video_device_lcd_set_level() call
467 * on resume to turn the backlight power on. We Enable backlight
468 * control on these systems, but do not register a backlight sysfs
469 * as brightness control does not work.
470 */
471 {
Hans de Goedede588b82016-01-11 14:46:17 +0100472 /* https://bugzilla.kernel.org/show_bug.cgi?id=21012 */
473 .callback = video_disable_backlight_sysfs_if,
474 .ident = "Toshiba Portege R700",
475 .matches = {
476 DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"),
477 DMI_MATCH(DMI_PRODUCT_NAME, "PORTEGE R700"),
478 },
479 },
480 {
Hans de Goede654a1822015-06-09 10:32:25 +0200481 /* https://bugs.freedesktop.org/show_bug.cgi?id=82634 */
482 .callback = video_disable_backlight_sysfs_if,
483 .ident = "Toshiba Portege R830",
484 .matches = {
485 DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"),
486 DMI_MATCH(DMI_PRODUCT_NAME, "PORTEGE R830"),
487 },
488 },
Hans de Goedeb21f2e82016-01-14 14:24:39 +0100489 {
490 /* https://bugzilla.kernel.org/show_bug.cgi?id=21012 */
491 .callback = video_disable_backlight_sysfs_if,
492 .ident = "Toshiba Satellite R830",
493 .matches = {
494 DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"),
495 DMI_MATCH(DMI_PRODUCT_NAME, "SATELLITE R830"),
496 },
497 },
Aaron Lue50b9be2015-10-28 15:09:23 +0800498 /*
499 * Some machine's _DOD IDs don't have bit 31(Device ID Scheme) set
500 * but the IDs actually follow the Device ID Scheme.
501 */
502 {
503 /* https://bugzilla.kernel.org/show_bug.cgi?id=104121 */
504 .callback = video_set_device_id_scheme,
505 .ident = "ESPRIMO Mobile M9410",
506 .matches = {
507 DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"),
508 DMI_MATCH(DMI_PRODUCT_NAME, "ESPRIMO Mobile M9410"),
509 },
510 },
511 /*
512 * Some machines have multiple video output devices, but only the one
513 * that is the type of LCD can do the backlight control so we should not
514 * register backlight interface for other video output devices.
515 */
516 {
517 /* https://bugzilla.kernel.org/show_bug.cgi?id=104121 */
518 .callback = video_enable_only_lcd,
519 .ident = "ESPRIMO Mobile M9410",
520 .matches = {
521 DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"),
522 DMI_MATCH(DMI_PRODUCT_NAME, "ESPRIMO Mobile M9410"),
523 },
524 },
Hans de Goede4b4b3b22015-12-22 19:09:52 +0100525 /*
526 * Some machines report wrong key events on the acpi-bus, suppress
527 * key event reporting on these. Note this is only intended to work
528 * around events which are plain wrong. In some cases we get double
529 * events, in this case acpi-video is considered the canonical source
530 * and the events from the other source should be filtered. E.g.
531 * by calling acpi_video_handles_brightness_key_presses() from the
532 * vendor acpi/wmi driver or by using /lib/udev/hwdb.d/60-keyboard.hwdb
533 */
534 {
535 .callback = video_set_report_key_events,
536 .driver_data = (void *)((uintptr_t)REPORT_OUTPUT_KEY_EVENTS),
537 .ident = "Dell Vostro V131",
538 .matches = {
539 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
540 DMI_MATCH(DMI_PRODUCT_NAME, "Vostro V131"),
541 },
542 },
Hans de Goede9249c322021-06-30 17:23:16 +0200543 {
544 .callback = video_set_report_key_events,
545 .driver_data = (void *)((uintptr_t)REPORT_BRIGHTNESS_KEY_EVENTS),
546 .ident = "Dell Vostro 3350",
547 .matches = {
548 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
549 DMI_MATCH(DMI_PRODUCT_NAME, "Vostro 3350"),
550 },
551 },
Hans de Goede4f7f9642019-07-12 12:00:33 +0200552 /*
553 * Some machines change the brightness themselves when a brightness
554 * hotkey gets pressed, despite us telling them not to. In this case
555 * acpi_video_device_notify() should only call backlight_force_update(
556 * BACKLIGHT_UPDATE_HOTKEY) and not do anything else.
557 */
558 {
559 /* https://bugzilla.kernel.org/show_bug.cgi?id=204077 */
560 .callback = video_hw_changes_brightness,
561 .ident = "Packard Bell EasyNote MZ35",
562 .matches = {
563 DMI_MATCH(DMI_SYS_VENDOR, "Packard Bell"),
564 DMI_MATCH(DMI_PRODUCT_NAME, "EasyNote MZ35"),
565 },
566 },
Zhang Rui45cb50e2009-04-24 12:13:18 -0400567 {}
568};
569
Danny Baumann994fa632013-03-19 16:22:52 +0000570static unsigned long long
571acpi_video_bqc_value_to_level(struct acpi_video_device *device,
572 unsigned long long bqc_value)
573{
574 unsigned long long level;
575
576 if (device->brightness->flags._BQC_use_index) {
577 /*
Dmitry Frankd485ef42017-04-19 12:48:07 +0300578 * _BQC returns an index that doesn't account for the first 2
579 * items with special meaning (see enum acpi_video_level_idx),
580 * so we need to compensate for that by offsetting ourselves
Danny Baumann994fa632013-03-19 16:22:52 +0000581 */
582 if (device->brightness->flags._BCL_reversed)
Dmitry Frankd485ef42017-04-19 12:48:07 +0300583 bqc_value = device->brightness->count -
584 ACPI_VIDEO_FIRST_LEVEL - 1 - bqc_value;
Danny Baumann994fa632013-03-19 16:22:52 +0000585
Dmitry Frankd485ef42017-04-19 12:48:07 +0300586 level = device->brightness->levels[bqc_value +
Maximilian Luzc6237b22020-11-05 03:06:00 +0100587 ACPI_VIDEO_FIRST_LEVEL];
Danny Baumann994fa632013-03-19 16:22:52 +0000588 } else {
589 level = bqc_value;
590 }
591
592 level += bqc_offset_aml_bug_workaround;
593
594 return level;
595}
596
Linus Torvalds1da177e2005-04-16 15:20:36 -0700597static int
Len Brown4be44fc2005-08-05 00:44:28 -0400598acpi_video_device_lcd_get_level_current(struct acpi_video_device *device,
Danny Baumanna89803d2013-03-19 16:22:50 +0000599 unsigned long long *level, bool raw)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700600{
Zhang Ruic8890f92009-03-18 16:27:08 +0800601 acpi_status status = AE_OK;
Vladimir Serbinenko4e231fa2009-06-24 15:17:36 +0800602 int i;
Zhang Ruic8890f92009-03-18 16:27:08 +0800603
Zhang Ruic60d6382009-03-18 16:27:18 +0800604 if (device->cap._BQC || device->cap._BCQ) {
605 char *buf = device->cap._BQC ? "_BQC" : "_BCQ";
606
607 status = acpi_evaluate_integer(device->dev->handle, buf,
Zhang Ruic8890f92009-03-18 16:27:08 +0800608 NULL, level);
609 if (ACPI_SUCCESS(status)) {
Danny Baumanna89803d2013-03-19 16:22:50 +0000610 if (raw) {
611 /*
612 * Caller has indicated he wants the raw
613 * value returned by _BQC, so don't furtherly
614 * mess with the value.
615 */
616 return 0;
617 }
618
Danny Baumann994fa632013-03-19 16:22:52 +0000619 *level = acpi_video_bqc_value_to_level(device, *level);
Zhang Rui1a7c6182009-03-18 16:27:16 +0800620
Dmitry Frankd485ef42017-04-19 12:48:07 +0300621 for (i = ACPI_VIDEO_FIRST_LEVEL;
622 i < device->brightness->count; i++)
Vladimir Serbinenko4e231fa2009-06-24 15:17:36 +0800623 if (device->brightness->levels[i] == *level) {
624 device->brightness->curr = *level;
625 return 0;
Felipe Contreras915ea7e2013-08-03 22:12:50 +0200626 }
Danny Baumanna89803d2013-03-19 16:22:50 +0000627 /*
628 * BQC returned an invalid level.
629 * Stop using it.
630 */
Rafael J. Wysocki2924d2f2021-02-03 19:48:33 +0100631 acpi_handle_info(device->dev->handle,
632 "%s returned an invalid level", buf);
Danny Baumanna89803d2013-03-19 16:22:50 +0000633 device->cap._BQC = device->cap._BCQ = 0;
Zhang Ruic8890f92009-03-18 16:27:08 +0800634 } else {
Felipe Contreras21fcb342013-08-01 18:43:59 -0500635 /*
636 * Fixme:
Zhang Ruic8890f92009-03-18 16:27:08 +0800637 * should we return an error or ignore this failure?
638 * dev->brightness->curr is a cached value which stores
639 * the correct current backlight level in most cases.
640 * ACPI video backlight still works w/ buggy _BQC.
641 * http://bugzilla.kernel.org/show_bug.cgi?id=12233
642 */
Rafael J. Wysocki2924d2f2021-02-03 19:48:33 +0100643 acpi_handle_info(device->dev->handle,
644 "%s evaluation failed", buf);
Zhang Ruic60d6382009-03-18 16:27:18 +0800645 device->cap._BQC = device->cap._BCQ = 0;
Zhang Ruic8890f92009-03-18 16:27:08 +0800646 }
647 }
648
Alexey Starikovskiy4500ca82007-09-03 16:29:58 +0400649 *level = device->brightness->curr;
Zhang Ruic8890f92009-03-18 16:27:08 +0800650 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700651}
652
653static int
Len Brown4be44fc2005-08-05 00:44:28 -0400654acpi_video_device_EDID(struct acpi_video_device *device,
655 union acpi_object **edid, ssize_t length)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700656{
Len Brown4be44fc2005-08-05 00:44:28 -0400657 int status;
658 struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
659 union acpi_object *obj;
660 union acpi_object arg0 = { ACPI_TYPE_INTEGER };
661 struct acpi_object_list args = { 1, &arg0 };
Linus Torvalds1da177e2005-04-16 15:20:36 -0700662
Linus Torvalds1da177e2005-04-16 15:20:36 -0700663
664 *edid = NULL;
665
666 if (!device)
Patrick Mocheld550d982006-06-27 00:41:40 -0400667 return -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700668 if (length == 128)
669 arg0.integer.value = 1;
670 else if (length == 256)
671 arg0.integer.value = 2;
672 else
Patrick Mocheld550d982006-06-27 00:41:40 -0400673 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700674
Patrick Mochel90130262006-05-19 16:54:48 -0400675 status = acpi_evaluate_object(device->dev->handle, "_DDC", &args, &buffer);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700676 if (ACPI_FAILURE(status))
Patrick Mocheld550d982006-06-27 00:41:40 -0400677 return -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700678
Jan Engelhardt50dd0962006-10-01 00:28:50 +0200679 obj = buffer.pointer;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700680
681 if (obj && obj->type == ACPI_TYPE_BUFFER)
682 *edid = obj;
683 else {
Rafael J. Wysocki2924d2f2021-02-03 19:48:33 +0100684 acpi_handle_info(device->dev->handle, "Invalid _DDC data\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700685 status = -EFAULT;
686 kfree(obj);
687 }
688
Patrick Mocheld550d982006-06-27 00:41:40 -0400689 return status;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700690}
691
Linus Torvalds1da177e2005-04-16 15:20:36 -0700692/* bus */
693
Linus Torvalds1da177e2005-04-16 15:20:36 -0700694/*
695 * Arg:
Felipe Contreras21fcb342013-08-01 18:43:59 -0500696 * video : video bus device pointer
697 * bios_flag :
Linus Torvalds1da177e2005-04-16 15:20:36 -0700698 * 0. The system BIOS should NOT automatically switch(toggle)
699 * the active display output.
700 * 1. The system BIOS should automatically switch (toggle) the
Julius Volz98fb8fe2007-02-20 16:38:40 +0100701 * active display output. No switch event.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700702 * 2. The _DGS value should be locked.
703 * 3. The system BIOS should not automatically switch (toggle) the
704 * active display output, but instead generate the display switch
705 * event notify code.
706 * lcd_flag :
707 * 0. The system BIOS should automatically control the brightness level
Kacper PiwiƄskib5b42b22019-10-07 17:48:18 +0200708 * of the LCD when:
709 * - the power changes from AC to DC (ACPI appendix B)
710 * - a brightness hotkey gets pressed (implied by Win7/8 backlight docs)
Felipe Contreras21fcb342013-08-01 18:43:59 -0500711 * 1. The system BIOS should NOT automatically control the brightness
Kacper PiwiƄskib5b42b22019-10-07 17:48:18 +0200712 * level of the LCD when:
713 * - the power changes from AC to DC (ACPI appendix B)
714 * - a brightness hotkey gets pressed (implied by Win7/8 backlight docs)
Felipe Contreras21fcb342013-08-01 18:43:59 -0500715 * Return Value:
Igor Murzovea9f8852012-03-30 21:32:08 +0400716 * -EINVAL wrong arg.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700717 */
718
719static int
Len Brown4be44fc2005-08-05 00:44:28 -0400720acpi_video_bus_DOS(struct acpi_video_bus *video, int bios_flag, int lcd_flag)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700721{
Igor Murzovea9f8852012-03-30 21:32:08 +0400722 acpi_status status;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700723
Zhang Ruib0373842012-06-20 09:48:43 +0800724 if (!video->cap._DOS)
725 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700726
Igor Murzovea9f8852012-03-30 21:32:08 +0400727 if (bios_flag < 0 || bios_flag > 3 || lcd_flag < 0 || lcd_flag > 1)
728 return -EINVAL;
Jiang Liu0db98202013-06-29 00:24:39 +0800729 video->dos_setting = (lcd_flag << 2) | bios_flag;
730 status = acpi_execute_simple_method(video->device->handle, "_DOS",
731 (lcd_flag << 2) | bios_flag);
Igor Murzovea9f8852012-03-30 21:32:08 +0400732 if (ACPI_FAILURE(status))
733 return -EIO;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700734
Igor Murzovea9f8852012-03-30 21:32:08 +0400735 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700736}
737
738/*
Zhang Rui935e5f22008-12-11 16:24:52 -0500739 * Simple comparison function used to sort backlight levels.
740 */
741
742static int
743acpi_video_cmp_level(const void *a, const void *b)
744{
745 return *(int *)a - *(int *)b;
746}
747
748/*
Aaron Lua50188d2013-04-22 14:08:32 +0200749 * Decides if _BQC/_BCQ for this system is usable
750 *
751 * We do this by changing the level first and then read out the current
752 * brightness level, if the value does not match, find out if it is using
753 * index. If not, clear the _BQC/_BCQ capability.
754 */
755static int acpi_video_bqc_quirk(struct acpi_video_device *device,
756 int max_level, int current_level)
757{
758 struct acpi_video_device_brightness *br = device->brightness;
759 int result;
760 unsigned long long level;
761 int test_level;
762
763 /* don't mess with existing known broken systems */
764 if (bqc_offset_aml_bug_workaround)
765 return 0;
766
767 /*
768 * Some systems always report current brightness level as maximum
Dmitry Frank592c8092017-04-19 13:36:18 +0300769 * through _BQC, we need to test another value for them. However,
770 * there is a subtlety:
771 *
772 * If the _BCL package ordering is descending, the first level
773 * (br->levels[2]) is likely to be 0, and if the number of levels
774 * matches the number of steps, we might confuse a returned level to
775 * mean the index.
776 *
777 * For example:
778 *
779 * current_level = max_level = 100
780 * test_level = 0
781 * returned level = 100
782 *
783 * In this case 100 means the level, not the index, and _BCM failed.
784 * Still, if the _BCL package ordering is descending, the index of
785 * level 0 is also 100, so we assume _BQC is indexed, when it's not.
786 *
787 * This causes all _BQC calls to return bogus values causing weird
788 * behavior from the user's perspective. For example:
789 *
790 * xbacklight -set 10; xbacklight -set 20;
791 *
792 * would flash to 90% and then slowly down to the desired level (20).
793 *
794 * The solution is simple; test anything other than the first level
795 * (e.g. 1).
Aaron Lua50188d2013-04-22 14:08:32 +0200796 */
Dmitry Frankd485ef42017-04-19 12:48:07 +0300797 test_level = current_level == max_level
798 ? br->levels[ACPI_VIDEO_FIRST_LEVEL + 1]
799 : max_level;
Aaron Lua50188d2013-04-22 14:08:32 +0200800
801 result = acpi_video_device_lcd_set_level(device, test_level);
802 if (result)
803 return result;
804
805 result = acpi_video_device_lcd_get_level_current(device, &level, true);
806 if (result)
807 return result;
808
809 if (level != test_level) {
810 /* buggy _BQC found, need to find out if it uses index */
811 if (level < br->count) {
812 if (br->flags._BCL_reversed)
Dmitry Frankd485ef42017-04-19 12:48:07 +0300813 level = br->count - ACPI_VIDEO_FIRST_LEVEL - 1 - level;
814 if (br->levels[level + ACPI_VIDEO_FIRST_LEVEL] == test_level)
Aaron Lua50188d2013-04-22 14:08:32 +0200815 br->flags._BQC_use_index = 1;
816 }
817
818 if (!br->flags._BQC_use_index)
819 device->cap._BQC = device->cap._BCQ = 0;
820 }
821
822 return 0;
823}
824
Aaron Lu05950092016-04-27 20:45:04 +0800825int acpi_video_get_levels(struct acpi_device *device,
Aaron Lu9f9cd7e2016-05-21 15:30:46 +0800826 struct acpi_video_device_brightness **dev_br,
827 int *pmax_level)
Julia Jomantaite469778c2008-06-23 22:50:42 +0100828{
829 union acpi_object *obj = NULL;
Zhang Ruid32f6942009-03-18 16:27:12 +0800830 int i, max_level = 0, count = 0, level_ac_battery = 0;
Julia Jomantaite469778c2008-06-23 22:50:42 +0100831 union acpi_object *o;
832 struct acpi_video_device_brightness *br = NULL;
Aaron Lu05950092016-04-27 20:45:04 +0800833 int result = 0;
Hans de Goedebd8ba202014-02-13 16:32:51 +0100834 u32 value;
Julia Jomantaite469778c2008-06-23 22:50:42 +0100835
Rafael J. Wysocki2924d2f2021-02-03 19:48:33 +0100836 if (ACPI_FAILURE(acpi_video_device_lcd_query_levels(device->handle, &obj))) {
837 acpi_handle_debug(device->handle,
838 "Could not query available LCD brightness level\n");
Aaron Lu05950092016-04-27 20:45:04 +0800839 result = -ENODEV;
Julia Jomantaite469778c2008-06-23 22:50:42 +0100840 goto out;
841 }
842
Dmitry Frankd485ef42017-04-19 12:48:07 +0300843 if (obj->package.count < ACPI_VIDEO_FIRST_LEVEL) {
Aaron Lu05950092016-04-27 20:45:04 +0800844 result = -EINVAL;
Julia Jomantaite469778c2008-06-23 22:50:42 +0100845 goto out;
Aaron Lu05950092016-04-27 20:45:04 +0800846 }
Julia Jomantaite469778c2008-06-23 22:50:42 +0100847
848 br = kzalloc(sizeof(*br), GFP_KERNEL);
849 if (!br) {
Zhang Rui1a7c6182009-03-18 16:27:16 +0800850 result = -ENOMEM;
Julia Jomantaite469778c2008-06-23 22:50:42 +0100851 goto out;
852 }
853
Dmitry Frank592c8092017-04-19 13:36:18 +0300854 /*
855 * Note that we have to reserve 2 extra items (ACPI_VIDEO_FIRST_LEVEL),
856 * in order to account for buggy BIOS which don't export the first two
857 * special levels (see below)
858 */
Kees Cook6da2ec52018-06-12 13:55:00 -0700859 br->levels = kmalloc_array(obj->package.count + ACPI_VIDEO_FIRST_LEVEL,
860 sizeof(*br->levels),
861 GFP_KERNEL);
Zhang Rui1a7c6182009-03-18 16:27:16 +0800862 if (!br->levels) {
863 result = -ENOMEM;
Julia Jomantaite469778c2008-06-23 22:50:42 +0100864 goto out_free;
Zhang Rui1a7c6182009-03-18 16:27:16 +0800865 }
Julia Jomantaite469778c2008-06-23 22:50:42 +0100866
867 for (i = 0; i < obj->package.count; i++) {
868 o = (union acpi_object *)&obj->package.elements[i];
869 if (o->type != ACPI_TYPE_INTEGER) {
Rafael J. Wysocki2924d2f2021-02-03 19:48:33 +0100870 acpi_handle_info(device->handle, "Invalid data\n");
Julia Jomantaite469778c2008-06-23 22:50:42 +0100871 continue;
872 }
Hans de Goedebd8ba202014-02-13 16:32:51 +0100873 value = (u32) o->integer.value;
874 /* Skip duplicate entries */
Dmitry Frankd485ef42017-04-19 12:48:07 +0300875 if (count > ACPI_VIDEO_FIRST_LEVEL
876 && br->levels[count - 1] == value)
Hans de Goedebd8ba202014-02-13 16:32:51 +0100877 continue;
878
879 br->levels[count] = value;
Julia Jomantaite469778c2008-06-23 22:50:42 +0100880
881 if (br->levels[count] > max_level)
882 max_level = br->levels[count];
883 count++;
884 }
885
Zhang Ruid32f6942009-03-18 16:27:12 +0800886 /*
887 * some buggy BIOS don't export the levels
888 * when machine is on AC/Battery in _BCL package.
889 * In this case, the first two elements in _BCL packages
890 * are also supported brightness levels that OS should take care of.
891 */
Dmitry Frankd485ef42017-04-19 12:48:07 +0300892 for (i = ACPI_VIDEO_FIRST_LEVEL; i < count; i++) {
893 if (br->levels[i] == br->levels[ACPI_VIDEO_AC_LEVEL])
Zhang Ruid32f6942009-03-18 16:27:12 +0800894 level_ac_battery++;
Dmitry Frankd485ef42017-04-19 12:48:07 +0300895 if (br->levels[i] == br->levels[ACPI_VIDEO_BATTERY_LEVEL])
Zhang Rui90af2cf2009-04-14 11:02:18 +0800896 level_ac_battery++;
897 }
Zhang Rui935e5f22008-12-11 16:24:52 -0500898
Dmitry Frankd485ef42017-04-19 12:48:07 +0300899 if (level_ac_battery < ACPI_VIDEO_FIRST_LEVEL) {
900 level_ac_battery = ACPI_VIDEO_FIRST_LEVEL - level_ac_battery;
Zhang Ruid32f6942009-03-18 16:27:12 +0800901 br->flags._BCL_no_ac_battery_levels = 1;
Dmitry Frankd485ef42017-04-19 12:48:07 +0300902 for (i = (count - 1 + level_ac_battery);
903 i >= ACPI_VIDEO_FIRST_LEVEL; i--)
Zhang Ruid32f6942009-03-18 16:27:12 +0800904 br->levels[i] = br->levels[i - level_ac_battery];
905 count += level_ac_battery;
Dmitry Frankd485ef42017-04-19 12:48:07 +0300906 } else if (level_ac_battery > ACPI_VIDEO_FIRST_LEVEL)
Rafael J. Wysocki2924d2f2021-02-03 19:48:33 +0100907 acpi_handle_info(device->handle,
908 "Too many duplicates in _BCL package");
Zhang Ruid32f6942009-03-18 16:27:12 +0800909
Zhang Ruid80fb992009-03-18 16:27:14 +0800910 /* Check if the _BCL package is in a reversed order */
Dmitry Frankd485ef42017-04-19 12:48:07 +0300911 if (max_level == br->levels[ACPI_VIDEO_FIRST_LEVEL]) {
Zhang Ruid80fb992009-03-18 16:27:14 +0800912 br->flags._BCL_reversed = 1;
Dmitry Frankd485ef42017-04-19 12:48:07 +0300913 sort(&br->levels[ACPI_VIDEO_FIRST_LEVEL],
914 count - ACPI_VIDEO_FIRST_LEVEL,
915 sizeof(br->levels[ACPI_VIDEO_FIRST_LEVEL]),
916 acpi_video_cmp_level, NULL);
Zhang Ruid80fb992009-03-18 16:27:14 +0800917 } else if (max_level != br->levels[count - 1])
Rafael J. Wysocki2924d2f2021-02-03 19:48:33 +0100918 acpi_handle_info(device->handle,
919 "Found unordered _BCL package");
Julia Jomantaite469778c2008-06-23 22:50:42 +0100920
921 br->count = count;
Aaron Lu05950092016-04-27 20:45:04 +0800922 *dev_br = br;
Aaron Lu9f9cd7e2016-05-21 15:30:46 +0800923 if (pmax_level)
924 *pmax_level = max_level;
Aaron Lu05950092016-04-27 20:45:04 +0800925
926out:
927 kfree(obj);
928 return result;
929out_free:
930 kfree(br);
931 goto out;
932}
933EXPORT_SYMBOL(acpi_video_get_levels);
934
935/*
936 * Arg:
937 * device : video output device (LCD, CRT, ..)
938 *
939 * Return Value:
940 * Maximum brightness level
941 *
942 * Allocate and initialize device->brightness.
943 */
944
945static int
946acpi_video_init_brightness(struct acpi_video_device *device)
947{
948 int i, max_level = 0;
949 unsigned long long level, level_old;
950 struct acpi_video_device_brightness *br = NULL;
Colin Ian King966f58d2020-02-29 00:12:43 +0000951 int result;
Aaron Lu05950092016-04-27 20:45:04 +0800952
Aaron Lu9f9cd7e2016-05-21 15:30:46 +0800953 result = acpi_video_get_levels(device->dev, &br, &max_level);
Aaron Lu05950092016-04-27 20:45:04 +0800954 if (result)
955 return result;
Julia Jomantaite469778c2008-06-23 22:50:42 +0100956 device->brightness = br;
Zhang Rui1a7c6182009-03-18 16:27:16 +0800957
Zhang Rui1a7c6182009-03-18 16:27:16 +0800958 /* _BQC uses INDEX while _BCL uses VALUE in some laptops */
Zhang Rui90c53ca2009-08-31 12:39:54 -0400959 br->curr = level = max_level;
Zhang Ruie047cca2009-04-09 14:24:35 +0800960
961 if (!device->cap._BQC)
962 goto set_level;
963
Danny Baumanna89803d2013-03-19 16:22:50 +0000964 result = acpi_video_device_lcd_get_level_current(device,
965 &level_old, true);
Zhang Rui1a7c6182009-03-18 16:27:16 +0800966 if (result)
967 goto out_free_levels;
968
Aaron Lua50188d2013-04-22 14:08:32 +0200969 result = acpi_video_bqc_quirk(device, max_level, level_old);
970 if (result)
971 goto out_free_levels;
Zhang Ruie047cca2009-04-09 14:24:35 +0800972 /*
Aaron Lua50188d2013-04-22 14:08:32 +0200973 * cap._BQC may get cleared due to _BQC is found to be broken
974 * in acpi_video_bqc_quirk, so check again here.
Zhang Ruie047cca2009-04-09 14:24:35 +0800975 */
Aaron Lua50188d2013-04-22 14:08:32 +0200976 if (!device->cap._BQC)
977 goto set_level;
Zhang Rui1a7c6182009-03-18 16:27:16 +0800978
Aaron Lu545ef362013-11-15 14:39:12 +0800979 level = acpi_video_bqc_value_to_level(device, level_old);
980 /*
981 * On some buggy laptops, _BQC returns an uninitialized
982 * value when invoked for the first time, i.e.
983 * level_old is invalid (no matter whether it's a level
984 * or an index). Set the backlight to max_level in this case.
985 */
Dmitry Frankd485ef42017-04-19 12:48:07 +0300986 for (i = ACPI_VIDEO_FIRST_LEVEL; i < br->count; i++)
Aaron Lu545ef362013-11-15 14:39:12 +0800987 if (level == br->levels[i])
988 break;
989 if (i == br->count || !level)
990 level = max_level;
Zhang Ruie047cca2009-04-09 14:24:35 +0800991
Zhang Ruie047cca2009-04-09 14:24:35 +0800992set_level:
Zhang Rui90c53ca2009-08-31 12:39:54 -0400993 result = acpi_video_device_lcd_set_level(device, level);
Zhang Ruie047cca2009-04-09 14:24:35 +0800994 if (result)
995 goto out_free_levels;
Zhang Rui1a7c6182009-03-18 16:27:16 +0800996
Rafael J. Wysocki2924d2f2021-02-03 19:48:33 +0100997 acpi_handle_debug(device->dev->handle, "found %d brightness levels\n",
998 br->count - ACPI_VIDEO_FIRST_LEVEL);
999
Aaron Lu05950092016-04-27 20:45:04 +08001000 return 0;
Julia Jomantaite469778c2008-06-23 22:50:42 +01001001
1002out_free_levels:
1003 kfree(br->levels);
Julia Jomantaite469778c2008-06-23 22:50:42 +01001004 kfree(br);
Julia Jomantaite469778c2008-06-23 22:50:42 +01001005 device->brightness = NULL;
Zhang Rui1a7c6182009-03-18 16:27:16 +08001006 return result;
Julia Jomantaite469778c2008-06-23 22:50:42 +01001007}
1008
1009/*
1010 * Arg:
1011 * device : video output device (LCD, CRT, ..)
1012 *
1013 * Return Value:
Felipe Contreras21fcb342013-08-01 18:43:59 -05001014 * None
Linus Torvalds1da177e2005-04-16 15:20:36 -07001015 *
Julius Volz98fb8fe2007-02-20 16:38:40 +01001016 * Find out all required AML methods defined under the output
Linus Torvalds1da177e2005-04-16 15:20:36 -07001017 * device.
1018 */
1019
Len Brown4be44fc2005-08-05 00:44:28 -04001020static void acpi_video_device_find_cap(struct acpi_video_device *device)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001021{
Jiang Liu952c63e2013-06-29 00:24:38 +08001022 if (acpi_has_method(device->dev->handle, "_ADR"))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001023 device->cap._ADR = 1;
Jiang Liu952c63e2013-06-29 00:24:38 +08001024 if (acpi_has_method(device->dev->handle, "_BCL"))
Len Brown4be44fc2005-08-05 00:44:28 -04001025 device->cap._BCL = 1;
Jiang Liu952c63e2013-06-29 00:24:38 +08001026 if (acpi_has_method(device->dev->handle, "_BCM"))
Len Brown4be44fc2005-08-05 00:44:28 -04001027 device->cap._BCM = 1;
Jiang Liu952c63e2013-06-29 00:24:38 +08001028 if (acpi_has_method(device->dev->handle, "_BQC")) {
Yu Luming2f3d0002006-11-11 02:40:34 +08001029 device->cap._BQC = 1;
Jiang Liu952c63e2013-06-29 00:24:38 +08001030 } else if (acpi_has_method(device->dev->handle, "_BCQ")) {
Rafael J. Wysocki2924d2f2021-02-03 19:48:33 +01001031 acpi_handle_info(device->dev->handle,
1032 "_BCQ is used instead of _BQC\n");
Zhang Ruic60d6382009-03-18 16:27:18 +08001033 device->cap._BCQ = 1;
1034 }
1035
Jiang Liu952c63e2013-06-29 00:24:38 +08001036 if (acpi_has_method(device->dev->handle, "_DDC"))
Len Brown4be44fc2005-08-05 00:44:28 -04001037 device->cap._DDC = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001038}
1039
1040/*
Felipe Contreras21fcb342013-08-01 18:43:59 -05001041 * Arg:
1042 * device : video output device (VGA)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001043 *
1044 * Return Value:
Felipe Contreras21fcb342013-08-01 18:43:59 -05001045 * None
Linus Torvalds1da177e2005-04-16 15:20:36 -07001046 *
Julius Volz98fb8fe2007-02-20 16:38:40 +01001047 * Find out all required AML methods defined under the video bus device.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001048 */
1049
Len Brown4be44fc2005-08-05 00:44:28 -04001050static void acpi_video_bus_find_cap(struct acpi_video_bus *video)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001051{
Jiang Liu952c63e2013-06-29 00:24:38 +08001052 if (acpi_has_method(video->device->handle, "_DOS"))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001053 video->cap._DOS = 1;
Jiang Liu952c63e2013-06-29 00:24:38 +08001054 if (acpi_has_method(video->device->handle, "_DOD"))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001055 video->cap._DOD = 1;
Jiang Liu952c63e2013-06-29 00:24:38 +08001056 if (acpi_has_method(video->device->handle, "_ROM"))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001057 video->cap._ROM = 1;
Jiang Liu952c63e2013-06-29 00:24:38 +08001058 if (acpi_has_method(video->device->handle, "_GPD"))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001059 video->cap._GPD = 1;
Jiang Liu952c63e2013-06-29 00:24:38 +08001060 if (acpi_has_method(video->device->handle, "_SPD"))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001061 video->cap._SPD = 1;
Jiang Liu952c63e2013-06-29 00:24:38 +08001062 if (acpi_has_method(video->device->handle, "_VPO"))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001063 video->cap._VPO = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001064}
1065
1066/*
1067 * Check whether the video bus device has required AML method to
1068 * support the desired features
1069 */
1070
Len Brown4be44fc2005-08-05 00:44:28 -04001071static int acpi_video_bus_check(struct acpi_video_bus *video)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001072{
Len Brown4be44fc2005-08-05 00:44:28 -04001073 acpi_status status = -ENOENT;
Alexander Chiang1e4cffe2009-06-10 19:56:00 +00001074 struct pci_dev *dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001075
1076 if (!video)
Patrick Mocheld550d982006-06-27 00:41:40 -04001077 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001078
Alexander Chiang1e4cffe2009-06-10 19:56:00 +00001079 dev = acpi_get_pci_dev(video->device->handle);
Thomas Renninger22c13f92008-08-01 17:37:54 +02001080 if (!dev)
1081 return -ENODEV;
Alexander Chiang1e4cffe2009-06-10 19:56:00 +00001082 pci_dev_put(dev);
Thomas Renninger22c13f92008-08-01 17:37:54 +02001083
Felipe Contreras21fcb342013-08-01 18:43:59 -05001084 /*
1085 * Since there is no HID, CID and so on for VGA driver, we have
Linus Torvalds1da177e2005-04-16 15:20:36 -07001086 * to check well known required nodes.
1087 */
1088
Julius Volz98fb8fe2007-02-20 16:38:40 +01001089 /* Does this device support video switching? */
Stefan Bader3a1151e2009-08-21 11:03:05 +02001090 if (video->cap._DOS || video->cap._DOD) {
1091 if (!video->cap._DOS) {
Rafael J. Wysocki2924d2f2021-02-03 19:48:33 +01001092 pr_info(FW_BUG "ACPI(%s) defines _DOD but not _DOS\n",
Stefan Bader3a1151e2009-08-21 11:03:05 +02001093 acpi_device_bid(video->device));
1094 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001095 video->flags.multihead = 1;
1096 status = 0;
1097 }
1098
Julius Volz98fb8fe2007-02-20 16:38:40 +01001099 /* Does this device support retrieving a video ROM? */
Len Brown4be44fc2005-08-05 00:44:28 -04001100 if (video->cap._ROM) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001101 video->flags.rom = 1;
1102 status = 0;
1103 }
1104
Julius Volz98fb8fe2007-02-20 16:38:40 +01001105 /* Does this device support configuring which video device to POST? */
Len Brown4be44fc2005-08-05 00:44:28 -04001106 if (video->cap._GPD && video->cap._SPD && video->cap._VPO) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001107 video->flags.post = 1;
1108 status = 0;
1109 }
1110
Patrick Mocheld550d982006-06-27 00:41:40 -04001111 return status;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001112}
1113
Felipe Contreras21fcb342013-08-01 18:43:59 -05001114/*
1115 * --------------------------------------------------------------------------
1116 * Driver Interface
1117 * --------------------------------------------------------------------------
1118 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001119
1120/* device interface */
Felipe Contreras915ea7e2013-08-03 22:12:50 +02001121static struct acpi_video_device_attrib *
Rui Zhang82cae992007-01-03 23:40:53 -05001122acpi_video_get_device_attr(struct acpi_video_bus *video, unsigned long device_id)
1123{
Dmitry Torokhov78eed022007-11-05 11:43:33 -05001124 struct acpi_video_enumerated_device *ids;
1125 int i;
Rui Zhang82cae992007-01-03 23:40:53 -05001126
Dmitry Torokhov78eed022007-11-05 11:43:33 -05001127 for (i = 0; i < video->attached_count; i++) {
1128 ids = &video->attached_array[i];
1129 if ((ids->value.int_val & 0xffff) == device_id)
1130 return &ids->value.attrib;
1131 }
1132
Rui Zhang82cae992007-01-03 23:40:53 -05001133 return NULL;
1134}
Linus Torvalds1da177e2005-04-16 15:20:36 -07001135
1136static int
Matthew Garrette92a7162010-01-12 14:17:03 -05001137acpi_video_get_device_type(struct acpi_video_bus *video,
1138 unsigned long device_id)
1139{
1140 struct acpi_video_enumerated_device *ids;
1141 int i;
1142
1143 for (i = 0; i < video->attached_count; i++) {
1144 ids = &video->attached_array[i];
1145 if ((ids->value.int_val & 0xffff) == device_id)
1146 return ids->value.int_val;
1147 }
1148
1149 return 0;
1150}
1151
1152static int
Len Brown4be44fc2005-08-05 00:44:28 -04001153acpi_video_bus_get_one_device(struct acpi_device *device,
1154 struct acpi_video_bus *video)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001155{
Matthew Wilcox27663c52008-10-10 02:22:59 -04001156 unsigned long long device_id;
Matthew Garrette92a7162010-01-12 14:17:03 -05001157 int status, device_type;
Len Brown4be44fc2005-08-05 00:44:28 -04001158 struct acpi_video_device *data;
Felipe Contreras915ea7e2013-08-03 22:12:50 +02001159 struct acpi_video_device_attrib *attribute;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001160
Len Brown4be44fc2005-08-05 00:44:28 -04001161 status =
1162 acpi_evaluate_integer(device->handle, "_ADR", NULL, &device_id);
Aaron Lu91e13aa2013-04-25 02:47:49 +00001163 /* Some device omits _ADR, we skip them instead of fail */
1164 if (ACPI_FAILURE(status))
1165 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001166
Aaron Lu91e13aa2013-04-25 02:47:49 +00001167 data = kzalloc(sizeof(struct acpi_video_device), GFP_KERNEL);
1168 if (!data)
1169 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001170
Aaron Lu91e13aa2013-04-25 02:47:49 +00001171 strcpy(acpi_device_name(device), ACPI_VIDEO_DEVICE_NAME);
1172 strcpy(acpi_device_class(device), ACPI_VIDEO_CLASS);
1173 device->driver_data = data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001174
Aaron Lu91e13aa2013-04-25 02:47:49 +00001175 data->device_id = device_id;
1176 data->video = video;
1177 data->dev = device;
Linus Torvalds8ab58e82014-07-18 14:32:51 +02001178 INIT_DELAYED_WORK(&data->switch_brightness_work,
1179 acpi_video_switch_brightness);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001180
Aaron Lu91e13aa2013-04-25 02:47:49 +00001181 attribute = acpi_video_get_device_attr(video, device_id);
Rui Zhang82cae992007-01-03 23:40:53 -05001182
Aaron Lue50b9be2015-10-28 15:09:23 +08001183 if (attribute && (attribute->device_id_scheme || device_id_scheme)) {
Aaron Lu91e13aa2013-04-25 02:47:49 +00001184 switch (attribute->display_type) {
1185 case ACPI_VIDEO_DISPLAY_CRT:
1186 data->flags.crt = 1;
1187 break;
1188 case ACPI_VIDEO_DISPLAY_TV:
1189 data->flags.tvout = 1;
1190 break;
1191 case ACPI_VIDEO_DISPLAY_DVI:
1192 data->flags.dvi = 1;
1193 break;
1194 case ACPI_VIDEO_DISPLAY_LCD:
1195 data->flags.lcd = 1;
1196 break;
1197 default:
1198 data->flags.unknown = 1;
1199 break;
1200 }
Felipe Contreras915ea7e2013-08-03 22:12:50 +02001201 if (attribute->bios_can_detect)
Aaron Lu91e13aa2013-04-25 02:47:49 +00001202 data->flags.bios = 1;
1203 } else {
1204 /* Check for legacy IDs */
1205 device_type = acpi_video_get_device_type(video, device_id);
1206 /* Ignore bits 16 and 18-20 */
1207 switch (device_type & 0xffe2ffff) {
Felipe Contreras915ea7e2013-08-03 22:12:50 +02001208 case ACPI_VIDEO_DISPLAY_LEGACY_MONITOR:
1209 data->flags.crt = 1;
1210 break;
1211 case ACPI_VIDEO_DISPLAY_LEGACY_PANEL:
1212 data->flags.lcd = 1;
1213 break;
1214 case ACPI_VIDEO_DISPLAY_LEGACY_TV:
1215 data->flags.tvout = 1;
1216 break;
1217 default:
1218 data->flags.unknown = 1;
Matthew Garrette92a7162010-01-12 14:17:03 -05001219 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001220 }
1221
Aaron Lu91e13aa2013-04-25 02:47:49 +00001222 acpi_video_device_bind(video, data);
1223 acpi_video_device_find_cap(data);
1224
Aaron Lu91e13aa2013-04-25 02:47:49 +00001225 mutex_lock(&video->device_list_lock);
1226 list_add_tail(&data->entry, &video->video_device_list);
1227 mutex_unlock(&video->device_list_lock);
1228
1229 return status;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001230}
1231
1232/*
1233 * Arg:
Felipe Contreras21fcb342013-08-01 18:43:59 -05001234 * video : video bus device
Linus Torvalds1da177e2005-04-16 15:20:36 -07001235 *
1236 * Return:
Felipe Contreras21fcb342013-08-01 18:43:59 -05001237 * none
1238 *
1239 * Enumerate the video device list of the video bus,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001240 * bind the ids with the corresponding video devices
1241 * under the video bus.
Len Brown4be44fc2005-08-05 00:44:28 -04001242 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001243
Len Brown4be44fc2005-08-05 00:44:28 -04001244static void acpi_video_device_rebind(struct acpi_video_bus *video)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001245{
Dmitry Torokhovff102ea2007-11-05 11:43:31 -05001246 struct acpi_video_device *dev;
1247
Dmitry Torokhovbbac81f2007-11-05 11:43:32 -05001248 mutex_lock(&video->device_list_lock);
Dmitry Torokhovff102ea2007-11-05 11:43:31 -05001249
1250 list_for_each_entry(dev, &video->video_device_list, entry)
Len Brown4be44fc2005-08-05 00:44:28 -04001251 acpi_video_device_bind(video, dev);
Dmitry Torokhovff102ea2007-11-05 11:43:31 -05001252
Dmitry Torokhovbbac81f2007-11-05 11:43:32 -05001253 mutex_unlock(&video->device_list_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001254}
1255
1256/*
1257 * Arg:
Felipe Contreras21fcb342013-08-01 18:43:59 -05001258 * video : video bus device
1259 * device : video output device under the video
1260 * bus
Linus Torvalds1da177e2005-04-16 15:20:36 -07001261 *
1262 * Return:
Felipe Contreras21fcb342013-08-01 18:43:59 -05001263 * none
1264 *
Linus Torvalds1da177e2005-04-16 15:20:36 -07001265 * Bind the ids with the corresponding video devices
1266 * under the video bus.
Len Brown4be44fc2005-08-05 00:44:28 -04001267 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001268
1269static void
Len Brown4be44fc2005-08-05 00:44:28 -04001270acpi_video_device_bind(struct acpi_video_bus *video,
1271 struct acpi_video_device *device)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001272{
Dmitry Torokhov78eed022007-11-05 11:43:33 -05001273 struct acpi_video_enumerated_device *ids;
Len Brown4be44fc2005-08-05 00:44:28 -04001274 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001275
Dmitry Torokhov78eed022007-11-05 11:43:33 -05001276 for (i = 0; i < video->attached_count; i++) {
1277 ids = &video->attached_array[i];
1278 if (device->device_id == (ids->value.int_val & 0xffff)) {
1279 ids->bind_info = device;
Rafael J. Wysocki2924d2f2021-02-03 19:48:33 +01001280 acpi_handle_debug(video->device->handle, "%s: %d\n",
1281 __func__, i);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001282 }
1283 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001284}
1285
Aaron Lu0b8db272014-09-30 14:10:17 +08001286static bool acpi_video_device_in_dod(struct acpi_video_device *device)
1287{
1288 struct acpi_video_bus *video = device->video;
1289 int i;
1290
Aaron Lub4df4632014-12-15 16:01:29 +08001291 /*
1292 * If we have a broken _DOD or we have more than 8 output devices
1293 * under the graphics controller node that we can't proper deal with
1294 * in the operation region code currently, no need to test.
1295 */
1296 if (!video->attached_count || video->child_count > 8)
Aaron Lu0b8db272014-09-30 14:10:17 +08001297 return true;
1298
1299 for (i = 0; i < video->attached_count; i++) {
Aaron Lu35d05652014-12-01 02:09:18 +01001300 if ((video->attached_array[i].value.int_val & 0xfff) ==
1301 (device->device_id & 0xfff))
Aaron Lu0b8db272014-09-30 14:10:17 +08001302 return true;
1303 }
1304
1305 return false;
1306}
1307
Linus Torvalds1da177e2005-04-16 15:20:36 -07001308/*
1309 * Arg:
Felipe Contreras21fcb342013-08-01 18:43:59 -05001310 * video : video bus device
Linus Torvalds1da177e2005-04-16 15:20:36 -07001311 *
1312 * Return:
Felipe Contreras21fcb342013-08-01 18:43:59 -05001313 * < 0 : error
1314 *
Linus Torvalds1da177e2005-04-16 15:20:36 -07001315 * Call _DOD to enumerate all devices attached to display adapter
1316 *
Len Brown4be44fc2005-08-05 00:44:28 -04001317 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001318
1319static int acpi_video_device_enumerate(struct acpi_video_bus *video)
1320{
Len Brown4be44fc2005-08-05 00:44:28 -04001321 int status;
1322 int count;
1323 int i;
Dmitry Torokhov78eed022007-11-05 11:43:33 -05001324 struct acpi_video_enumerated_device *active_list;
Len Brown4be44fc2005-08-05 00:44:28 -04001325 struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
1326 union acpi_object *dod = NULL;
1327 union acpi_object *obj;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001328
Alex Hunge34fbba2016-05-27 15:47:06 +08001329 if (!video->cap._DOD)
1330 return AE_NOT_EXIST;
1331
Patrick Mochel90130262006-05-19 16:54:48 -04001332 status = acpi_evaluate_object(video->device->handle, "_DOD", NULL, &buffer);
Rafael J. Wysocki2924d2f2021-02-03 19:48:33 +01001333 if (ACPI_FAILURE(status)) {
1334 acpi_handle_info(video->device->handle,
1335 "_DOD evaluation failed: %s\n",
1336 acpi_format_exception(status));
Patrick Mocheld550d982006-06-27 00:41:40 -04001337 return status;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001338 }
1339
Jan Engelhardt50dd0962006-10-01 00:28:50 +02001340 dod = buffer.pointer;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001341 if (!dod || (dod->type != ACPI_TYPE_PACKAGE)) {
Rafael J. Wysocki2924d2f2021-02-03 19:48:33 +01001342 acpi_handle_info(video->device->handle, "Invalid _DOD data\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001343 status = -EFAULT;
1344 goto out;
1345 }
1346
Rafael J. Wysocki2924d2f2021-02-03 19:48:33 +01001347 acpi_handle_debug(video->device->handle, "Found %d video heads in _DOD\n",
1348 dod->package.count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001349
Dmitry Torokhov78eed022007-11-05 11:43:33 -05001350 active_list = kcalloc(1 + dod->package.count,
1351 sizeof(struct acpi_video_enumerated_device),
1352 GFP_KERNEL);
1353 if (!active_list) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001354 status = -ENOMEM;
1355 goto out;
1356 }
1357
1358 count = 0;
1359 for (i = 0; i < dod->package.count; i++) {
Jan Engelhardt50dd0962006-10-01 00:28:50 +02001360 obj = &dod->package.elements[i];
Linus Torvalds1da177e2005-04-16 15:20:36 -07001361
1362 if (obj->type != ACPI_TYPE_INTEGER) {
Rafael J. Wysocki2924d2f2021-02-03 19:48:33 +01001363 acpi_handle_info(video->device->handle,
1364 "Invalid _DOD data in element %d\n", i);
Dmitry Torokhov78eed022007-11-05 11:43:33 -05001365 continue;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001366 }
Dmitry Torokhov78eed022007-11-05 11:43:33 -05001367
1368 active_list[count].value.int_val = obj->integer.value;
1369 active_list[count].bind_info = NULL;
Rafael J. Wysocki2924d2f2021-02-03 19:48:33 +01001370
1371 acpi_handle_debug(video->device->handle,
1372 "_DOD element[%d] = %d\n", i,
1373 (int)obj->integer.value);
1374
Linus Torvalds1da177e2005-04-16 15:20:36 -07001375 count++;
1376 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001377
Jesper Juhl6044ec82005-11-07 01:01:32 -08001378 kfree(video->attached_array);
Len Brown4be44fc2005-08-05 00:44:28 -04001379
Dmitry Torokhov78eed022007-11-05 11:43:33 -05001380 video->attached_array = active_list;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001381 video->attached_count = count;
Dmitry Torokhov78eed022007-11-05 11:43:33 -05001382
Felipe Contreras915ea7e2013-08-03 22:12:50 +02001383out:
Len Brown02438d82006-06-30 03:19:10 -04001384 kfree(buffer.pointer);
Patrick Mocheld550d982006-06-27 00:41:40 -04001385 return status;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001386}
1387
Len Brown4be44fc2005-08-05 00:44:28 -04001388static int
1389acpi_video_get_next_level(struct acpi_video_device *device,
1390 u32 level_current, u32 event)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001391{
Alexey Starikovskiy63f0edf2007-09-03 16:30:08 +04001392 int min, max, min_above, max_below, i, l, delta = 255;
Thomas Tuttlef4715182006-12-19 12:56:14 -08001393 max = max_below = 0;
1394 min = min_above = 255;
Alexey Starikovskiy63f0edf2007-09-03 16:30:08 +04001395 /* Find closest level to level_current */
Dmitry Frankd485ef42017-04-19 12:48:07 +03001396 for (i = ACPI_VIDEO_FIRST_LEVEL; i < device->brightness->count; i++) {
Alexey Starikovskiy63f0edf2007-09-03 16:30:08 +04001397 l = device->brightness->levels[i];
1398 if (abs(l - level_current) < abs(delta)) {
1399 delta = l - level_current;
1400 if (!delta)
1401 break;
1402 }
1403 }
Tom Saeger935ab852021-03-12 18:55:35 -07001404 /* Adjust level_current to closest available level */
Alexey Starikovskiy63f0edf2007-09-03 16:30:08 +04001405 level_current += delta;
Dmitry Frankd485ef42017-04-19 12:48:07 +03001406 for (i = ACPI_VIDEO_FIRST_LEVEL; i < device->brightness->count; i++) {
Thomas Tuttlef4715182006-12-19 12:56:14 -08001407 l = device->brightness->levels[i];
1408 if (l < min)
1409 min = l;
1410 if (l > max)
1411 max = l;
1412 if (l < min_above && l > level_current)
1413 min_above = l;
1414 if (l > max_below && l < level_current)
1415 max_below = l;
1416 }
1417
1418 switch (event) {
1419 case ACPI_VIDEO_NOTIFY_CYCLE_BRIGHTNESS:
1420 return (level_current < max) ? min_above : min;
1421 case ACPI_VIDEO_NOTIFY_INC_BRIGHTNESS:
1422 return (level_current < max) ? min_above : max;
1423 case ACPI_VIDEO_NOTIFY_DEC_BRIGHTNESS:
1424 return (level_current > min) ? max_below : min;
1425 case ACPI_VIDEO_NOTIFY_ZERO_BRIGHTNESS:
1426 case ACPI_VIDEO_NOTIFY_DISPLAY_OFF:
1427 return 0;
1428 default:
1429 return level_current;
1430 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001431}
1432
Linus Torvalds8ab58e82014-07-18 14:32:51 +02001433static void
1434acpi_video_switch_brightness(struct work_struct *work)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001435{
Linus Torvalds8ab58e82014-07-18 14:32:51 +02001436 struct acpi_video_device *device = container_of(to_delayed_work(work),
1437 struct acpi_video_device, switch_brightness_work);
Matthew Wilcox27663c52008-10-10 02:22:59 -04001438 unsigned long long level_current, level_next;
Linus Torvalds8ab58e82014-07-18 14:32:51 +02001439 int event = device->switch_brightness_event;
Zhang Ruic8890f92009-03-18 16:27:08 +08001440 int result = -EINVAL;
1441
Aaron Lufbc9fe12013-10-11 21:27:45 +08001442 /* no warning message if acpi_backlight=vendor or a quirk is used */
Hans de Goede654a1822015-06-09 10:32:25 +02001443 if (!device->backlight)
Linus Torvalds8ab58e82014-07-18 14:32:51 +02001444 return;
Zhang Rui28c32e92009-07-13 10:33:24 +08001445
Julia Jomantaite469778c2008-06-23 22:50:42 +01001446 if (!device->brightness)
Zhang Ruic8890f92009-03-18 16:27:08 +08001447 goto out;
1448
1449 result = acpi_video_device_lcd_get_level_current(device,
Danny Baumanna89803d2013-03-19 16:22:50 +00001450 &level_current,
1451 false);
Zhang Ruic8890f92009-03-18 16:27:08 +08001452 if (result)
1453 goto out;
1454
Linus Torvalds1da177e2005-04-16 15:20:36 -07001455 level_next = acpi_video_get_next_level(device, level_current, event);
Zhang Ruic8890f92009-03-18 16:27:08 +08001456
Zhang Rui24450c72009-03-18 16:27:10 +08001457 result = acpi_video_device_lcd_set_level(device, level_next);
Zhang Ruic8890f92009-03-18 16:27:08 +08001458
Matthew Garrett36342742009-07-14 17:06:03 +01001459 if (!result)
1460 backlight_force_update(device->backlight,
1461 BACKLIGHT_UPDATE_HOTKEY);
1462
Zhang Ruic8890f92009-03-18 16:27:08 +08001463out:
1464 if (result)
Rafael J. Wysocki2924d2f2021-02-03 19:48:33 +01001465 acpi_handle_info(device->dev->handle,
1466 "Failed to switch brightness\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001467}
1468
Matthew Garrette92a7162010-01-12 14:17:03 -05001469int acpi_video_get_edid(struct acpi_device *device, int type, int device_id,
1470 void **edid)
1471{
1472 struct acpi_video_bus *video;
1473 struct acpi_video_device *video_device;
1474 union acpi_object *buffer = NULL;
1475 acpi_status status;
1476 int i, length;
1477
1478 if (!device || !acpi_driver_data(device))
1479 return -EINVAL;
1480
1481 video = acpi_driver_data(device);
1482
1483 for (i = 0; i < video->attached_count; i++) {
1484 video_device = video->attached_array[i].bind_info;
1485 length = 256;
1486
1487 if (!video_device)
1488 continue;
1489
Zhang Rui82069552010-12-06 15:04:24 +08001490 if (!video_device->cap._DDC)
1491 continue;
1492
Matthew Garrette92a7162010-01-12 14:17:03 -05001493 if (type) {
1494 switch (type) {
1495 case ACPI_VIDEO_DISPLAY_CRT:
1496 if (!video_device->flags.crt)
1497 continue;
1498 break;
1499 case ACPI_VIDEO_DISPLAY_TV:
1500 if (!video_device->flags.tvout)
1501 continue;
1502 break;
1503 case ACPI_VIDEO_DISPLAY_DVI:
1504 if (!video_device->flags.dvi)
1505 continue;
1506 break;
1507 case ACPI_VIDEO_DISPLAY_LCD:
1508 if (!video_device->flags.lcd)
1509 continue;
1510 break;
1511 }
1512 } else if (video_device->device_id != device_id) {
1513 continue;
1514 }
1515
1516 status = acpi_video_device_EDID(video_device, &buffer, length);
1517
1518 if (ACPI_FAILURE(status) || !buffer ||
1519 buffer->type != ACPI_TYPE_BUFFER) {
1520 length = 128;
1521 status = acpi_video_device_EDID(video_device, &buffer,
1522 length);
1523 if (ACPI_FAILURE(status) || !buffer ||
1524 buffer->type != ACPI_TYPE_BUFFER) {
1525 continue;
1526 }
1527 }
1528
1529 *edid = buffer->buffer.pointer;
1530 return length;
1531 }
1532
1533 return -ENODEV;
1534}
1535EXPORT_SYMBOL(acpi_video_get_edid);
1536
Linus Torvalds1da177e2005-04-16 15:20:36 -07001537static int
Len Brown4be44fc2005-08-05 00:44:28 -04001538acpi_video_bus_get_devices(struct acpi_video_bus *video,
1539 struct acpi_device *device)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001540{
Igor Murzovfba4e082012-10-13 04:41:25 +04001541 int status = 0;
Dmitry Torokhovff102ea2007-11-05 11:43:31 -05001542 struct acpi_device *dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001543
Igor Murzovfba4e082012-10-13 04:41:25 +04001544 /*
1545 * There are systems where video module known to work fine regardless
1546 * of broken _DOD and ignoring returned value here doesn't cause
1547 * any issues later.
1548 */
1549 acpi_video_device_enumerate(video);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001550
Dmitry Torokhovff102ea2007-11-05 11:43:31 -05001551 list_for_each_entry(dev, &device->children, node) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001552
1553 status = acpi_video_bus_get_one_device(dev, video);
Igor Murzovea9f8852012-03-30 21:32:08 +04001554 if (status) {
Aaron Lu91e13aa2013-04-25 02:47:49 +00001555 dev_err(&dev->dev, "Can't attach device\n");
1556 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001557 }
Aaron Lub4df4632014-12-15 16:01:29 +08001558 video->child_count++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001559 }
Patrick Mocheld550d982006-06-27 00:41:40 -04001560 return status;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001561}
1562
Linus Torvalds1da177e2005-04-16 15:20:36 -07001563/* acpi_video interface */
1564
Aaron Luefaa14c2013-07-16 13:08:05 +08001565/*
1566 * Win8 requires setting bit2 of _DOS to let firmware know it shouldn't
Tom Saeger935ab852021-03-12 18:55:35 -07001567 * perform any automatic brightness change on receiving a notification.
Aaron Luefaa14c2013-07-16 13:08:05 +08001568 */
Len Brown4be44fc2005-08-05 00:44:28 -04001569static int acpi_video_bus_start_devices(struct acpi_video_bus *video)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001570{
Aaron Luefaa14c2013-07-16 13:08:05 +08001571 return acpi_video_bus_DOS(video, 0,
Aaron Lufbc9fe12013-10-11 21:27:45 +08001572 acpi_osi_is_win8() ? 1 : 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001573}
1574
Len Brown4be44fc2005-08-05 00:44:28 -04001575static int acpi_video_bus_stop_devices(struct acpi_video_bus *video)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001576{
Aaron Luefaa14c2013-07-16 13:08:05 +08001577 return acpi_video_bus_DOS(video, 0,
Aaron Lufbc9fe12013-10-11 21:27:45 +08001578 acpi_osi_is_win8() ? 0 : 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001579}
1580
Bjorn Helgaas70155582009-04-07 15:37:11 +00001581static void acpi_video_bus_notify(struct acpi_device *device, u32 event)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001582{
Bjorn Helgaas70155582009-04-07 15:37:11 +00001583 struct acpi_video_bus *video = acpi_driver_data(device);
Luming Yue9dab192007-08-20 18:23:53 +08001584 struct input_dev *input;
Matthew Garrett17c452f2009-12-11 17:40:46 -05001585 int keycode = 0;
Luming Yue9dab192007-08-20 18:23:53 +08001586
Aaron Lu67b662e2013-10-11 21:27:44 +08001587 if (!video || !video->input)
Patrick Mocheld550d982006-06-27 00:41:40 -04001588 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001589
Luming Yue9dab192007-08-20 18:23:53 +08001590 input = video->input;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001591
1592 switch (event) {
Julius Volz98fb8fe2007-02-20 16:38:40 +01001593 case ACPI_VIDEO_NOTIFY_SWITCH: /* User requested a switch,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001594 * most likely via hotkey. */
Luca Tettamanti8a37c652012-08-02 15:30:27 +02001595 keycode = KEY_SWITCHVIDEOMODE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001596 break;
1597
Julius Volz98fb8fe2007-02-20 16:38:40 +01001598 case ACPI_VIDEO_NOTIFY_PROBE: /* User plugged in or removed a video
Linus Torvalds1da177e2005-04-16 15:20:36 -07001599 * connector. */
1600 acpi_video_device_enumerate(video);
1601 acpi_video_device_rebind(video);
Luming Yue9dab192007-08-20 18:23:53 +08001602 keycode = KEY_SWITCHVIDEOMODE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001603 break;
1604
Len Brown4be44fc2005-08-05 00:44:28 -04001605 case ACPI_VIDEO_NOTIFY_CYCLE: /* Cycle Display output hotkey pressed. */
Luming Yue9dab192007-08-20 18:23:53 +08001606 keycode = KEY_SWITCHVIDEOMODE;
1607 break;
Len Brown4be44fc2005-08-05 00:44:28 -04001608 case ACPI_VIDEO_NOTIFY_NEXT_OUTPUT: /* Next Display output hotkey pressed. */
Luming Yue9dab192007-08-20 18:23:53 +08001609 keycode = KEY_VIDEO_NEXT;
1610 break;
Len Brown4be44fc2005-08-05 00:44:28 -04001611 case ACPI_VIDEO_NOTIFY_PREV_OUTPUT: /* previous Display output hotkey pressed. */
Luming Yue9dab192007-08-20 18:23:53 +08001612 keycode = KEY_VIDEO_PREV;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001613 break;
1614
1615 default:
Rafael J. Wysocki2924d2f2021-02-03 19:48:33 +01001616 acpi_handle_debug(device->handle, "Unsupported event [0x%x]\n",
1617 event);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001618 break;
1619 }
1620
Luca Tettamanti8a37c652012-08-02 15:30:27 +02001621 if (acpi_notifier_call_chain(device, event, 0))
1622 /* Something vetoed the keypress. */
1623 keycode = 0;
Matthew Garrett17c452f2009-12-11 17:40:46 -05001624
Hans de Goede05bc59a2015-12-22 19:09:51 +01001625 if (keycode && (report_key_events & REPORT_OUTPUT_KEY_EVENTS)) {
Matthew Garrett17c452f2009-12-11 17:40:46 -05001626 input_report_key(input, keycode, 1);
1627 input_sync(input);
1628 input_report_key(input, keycode, 0);
1629 input_sync(input);
1630 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001631}
1632
Linus Torvalds8ab58e82014-07-18 14:32:51 +02001633static void brightness_switch_event(struct acpi_video_device *video_device,
1634 u32 event)
1635{
1636 if (!brightness_switch_enabled)
1637 return;
1638
1639 video_device->switch_brightness_event = event;
1640 schedule_delayed_work(&video_device->switch_brightness_work, HZ / 10);
1641}
1642
Len Brown4be44fc2005-08-05 00:44:28 -04001643static void acpi_video_device_notify(acpi_handle handle, u32 event, void *data)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001644{
Jan Engelhardt50dd0962006-10-01 00:28:50 +02001645 struct acpi_video_device *video_device = data;
Len Brown4be44fc2005-08-05 00:44:28 -04001646 struct acpi_device *device = NULL;
Luming Yue9dab192007-08-20 18:23:53 +08001647 struct acpi_video_bus *bus;
1648 struct input_dev *input;
Matthew Garrett17c452f2009-12-11 17:40:46 -05001649 int keycode = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001650
Linus Torvalds1da177e2005-04-16 15:20:36 -07001651 if (!video_device)
Patrick Mocheld550d982006-06-27 00:41:40 -04001652 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001653
Patrick Mochele6afa0d2006-05-19 16:54:40 -04001654 device = video_device->dev;
Luming Yue9dab192007-08-20 18:23:53 +08001655 bus = video_device->video;
1656 input = bus->input;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001657
Hans de Goede4f7f9642019-07-12 12:00:33 +02001658 if (hw_changes_brightness > 0) {
1659 if (video_device->backlight)
1660 backlight_force_update(video_device->backlight,
1661 BACKLIGHT_UPDATE_HOTKEY);
1662 acpi_notifier_call_chain(device, event, 0);
1663 return;
1664 }
1665
Linus Torvalds1da177e2005-04-16 15:20:36 -07001666 switch (event) {
Len Brown4be44fc2005-08-05 00:44:28 -04001667 case ACPI_VIDEO_NOTIFY_CYCLE_BRIGHTNESS: /* Cycle brightness */
Linus Torvalds8ab58e82014-07-18 14:32:51 +02001668 brightness_switch_event(video_device, event);
Luming Yue9dab192007-08-20 18:23:53 +08001669 keycode = KEY_BRIGHTNESS_CYCLE;
1670 break;
Len Brown4be44fc2005-08-05 00:44:28 -04001671 case ACPI_VIDEO_NOTIFY_INC_BRIGHTNESS: /* Increase brightness */
Linus Torvalds8ab58e82014-07-18 14:32:51 +02001672 brightness_switch_event(video_device, event);
Luming Yue9dab192007-08-20 18:23:53 +08001673 keycode = KEY_BRIGHTNESSUP;
1674 break;
Len Brown4be44fc2005-08-05 00:44:28 -04001675 case ACPI_VIDEO_NOTIFY_DEC_BRIGHTNESS: /* Decrease brightness */
Linus Torvalds8ab58e82014-07-18 14:32:51 +02001676 brightness_switch_event(video_device, event);
Luming Yue9dab192007-08-20 18:23:53 +08001677 keycode = KEY_BRIGHTNESSDOWN;
1678 break;
Justin P. Mattock70f23fd2011-05-10 10:16:21 +02001679 case ACPI_VIDEO_NOTIFY_ZERO_BRIGHTNESS: /* zero brightness */
Linus Torvalds8ab58e82014-07-18 14:32:51 +02001680 brightness_switch_event(video_device, event);
Luming Yue9dab192007-08-20 18:23:53 +08001681 keycode = KEY_BRIGHTNESS_ZERO;
1682 break;
Len Brown4be44fc2005-08-05 00:44:28 -04001683 case ACPI_VIDEO_NOTIFY_DISPLAY_OFF: /* display device off */
Linus Torvalds8ab58e82014-07-18 14:32:51 +02001684 brightness_switch_event(video_device, event);
Luming Yue9dab192007-08-20 18:23:53 +08001685 keycode = KEY_DISPLAY_OFF;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001686 break;
1687 default:
Rafael J. Wysocki2924d2f2021-02-03 19:48:33 +01001688 acpi_handle_debug(handle, "Unsupported event [0x%x]\n", event);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001689 break;
1690 }
Luming Yue9dab192007-08-20 18:23:53 +08001691
Zhang Rui7761f632008-01-25 14:48:12 +08001692 acpi_notifier_call_chain(device, event, 0);
Matthew Garrett17c452f2009-12-11 17:40:46 -05001693
Hans de Goede05bc59a2015-12-22 19:09:51 +01001694 if (keycode && (report_key_events & REPORT_BRIGHTNESS_KEY_EVENTS)) {
Matthew Garrett17c452f2009-12-11 17:40:46 -05001695 input_report_key(input, keycode, 1);
1696 input_sync(input);
1697 input_report_key(input, keycode, 0);
1698 input_sync(input);
1699 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001700}
1701
Rafael J. Wysockiac7729d2010-04-05 01:43:51 +02001702static int acpi_video_resume(struct notifier_block *nb,
1703 unsigned long val, void *ign)
Matthew Garrett863c1492008-02-04 23:31:24 -08001704{
1705 struct acpi_video_bus *video;
1706 struct acpi_video_device *video_device;
1707 int i;
1708
Rafael J. Wysockiac7729d2010-04-05 01:43:51 +02001709 switch (val) {
1710 case PM_HIBERNATION_PREPARE:
1711 case PM_SUSPEND_PREPARE:
1712 case PM_RESTORE_PREPARE:
1713 return NOTIFY_DONE;
1714 }
Matthew Garrett863c1492008-02-04 23:31:24 -08001715
Rafael J. Wysockiac7729d2010-04-05 01:43:51 +02001716 video = container_of(nb, struct acpi_video_bus, pm_nb);
1717
1718 dev_info(&video->device->dev, "Restoring backlight state\n");
Matthew Garrett863c1492008-02-04 23:31:24 -08001719
1720 for (i = 0; i < video->attached_count; i++) {
1721 video_device = video->attached_array[i].bind_info;
Hans de Goede654a1822015-06-09 10:32:25 +02001722 if (video_device && video_device->brightness)
1723 acpi_video_device_lcd_set_level(video_device,
1724 video_device->brightness->curr);
Matthew Garrett863c1492008-02-04 23:31:24 -08001725 }
Rafael J. Wysockiac7729d2010-04-05 01:43:51 +02001726
1727 return NOTIFY_OK;
Matthew Garrett863c1492008-02-04 23:31:24 -08001728}
1729
Zhang Ruic504f8c2009-12-30 15:59:23 +08001730static acpi_status
1731acpi_video_bus_match(acpi_handle handle, u32 level, void *context,
1732 void **return_value)
1733{
1734 struct acpi_device *device = context;
1735 struct acpi_device *sibling;
Zhang Ruic504f8c2009-12-30 15:59:23 +08001736
1737 if (handle == device->handle)
1738 return AE_CTRL_TERMINATE;
1739
Rafael J. Wysocki99ece712021-12-03 17:37:10 +01001740 sibling = acpi_fetch_acpi_dev(handle);
1741 if (!sibling)
Zhang Ruic504f8c2009-12-30 15:59:23 +08001742 return AE_OK;
1743
1744 if (!strcmp(acpi_device_name(sibling), ACPI_VIDEO_BUS_NAME))
1745 return AE_ALREADY_EXISTS;
1746
1747 return AE_OK;
1748}
1749
Aaron Lu67b662e2013-10-11 21:27:44 +08001750static void acpi_video_dev_register_backlight(struct acpi_video_device *device)
1751{
Hans de Goede99678ed2014-05-15 13:22:33 +02001752 struct backlight_properties props;
1753 struct pci_dev *pdev;
1754 acpi_handle acpi_parent;
1755 struct device *parent = NULL;
1756 int result;
1757 static int count;
1758 char *name;
Aaron Lu67b662e2013-10-11 21:27:44 +08001759
Hans de Goede99678ed2014-05-15 13:22:33 +02001760 result = acpi_video_init_brightness(device);
1761 if (result)
1762 return;
Hans de Goede654a1822015-06-09 10:32:25 +02001763
1764 if (disable_backlight_sysfs_if > 0)
1765 return;
1766
Hans de Goede99678ed2014-05-15 13:22:33 +02001767 name = kasprintf(GFP_KERNEL, "acpi_video%d", count);
1768 if (!name)
1769 return;
1770 count++;
Aaron Lu67b662e2013-10-11 21:27:44 +08001771
Hans de Goede99678ed2014-05-15 13:22:33 +02001772 acpi_get_parent(device->dev->handle, &acpi_parent);
Aaron Lu67b662e2013-10-11 21:27:44 +08001773
Hans de Goede99678ed2014-05-15 13:22:33 +02001774 pdev = acpi_get_pci_dev(acpi_parent);
1775 if (pdev) {
1776 parent = &pdev->dev;
1777 pci_dev_put(pdev);
Aaron Lu67b662e2013-10-11 21:27:44 +08001778 }
Hans de Goede99678ed2014-05-15 13:22:33 +02001779
1780 memset(&props, 0, sizeof(struct backlight_properties));
1781 props.type = BACKLIGHT_FIRMWARE;
Dmitry Frankd485ef42017-04-19 12:48:07 +03001782 props.max_brightness =
1783 device->brightness->count - ACPI_VIDEO_FIRST_LEVEL - 1;
Hans de Goede99678ed2014-05-15 13:22:33 +02001784 device->backlight = backlight_device_register(name,
1785 parent,
1786 device,
1787 &acpi_backlight_ops,
1788 &props);
1789 kfree(name);
Hans de Goede654a1822015-06-09 10:32:25 +02001790 if (IS_ERR(device->backlight)) {
1791 device->backlight = NULL;
Hans de Goede99678ed2014-05-15 13:22:33 +02001792 return;
Hans de Goede654a1822015-06-09 10:32:25 +02001793 }
Hans de Goede99678ed2014-05-15 13:22:33 +02001794
1795 /*
1796 * Save current brightness level in case we have to restore it
1797 * before acpi_video_device_lcd_set_level() is called next time.
1798 */
1799 device->backlight->props.brightness =
1800 acpi_video_get_brightness(device->backlight);
1801
1802 device->cooling_dev = thermal_cooling_device_register("LCD",
1803 device->dev, &video_cooling_ops);
1804 if (IS_ERR(device->cooling_dev)) {
1805 /*
1806 * Set cooling_dev to NULL so we don't crash trying to free it.
1807 * Also, why the hell we are returning early and not attempt to
1808 * register video output if cooling device registration failed?
1809 * -- dtor
1810 */
1811 device->cooling_dev = NULL;
1812 return;
1813 }
1814
1815 dev_info(&device->dev->dev, "registered as cooling_device%d\n",
1816 device->cooling_dev->id);
1817 result = sysfs_create_link(&device->dev->dev.kobj,
1818 &device->cooling_dev->device.kobj,
1819 "thermal_cooling");
1820 if (result)
Rafael J. Wysocki2924d2f2021-02-03 19:48:33 +01001821 pr_info("sysfs link creation failed\n");
1822
Hans de Goede99678ed2014-05-15 13:22:33 +02001823 result = sysfs_create_link(&device->cooling_dev->device.kobj,
1824 &device->dev->dev.kobj, "device");
1825 if (result)
Rafael J. Wysocki2924d2f2021-02-03 19:48:33 +01001826 pr_info("Reverse sysfs link creation failed\n");
Aaron Lu67b662e2013-10-11 21:27:44 +08001827}
1828
Aaron Ludce4ec22014-10-28 14:35:59 +08001829static void acpi_video_run_bcl_for_osi(struct acpi_video_bus *video)
1830{
1831 struct acpi_video_device *dev;
1832 union acpi_object *levels;
1833
1834 mutex_lock(&video->device_list_lock);
1835 list_for_each_entry(dev, &video->video_device_list, entry) {
Aaron Lu9f9cd7e2016-05-21 15:30:46 +08001836 if (!acpi_video_device_lcd_query_levels(dev->dev->handle, &levels))
Aaron Ludce4ec22014-10-28 14:35:59 +08001837 kfree(levels);
1838 }
1839 mutex_unlock(&video->device_list_lock);
1840}
1841
Aaron Lue50b9be2015-10-28 15:09:23 +08001842static bool acpi_video_should_register_backlight(struct acpi_video_device *dev)
1843{
1844 /*
1845 * Do not create backlight device for video output
1846 * device that is not in the enumerated list.
1847 */
1848 if (!acpi_video_device_in_dod(dev)) {
1849 dev_dbg(&dev->dev->dev, "not in _DOD list, ignore\n");
1850 return false;
1851 }
1852
1853 if (only_lcd)
1854 return dev->flags.lcd;
1855 return true;
1856}
1857
Aaron Lu67b662e2013-10-11 21:27:44 +08001858static int acpi_video_bus_register_backlight(struct acpi_video_bus *video)
1859{
1860 struct acpi_video_device *dev;
1861
Hans de Goede53a92ba2014-05-21 15:39:55 +02001862 if (video->backlight_registered)
1863 return 0;
1864
Aaron Ludce4ec22014-10-28 14:35:59 +08001865 acpi_video_run_bcl_for_osi(video);
1866
Hans de Goede3bd6bce2015-06-16 16:27:51 +02001867 if (acpi_video_get_backlight_type() != acpi_backlight_video)
Hans de Goede99678ed2014-05-15 13:22:33 +02001868 return 0;
1869
Aaron Lu67b662e2013-10-11 21:27:44 +08001870 mutex_lock(&video->device_list_lock);
Aaron Lue50b9be2015-10-28 15:09:23 +08001871 list_for_each_entry(dev, &video->video_device_list, entry) {
1872 if (acpi_video_should_register_backlight(dev))
1873 acpi_video_dev_register_backlight(dev);
1874 }
Aaron Lu67b662e2013-10-11 21:27:44 +08001875 mutex_unlock(&video->device_list_lock);
1876
Hans de Goede99678ed2014-05-15 13:22:33 +02001877 video->backlight_registered = true;
1878
Aaron Lu67b662e2013-10-11 21:27:44 +08001879 video->pm_nb.notifier_call = acpi_video_resume;
1880 video->pm_nb.priority = 0;
1881 return register_pm_notifier(&video->pm_nb);
1882}
1883
1884static void acpi_video_dev_unregister_backlight(struct acpi_video_device *device)
1885{
1886 if (device->backlight) {
1887 backlight_device_unregister(device->backlight);
1888 device->backlight = NULL;
1889 }
1890 if (device->brightness) {
1891 kfree(device->brightness->levels);
1892 kfree(device->brightness);
1893 device->brightness = NULL;
1894 }
1895 if (device->cooling_dev) {
1896 sysfs_remove_link(&device->dev->dev.kobj, "thermal_cooling");
1897 sysfs_remove_link(&device->cooling_dev->device.kobj, "device");
1898 thermal_cooling_device_unregister(device->cooling_dev);
1899 device->cooling_dev = NULL;
1900 }
1901}
1902
1903static int acpi_video_bus_unregister_backlight(struct acpi_video_bus *video)
1904{
1905 struct acpi_video_device *dev;
Hans de Goede99678ed2014-05-15 13:22:33 +02001906 int error;
1907
1908 if (!video->backlight_registered)
1909 return 0;
1910
1911 error = unregister_pm_notifier(&video->pm_nb);
Aaron Lu67b662e2013-10-11 21:27:44 +08001912
1913 mutex_lock(&video->device_list_lock);
1914 list_for_each_entry(dev, &video->video_device_list, entry)
1915 acpi_video_dev_unregister_backlight(dev);
1916 mutex_unlock(&video->device_list_lock);
1917
Hans de Goede99678ed2014-05-15 13:22:33 +02001918 video->backlight_registered = false;
1919
Aaron Lu67b662e2013-10-11 21:27:44 +08001920 return error;
1921}
1922
1923static void acpi_video_dev_add_notify_handler(struct acpi_video_device *device)
1924{
1925 acpi_status status;
1926 struct acpi_device *adev = device->dev;
1927
1928 status = acpi_install_notify_handler(adev->handle, ACPI_DEVICE_NOTIFY,
1929 acpi_video_device_notify, device);
1930 if (ACPI_FAILURE(status))
1931 dev_err(&adev->dev, "Error installing notify handler\n");
1932 else
1933 device->flags.notify = 1;
1934}
1935
1936static int acpi_video_bus_add_notify_handler(struct acpi_video_bus *video)
1937{
1938 struct input_dev *input;
1939 struct acpi_video_device *dev;
1940 int error;
1941
1942 video->input = input = input_allocate_device();
1943 if (!input) {
1944 error = -ENOMEM;
1945 goto out;
1946 }
1947
1948 error = acpi_video_bus_start_devices(video);
1949 if (error)
1950 goto err_free_input;
1951
1952 snprintf(video->phys, sizeof(video->phys),
1953 "%s/video/input0", acpi_device_hid(video->device));
1954
1955 input->name = acpi_device_name(video->device);
1956 input->phys = video->phys;
1957 input->id.bustype = BUS_HOST;
1958 input->id.product = 0x06;
1959 input->dev.parent = &video->device->dev;
1960 input->evbit[0] = BIT(EV_KEY);
1961 set_bit(KEY_SWITCHVIDEOMODE, input->keybit);
1962 set_bit(KEY_VIDEO_NEXT, input->keybit);
1963 set_bit(KEY_VIDEO_PREV, input->keybit);
1964 set_bit(KEY_BRIGHTNESS_CYCLE, input->keybit);
1965 set_bit(KEY_BRIGHTNESSUP, input->keybit);
1966 set_bit(KEY_BRIGHTNESSDOWN, input->keybit);
1967 set_bit(KEY_BRIGHTNESS_ZERO, input->keybit);
1968 set_bit(KEY_DISPLAY_OFF, input->keybit);
1969
1970 error = input_register_device(input);
1971 if (error)
1972 goto err_stop_dev;
1973
1974 mutex_lock(&video->device_list_lock);
1975 list_for_each_entry(dev, &video->video_device_list, entry)
1976 acpi_video_dev_add_notify_handler(dev);
1977 mutex_unlock(&video->device_list_lock);
1978
1979 return 0;
1980
1981err_stop_dev:
1982 acpi_video_bus_stop_devices(video);
1983err_free_input:
1984 input_free_device(input);
1985 video->input = NULL;
1986out:
1987 return error;
1988}
1989
1990static void acpi_video_dev_remove_notify_handler(struct acpi_video_device *dev)
1991{
1992 if (dev->flags.notify) {
1993 acpi_remove_notify_handler(dev->dev->handle, ACPI_DEVICE_NOTIFY,
1994 acpi_video_device_notify);
1995 dev->flags.notify = 0;
1996 }
1997}
1998
1999static void acpi_video_bus_remove_notify_handler(struct acpi_video_bus *video)
2000{
2001 struct acpi_video_device *dev;
2002
2003 mutex_lock(&video->device_list_lock);
2004 list_for_each_entry(dev, &video->video_device_list, entry)
2005 acpi_video_dev_remove_notify_handler(dev);
2006 mutex_unlock(&video->device_list_lock);
2007
2008 acpi_video_bus_stop_devices(video);
2009 input_unregister_device(video->input);
2010 video->input = NULL;
2011}
2012
2013static int acpi_video_bus_put_devices(struct acpi_video_bus *video)
2014{
2015 struct acpi_video_device *dev, *next;
2016
2017 mutex_lock(&video->device_list_lock);
2018 list_for_each_entry_safe(dev, next, &video->video_device_list, entry) {
2019 list_del(&dev->entry);
2020 kfree(dev);
2021 }
2022 mutex_unlock(&video->device_list_lock);
2023
2024 return 0;
2025}
2026
Rafael J. Wysockiac7729d2010-04-05 01:43:51 +02002027static int instance;
2028
Len Brown4be44fc2005-08-05 00:44:28 -04002029static int acpi_video_bus_add(struct acpi_device *device)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002030{
Dmitry Torokhovf51e8392007-11-05 11:43:30 -05002031 struct acpi_video_bus *video;
Dmitry Torokhovf51e8392007-11-05 11:43:30 -05002032 int error;
Zhang Ruic504f8c2009-12-30 15:59:23 +08002033 acpi_status status;
2034
2035 status = acpi_walk_namespace(ACPI_TYPE_DEVICE,
2036 device->parent->handle, 1,
2037 acpi_video_bus_match, NULL,
2038 device, NULL);
2039 if (status == AE_ALREADY_EXISTS) {
Rafael J. Wysocki2924d2f2021-02-03 19:48:33 +01002040 pr_info(FW_BUG
Zhang Ruic504f8c2009-12-30 15:59:23 +08002041 "Duplicate ACPI video bus devices for the"
2042 " same VGA controller, please try module "
2043 "parameter \"video.allow_duplicates=1\""
2044 "if the current driver doesn't work.\n");
2045 if (!allow_duplicates)
2046 return -ENODEV;
2047 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002048
Burman Yan36bcbec2006-12-19 12:56:11 -08002049 video = kzalloc(sizeof(struct acpi_video_bus), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002050 if (!video)
Patrick Mocheld550d982006-06-27 00:41:40 -04002051 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002052
Zhang Ruie6d9da12007-08-25 02:23:31 -04002053 /* a hack to fix the duplicate name "VID" problem on T61 */
2054 if (!strcmp(device->pnp.bus_id, "VID")) {
2055 if (instance)
2056 device->pnp.bus_id[3] = '0' + instance;
Felipe Contreras915ea7e2013-08-03 22:12:50 +02002057 instance++;
Zhang Ruie6d9da12007-08-25 02:23:31 -04002058 }
Zhao Yakuif3b39f12009-02-02 22:55:01 -05002059 /* a hack to fix the duplicate name "VGA" problem on Pa 3553 */
2060 if (!strcmp(device->pnp.bus_id, "VGA")) {
2061 if (instance)
2062 device->pnp.bus_id[3] = '0' + instance;
2063 instance++;
2064 }
Zhang Ruie6d9da12007-08-25 02:23:31 -04002065
Patrick Mochele6afa0d2006-05-19 16:54:40 -04002066 video->device = device;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002067 strcpy(acpi_device_name(device), ACPI_VIDEO_BUS_NAME);
2068 strcpy(acpi_device_class(device), ACPI_VIDEO_CLASS);
Pavel Machekdb89b4f2008-09-22 14:37:34 -07002069 device->driver_data = video;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002070
2071 acpi_video_bus_find_cap(video);
Dmitry Torokhovf51e8392007-11-05 11:43:30 -05002072 error = acpi_video_bus_check(video);
2073 if (error)
2074 goto err_free_video;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002075
Dmitry Torokhovbbac81f2007-11-05 11:43:32 -05002076 mutex_init(&video->device_list_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002077 INIT_LIST_HEAD(&video->video_device_list);
2078
Igor Murzovea9f8852012-03-30 21:32:08 +04002079 error = acpi_video_bus_get_devices(video, device);
2080 if (error)
Aaron Lu91e13aa2013-04-25 02:47:49 +00002081 goto err_put_video;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002082
Rafael J. Wysocki2924d2f2021-02-03 19:48:33 +01002083 pr_info("%s [%s] (multi-head: %s rom: %s post: %s)\n",
Len Brown4be44fc2005-08-05 00:44:28 -04002084 ACPI_VIDEO_DEVICE_NAME, acpi_device_bid(device),
2085 video->flags.multihead ? "yes" : "no",
2086 video->flags.rom ? "yes" : "no",
2087 video->flags.post ? "yes" : "no");
Aaron Lu67b662e2013-10-11 21:27:44 +08002088 mutex_lock(&video_list_lock);
2089 list_add_tail(&video->entry, &video_bus_head);
2090 mutex_unlock(&video_list_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002091
Aaron Lu67b662e2013-10-11 21:27:44 +08002092 acpi_video_bus_register_backlight(video);
2093 acpi_video_bus_add_notify_handler(video);
Rafael J. Wysockiac7729d2010-04-05 01:43:51 +02002094
Dmitry Torokhovf51e8392007-11-05 11:43:30 -05002095 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002096
Aaron Lu67b662e2013-10-11 21:27:44 +08002097err_put_video:
Dmitry Torokhovf51e8392007-11-05 11:43:30 -05002098 acpi_video_bus_put_devices(video);
2099 kfree(video->attached_array);
Aaron Lu67b662e2013-10-11 21:27:44 +08002100err_free_video:
Dmitry Torokhovf51e8392007-11-05 11:43:30 -05002101 kfree(video);
Pavel Machekdb89b4f2008-09-22 14:37:34 -07002102 device->driver_data = NULL;
Dmitry Torokhovf51e8392007-11-05 11:43:30 -05002103
2104 return error;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002105}
2106
Rafael J. Wysocki51fac832013-01-24 00:24:48 +01002107static int acpi_video_bus_remove(struct acpi_device *device)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002108{
Len Brown4be44fc2005-08-05 00:44:28 -04002109 struct acpi_video_bus *video = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002110
Linus Torvalds1da177e2005-04-16 15:20:36 -07002111
2112 if (!device || !acpi_driver_data(device))
Patrick Mocheld550d982006-06-27 00:41:40 -04002113 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002114
Jan Engelhardt50dd0962006-10-01 00:28:50 +02002115 video = acpi_driver_data(device);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002116
Aaron Lu67b662e2013-10-11 21:27:44 +08002117 acpi_video_bus_remove_notify_handler(video);
2118 acpi_video_bus_unregister_backlight(video);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002119 acpi_video_bus_put_devices(video);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002120
Aaron Lu67b662e2013-10-11 21:27:44 +08002121 mutex_lock(&video_list_lock);
2122 list_del(&video->entry);
2123 mutex_unlock(&video_list_lock);
2124
Jesper Juhl6044ec82005-11-07 01:01:32 -08002125 kfree(video->attached_array);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002126 kfree(video);
2127
Patrick Mocheld550d982006-06-27 00:41:40 -04002128 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002129}
2130
Alan Coxc6996bd2012-04-25 14:33:48 +01002131static int __init is_i740(struct pci_dev *dev)
2132{
2133 if (dev->device == 0x00D1)
2134 return 1;
2135 if (dev->device == 0x7000)
2136 return 1;
2137 return 0;
2138}
2139
Matthew Garrett74a365b2009-03-19 21:35:39 +00002140static int __init intel_opregion_present(void)
2141{
Alan Coxc6996bd2012-04-25 14:33:48 +01002142 int opregion = 0;
Matthew Garrett74a365b2009-03-19 21:35:39 +00002143 struct pci_dev *dev = NULL;
2144 u32 address;
2145
2146 for_each_pci_dev(dev) {
2147 if ((dev->class >> 8) != PCI_CLASS_DISPLAY_VGA)
2148 continue;
2149 if (dev->vendor != PCI_VENDOR_ID_INTEL)
2150 continue;
Alan Coxc6996bd2012-04-25 14:33:48 +01002151 /* We don't want to poke around undefined i740 registers */
2152 if (is_i740(dev))
2153 continue;
Matthew Garrett74a365b2009-03-19 21:35:39 +00002154 pci_read_config_dword(dev, 0xfc, &address);
2155 if (!address)
2156 continue;
Alan Coxc6996bd2012-04-25 14:33:48 +01002157 opregion = 1;
Matthew Garrett74a365b2009-03-19 21:35:39 +00002158 }
Alan Coxc6996bd2012-04-25 14:33:48 +01002159 return opregion;
Matthew Garrett74a365b2009-03-19 21:35:39 +00002160}
2161
Hans de Goedececf3e32019-01-07 17:08:20 +01002162/* Check if the chassis-type indicates there is no builtin LCD panel */
Hans de Goede53fa1f62018-04-17 18:23:50 +02002163static bool dmi_is_desktop(void)
2164{
2165 const char *chassis_type;
Hans de Goedececf3e32019-01-07 17:08:20 +01002166 unsigned long type;
Hans de Goede53fa1f62018-04-17 18:23:50 +02002167
2168 chassis_type = dmi_get_system_info(DMI_CHASSIS_TYPE);
2169 if (!chassis_type)
2170 return false;
2171
Hans de Goedececf3e32019-01-07 17:08:20 +01002172 if (kstrtoul(chassis_type, 10, &type) != 0)
2173 return false;
2174
2175 switch (type) {
2176 case 0x03: /* Desktop */
2177 case 0x04: /* Low Profile Desktop */
2178 case 0x05: /* Pizza Box */
2179 case 0x06: /* Mini Tower */
2180 case 0x07: /* Tower */
Hans de Goeded693c002019-01-07 17:08:21 +01002181 case 0x10: /* Lunch Box */
Hans de Goedececf3e32019-01-07 17:08:20 +01002182 case 0x11: /* Main Server Chassis */
Hans de Goede53fa1f62018-04-17 18:23:50 +02002183 return true;
Hans de Goedececf3e32019-01-07 17:08:20 +01002184 }
Hans de Goede53fa1f62018-04-17 18:23:50 +02002185
2186 return false;
2187}
2188
Hans de Goede81cc7e92021-04-06 23:16:53 +02002189/*
2190 * We're seeing a lot of bogus backlight interfaces on newer machines
2191 * without a LCD such as desktops, servers and HDMI sticks. Checking the
2192 * lcd flag fixes this, enable this by default on any machines which are:
2193 * 1. Win8 ready (where we also prefer the native backlight driver, so
2194 * normally the acpi_video code should not register there anyways); *and*
2195 * 2.1 Report a desktop/server DMI chassis-type, or
2196 * 2.2 Are an ACPI-reduced-hardware platform (and thus won't use the EC for
2197 backlight control)
2198 */
2199static bool should_check_lcd_flag(void)
2200{
2201 if (!acpi_osi_is_win8())
2202 return false;
2203
2204 if (dmi_is_desktop())
2205 return true;
2206
2207 if (acpi_reduced_hardware())
2208 return true;
2209
2210 return false;
2211}
2212
Rafael J. Wysocki8e5c2b72013-07-25 21:43:39 +02002213int acpi_video_register(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002214{
Hans de Goede2a8b18e2015-06-16 16:27:54 +02002215 int ret = 0;
Chris Wilson28d63402015-03-01 10:41:38 +00002216
Hans de Goede970530c2016-01-14 09:41:45 +01002217 mutex_lock(&register_count_mutex);
2218 if (register_count) {
Zhao Yakui86e437f2009-06-16 11:23:13 +08002219 /*
Rafael J. Wysocki8e5c2b72013-07-25 21:43:39 +02002220 * if the function of acpi_video_register is already called,
Kacper PiwiƄskicbf6d032019-12-11 10:37:28 +01002221 * don't register the acpi_video_bus again and return no error.
Zhao Yakui86e437f2009-06-16 11:23:13 +08002222 */
Hans de Goede2a8b18e2015-06-16 16:27:54 +02002223 goto leave;
Zhao Yakui86e437f2009-06-16 11:23:13 +08002224 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002225
Hans de Goede81cc7e92021-04-06 23:16:53 +02002226 if (only_lcd == -1)
2227 only_lcd = should_check_lcd_flag();
Hans de Goede5928c282017-12-23 19:41:47 +01002228
Hans de Goede7ee33ba2015-06-16 16:27:53 +02002229 dmi_check_system(video_dmi_table);
2230
Chris Wilson28d63402015-03-01 10:41:38 +00002231 ret = acpi_bus_register_driver(&acpi_video_bus);
2232 if (ret)
Hans de Goede2a8b18e2015-06-16 16:27:54 +02002233 goto leave;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002234
Zhao Yakui86e437f2009-06-16 11:23:13 +08002235 /*
2236 * When the acpi_video_bus is loaded successfully, increase
2237 * the counter reference.
2238 */
Hans de Goede970530c2016-01-14 09:41:45 +01002239 register_count = 1;
Zhao Yakui86e437f2009-06-16 11:23:13 +08002240
Hans de Goede2a8b18e2015-06-16 16:27:54 +02002241leave:
Hans de Goede970530c2016-01-14 09:41:45 +01002242 mutex_unlock(&register_count_mutex);
Hans de Goede2a8b18e2015-06-16 16:27:54 +02002243 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002244}
Rafael J. Wysocki8e5c2b72013-07-25 21:43:39 +02002245EXPORT_SYMBOL(acpi_video_register);
Matthew Garrett74a365b2009-03-19 21:35:39 +00002246
Zhao Yakui86e437f2009-06-16 11:23:13 +08002247void acpi_video_unregister(void)
2248{
Hans de Goede970530c2016-01-14 09:41:45 +01002249 mutex_lock(&register_count_mutex);
2250 if (register_count) {
Hans de Goede2a8b18e2015-06-16 16:27:54 +02002251 acpi_bus_unregister_driver(&acpi_video_bus);
Hans de Goede970530c2016-01-14 09:41:45 +01002252 register_count = 0;
Zhao Yakui86e437f2009-06-16 11:23:13 +08002253 }
Hans de Goede970530c2016-01-14 09:41:45 +01002254 mutex_unlock(&register_count_mutex);
Zhao Yakui86e437f2009-06-16 11:23:13 +08002255}
2256EXPORT_SYMBOL(acpi_video_unregister);
2257
Hans de Goede1b7f37e2014-05-17 10:48:01 +02002258void acpi_video_unregister_backlight(void)
2259{
2260 struct acpi_video_bus *video;
2261
Hans de Goede970530c2016-01-14 09:41:45 +01002262 mutex_lock(&register_count_mutex);
2263 if (register_count) {
Hans de Goede2a8b18e2015-06-16 16:27:54 +02002264 mutex_lock(&video_list_lock);
2265 list_for_each_entry(video, &video_bus_head, entry)
2266 acpi_video_bus_unregister_backlight(video);
2267 mutex_unlock(&video_list_lock);
2268 }
Hans de Goede970530c2016-01-14 09:41:45 +01002269 mutex_unlock(&register_count_mutex);
Hans de Goede1b7f37e2014-05-17 10:48:01 +02002270}
Hans de Goede1b7f37e2014-05-17 10:48:01 +02002271
Hans de Goede90b066b2015-12-22 19:09:48 +01002272bool acpi_video_handles_brightness_key_presses(void)
2273{
2274 bool have_video_busses;
2275
2276 mutex_lock(&video_list_lock);
2277 have_video_busses = !list_empty(&video_bus_head);
2278 mutex_unlock(&video_list_lock);
2279
Hans de Goede05bc59a2015-12-22 19:09:51 +01002280 return have_video_busses &&
2281 (report_key_events & REPORT_BRIGHTNESS_KEY_EVENTS);
Hans de Goede90b066b2015-12-22 19:09:48 +01002282}
2283EXPORT_SYMBOL(acpi_video_handles_brightness_key_presses);
2284
Matthew Garrett74a365b2009-03-19 21:35:39 +00002285/*
2286 * This is kind of nasty. Hardware using Intel chipsets may require
2287 * the video opregion code to be run first in order to initialise
2288 * state before any ACPI video calls are made. To handle this we defer
2289 * registration of the video class until the opregion code has run.
2290 */
2291
2292static int __init acpi_video_init(void)
2293{
Chris Wilson6e17cb12015-03-01 10:41:37 +00002294 /*
2295 * Let the module load even if ACPI is disabled (e.g. due to
2296 * a broken BIOS) so that i915.ko can still be loaded on such
2297 * old systems without an AcpiOpRegion.
2298 *
2299 * acpi_video_register() will report -ENODEV later as well due
2300 * to acpi_disabled when i915.ko tries to register itself afterwards.
2301 */
2302 if (acpi_disabled)
2303 return 0;
2304
Matthew Garrett74a365b2009-03-19 21:35:39 +00002305 if (intel_opregion_present())
2306 return 0;
2307
2308 return acpi_video_register();
2309}
Linus Torvalds1da177e2005-04-16 15:20:36 -07002310
Zhao Yakui86e437f2009-06-16 11:23:13 +08002311static void __exit acpi_video_exit(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002312{
Hans de Goede93a291d2015-06-16 16:27:52 +02002313 acpi_video_detect_exit();
Zhao Yakui86e437f2009-06-16 11:23:13 +08002314 acpi_video_unregister();
Linus Torvalds1da177e2005-04-16 15:20:36 -07002315}
Linus Torvalds1da177e2005-04-16 15:20:36 -07002316
2317module_init(acpi_video_init);
2318module_exit(acpi_video_exit);