1*4882a593Smuzhiyun /*
2*4882a593Smuzhiyun * Copyright (C) 2015 Red Hat Inc.
3*4882a593Smuzhiyun * Hans de Goede <hdegoede@redhat.com>
4*4882a593Smuzhiyun * Copyright (C) 2008 SuSE Linux Products GmbH
5*4882a593Smuzhiyun * Thomas Renninger <trenn@suse.de>
6*4882a593Smuzhiyun *
7*4882a593Smuzhiyun * May be copied or modified under the terms of the GNU General Public License
8*4882a593Smuzhiyun *
9*4882a593Smuzhiyun * video_detect.c:
10*4882a593Smuzhiyun * After PCI devices are glued with ACPI devices
11*4882a593Smuzhiyun * acpi_get_pci_dev() can be called to identify ACPI graphics
12*4882a593Smuzhiyun * devices for which a real graphics card is plugged in
13*4882a593Smuzhiyun *
14*4882a593Smuzhiyun * Depending on whether ACPI graphics extensions (cmp. ACPI spec Appendix B)
15*4882a593Smuzhiyun * are available, video.ko should be used to handle the device.
16*4882a593Smuzhiyun *
17*4882a593Smuzhiyun * Otherwise vendor specific drivers like thinkpad_acpi, asus-laptop,
18*4882a593Smuzhiyun * sony_acpi,... can take care about backlight brightness.
19*4882a593Smuzhiyun *
20*4882a593Smuzhiyun * Backlight drivers can use acpi_video_get_backlight_type() to determine
21*4882a593Smuzhiyun * which driver should handle the backlight.
22*4882a593Smuzhiyun *
23*4882a593Smuzhiyun * If CONFIG_ACPI_VIDEO is neither set as "compiled in" (y) nor as a module (m)
24*4882a593Smuzhiyun * this file will not be compiled and acpi_video_get_backlight_type() will
25*4882a593Smuzhiyun * always return acpi_backlight_vendor.
26*4882a593Smuzhiyun */
27*4882a593Smuzhiyun
28*4882a593Smuzhiyun #include <linux/export.h>
29*4882a593Smuzhiyun #include <linux/acpi.h>
30*4882a593Smuzhiyun #include <linux/backlight.h>
31*4882a593Smuzhiyun #include <linux/dmi.h>
32*4882a593Smuzhiyun #include <linux/module.h>
33*4882a593Smuzhiyun #include <linux/pci.h>
34*4882a593Smuzhiyun #include <linux/types.h>
35*4882a593Smuzhiyun #include <linux/workqueue.h>
36*4882a593Smuzhiyun #include <acpi/video.h>
37*4882a593Smuzhiyun
38*4882a593Smuzhiyun void acpi_video_unregister_backlight(void);
39*4882a593Smuzhiyun
40*4882a593Smuzhiyun static bool backlight_notifier_registered;
41*4882a593Smuzhiyun static struct notifier_block backlight_nb;
42*4882a593Smuzhiyun static struct work_struct backlight_notify_work;
43*4882a593Smuzhiyun
44*4882a593Smuzhiyun static enum acpi_backlight_type acpi_backlight_cmdline = acpi_backlight_undef;
45*4882a593Smuzhiyun static enum acpi_backlight_type acpi_backlight_dmi = acpi_backlight_undef;
46*4882a593Smuzhiyun
acpi_video_parse_cmdline(void)47*4882a593Smuzhiyun static void acpi_video_parse_cmdline(void)
48*4882a593Smuzhiyun {
49*4882a593Smuzhiyun if (!strcmp("vendor", acpi_video_backlight_string))
50*4882a593Smuzhiyun acpi_backlight_cmdline = acpi_backlight_vendor;
51*4882a593Smuzhiyun if (!strcmp("video", acpi_video_backlight_string))
52*4882a593Smuzhiyun acpi_backlight_cmdline = acpi_backlight_video;
53*4882a593Smuzhiyun if (!strcmp("native", acpi_video_backlight_string))
54*4882a593Smuzhiyun acpi_backlight_cmdline = acpi_backlight_native;
55*4882a593Smuzhiyun if (!strcmp("none", acpi_video_backlight_string))
56*4882a593Smuzhiyun acpi_backlight_cmdline = acpi_backlight_none;
57*4882a593Smuzhiyun }
58*4882a593Smuzhiyun
59*4882a593Smuzhiyun static acpi_status
find_video(acpi_handle handle,u32 lvl,void * context,void ** rv)60*4882a593Smuzhiyun find_video(acpi_handle handle, u32 lvl, void *context, void **rv)
61*4882a593Smuzhiyun {
62*4882a593Smuzhiyun long *cap = context;
63*4882a593Smuzhiyun struct pci_dev *dev;
64*4882a593Smuzhiyun struct acpi_device *acpi_dev;
65*4882a593Smuzhiyun
66*4882a593Smuzhiyun static const struct acpi_device_id video_ids[] = {
67*4882a593Smuzhiyun {ACPI_VIDEO_HID, 0},
68*4882a593Smuzhiyun {"", 0},
69*4882a593Smuzhiyun };
70*4882a593Smuzhiyun if (acpi_bus_get_device(handle, &acpi_dev))
71*4882a593Smuzhiyun return AE_OK;
72*4882a593Smuzhiyun
73*4882a593Smuzhiyun if (!acpi_match_device_ids(acpi_dev, video_ids)) {
74*4882a593Smuzhiyun dev = acpi_get_pci_dev(handle);
75*4882a593Smuzhiyun if (!dev)
76*4882a593Smuzhiyun return AE_OK;
77*4882a593Smuzhiyun pci_dev_put(dev);
78*4882a593Smuzhiyun *cap |= acpi_is_video_device(handle);
79*4882a593Smuzhiyun }
80*4882a593Smuzhiyun return AE_OK;
81*4882a593Smuzhiyun }
82*4882a593Smuzhiyun
83*4882a593Smuzhiyun /* Force to use vendor driver when the ACPI device is known to be
84*4882a593Smuzhiyun * buggy */
video_detect_force_vendor(const struct dmi_system_id * d)85*4882a593Smuzhiyun static int video_detect_force_vendor(const struct dmi_system_id *d)
86*4882a593Smuzhiyun {
87*4882a593Smuzhiyun acpi_backlight_dmi = acpi_backlight_vendor;
88*4882a593Smuzhiyun return 0;
89*4882a593Smuzhiyun }
90*4882a593Smuzhiyun
video_detect_force_video(const struct dmi_system_id * d)91*4882a593Smuzhiyun static int video_detect_force_video(const struct dmi_system_id *d)
92*4882a593Smuzhiyun {
93*4882a593Smuzhiyun acpi_backlight_dmi = acpi_backlight_video;
94*4882a593Smuzhiyun return 0;
95*4882a593Smuzhiyun }
96*4882a593Smuzhiyun
video_detect_force_native(const struct dmi_system_id * d)97*4882a593Smuzhiyun static int video_detect_force_native(const struct dmi_system_id *d)
98*4882a593Smuzhiyun {
99*4882a593Smuzhiyun acpi_backlight_dmi = acpi_backlight_native;
100*4882a593Smuzhiyun return 0;
101*4882a593Smuzhiyun }
102*4882a593Smuzhiyun
video_detect_force_none(const struct dmi_system_id * d)103*4882a593Smuzhiyun static int video_detect_force_none(const struct dmi_system_id *d)
104*4882a593Smuzhiyun {
105*4882a593Smuzhiyun acpi_backlight_dmi = acpi_backlight_none;
106*4882a593Smuzhiyun return 0;
107*4882a593Smuzhiyun }
108*4882a593Smuzhiyun
109*4882a593Smuzhiyun static const struct dmi_system_id video_detect_dmi_table[] = {
110*4882a593Smuzhiyun /* On Samsung X360, the BIOS will set a flag (VDRV) if generic
111*4882a593Smuzhiyun * ACPI backlight device is used. This flag will definitively break
112*4882a593Smuzhiyun * the backlight interface (even the vendor interface) until next
113*4882a593Smuzhiyun * reboot. It's why we should prevent video.ko from being used here
114*4882a593Smuzhiyun * and we can't rely on a later call to acpi_video_unregister().
115*4882a593Smuzhiyun */
116*4882a593Smuzhiyun {
117*4882a593Smuzhiyun .callback = video_detect_force_vendor,
118*4882a593Smuzhiyun .ident = "X360",
119*4882a593Smuzhiyun .matches = {
120*4882a593Smuzhiyun DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."),
121*4882a593Smuzhiyun DMI_MATCH(DMI_PRODUCT_NAME, "X360"),
122*4882a593Smuzhiyun DMI_MATCH(DMI_BOARD_NAME, "X360"),
123*4882a593Smuzhiyun },
124*4882a593Smuzhiyun },
125*4882a593Smuzhiyun {
126*4882a593Smuzhiyun .callback = video_detect_force_vendor,
127*4882a593Smuzhiyun .ident = "Asus UL30VT",
128*4882a593Smuzhiyun .matches = {
129*4882a593Smuzhiyun DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK Computer Inc."),
130*4882a593Smuzhiyun DMI_MATCH(DMI_PRODUCT_NAME, "UL30VT"),
131*4882a593Smuzhiyun },
132*4882a593Smuzhiyun },
133*4882a593Smuzhiyun {
134*4882a593Smuzhiyun .callback = video_detect_force_vendor,
135*4882a593Smuzhiyun .ident = "Asus UL30A",
136*4882a593Smuzhiyun .matches = {
137*4882a593Smuzhiyun DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK Computer Inc."),
138*4882a593Smuzhiyun DMI_MATCH(DMI_PRODUCT_NAME, "UL30A"),
139*4882a593Smuzhiyun },
140*4882a593Smuzhiyun },
141*4882a593Smuzhiyun {
142*4882a593Smuzhiyun .callback = video_detect_force_vendor,
143*4882a593Smuzhiyun .ident = "GIGABYTE GB-BXBT-2807",
144*4882a593Smuzhiyun .matches = {
145*4882a593Smuzhiyun DMI_MATCH(DMI_SYS_VENDOR, "GIGABYTE"),
146*4882a593Smuzhiyun DMI_MATCH(DMI_PRODUCT_NAME, "GB-BXBT-2807"),
147*4882a593Smuzhiyun },
148*4882a593Smuzhiyun },
149*4882a593Smuzhiyun {
150*4882a593Smuzhiyun .callback = video_detect_force_vendor,
151*4882a593Smuzhiyun .ident = "Sony VPCEH3U1E",
152*4882a593Smuzhiyun .matches = {
153*4882a593Smuzhiyun DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"),
154*4882a593Smuzhiyun DMI_MATCH(DMI_PRODUCT_NAME, "VPCEH3U1E"),
155*4882a593Smuzhiyun },
156*4882a593Smuzhiyun },
157*4882a593Smuzhiyun
158*4882a593Smuzhiyun /*
159*4882a593Smuzhiyun * These models have a working acpi_video backlight control, and using
160*4882a593Smuzhiyun * native backlight causes a regression where backlight does not work
161*4882a593Smuzhiyun * when userspace is not handling brightness key events. Disable
162*4882a593Smuzhiyun * native_backlight on these to fix this:
163*4882a593Smuzhiyun * https://bugzilla.kernel.org/show_bug.cgi?id=81691
164*4882a593Smuzhiyun */
165*4882a593Smuzhiyun {
166*4882a593Smuzhiyun .callback = video_detect_force_video,
167*4882a593Smuzhiyun .ident = "ThinkPad T420",
168*4882a593Smuzhiyun .matches = {
169*4882a593Smuzhiyun DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
170*4882a593Smuzhiyun DMI_MATCH(DMI_PRODUCT_VERSION, "ThinkPad T420"),
171*4882a593Smuzhiyun },
172*4882a593Smuzhiyun },
173*4882a593Smuzhiyun {
174*4882a593Smuzhiyun .callback = video_detect_force_video,
175*4882a593Smuzhiyun .ident = "ThinkPad T520",
176*4882a593Smuzhiyun .matches = {
177*4882a593Smuzhiyun DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
178*4882a593Smuzhiyun DMI_MATCH(DMI_PRODUCT_VERSION, "ThinkPad T520"),
179*4882a593Smuzhiyun },
180*4882a593Smuzhiyun },
181*4882a593Smuzhiyun {
182*4882a593Smuzhiyun .callback = video_detect_force_video,
183*4882a593Smuzhiyun .ident = "ThinkPad X201s",
184*4882a593Smuzhiyun .matches = {
185*4882a593Smuzhiyun DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
186*4882a593Smuzhiyun DMI_MATCH(DMI_PRODUCT_VERSION, "ThinkPad X201s"),
187*4882a593Smuzhiyun },
188*4882a593Smuzhiyun },
189*4882a593Smuzhiyun {
190*4882a593Smuzhiyun .callback = video_detect_force_video,
191*4882a593Smuzhiyun .ident = "ThinkPad X201T",
192*4882a593Smuzhiyun .matches = {
193*4882a593Smuzhiyun DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
194*4882a593Smuzhiyun DMI_MATCH(DMI_PRODUCT_VERSION, "ThinkPad X201T"),
195*4882a593Smuzhiyun },
196*4882a593Smuzhiyun },
197*4882a593Smuzhiyun
198*4882a593Smuzhiyun /* The native backlight controls do not work on some older machines */
199*4882a593Smuzhiyun {
200*4882a593Smuzhiyun /* https://bugs.freedesktop.org/show_bug.cgi?id=81515 */
201*4882a593Smuzhiyun .callback = video_detect_force_video,
202*4882a593Smuzhiyun .ident = "HP ENVY 15 Notebook",
203*4882a593Smuzhiyun .matches = {
204*4882a593Smuzhiyun DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"),
205*4882a593Smuzhiyun DMI_MATCH(DMI_PRODUCT_NAME, "HP ENVY 15 Notebook PC"),
206*4882a593Smuzhiyun },
207*4882a593Smuzhiyun },
208*4882a593Smuzhiyun {
209*4882a593Smuzhiyun .callback = video_detect_force_video,
210*4882a593Smuzhiyun .ident = "SAMSUNG 870Z5E/880Z5E/680Z5E",
211*4882a593Smuzhiyun .matches = {
212*4882a593Smuzhiyun DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."),
213*4882a593Smuzhiyun DMI_MATCH(DMI_PRODUCT_NAME, "870Z5E/880Z5E/680Z5E"),
214*4882a593Smuzhiyun },
215*4882a593Smuzhiyun },
216*4882a593Smuzhiyun {
217*4882a593Smuzhiyun .callback = video_detect_force_video,
218*4882a593Smuzhiyun .ident = "SAMSUNG 370R4E/370R4V/370R5E/3570RE/370R5V",
219*4882a593Smuzhiyun .matches = {
220*4882a593Smuzhiyun DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."),
221*4882a593Smuzhiyun DMI_MATCH(DMI_PRODUCT_NAME,
222*4882a593Smuzhiyun "370R4E/370R4V/370R5E/3570RE/370R5V"),
223*4882a593Smuzhiyun },
224*4882a593Smuzhiyun },
225*4882a593Smuzhiyun {
226*4882a593Smuzhiyun /* https://bugzilla.redhat.com/show_bug.cgi?id=1186097 */
227*4882a593Smuzhiyun .callback = video_detect_force_video,
228*4882a593Smuzhiyun .ident = "SAMSUNG 3570R/370R/470R/450R/510R/4450RV",
229*4882a593Smuzhiyun .matches = {
230*4882a593Smuzhiyun DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."),
231*4882a593Smuzhiyun DMI_MATCH(DMI_PRODUCT_NAME,
232*4882a593Smuzhiyun "3570R/370R/470R/450R/510R/4450RV"),
233*4882a593Smuzhiyun },
234*4882a593Smuzhiyun },
235*4882a593Smuzhiyun {
236*4882a593Smuzhiyun /* https://bugzilla.redhat.com/show_bug.cgi?id=1557060 */
237*4882a593Smuzhiyun .callback = video_detect_force_video,
238*4882a593Smuzhiyun .ident = "SAMSUNG 670Z5E",
239*4882a593Smuzhiyun .matches = {
240*4882a593Smuzhiyun DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."),
241*4882a593Smuzhiyun DMI_MATCH(DMI_PRODUCT_NAME, "670Z5E"),
242*4882a593Smuzhiyun },
243*4882a593Smuzhiyun },
244*4882a593Smuzhiyun {
245*4882a593Smuzhiyun /* https://bugzilla.redhat.com/show_bug.cgi?id=1094948 */
246*4882a593Smuzhiyun .callback = video_detect_force_video,
247*4882a593Smuzhiyun .ident = "SAMSUNG 730U3E/740U3E",
248*4882a593Smuzhiyun .matches = {
249*4882a593Smuzhiyun DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."),
250*4882a593Smuzhiyun DMI_MATCH(DMI_PRODUCT_NAME, "730U3E/740U3E"),
251*4882a593Smuzhiyun },
252*4882a593Smuzhiyun },
253*4882a593Smuzhiyun {
254*4882a593Smuzhiyun /* https://bugs.freedesktop.org/show_bug.cgi?id=87286 */
255*4882a593Smuzhiyun .callback = video_detect_force_video,
256*4882a593Smuzhiyun .ident = "SAMSUNG 900X3C/900X3D/900X3E/900X4C/900X4D",
257*4882a593Smuzhiyun .matches = {
258*4882a593Smuzhiyun DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."),
259*4882a593Smuzhiyun DMI_MATCH(DMI_PRODUCT_NAME,
260*4882a593Smuzhiyun "900X3C/900X3D/900X3E/900X4C/900X4D"),
261*4882a593Smuzhiyun },
262*4882a593Smuzhiyun },
263*4882a593Smuzhiyun {
264*4882a593Smuzhiyun /* https://bugzilla.redhat.com/show_bug.cgi?id=1272633 */
265*4882a593Smuzhiyun .callback = video_detect_force_video,
266*4882a593Smuzhiyun .ident = "Dell XPS14 L421X",
267*4882a593Smuzhiyun .matches = {
268*4882a593Smuzhiyun DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
269*4882a593Smuzhiyun DMI_MATCH(DMI_PRODUCT_NAME, "XPS L421X"),
270*4882a593Smuzhiyun },
271*4882a593Smuzhiyun },
272*4882a593Smuzhiyun {
273*4882a593Smuzhiyun /* https://bugzilla.redhat.com/show_bug.cgi?id=1163574 */
274*4882a593Smuzhiyun .callback = video_detect_force_video,
275*4882a593Smuzhiyun .ident = "Dell XPS15 L521X",
276*4882a593Smuzhiyun .matches = {
277*4882a593Smuzhiyun DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
278*4882a593Smuzhiyun DMI_MATCH(DMI_PRODUCT_NAME, "XPS L521X"),
279*4882a593Smuzhiyun },
280*4882a593Smuzhiyun },
281*4882a593Smuzhiyun {
282*4882a593Smuzhiyun /* https://bugzilla.kernel.org/show_bug.cgi?id=108971 */
283*4882a593Smuzhiyun .callback = video_detect_force_video,
284*4882a593Smuzhiyun .ident = "SAMSUNG 530U4E/540U4E",
285*4882a593Smuzhiyun .matches = {
286*4882a593Smuzhiyun DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."),
287*4882a593Smuzhiyun DMI_MATCH(DMI_PRODUCT_NAME, "530U4E/540U4E"),
288*4882a593Smuzhiyun },
289*4882a593Smuzhiyun },
290*4882a593Smuzhiyun /* https://bugs.launchpad.net/bugs/1894667 */
291*4882a593Smuzhiyun {
292*4882a593Smuzhiyun .callback = video_detect_force_video,
293*4882a593Smuzhiyun .ident = "HP 635 Notebook",
294*4882a593Smuzhiyun .matches = {
295*4882a593Smuzhiyun DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"),
296*4882a593Smuzhiyun DMI_MATCH(DMI_PRODUCT_NAME, "HP 635 Notebook PC"),
297*4882a593Smuzhiyun },
298*4882a593Smuzhiyun },
299*4882a593Smuzhiyun
300*4882a593Smuzhiyun /* Non win8 machines which need native backlight nevertheless */
301*4882a593Smuzhiyun {
302*4882a593Smuzhiyun /* https://bugzilla.redhat.com/show_bug.cgi?id=1201530 */
303*4882a593Smuzhiyun .callback = video_detect_force_native,
304*4882a593Smuzhiyun .ident = "Lenovo Ideapad S405",
305*4882a593Smuzhiyun .matches = {
306*4882a593Smuzhiyun DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
307*4882a593Smuzhiyun DMI_MATCH(DMI_BOARD_NAME, "Lenovo IdeaPad S405"),
308*4882a593Smuzhiyun },
309*4882a593Smuzhiyun },
310*4882a593Smuzhiyun {
311*4882a593Smuzhiyun /* https://bugzilla.redhat.com/show_bug.cgi?id=1187004 */
312*4882a593Smuzhiyun .callback = video_detect_force_native,
313*4882a593Smuzhiyun .ident = "Lenovo Ideapad Z570",
314*4882a593Smuzhiyun .matches = {
315*4882a593Smuzhiyun DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
316*4882a593Smuzhiyun DMI_MATCH(DMI_PRODUCT_NAME, "102434U"),
317*4882a593Smuzhiyun },
318*4882a593Smuzhiyun },
319*4882a593Smuzhiyun {
320*4882a593Smuzhiyun .callback = video_detect_force_native,
321*4882a593Smuzhiyun .ident = "Lenovo E41-25",
322*4882a593Smuzhiyun .matches = {
323*4882a593Smuzhiyun DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
324*4882a593Smuzhiyun DMI_MATCH(DMI_PRODUCT_NAME, "81FS"),
325*4882a593Smuzhiyun },
326*4882a593Smuzhiyun },
327*4882a593Smuzhiyun {
328*4882a593Smuzhiyun .callback = video_detect_force_native,
329*4882a593Smuzhiyun .ident = "Lenovo E41-45",
330*4882a593Smuzhiyun .matches = {
331*4882a593Smuzhiyun DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
332*4882a593Smuzhiyun DMI_MATCH(DMI_PRODUCT_NAME, "82BK"),
333*4882a593Smuzhiyun },
334*4882a593Smuzhiyun },
335*4882a593Smuzhiyun {
336*4882a593Smuzhiyun /* https://bugzilla.redhat.com/show_bug.cgi?id=1217249 */
337*4882a593Smuzhiyun .callback = video_detect_force_native,
338*4882a593Smuzhiyun .ident = "Apple MacBook Pro 12,1",
339*4882a593Smuzhiyun .matches = {
340*4882a593Smuzhiyun DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."),
341*4882a593Smuzhiyun DMI_MATCH(DMI_PRODUCT_NAME, "MacBookPro12,1"),
342*4882a593Smuzhiyun },
343*4882a593Smuzhiyun },
344*4882a593Smuzhiyun {
345*4882a593Smuzhiyun .callback = video_detect_force_native,
346*4882a593Smuzhiyun .ident = "Dell Vostro V131",
347*4882a593Smuzhiyun .matches = {
348*4882a593Smuzhiyun DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
349*4882a593Smuzhiyun DMI_MATCH(DMI_PRODUCT_NAME, "Vostro V131"),
350*4882a593Smuzhiyun },
351*4882a593Smuzhiyun },
352*4882a593Smuzhiyun {
353*4882a593Smuzhiyun /* https://bugzilla.redhat.com/show_bug.cgi?id=1123661 */
354*4882a593Smuzhiyun .callback = video_detect_force_native,
355*4882a593Smuzhiyun .ident = "Dell XPS 17 L702X",
356*4882a593Smuzhiyun .matches = {
357*4882a593Smuzhiyun DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
358*4882a593Smuzhiyun DMI_MATCH(DMI_PRODUCT_NAME, "Dell System XPS L702X"),
359*4882a593Smuzhiyun },
360*4882a593Smuzhiyun },
361*4882a593Smuzhiyun {
362*4882a593Smuzhiyun .callback = video_detect_force_native,
363*4882a593Smuzhiyun .ident = "Dell Precision 7510",
364*4882a593Smuzhiyun .matches = {
365*4882a593Smuzhiyun DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
366*4882a593Smuzhiyun DMI_MATCH(DMI_PRODUCT_NAME, "Precision 7510"),
367*4882a593Smuzhiyun },
368*4882a593Smuzhiyun },
369*4882a593Smuzhiyun {
370*4882a593Smuzhiyun .callback = video_detect_force_native,
371*4882a593Smuzhiyun .ident = "Acer Aspire 5738z",
372*4882a593Smuzhiyun .matches = {
373*4882a593Smuzhiyun DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
374*4882a593Smuzhiyun DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5738"),
375*4882a593Smuzhiyun DMI_MATCH(DMI_BOARD_NAME, "JV50"),
376*4882a593Smuzhiyun },
377*4882a593Smuzhiyun },
378*4882a593Smuzhiyun {
379*4882a593Smuzhiyun /* https://bugzilla.kernel.org/show_bug.cgi?id=207835 */
380*4882a593Smuzhiyun .callback = video_detect_force_native,
381*4882a593Smuzhiyun .ident = "Acer TravelMate 5735Z",
382*4882a593Smuzhiyun .matches = {
383*4882a593Smuzhiyun DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
384*4882a593Smuzhiyun DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 5735Z"),
385*4882a593Smuzhiyun DMI_MATCH(DMI_BOARD_NAME, "BA51_MV"),
386*4882a593Smuzhiyun },
387*4882a593Smuzhiyun },
388*4882a593Smuzhiyun {
389*4882a593Smuzhiyun .callback = video_detect_force_native,
390*4882a593Smuzhiyun .ident = "ASUSTeK COMPUTER INC. GA401",
391*4882a593Smuzhiyun .matches = {
392*4882a593Smuzhiyun DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
393*4882a593Smuzhiyun DMI_MATCH(DMI_PRODUCT_NAME, "GA401"),
394*4882a593Smuzhiyun },
395*4882a593Smuzhiyun },
396*4882a593Smuzhiyun {
397*4882a593Smuzhiyun .callback = video_detect_force_native,
398*4882a593Smuzhiyun .ident = "ASUSTeK COMPUTER INC. GA502",
399*4882a593Smuzhiyun .matches = {
400*4882a593Smuzhiyun DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
401*4882a593Smuzhiyun DMI_MATCH(DMI_PRODUCT_NAME, "GA502"),
402*4882a593Smuzhiyun },
403*4882a593Smuzhiyun },
404*4882a593Smuzhiyun {
405*4882a593Smuzhiyun .callback = video_detect_force_native,
406*4882a593Smuzhiyun .ident = "ASUSTeK COMPUTER INC. GA503",
407*4882a593Smuzhiyun .matches = {
408*4882a593Smuzhiyun DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
409*4882a593Smuzhiyun DMI_MATCH(DMI_PRODUCT_NAME, "GA503"),
410*4882a593Smuzhiyun },
411*4882a593Smuzhiyun },
412*4882a593Smuzhiyun /*
413*4882a593Smuzhiyun * Clevo NL5xRU and NL5xNU/TUXEDO Aura 15 Gen1 and Gen2 have both a
414*4882a593Smuzhiyun * working native and video interface. However the default detection
415*4882a593Smuzhiyun * mechanism first registers the video interface before unregistering
416*4882a593Smuzhiyun * it again and switching to the native interface during boot. This
417*4882a593Smuzhiyun * results in a dangling SBIOS request for backlight change for some
418*4882a593Smuzhiyun * reason, causing the backlight to switch to ~2% once per boot on the
419*4882a593Smuzhiyun * first power cord connect or disconnect event. Setting the native
420*4882a593Smuzhiyun * interface explicitly circumvents this buggy behaviour, by avoiding
421*4882a593Smuzhiyun * the unregistering process.
422*4882a593Smuzhiyun */
423*4882a593Smuzhiyun {
424*4882a593Smuzhiyun .callback = video_detect_force_native,
425*4882a593Smuzhiyun .ident = "Clevo NL5xRU",
426*4882a593Smuzhiyun .matches = {
427*4882a593Smuzhiyun DMI_MATCH(DMI_BOARD_NAME, "NL5xRU"),
428*4882a593Smuzhiyun },
429*4882a593Smuzhiyun },
430*4882a593Smuzhiyun {
431*4882a593Smuzhiyun .callback = video_detect_force_native,
432*4882a593Smuzhiyun .ident = "Clevo NL5xRU",
433*4882a593Smuzhiyun .matches = {
434*4882a593Smuzhiyun DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
435*4882a593Smuzhiyun DMI_MATCH(DMI_BOARD_NAME, "AURA1501"),
436*4882a593Smuzhiyun },
437*4882a593Smuzhiyun },
438*4882a593Smuzhiyun {
439*4882a593Smuzhiyun .callback = video_detect_force_native,
440*4882a593Smuzhiyun .ident = "Clevo NL5xRU",
441*4882a593Smuzhiyun .matches = {
442*4882a593Smuzhiyun DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
443*4882a593Smuzhiyun DMI_MATCH(DMI_BOARD_NAME, "EDUBOOK1502"),
444*4882a593Smuzhiyun },
445*4882a593Smuzhiyun },
446*4882a593Smuzhiyun {
447*4882a593Smuzhiyun .callback = video_detect_force_native,
448*4882a593Smuzhiyun .ident = "Clevo NL5xNU",
449*4882a593Smuzhiyun .matches = {
450*4882a593Smuzhiyun DMI_MATCH(DMI_BOARD_NAME, "NL5xNU"),
451*4882a593Smuzhiyun },
452*4882a593Smuzhiyun },
453*4882a593Smuzhiyun /*
454*4882a593Smuzhiyun * The TongFang PF5PU1G, PF4NU1F, PF5NU1G, and PF5LUXG/TUXEDO BA15 Gen10,
455*4882a593Smuzhiyun * Pulse 14/15 Gen1, and Pulse 15 Gen2 have the same problem as the Clevo
456*4882a593Smuzhiyun * NL5xRU and NL5xNU/TUXEDO Aura 15 Gen1 and Gen2. See the description
457*4882a593Smuzhiyun * above.
458*4882a593Smuzhiyun */
459*4882a593Smuzhiyun {
460*4882a593Smuzhiyun .callback = video_detect_force_native,
461*4882a593Smuzhiyun .ident = "TongFang PF5PU1G",
462*4882a593Smuzhiyun .matches = {
463*4882a593Smuzhiyun DMI_MATCH(DMI_BOARD_NAME, "PF5PU1G"),
464*4882a593Smuzhiyun },
465*4882a593Smuzhiyun },
466*4882a593Smuzhiyun {
467*4882a593Smuzhiyun .callback = video_detect_force_native,
468*4882a593Smuzhiyun .ident = "TongFang PF4NU1F",
469*4882a593Smuzhiyun .matches = {
470*4882a593Smuzhiyun DMI_MATCH(DMI_BOARD_NAME, "PF4NU1F"),
471*4882a593Smuzhiyun },
472*4882a593Smuzhiyun },
473*4882a593Smuzhiyun {
474*4882a593Smuzhiyun .callback = video_detect_force_native,
475*4882a593Smuzhiyun .ident = "TongFang PF4NU1F",
476*4882a593Smuzhiyun .matches = {
477*4882a593Smuzhiyun DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
478*4882a593Smuzhiyun DMI_MATCH(DMI_BOARD_NAME, "PULSE1401"),
479*4882a593Smuzhiyun },
480*4882a593Smuzhiyun },
481*4882a593Smuzhiyun {
482*4882a593Smuzhiyun .callback = video_detect_force_native,
483*4882a593Smuzhiyun .ident = "TongFang PF5NU1G",
484*4882a593Smuzhiyun .matches = {
485*4882a593Smuzhiyun DMI_MATCH(DMI_BOARD_NAME, "PF5NU1G"),
486*4882a593Smuzhiyun },
487*4882a593Smuzhiyun },
488*4882a593Smuzhiyun {
489*4882a593Smuzhiyun .callback = video_detect_force_native,
490*4882a593Smuzhiyun .ident = "TongFang PF5NU1G",
491*4882a593Smuzhiyun .matches = {
492*4882a593Smuzhiyun DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
493*4882a593Smuzhiyun DMI_MATCH(DMI_BOARD_NAME, "PULSE1501"),
494*4882a593Smuzhiyun },
495*4882a593Smuzhiyun },
496*4882a593Smuzhiyun {
497*4882a593Smuzhiyun .callback = video_detect_force_native,
498*4882a593Smuzhiyun .ident = "TongFang PF5LUXG",
499*4882a593Smuzhiyun .matches = {
500*4882a593Smuzhiyun DMI_MATCH(DMI_BOARD_NAME, "PF5LUXG"),
501*4882a593Smuzhiyun },
502*4882a593Smuzhiyun },
503*4882a593Smuzhiyun /*
504*4882a593Smuzhiyun * More Tongfang devices with the same issue as the Clevo NL5xRU and
505*4882a593Smuzhiyun * NL5xNU/TUXEDO Aura 15 Gen1 and Gen2. See the description above.
506*4882a593Smuzhiyun */
507*4882a593Smuzhiyun {
508*4882a593Smuzhiyun .callback = video_detect_force_native,
509*4882a593Smuzhiyun .ident = "TongFang GKxNRxx",
510*4882a593Smuzhiyun .matches = {
511*4882a593Smuzhiyun DMI_MATCH(DMI_BOARD_NAME, "GKxNRxx"),
512*4882a593Smuzhiyun },
513*4882a593Smuzhiyun },
514*4882a593Smuzhiyun {
515*4882a593Smuzhiyun .callback = video_detect_force_native,
516*4882a593Smuzhiyun .ident = "TongFang GKxNRxx",
517*4882a593Smuzhiyun .matches = {
518*4882a593Smuzhiyun DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
519*4882a593Smuzhiyun DMI_MATCH(DMI_BOARD_NAME, "POLARIS1501A1650TI"),
520*4882a593Smuzhiyun },
521*4882a593Smuzhiyun },
522*4882a593Smuzhiyun {
523*4882a593Smuzhiyun .callback = video_detect_force_native,
524*4882a593Smuzhiyun .ident = "TongFang GKxNRxx",
525*4882a593Smuzhiyun .matches = {
526*4882a593Smuzhiyun DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
527*4882a593Smuzhiyun DMI_MATCH(DMI_BOARD_NAME, "POLARIS1501A2060"),
528*4882a593Smuzhiyun },
529*4882a593Smuzhiyun },
530*4882a593Smuzhiyun {
531*4882a593Smuzhiyun .callback = video_detect_force_native,
532*4882a593Smuzhiyun .ident = "TongFang GKxNRxx",
533*4882a593Smuzhiyun .matches = {
534*4882a593Smuzhiyun DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
535*4882a593Smuzhiyun DMI_MATCH(DMI_BOARD_NAME, "POLARIS1701A1650TI"),
536*4882a593Smuzhiyun },
537*4882a593Smuzhiyun },
538*4882a593Smuzhiyun {
539*4882a593Smuzhiyun .callback = video_detect_force_native,
540*4882a593Smuzhiyun .ident = "TongFang GKxNRxx",
541*4882a593Smuzhiyun .matches = {
542*4882a593Smuzhiyun DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
543*4882a593Smuzhiyun DMI_MATCH(DMI_BOARD_NAME, "POLARIS1701A2060"),
544*4882a593Smuzhiyun },
545*4882a593Smuzhiyun },
546*4882a593Smuzhiyun {
547*4882a593Smuzhiyun .callback = video_detect_force_native,
548*4882a593Smuzhiyun .ident = "TongFang GMxNGxx",
549*4882a593Smuzhiyun .matches = {
550*4882a593Smuzhiyun DMI_MATCH(DMI_BOARD_NAME, "GMxNGxx"),
551*4882a593Smuzhiyun },
552*4882a593Smuzhiyun },
553*4882a593Smuzhiyun {
554*4882a593Smuzhiyun .callback = video_detect_force_native,
555*4882a593Smuzhiyun .ident = "TongFang GMxZGxx",
556*4882a593Smuzhiyun .matches = {
557*4882a593Smuzhiyun DMI_MATCH(DMI_BOARD_NAME, "GMxZGxx"),
558*4882a593Smuzhiyun },
559*4882a593Smuzhiyun },
560*4882a593Smuzhiyun {
561*4882a593Smuzhiyun .callback = video_detect_force_native,
562*4882a593Smuzhiyun .ident = "TongFang GMxRGxx",
563*4882a593Smuzhiyun .matches = {
564*4882a593Smuzhiyun DMI_MATCH(DMI_BOARD_NAME, "GMxRGxx"),
565*4882a593Smuzhiyun },
566*4882a593Smuzhiyun },
567*4882a593Smuzhiyun /*
568*4882a593Smuzhiyun * Desktops which falsely report a backlight and which our heuristics
569*4882a593Smuzhiyun * for this do not catch.
570*4882a593Smuzhiyun */
571*4882a593Smuzhiyun {
572*4882a593Smuzhiyun .callback = video_detect_force_none,
573*4882a593Smuzhiyun .ident = "Dell OptiPlex 9020M",
574*4882a593Smuzhiyun .matches = {
575*4882a593Smuzhiyun DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
576*4882a593Smuzhiyun DMI_MATCH(DMI_PRODUCT_NAME, "OptiPlex 9020M"),
577*4882a593Smuzhiyun },
578*4882a593Smuzhiyun },
579*4882a593Smuzhiyun {
580*4882a593Smuzhiyun .callback = video_detect_force_none,
581*4882a593Smuzhiyun .ident = "MSI MS-7721",
582*4882a593Smuzhiyun .matches = {
583*4882a593Smuzhiyun DMI_MATCH(DMI_SYS_VENDOR, "MSI"),
584*4882a593Smuzhiyun DMI_MATCH(DMI_PRODUCT_NAME, "MS-7721"),
585*4882a593Smuzhiyun },
586*4882a593Smuzhiyun },
587*4882a593Smuzhiyun { },
588*4882a593Smuzhiyun };
589*4882a593Smuzhiyun
590*4882a593Smuzhiyun /* This uses a workqueue to avoid various locking ordering issues */
acpi_video_backlight_notify_work(struct work_struct * work)591*4882a593Smuzhiyun static void acpi_video_backlight_notify_work(struct work_struct *work)
592*4882a593Smuzhiyun {
593*4882a593Smuzhiyun if (acpi_video_get_backlight_type() != acpi_backlight_video)
594*4882a593Smuzhiyun acpi_video_unregister_backlight();
595*4882a593Smuzhiyun }
596*4882a593Smuzhiyun
acpi_video_backlight_notify(struct notifier_block * nb,unsigned long val,void * bd)597*4882a593Smuzhiyun static int acpi_video_backlight_notify(struct notifier_block *nb,
598*4882a593Smuzhiyun unsigned long val, void *bd)
599*4882a593Smuzhiyun {
600*4882a593Smuzhiyun struct backlight_device *backlight = bd;
601*4882a593Smuzhiyun
602*4882a593Smuzhiyun /* A raw bl registering may change video -> native */
603*4882a593Smuzhiyun if (backlight->props.type == BACKLIGHT_RAW &&
604*4882a593Smuzhiyun val == BACKLIGHT_REGISTERED)
605*4882a593Smuzhiyun schedule_work(&backlight_notify_work);
606*4882a593Smuzhiyun
607*4882a593Smuzhiyun return NOTIFY_OK;
608*4882a593Smuzhiyun }
609*4882a593Smuzhiyun
610*4882a593Smuzhiyun /*
611*4882a593Smuzhiyun * Determine which type of backlight interface to use on this system,
612*4882a593Smuzhiyun * First check cmdline, then dmi quirks, then do autodetect.
613*4882a593Smuzhiyun *
614*4882a593Smuzhiyun * The autodetect order is:
615*4882a593Smuzhiyun * 1) Is the acpi-video backlight interface supported ->
616*4882a593Smuzhiyun * no, use a vendor interface
617*4882a593Smuzhiyun * 2) Is this a win8 "ready" BIOS and do we have a native interface ->
618*4882a593Smuzhiyun * yes, use a native interface
619*4882a593Smuzhiyun * 3) Else use the acpi-video interface
620*4882a593Smuzhiyun *
621*4882a593Smuzhiyun * Arguably the native on win8 check should be done first, but that would
622*4882a593Smuzhiyun * be a behavior change, which may causes issues.
623*4882a593Smuzhiyun */
acpi_video_get_backlight_type(void)624*4882a593Smuzhiyun enum acpi_backlight_type acpi_video_get_backlight_type(void)
625*4882a593Smuzhiyun {
626*4882a593Smuzhiyun static DEFINE_MUTEX(init_mutex);
627*4882a593Smuzhiyun static bool init_done;
628*4882a593Smuzhiyun static long video_caps;
629*4882a593Smuzhiyun
630*4882a593Smuzhiyun /* Parse cmdline, dmi and acpi only once */
631*4882a593Smuzhiyun mutex_lock(&init_mutex);
632*4882a593Smuzhiyun if (!init_done) {
633*4882a593Smuzhiyun acpi_video_parse_cmdline();
634*4882a593Smuzhiyun dmi_check_system(video_detect_dmi_table);
635*4882a593Smuzhiyun acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT,
636*4882a593Smuzhiyun ACPI_UINT32_MAX, find_video, NULL,
637*4882a593Smuzhiyun &video_caps, NULL);
638*4882a593Smuzhiyun INIT_WORK(&backlight_notify_work,
639*4882a593Smuzhiyun acpi_video_backlight_notify_work);
640*4882a593Smuzhiyun backlight_nb.notifier_call = acpi_video_backlight_notify;
641*4882a593Smuzhiyun backlight_nb.priority = 0;
642*4882a593Smuzhiyun if (backlight_register_notifier(&backlight_nb) == 0)
643*4882a593Smuzhiyun backlight_notifier_registered = true;
644*4882a593Smuzhiyun init_done = true;
645*4882a593Smuzhiyun }
646*4882a593Smuzhiyun mutex_unlock(&init_mutex);
647*4882a593Smuzhiyun
648*4882a593Smuzhiyun if (acpi_backlight_cmdline != acpi_backlight_undef)
649*4882a593Smuzhiyun return acpi_backlight_cmdline;
650*4882a593Smuzhiyun
651*4882a593Smuzhiyun if (acpi_backlight_dmi != acpi_backlight_undef)
652*4882a593Smuzhiyun return acpi_backlight_dmi;
653*4882a593Smuzhiyun
654*4882a593Smuzhiyun if (!(video_caps & ACPI_VIDEO_BACKLIGHT))
655*4882a593Smuzhiyun return acpi_backlight_vendor;
656*4882a593Smuzhiyun
657*4882a593Smuzhiyun if (acpi_osi_is_win8() && backlight_device_get_by_type(BACKLIGHT_RAW))
658*4882a593Smuzhiyun return acpi_backlight_native;
659*4882a593Smuzhiyun
660*4882a593Smuzhiyun return acpi_backlight_video;
661*4882a593Smuzhiyun }
662*4882a593Smuzhiyun EXPORT_SYMBOL(acpi_video_get_backlight_type);
663*4882a593Smuzhiyun
664*4882a593Smuzhiyun /*
665*4882a593Smuzhiyun * Set the preferred backlight interface type based on DMI info.
666*4882a593Smuzhiyun * This function allows DMI blacklists to be implemented by external
667*4882a593Smuzhiyun * platform drivers instead of putting a big blacklist in video_detect.c
668*4882a593Smuzhiyun */
acpi_video_set_dmi_backlight_type(enum acpi_backlight_type type)669*4882a593Smuzhiyun void acpi_video_set_dmi_backlight_type(enum acpi_backlight_type type)
670*4882a593Smuzhiyun {
671*4882a593Smuzhiyun acpi_backlight_dmi = type;
672*4882a593Smuzhiyun /* Remove acpi-video backlight interface if it is no longer desired */
673*4882a593Smuzhiyun if (acpi_video_get_backlight_type() != acpi_backlight_video)
674*4882a593Smuzhiyun acpi_video_unregister_backlight();
675*4882a593Smuzhiyun }
676*4882a593Smuzhiyun EXPORT_SYMBOL(acpi_video_set_dmi_backlight_type);
677*4882a593Smuzhiyun
acpi_video_detect_exit(void)678*4882a593Smuzhiyun void __exit acpi_video_detect_exit(void)
679*4882a593Smuzhiyun {
680*4882a593Smuzhiyun if (backlight_notifier_registered)
681*4882a593Smuzhiyun backlight_unregister_notifier(&backlight_nb);
682*4882a593Smuzhiyun }
683