]>
Commit | Line | Data |
---|---|---|
c3d6de69 TR |
1 | /* |
2 | * Copyright (C) 2008 SuSE Linux Products GmbH | |
3 | * Thomas Renninger <trenn@suse.de> | |
4 | * | |
5 | * May be copied or modified under the terms of the GNU General Public License | |
6 | * | |
7 | * video_detect.c: | |
c3d6de69 | 8 | * After PCI devices are glued with ACPI devices |
1e4cffe7 | 9 | * acpi_get_pci_dev() can be called to identify ACPI graphics |
c3d6de69 TR |
10 | * devices for which a real graphics card is plugged in |
11 | * | |
12 | * Now acpi_video_get_capabilities() can be called to check which | |
13 | * capabilities the graphics cards plugged in support. The check for general | |
14 | * video capabilities will be triggered by the first caller of | |
15 | * acpi_video_get_capabilities(NULL); which will happen when the first | |
677bd810 | 16 | * backlight switching supporting driver calls: |
c3d6de69 TR |
17 | * acpi_video_backlight_support(); |
18 | * | |
19 | * Depending on whether ACPI graphics extensions (cmp. ACPI spec Appendix B) | |
20 | * are available, video.ko should be used to handle the device. | |
21 | * | |
7ec48ced | 22 | * Otherwise vendor specific drivers like thinkpad_acpi, asus-laptop, |
677bd810 | 23 | * sony_acpi,... can take care about backlight brightness. |
c3d6de69 TR |
24 | * |
25 | * If CONFIG_ACPI_VIDEO is neither set as "compiled in" (y) nor as a module (m) | |
26 | * this file will not be compiled, acpi_video_get_capabilities() and | |
27 | * acpi_video_backlight_support() will always return 0 and vendor specific | |
28 | * drivers always can handle backlight. | |
29 | * | |
30 | */ | |
31 | ||
214f2c90 | 32 | #include <linux/export.h> |
c3d6de69 TR |
33 | #include <linux/acpi.h> |
34 | #include <linux/dmi.h> | |
14ca7a47 | 35 | #include <linux/module.h> |
1e4cffe7 | 36 | #include <linux/pci.h> |
c3d6de69 TR |
37 | |
38 | ACPI_MODULE_NAME("video"); | |
c3d6de69 TR |
39 | #define _COMPONENT ACPI_VIDEO_COMPONENT |
40 | ||
41 | static long acpi_video_support; | |
42 | static bool acpi_video_caps_checked; | |
43 | ||
14ca7a47 HG |
44 | static void acpi_video_parse_cmdline(void) |
45 | { | |
46 | if (!strcmp("vendor", acpi_video_backlight_string)) | |
47 | acpi_video_support |= ACPI_VIDEO_BACKLIGHT_FORCE_VENDOR; | |
48 | if (!strcmp("video", acpi_video_backlight_string)) | |
49 | acpi_video_support |= ACPI_VIDEO_BACKLIGHT_FORCE_VIDEO; | |
50 | } | |
51 | ||
c3d6de69 TR |
52 | static acpi_status |
53 | find_video(acpi_handle handle, u32 lvl, void *context, void **rv) | |
54 | { | |
55 | long *cap = context; | |
1e4cffe7 | 56 | struct pci_dev *dev; |
c3d6de69 TR |
57 | struct acpi_device *acpi_dev; |
58 | ||
4a4f01a6 | 59 | static const struct acpi_device_id video_ids[] = { |
c3d6de69 TR |
60 | {ACPI_VIDEO_HID, 0}, |
61 | {"", 0}, | |
62 | }; | |
63 | if (acpi_bus_get_device(handle, &acpi_dev)) | |
64 | return AE_OK; | |
65 | ||
66 | if (!acpi_match_device_ids(acpi_dev, video_ids)) { | |
1e4cffe7 | 67 | dev = acpi_get_pci_dev(handle); |
c3d6de69 TR |
68 | if (!dev) |
69 | return AE_OK; | |
1e4cffe7 | 70 | pci_dev_put(dev); |
d4e1a692 | 71 | *cap |= acpi_is_video_device(handle); |
c3d6de69 TR |
72 | } |
73 | return AE_OK; | |
74 | } | |
75 | ||
084940d5 CC |
76 | /* Force to use vendor driver when the ACPI device is known to be |
77 | * buggy */ | |
78 | static int video_detect_force_vendor(const struct dmi_system_id *d) | |
79 | { | |
80 | acpi_video_support |= ACPI_VIDEO_BACKLIGHT_DMI_VENDOR; | |
81 | return 0; | |
82 | } | |
83 | ||
4a4f01a6 | 84 | static const struct dmi_system_id video_detect_dmi_table[] = { |
084940d5 CC |
85 | /* On Samsung X360, the BIOS will set a flag (VDRV) if generic |
86 | * ACPI backlight device is used. This flag will definitively break | |
87 | * the backlight interface (even the vendor interface) untill next | |
88 | * reboot. It's why we should prevent video.ko from being used here | |
89 | * and we can't rely on a later call to acpi_video_unregister(). | |
90 | */ | |
91 | { | |
92 | .callback = video_detect_force_vendor, | |
93 | .ident = "X360", | |
94 | .matches = { | |
95 | DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."), | |
96 | DMI_MATCH(DMI_PRODUCT_NAME, "X360"), | |
97 | DMI_MATCH(DMI_BOARD_NAME, "X360"), | |
98 | }, | |
99 | }, | |
d0c2ce16 LT |
100 | { |
101 | .callback = video_detect_force_vendor, | |
102 | .ident = "Asus UL30VT", | |
103 | .matches = { | |
104 | DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK Computer Inc."), | |
105 | DMI_MATCH(DMI_PRODUCT_NAME, "UL30VT"), | |
106 | }, | |
107 | }, | |
c8f6d835 BT |
108 | { |
109 | .callback = video_detect_force_vendor, | |
110 | .ident = "Asus UL30A", | |
111 | .matches = { | |
112 | DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK Computer Inc."), | |
113 | DMI_MATCH(DMI_PRODUCT_NAME, "UL30A"), | |
114 | }, | |
115 | }, | |
08a56226 EL |
116 | { |
117 | .callback = video_detect_force_vendor, | |
118 | .ident = "Dell Inspiron 5737", | |
119 | .matches = { | |
120 | DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), | |
121 | DMI_MATCH(DMI_PRODUCT_NAME, "Inspiron 5737"), | |
122 | }, | |
123 | }, | |
084940d5 CC |
124 | { }, |
125 | }; | |
126 | ||
c3d6de69 TR |
127 | /* |
128 | * Returns the video capabilities of a specific ACPI graphics device | |
129 | * | |
130 | * if NULL is passed as argument all ACPI devices are enumerated and | |
131 | * all graphics capabilities of physically present devices are | |
94e2bd68 | 132 | * summarized and returned. This is cached and done only once. |
c3d6de69 | 133 | */ |
fb105d96 | 134 | static long acpi_video_get_capabilities(acpi_handle graphics_handle) |
c3d6de69 TR |
135 | { |
136 | long caps = 0; | |
137 | struct acpi_device *tmp_dev; | |
138 | acpi_status status; | |
139 | ||
140 | if (acpi_video_caps_checked && graphics_handle == NULL) | |
141 | return acpi_video_support; | |
142 | ||
143 | if (!graphics_handle) { | |
144 | /* Only do the global walk through all graphics devices once */ | |
145 | acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT, | |
2263576c | 146 | ACPI_UINT32_MAX, find_video, NULL, |
c3d6de69 TR |
147 | &caps, NULL); |
148 | /* There might be boot param flags set already... */ | |
149 | acpi_video_support |= caps; | |
150 | acpi_video_caps_checked = 1; | |
151 | /* Add blacklists here. Be careful to use the right *DMI* bits | |
152 | * to still be able to override logic via boot params, e.g.: | |
153 | * | |
154 | * if (dmi_name_in_vendors("XY")) { | |
155 | * acpi_video_support |= | |
c3d6de69 TR |
156 | * ACPI_VIDEO_BACKLIGHT_DMI_VENDOR; |
157 | *} | |
158 | */ | |
084940d5 CC |
159 | |
160 | dmi_check_system(video_detect_dmi_table); | |
c3d6de69 TR |
161 | } else { |
162 | status = acpi_bus_get_device(graphics_handle, &tmp_dev); | |
163 | if (ACPI_FAILURE(status)) { | |
164 | ACPI_EXCEPTION((AE_INFO, status, "Invalid device")); | |
165 | return 0; | |
166 | } | |
167 | acpi_walk_namespace(ACPI_TYPE_DEVICE, graphics_handle, | |
2263576c | 168 | ACPI_UINT32_MAX, find_video, NULL, |
c3d6de69 TR |
169 | &caps, NULL); |
170 | } | |
171 | ACPI_DEBUG_PRINT((ACPI_DB_INFO, "We have 0x%lX video support %s %s\n", | |
172 | graphics_handle ? caps : acpi_video_support, | |
173 | graphics_handle ? "on device " : "in general", | |
174 | graphics_handle ? acpi_device_bid(tmp_dev) : "")); | |
175 | return caps; | |
176 | } | |
c3d6de69 | 177 | |
f838eb5b | 178 | static void acpi_video_caps_check(void) |
c3d6de69 TR |
179 | { |
180 | /* | |
181 | * We must check whether the ACPI graphics device is physically plugged | |
182 | * in. Therefore this must be called after binding PCI and ACPI devices | |
183 | */ | |
14ca7a47 HG |
184 | if (!acpi_video_caps_checked) { |
185 | acpi_video_parse_cmdline(); | |
c3d6de69 | 186 | acpi_video_get_capabilities(NULL); |
14ca7a47 | 187 | } |
f838eb5b CC |
188 | } |
189 | ||
190 | /* Promote the vendor interface instead of the generic video module. | |
191 | * This function allow DMI blacklists to be implemented by externals | |
192 | * platform drivers instead of putting a big blacklist in video_detect.c | |
193 | * After calling this function you will probably want to call | |
194 | * acpi_video_unregister() to make sure the video module is not loaded | |
195 | */ | |
196 | void acpi_video_dmi_promote_vendor(void) | |
197 | { | |
198 | acpi_video_caps_check(); | |
199 | acpi_video_support |= ACPI_VIDEO_BACKLIGHT_DMI_VENDOR; | |
200 | } | |
201 | EXPORT_SYMBOL(acpi_video_dmi_promote_vendor); | |
202 | ||
f838eb5b CC |
203 | /* Returns true if video.ko can do backlight switching */ |
204 | int acpi_video_backlight_support(void) | |
205 | { | |
206 | acpi_video_caps_check(); | |
c3d6de69 TR |
207 | |
208 | /* First check for boot param -> highest prio */ | |
209 | if (acpi_video_support & ACPI_VIDEO_BACKLIGHT_FORCE_VENDOR) | |
210 | return 0; | |
211 | else if (acpi_video_support & ACPI_VIDEO_BACKLIGHT_FORCE_VIDEO) | |
212 | return 1; | |
213 | ||
214 | /* Then check for DMI blacklist -> second highest prio */ | |
215 | if (acpi_video_support & ACPI_VIDEO_BACKLIGHT_DMI_VENDOR) | |
216 | return 0; | |
217 | else if (acpi_video_support & ACPI_VIDEO_BACKLIGHT_DMI_VIDEO) | |
218 | return 1; | |
219 | ||
220 | /* Then go the default way */ | |
221 | return acpi_video_support & ACPI_VIDEO_BACKLIGHT; | |
222 | } | |
223 | EXPORT_SYMBOL(acpi_video_backlight_support); |