1c942fddfSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later 214ca7a47SHans de Goede /* 314ca7a47SHans de Goede * video.c - ACPI Video Driver 414ca7a47SHans de Goede * 514ca7a47SHans de Goede * Copyright (C) 2004 Luming Yu <luming.yu@intel.com> 614ca7a47SHans de Goede * Copyright (C) 2004 Bruno Ducrot <ducrot@poupinou.org> 714ca7a47SHans de Goede * Copyright (C) 2006 Thomas Tuttle <linux-kernel@ttuttle.net> 814ca7a47SHans de Goede */ 914ca7a47SHans de Goede 102924d2f8SRafael J. Wysocki #define pr_fmt(fmt) "ACPI: video: " fmt 112924d2f8SRafael J. Wysocki 1214ca7a47SHans de Goede #include <linux/kernel.h> 1314ca7a47SHans de Goede #include <linux/module.h> 1414ca7a47SHans de Goede #include <linux/init.h> 1514ca7a47SHans de Goede #include <linux/types.h> 1614ca7a47SHans de Goede #include <linux/list.h> 1714ca7a47SHans de Goede #include <linux/mutex.h> 1814ca7a47SHans de Goede #include <linux/input.h> 1914ca7a47SHans de Goede #include <linux/backlight.h> 2014ca7a47SHans de Goede #include <linux/thermal.h> 2114ca7a47SHans de Goede #include <linux/sort.h> 2214ca7a47SHans de Goede #include <linux/pci.h> 2314ca7a47SHans de Goede #include <linux/pci_ids.h> 2414ca7a47SHans de Goede #include <linux/slab.h> 2514ca7a47SHans de Goede #include <linux/dmi.h> 2614ca7a47SHans de Goede #include <linux/suspend.h> 2714ca7a47SHans de Goede #include <linux/acpi.h> 2814ca7a47SHans de Goede #include <acpi/video.h> 297c0f6ba6SLinus Torvalds #include <linux/uaccess.h> 3014ca7a47SHans de Goede 3114ca7a47SHans de Goede #define ACPI_VIDEO_BUS_NAME "Video Bus" 3214ca7a47SHans de Goede #define ACPI_VIDEO_DEVICE_NAME "Video Device" 3314ca7a47SHans de Goede 3414ca7a47SHans de Goede #define MAX_NAME_LEN 20 3514ca7a47SHans de Goede 3614ca7a47SHans de Goede MODULE_AUTHOR("Bruno Ducrot"); 3714ca7a47SHans de Goede MODULE_DESCRIPTION("ACPI Video Driver"); 3814ca7a47SHans de Goede MODULE_LICENSE("GPL"); 3914ca7a47SHans de Goede 4097e45dd6SGustavo A. R. Silva static bool brightness_switch_enabled = true; 4114ca7a47SHans de Goede module_param(brightness_switch_enabled, bool, 0644); 4214ca7a47SHans de Goede 4314ca7a47SHans de Goede /* 4414ca7a47SHans de Goede * By default, we don't allow duplicate ACPI video bus devices 4514ca7a47SHans de Goede * under the same VGA controller 4614ca7a47SHans de Goede */ 4714ca7a47SHans de Goede static bool allow_duplicates; 4814ca7a47SHans de Goede module_param(allow_duplicates, bool, 0644); 4914ca7a47SHans de Goede 5005bc59a0SHans de Goede #define REPORT_OUTPUT_KEY_EVENTS 0x01 5105bc59a0SHans de Goede #define REPORT_BRIGHTNESS_KEY_EVENTS 0x02 5205bc59a0SHans de Goede static int report_key_events = -1; 5305bc59a0SHans de Goede module_param(report_key_events, int, 0644); 5405bc59a0SHans de Goede MODULE_PARM_DESC(report_key_events, 5505bc59a0SHans de Goede "0: none, 1: output changes, 2: brightness changes, 3: all"); 5605bc59a0SHans de Goede 574f7f9645SHans de Goede static int hw_changes_brightness = -1; 584f7f9645SHans de Goede module_param(hw_changes_brightness, int, 0644); 594f7f9645SHans de Goede MODULE_PARM_DESC(hw_changes_brightness, 604f7f9645SHans de Goede "Set this to 1 on buggy hw which changes the brightness itself when " 614f7f9645SHans de Goede "a hotkey is pressed: -1: auto, 0: normal 1: hw-changes-brightness"); 624f7f9645SHans de Goede 63592c8095SDmitry Frank /* 64592c8095SDmitry Frank * Whether the struct acpi_video_device_attrib::device_id_scheme bit should be 65592c8095SDmitry Frank * assumed even if not actually set. 66592c8095SDmitry Frank */ 67e50b9be1SAaron Lu static bool device_id_scheme = false; 68e50b9be1SAaron Lu module_param(device_id_scheme, bool, 0444); 69e50b9be1SAaron Lu 705928c281SHans de Goede static int only_lcd = -1; 715928c281SHans de Goede module_param(only_lcd, int, 0444); 72e50b9be1SAaron Lu 733dbc80a3SHans de Goede /* 743dbc80a3SHans de Goede * Display probing is known to take up to 5 seconds, so delay the fallback 753dbc80a3SHans de Goede * backlight registration by 5 seconds + 3 seconds for some extra margin. 763dbc80a3SHans de Goede */ 773dbc80a3SHans de Goede static int register_backlight_delay = 8; 783dbc80a3SHans de Goede module_param(register_backlight_delay, int, 0444); 793dbc80a3SHans de Goede MODULE_PARM_DESC(register_backlight_delay, 803dbc80a3SHans de Goede "Delay in seconds before doing fallback (non GPU driver triggered) " 813dbc80a3SHans de Goede "backlight registration, set to 0 to disable."); 823dbc80a3SHans de Goede 835ad26161SHans de Goede static bool may_report_brightness_keys; 84970530cdSHans de Goede static int register_count; 85970530cdSHans de Goede static DEFINE_MUTEX(register_count_mutex); 8614e93553SHans de Goede static DEFINE_MUTEX(video_list_lock); 8714e93553SHans de Goede static LIST_HEAD(video_bus_head); 8814ca7a47SHans de Goede static int acpi_video_bus_add(struct acpi_device *device); 89*6c0eb5baSDawei Li static void acpi_video_bus_remove(struct acpi_device *device); 9014ca7a47SHans de Goede static void acpi_video_bus_notify(struct acpi_device *device, u32 event); 913dbc80a3SHans de Goede static void acpi_video_bus_register_backlight_work(struct work_struct *ignored); 923dbc80a3SHans de Goede static DECLARE_DELAYED_WORK(video_bus_register_backlight_work, 933dbc80a3SHans de Goede acpi_video_bus_register_backlight_work); 9414ca7a47SHans de Goede 95d485ef43SDmitry Frank /* 96d485ef43SDmitry Frank * Indices in the _BCL method response: the first two items are special, 97d485ef43SDmitry Frank * the rest are all supported levels. 98d485ef43SDmitry Frank * 99d485ef43SDmitry Frank * See page 575 of the ACPI spec 3.0 100d485ef43SDmitry Frank */ 101d485ef43SDmitry Frank enum acpi_video_level_idx { 102d485ef43SDmitry Frank ACPI_VIDEO_AC_LEVEL, /* level when machine has full power */ 103d485ef43SDmitry Frank ACPI_VIDEO_BATTERY_LEVEL, /* level when machine is on batteries */ 104d485ef43SDmitry Frank ACPI_VIDEO_FIRST_LEVEL, /* actual supported levels begin here */ 105d485ef43SDmitry Frank }; 106d485ef43SDmitry Frank 10714ca7a47SHans de Goede static const struct acpi_device_id video_device_ids[] = { 10814ca7a47SHans de Goede {ACPI_VIDEO_HID, 0}, 10914ca7a47SHans de Goede {"", 0}, 11014ca7a47SHans de Goede }; 11114ca7a47SHans de Goede MODULE_DEVICE_TABLE(acpi, video_device_ids); 11214ca7a47SHans de Goede 11314ca7a47SHans de Goede static struct acpi_driver acpi_video_bus = { 11414ca7a47SHans de Goede .name = "video", 11514ca7a47SHans de Goede .class = ACPI_VIDEO_CLASS, 11614ca7a47SHans de Goede .ids = video_device_ids, 11714ca7a47SHans de Goede .ops = { 11814ca7a47SHans de Goede .add = acpi_video_bus_add, 11914ca7a47SHans de Goede .remove = acpi_video_bus_remove, 12014ca7a47SHans de Goede .notify = acpi_video_bus_notify, 12114ca7a47SHans de Goede }, 12214ca7a47SHans de Goede }; 12314ca7a47SHans de Goede 12414ca7a47SHans de Goede struct acpi_video_bus_flags { 12514ca7a47SHans de Goede u8 multihead:1; /* can switch video heads */ 12614ca7a47SHans de Goede u8 rom:1; /* can retrieve a video rom */ 12714ca7a47SHans de Goede u8 post:1; /* can configure the head to */ 12814ca7a47SHans de Goede u8 reserved:5; 12914ca7a47SHans de Goede }; 13014ca7a47SHans de Goede 13114ca7a47SHans de Goede struct acpi_video_bus_cap { 13214ca7a47SHans de Goede u8 _DOS:1; /* Enable/Disable output switching */ 13314ca7a47SHans de Goede u8 _DOD:1; /* Enumerate all devices attached to display adapter */ 13414ca7a47SHans de Goede u8 _ROM:1; /* Get ROM Data */ 13514ca7a47SHans de Goede u8 _GPD:1; /* Get POST Device */ 13614ca7a47SHans de Goede u8 _SPD:1; /* Set POST Device */ 13714ca7a47SHans de Goede u8 _VPO:1; /* Video POST Options */ 13814ca7a47SHans de Goede u8 reserved:2; 13914ca7a47SHans de Goede }; 14014ca7a47SHans de Goede 14114ca7a47SHans de Goede struct acpi_video_device_attrib { 14214ca7a47SHans de Goede u32 display_index:4; /* A zero-based instance of the Display */ 14314ca7a47SHans de Goede u32 display_port_attachment:4; /* This field differentiates the display type */ 14414ca7a47SHans de Goede u32 display_type:4; /* Describe the specific type in use */ 14514ca7a47SHans de Goede u32 vendor_specific:4; /* Chipset Vendor Specific */ 14614ca7a47SHans de Goede u32 bios_can_detect:1; /* BIOS can detect the device */ 14714ca7a47SHans de Goede u32 depend_on_vga:1; /* Non-VGA output device whose power is related to 14814ca7a47SHans de Goede the VGA device. */ 14914ca7a47SHans de Goede u32 pipe_id:3; /* For VGA multiple-head devices. */ 15014ca7a47SHans de Goede u32 reserved:10; /* Must be 0 */ 151592c8095SDmitry Frank 152592c8095SDmitry Frank /* 153592c8095SDmitry Frank * The device ID might not actually follow the scheme described by this 154592c8095SDmitry Frank * struct acpi_video_device_attrib. If it does, then this bit 155592c8095SDmitry Frank * device_id_scheme is set; otherwise, other fields should be ignored. 156592c8095SDmitry Frank * 157592c8095SDmitry Frank * (but also see the global flag device_id_scheme) 158592c8095SDmitry Frank */ 159592c8095SDmitry Frank u32 device_id_scheme:1; 16014ca7a47SHans de Goede }; 16114ca7a47SHans de Goede 16214ca7a47SHans de Goede struct acpi_video_enumerated_device { 16314ca7a47SHans de Goede union { 16414ca7a47SHans de Goede u32 int_val; 16514ca7a47SHans de Goede struct acpi_video_device_attrib attrib; 16614ca7a47SHans de Goede } value; 16714ca7a47SHans de Goede struct acpi_video_device *bind_info; 16814ca7a47SHans de Goede }; 16914ca7a47SHans de Goede 17014ca7a47SHans de Goede struct acpi_video_bus { 17114ca7a47SHans de Goede struct acpi_device *device; 17214ca7a47SHans de Goede bool backlight_registered; 17314ca7a47SHans de Goede u8 dos_setting; 17414ca7a47SHans de Goede struct acpi_video_enumerated_device *attached_array; 17514ca7a47SHans de Goede u8 attached_count; 17614ca7a47SHans de Goede u8 child_count; 17714ca7a47SHans de Goede struct acpi_video_bus_cap cap; 17814ca7a47SHans de Goede struct acpi_video_bus_flags flags; 17914ca7a47SHans de Goede struct list_head video_device_list; 18014ca7a47SHans de Goede struct mutex device_list_lock; /* protects video_device_list */ 18114ca7a47SHans de Goede struct list_head entry; 18214ca7a47SHans de Goede struct input_dev *input; 18314ca7a47SHans de Goede char phys[32]; /* for input device */ 18414ca7a47SHans de Goede struct notifier_block pm_nb; 18514ca7a47SHans de Goede }; 18614ca7a47SHans de Goede 18714ca7a47SHans de Goede struct acpi_video_device_flags { 18814ca7a47SHans de Goede u8 crt:1; 18914ca7a47SHans de Goede u8 lcd:1; 19014ca7a47SHans de Goede u8 tvout:1; 19114ca7a47SHans de Goede u8 dvi:1; 19214ca7a47SHans de Goede u8 bios:1; 19314ca7a47SHans de Goede u8 unknown:1; 19414ca7a47SHans de Goede u8 notify:1; 19514ca7a47SHans de Goede u8 reserved:1; 19614ca7a47SHans de Goede }; 19714ca7a47SHans de Goede 19814ca7a47SHans de Goede struct acpi_video_device_cap { 19914ca7a47SHans de Goede u8 _ADR:1; /* Return the unique ID */ 20014ca7a47SHans de Goede u8 _BCL:1; /* Query list of brightness control levels supported */ 20114ca7a47SHans de Goede u8 _BCM:1; /* Set the brightness level */ 20214ca7a47SHans de Goede u8 _BQC:1; /* Get current brightness level */ 20314ca7a47SHans de Goede u8 _BCQ:1; /* Some buggy BIOS uses _BCQ instead of _BQC */ 20414ca7a47SHans de Goede u8 _DDC:1; /* Return the EDID for this device */ 20514ca7a47SHans de Goede }; 20614ca7a47SHans de Goede 20714ca7a47SHans de Goede struct acpi_video_device { 20814ca7a47SHans de Goede unsigned long device_id; 20914ca7a47SHans de Goede struct acpi_video_device_flags flags; 21014ca7a47SHans de Goede struct acpi_video_device_cap cap; 21114ca7a47SHans de Goede struct list_head entry; 21214ca7a47SHans de Goede struct delayed_work switch_brightness_work; 21314ca7a47SHans de Goede int switch_brightness_event; 21414ca7a47SHans de Goede struct acpi_video_bus *video; 21514ca7a47SHans de Goede struct acpi_device *dev; 21614ca7a47SHans de Goede struct acpi_video_device_brightness *brightness; 21714ca7a47SHans de Goede struct backlight_device *backlight; 21814ca7a47SHans de Goede struct thermal_cooling_device *cooling_dev; 21914ca7a47SHans de Goede }; 22014ca7a47SHans de Goede 22114ca7a47SHans de Goede static void acpi_video_device_notify(acpi_handle handle, u32 event, void *data); 22214ca7a47SHans de Goede static void acpi_video_device_rebind(struct acpi_video_bus *video); 22314ca7a47SHans de Goede static void acpi_video_device_bind(struct acpi_video_bus *video, 22414ca7a47SHans de Goede struct acpi_video_device *device); 22514ca7a47SHans de Goede static int acpi_video_device_enumerate(struct acpi_video_bus *video); 22614ca7a47SHans de Goede static int acpi_video_device_lcd_set_level(struct acpi_video_device *device, 22714ca7a47SHans de Goede int level); 22814ca7a47SHans de Goede static int acpi_video_device_lcd_get_level_current( 22914ca7a47SHans de Goede struct acpi_video_device *device, 23014ca7a47SHans de Goede unsigned long long *level, bool raw); 23114ca7a47SHans de Goede static int acpi_video_get_next_level(struct acpi_video_device *device, 23214ca7a47SHans de Goede u32 level_current, u32 event); 23314ca7a47SHans de Goede static void acpi_video_switch_brightness(struct work_struct *work); 23414ca7a47SHans de Goede 23514ca7a47SHans de Goede /* backlight device sysfs support */ 23614ca7a47SHans de Goede static int acpi_video_get_brightness(struct backlight_device *bd) 23714ca7a47SHans de Goede { 23814ca7a47SHans de Goede unsigned long long cur_level; 23914ca7a47SHans de Goede int i; 24014ca7a47SHans de Goede struct acpi_video_device *vd = bl_get_data(bd); 24114ca7a47SHans de Goede 24214ca7a47SHans de Goede if (acpi_video_device_lcd_get_level_current(vd, &cur_level, false)) 24314ca7a47SHans de Goede return -EINVAL; 244d485ef43SDmitry Frank for (i = ACPI_VIDEO_FIRST_LEVEL; i < vd->brightness->count; i++) { 24514ca7a47SHans de Goede if (vd->brightness->levels[i] == cur_level) 246d485ef43SDmitry Frank return i - ACPI_VIDEO_FIRST_LEVEL; 24714ca7a47SHans de Goede } 24814ca7a47SHans de Goede return 0; 24914ca7a47SHans de Goede } 25014ca7a47SHans de Goede 25114ca7a47SHans de Goede static int acpi_video_set_brightness(struct backlight_device *bd) 25214ca7a47SHans de Goede { 253d485ef43SDmitry Frank int request_level = bd->props.brightness + ACPI_VIDEO_FIRST_LEVEL; 25414ca7a47SHans de Goede struct acpi_video_device *vd = bl_get_data(bd); 25514ca7a47SHans de Goede 25614ca7a47SHans de Goede cancel_delayed_work(&vd->switch_brightness_work); 25714ca7a47SHans de Goede return acpi_video_device_lcd_set_level(vd, 25814ca7a47SHans de Goede vd->brightness->levels[request_level]); 25914ca7a47SHans de Goede } 26014ca7a47SHans de Goede 26114ca7a47SHans de Goede static const struct backlight_ops acpi_backlight_ops = { 26214ca7a47SHans de Goede .get_brightness = acpi_video_get_brightness, 26314ca7a47SHans de Goede .update_status = acpi_video_set_brightness, 26414ca7a47SHans de Goede }; 26514ca7a47SHans de Goede 26614ca7a47SHans de Goede /* thermal cooling device callbacks */ 267d485ef43SDmitry Frank static int video_get_max_state(struct thermal_cooling_device *cooling_dev, 268d485ef43SDmitry Frank unsigned long *state) 26914ca7a47SHans de Goede { 27014ca7a47SHans de Goede struct acpi_device *device = cooling_dev->devdata; 27114ca7a47SHans de Goede struct acpi_video_device *video = acpi_driver_data(device); 27214ca7a47SHans de Goede 273d485ef43SDmitry Frank *state = video->brightness->count - ACPI_VIDEO_FIRST_LEVEL - 1; 27414ca7a47SHans de Goede return 0; 27514ca7a47SHans de Goede } 27614ca7a47SHans de Goede 277d485ef43SDmitry Frank static int video_get_cur_state(struct thermal_cooling_device *cooling_dev, 278d485ef43SDmitry Frank unsigned long *state) 27914ca7a47SHans de Goede { 28014ca7a47SHans de Goede struct acpi_device *device = cooling_dev->devdata; 28114ca7a47SHans de Goede struct acpi_video_device *video = acpi_driver_data(device); 28214ca7a47SHans de Goede unsigned long long level; 28314ca7a47SHans de Goede int offset; 28414ca7a47SHans de Goede 28514ca7a47SHans de Goede if (acpi_video_device_lcd_get_level_current(video, &level, false)) 28614ca7a47SHans de Goede return -EINVAL; 287d485ef43SDmitry Frank for (offset = ACPI_VIDEO_FIRST_LEVEL; offset < video->brightness->count; 288d485ef43SDmitry Frank offset++) 28914ca7a47SHans de Goede if (level == video->brightness->levels[offset]) { 29014ca7a47SHans de Goede *state = video->brightness->count - offset - 1; 29114ca7a47SHans de Goede return 0; 29214ca7a47SHans de Goede } 29314ca7a47SHans de Goede 29414ca7a47SHans de Goede return -EINVAL; 29514ca7a47SHans de Goede } 29614ca7a47SHans de Goede 29714ca7a47SHans de Goede static int 29814ca7a47SHans de Goede video_set_cur_state(struct thermal_cooling_device *cooling_dev, unsigned long state) 29914ca7a47SHans de Goede { 30014ca7a47SHans de Goede struct acpi_device *device = cooling_dev->devdata; 30114ca7a47SHans de Goede struct acpi_video_device *video = acpi_driver_data(device); 30214ca7a47SHans de Goede int level; 30314ca7a47SHans de Goede 304d485ef43SDmitry Frank if (state >= video->brightness->count - ACPI_VIDEO_FIRST_LEVEL) 30514ca7a47SHans de Goede return -EINVAL; 30614ca7a47SHans de Goede 30714ca7a47SHans de Goede state = video->brightness->count - state; 30814ca7a47SHans de Goede level = video->brightness->levels[state - 1]; 30914ca7a47SHans de Goede return acpi_video_device_lcd_set_level(video, level); 31014ca7a47SHans de Goede } 31114ca7a47SHans de Goede 31214ca7a47SHans de Goede static const struct thermal_cooling_device_ops video_cooling_ops = { 31314ca7a47SHans de Goede .get_max_state = video_get_max_state, 31414ca7a47SHans de Goede .get_cur_state = video_get_cur_state, 31514ca7a47SHans de Goede .set_cur_state = video_set_cur_state, 31614ca7a47SHans de Goede }; 31714ca7a47SHans de Goede 31814ca7a47SHans de Goede /* 31914ca7a47SHans de Goede * -------------------------------------------------------------------------- 32014ca7a47SHans de Goede * Video Management 32114ca7a47SHans de Goede * -------------------------------------------------------------------------- 32214ca7a47SHans de Goede */ 32314ca7a47SHans de Goede 32414ca7a47SHans de Goede static int 32505950094SAaron Lu acpi_video_device_lcd_query_levels(acpi_handle handle, 32614ca7a47SHans de Goede union acpi_object **levels) 32714ca7a47SHans de Goede { 32814ca7a47SHans de Goede int status; 32914ca7a47SHans de Goede struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; 33014ca7a47SHans de Goede union acpi_object *obj; 33114ca7a47SHans de Goede 33214ca7a47SHans de Goede 33314ca7a47SHans de Goede *levels = NULL; 33414ca7a47SHans de Goede 33505950094SAaron Lu status = acpi_evaluate_object(handle, "_BCL", NULL, &buffer); 3362924d2f8SRafael J. Wysocki if (ACPI_FAILURE(status)) 33714ca7a47SHans de Goede return status; 33814ca7a47SHans de Goede obj = (union acpi_object *)buffer.pointer; 33914ca7a47SHans de Goede if (!obj || (obj->type != ACPI_TYPE_PACKAGE)) { 3402924d2f8SRafael J. Wysocki acpi_handle_info(handle, "Invalid _BCL data\n"); 34114ca7a47SHans de Goede status = -EFAULT; 34214ca7a47SHans de Goede goto err; 34314ca7a47SHans de Goede } 34414ca7a47SHans de Goede 34514ca7a47SHans de Goede *levels = obj; 34614ca7a47SHans de Goede 34714ca7a47SHans de Goede return 0; 34814ca7a47SHans de Goede 34914ca7a47SHans de Goede err: 35014ca7a47SHans de Goede kfree(buffer.pointer); 35114ca7a47SHans de Goede 35214ca7a47SHans de Goede return status; 35314ca7a47SHans de Goede } 35414ca7a47SHans de Goede 35514ca7a47SHans de Goede static int 35614ca7a47SHans de Goede acpi_video_device_lcd_set_level(struct acpi_video_device *device, int level) 35714ca7a47SHans de Goede { 35814ca7a47SHans de Goede int status; 35914ca7a47SHans de Goede int state; 36014ca7a47SHans de Goede 36114ca7a47SHans de Goede status = acpi_execute_simple_method(device->dev->handle, 36214ca7a47SHans de Goede "_BCM", level); 36314ca7a47SHans de Goede if (ACPI_FAILURE(status)) { 3642924d2f8SRafael J. Wysocki acpi_handle_info(device->dev->handle, "_BCM evaluation failed\n"); 36514ca7a47SHans de Goede return -EIO; 36614ca7a47SHans de Goede } 36714ca7a47SHans de Goede 36814ca7a47SHans de Goede device->brightness->curr = level; 369d485ef43SDmitry Frank for (state = ACPI_VIDEO_FIRST_LEVEL; state < device->brightness->count; 370d485ef43SDmitry Frank state++) 37114ca7a47SHans de Goede if (level == device->brightness->levels[state]) { 37214ca7a47SHans de Goede if (device->backlight) 373d485ef43SDmitry Frank device->backlight->props.brightness = 374d485ef43SDmitry Frank state - ACPI_VIDEO_FIRST_LEVEL; 37514ca7a47SHans de Goede return 0; 37614ca7a47SHans de Goede } 37714ca7a47SHans de Goede 3782924d2f8SRafael J. Wysocki acpi_handle_info(device->dev->handle, "Current brightness invalid\n"); 37914ca7a47SHans de Goede return -EINVAL; 38014ca7a47SHans de Goede } 38114ca7a47SHans de Goede 38214ca7a47SHans de Goede /* 38314ca7a47SHans de Goede * For some buggy _BQC methods, we need to add a constant value to 38414ca7a47SHans de Goede * the _BQC return value to get the actual current brightness level 38514ca7a47SHans de Goede */ 38614ca7a47SHans de Goede 38714ca7a47SHans de Goede static int bqc_offset_aml_bug_workaround; 3887ee33baaSHans de Goede static int video_set_bqc_offset(const struct dmi_system_id *d) 38914ca7a47SHans de Goede { 39014ca7a47SHans de Goede bqc_offset_aml_bug_workaround = 9; 39114ca7a47SHans de Goede return 0; 39214ca7a47SHans de Goede } 39314ca7a47SHans de Goede 394e50b9be1SAaron Lu static int video_set_device_id_scheme(const struct dmi_system_id *d) 395e50b9be1SAaron Lu { 396e50b9be1SAaron Lu device_id_scheme = true; 397e50b9be1SAaron Lu return 0; 398e50b9be1SAaron Lu } 399e50b9be1SAaron Lu 400e50b9be1SAaron Lu static int video_enable_only_lcd(const struct dmi_system_id *d) 401e50b9be1SAaron Lu { 402e50b9be1SAaron Lu only_lcd = true; 403e50b9be1SAaron Lu return 0; 404e50b9be1SAaron Lu } 405e50b9be1SAaron Lu 4064b4b3b20SHans de Goede static int video_set_report_key_events(const struct dmi_system_id *id) 4074b4b3b20SHans de Goede { 4084b4b3b20SHans de Goede if (report_key_events == -1) 4094b4b3b20SHans de Goede report_key_events = (uintptr_t)id->driver_data; 4104b4b3b20SHans de Goede return 0; 4114b4b3b20SHans de Goede } 4124b4b3b20SHans de Goede 4134f7f9645SHans de Goede static int video_hw_changes_brightness( 4144f7f9645SHans de Goede const struct dmi_system_id *d) 4154f7f9645SHans de Goede { 4164f7f9645SHans de Goede if (hw_changes_brightness == -1) 4174f7f9645SHans de Goede hw_changes_brightness = 1; 4184f7f9645SHans de Goede return 0; 4194f7f9645SHans de Goede } 4204f7f9645SHans de Goede 4216faadbbbSChristoph Hellwig static const struct dmi_system_id video_dmi_table[] = { 42214ca7a47SHans de Goede /* 42314ca7a47SHans de Goede * Broken _BQC workaround http://bugzilla.kernel.org/show_bug.cgi?id=13121 42414ca7a47SHans de Goede */ 42514ca7a47SHans de Goede { 42614ca7a47SHans de Goede .callback = video_set_bqc_offset, 42714ca7a47SHans de Goede .ident = "Acer Aspire 5720", 42814ca7a47SHans de Goede .matches = { 42914ca7a47SHans de Goede DMI_MATCH(DMI_BOARD_VENDOR, "Acer"), 43014ca7a47SHans de Goede DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5720"), 43114ca7a47SHans de Goede }, 43214ca7a47SHans de Goede }, 43314ca7a47SHans de Goede { 43414ca7a47SHans de Goede .callback = video_set_bqc_offset, 43514ca7a47SHans de Goede .ident = "Acer Aspire 5710Z", 43614ca7a47SHans de Goede .matches = { 43714ca7a47SHans de Goede DMI_MATCH(DMI_BOARD_VENDOR, "Acer"), 43814ca7a47SHans de Goede DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5710Z"), 43914ca7a47SHans de Goede }, 44014ca7a47SHans de Goede }, 44114ca7a47SHans de Goede { 44214ca7a47SHans de Goede .callback = video_set_bqc_offset, 44314ca7a47SHans de Goede .ident = "eMachines E510", 44414ca7a47SHans de Goede .matches = { 44514ca7a47SHans de Goede DMI_MATCH(DMI_BOARD_VENDOR, "EMACHINES"), 44614ca7a47SHans de Goede DMI_MATCH(DMI_PRODUCT_NAME, "eMachines E510"), 44714ca7a47SHans de Goede }, 44814ca7a47SHans de Goede }, 44914ca7a47SHans de Goede { 45014ca7a47SHans de Goede .callback = video_set_bqc_offset, 45114ca7a47SHans de Goede .ident = "Acer Aspire 5315", 45214ca7a47SHans de Goede .matches = { 45314ca7a47SHans de Goede DMI_MATCH(DMI_BOARD_VENDOR, "Acer"), 45414ca7a47SHans de Goede DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5315"), 45514ca7a47SHans de Goede }, 45614ca7a47SHans de Goede }, 45714ca7a47SHans de Goede { 45814ca7a47SHans de Goede .callback = video_set_bqc_offset, 45914ca7a47SHans de Goede .ident = "Acer Aspire 7720", 46014ca7a47SHans de Goede .matches = { 46114ca7a47SHans de Goede DMI_MATCH(DMI_BOARD_VENDOR, "Acer"), 46214ca7a47SHans de Goede DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 7720"), 46314ca7a47SHans de Goede }, 46414ca7a47SHans de Goede }, 46514ca7a47SHans de Goede 46614ca7a47SHans de Goede /* 467e50b9be1SAaron Lu * Some machine's _DOD IDs don't have bit 31(Device ID Scheme) set 468e50b9be1SAaron Lu * but the IDs actually follow the Device ID Scheme. 469e50b9be1SAaron Lu */ 470e50b9be1SAaron Lu { 471e50b9be1SAaron Lu /* https://bugzilla.kernel.org/show_bug.cgi?id=104121 */ 472e50b9be1SAaron Lu .callback = video_set_device_id_scheme, 473e50b9be1SAaron Lu .ident = "ESPRIMO Mobile M9410", 474e50b9be1SAaron Lu .matches = { 475e50b9be1SAaron Lu DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"), 476e50b9be1SAaron Lu DMI_MATCH(DMI_PRODUCT_NAME, "ESPRIMO Mobile M9410"), 477e50b9be1SAaron Lu }, 478e50b9be1SAaron Lu }, 479e50b9be1SAaron Lu /* 480e50b9be1SAaron Lu * Some machines have multiple video output devices, but only the one 481e50b9be1SAaron Lu * that is the type of LCD can do the backlight control so we should not 482e50b9be1SAaron Lu * register backlight interface for other video output devices. 483e50b9be1SAaron Lu */ 484e50b9be1SAaron Lu { 485e50b9be1SAaron Lu /* https://bugzilla.kernel.org/show_bug.cgi?id=104121 */ 486e50b9be1SAaron Lu .callback = video_enable_only_lcd, 487e50b9be1SAaron Lu .ident = "ESPRIMO Mobile M9410", 488e50b9be1SAaron Lu .matches = { 489e50b9be1SAaron Lu DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"), 490e50b9be1SAaron Lu DMI_MATCH(DMI_PRODUCT_NAME, "ESPRIMO Mobile M9410"), 491e50b9be1SAaron Lu }, 492e50b9be1SAaron Lu }, 4934b4b3b20SHans de Goede /* 4944b4b3b20SHans de Goede * Some machines report wrong key events on the acpi-bus, suppress 4954b4b3b20SHans de Goede * key event reporting on these. Note this is only intended to work 4964b4b3b20SHans de Goede * around events which are plain wrong. In some cases we get double 4974b4b3b20SHans de Goede * events, in this case acpi-video is considered the canonical source 4984b4b3b20SHans de Goede * and the events from the other source should be filtered. E.g. 4994b4b3b20SHans de Goede * by calling acpi_video_handles_brightness_key_presses() from the 5004b4b3b20SHans de Goede * vendor acpi/wmi driver or by using /lib/udev/hwdb.d/60-keyboard.hwdb 5014b4b3b20SHans de Goede */ 5024b4b3b20SHans de Goede { 5034b4b3b20SHans de Goede .callback = video_set_report_key_events, 5044b4b3b20SHans de Goede .driver_data = (void *)((uintptr_t)REPORT_OUTPUT_KEY_EVENTS), 5054b4b3b20SHans de Goede .ident = "Dell Vostro V131", 5064b4b3b20SHans de Goede .matches = { 5074b4b3b20SHans de Goede DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), 5084b4b3b20SHans de Goede DMI_MATCH(DMI_PRODUCT_NAME, "Vostro V131"), 5094b4b3b20SHans de Goede }, 5104b4b3b20SHans de Goede }, 5119249c32eSHans de Goede { 5129249c32eSHans de Goede .callback = video_set_report_key_events, 5139249c32eSHans de Goede .driver_data = (void *)((uintptr_t)REPORT_BRIGHTNESS_KEY_EVENTS), 5149249c32eSHans de Goede .ident = "Dell Vostro 3350", 5159249c32eSHans de Goede .matches = { 5169249c32eSHans de Goede DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), 5179249c32eSHans de Goede DMI_MATCH(DMI_PRODUCT_NAME, "Vostro 3350"), 5189249c32eSHans de Goede }, 5199249c32eSHans de Goede }, 5204f7f9645SHans de Goede /* 5214f7f9645SHans de Goede * Some machines change the brightness themselves when a brightness 5224f7f9645SHans de Goede * hotkey gets pressed, despite us telling them not to. In this case 5234f7f9645SHans de Goede * acpi_video_device_notify() should only call backlight_force_update( 5244f7f9645SHans de Goede * BACKLIGHT_UPDATE_HOTKEY) and not do anything else. 5254f7f9645SHans de Goede */ 5264f7f9645SHans de Goede { 5274f7f9645SHans de Goede /* https://bugzilla.kernel.org/show_bug.cgi?id=204077 */ 5284f7f9645SHans de Goede .callback = video_hw_changes_brightness, 5294f7f9645SHans de Goede .ident = "Packard Bell EasyNote MZ35", 5304f7f9645SHans de Goede .matches = { 5314f7f9645SHans de Goede DMI_MATCH(DMI_SYS_VENDOR, "Packard Bell"), 5324f7f9645SHans de Goede DMI_MATCH(DMI_PRODUCT_NAME, "EasyNote MZ35"), 5334f7f9645SHans de Goede }, 5344f7f9645SHans de Goede }, 53514ca7a47SHans de Goede {} 53614ca7a47SHans de Goede }; 53714ca7a47SHans de Goede 53814ca7a47SHans de Goede static unsigned long long 53914ca7a47SHans de Goede acpi_video_bqc_value_to_level(struct acpi_video_device *device, 54014ca7a47SHans de Goede unsigned long long bqc_value) 54114ca7a47SHans de Goede { 54214ca7a47SHans de Goede unsigned long long level; 54314ca7a47SHans de Goede 54414ca7a47SHans de Goede if (device->brightness->flags._BQC_use_index) { 54514ca7a47SHans de Goede /* 546d485ef43SDmitry Frank * _BQC returns an index that doesn't account for the first 2 547d485ef43SDmitry Frank * items with special meaning (see enum acpi_video_level_idx), 548d485ef43SDmitry Frank * so we need to compensate for that by offsetting ourselves 54914ca7a47SHans de Goede */ 55014ca7a47SHans de Goede if (device->brightness->flags._BCL_reversed) 551d485ef43SDmitry Frank bqc_value = device->brightness->count - 552d485ef43SDmitry Frank ACPI_VIDEO_FIRST_LEVEL - 1 - bqc_value; 55314ca7a47SHans de Goede 554d485ef43SDmitry Frank level = device->brightness->levels[bqc_value + 555d485ef43SDmitry Frank ACPI_VIDEO_FIRST_LEVEL]; 55614ca7a47SHans de Goede } else { 55714ca7a47SHans de Goede level = bqc_value; 55814ca7a47SHans de Goede } 55914ca7a47SHans de Goede 56014ca7a47SHans de Goede level += bqc_offset_aml_bug_workaround; 56114ca7a47SHans de Goede 56214ca7a47SHans de Goede return level; 56314ca7a47SHans de Goede } 56414ca7a47SHans de Goede 56514ca7a47SHans de Goede static int 56614ca7a47SHans de Goede acpi_video_device_lcd_get_level_current(struct acpi_video_device *device, 56714ca7a47SHans de Goede unsigned long long *level, bool raw) 56814ca7a47SHans de Goede { 56914ca7a47SHans de Goede acpi_status status = AE_OK; 57014ca7a47SHans de Goede int i; 57114ca7a47SHans de Goede 57214ca7a47SHans de Goede if (device->cap._BQC || device->cap._BCQ) { 57314ca7a47SHans de Goede char *buf = device->cap._BQC ? "_BQC" : "_BCQ"; 57414ca7a47SHans de Goede 57514ca7a47SHans de Goede status = acpi_evaluate_integer(device->dev->handle, buf, 57614ca7a47SHans de Goede NULL, level); 57714ca7a47SHans de Goede if (ACPI_SUCCESS(status)) { 57814ca7a47SHans de Goede if (raw) { 57914ca7a47SHans de Goede /* 58014ca7a47SHans de Goede * Caller has indicated he wants the raw 58114ca7a47SHans de Goede * value returned by _BQC, so don't furtherly 58214ca7a47SHans de Goede * mess with the value. 58314ca7a47SHans de Goede */ 58414ca7a47SHans de Goede return 0; 58514ca7a47SHans de Goede } 58614ca7a47SHans de Goede 58714ca7a47SHans de Goede *level = acpi_video_bqc_value_to_level(device, *level); 58814ca7a47SHans de Goede 589d485ef43SDmitry Frank for (i = ACPI_VIDEO_FIRST_LEVEL; 590d485ef43SDmitry Frank i < device->brightness->count; i++) 59114ca7a47SHans de Goede if (device->brightness->levels[i] == *level) { 59214ca7a47SHans de Goede device->brightness->curr = *level; 59314ca7a47SHans de Goede return 0; 59414ca7a47SHans de Goede } 59514ca7a47SHans de Goede /* 59614ca7a47SHans de Goede * BQC returned an invalid level. 59714ca7a47SHans de Goede * Stop using it. 59814ca7a47SHans de Goede */ 5992924d2f8SRafael J. Wysocki acpi_handle_info(device->dev->handle, 6002924d2f8SRafael J. Wysocki "%s returned an invalid level", buf); 60114ca7a47SHans de Goede device->cap._BQC = device->cap._BCQ = 0; 60214ca7a47SHans de Goede } else { 60314ca7a47SHans de Goede /* 60414ca7a47SHans de Goede * Fixme: 60514ca7a47SHans de Goede * should we return an error or ignore this failure? 60614ca7a47SHans de Goede * dev->brightness->curr is a cached value which stores 60714ca7a47SHans de Goede * the correct current backlight level in most cases. 60814ca7a47SHans de Goede * ACPI video backlight still works w/ buggy _BQC. 60914ca7a47SHans de Goede * http://bugzilla.kernel.org/show_bug.cgi?id=12233 61014ca7a47SHans de Goede */ 6112924d2f8SRafael J. Wysocki acpi_handle_info(device->dev->handle, 6122924d2f8SRafael J. Wysocki "%s evaluation failed", buf); 61314ca7a47SHans de Goede device->cap._BQC = device->cap._BCQ = 0; 61414ca7a47SHans de Goede } 61514ca7a47SHans de Goede } 61614ca7a47SHans de Goede 61714ca7a47SHans de Goede *level = device->brightness->curr; 61814ca7a47SHans de Goede return 0; 61914ca7a47SHans de Goede } 62014ca7a47SHans de Goede 62114ca7a47SHans de Goede static int 62214ca7a47SHans de Goede acpi_video_device_EDID(struct acpi_video_device *device, 62314ca7a47SHans de Goede union acpi_object **edid, ssize_t length) 62414ca7a47SHans de Goede { 62514ca7a47SHans de Goede int status; 62614ca7a47SHans de Goede struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; 62714ca7a47SHans de Goede union acpi_object *obj; 62814ca7a47SHans de Goede union acpi_object arg0 = { ACPI_TYPE_INTEGER }; 62914ca7a47SHans de Goede struct acpi_object_list args = { 1, &arg0 }; 63014ca7a47SHans de Goede 63114ca7a47SHans de Goede 63214ca7a47SHans de Goede *edid = NULL; 63314ca7a47SHans de Goede 63414ca7a47SHans de Goede if (!device) 63514ca7a47SHans de Goede return -ENODEV; 63614ca7a47SHans de Goede if (length == 128) 63714ca7a47SHans de Goede arg0.integer.value = 1; 63814ca7a47SHans de Goede else if (length == 256) 63914ca7a47SHans de Goede arg0.integer.value = 2; 64014ca7a47SHans de Goede else 64114ca7a47SHans de Goede return -EINVAL; 64214ca7a47SHans de Goede 64314ca7a47SHans de Goede status = acpi_evaluate_object(device->dev->handle, "_DDC", &args, &buffer); 64414ca7a47SHans de Goede if (ACPI_FAILURE(status)) 64514ca7a47SHans de Goede return -ENODEV; 64614ca7a47SHans de Goede 64714ca7a47SHans de Goede obj = buffer.pointer; 64814ca7a47SHans de Goede 64914ca7a47SHans de Goede if (obj && obj->type == ACPI_TYPE_BUFFER) 65014ca7a47SHans de Goede *edid = obj; 65114ca7a47SHans de Goede else { 6522924d2f8SRafael J. Wysocki acpi_handle_info(device->dev->handle, "Invalid _DDC data\n"); 65314ca7a47SHans de Goede status = -EFAULT; 65414ca7a47SHans de Goede kfree(obj); 65514ca7a47SHans de Goede } 65614ca7a47SHans de Goede 65714ca7a47SHans de Goede return status; 65814ca7a47SHans de Goede } 65914ca7a47SHans de Goede 66014ca7a47SHans de Goede /* bus */ 66114ca7a47SHans de Goede 66214ca7a47SHans de Goede /* 66314ca7a47SHans de Goede * Arg: 66414ca7a47SHans de Goede * video : video bus device pointer 66514ca7a47SHans de Goede * bios_flag : 66614ca7a47SHans de Goede * 0. The system BIOS should NOT automatically switch(toggle) 66714ca7a47SHans de Goede * the active display output. 66814ca7a47SHans de Goede * 1. The system BIOS should automatically switch (toggle) the 66914ca7a47SHans de Goede * active display output. No switch event. 67014ca7a47SHans de Goede * 2. The _DGS value should be locked. 67114ca7a47SHans de Goede * 3. The system BIOS should not automatically switch (toggle) the 67214ca7a47SHans de Goede * active display output, but instead generate the display switch 67314ca7a47SHans de Goede * event notify code. 67414ca7a47SHans de Goede * lcd_flag : 67514ca7a47SHans de Goede * 0. The system BIOS should automatically control the brightness level 676b5b42b24SKacper Piwiński * of the LCD when: 677b5b42b24SKacper Piwiński * - the power changes from AC to DC (ACPI appendix B) 678b5b42b24SKacper Piwiński * - a brightness hotkey gets pressed (implied by Win7/8 backlight docs) 67914ca7a47SHans de Goede * 1. The system BIOS should NOT automatically control the brightness 680b5b42b24SKacper Piwiński * level of the LCD when: 681b5b42b24SKacper Piwiński * - the power changes from AC to DC (ACPI appendix B) 682b5b42b24SKacper Piwiński * - a brightness hotkey gets pressed (implied by Win7/8 backlight docs) 68314ca7a47SHans de Goede * Return Value: 68414ca7a47SHans de Goede * -EINVAL wrong arg. 68514ca7a47SHans de Goede */ 68614ca7a47SHans de Goede 68714ca7a47SHans de Goede static int 68814ca7a47SHans de Goede acpi_video_bus_DOS(struct acpi_video_bus *video, int bios_flag, int lcd_flag) 68914ca7a47SHans de Goede { 69014ca7a47SHans de Goede acpi_status status; 69114ca7a47SHans de Goede 69214ca7a47SHans de Goede if (!video->cap._DOS) 69314ca7a47SHans de Goede return 0; 69414ca7a47SHans de Goede 69514ca7a47SHans de Goede if (bios_flag < 0 || bios_flag > 3 || lcd_flag < 0 || lcd_flag > 1) 69614ca7a47SHans de Goede return -EINVAL; 69714ca7a47SHans de Goede video->dos_setting = (lcd_flag << 2) | bios_flag; 69814ca7a47SHans de Goede status = acpi_execute_simple_method(video->device->handle, "_DOS", 69914ca7a47SHans de Goede (lcd_flag << 2) | bios_flag); 70014ca7a47SHans de Goede if (ACPI_FAILURE(status)) 70114ca7a47SHans de Goede return -EIO; 70214ca7a47SHans de Goede 70314ca7a47SHans de Goede return 0; 70414ca7a47SHans de Goede } 70514ca7a47SHans de Goede 70614ca7a47SHans de Goede /* 70714ca7a47SHans de Goede * Simple comparison function used to sort backlight levels. 70814ca7a47SHans de Goede */ 70914ca7a47SHans de Goede 71014ca7a47SHans de Goede static int 71114ca7a47SHans de Goede acpi_video_cmp_level(const void *a, const void *b) 71214ca7a47SHans de Goede { 71314ca7a47SHans de Goede return *(int *)a - *(int *)b; 71414ca7a47SHans de Goede } 71514ca7a47SHans de Goede 71614ca7a47SHans de Goede /* 71714ca7a47SHans de Goede * Decides if _BQC/_BCQ for this system is usable 71814ca7a47SHans de Goede * 71914ca7a47SHans de Goede * We do this by changing the level first and then read out the current 72014ca7a47SHans de Goede * brightness level, if the value does not match, find out if it is using 72114ca7a47SHans de Goede * index. If not, clear the _BQC/_BCQ capability. 72214ca7a47SHans de Goede */ 72314ca7a47SHans de Goede static int acpi_video_bqc_quirk(struct acpi_video_device *device, 72414ca7a47SHans de Goede int max_level, int current_level) 72514ca7a47SHans de Goede { 72614ca7a47SHans de Goede struct acpi_video_device_brightness *br = device->brightness; 72714ca7a47SHans de Goede int result; 72814ca7a47SHans de Goede unsigned long long level; 72914ca7a47SHans de Goede int test_level; 73014ca7a47SHans de Goede 73114ca7a47SHans de Goede /* don't mess with existing known broken systems */ 73214ca7a47SHans de Goede if (bqc_offset_aml_bug_workaround) 73314ca7a47SHans de Goede return 0; 73414ca7a47SHans de Goede 73514ca7a47SHans de Goede /* 73614ca7a47SHans de Goede * Some systems always report current brightness level as maximum 737592c8095SDmitry Frank * through _BQC, we need to test another value for them. However, 738592c8095SDmitry Frank * there is a subtlety: 739592c8095SDmitry Frank * 740592c8095SDmitry Frank * If the _BCL package ordering is descending, the first level 741592c8095SDmitry Frank * (br->levels[2]) is likely to be 0, and if the number of levels 742592c8095SDmitry Frank * matches the number of steps, we might confuse a returned level to 743592c8095SDmitry Frank * mean the index. 744592c8095SDmitry Frank * 745592c8095SDmitry Frank * For example: 746592c8095SDmitry Frank * 747592c8095SDmitry Frank * current_level = max_level = 100 748592c8095SDmitry Frank * test_level = 0 749592c8095SDmitry Frank * returned level = 100 750592c8095SDmitry Frank * 751592c8095SDmitry Frank * In this case 100 means the level, not the index, and _BCM failed. 752592c8095SDmitry Frank * Still, if the _BCL package ordering is descending, the index of 753592c8095SDmitry Frank * level 0 is also 100, so we assume _BQC is indexed, when it's not. 754592c8095SDmitry Frank * 755592c8095SDmitry Frank * This causes all _BQC calls to return bogus values causing weird 756592c8095SDmitry Frank * behavior from the user's perspective. For example: 757592c8095SDmitry Frank * 758592c8095SDmitry Frank * xbacklight -set 10; xbacklight -set 20; 759592c8095SDmitry Frank * 760592c8095SDmitry Frank * would flash to 90% and then slowly down to the desired level (20). 761592c8095SDmitry Frank * 762592c8095SDmitry Frank * The solution is simple; test anything other than the first level 763592c8095SDmitry Frank * (e.g. 1). 76414ca7a47SHans de Goede */ 765d485ef43SDmitry Frank test_level = current_level == max_level 766d485ef43SDmitry Frank ? br->levels[ACPI_VIDEO_FIRST_LEVEL + 1] 767d485ef43SDmitry Frank : max_level; 76814ca7a47SHans de Goede 76914ca7a47SHans de Goede result = acpi_video_device_lcd_set_level(device, test_level); 77014ca7a47SHans de Goede if (result) 77114ca7a47SHans de Goede return result; 77214ca7a47SHans de Goede 77314ca7a47SHans de Goede result = acpi_video_device_lcd_get_level_current(device, &level, true); 77414ca7a47SHans de Goede if (result) 77514ca7a47SHans de Goede return result; 77614ca7a47SHans de Goede 77714ca7a47SHans de Goede if (level != test_level) { 77814ca7a47SHans de Goede /* buggy _BQC found, need to find out if it uses index */ 77914ca7a47SHans de Goede if (level < br->count) { 78014ca7a47SHans de Goede if (br->flags._BCL_reversed) 781d485ef43SDmitry Frank level = br->count - ACPI_VIDEO_FIRST_LEVEL - 1 - level; 782d485ef43SDmitry Frank if (br->levels[level + ACPI_VIDEO_FIRST_LEVEL] == test_level) 78314ca7a47SHans de Goede br->flags._BQC_use_index = 1; 78414ca7a47SHans de Goede } 78514ca7a47SHans de Goede 78614ca7a47SHans de Goede if (!br->flags._BQC_use_index) 78714ca7a47SHans de Goede device->cap._BQC = device->cap._BCQ = 0; 78814ca7a47SHans de Goede } 78914ca7a47SHans de Goede 79014ca7a47SHans de Goede return 0; 79114ca7a47SHans de Goede } 79214ca7a47SHans de Goede 79305950094SAaron Lu int acpi_video_get_levels(struct acpi_device *device, 7949f9cd7eeSAaron Lu struct acpi_video_device_brightness **dev_br, 7959f9cd7eeSAaron Lu int *pmax_level) 79614ca7a47SHans de Goede { 79714ca7a47SHans de Goede union acpi_object *obj = NULL; 79814ca7a47SHans de Goede int i, max_level = 0, count = 0, level_ac_battery = 0; 79914ca7a47SHans de Goede union acpi_object *o; 80014ca7a47SHans de Goede struct acpi_video_device_brightness *br = NULL; 80105950094SAaron Lu int result = 0; 80214ca7a47SHans de Goede u32 value; 80314ca7a47SHans de Goede 8042924d2f8SRafael J. Wysocki if (ACPI_FAILURE(acpi_video_device_lcd_query_levels(device->handle, &obj))) { 8052924d2f8SRafael J. Wysocki acpi_handle_debug(device->handle, 8062924d2f8SRafael J. Wysocki "Could not query available LCD brightness level\n"); 80705950094SAaron Lu result = -ENODEV; 80814ca7a47SHans de Goede goto out; 80914ca7a47SHans de Goede } 81014ca7a47SHans de Goede 811d485ef43SDmitry Frank if (obj->package.count < ACPI_VIDEO_FIRST_LEVEL) { 81205950094SAaron Lu result = -EINVAL; 81314ca7a47SHans de Goede goto out; 81405950094SAaron Lu } 81514ca7a47SHans de Goede 81614ca7a47SHans de Goede br = kzalloc(sizeof(*br), GFP_KERNEL); 81714ca7a47SHans de Goede if (!br) { 81814ca7a47SHans de Goede result = -ENOMEM; 81914ca7a47SHans de Goede goto out; 82014ca7a47SHans de Goede } 82114ca7a47SHans de Goede 822592c8095SDmitry Frank /* 823592c8095SDmitry Frank * Note that we have to reserve 2 extra items (ACPI_VIDEO_FIRST_LEVEL), 824592c8095SDmitry Frank * in order to account for buggy BIOS which don't export the first two 825592c8095SDmitry Frank * special levels (see below) 826592c8095SDmitry Frank */ 8276da2ec56SKees Cook br->levels = kmalloc_array(obj->package.count + ACPI_VIDEO_FIRST_LEVEL, 8286da2ec56SKees Cook sizeof(*br->levels), 8296da2ec56SKees Cook GFP_KERNEL); 83014ca7a47SHans de Goede if (!br->levels) { 83114ca7a47SHans de Goede result = -ENOMEM; 83214ca7a47SHans de Goede goto out_free; 83314ca7a47SHans de Goede } 83414ca7a47SHans de Goede 83514ca7a47SHans de Goede for (i = 0; i < obj->package.count; i++) { 83614ca7a47SHans de Goede o = (union acpi_object *)&obj->package.elements[i]; 83714ca7a47SHans de Goede if (o->type != ACPI_TYPE_INTEGER) { 8382924d2f8SRafael J. Wysocki acpi_handle_info(device->handle, "Invalid data\n"); 83914ca7a47SHans de Goede continue; 84014ca7a47SHans de Goede } 84114ca7a47SHans de Goede value = (u32) o->integer.value; 84214ca7a47SHans de Goede /* Skip duplicate entries */ 843d485ef43SDmitry Frank if (count > ACPI_VIDEO_FIRST_LEVEL 844d485ef43SDmitry Frank && br->levels[count - 1] == value) 84514ca7a47SHans de Goede continue; 84614ca7a47SHans de Goede 84714ca7a47SHans de Goede br->levels[count] = value; 84814ca7a47SHans de Goede 84914ca7a47SHans de Goede if (br->levels[count] > max_level) 85014ca7a47SHans de Goede max_level = br->levels[count]; 85114ca7a47SHans de Goede count++; 85214ca7a47SHans de Goede } 85314ca7a47SHans de Goede 85414ca7a47SHans de Goede /* 85514ca7a47SHans de Goede * some buggy BIOS don't export the levels 85614ca7a47SHans de Goede * when machine is on AC/Battery in _BCL package. 85714ca7a47SHans de Goede * In this case, the first two elements in _BCL packages 85814ca7a47SHans de Goede * are also supported brightness levels that OS should take care of. 85914ca7a47SHans de Goede */ 860d485ef43SDmitry Frank for (i = ACPI_VIDEO_FIRST_LEVEL; i < count; i++) { 861d485ef43SDmitry Frank if (br->levels[i] == br->levels[ACPI_VIDEO_AC_LEVEL]) 86214ca7a47SHans de Goede level_ac_battery++; 863d485ef43SDmitry Frank if (br->levels[i] == br->levels[ACPI_VIDEO_BATTERY_LEVEL]) 86414ca7a47SHans de Goede level_ac_battery++; 86514ca7a47SHans de Goede } 86614ca7a47SHans de Goede 867d485ef43SDmitry Frank if (level_ac_battery < ACPI_VIDEO_FIRST_LEVEL) { 868d485ef43SDmitry Frank level_ac_battery = ACPI_VIDEO_FIRST_LEVEL - level_ac_battery; 86914ca7a47SHans de Goede br->flags._BCL_no_ac_battery_levels = 1; 870d485ef43SDmitry Frank for (i = (count - 1 + level_ac_battery); 871d485ef43SDmitry Frank i >= ACPI_VIDEO_FIRST_LEVEL; i--) 87214ca7a47SHans de Goede br->levels[i] = br->levels[i - level_ac_battery]; 87314ca7a47SHans de Goede count += level_ac_battery; 874d485ef43SDmitry Frank } else if (level_ac_battery > ACPI_VIDEO_FIRST_LEVEL) 8752924d2f8SRafael J. Wysocki acpi_handle_info(device->handle, 8762924d2f8SRafael J. Wysocki "Too many duplicates in _BCL package"); 87714ca7a47SHans de Goede 87814ca7a47SHans de Goede /* Check if the _BCL package is in a reversed order */ 879d485ef43SDmitry Frank if (max_level == br->levels[ACPI_VIDEO_FIRST_LEVEL]) { 88014ca7a47SHans de Goede br->flags._BCL_reversed = 1; 881d485ef43SDmitry Frank sort(&br->levels[ACPI_VIDEO_FIRST_LEVEL], 882d485ef43SDmitry Frank count - ACPI_VIDEO_FIRST_LEVEL, 883d485ef43SDmitry Frank sizeof(br->levels[ACPI_VIDEO_FIRST_LEVEL]), 88414ca7a47SHans de Goede acpi_video_cmp_level, NULL); 88514ca7a47SHans de Goede } else if (max_level != br->levels[count - 1]) 8862924d2f8SRafael J. Wysocki acpi_handle_info(device->handle, 8872924d2f8SRafael J. Wysocki "Found unordered _BCL package"); 88814ca7a47SHans de Goede 88914ca7a47SHans de Goede br->count = count; 89005950094SAaron Lu *dev_br = br; 8919f9cd7eeSAaron Lu if (pmax_level) 8929f9cd7eeSAaron Lu *pmax_level = max_level; 89305950094SAaron Lu 89405950094SAaron Lu out: 89505950094SAaron Lu kfree(obj); 89605950094SAaron Lu return result; 89705950094SAaron Lu out_free: 89805950094SAaron Lu kfree(br); 89905950094SAaron Lu goto out; 90005950094SAaron Lu } 90105950094SAaron Lu EXPORT_SYMBOL(acpi_video_get_levels); 90205950094SAaron Lu 90305950094SAaron Lu /* 90405950094SAaron Lu * Arg: 90505950094SAaron Lu * device : video output device (LCD, CRT, ..) 90605950094SAaron Lu * 90705950094SAaron Lu * Return Value: 90805950094SAaron Lu * Maximum brightness level 90905950094SAaron Lu * 91005950094SAaron Lu * Allocate and initialize device->brightness. 91105950094SAaron Lu */ 91205950094SAaron Lu 91305950094SAaron Lu static int 91405950094SAaron Lu acpi_video_init_brightness(struct acpi_video_device *device) 91505950094SAaron Lu { 91605950094SAaron Lu int i, max_level = 0; 91705950094SAaron Lu unsigned long long level, level_old; 91805950094SAaron Lu struct acpi_video_device_brightness *br = NULL; 919966f58dfSColin Ian King int result; 92005950094SAaron Lu 9219f9cd7eeSAaron Lu result = acpi_video_get_levels(device->dev, &br, &max_level); 92205950094SAaron Lu if (result) 92305950094SAaron Lu return result; 92414ca7a47SHans de Goede device->brightness = br; 92514ca7a47SHans de Goede 92614ca7a47SHans de Goede /* _BQC uses INDEX while _BCL uses VALUE in some laptops */ 92714ca7a47SHans de Goede br->curr = level = max_level; 92814ca7a47SHans de Goede 92914ca7a47SHans de Goede if (!device->cap._BQC) 93014ca7a47SHans de Goede goto set_level; 93114ca7a47SHans de Goede 93214ca7a47SHans de Goede result = acpi_video_device_lcd_get_level_current(device, 93314ca7a47SHans de Goede &level_old, true); 93414ca7a47SHans de Goede if (result) 93514ca7a47SHans de Goede goto out_free_levels; 93614ca7a47SHans de Goede 93714ca7a47SHans de Goede result = acpi_video_bqc_quirk(device, max_level, level_old); 93814ca7a47SHans de Goede if (result) 93914ca7a47SHans de Goede goto out_free_levels; 94014ca7a47SHans de Goede /* 94114ca7a47SHans de Goede * cap._BQC may get cleared due to _BQC is found to be broken 94214ca7a47SHans de Goede * in acpi_video_bqc_quirk, so check again here. 94314ca7a47SHans de Goede */ 94414ca7a47SHans de Goede if (!device->cap._BQC) 94514ca7a47SHans de Goede goto set_level; 94614ca7a47SHans de Goede 94714ca7a47SHans de Goede level = acpi_video_bqc_value_to_level(device, level_old); 94814ca7a47SHans de Goede /* 94914ca7a47SHans de Goede * On some buggy laptops, _BQC returns an uninitialized 95014ca7a47SHans de Goede * value when invoked for the first time, i.e. 95114ca7a47SHans de Goede * level_old is invalid (no matter whether it's a level 95214ca7a47SHans de Goede * or an index). Set the backlight to max_level in this case. 95314ca7a47SHans de Goede */ 954d485ef43SDmitry Frank for (i = ACPI_VIDEO_FIRST_LEVEL; i < br->count; i++) 95514ca7a47SHans de Goede if (level == br->levels[i]) 95614ca7a47SHans de Goede break; 95714ca7a47SHans de Goede if (i == br->count || !level) 95814ca7a47SHans de Goede level = max_level; 95914ca7a47SHans de Goede 96014ca7a47SHans de Goede set_level: 96114ca7a47SHans de Goede result = acpi_video_device_lcd_set_level(device, level); 96214ca7a47SHans de Goede if (result) 96314ca7a47SHans de Goede goto out_free_levels; 96414ca7a47SHans de Goede 9652924d2f8SRafael J. Wysocki acpi_handle_debug(device->dev->handle, "found %d brightness levels\n", 9662924d2f8SRafael J. Wysocki br->count - ACPI_VIDEO_FIRST_LEVEL); 9672924d2f8SRafael J. Wysocki 96805950094SAaron Lu return 0; 96914ca7a47SHans de Goede 97014ca7a47SHans de Goede out_free_levels: 97114ca7a47SHans de Goede kfree(br->levels); 97214ca7a47SHans de Goede kfree(br); 97314ca7a47SHans de Goede device->brightness = NULL; 97414ca7a47SHans de Goede return result; 97514ca7a47SHans de Goede } 97614ca7a47SHans de Goede 97714ca7a47SHans de Goede /* 97814ca7a47SHans de Goede * Arg: 97914ca7a47SHans de Goede * device : video output device (LCD, CRT, ..) 98014ca7a47SHans de Goede * 98114ca7a47SHans de Goede * Return Value: 98214ca7a47SHans de Goede * None 98314ca7a47SHans de Goede * 98414ca7a47SHans de Goede * Find out all required AML methods defined under the output 98514ca7a47SHans de Goede * device. 98614ca7a47SHans de Goede */ 98714ca7a47SHans de Goede 98814ca7a47SHans de Goede static void acpi_video_device_find_cap(struct acpi_video_device *device) 98914ca7a47SHans de Goede { 99014ca7a47SHans de Goede if (acpi_has_method(device->dev->handle, "_ADR")) 99114ca7a47SHans de Goede device->cap._ADR = 1; 99214ca7a47SHans de Goede if (acpi_has_method(device->dev->handle, "_BCL")) 99314ca7a47SHans de Goede device->cap._BCL = 1; 99414ca7a47SHans de Goede if (acpi_has_method(device->dev->handle, "_BCM")) 99514ca7a47SHans de Goede device->cap._BCM = 1; 99614ca7a47SHans de Goede if (acpi_has_method(device->dev->handle, "_BQC")) { 99714ca7a47SHans de Goede device->cap._BQC = 1; 99814ca7a47SHans de Goede } else if (acpi_has_method(device->dev->handle, "_BCQ")) { 9992924d2f8SRafael J. Wysocki acpi_handle_info(device->dev->handle, 10002924d2f8SRafael J. Wysocki "_BCQ is used instead of _BQC\n"); 100114ca7a47SHans de Goede device->cap._BCQ = 1; 100214ca7a47SHans de Goede } 100314ca7a47SHans de Goede 100414ca7a47SHans de Goede if (acpi_has_method(device->dev->handle, "_DDC")) 100514ca7a47SHans de Goede device->cap._DDC = 1; 100614ca7a47SHans de Goede } 100714ca7a47SHans de Goede 100814ca7a47SHans de Goede /* 100914ca7a47SHans de Goede * Arg: 101014ca7a47SHans de Goede * device : video output device (VGA) 101114ca7a47SHans de Goede * 101214ca7a47SHans de Goede * Return Value: 101314ca7a47SHans de Goede * None 101414ca7a47SHans de Goede * 101514ca7a47SHans de Goede * Find out all required AML methods defined under the video bus device. 101614ca7a47SHans de Goede */ 101714ca7a47SHans de Goede 101814ca7a47SHans de Goede static void acpi_video_bus_find_cap(struct acpi_video_bus *video) 101914ca7a47SHans de Goede { 102014ca7a47SHans de Goede if (acpi_has_method(video->device->handle, "_DOS")) 102114ca7a47SHans de Goede video->cap._DOS = 1; 102214ca7a47SHans de Goede if (acpi_has_method(video->device->handle, "_DOD")) 102314ca7a47SHans de Goede video->cap._DOD = 1; 102414ca7a47SHans de Goede if (acpi_has_method(video->device->handle, "_ROM")) 102514ca7a47SHans de Goede video->cap._ROM = 1; 102614ca7a47SHans de Goede if (acpi_has_method(video->device->handle, "_GPD")) 102714ca7a47SHans de Goede video->cap._GPD = 1; 102814ca7a47SHans de Goede if (acpi_has_method(video->device->handle, "_SPD")) 102914ca7a47SHans de Goede video->cap._SPD = 1; 103014ca7a47SHans de Goede if (acpi_has_method(video->device->handle, "_VPO")) 103114ca7a47SHans de Goede video->cap._VPO = 1; 103214ca7a47SHans de Goede } 103314ca7a47SHans de Goede 103414ca7a47SHans de Goede /* 103514ca7a47SHans de Goede * Check whether the video bus device has required AML method to 103614ca7a47SHans de Goede * support the desired features 103714ca7a47SHans de Goede */ 103814ca7a47SHans de Goede 103914ca7a47SHans de Goede static int acpi_video_bus_check(struct acpi_video_bus *video) 104014ca7a47SHans de Goede { 104114ca7a47SHans de Goede acpi_status status = -ENOENT; 104214ca7a47SHans de Goede struct pci_dev *dev; 104314ca7a47SHans de Goede 104414ca7a47SHans de Goede if (!video) 104514ca7a47SHans de Goede return -EINVAL; 104614ca7a47SHans de Goede 104714ca7a47SHans de Goede dev = acpi_get_pci_dev(video->device->handle); 104814ca7a47SHans de Goede if (!dev) 104914ca7a47SHans de Goede return -ENODEV; 105014ca7a47SHans de Goede pci_dev_put(dev); 105114ca7a47SHans de Goede 105214ca7a47SHans de Goede /* 105314ca7a47SHans de Goede * Since there is no HID, CID and so on for VGA driver, we have 105414ca7a47SHans de Goede * to check well known required nodes. 105514ca7a47SHans de Goede */ 105614ca7a47SHans de Goede 105714ca7a47SHans de Goede /* Does this device support video switching? */ 105814ca7a47SHans de Goede if (video->cap._DOS || video->cap._DOD) { 105914ca7a47SHans de Goede if (!video->cap._DOS) { 10602924d2f8SRafael J. Wysocki pr_info(FW_BUG "ACPI(%s) defines _DOD but not _DOS\n", 106114ca7a47SHans de Goede acpi_device_bid(video->device)); 106214ca7a47SHans de Goede } 106314ca7a47SHans de Goede video->flags.multihead = 1; 106414ca7a47SHans de Goede status = 0; 106514ca7a47SHans de Goede } 106614ca7a47SHans de Goede 106714ca7a47SHans de Goede /* Does this device support retrieving a video ROM? */ 106814ca7a47SHans de Goede if (video->cap._ROM) { 106914ca7a47SHans de Goede video->flags.rom = 1; 107014ca7a47SHans de Goede status = 0; 107114ca7a47SHans de Goede } 107214ca7a47SHans de Goede 107314ca7a47SHans de Goede /* Does this device support configuring which video device to POST? */ 107414ca7a47SHans de Goede if (video->cap._GPD && video->cap._SPD && video->cap._VPO) { 107514ca7a47SHans de Goede video->flags.post = 1; 107614ca7a47SHans de Goede status = 0; 107714ca7a47SHans de Goede } 107814ca7a47SHans de Goede 107914ca7a47SHans de Goede return status; 108014ca7a47SHans de Goede } 108114ca7a47SHans de Goede 108214ca7a47SHans de Goede /* 108314ca7a47SHans de Goede * -------------------------------------------------------------------------- 108414ca7a47SHans de Goede * Driver Interface 108514ca7a47SHans de Goede * -------------------------------------------------------------------------- 108614ca7a47SHans de Goede */ 108714ca7a47SHans de Goede 108814ca7a47SHans de Goede /* device interface */ 108914ca7a47SHans de Goede static struct acpi_video_device_attrib * 109014ca7a47SHans de Goede acpi_video_get_device_attr(struct acpi_video_bus *video, unsigned long device_id) 109114ca7a47SHans de Goede { 109214ca7a47SHans de Goede struct acpi_video_enumerated_device *ids; 109314ca7a47SHans de Goede int i; 109414ca7a47SHans de Goede 109514ca7a47SHans de Goede for (i = 0; i < video->attached_count; i++) { 109614ca7a47SHans de Goede ids = &video->attached_array[i]; 109714ca7a47SHans de Goede if ((ids->value.int_val & 0xffff) == device_id) 109814ca7a47SHans de Goede return &ids->value.attrib; 109914ca7a47SHans de Goede } 110014ca7a47SHans de Goede 110114ca7a47SHans de Goede return NULL; 110214ca7a47SHans de Goede } 110314ca7a47SHans de Goede 110414ca7a47SHans de Goede static int 110514ca7a47SHans de Goede acpi_video_get_device_type(struct acpi_video_bus *video, 110614ca7a47SHans de Goede unsigned long device_id) 110714ca7a47SHans de Goede { 110814ca7a47SHans de Goede struct acpi_video_enumerated_device *ids; 110914ca7a47SHans de Goede int i; 111014ca7a47SHans de Goede 111114ca7a47SHans de Goede for (i = 0; i < video->attached_count; i++) { 111214ca7a47SHans de Goede ids = &video->attached_array[i]; 111314ca7a47SHans de Goede if ((ids->value.int_val & 0xffff) == device_id) 111414ca7a47SHans de Goede return ids->value.int_val; 111514ca7a47SHans de Goede } 111614ca7a47SHans de Goede 111714ca7a47SHans de Goede return 0; 111814ca7a47SHans de Goede } 111914ca7a47SHans de Goede 11200ea3ef24SRafael J. Wysocki static int acpi_video_bus_get_one_device(struct acpi_device *device, void *arg) 112114ca7a47SHans de Goede { 11220ea3ef24SRafael J. Wysocki struct acpi_video_bus *video = arg; 112314ca7a47SHans de Goede struct acpi_video_device_attrib *attribute; 11240ea3ef24SRafael J. Wysocki struct acpi_video_device *data; 11250ea3ef24SRafael J. Wysocki unsigned long long device_id; 11260ea3ef24SRafael J. Wysocki acpi_status status; 11270ea3ef24SRafael J. Wysocki int device_type; 112814ca7a47SHans de Goede 11290ea3ef24SRafael J. Wysocki status = acpi_evaluate_integer(device->handle, "_ADR", NULL, &device_id); 11300ea3ef24SRafael J. Wysocki /* Skip devices without _ADR instead of failing. */ 113114ca7a47SHans de Goede if (ACPI_FAILURE(status)) 11320ea3ef24SRafael J. Wysocki goto exit; 113314ca7a47SHans de Goede 113414ca7a47SHans de Goede data = kzalloc(sizeof(struct acpi_video_device), GFP_KERNEL); 11350ea3ef24SRafael J. Wysocki if (!data) { 11360ea3ef24SRafael J. Wysocki dev_dbg(&device->dev, "Cannot attach\n"); 113714ca7a47SHans de Goede return -ENOMEM; 11380ea3ef24SRafael J. Wysocki } 113914ca7a47SHans de Goede 114014ca7a47SHans de Goede strcpy(acpi_device_name(device), ACPI_VIDEO_DEVICE_NAME); 114114ca7a47SHans de Goede strcpy(acpi_device_class(device), ACPI_VIDEO_CLASS); 114214ca7a47SHans de Goede device->driver_data = data; 114314ca7a47SHans de Goede 114414ca7a47SHans de Goede data->device_id = device_id; 114514ca7a47SHans de Goede data->video = video; 114614ca7a47SHans de Goede data->dev = device; 114714ca7a47SHans de Goede INIT_DELAYED_WORK(&data->switch_brightness_work, 114814ca7a47SHans de Goede acpi_video_switch_brightness); 114914ca7a47SHans de Goede 115014ca7a47SHans de Goede attribute = acpi_video_get_device_attr(video, device_id); 115114ca7a47SHans de Goede 1152e50b9be1SAaron Lu if (attribute && (attribute->device_id_scheme || device_id_scheme)) { 115314ca7a47SHans de Goede switch (attribute->display_type) { 115414ca7a47SHans de Goede case ACPI_VIDEO_DISPLAY_CRT: 115514ca7a47SHans de Goede data->flags.crt = 1; 115614ca7a47SHans de Goede break; 115714ca7a47SHans de Goede case ACPI_VIDEO_DISPLAY_TV: 115814ca7a47SHans de Goede data->flags.tvout = 1; 115914ca7a47SHans de Goede break; 116014ca7a47SHans de Goede case ACPI_VIDEO_DISPLAY_DVI: 116114ca7a47SHans de Goede data->flags.dvi = 1; 116214ca7a47SHans de Goede break; 116314ca7a47SHans de Goede case ACPI_VIDEO_DISPLAY_LCD: 116414ca7a47SHans de Goede data->flags.lcd = 1; 116514ca7a47SHans de Goede break; 116614ca7a47SHans de Goede default: 116714ca7a47SHans de Goede data->flags.unknown = 1; 116814ca7a47SHans de Goede break; 116914ca7a47SHans de Goede } 117014ca7a47SHans de Goede if (attribute->bios_can_detect) 117114ca7a47SHans de Goede data->flags.bios = 1; 117214ca7a47SHans de Goede } else { 117314ca7a47SHans de Goede /* Check for legacy IDs */ 117414ca7a47SHans de Goede device_type = acpi_video_get_device_type(video, device_id); 117514ca7a47SHans de Goede /* Ignore bits 16 and 18-20 */ 117614ca7a47SHans de Goede switch (device_type & 0xffe2ffff) { 117714ca7a47SHans de Goede case ACPI_VIDEO_DISPLAY_LEGACY_MONITOR: 117814ca7a47SHans de Goede data->flags.crt = 1; 117914ca7a47SHans de Goede break; 118014ca7a47SHans de Goede case ACPI_VIDEO_DISPLAY_LEGACY_PANEL: 118114ca7a47SHans de Goede data->flags.lcd = 1; 118214ca7a47SHans de Goede break; 118314ca7a47SHans de Goede case ACPI_VIDEO_DISPLAY_LEGACY_TV: 118414ca7a47SHans de Goede data->flags.tvout = 1; 118514ca7a47SHans de Goede break; 118614ca7a47SHans de Goede default: 118714ca7a47SHans de Goede data->flags.unknown = 1; 118814ca7a47SHans de Goede } 118914ca7a47SHans de Goede } 119014ca7a47SHans de Goede 119114ca7a47SHans de Goede acpi_video_device_bind(video, data); 119214ca7a47SHans de Goede acpi_video_device_find_cap(data); 119314ca7a47SHans de Goede 11943a0cf7abSHans de Goede if (data->cap._BCM && data->cap._BCL) 11955ad26161SHans de Goede may_report_brightness_keys = true; 11963a0cf7abSHans de Goede 119714ca7a47SHans de Goede mutex_lock(&video->device_list_lock); 119814ca7a47SHans de Goede list_add_tail(&data->entry, &video->video_device_list); 119914ca7a47SHans de Goede mutex_unlock(&video->device_list_lock); 120014ca7a47SHans de Goede 12010ea3ef24SRafael J. Wysocki exit: 12020ea3ef24SRafael J. Wysocki video->child_count++; 12030ea3ef24SRafael J. Wysocki return 0; 120414ca7a47SHans de Goede } 120514ca7a47SHans de Goede 120614ca7a47SHans de Goede /* 120714ca7a47SHans de Goede * Arg: 120814ca7a47SHans de Goede * video : video bus device 120914ca7a47SHans de Goede * 121014ca7a47SHans de Goede * Return: 121114ca7a47SHans de Goede * none 121214ca7a47SHans de Goede * 121314ca7a47SHans de Goede * Enumerate the video device list of the video bus, 121414ca7a47SHans de Goede * bind the ids with the corresponding video devices 121514ca7a47SHans de Goede * under the video bus. 121614ca7a47SHans de Goede */ 121714ca7a47SHans de Goede 121814ca7a47SHans de Goede static void acpi_video_device_rebind(struct acpi_video_bus *video) 121914ca7a47SHans de Goede { 122014ca7a47SHans de Goede struct acpi_video_device *dev; 122114ca7a47SHans de Goede 122214ca7a47SHans de Goede mutex_lock(&video->device_list_lock); 122314ca7a47SHans de Goede 122414ca7a47SHans de Goede list_for_each_entry(dev, &video->video_device_list, entry) 122514ca7a47SHans de Goede acpi_video_device_bind(video, dev); 122614ca7a47SHans de Goede 122714ca7a47SHans de Goede mutex_unlock(&video->device_list_lock); 122814ca7a47SHans de Goede } 122914ca7a47SHans de Goede 123014ca7a47SHans de Goede /* 123114ca7a47SHans de Goede * Arg: 123214ca7a47SHans de Goede * video : video bus device 123314ca7a47SHans de Goede * device : video output device under the video 123414ca7a47SHans de Goede * bus 123514ca7a47SHans de Goede * 123614ca7a47SHans de Goede * Return: 123714ca7a47SHans de Goede * none 123814ca7a47SHans de Goede * 123914ca7a47SHans de Goede * Bind the ids with the corresponding video devices 124014ca7a47SHans de Goede * under the video bus. 124114ca7a47SHans de Goede */ 124214ca7a47SHans de Goede 124314ca7a47SHans de Goede static void 124414ca7a47SHans de Goede acpi_video_device_bind(struct acpi_video_bus *video, 124514ca7a47SHans de Goede struct acpi_video_device *device) 124614ca7a47SHans de Goede { 124714ca7a47SHans de Goede struct acpi_video_enumerated_device *ids; 124814ca7a47SHans de Goede int i; 124914ca7a47SHans de Goede 125014ca7a47SHans de Goede for (i = 0; i < video->attached_count; i++) { 125114ca7a47SHans de Goede ids = &video->attached_array[i]; 125214ca7a47SHans de Goede if (device->device_id == (ids->value.int_val & 0xffff)) { 125314ca7a47SHans de Goede ids->bind_info = device; 12542924d2f8SRafael J. Wysocki acpi_handle_debug(video->device->handle, "%s: %d\n", 12552924d2f8SRafael J. Wysocki __func__, i); 125614ca7a47SHans de Goede } 125714ca7a47SHans de Goede } 125814ca7a47SHans de Goede } 125914ca7a47SHans de Goede 126014ca7a47SHans de Goede static bool acpi_video_device_in_dod(struct acpi_video_device *device) 126114ca7a47SHans de Goede { 126214ca7a47SHans de Goede struct acpi_video_bus *video = device->video; 126314ca7a47SHans de Goede int i; 126414ca7a47SHans de Goede 126514ca7a47SHans de Goede /* 126614ca7a47SHans de Goede * If we have a broken _DOD or we have more than 8 output devices 126714ca7a47SHans de Goede * under the graphics controller node that we can't proper deal with 126814ca7a47SHans de Goede * in the operation region code currently, no need to test. 126914ca7a47SHans de Goede */ 127014ca7a47SHans de Goede if (!video->attached_count || video->child_count > 8) 127114ca7a47SHans de Goede return true; 127214ca7a47SHans de Goede 127314ca7a47SHans de Goede for (i = 0; i < video->attached_count; i++) { 127414ca7a47SHans de Goede if ((video->attached_array[i].value.int_val & 0xfff) == 127514ca7a47SHans de Goede (device->device_id & 0xfff)) 127614ca7a47SHans de Goede return true; 127714ca7a47SHans de Goede } 127814ca7a47SHans de Goede 127914ca7a47SHans de Goede return false; 128014ca7a47SHans de Goede } 128114ca7a47SHans de Goede 128214ca7a47SHans de Goede /* 128314ca7a47SHans de Goede * Arg: 128414ca7a47SHans de Goede * video : video bus device 128514ca7a47SHans de Goede * 128614ca7a47SHans de Goede * Return: 128714ca7a47SHans de Goede * < 0 : error 128814ca7a47SHans de Goede * 128914ca7a47SHans de Goede * Call _DOD to enumerate all devices attached to display adapter 129014ca7a47SHans de Goede * 129114ca7a47SHans de Goede */ 129214ca7a47SHans de Goede 129314ca7a47SHans de Goede static int acpi_video_device_enumerate(struct acpi_video_bus *video) 129414ca7a47SHans de Goede { 129514ca7a47SHans de Goede int status; 129614ca7a47SHans de Goede int count; 129714ca7a47SHans de Goede int i; 129814ca7a47SHans de Goede struct acpi_video_enumerated_device *active_list; 129914ca7a47SHans de Goede struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; 130014ca7a47SHans de Goede union acpi_object *dod = NULL; 130114ca7a47SHans de Goede union acpi_object *obj; 130214ca7a47SHans de Goede 1303e34fbbacSAlex Hung if (!video->cap._DOD) 1304e34fbbacSAlex Hung return AE_NOT_EXIST; 1305e34fbbacSAlex Hung 130614ca7a47SHans de Goede status = acpi_evaluate_object(video->device->handle, "_DOD", NULL, &buffer); 13072924d2f8SRafael J. Wysocki if (ACPI_FAILURE(status)) { 13082924d2f8SRafael J. Wysocki acpi_handle_info(video->device->handle, 13092924d2f8SRafael J. Wysocki "_DOD evaluation failed: %s\n", 13102924d2f8SRafael J. Wysocki acpi_format_exception(status)); 131114ca7a47SHans de Goede return status; 131214ca7a47SHans de Goede } 131314ca7a47SHans de Goede 131414ca7a47SHans de Goede dod = buffer.pointer; 131514ca7a47SHans de Goede if (!dod || (dod->type != ACPI_TYPE_PACKAGE)) { 13162924d2f8SRafael J. Wysocki acpi_handle_info(video->device->handle, "Invalid _DOD data\n"); 131714ca7a47SHans de Goede status = -EFAULT; 131814ca7a47SHans de Goede goto out; 131914ca7a47SHans de Goede } 132014ca7a47SHans de Goede 13212924d2f8SRafael J. Wysocki acpi_handle_debug(video->device->handle, "Found %d video heads in _DOD\n", 13222924d2f8SRafael J. Wysocki dod->package.count); 132314ca7a47SHans de Goede 132414ca7a47SHans de Goede active_list = kcalloc(1 + dod->package.count, 132514ca7a47SHans de Goede sizeof(struct acpi_video_enumerated_device), 132614ca7a47SHans de Goede GFP_KERNEL); 132714ca7a47SHans de Goede if (!active_list) { 132814ca7a47SHans de Goede status = -ENOMEM; 132914ca7a47SHans de Goede goto out; 133014ca7a47SHans de Goede } 133114ca7a47SHans de Goede 133214ca7a47SHans de Goede count = 0; 133314ca7a47SHans de Goede for (i = 0; i < dod->package.count; i++) { 133414ca7a47SHans de Goede obj = &dod->package.elements[i]; 133514ca7a47SHans de Goede 133614ca7a47SHans de Goede if (obj->type != ACPI_TYPE_INTEGER) { 13372924d2f8SRafael J. Wysocki acpi_handle_info(video->device->handle, 133814ca7a47SHans de Goede "Invalid _DOD data in element %d\n", i); 133914ca7a47SHans de Goede continue; 134014ca7a47SHans de Goede } 134114ca7a47SHans de Goede 134214ca7a47SHans de Goede active_list[count].value.int_val = obj->integer.value; 134314ca7a47SHans de Goede active_list[count].bind_info = NULL; 13442924d2f8SRafael J. Wysocki 13452924d2f8SRafael J. Wysocki acpi_handle_debug(video->device->handle, 13462924d2f8SRafael J. Wysocki "_DOD element[%d] = %d\n", i, 13472924d2f8SRafael J. Wysocki (int)obj->integer.value); 13482924d2f8SRafael J. Wysocki 134914ca7a47SHans de Goede count++; 135014ca7a47SHans de Goede } 135114ca7a47SHans de Goede 135214ca7a47SHans de Goede kfree(video->attached_array); 135314ca7a47SHans de Goede 135414ca7a47SHans de Goede video->attached_array = active_list; 135514ca7a47SHans de Goede video->attached_count = count; 135614ca7a47SHans de Goede 135714ca7a47SHans de Goede out: 135814ca7a47SHans de Goede kfree(buffer.pointer); 135914ca7a47SHans de Goede return status; 136014ca7a47SHans de Goede } 136114ca7a47SHans de Goede 136214ca7a47SHans de Goede static int 136314ca7a47SHans de Goede acpi_video_get_next_level(struct acpi_video_device *device, 136414ca7a47SHans de Goede u32 level_current, u32 event) 136514ca7a47SHans de Goede { 136614ca7a47SHans de Goede int min, max, min_above, max_below, i, l, delta = 255; 136714ca7a47SHans de Goede max = max_below = 0; 136814ca7a47SHans de Goede min = min_above = 255; 136914ca7a47SHans de Goede /* Find closest level to level_current */ 1370d485ef43SDmitry Frank for (i = ACPI_VIDEO_FIRST_LEVEL; i < device->brightness->count; i++) { 137114ca7a47SHans de Goede l = device->brightness->levels[i]; 137214ca7a47SHans de Goede if (abs(l - level_current) < abs(delta)) { 137314ca7a47SHans de Goede delta = l - level_current; 137414ca7a47SHans de Goede if (!delta) 137514ca7a47SHans de Goede break; 137614ca7a47SHans de Goede } 137714ca7a47SHans de Goede } 1378935ab850STom Saeger /* Adjust level_current to closest available level */ 137914ca7a47SHans de Goede level_current += delta; 1380d485ef43SDmitry Frank for (i = ACPI_VIDEO_FIRST_LEVEL; i < device->brightness->count; i++) { 138114ca7a47SHans de Goede l = device->brightness->levels[i]; 138214ca7a47SHans de Goede if (l < min) 138314ca7a47SHans de Goede min = l; 138414ca7a47SHans de Goede if (l > max) 138514ca7a47SHans de Goede max = l; 138614ca7a47SHans de Goede if (l < min_above && l > level_current) 138714ca7a47SHans de Goede min_above = l; 138814ca7a47SHans de Goede if (l > max_below && l < level_current) 138914ca7a47SHans de Goede max_below = l; 139014ca7a47SHans de Goede } 139114ca7a47SHans de Goede 139214ca7a47SHans de Goede switch (event) { 139314ca7a47SHans de Goede case ACPI_VIDEO_NOTIFY_CYCLE_BRIGHTNESS: 139414ca7a47SHans de Goede return (level_current < max) ? min_above : min; 139514ca7a47SHans de Goede case ACPI_VIDEO_NOTIFY_INC_BRIGHTNESS: 139614ca7a47SHans de Goede return (level_current < max) ? min_above : max; 139714ca7a47SHans de Goede case ACPI_VIDEO_NOTIFY_DEC_BRIGHTNESS: 139814ca7a47SHans de Goede return (level_current > min) ? max_below : min; 139914ca7a47SHans de Goede case ACPI_VIDEO_NOTIFY_ZERO_BRIGHTNESS: 140014ca7a47SHans de Goede case ACPI_VIDEO_NOTIFY_DISPLAY_OFF: 140114ca7a47SHans de Goede return 0; 140214ca7a47SHans de Goede default: 140314ca7a47SHans de Goede return level_current; 140414ca7a47SHans de Goede } 140514ca7a47SHans de Goede } 140614ca7a47SHans de Goede 140714ca7a47SHans de Goede static void 140814ca7a47SHans de Goede acpi_video_switch_brightness(struct work_struct *work) 140914ca7a47SHans de Goede { 141014ca7a47SHans de Goede struct acpi_video_device *device = container_of(to_delayed_work(work), 141114ca7a47SHans de Goede struct acpi_video_device, switch_brightness_work); 141214ca7a47SHans de Goede unsigned long long level_current, level_next; 141314ca7a47SHans de Goede int event = device->switch_brightness_event; 141414ca7a47SHans de Goede int result = -EINVAL; 141514ca7a47SHans de Goede 141614ca7a47SHans de Goede /* no warning message if acpi_backlight=vendor or a quirk is used */ 141714ca7a47SHans de Goede if (!device->backlight) 141814ca7a47SHans de Goede return; 141914ca7a47SHans de Goede 142014ca7a47SHans de Goede if (!device->brightness) 142114ca7a47SHans de Goede goto out; 142214ca7a47SHans de Goede 142314ca7a47SHans de Goede result = acpi_video_device_lcd_get_level_current(device, 142414ca7a47SHans de Goede &level_current, 142514ca7a47SHans de Goede false); 142614ca7a47SHans de Goede if (result) 142714ca7a47SHans de Goede goto out; 142814ca7a47SHans de Goede 142914ca7a47SHans de Goede level_next = acpi_video_get_next_level(device, level_current, event); 143014ca7a47SHans de Goede 143114ca7a47SHans de Goede result = acpi_video_device_lcd_set_level(device, level_next); 143214ca7a47SHans de Goede 143314ca7a47SHans de Goede if (!result) 143414ca7a47SHans de Goede backlight_force_update(device->backlight, 143514ca7a47SHans de Goede BACKLIGHT_UPDATE_HOTKEY); 143614ca7a47SHans de Goede 143714ca7a47SHans de Goede out: 143814ca7a47SHans de Goede if (result) 14392924d2f8SRafael J. Wysocki acpi_handle_info(device->dev->handle, 14402924d2f8SRafael J. Wysocki "Failed to switch brightness\n"); 144114ca7a47SHans de Goede } 144214ca7a47SHans de Goede 144314ca7a47SHans de Goede int acpi_video_get_edid(struct acpi_device *device, int type, int device_id, 144414ca7a47SHans de Goede void **edid) 144514ca7a47SHans de Goede { 144614ca7a47SHans de Goede struct acpi_video_bus *video; 144714ca7a47SHans de Goede struct acpi_video_device *video_device; 144814ca7a47SHans de Goede union acpi_object *buffer = NULL; 144914ca7a47SHans de Goede acpi_status status; 145014ca7a47SHans de Goede int i, length; 145114ca7a47SHans de Goede 145214ca7a47SHans de Goede if (!device || !acpi_driver_data(device)) 145314ca7a47SHans de Goede return -EINVAL; 145414ca7a47SHans de Goede 145514ca7a47SHans de Goede video = acpi_driver_data(device); 145614ca7a47SHans de Goede 145714ca7a47SHans de Goede for (i = 0; i < video->attached_count; i++) { 145814ca7a47SHans de Goede video_device = video->attached_array[i].bind_info; 145914ca7a47SHans de Goede length = 256; 146014ca7a47SHans de Goede 146114ca7a47SHans de Goede if (!video_device) 146214ca7a47SHans de Goede continue; 146314ca7a47SHans de Goede 146414ca7a47SHans de Goede if (!video_device->cap._DDC) 146514ca7a47SHans de Goede continue; 146614ca7a47SHans de Goede 146714ca7a47SHans de Goede if (type) { 146814ca7a47SHans de Goede switch (type) { 146914ca7a47SHans de Goede case ACPI_VIDEO_DISPLAY_CRT: 147014ca7a47SHans de Goede if (!video_device->flags.crt) 147114ca7a47SHans de Goede continue; 147214ca7a47SHans de Goede break; 147314ca7a47SHans de Goede case ACPI_VIDEO_DISPLAY_TV: 147414ca7a47SHans de Goede if (!video_device->flags.tvout) 147514ca7a47SHans de Goede continue; 147614ca7a47SHans de Goede break; 147714ca7a47SHans de Goede case ACPI_VIDEO_DISPLAY_DVI: 147814ca7a47SHans de Goede if (!video_device->flags.dvi) 147914ca7a47SHans de Goede continue; 148014ca7a47SHans de Goede break; 148114ca7a47SHans de Goede case ACPI_VIDEO_DISPLAY_LCD: 148214ca7a47SHans de Goede if (!video_device->flags.lcd) 148314ca7a47SHans de Goede continue; 148414ca7a47SHans de Goede break; 148514ca7a47SHans de Goede } 148614ca7a47SHans de Goede } else if (video_device->device_id != device_id) { 148714ca7a47SHans de Goede continue; 148814ca7a47SHans de Goede } 148914ca7a47SHans de Goede 149014ca7a47SHans de Goede status = acpi_video_device_EDID(video_device, &buffer, length); 149114ca7a47SHans de Goede 149214ca7a47SHans de Goede if (ACPI_FAILURE(status) || !buffer || 149314ca7a47SHans de Goede buffer->type != ACPI_TYPE_BUFFER) { 149414ca7a47SHans de Goede length = 128; 149514ca7a47SHans de Goede status = acpi_video_device_EDID(video_device, &buffer, 149614ca7a47SHans de Goede length); 149714ca7a47SHans de Goede if (ACPI_FAILURE(status) || !buffer || 149814ca7a47SHans de Goede buffer->type != ACPI_TYPE_BUFFER) { 149914ca7a47SHans de Goede continue; 150014ca7a47SHans de Goede } 150114ca7a47SHans de Goede } 150214ca7a47SHans de Goede 150314ca7a47SHans de Goede *edid = buffer->buffer.pointer; 150414ca7a47SHans de Goede return length; 150514ca7a47SHans de Goede } 150614ca7a47SHans de Goede 150714ca7a47SHans de Goede return -ENODEV; 150814ca7a47SHans de Goede } 150914ca7a47SHans de Goede EXPORT_SYMBOL(acpi_video_get_edid); 151014ca7a47SHans de Goede 151114ca7a47SHans de Goede static int 151214ca7a47SHans de Goede acpi_video_bus_get_devices(struct acpi_video_bus *video, 151314ca7a47SHans de Goede struct acpi_device *device) 151414ca7a47SHans de Goede { 151514ca7a47SHans de Goede /* 151614ca7a47SHans de Goede * There are systems where video module known to work fine regardless 151714ca7a47SHans de Goede * of broken _DOD and ignoring returned value here doesn't cause 151814ca7a47SHans de Goede * any issues later. 151914ca7a47SHans de Goede */ 152014ca7a47SHans de Goede acpi_video_device_enumerate(video); 152114ca7a47SHans de Goede 15220ea3ef24SRafael J. Wysocki return acpi_dev_for_each_child(device, acpi_video_bus_get_one_device, video); 152314ca7a47SHans de Goede } 152414ca7a47SHans de Goede 152514ca7a47SHans de Goede /* acpi_video interface */ 152614ca7a47SHans de Goede 152714ca7a47SHans de Goede /* 152814ca7a47SHans de Goede * Win8 requires setting bit2 of _DOS to let firmware know it shouldn't 1529935ab850STom Saeger * perform any automatic brightness change on receiving a notification. 153014ca7a47SHans de Goede */ 153114ca7a47SHans de Goede static int acpi_video_bus_start_devices(struct acpi_video_bus *video) 153214ca7a47SHans de Goede { 153314ca7a47SHans de Goede return acpi_video_bus_DOS(video, 0, 153414ca7a47SHans de Goede acpi_osi_is_win8() ? 1 : 0); 153514ca7a47SHans de Goede } 153614ca7a47SHans de Goede 153714ca7a47SHans de Goede static int acpi_video_bus_stop_devices(struct acpi_video_bus *video) 153814ca7a47SHans de Goede { 153914ca7a47SHans de Goede return acpi_video_bus_DOS(video, 0, 154014ca7a47SHans de Goede acpi_osi_is_win8() ? 0 : 1); 154114ca7a47SHans de Goede } 154214ca7a47SHans de Goede 154314ca7a47SHans de Goede static void acpi_video_bus_notify(struct acpi_device *device, u32 event) 154414ca7a47SHans de Goede { 154514ca7a47SHans de Goede struct acpi_video_bus *video = acpi_driver_data(device); 154614ca7a47SHans de Goede struct input_dev *input; 154714ca7a47SHans de Goede int keycode = 0; 154814ca7a47SHans de Goede 154914ca7a47SHans de Goede if (!video || !video->input) 155014ca7a47SHans de Goede return; 155114ca7a47SHans de Goede 155214ca7a47SHans de Goede input = video->input; 155314ca7a47SHans de Goede 155414ca7a47SHans de Goede switch (event) { 155514ca7a47SHans de Goede case ACPI_VIDEO_NOTIFY_SWITCH: /* User requested a switch, 155614ca7a47SHans de Goede * most likely via hotkey. */ 155714ca7a47SHans de Goede keycode = KEY_SWITCHVIDEOMODE; 155814ca7a47SHans de Goede break; 155914ca7a47SHans de Goede 156014ca7a47SHans de Goede case ACPI_VIDEO_NOTIFY_PROBE: /* User plugged in or removed a video 156114ca7a47SHans de Goede * connector. */ 156214ca7a47SHans de Goede acpi_video_device_enumerate(video); 156314ca7a47SHans de Goede acpi_video_device_rebind(video); 156414ca7a47SHans de Goede keycode = KEY_SWITCHVIDEOMODE; 156514ca7a47SHans de Goede break; 156614ca7a47SHans de Goede 156714ca7a47SHans de Goede case ACPI_VIDEO_NOTIFY_CYCLE: /* Cycle Display output hotkey pressed. */ 156814ca7a47SHans de Goede keycode = KEY_SWITCHVIDEOMODE; 156914ca7a47SHans de Goede break; 157014ca7a47SHans de Goede case ACPI_VIDEO_NOTIFY_NEXT_OUTPUT: /* Next Display output hotkey pressed. */ 157114ca7a47SHans de Goede keycode = KEY_VIDEO_NEXT; 157214ca7a47SHans de Goede break; 157314ca7a47SHans de Goede case ACPI_VIDEO_NOTIFY_PREV_OUTPUT: /* previous Display output hotkey pressed. */ 157414ca7a47SHans de Goede keycode = KEY_VIDEO_PREV; 157514ca7a47SHans de Goede break; 157614ca7a47SHans de Goede 157714ca7a47SHans de Goede default: 15782924d2f8SRafael J. Wysocki acpi_handle_debug(device->handle, "Unsupported event [0x%x]\n", 15792924d2f8SRafael J. Wysocki event); 158014ca7a47SHans de Goede break; 158114ca7a47SHans de Goede } 158214ca7a47SHans de Goede 158314ca7a47SHans de Goede if (acpi_notifier_call_chain(device, event, 0)) 158414ca7a47SHans de Goede /* Something vetoed the keypress. */ 158514ca7a47SHans de Goede keycode = 0; 158614ca7a47SHans de Goede 158705bc59a0SHans de Goede if (keycode && (report_key_events & REPORT_OUTPUT_KEY_EVENTS)) { 158814ca7a47SHans de Goede input_report_key(input, keycode, 1); 158914ca7a47SHans de Goede input_sync(input); 159014ca7a47SHans de Goede input_report_key(input, keycode, 0); 159114ca7a47SHans de Goede input_sync(input); 159214ca7a47SHans de Goede } 159314ca7a47SHans de Goede } 159414ca7a47SHans de Goede 159514ca7a47SHans de Goede static void brightness_switch_event(struct acpi_video_device *video_device, 159614ca7a47SHans de Goede u32 event) 159714ca7a47SHans de Goede { 159814ca7a47SHans de Goede if (!brightness_switch_enabled) 159914ca7a47SHans de Goede return; 160014ca7a47SHans de Goede 160114ca7a47SHans de Goede video_device->switch_brightness_event = event; 160214ca7a47SHans de Goede schedule_delayed_work(&video_device->switch_brightness_work, HZ / 10); 160314ca7a47SHans de Goede } 160414ca7a47SHans de Goede 160514ca7a47SHans de Goede static void acpi_video_device_notify(acpi_handle handle, u32 event, void *data) 160614ca7a47SHans de Goede { 160714ca7a47SHans de Goede struct acpi_video_device *video_device = data; 160814ca7a47SHans de Goede struct acpi_device *device = NULL; 160914ca7a47SHans de Goede struct acpi_video_bus *bus; 161014ca7a47SHans de Goede struct input_dev *input; 161114ca7a47SHans de Goede int keycode = 0; 161214ca7a47SHans de Goede 161314ca7a47SHans de Goede if (!video_device) 161414ca7a47SHans de Goede return; 161514ca7a47SHans de Goede 161614ca7a47SHans de Goede device = video_device->dev; 161714ca7a47SHans de Goede bus = video_device->video; 161814ca7a47SHans de Goede input = bus->input; 161914ca7a47SHans de Goede 16204f7f9645SHans de Goede if (hw_changes_brightness > 0) { 16214f7f9645SHans de Goede if (video_device->backlight) 16224f7f9645SHans de Goede backlight_force_update(video_device->backlight, 16234f7f9645SHans de Goede BACKLIGHT_UPDATE_HOTKEY); 16244f7f9645SHans de Goede acpi_notifier_call_chain(device, event, 0); 16254f7f9645SHans de Goede return; 16264f7f9645SHans de Goede } 16274f7f9645SHans de Goede 162814ca7a47SHans de Goede switch (event) { 162914ca7a47SHans de Goede case ACPI_VIDEO_NOTIFY_CYCLE_BRIGHTNESS: /* Cycle brightness */ 163014ca7a47SHans de Goede brightness_switch_event(video_device, event); 163114ca7a47SHans de Goede keycode = KEY_BRIGHTNESS_CYCLE; 163214ca7a47SHans de Goede break; 163314ca7a47SHans de Goede case ACPI_VIDEO_NOTIFY_INC_BRIGHTNESS: /* Increase brightness */ 163414ca7a47SHans de Goede brightness_switch_event(video_device, event); 163514ca7a47SHans de Goede keycode = KEY_BRIGHTNESSUP; 163614ca7a47SHans de Goede break; 163714ca7a47SHans de Goede case ACPI_VIDEO_NOTIFY_DEC_BRIGHTNESS: /* Decrease brightness */ 163814ca7a47SHans de Goede brightness_switch_event(video_device, event); 163914ca7a47SHans de Goede keycode = KEY_BRIGHTNESSDOWN; 164014ca7a47SHans de Goede break; 164114ca7a47SHans de Goede case ACPI_VIDEO_NOTIFY_ZERO_BRIGHTNESS: /* zero brightness */ 164214ca7a47SHans de Goede brightness_switch_event(video_device, event); 164314ca7a47SHans de Goede keycode = KEY_BRIGHTNESS_ZERO; 164414ca7a47SHans de Goede break; 164514ca7a47SHans de Goede case ACPI_VIDEO_NOTIFY_DISPLAY_OFF: /* display device off */ 164614ca7a47SHans de Goede brightness_switch_event(video_device, event); 164714ca7a47SHans de Goede keycode = KEY_DISPLAY_OFF; 164814ca7a47SHans de Goede break; 164914ca7a47SHans de Goede default: 16502924d2f8SRafael J. Wysocki acpi_handle_debug(handle, "Unsupported event [0x%x]\n", event); 165114ca7a47SHans de Goede break; 165214ca7a47SHans de Goede } 165314ca7a47SHans de Goede 16545ad26161SHans de Goede if (keycode) 16555ad26161SHans de Goede may_report_brightness_keys = true; 16565ad26161SHans de Goede 165714ca7a47SHans de Goede acpi_notifier_call_chain(device, event, 0); 165814ca7a47SHans de Goede 165905bc59a0SHans de Goede if (keycode && (report_key_events & REPORT_BRIGHTNESS_KEY_EVENTS)) { 166014ca7a47SHans de Goede input_report_key(input, keycode, 1); 166114ca7a47SHans de Goede input_sync(input); 166214ca7a47SHans de Goede input_report_key(input, keycode, 0); 166314ca7a47SHans de Goede input_sync(input); 166414ca7a47SHans de Goede } 166514ca7a47SHans de Goede } 166614ca7a47SHans de Goede 166714ca7a47SHans de Goede static int acpi_video_resume(struct notifier_block *nb, 166814ca7a47SHans de Goede unsigned long val, void *ign) 166914ca7a47SHans de Goede { 167014ca7a47SHans de Goede struct acpi_video_bus *video; 167114ca7a47SHans de Goede struct acpi_video_device *video_device; 167214ca7a47SHans de Goede int i; 167314ca7a47SHans de Goede 167414ca7a47SHans de Goede switch (val) { 16751934fee6SZhang Rui case PM_POST_HIBERNATION: 16761934fee6SZhang Rui case PM_POST_SUSPEND: 16771934fee6SZhang Rui case PM_POST_RESTORE: 167814ca7a47SHans de Goede video = container_of(nb, struct acpi_video_bus, pm_nb); 167914ca7a47SHans de Goede 168014ca7a47SHans de Goede dev_info(&video->device->dev, "Restoring backlight state\n"); 168114ca7a47SHans de Goede 168214ca7a47SHans de Goede for (i = 0; i < video->attached_count; i++) { 168314ca7a47SHans de Goede video_device = video->attached_array[i].bind_info; 168414ca7a47SHans de Goede if (video_device && video_device->brightness) 168514ca7a47SHans de Goede acpi_video_device_lcd_set_level(video_device, 168614ca7a47SHans de Goede video_device->brightness->curr); 168714ca7a47SHans de Goede } 168814ca7a47SHans de Goede 168914ca7a47SHans de Goede return NOTIFY_OK; 169014ca7a47SHans de Goede } 16911934fee6SZhang Rui return NOTIFY_DONE; 16921934fee6SZhang Rui } 169314ca7a47SHans de Goede 169414ca7a47SHans de Goede static acpi_status 169514ca7a47SHans de Goede acpi_video_bus_match(acpi_handle handle, u32 level, void *context, 169614ca7a47SHans de Goede void **return_value) 169714ca7a47SHans de Goede { 169814ca7a47SHans de Goede struct acpi_device *device = context; 169914ca7a47SHans de Goede struct acpi_device *sibling; 170014ca7a47SHans de Goede 170114ca7a47SHans de Goede if (handle == device->handle) 170214ca7a47SHans de Goede return AE_CTRL_TERMINATE; 170314ca7a47SHans de Goede 170499ece713SRafael J. Wysocki sibling = acpi_fetch_acpi_dev(handle); 170599ece713SRafael J. Wysocki if (!sibling) 170614ca7a47SHans de Goede return AE_OK; 170714ca7a47SHans de Goede 170814ca7a47SHans de Goede if (!strcmp(acpi_device_name(sibling), ACPI_VIDEO_BUS_NAME)) 170914ca7a47SHans de Goede return AE_ALREADY_EXISTS; 171014ca7a47SHans de Goede 171114ca7a47SHans de Goede return AE_OK; 171214ca7a47SHans de Goede } 171314ca7a47SHans de Goede 171414ca7a47SHans de Goede static void acpi_video_dev_register_backlight(struct acpi_video_device *device) 171514ca7a47SHans de Goede { 171614ca7a47SHans de Goede struct backlight_properties props; 171714ca7a47SHans de Goede struct pci_dev *pdev; 171814ca7a47SHans de Goede acpi_handle acpi_parent; 171914ca7a47SHans de Goede struct device *parent = NULL; 172014ca7a47SHans de Goede int result; 172114ca7a47SHans de Goede static int count; 172214ca7a47SHans de Goede char *name; 172314ca7a47SHans de Goede 172414ca7a47SHans de Goede result = acpi_video_init_brightness(device); 172514ca7a47SHans de Goede if (result) 172614ca7a47SHans de Goede return; 172714ca7a47SHans de Goede 172814ca7a47SHans de Goede name = kasprintf(GFP_KERNEL, "acpi_video%d", count); 172914ca7a47SHans de Goede if (!name) 173014ca7a47SHans de Goede return; 173114ca7a47SHans de Goede count++; 173214ca7a47SHans de Goede 173314ca7a47SHans de Goede acpi_get_parent(device->dev->handle, &acpi_parent); 173414ca7a47SHans de Goede 173514ca7a47SHans de Goede pdev = acpi_get_pci_dev(acpi_parent); 173614ca7a47SHans de Goede if (pdev) { 173714ca7a47SHans de Goede parent = &pdev->dev; 173814ca7a47SHans de Goede pci_dev_put(pdev); 173914ca7a47SHans de Goede } 174014ca7a47SHans de Goede 174114ca7a47SHans de Goede memset(&props, 0, sizeof(struct backlight_properties)); 174214ca7a47SHans de Goede props.type = BACKLIGHT_FIRMWARE; 1743d485ef43SDmitry Frank props.max_brightness = 1744d485ef43SDmitry Frank device->brightness->count - ACPI_VIDEO_FIRST_LEVEL - 1; 174514ca7a47SHans de Goede device->backlight = backlight_device_register(name, 174614ca7a47SHans de Goede parent, 174714ca7a47SHans de Goede device, 174814ca7a47SHans de Goede &acpi_backlight_ops, 174914ca7a47SHans de Goede &props); 175014ca7a47SHans de Goede kfree(name); 175114ca7a47SHans de Goede if (IS_ERR(device->backlight)) { 175214ca7a47SHans de Goede device->backlight = NULL; 175314ca7a47SHans de Goede return; 175414ca7a47SHans de Goede } 175514ca7a47SHans de Goede 175614ca7a47SHans de Goede /* 175714ca7a47SHans de Goede * Save current brightness level in case we have to restore it 175814ca7a47SHans de Goede * before acpi_video_device_lcd_set_level() is called next time. 175914ca7a47SHans de Goede */ 176014ca7a47SHans de Goede device->backlight->props.brightness = 176114ca7a47SHans de Goede acpi_video_get_brightness(device->backlight); 176214ca7a47SHans de Goede 176314ca7a47SHans de Goede device->cooling_dev = thermal_cooling_device_register("LCD", 176414ca7a47SHans de Goede device->dev, &video_cooling_ops); 176514ca7a47SHans de Goede if (IS_ERR(device->cooling_dev)) { 176614ca7a47SHans de Goede /* 176714ca7a47SHans de Goede * Set cooling_dev to NULL so we don't crash trying to free it. 176814ca7a47SHans de Goede * Also, why the hell we are returning early and not attempt to 176914ca7a47SHans de Goede * register video output if cooling device registration failed? 177014ca7a47SHans de Goede * -- dtor 177114ca7a47SHans de Goede */ 177214ca7a47SHans de Goede device->cooling_dev = NULL; 177314ca7a47SHans de Goede return; 177414ca7a47SHans de Goede } 177514ca7a47SHans de Goede 177614ca7a47SHans de Goede dev_info(&device->dev->dev, "registered as cooling_device%d\n", 177714ca7a47SHans de Goede device->cooling_dev->id); 177814ca7a47SHans de Goede result = sysfs_create_link(&device->dev->dev.kobj, 177914ca7a47SHans de Goede &device->cooling_dev->device.kobj, 178014ca7a47SHans de Goede "thermal_cooling"); 178114ca7a47SHans de Goede if (result) 17822924d2f8SRafael J. Wysocki pr_info("sysfs link creation failed\n"); 17832924d2f8SRafael J. Wysocki 178414ca7a47SHans de Goede result = sysfs_create_link(&device->cooling_dev->device.kobj, 178514ca7a47SHans de Goede &device->dev->dev.kobj, "device"); 178614ca7a47SHans de Goede if (result) 17872924d2f8SRafael J. Wysocki pr_info("Reverse sysfs link creation failed\n"); 178814ca7a47SHans de Goede } 178914ca7a47SHans de Goede 179014ca7a47SHans de Goede static void acpi_video_run_bcl_for_osi(struct acpi_video_bus *video) 179114ca7a47SHans de Goede { 179214ca7a47SHans de Goede struct acpi_video_device *dev; 179314ca7a47SHans de Goede union acpi_object *levels; 179414ca7a47SHans de Goede 179514ca7a47SHans de Goede mutex_lock(&video->device_list_lock); 179614ca7a47SHans de Goede list_for_each_entry(dev, &video->video_device_list, entry) { 17979f9cd7eeSAaron Lu if (!acpi_video_device_lcd_query_levels(dev->dev->handle, &levels)) 179814ca7a47SHans de Goede kfree(levels); 179914ca7a47SHans de Goede } 180014ca7a47SHans de Goede mutex_unlock(&video->device_list_lock); 180114ca7a47SHans de Goede } 180214ca7a47SHans de Goede 1803e50b9be1SAaron Lu static bool acpi_video_should_register_backlight(struct acpi_video_device *dev) 1804e50b9be1SAaron Lu { 1805e50b9be1SAaron Lu /* 1806e50b9be1SAaron Lu * Do not create backlight device for video output 1807e50b9be1SAaron Lu * device that is not in the enumerated list. 1808e50b9be1SAaron Lu */ 1809e50b9be1SAaron Lu if (!acpi_video_device_in_dod(dev)) { 1810e50b9be1SAaron Lu dev_dbg(&dev->dev->dev, "not in _DOD list, ignore\n"); 1811e50b9be1SAaron Lu return false; 1812e50b9be1SAaron Lu } 1813e50b9be1SAaron Lu 1814e50b9be1SAaron Lu if (only_lcd) 1815e50b9be1SAaron Lu return dev->flags.lcd; 1816e50b9be1SAaron Lu return true; 1817e50b9be1SAaron Lu } 1818e50b9be1SAaron Lu 181914ca7a47SHans de Goede static int acpi_video_bus_register_backlight(struct acpi_video_bus *video) 182014ca7a47SHans de Goede { 182114ca7a47SHans de Goede struct acpi_video_device *dev; 182214ca7a47SHans de Goede 182314ca7a47SHans de Goede if (video->backlight_registered) 182414ca7a47SHans de Goede return 0; 182514ca7a47SHans de Goede 18263bd6bce3SHans de Goede if (acpi_video_get_backlight_type() != acpi_backlight_video) 182714ca7a47SHans de Goede return 0; 182814ca7a47SHans de Goede 182914ca7a47SHans de Goede mutex_lock(&video->device_list_lock); 1830e50b9be1SAaron Lu list_for_each_entry(dev, &video->video_device_list, entry) { 1831e50b9be1SAaron Lu if (acpi_video_should_register_backlight(dev)) 183214ca7a47SHans de Goede acpi_video_dev_register_backlight(dev); 1833e50b9be1SAaron Lu } 183414ca7a47SHans de Goede mutex_unlock(&video->device_list_lock); 183514ca7a47SHans de Goede 183614ca7a47SHans de Goede video->backlight_registered = true; 183714ca7a47SHans de Goede 183814ca7a47SHans de Goede video->pm_nb.notifier_call = acpi_video_resume; 183914ca7a47SHans de Goede video->pm_nb.priority = 0; 184014ca7a47SHans de Goede return register_pm_notifier(&video->pm_nb); 184114ca7a47SHans de Goede } 184214ca7a47SHans de Goede 184314ca7a47SHans de Goede static void acpi_video_dev_unregister_backlight(struct acpi_video_device *device) 184414ca7a47SHans de Goede { 184514ca7a47SHans de Goede if (device->backlight) { 184614ca7a47SHans de Goede backlight_device_unregister(device->backlight); 184714ca7a47SHans de Goede device->backlight = NULL; 184814ca7a47SHans de Goede } 184914ca7a47SHans de Goede if (device->brightness) { 185014ca7a47SHans de Goede kfree(device->brightness->levels); 185114ca7a47SHans de Goede kfree(device->brightness); 185214ca7a47SHans de Goede device->brightness = NULL; 185314ca7a47SHans de Goede } 185414ca7a47SHans de Goede if (device->cooling_dev) { 185514ca7a47SHans de Goede sysfs_remove_link(&device->dev->dev.kobj, "thermal_cooling"); 185614ca7a47SHans de Goede sysfs_remove_link(&device->cooling_dev->device.kobj, "device"); 185714ca7a47SHans de Goede thermal_cooling_device_unregister(device->cooling_dev); 185814ca7a47SHans de Goede device->cooling_dev = NULL; 185914ca7a47SHans de Goede } 186014ca7a47SHans de Goede } 186114ca7a47SHans de Goede 186214ca7a47SHans de Goede static int acpi_video_bus_unregister_backlight(struct acpi_video_bus *video) 186314ca7a47SHans de Goede { 186414ca7a47SHans de Goede struct acpi_video_device *dev; 186514ca7a47SHans de Goede int error; 186614ca7a47SHans de Goede 186714ca7a47SHans de Goede if (!video->backlight_registered) 186814ca7a47SHans de Goede return 0; 186914ca7a47SHans de Goede 187014ca7a47SHans de Goede error = unregister_pm_notifier(&video->pm_nb); 187114ca7a47SHans de Goede 187214ca7a47SHans de Goede mutex_lock(&video->device_list_lock); 187314ca7a47SHans de Goede list_for_each_entry(dev, &video->video_device_list, entry) 187414ca7a47SHans de Goede acpi_video_dev_unregister_backlight(dev); 187514ca7a47SHans de Goede mutex_unlock(&video->device_list_lock); 187614ca7a47SHans de Goede 187714ca7a47SHans de Goede video->backlight_registered = false; 187814ca7a47SHans de Goede 187914ca7a47SHans de Goede return error; 188014ca7a47SHans de Goede } 188114ca7a47SHans de Goede 188214ca7a47SHans de Goede static void acpi_video_dev_add_notify_handler(struct acpi_video_device *device) 188314ca7a47SHans de Goede { 188414ca7a47SHans de Goede acpi_status status; 188514ca7a47SHans de Goede struct acpi_device *adev = device->dev; 188614ca7a47SHans de Goede 188714ca7a47SHans de Goede status = acpi_install_notify_handler(adev->handle, ACPI_DEVICE_NOTIFY, 188814ca7a47SHans de Goede acpi_video_device_notify, device); 188914ca7a47SHans de Goede if (ACPI_FAILURE(status)) 189014ca7a47SHans de Goede dev_err(&adev->dev, "Error installing notify handler\n"); 189114ca7a47SHans de Goede else 189214ca7a47SHans de Goede device->flags.notify = 1; 189314ca7a47SHans de Goede } 189414ca7a47SHans de Goede 189514ca7a47SHans de Goede static int acpi_video_bus_add_notify_handler(struct acpi_video_bus *video) 189614ca7a47SHans de Goede { 189714ca7a47SHans de Goede struct input_dev *input; 189814ca7a47SHans de Goede struct acpi_video_device *dev; 189914ca7a47SHans de Goede int error; 190014ca7a47SHans de Goede 190114ca7a47SHans de Goede video->input = input = input_allocate_device(); 190214ca7a47SHans de Goede if (!input) { 190314ca7a47SHans de Goede error = -ENOMEM; 190414ca7a47SHans de Goede goto out; 190514ca7a47SHans de Goede } 190614ca7a47SHans de Goede 190714ca7a47SHans de Goede error = acpi_video_bus_start_devices(video); 190814ca7a47SHans de Goede if (error) 190914ca7a47SHans de Goede goto err_free_input; 191014ca7a47SHans de Goede 191114ca7a47SHans de Goede snprintf(video->phys, sizeof(video->phys), 191214ca7a47SHans de Goede "%s/video/input0", acpi_device_hid(video->device)); 191314ca7a47SHans de Goede 191414ca7a47SHans de Goede input->name = acpi_device_name(video->device); 191514ca7a47SHans de Goede input->phys = video->phys; 191614ca7a47SHans de Goede input->id.bustype = BUS_HOST; 191714ca7a47SHans de Goede input->id.product = 0x06; 191814ca7a47SHans de Goede input->dev.parent = &video->device->dev; 191914ca7a47SHans de Goede input->evbit[0] = BIT(EV_KEY); 192014ca7a47SHans de Goede set_bit(KEY_SWITCHVIDEOMODE, input->keybit); 192114ca7a47SHans de Goede set_bit(KEY_VIDEO_NEXT, input->keybit); 192214ca7a47SHans de Goede set_bit(KEY_VIDEO_PREV, input->keybit); 192314ca7a47SHans de Goede set_bit(KEY_BRIGHTNESS_CYCLE, input->keybit); 192414ca7a47SHans de Goede set_bit(KEY_BRIGHTNESSUP, input->keybit); 192514ca7a47SHans de Goede set_bit(KEY_BRIGHTNESSDOWN, input->keybit); 192614ca7a47SHans de Goede set_bit(KEY_BRIGHTNESS_ZERO, input->keybit); 192714ca7a47SHans de Goede set_bit(KEY_DISPLAY_OFF, input->keybit); 192814ca7a47SHans de Goede 192914ca7a47SHans de Goede error = input_register_device(input); 193014ca7a47SHans de Goede if (error) 193114ca7a47SHans de Goede goto err_stop_dev; 193214ca7a47SHans de Goede 193314ca7a47SHans de Goede mutex_lock(&video->device_list_lock); 193414ca7a47SHans de Goede list_for_each_entry(dev, &video->video_device_list, entry) 193514ca7a47SHans de Goede acpi_video_dev_add_notify_handler(dev); 193614ca7a47SHans de Goede mutex_unlock(&video->device_list_lock); 193714ca7a47SHans de Goede 193814ca7a47SHans de Goede return 0; 193914ca7a47SHans de Goede 194014ca7a47SHans de Goede err_stop_dev: 194114ca7a47SHans de Goede acpi_video_bus_stop_devices(video); 194214ca7a47SHans de Goede err_free_input: 194314ca7a47SHans de Goede input_free_device(input); 194414ca7a47SHans de Goede video->input = NULL; 194514ca7a47SHans de Goede out: 194614ca7a47SHans de Goede return error; 194714ca7a47SHans de Goede } 194814ca7a47SHans de Goede 194914ca7a47SHans de Goede static void acpi_video_dev_remove_notify_handler(struct acpi_video_device *dev) 195014ca7a47SHans de Goede { 195114ca7a47SHans de Goede if (dev->flags.notify) { 195214ca7a47SHans de Goede acpi_remove_notify_handler(dev->dev->handle, ACPI_DEVICE_NOTIFY, 195314ca7a47SHans de Goede acpi_video_device_notify); 195414ca7a47SHans de Goede dev->flags.notify = 0; 195514ca7a47SHans de Goede } 195614ca7a47SHans de Goede } 195714ca7a47SHans de Goede 195814ca7a47SHans de Goede static void acpi_video_bus_remove_notify_handler(struct acpi_video_bus *video) 195914ca7a47SHans de Goede { 196014ca7a47SHans de Goede struct acpi_video_device *dev; 196114ca7a47SHans de Goede 196214ca7a47SHans de Goede mutex_lock(&video->device_list_lock); 196314ca7a47SHans de Goede list_for_each_entry(dev, &video->video_device_list, entry) 196414ca7a47SHans de Goede acpi_video_dev_remove_notify_handler(dev); 196514ca7a47SHans de Goede mutex_unlock(&video->device_list_lock); 196614ca7a47SHans de Goede 196714ca7a47SHans de Goede acpi_video_bus_stop_devices(video); 196814ca7a47SHans de Goede input_unregister_device(video->input); 196914ca7a47SHans de Goede video->input = NULL; 197014ca7a47SHans de Goede } 197114ca7a47SHans de Goede 197214ca7a47SHans de Goede static int acpi_video_bus_put_devices(struct acpi_video_bus *video) 197314ca7a47SHans de Goede { 197414ca7a47SHans de Goede struct acpi_video_device *dev, *next; 197514ca7a47SHans de Goede 197614ca7a47SHans de Goede mutex_lock(&video->device_list_lock); 197714ca7a47SHans de Goede list_for_each_entry_safe(dev, next, &video->video_device_list, entry) { 197814ca7a47SHans de Goede list_del(&dev->entry); 197914ca7a47SHans de Goede kfree(dev); 198014ca7a47SHans de Goede } 198114ca7a47SHans de Goede mutex_unlock(&video->device_list_lock); 198214ca7a47SHans de Goede 198314ca7a47SHans de Goede return 0; 198414ca7a47SHans de Goede } 198514ca7a47SHans de Goede 198614ca7a47SHans de Goede static int instance; 198714ca7a47SHans de Goede 198814ca7a47SHans de Goede static int acpi_video_bus_add(struct acpi_device *device) 198914ca7a47SHans de Goede { 199014ca7a47SHans de Goede struct acpi_video_bus *video; 199114ca7a47SHans de Goede int error; 199214ca7a47SHans de Goede acpi_status status; 199314ca7a47SHans de Goede 199414ca7a47SHans de Goede status = acpi_walk_namespace(ACPI_TYPE_DEVICE, 199562fcb99bSRafael J. Wysocki acpi_dev_parent(device)->handle, 1, 199614ca7a47SHans de Goede acpi_video_bus_match, NULL, 199714ca7a47SHans de Goede device, NULL); 199814ca7a47SHans de Goede if (status == AE_ALREADY_EXISTS) { 19992924d2f8SRafael J. Wysocki pr_info(FW_BUG 200014ca7a47SHans de Goede "Duplicate ACPI video bus devices for the" 200114ca7a47SHans de Goede " same VGA controller, please try module " 200214ca7a47SHans de Goede "parameter \"video.allow_duplicates=1\"" 200314ca7a47SHans de Goede "if the current driver doesn't work.\n"); 200414ca7a47SHans de Goede if (!allow_duplicates) 200514ca7a47SHans de Goede return -ENODEV; 200614ca7a47SHans de Goede } 200714ca7a47SHans de Goede 200814ca7a47SHans de Goede video = kzalloc(sizeof(struct acpi_video_bus), GFP_KERNEL); 200914ca7a47SHans de Goede if (!video) 201014ca7a47SHans de Goede return -ENOMEM; 201114ca7a47SHans de Goede 201214ca7a47SHans de Goede /* a hack to fix the duplicate name "VID" problem on T61 */ 201314ca7a47SHans de Goede if (!strcmp(device->pnp.bus_id, "VID")) { 201414ca7a47SHans de Goede if (instance) 201514ca7a47SHans de Goede device->pnp.bus_id[3] = '0' + instance; 201614ca7a47SHans de Goede instance++; 201714ca7a47SHans de Goede } 201814ca7a47SHans de Goede /* a hack to fix the duplicate name "VGA" problem on Pa 3553 */ 201914ca7a47SHans de Goede if (!strcmp(device->pnp.bus_id, "VGA")) { 202014ca7a47SHans de Goede if (instance) 202114ca7a47SHans de Goede device->pnp.bus_id[3] = '0' + instance; 202214ca7a47SHans de Goede instance++; 202314ca7a47SHans de Goede } 202414ca7a47SHans de Goede 202514ca7a47SHans de Goede video->device = device; 202614ca7a47SHans de Goede strcpy(acpi_device_name(device), ACPI_VIDEO_BUS_NAME); 202714ca7a47SHans de Goede strcpy(acpi_device_class(device), ACPI_VIDEO_CLASS); 202814ca7a47SHans de Goede device->driver_data = video; 202914ca7a47SHans de Goede 203014ca7a47SHans de Goede acpi_video_bus_find_cap(video); 203114ca7a47SHans de Goede error = acpi_video_bus_check(video); 203214ca7a47SHans de Goede if (error) 203314ca7a47SHans de Goede goto err_free_video; 203414ca7a47SHans de Goede 203514ca7a47SHans de Goede mutex_init(&video->device_list_lock); 203614ca7a47SHans de Goede INIT_LIST_HEAD(&video->video_device_list); 203714ca7a47SHans de Goede 203814ca7a47SHans de Goede error = acpi_video_bus_get_devices(video, device); 203914ca7a47SHans de Goede if (error) 204014ca7a47SHans de Goede goto err_put_video; 204114ca7a47SHans de Goede 20422924d2f8SRafael J. Wysocki pr_info("%s [%s] (multi-head: %s rom: %s post: %s)\n", 204314ca7a47SHans de Goede ACPI_VIDEO_DEVICE_NAME, acpi_device_bid(device), 204414ca7a47SHans de Goede video->flags.multihead ? "yes" : "no", 204514ca7a47SHans de Goede video->flags.rom ? "yes" : "no", 204614ca7a47SHans de Goede video->flags.post ? "yes" : "no"); 204714ca7a47SHans de Goede mutex_lock(&video_list_lock); 204814ca7a47SHans de Goede list_add_tail(&video->entry, &video_bus_head); 204914ca7a47SHans de Goede mutex_unlock(&video_list_lock); 205014ca7a47SHans de Goede 20513dbc80a3SHans de Goede /* 20523dbc80a3SHans de Goede * The userspace visible backlight_device gets registered separately 20533dbc80a3SHans de Goede * from acpi_video_register_backlight(). 20543dbc80a3SHans de Goede */ 20553dbc80a3SHans de Goede acpi_video_run_bcl_for_osi(video); 205614ca7a47SHans de Goede acpi_video_bus_add_notify_handler(video); 205714ca7a47SHans de Goede 205814ca7a47SHans de Goede return 0; 205914ca7a47SHans de Goede 206014ca7a47SHans de Goede err_put_video: 206114ca7a47SHans de Goede acpi_video_bus_put_devices(video); 206214ca7a47SHans de Goede kfree(video->attached_array); 206314ca7a47SHans de Goede err_free_video: 206414ca7a47SHans de Goede kfree(video); 206514ca7a47SHans de Goede device->driver_data = NULL; 206614ca7a47SHans de Goede 206714ca7a47SHans de Goede return error; 206814ca7a47SHans de Goede } 206914ca7a47SHans de Goede 2070*6c0eb5baSDawei Li static void acpi_video_bus_remove(struct acpi_device *device) 207114ca7a47SHans de Goede { 207214ca7a47SHans de Goede struct acpi_video_bus *video = NULL; 207314ca7a47SHans de Goede 207414ca7a47SHans de Goede 207514ca7a47SHans de Goede if (!device || !acpi_driver_data(device)) 2076*6c0eb5baSDawei Li return; 207714ca7a47SHans de Goede 207814ca7a47SHans de Goede video = acpi_driver_data(device); 207914ca7a47SHans de Goede 208014ca7a47SHans de Goede mutex_lock(&video_list_lock); 208114ca7a47SHans de Goede list_del(&video->entry); 208214ca7a47SHans de Goede mutex_unlock(&video_list_lock); 208314ca7a47SHans de Goede 2084c1af8becSHans de Goede acpi_video_bus_remove_notify_handler(video); 2085c1af8becSHans de Goede acpi_video_bus_unregister_backlight(video); 2086c1af8becSHans de Goede acpi_video_bus_put_devices(video); 2087c1af8becSHans de Goede 208814ca7a47SHans de Goede kfree(video->attached_array); 208914ca7a47SHans de Goede kfree(video); 209014ca7a47SHans de Goede } 209114ca7a47SHans de Goede 20923dbc80a3SHans de Goede static void acpi_video_bus_register_backlight_work(struct work_struct *ignored) 20933dbc80a3SHans de Goede { 20943dbc80a3SHans de Goede acpi_video_register_backlight(); 20953dbc80a3SHans de Goede } 20963dbc80a3SHans de Goede 209714ca7a47SHans de Goede static int __init is_i740(struct pci_dev *dev) 209814ca7a47SHans de Goede { 209914ca7a47SHans de Goede if (dev->device == 0x00D1) 210014ca7a47SHans de Goede return 1; 210114ca7a47SHans de Goede if (dev->device == 0x7000) 210214ca7a47SHans de Goede return 1; 210314ca7a47SHans de Goede return 0; 210414ca7a47SHans de Goede } 210514ca7a47SHans de Goede 210614ca7a47SHans de Goede static int __init intel_opregion_present(void) 210714ca7a47SHans de Goede { 210814ca7a47SHans de Goede int opregion = 0; 210914ca7a47SHans de Goede struct pci_dev *dev = NULL; 211014ca7a47SHans de Goede u32 address; 211114ca7a47SHans de Goede 211214ca7a47SHans de Goede for_each_pci_dev(dev) { 211314ca7a47SHans de Goede if ((dev->class >> 8) != PCI_CLASS_DISPLAY_VGA) 211414ca7a47SHans de Goede continue; 211514ca7a47SHans de Goede if (dev->vendor != PCI_VENDOR_ID_INTEL) 211614ca7a47SHans de Goede continue; 211714ca7a47SHans de Goede /* We don't want to poke around undefined i740 registers */ 211814ca7a47SHans de Goede if (is_i740(dev)) 211914ca7a47SHans de Goede continue; 212014ca7a47SHans de Goede pci_read_config_dword(dev, 0xfc, &address); 212114ca7a47SHans de Goede if (!address) 212214ca7a47SHans de Goede continue; 212314ca7a47SHans de Goede opregion = 1; 212414ca7a47SHans de Goede } 212514ca7a47SHans de Goede return opregion; 212614ca7a47SHans de Goede } 212714ca7a47SHans de Goede 2128cecf3e3eSHans de Goede /* Check if the chassis-type indicates there is no builtin LCD panel */ 212953fa1f6eSHans de Goede static bool dmi_is_desktop(void) 213053fa1f6eSHans de Goede { 213153fa1f6eSHans de Goede const char *chassis_type; 2132cecf3e3eSHans de Goede unsigned long type; 213353fa1f6eSHans de Goede 213453fa1f6eSHans de Goede chassis_type = dmi_get_system_info(DMI_CHASSIS_TYPE); 213553fa1f6eSHans de Goede if (!chassis_type) 213653fa1f6eSHans de Goede return false; 213753fa1f6eSHans de Goede 2138cecf3e3eSHans de Goede if (kstrtoul(chassis_type, 10, &type) != 0) 2139cecf3e3eSHans de Goede return false; 2140cecf3e3eSHans de Goede 2141cecf3e3eSHans de Goede switch (type) { 2142cecf3e3eSHans de Goede case 0x03: /* Desktop */ 2143cecf3e3eSHans de Goede case 0x04: /* Low Profile Desktop */ 2144cecf3e3eSHans de Goede case 0x05: /* Pizza Box */ 2145cecf3e3eSHans de Goede case 0x06: /* Mini Tower */ 2146cecf3e3eSHans de Goede case 0x07: /* Tower */ 2147d693c008SHans de Goede case 0x10: /* Lunch Box */ 2148cecf3e3eSHans de Goede case 0x11: /* Main Server Chassis */ 214953fa1f6eSHans de Goede return true; 2150cecf3e3eSHans de Goede } 215153fa1f6eSHans de Goede 215253fa1f6eSHans de Goede return false; 215353fa1f6eSHans de Goede } 215453fa1f6eSHans de Goede 215581cc7e99SHans de Goede /* 215681cc7e99SHans de Goede * We're seeing a lot of bogus backlight interfaces on newer machines 215781cc7e99SHans de Goede * without a LCD such as desktops, servers and HDMI sticks. Checking the 215881cc7e99SHans de Goede * lcd flag fixes this, enable this by default on any machines which are: 215981cc7e99SHans de Goede * 1. Win8 ready (where we also prefer the native backlight driver, so 216081cc7e99SHans de Goede * normally the acpi_video code should not register there anyways); *and* 216181cc7e99SHans de Goede * 2.1 Report a desktop/server DMI chassis-type, or 216281cc7e99SHans de Goede * 2.2 Are an ACPI-reduced-hardware platform (and thus won't use the EC for 216381cc7e99SHans de Goede backlight control) 216481cc7e99SHans de Goede */ 216581cc7e99SHans de Goede static bool should_check_lcd_flag(void) 216681cc7e99SHans de Goede { 216781cc7e99SHans de Goede if (!acpi_osi_is_win8()) 216881cc7e99SHans de Goede return false; 216981cc7e99SHans de Goede 217081cc7e99SHans de Goede if (dmi_is_desktop()) 217181cc7e99SHans de Goede return true; 217281cc7e99SHans de Goede 217381cc7e99SHans de Goede if (acpi_reduced_hardware()) 217481cc7e99SHans de Goede return true; 217581cc7e99SHans de Goede 217681cc7e99SHans de Goede return false; 217781cc7e99SHans de Goede } 217881cc7e99SHans de Goede 217914ca7a47SHans de Goede int acpi_video_register(void) 218014ca7a47SHans de Goede { 21812a8b18e9SHans de Goede int ret = 0; 218214ca7a47SHans de Goede 2183970530cdSHans de Goede mutex_lock(®ister_count_mutex); 2184970530cdSHans de Goede if (register_count) { 218514ca7a47SHans de Goede /* 218614ca7a47SHans de Goede * if the function of acpi_video_register is already called, 2187cbf6d033SKacper Piwiński * don't register the acpi_video_bus again and return no error. 218814ca7a47SHans de Goede */ 21892a8b18e9SHans de Goede goto leave; 219014ca7a47SHans de Goede } 219114ca7a47SHans de Goede 219281cc7e99SHans de Goede if (only_lcd == -1) 219381cc7e99SHans de Goede only_lcd = should_check_lcd_flag(); 21945928c281SHans de Goede 21957ee33baaSHans de Goede dmi_check_system(video_dmi_table); 21967ee33baaSHans de Goede 219714ca7a47SHans de Goede ret = acpi_bus_register_driver(&acpi_video_bus); 219814ca7a47SHans de Goede if (ret) 21992a8b18e9SHans de Goede goto leave; 220014ca7a47SHans de Goede 220114ca7a47SHans de Goede /* 220214ca7a47SHans de Goede * When the acpi_video_bus is loaded successfully, increase 220314ca7a47SHans de Goede * the counter reference. 220414ca7a47SHans de Goede */ 2205970530cdSHans de Goede register_count = 1; 220614ca7a47SHans de Goede 22073dbc80a3SHans de Goede /* 22083dbc80a3SHans de Goede * acpi_video_bus_add() skips registering the userspace visible 22093dbc80a3SHans de Goede * backlight_device. The intend is for this to be registered by the 22103dbc80a3SHans de Goede * drm/kms driver calling acpi_video_register_backlight() *after* it is 22113dbc80a3SHans de Goede * done setting up its own native backlight device. The delayed work 22123dbc80a3SHans de Goede * ensures that acpi_video_register_backlight() always gets called 22133dbc80a3SHans de Goede * eventually, in case there is no drm/kms driver or it is disabled. 22143dbc80a3SHans de Goede */ 22153dbc80a3SHans de Goede if (register_backlight_delay) 22163dbc80a3SHans de Goede schedule_delayed_work(&video_bus_register_backlight_work, 22173dbc80a3SHans de Goede register_backlight_delay * HZ); 22183dbc80a3SHans de Goede 22192a8b18e9SHans de Goede leave: 2220970530cdSHans de Goede mutex_unlock(®ister_count_mutex); 22212a8b18e9SHans de Goede return ret; 222214ca7a47SHans de Goede } 222314ca7a47SHans de Goede EXPORT_SYMBOL(acpi_video_register); 222414ca7a47SHans de Goede 222514ca7a47SHans de Goede void acpi_video_unregister(void) 222614ca7a47SHans de Goede { 2227970530cdSHans de Goede mutex_lock(®ister_count_mutex); 2228970530cdSHans de Goede if (register_count) { 22293dbc80a3SHans de Goede cancel_delayed_work_sync(&video_bus_register_backlight_work); 223014ca7a47SHans de Goede acpi_bus_unregister_driver(&acpi_video_bus); 2231970530cdSHans de Goede register_count = 0; 22325ad26161SHans de Goede may_report_brightness_keys = false; 22332a8b18e9SHans de Goede } 2234970530cdSHans de Goede mutex_unlock(®ister_count_mutex); 223514ca7a47SHans de Goede } 223614ca7a47SHans de Goede EXPORT_SYMBOL(acpi_video_unregister); 223714ca7a47SHans de Goede 22383dbc80a3SHans de Goede void acpi_video_register_backlight(void) 223914ca7a47SHans de Goede { 224014ca7a47SHans de Goede struct acpi_video_bus *video; 224114ca7a47SHans de Goede 224214ca7a47SHans de Goede mutex_lock(&video_list_lock); 224314ca7a47SHans de Goede list_for_each_entry(video, &video_bus_head, entry) 22443dbc80a3SHans de Goede acpi_video_bus_register_backlight(video); 224514ca7a47SHans de Goede mutex_unlock(&video_list_lock); 224614ca7a47SHans de Goede } 22473dbc80a3SHans de Goede EXPORT_SYMBOL(acpi_video_register_backlight); 224814ca7a47SHans de Goede 224990b066b1SHans de Goede bool acpi_video_handles_brightness_key_presses(void) 225090b066b1SHans de Goede { 22515ad26161SHans de Goede return may_report_brightness_keys && 225205bc59a0SHans de Goede (report_key_events & REPORT_BRIGHTNESS_KEY_EVENTS); 225390b066b1SHans de Goede } 225490b066b1SHans de Goede EXPORT_SYMBOL(acpi_video_handles_brightness_key_presses); 225590b066b1SHans de Goede 225614ca7a47SHans de Goede /* 225714ca7a47SHans de Goede * This is kind of nasty. Hardware using Intel chipsets may require 225814ca7a47SHans de Goede * the video opregion code to be run first in order to initialise 225914ca7a47SHans de Goede * state before any ACPI video calls are made. To handle this we defer 226014ca7a47SHans de Goede * registration of the video class until the opregion code has run. 226114ca7a47SHans de Goede */ 226214ca7a47SHans de Goede 226314ca7a47SHans de Goede static int __init acpi_video_init(void) 226414ca7a47SHans de Goede { 226514ca7a47SHans de Goede /* 226614ca7a47SHans de Goede * Let the module load even if ACPI is disabled (e.g. due to 226714ca7a47SHans de Goede * a broken BIOS) so that i915.ko can still be loaded on such 226814ca7a47SHans de Goede * old systems without an AcpiOpRegion. 226914ca7a47SHans de Goede * 227014ca7a47SHans de Goede * acpi_video_register() will report -ENODEV later as well due 227114ca7a47SHans de Goede * to acpi_disabled when i915.ko tries to register itself afterwards. 227214ca7a47SHans de Goede */ 227314ca7a47SHans de Goede if (acpi_disabled) 227414ca7a47SHans de Goede return 0; 227514ca7a47SHans de Goede 227614ca7a47SHans de Goede if (intel_opregion_present()) 227714ca7a47SHans de Goede return 0; 227814ca7a47SHans de Goede 227914ca7a47SHans de Goede return acpi_video_register(); 228014ca7a47SHans de Goede } 228114ca7a47SHans de Goede 228214ca7a47SHans de Goede static void __exit acpi_video_exit(void) 228314ca7a47SHans de Goede { 228414ca7a47SHans de Goede acpi_video_unregister(); 228514ca7a47SHans de Goede } 228614ca7a47SHans de Goede 228714ca7a47SHans de Goede module_init(acpi_video_init); 228814ca7a47SHans de Goede module_exit(acpi_video_exit); 2289