diff options
Diffstat (limited to 'drivers/acpi/video_detect.c')
| -rw-r--r-- | drivers/acpi/video_detect.c | 267 |
1 files changed, 267 insertions, 0 deletions
diff --git a/drivers/acpi/video_detect.c b/drivers/acpi/video_detect.c new file mode 100644 index 000000000000..f022eb6f5637 --- /dev/null +++ b/drivers/acpi/video_detect.c | |||
| @@ -0,0 +1,267 @@ | |||
| 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: | ||
| 8 | * Provides acpi_is_video_device() for early scanning of ACPI devices in scan.c | ||
| 9 | * There a Linux specific (Spec does not provide a HID for video devices) is | ||
| 10 | * assinged | ||
| 11 | * | ||
| 12 | * After PCI devices are glued with ACPI devices | ||
| 13 | * acpi_get_physical_pci_device() can be called to identify ACPI graphics | ||
| 14 | * devices for which a real graphics card is plugged in | ||
| 15 | * | ||
| 16 | * Now acpi_video_get_capabilities() can be called to check which | ||
| 17 | * capabilities the graphics cards plugged in support. The check for general | ||
| 18 | * video capabilities will be triggered by the first caller of | ||
| 19 | * acpi_video_get_capabilities(NULL); which will happen when the first | ||
| 20 | * backlight (or display output) switching supporting driver calls: | ||
| 21 | * acpi_video_backlight_support(); | ||
| 22 | * | ||
| 23 | * Depending on whether ACPI graphics extensions (cmp. ACPI spec Appendix B) | ||
| 24 | * are available, video.ko should be used to handle the device. | ||
| 25 | * | ||
| 26 | * Otherwise vendor specific drivers like thinkpad_acpi, asus_acpi, | ||
| 27 | * sony_acpi,... can take care about backlight brightness and display output | ||
| 28 | * switching. | ||
| 29 | * | ||
| 30 | * If CONFIG_ACPI_VIDEO is neither set as "compiled in" (y) nor as a module (m) | ||
| 31 | * this file will not be compiled, acpi_video_get_capabilities() and | ||
| 32 | * acpi_video_backlight_support() will always return 0 and vendor specific | ||
| 33 | * drivers always can handle backlight. | ||
| 34 | * | ||
| 35 | */ | ||
| 36 | |||
| 37 | #include <linux/acpi.h> | ||
| 38 | #include <linux/dmi.h> | ||
| 39 | |||
| 40 | ACPI_MODULE_NAME("video"); | ||
| 41 | #define _COMPONENT ACPI_VIDEO_COMPONENT | ||
| 42 | |||
| 43 | static long acpi_video_support; | ||
| 44 | static bool acpi_video_caps_checked; | ||
| 45 | |||
| 46 | static acpi_status | ||
| 47 | acpi_backlight_cap_match(acpi_handle handle, u32 level, void *context, | ||
| 48 | void **retyurn_value) | ||
| 49 | { | ||
| 50 | long *cap = context; | ||
| 51 | acpi_handle h_dummy; | ||
| 52 | |||
| 53 | if (ACPI_SUCCESS(acpi_get_handle(handle, "_BCM", &h_dummy)) && | ||
| 54 | ACPI_SUCCESS(acpi_get_handle(handle, "_BCL", &h_dummy))) { | ||
| 55 | ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Found generic backlight " | ||
| 56 | "support\n")); | ||
| 57 | *cap |= ACPI_VIDEO_BACKLIGHT; | ||
| 58 | /* We have backlight support, no need to scan further */ | ||
| 59 | return AE_CTRL_TERMINATE; | ||
| 60 | } | ||
| 61 | return 0; | ||
| 62 | } | ||
| 63 | |||
| 64 | /* Returns true if the device is a video device which can be handled by | ||
| 65 | * video.ko. | ||
| 66 | * The device will get a Linux specific CID added in scan.c to | ||
| 67 | * identify the device as an ACPI graphics device | ||
| 68 | * Be aware that the graphics device may not be physically present | ||
| 69 | * Use acpi_video_get_capabilities() to detect general ACPI video | ||
| 70 | * capabilities of present cards | ||
| 71 | */ | ||
| 72 | long acpi_is_video_device(struct acpi_device *device) | ||
| 73 | { | ||
| 74 | acpi_handle h_dummy; | ||
| 75 | long video_caps = 0; | ||
| 76 | |||
| 77 | if (!device) | ||
| 78 | return 0; | ||
| 79 | |||
| 80 | /* Does this device able to support video switching ? */ | ||
| 81 | if (ACPI_SUCCESS(acpi_get_handle(device->handle, "_DOD", &h_dummy)) && | ||
| 82 | ACPI_SUCCESS(acpi_get_handle(device->handle, "_DOS", &h_dummy))) | ||
| 83 | video_caps |= ACPI_VIDEO_OUTPUT_SWITCHING; | ||
| 84 | |||
| 85 | /* Does this device able to retrieve a video ROM ? */ | ||
| 86 | if (ACPI_SUCCESS(acpi_get_handle(device->handle, "_ROM", &h_dummy))) | ||
| 87 | video_caps |= ACPI_VIDEO_ROM_AVAILABLE; | ||
| 88 | |||
| 89 | /* Does this device able to configure which video head to be POSTed ? */ | ||
| 90 | if (ACPI_SUCCESS(acpi_get_handle(device->handle, "_VPO", &h_dummy)) && | ||
| 91 | ACPI_SUCCESS(acpi_get_handle(device->handle, "_GPD", &h_dummy)) && | ||
| 92 | ACPI_SUCCESS(acpi_get_handle(device->handle, "_SPD", &h_dummy))) | ||
| 93 | video_caps |= ACPI_VIDEO_DEVICE_POSTING; | ||
| 94 | |||
| 95 | /* Only check for backlight functionality if one of the above hit. */ | ||
| 96 | if (video_caps) | ||
| 97 | acpi_walk_namespace(ACPI_TYPE_DEVICE, device->handle, | ||
| 98 | ACPI_UINT32_MAX, acpi_backlight_cap_match, | ||
| 99 | &video_caps, NULL); | ||
| 100 | |||
| 101 | return video_caps; | ||
| 102 | } | ||
| 103 | EXPORT_SYMBOL(acpi_is_video_device); | ||
| 104 | |||
| 105 | static acpi_status | ||
| 106 | find_video(acpi_handle handle, u32 lvl, void *context, void **rv) | ||
| 107 | { | ||
| 108 | long *cap = context; | ||
| 109 | struct device *dev; | ||
| 110 | struct acpi_device *acpi_dev; | ||
| 111 | |||
| 112 | const struct acpi_device_id video_ids[] = { | ||
| 113 | {ACPI_VIDEO_HID, 0}, | ||
| 114 | {"", 0}, | ||
| 115 | }; | ||
| 116 | if (acpi_bus_get_device(handle, &acpi_dev)) | ||
| 117 | return AE_OK; | ||
| 118 | |||
| 119 | if (!acpi_match_device_ids(acpi_dev, video_ids)) { | ||
| 120 | dev = acpi_get_physical_pci_device(handle); | ||
| 121 | if (!dev) | ||
| 122 | return AE_OK; | ||
| 123 | put_device(dev); | ||
| 124 | *cap |= acpi_is_video_device(acpi_dev); | ||
| 125 | } | ||
| 126 | return AE_OK; | ||
| 127 | } | ||
| 128 | |||
| 129 | /* | ||
| 130 | * Returns the video capabilities of a specific ACPI graphics device | ||
| 131 | * | ||
| 132 | * if NULL is passed as argument all ACPI devices are enumerated and | ||
| 133 | * all graphics capabilities of physically present devices are | ||
| 134 | * summerized and returned. This is cached and done only once. | ||
| 135 | */ | ||
| 136 | long acpi_video_get_capabilities(acpi_handle graphics_handle) | ||
| 137 | { | ||
| 138 | long caps = 0; | ||
| 139 | struct acpi_device *tmp_dev; | ||
| 140 | acpi_status status; | ||
| 141 | |||
| 142 | if (acpi_video_caps_checked && graphics_handle == NULL) | ||
| 143 | return acpi_video_support; | ||
| 144 | |||
| 145 | if (!graphics_handle) { | ||
| 146 | /* Only do the global walk through all graphics devices once */ | ||
| 147 | acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT, | ||
| 148 | ACPI_UINT32_MAX, find_video, | ||
| 149 | &caps, NULL); | ||
| 150 | /* There might be boot param flags set already... */ | ||
| 151 | acpi_video_support |= caps; | ||
| 152 | acpi_video_caps_checked = 1; | ||
| 153 | /* Add blacklists here. Be careful to use the right *DMI* bits | ||
| 154 | * to still be able to override logic via boot params, e.g.: | ||
| 155 | * | ||
| 156 | * if (dmi_name_in_vendors("XY")) { | ||
| 157 | * acpi_video_support |= | ||
| 158 | * ACPI_VIDEO_OUTPUT_SWITCHING_DMI_VENDOR; | ||
| 159 | * acpi_video_support |= | ||
| 160 | * ACPI_VIDEO_BACKLIGHT_DMI_VENDOR; | ||
| 161 | *} | ||
| 162 | */ | ||
| 163 | } else { | ||
| 164 | status = acpi_bus_get_device(graphics_handle, &tmp_dev); | ||
| 165 | if (ACPI_FAILURE(status)) { | ||
| 166 | ACPI_EXCEPTION((AE_INFO, status, "Invalid device")); | ||
| 167 | return 0; | ||
| 168 | } | ||
| 169 | acpi_walk_namespace(ACPI_TYPE_DEVICE, graphics_handle, | ||
| 170 | ACPI_UINT32_MAX, find_video, | ||
| 171 | &caps, NULL); | ||
| 172 | } | ||
| 173 | ACPI_DEBUG_PRINT((ACPI_DB_INFO, "We have 0x%lX video support %s %s\n", | ||
| 174 | graphics_handle ? caps : acpi_video_support, | ||
| 175 | graphics_handle ? "on device " : "in general", | ||
| 176 | graphics_handle ? acpi_device_bid(tmp_dev) : "")); | ||
| 177 | return caps; | ||
| 178 | } | ||
| 179 | EXPORT_SYMBOL(acpi_video_get_capabilities); | ||
| 180 | |||
| 181 | /* Returns true if video.ko can do backlight switching */ | ||
| 182 | int acpi_video_backlight_support(void) | ||
| 183 | { | ||
| 184 | /* | ||
| 185 | * We must check whether the ACPI graphics device is physically plugged | ||
| 186 | * in. Therefore this must be called after binding PCI and ACPI devices | ||
| 187 | */ | ||
| 188 | if (!acpi_video_caps_checked) | ||
| 189 | acpi_video_get_capabilities(NULL); | ||
| 190 | |||
| 191 | /* First check for boot param -> highest prio */ | ||
| 192 | if (acpi_video_support & ACPI_VIDEO_BACKLIGHT_FORCE_VENDOR) | ||
| 193 | return 0; | ||
| 194 | else if (acpi_video_support & ACPI_VIDEO_BACKLIGHT_FORCE_VIDEO) | ||
| 195 | return 1; | ||
| 196 | |||
| 197 | /* Then check for DMI blacklist -> second highest prio */ | ||
| 198 | if (acpi_video_support & ACPI_VIDEO_BACKLIGHT_DMI_VENDOR) | ||
| 199 | return 0; | ||
| 200 | else if (acpi_video_support & ACPI_VIDEO_BACKLIGHT_DMI_VIDEO) | ||
| 201 | return 1; | ||
| 202 | |||
| 203 | /* Then go the default way */ | ||
| 204 | return acpi_video_support & ACPI_VIDEO_BACKLIGHT; | ||
| 205 | } | ||
| 206 | EXPORT_SYMBOL(acpi_video_backlight_support); | ||
| 207 | |||
| 208 | /* | ||
| 209 | * Returns true if video.ko can do display output switching. | ||
| 210 | * This does not work well/at all with binary graphics drivers | ||
| 211 | * which disable system io ranges and do it on their own. | ||
| 212 | */ | ||
| 213 | int acpi_video_display_switch_support(void) | ||
| 214 | { | ||
| 215 | if (!acpi_video_caps_checked) | ||
| 216 | acpi_video_get_capabilities(NULL); | ||
| 217 | |||
| 218 | if (acpi_video_support & ACPI_VIDEO_OUTPUT_SWITCHING_FORCE_VENDOR) | ||
| 219 | return 0; | ||
| 220 | else if (acpi_video_support & ACPI_VIDEO_OUTPUT_SWITCHING_FORCE_VIDEO) | ||
| 221 | return 1; | ||
| 222 | |||
| 223 | if (acpi_video_support & ACPI_VIDEO_OUTPUT_SWITCHING_DMI_VENDOR) | ||
| 224 | return 0; | ||
| 225 | else if (acpi_video_support & ACPI_VIDEO_OUTPUT_SWITCHING_DMI_VIDEO) | ||
| 226 | return 1; | ||
| 227 | |||
| 228 | return acpi_video_support & ACPI_VIDEO_OUTPUT_SWITCHING; | ||
| 229 | } | ||
| 230 | EXPORT_SYMBOL(acpi_video_display_switch_support); | ||
| 231 | |||
| 232 | /* | ||
| 233 | * Use acpi_display_output=vendor/video or acpi_backlight=vendor/video | ||
| 234 | * To force that backlight or display output switching is processed by vendor | ||
| 235 | * specific acpi drivers or video.ko driver. | ||
| 236 | */ | ||
| 237 | int __init acpi_backlight(char *str) | ||
| 238 | { | ||
| 239 | if (str == NULL || *str == '\0') | ||
| 240 | return 1; | ||
| 241 | else { | ||
| 242 | if (!strcmp("vendor", str)) | ||
| 243 | acpi_video_support |= | ||
| 244 | ACPI_VIDEO_BACKLIGHT_FORCE_VENDOR; | ||
| 245 | if (!strcmp("video", str)) | ||
| 246 | acpi_video_support |= | ||
| 247 | ACPI_VIDEO_OUTPUT_SWITCHING_FORCE_VIDEO; | ||
| 248 | } | ||
| 249 | return 1; | ||
| 250 | } | ||
| 251 | __setup("acpi_backlight=", acpi_backlight); | ||
| 252 | |||
| 253 | int __init acpi_display_output(char *str) | ||
| 254 | { | ||
| 255 | if (str == NULL || *str == '\0') | ||
| 256 | return 1; | ||
| 257 | else { | ||
| 258 | if (!strcmp("vendor", str)) | ||
| 259 | acpi_video_support |= | ||
| 260 | ACPI_VIDEO_OUTPUT_SWITCHING_FORCE_VENDOR; | ||
| 261 | if (!strcmp("video", str)) | ||
| 262 | acpi_video_support |= | ||
| 263 | ACPI_VIDEO_OUTPUT_SWITCHING_FORCE_VIDEO; | ||
| 264 | } | ||
| 265 | return 1; | ||
| 266 | } | ||
| 267 | __setup("acpi_display_output=", acpi_display_output); | ||
