114ca7a47SHans de Goede /* 214ca7a47SHans de Goede * video.c - ACPI Video Driver 314ca7a47SHans de Goede * 414ca7a47SHans de Goede * Copyright (C) 2004 Luming Yu <luming.yu@intel.com> 514ca7a47SHans de Goede * Copyright (C) 2004 Bruno Ducrot <ducrot@poupinou.org> 614ca7a47SHans de Goede * Copyright (C) 2006 Thomas Tuttle <linux-kernel@ttuttle.net> 714ca7a47SHans de Goede * 814ca7a47SHans de Goede * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 914ca7a47SHans de Goede * 1014ca7a47SHans de Goede * This program is free software; you can redistribute it and/or modify 1114ca7a47SHans de Goede * it under the terms of the GNU General Public License as published by 1214ca7a47SHans de Goede * the Free Software Foundation; either version 2 of the License, or (at 1314ca7a47SHans de Goede * your option) any later version. 1414ca7a47SHans de Goede * 1514ca7a47SHans de Goede * This program is distributed in the hope that it will be useful, but 1614ca7a47SHans de Goede * WITHOUT ANY WARRANTY; without even the implied warranty of 1714ca7a47SHans de Goede * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 1814ca7a47SHans de Goede * General Public License for more details. 1914ca7a47SHans de Goede * 2014ca7a47SHans de Goede * You should have received a copy of the GNU General Public License along 2114ca7a47SHans de Goede * with this program; if not, write to the Free Software Foundation, Inc., 2214ca7a47SHans de Goede * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. 2314ca7a47SHans de Goede * 2414ca7a47SHans de Goede * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 2514ca7a47SHans de Goede */ 2614ca7a47SHans de Goede 2714ca7a47SHans de Goede #include <linux/kernel.h> 2814ca7a47SHans de Goede #include <linux/module.h> 2914ca7a47SHans de Goede #include <linux/init.h> 3014ca7a47SHans de Goede #include <linux/types.h> 3114ca7a47SHans de Goede #include <linux/list.h> 3214ca7a47SHans de Goede #include <linux/mutex.h> 3314ca7a47SHans de Goede #include <linux/input.h> 3414ca7a47SHans de Goede #include <linux/backlight.h> 3514ca7a47SHans de Goede #include <linux/thermal.h> 3614ca7a47SHans de Goede #include <linux/sort.h> 3714ca7a47SHans de Goede #include <linux/pci.h> 3814ca7a47SHans de Goede #include <linux/pci_ids.h> 3914ca7a47SHans de Goede #include <linux/slab.h> 4014ca7a47SHans de Goede #include <linux/dmi.h> 4114ca7a47SHans de Goede #include <linux/suspend.h> 4214ca7a47SHans de Goede #include <linux/acpi.h> 4314ca7a47SHans de Goede #include <acpi/video.h> 4414ca7a47SHans de Goede #include <asm/uaccess.h> 4514ca7a47SHans de Goede 4614ca7a47SHans de Goede #define PREFIX "ACPI: " 4714ca7a47SHans de Goede 4814ca7a47SHans de Goede #define ACPI_VIDEO_BUS_NAME "Video Bus" 4914ca7a47SHans de Goede #define ACPI_VIDEO_DEVICE_NAME "Video Device" 5014ca7a47SHans de Goede #define ACPI_VIDEO_NOTIFY_SWITCH 0x80 5114ca7a47SHans de Goede #define ACPI_VIDEO_NOTIFY_PROBE 0x81 5214ca7a47SHans de Goede #define ACPI_VIDEO_NOTIFY_CYCLE 0x82 5314ca7a47SHans de Goede #define ACPI_VIDEO_NOTIFY_NEXT_OUTPUT 0x83 5414ca7a47SHans de Goede #define ACPI_VIDEO_NOTIFY_PREV_OUTPUT 0x84 5514ca7a47SHans de Goede 5614ca7a47SHans de Goede #define ACPI_VIDEO_NOTIFY_CYCLE_BRIGHTNESS 0x85 5714ca7a47SHans de Goede #define ACPI_VIDEO_NOTIFY_INC_BRIGHTNESS 0x86 5814ca7a47SHans de Goede #define ACPI_VIDEO_NOTIFY_DEC_BRIGHTNESS 0x87 5914ca7a47SHans de Goede #define ACPI_VIDEO_NOTIFY_ZERO_BRIGHTNESS 0x88 6014ca7a47SHans de Goede #define ACPI_VIDEO_NOTIFY_DISPLAY_OFF 0x89 6114ca7a47SHans de Goede 6214ca7a47SHans de Goede #define MAX_NAME_LEN 20 6314ca7a47SHans de Goede 6414ca7a47SHans de Goede #define _COMPONENT ACPI_VIDEO_COMPONENT 6514ca7a47SHans de Goede ACPI_MODULE_NAME("video"); 6614ca7a47SHans de Goede 6714ca7a47SHans de Goede MODULE_AUTHOR("Bruno Ducrot"); 6814ca7a47SHans de Goede MODULE_DESCRIPTION("ACPI Video Driver"); 6914ca7a47SHans de Goede MODULE_LICENSE("GPL"); 7014ca7a47SHans de Goede 7114ca7a47SHans de Goede static bool brightness_switch_enabled = 1; 7214ca7a47SHans de Goede module_param(brightness_switch_enabled, bool, 0644); 7314ca7a47SHans de Goede 7414ca7a47SHans de Goede /* 7514ca7a47SHans de Goede * By default, we don't allow duplicate ACPI video bus devices 7614ca7a47SHans de Goede * under the same VGA controller 7714ca7a47SHans de Goede */ 7814ca7a47SHans de Goede static bool allow_duplicates; 7914ca7a47SHans de Goede module_param(allow_duplicates, bool, 0644); 8014ca7a47SHans de Goede 8114ca7a47SHans de Goede static int disable_backlight_sysfs_if = -1; 8214ca7a47SHans de Goede module_param(disable_backlight_sysfs_if, int, 0444); 8314ca7a47SHans de Goede 8414ca7a47SHans de Goede static int register_count; 8514ca7a47SHans de Goede static struct mutex video_list_lock; 8614ca7a47SHans de Goede static struct list_head video_bus_head; 8714ca7a47SHans de Goede static int acpi_video_bus_add(struct acpi_device *device); 8814ca7a47SHans de Goede static int acpi_video_bus_remove(struct acpi_device *device); 8914ca7a47SHans de Goede static void acpi_video_bus_notify(struct acpi_device *device, u32 event); 90*93a291dfSHans de Goede void acpi_video_detect_exit(void); 9114ca7a47SHans de Goede 9214ca7a47SHans de Goede static const struct acpi_device_id video_device_ids[] = { 9314ca7a47SHans de Goede {ACPI_VIDEO_HID, 0}, 9414ca7a47SHans de Goede {"", 0}, 9514ca7a47SHans de Goede }; 9614ca7a47SHans de Goede MODULE_DEVICE_TABLE(acpi, video_device_ids); 9714ca7a47SHans de Goede 9814ca7a47SHans de Goede static struct acpi_driver acpi_video_bus = { 9914ca7a47SHans de Goede .name = "video", 10014ca7a47SHans de Goede .class = ACPI_VIDEO_CLASS, 10114ca7a47SHans de Goede .ids = video_device_ids, 10214ca7a47SHans de Goede .ops = { 10314ca7a47SHans de Goede .add = acpi_video_bus_add, 10414ca7a47SHans de Goede .remove = acpi_video_bus_remove, 10514ca7a47SHans de Goede .notify = acpi_video_bus_notify, 10614ca7a47SHans de Goede }, 10714ca7a47SHans de Goede }; 10814ca7a47SHans de Goede 10914ca7a47SHans de Goede struct acpi_video_bus_flags { 11014ca7a47SHans de Goede u8 multihead:1; /* can switch video heads */ 11114ca7a47SHans de Goede u8 rom:1; /* can retrieve a video rom */ 11214ca7a47SHans de Goede u8 post:1; /* can configure the head to */ 11314ca7a47SHans de Goede u8 reserved:5; 11414ca7a47SHans de Goede }; 11514ca7a47SHans de Goede 11614ca7a47SHans de Goede struct acpi_video_bus_cap { 11714ca7a47SHans de Goede u8 _DOS:1; /* Enable/Disable output switching */ 11814ca7a47SHans de Goede u8 _DOD:1; /* Enumerate all devices attached to display adapter */ 11914ca7a47SHans de Goede u8 _ROM:1; /* Get ROM Data */ 12014ca7a47SHans de Goede u8 _GPD:1; /* Get POST Device */ 12114ca7a47SHans de Goede u8 _SPD:1; /* Set POST Device */ 12214ca7a47SHans de Goede u8 _VPO:1; /* Video POST Options */ 12314ca7a47SHans de Goede u8 reserved:2; 12414ca7a47SHans de Goede }; 12514ca7a47SHans de Goede 12614ca7a47SHans de Goede struct acpi_video_device_attrib { 12714ca7a47SHans de Goede u32 display_index:4; /* A zero-based instance of the Display */ 12814ca7a47SHans de Goede u32 display_port_attachment:4; /* This field differentiates the display type */ 12914ca7a47SHans de Goede u32 display_type:4; /* Describe the specific type in use */ 13014ca7a47SHans de Goede u32 vendor_specific:4; /* Chipset Vendor Specific */ 13114ca7a47SHans de Goede u32 bios_can_detect:1; /* BIOS can detect the device */ 13214ca7a47SHans de Goede u32 depend_on_vga:1; /* Non-VGA output device whose power is related to 13314ca7a47SHans de Goede the VGA device. */ 13414ca7a47SHans de Goede u32 pipe_id:3; /* For VGA multiple-head devices. */ 13514ca7a47SHans de Goede u32 reserved:10; /* Must be 0 */ 13614ca7a47SHans de Goede u32 device_id_scheme:1; /* Device ID Scheme */ 13714ca7a47SHans de Goede }; 13814ca7a47SHans de Goede 13914ca7a47SHans de Goede struct acpi_video_enumerated_device { 14014ca7a47SHans de Goede union { 14114ca7a47SHans de Goede u32 int_val; 14214ca7a47SHans de Goede struct acpi_video_device_attrib attrib; 14314ca7a47SHans de Goede } value; 14414ca7a47SHans de Goede struct acpi_video_device *bind_info; 14514ca7a47SHans de Goede }; 14614ca7a47SHans de Goede 14714ca7a47SHans de Goede struct acpi_video_bus { 14814ca7a47SHans de Goede struct acpi_device *device; 14914ca7a47SHans de Goede bool backlight_registered; 15014ca7a47SHans de Goede u8 dos_setting; 15114ca7a47SHans de Goede struct acpi_video_enumerated_device *attached_array; 15214ca7a47SHans de Goede u8 attached_count; 15314ca7a47SHans de Goede u8 child_count; 15414ca7a47SHans de Goede struct acpi_video_bus_cap cap; 15514ca7a47SHans de Goede struct acpi_video_bus_flags flags; 15614ca7a47SHans de Goede struct list_head video_device_list; 15714ca7a47SHans de Goede struct mutex device_list_lock; /* protects video_device_list */ 15814ca7a47SHans de Goede struct list_head entry; 15914ca7a47SHans de Goede struct input_dev *input; 16014ca7a47SHans de Goede char phys[32]; /* for input device */ 16114ca7a47SHans de Goede struct notifier_block pm_nb; 16214ca7a47SHans de Goede }; 16314ca7a47SHans de Goede 16414ca7a47SHans de Goede struct acpi_video_device_flags { 16514ca7a47SHans de Goede u8 crt:1; 16614ca7a47SHans de Goede u8 lcd:1; 16714ca7a47SHans de Goede u8 tvout:1; 16814ca7a47SHans de Goede u8 dvi:1; 16914ca7a47SHans de Goede u8 bios:1; 17014ca7a47SHans de Goede u8 unknown:1; 17114ca7a47SHans de Goede u8 notify:1; 17214ca7a47SHans de Goede u8 reserved:1; 17314ca7a47SHans de Goede }; 17414ca7a47SHans de Goede 17514ca7a47SHans de Goede struct acpi_video_device_cap { 17614ca7a47SHans de Goede u8 _ADR:1; /* Return the unique ID */ 17714ca7a47SHans de Goede u8 _BCL:1; /* Query list of brightness control levels supported */ 17814ca7a47SHans de Goede u8 _BCM:1; /* Set the brightness level */ 17914ca7a47SHans de Goede u8 _BQC:1; /* Get current brightness level */ 18014ca7a47SHans de Goede u8 _BCQ:1; /* Some buggy BIOS uses _BCQ instead of _BQC */ 18114ca7a47SHans de Goede u8 _DDC:1; /* Return the EDID for this device */ 18214ca7a47SHans de Goede }; 18314ca7a47SHans de Goede 18414ca7a47SHans de Goede struct acpi_video_brightness_flags { 18514ca7a47SHans de Goede u8 _BCL_no_ac_battery_levels:1; /* no AC/Battery levels in _BCL */ 18614ca7a47SHans de Goede u8 _BCL_reversed:1; /* _BCL package is in a reversed order */ 18714ca7a47SHans de Goede u8 _BQC_use_index:1; /* _BQC returns an index value */ 18814ca7a47SHans de Goede }; 18914ca7a47SHans de Goede 19014ca7a47SHans de Goede struct acpi_video_device_brightness { 19114ca7a47SHans de Goede int curr; 19214ca7a47SHans de Goede int count; 19314ca7a47SHans de Goede int *levels; 19414ca7a47SHans de Goede struct acpi_video_brightness_flags flags; 19514ca7a47SHans de Goede }; 19614ca7a47SHans de Goede 19714ca7a47SHans de Goede struct acpi_video_device { 19814ca7a47SHans de Goede unsigned long device_id; 19914ca7a47SHans de Goede struct acpi_video_device_flags flags; 20014ca7a47SHans de Goede struct acpi_video_device_cap cap; 20114ca7a47SHans de Goede struct list_head entry; 20214ca7a47SHans de Goede struct delayed_work switch_brightness_work; 20314ca7a47SHans de Goede int switch_brightness_event; 20414ca7a47SHans de Goede struct acpi_video_bus *video; 20514ca7a47SHans de Goede struct acpi_device *dev; 20614ca7a47SHans de Goede struct acpi_video_device_brightness *brightness; 20714ca7a47SHans de Goede struct backlight_device *backlight; 20814ca7a47SHans de Goede struct thermal_cooling_device *cooling_dev; 20914ca7a47SHans de Goede }; 21014ca7a47SHans de Goede 21114ca7a47SHans de Goede static const char device_decode[][30] = { 21214ca7a47SHans de Goede "motherboard VGA device", 21314ca7a47SHans de Goede "PCI VGA device", 21414ca7a47SHans de Goede "AGP VGA device", 21514ca7a47SHans de Goede "UNKNOWN", 21614ca7a47SHans de Goede }; 21714ca7a47SHans de Goede 21814ca7a47SHans de Goede static void acpi_video_device_notify(acpi_handle handle, u32 event, void *data); 21914ca7a47SHans de Goede static void acpi_video_device_rebind(struct acpi_video_bus *video); 22014ca7a47SHans de Goede static void acpi_video_device_bind(struct acpi_video_bus *video, 22114ca7a47SHans de Goede struct acpi_video_device *device); 22214ca7a47SHans de Goede static int acpi_video_device_enumerate(struct acpi_video_bus *video); 22314ca7a47SHans de Goede static int acpi_video_device_lcd_set_level(struct acpi_video_device *device, 22414ca7a47SHans de Goede int level); 22514ca7a47SHans de Goede static int acpi_video_device_lcd_get_level_current( 22614ca7a47SHans de Goede struct acpi_video_device *device, 22714ca7a47SHans de Goede unsigned long long *level, bool raw); 22814ca7a47SHans de Goede static int acpi_video_get_next_level(struct acpi_video_device *device, 22914ca7a47SHans de Goede u32 level_current, u32 event); 23014ca7a47SHans de Goede static void acpi_video_switch_brightness(struct work_struct *work); 23114ca7a47SHans de Goede 23214ca7a47SHans de Goede /* backlight device sysfs support */ 23314ca7a47SHans de Goede static int acpi_video_get_brightness(struct backlight_device *bd) 23414ca7a47SHans de Goede { 23514ca7a47SHans de Goede unsigned long long cur_level; 23614ca7a47SHans de Goede int i; 23714ca7a47SHans de Goede struct acpi_video_device *vd = bl_get_data(bd); 23814ca7a47SHans de Goede 23914ca7a47SHans de Goede if (acpi_video_device_lcd_get_level_current(vd, &cur_level, false)) 24014ca7a47SHans de Goede return -EINVAL; 24114ca7a47SHans de Goede for (i = 2; i < vd->brightness->count; i++) { 24214ca7a47SHans de Goede if (vd->brightness->levels[i] == cur_level) 24314ca7a47SHans de Goede /* 24414ca7a47SHans de Goede * The first two entries are special - see page 575 24514ca7a47SHans de Goede * of the ACPI spec 3.0 24614ca7a47SHans de Goede */ 24714ca7a47SHans de Goede return i - 2; 24814ca7a47SHans de Goede } 24914ca7a47SHans de Goede return 0; 25014ca7a47SHans de Goede } 25114ca7a47SHans de Goede 25214ca7a47SHans de Goede static int acpi_video_set_brightness(struct backlight_device *bd) 25314ca7a47SHans de Goede { 25414ca7a47SHans de Goede int request_level = bd->props.brightness + 2; 25514ca7a47SHans de Goede struct acpi_video_device *vd = bl_get_data(bd); 25614ca7a47SHans de Goede 25714ca7a47SHans de Goede cancel_delayed_work(&vd->switch_brightness_work); 25814ca7a47SHans de Goede return acpi_video_device_lcd_set_level(vd, 25914ca7a47SHans de Goede vd->brightness->levels[request_level]); 26014ca7a47SHans de Goede } 26114ca7a47SHans de Goede 26214ca7a47SHans de Goede static const struct backlight_ops acpi_backlight_ops = { 26314ca7a47SHans de Goede .get_brightness = acpi_video_get_brightness, 26414ca7a47SHans de Goede .update_status = acpi_video_set_brightness, 26514ca7a47SHans de Goede }; 26614ca7a47SHans de Goede 26714ca7a47SHans de Goede /* thermal cooling device callbacks */ 26814ca7a47SHans de Goede static int video_get_max_state(struct thermal_cooling_device *cooling_dev, unsigned 26914ca7a47SHans de Goede long *state) 27014ca7a47SHans de Goede { 27114ca7a47SHans de Goede struct acpi_device *device = cooling_dev->devdata; 27214ca7a47SHans de Goede struct acpi_video_device *video = acpi_driver_data(device); 27314ca7a47SHans de Goede 27414ca7a47SHans de Goede *state = video->brightness->count - 3; 27514ca7a47SHans de Goede return 0; 27614ca7a47SHans de Goede } 27714ca7a47SHans de Goede 27814ca7a47SHans de Goede static int video_get_cur_state(struct thermal_cooling_device *cooling_dev, unsigned 27914ca7a47SHans de Goede long *state) 28014ca7a47SHans de Goede { 28114ca7a47SHans de Goede struct acpi_device *device = cooling_dev->devdata; 28214ca7a47SHans de Goede struct acpi_video_device *video = acpi_driver_data(device); 28314ca7a47SHans de Goede unsigned long long level; 28414ca7a47SHans de Goede int offset; 28514ca7a47SHans de Goede 28614ca7a47SHans de Goede if (acpi_video_device_lcd_get_level_current(video, &level, false)) 28714ca7a47SHans de Goede return -EINVAL; 28814ca7a47SHans de Goede for (offset = 2; offset < video->brightness->count; 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 30414ca7a47SHans de Goede if (state >= video->brightness->count - 2) 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 32514ca7a47SHans de Goede acpi_video_device_lcd_query_levels(struct acpi_video_device *device, 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 33514ca7a47SHans de Goede status = acpi_evaluate_object(device->dev->handle, "_BCL", NULL, &buffer); 33614ca7a47SHans de Goede if (!ACPI_SUCCESS(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)) { 34014ca7a47SHans de Goede printk(KERN_ERR PREFIX "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)) { 36414ca7a47SHans de Goede ACPI_ERROR((AE_INFO, "Evaluating _BCM failed")); 36514ca7a47SHans de Goede return -EIO; 36614ca7a47SHans de Goede } 36714ca7a47SHans de Goede 36814ca7a47SHans de Goede device->brightness->curr = level; 36914ca7a47SHans de Goede for (state = 2; state < device->brightness->count; state++) 37014ca7a47SHans de Goede if (level == device->brightness->levels[state]) { 37114ca7a47SHans de Goede if (device->backlight) 37214ca7a47SHans de Goede device->backlight->props.brightness = state - 2; 37314ca7a47SHans de Goede return 0; 37414ca7a47SHans de Goede } 37514ca7a47SHans de Goede 37614ca7a47SHans de Goede ACPI_ERROR((AE_INFO, "Current brightness invalid")); 37714ca7a47SHans de Goede return -EINVAL; 37814ca7a47SHans de Goede } 37914ca7a47SHans de Goede 38014ca7a47SHans de Goede /* 38114ca7a47SHans de Goede * For some buggy _BQC methods, we need to add a constant value to 38214ca7a47SHans de Goede * the _BQC return value to get the actual current brightness level 38314ca7a47SHans de Goede */ 38414ca7a47SHans de Goede 38514ca7a47SHans de Goede static int bqc_offset_aml_bug_workaround; 38614ca7a47SHans de Goede static int __init video_set_bqc_offset(const struct dmi_system_id *d) 38714ca7a47SHans de Goede { 38814ca7a47SHans de Goede bqc_offset_aml_bug_workaround = 9; 38914ca7a47SHans de Goede return 0; 39014ca7a47SHans de Goede } 39114ca7a47SHans de Goede 39214ca7a47SHans de Goede static int __init video_disable_backlight_sysfs_if( 39314ca7a47SHans de Goede const struct dmi_system_id *d) 39414ca7a47SHans de Goede { 39514ca7a47SHans de Goede if (disable_backlight_sysfs_if == -1) 39614ca7a47SHans de Goede disable_backlight_sysfs_if = 1; 39714ca7a47SHans de Goede return 0; 39814ca7a47SHans de Goede } 39914ca7a47SHans de Goede 40014ca7a47SHans de Goede static struct dmi_system_id video_dmi_table[] __initdata = { 40114ca7a47SHans de Goede /* 40214ca7a47SHans de Goede * Broken _BQC workaround http://bugzilla.kernel.org/show_bug.cgi?id=13121 40314ca7a47SHans de Goede */ 40414ca7a47SHans de Goede { 40514ca7a47SHans de Goede .callback = video_set_bqc_offset, 40614ca7a47SHans de Goede .ident = "Acer Aspire 5720", 40714ca7a47SHans de Goede .matches = { 40814ca7a47SHans de Goede DMI_MATCH(DMI_BOARD_VENDOR, "Acer"), 40914ca7a47SHans de Goede DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5720"), 41014ca7a47SHans de Goede }, 41114ca7a47SHans de Goede }, 41214ca7a47SHans de Goede { 41314ca7a47SHans de Goede .callback = video_set_bqc_offset, 41414ca7a47SHans de Goede .ident = "Acer Aspire 5710Z", 41514ca7a47SHans de Goede .matches = { 41614ca7a47SHans de Goede DMI_MATCH(DMI_BOARD_VENDOR, "Acer"), 41714ca7a47SHans de Goede DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5710Z"), 41814ca7a47SHans de Goede }, 41914ca7a47SHans de Goede }, 42014ca7a47SHans de Goede { 42114ca7a47SHans de Goede .callback = video_set_bqc_offset, 42214ca7a47SHans de Goede .ident = "eMachines E510", 42314ca7a47SHans de Goede .matches = { 42414ca7a47SHans de Goede DMI_MATCH(DMI_BOARD_VENDOR, "EMACHINES"), 42514ca7a47SHans de Goede DMI_MATCH(DMI_PRODUCT_NAME, "eMachines E510"), 42614ca7a47SHans de Goede }, 42714ca7a47SHans de Goede }, 42814ca7a47SHans de Goede { 42914ca7a47SHans de Goede .callback = video_set_bqc_offset, 43014ca7a47SHans de Goede .ident = "Acer Aspire 5315", 43114ca7a47SHans de Goede .matches = { 43214ca7a47SHans de Goede DMI_MATCH(DMI_BOARD_VENDOR, "Acer"), 43314ca7a47SHans de Goede DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5315"), 43414ca7a47SHans de Goede }, 43514ca7a47SHans de Goede }, 43614ca7a47SHans de Goede { 43714ca7a47SHans de Goede .callback = video_set_bqc_offset, 43814ca7a47SHans de Goede .ident = "Acer Aspire 7720", 43914ca7a47SHans de Goede .matches = { 44014ca7a47SHans de Goede DMI_MATCH(DMI_BOARD_VENDOR, "Acer"), 44114ca7a47SHans de Goede DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 7720"), 44214ca7a47SHans de Goede }, 44314ca7a47SHans de Goede }, 44414ca7a47SHans de Goede 44514ca7a47SHans de Goede /* 44614ca7a47SHans de Goede * Some machines have a broken acpi-video interface for brightness 44714ca7a47SHans de Goede * control, but still need an acpi_video_device_lcd_set_level() call 44814ca7a47SHans de Goede * on resume to turn the backlight power on. We Enable backlight 44914ca7a47SHans de Goede * control on these systems, but do not register a backlight sysfs 45014ca7a47SHans de Goede * as brightness control does not work. 45114ca7a47SHans de Goede */ 45214ca7a47SHans de Goede { 45314ca7a47SHans de Goede /* https://bugs.freedesktop.org/show_bug.cgi?id=82634 */ 45414ca7a47SHans de Goede .callback = video_disable_backlight_sysfs_if, 45514ca7a47SHans de Goede .ident = "Toshiba Portege R830", 45614ca7a47SHans de Goede .matches = { 45714ca7a47SHans de Goede DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"), 45814ca7a47SHans de Goede DMI_MATCH(DMI_PRODUCT_NAME, "PORTEGE R830"), 45914ca7a47SHans de Goede }, 46014ca7a47SHans de Goede }, 46114ca7a47SHans de Goede {} 46214ca7a47SHans de Goede }; 46314ca7a47SHans de Goede 46414ca7a47SHans de Goede static unsigned long long 46514ca7a47SHans de Goede acpi_video_bqc_value_to_level(struct acpi_video_device *device, 46614ca7a47SHans de Goede unsigned long long bqc_value) 46714ca7a47SHans de Goede { 46814ca7a47SHans de Goede unsigned long long level; 46914ca7a47SHans de Goede 47014ca7a47SHans de Goede if (device->brightness->flags._BQC_use_index) { 47114ca7a47SHans de Goede /* 47214ca7a47SHans de Goede * _BQC returns an index that doesn't account for 47314ca7a47SHans de Goede * the first 2 items with special meaning, so we need 47414ca7a47SHans de Goede * to compensate for that by offsetting ourselves 47514ca7a47SHans de Goede */ 47614ca7a47SHans de Goede if (device->brightness->flags._BCL_reversed) 47714ca7a47SHans de Goede bqc_value = device->brightness->count - 3 - bqc_value; 47814ca7a47SHans de Goede 47914ca7a47SHans de Goede level = device->brightness->levels[bqc_value + 2]; 48014ca7a47SHans de Goede } else { 48114ca7a47SHans de Goede level = bqc_value; 48214ca7a47SHans de Goede } 48314ca7a47SHans de Goede 48414ca7a47SHans de Goede level += bqc_offset_aml_bug_workaround; 48514ca7a47SHans de Goede 48614ca7a47SHans de Goede return level; 48714ca7a47SHans de Goede } 48814ca7a47SHans de Goede 48914ca7a47SHans de Goede static int 49014ca7a47SHans de Goede acpi_video_device_lcd_get_level_current(struct acpi_video_device *device, 49114ca7a47SHans de Goede unsigned long long *level, bool raw) 49214ca7a47SHans de Goede { 49314ca7a47SHans de Goede acpi_status status = AE_OK; 49414ca7a47SHans de Goede int i; 49514ca7a47SHans de Goede 49614ca7a47SHans de Goede if (device->cap._BQC || device->cap._BCQ) { 49714ca7a47SHans de Goede char *buf = device->cap._BQC ? "_BQC" : "_BCQ"; 49814ca7a47SHans de Goede 49914ca7a47SHans de Goede status = acpi_evaluate_integer(device->dev->handle, buf, 50014ca7a47SHans de Goede NULL, level); 50114ca7a47SHans de Goede if (ACPI_SUCCESS(status)) { 50214ca7a47SHans de Goede if (raw) { 50314ca7a47SHans de Goede /* 50414ca7a47SHans de Goede * Caller has indicated he wants the raw 50514ca7a47SHans de Goede * value returned by _BQC, so don't furtherly 50614ca7a47SHans de Goede * mess with the value. 50714ca7a47SHans de Goede */ 50814ca7a47SHans de Goede return 0; 50914ca7a47SHans de Goede } 51014ca7a47SHans de Goede 51114ca7a47SHans de Goede *level = acpi_video_bqc_value_to_level(device, *level); 51214ca7a47SHans de Goede 51314ca7a47SHans de Goede for (i = 2; i < device->brightness->count; i++) 51414ca7a47SHans de Goede if (device->brightness->levels[i] == *level) { 51514ca7a47SHans de Goede device->brightness->curr = *level; 51614ca7a47SHans de Goede return 0; 51714ca7a47SHans de Goede } 51814ca7a47SHans de Goede /* 51914ca7a47SHans de Goede * BQC returned an invalid level. 52014ca7a47SHans de Goede * Stop using it. 52114ca7a47SHans de Goede */ 52214ca7a47SHans de Goede ACPI_WARNING((AE_INFO, 52314ca7a47SHans de Goede "%s returned an invalid level", 52414ca7a47SHans de Goede buf)); 52514ca7a47SHans de Goede device->cap._BQC = device->cap._BCQ = 0; 52614ca7a47SHans de Goede } else { 52714ca7a47SHans de Goede /* 52814ca7a47SHans de Goede * Fixme: 52914ca7a47SHans de Goede * should we return an error or ignore this failure? 53014ca7a47SHans de Goede * dev->brightness->curr is a cached value which stores 53114ca7a47SHans de Goede * the correct current backlight level in most cases. 53214ca7a47SHans de Goede * ACPI video backlight still works w/ buggy _BQC. 53314ca7a47SHans de Goede * http://bugzilla.kernel.org/show_bug.cgi?id=12233 53414ca7a47SHans de Goede */ 53514ca7a47SHans de Goede ACPI_WARNING((AE_INFO, "Evaluating %s failed", buf)); 53614ca7a47SHans de Goede device->cap._BQC = device->cap._BCQ = 0; 53714ca7a47SHans de Goede } 53814ca7a47SHans de Goede } 53914ca7a47SHans de Goede 54014ca7a47SHans de Goede *level = device->brightness->curr; 54114ca7a47SHans de Goede return 0; 54214ca7a47SHans de Goede } 54314ca7a47SHans de Goede 54414ca7a47SHans de Goede static int 54514ca7a47SHans de Goede acpi_video_device_EDID(struct acpi_video_device *device, 54614ca7a47SHans de Goede union acpi_object **edid, ssize_t length) 54714ca7a47SHans de Goede { 54814ca7a47SHans de Goede int status; 54914ca7a47SHans de Goede struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; 55014ca7a47SHans de Goede union acpi_object *obj; 55114ca7a47SHans de Goede union acpi_object arg0 = { ACPI_TYPE_INTEGER }; 55214ca7a47SHans de Goede struct acpi_object_list args = { 1, &arg0 }; 55314ca7a47SHans de Goede 55414ca7a47SHans de Goede 55514ca7a47SHans de Goede *edid = NULL; 55614ca7a47SHans de Goede 55714ca7a47SHans de Goede if (!device) 55814ca7a47SHans de Goede return -ENODEV; 55914ca7a47SHans de Goede if (length == 128) 56014ca7a47SHans de Goede arg0.integer.value = 1; 56114ca7a47SHans de Goede else if (length == 256) 56214ca7a47SHans de Goede arg0.integer.value = 2; 56314ca7a47SHans de Goede else 56414ca7a47SHans de Goede return -EINVAL; 56514ca7a47SHans de Goede 56614ca7a47SHans de Goede status = acpi_evaluate_object(device->dev->handle, "_DDC", &args, &buffer); 56714ca7a47SHans de Goede if (ACPI_FAILURE(status)) 56814ca7a47SHans de Goede return -ENODEV; 56914ca7a47SHans de Goede 57014ca7a47SHans de Goede obj = buffer.pointer; 57114ca7a47SHans de Goede 57214ca7a47SHans de Goede if (obj && obj->type == ACPI_TYPE_BUFFER) 57314ca7a47SHans de Goede *edid = obj; 57414ca7a47SHans de Goede else { 57514ca7a47SHans de Goede printk(KERN_ERR PREFIX "Invalid _DDC data\n"); 57614ca7a47SHans de Goede status = -EFAULT; 57714ca7a47SHans de Goede kfree(obj); 57814ca7a47SHans de Goede } 57914ca7a47SHans de Goede 58014ca7a47SHans de Goede return status; 58114ca7a47SHans de Goede } 58214ca7a47SHans de Goede 58314ca7a47SHans de Goede /* bus */ 58414ca7a47SHans de Goede 58514ca7a47SHans de Goede /* 58614ca7a47SHans de Goede * Arg: 58714ca7a47SHans de Goede * video : video bus device pointer 58814ca7a47SHans de Goede * bios_flag : 58914ca7a47SHans de Goede * 0. The system BIOS should NOT automatically switch(toggle) 59014ca7a47SHans de Goede * the active display output. 59114ca7a47SHans de Goede * 1. The system BIOS should automatically switch (toggle) the 59214ca7a47SHans de Goede * active display output. No switch event. 59314ca7a47SHans de Goede * 2. The _DGS value should be locked. 59414ca7a47SHans de Goede * 3. The system BIOS should not automatically switch (toggle) the 59514ca7a47SHans de Goede * active display output, but instead generate the display switch 59614ca7a47SHans de Goede * event notify code. 59714ca7a47SHans de Goede * lcd_flag : 59814ca7a47SHans de Goede * 0. The system BIOS should automatically control the brightness level 59914ca7a47SHans de Goede * of the LCD when the power changes from AC to DC 60014ca7a47SHans de Goede * 1. The system BIOS should NOT automatically control the brightness 60114ca7a47SHans de Goede * level of the LCD when the power changes from AC to DC. 60214ca7a47SHans de Goede * Return Value: 60314ca7a47SHans de Goede * -EINVAL wrong arg. 60414ca7a47SHans de Goede */ 60514ca7a47SHans de Goede 60614ca7a47SHans de Goede static int 60714ca7a47SHans de Goede acpi_video_bus_DOS(struct acpi_video_bus *video, int bios_flag, int lcd_flag) 60814ca7a47SHans de Goede { 60914ca7a47SHans de Goede acpi_status status; 61014ca7a47SHans de Goede 61114ca7a47SHans de Goede if (!video->cap._DOS) 61214ca7a47SHans de Goede return 0; 61314ca7a47SHans de Goede 61414ca7a47SHans de Goede if (bios_flag < 0 || bios_flag > 3 || lcd_flag < 0 || lcd_flag > 1) 61514ca7a47SHans de Goede return -EINVAL; 61614ca7a47SHans de Goede video->dos_setting = (lcd_flag << 2) | bios_flag; 61714ca7a47SHans de Goede status = acpi_execute_simple_method(video->device->handle, "_DOS", 61814ca7a47SHans de Goede (lcd_flag << 2) | bios_flag); 61914ca7a47SHans de Goede if (ACPI_FAILURE(status)) 62014ca7a47SHans de Goede return -EIO; 62114ca7a47SHans de Goede 62214ca7a47SHans de Goede return 0; 62314ca7a47SHans de Goede } 62414ca7a47SHans de Goede 62514ca7a47SHans de Goede /* 62614ca7a47SHans de Goede * Simple comparison function used to sort backlight levels. 62714ca7a47SHans de Goede */ 62814ca7a47SHans de Goede 62914ca7a47SHans de Goede static int 63014ca7a47SHans de Goede acpi_video_cmp_level(const void *a, const void *b) 63114ca7a47SHans de Goede { 63214ca7a47SHans de Goede return *(int *)a - *(int *)b; 63314ca7a47SHans de Goede } 63414ca7a47SHans de Goede 63514ca7a47SHans de Goede /* 63614ca7a47SHans de Goede * Decides if _BQC/_BCQ for this system is usable 63714ca7a47SHans de Goede * 63814ca7a47SHans de Goede * We do this by changing the level first and then read out the current 63914ca7a47SHans de Goede * brightness level, if the value does not match, find out if it is using 64014ca7a47SHans de Goede * index. If not, clear the _BQC/_BCQ capability. 64114ca7a47SHans de Goede */ 64214ca7a47SHans de Goede static int acpi_video_bqc_quirk(struct acpi_video_device *device, 64314ca7a47SHans de Goede int max_level, int current_level) 64414ca7a47SHans de Goede { 64514ca7a47SHans de Goede struct acpi_video_device_brightness *br = device->brightness; 64614ca7a47SHans de Goede int result; 64714ca7a47SHans de Goede unsigned long long level; 64814ca7a47SHans de Goede int test_level; 64914ca7a47SHans de Goede 65014ca7a47SHans de Goede /* don't mess with existing known broken systems */ 65114ca7a47SHans de Goede if (bqc_offset_aml_bug_workaround) 65214ca7a47SHans de Goede return 0; 65314ca7a47SHans de Goede 65414ca7a47SHans de Goede /* 65514ca7a47SHans de Goede * Some systems always report current brightness level as maximum 65614ca7a47SHans de Goede * through _BQC, we need to test another value for them. 65714ca7a47SHans de Goede */ 65814ca7a47SHans de Goede test_level = current_level == max_level ? br->levels[3] : max_level; 65914ca7a47SHans de Goede 66014ca7a47SHans de Goede result = acpi_video_device_lcd_set_level(device, test_level); 66114ca7a47SHans de Goede if (result) 66214ca7a47SHans de Goede return result; 66314ca7a47SHans de Goede 66414ca7a47SHans de Goede result = acpi_video_device_lcd_get_level_current(device, &level, true); 66514ca7a47SHans de Goede if (result) 66614ca7a47SHans de Goede return result; 66714ca7a47SHans de Goede 66814ca7a47SHans de Goede if (level != test_level) { 66914ca7a47SHans de Goede /* buggy _BQC found, need to find out if it uses index */ 67014ca7a47SHans de Goede if (level < br->count) { 67114ca7a47SHans de Goede if (br->flags._BCL_reversed) 67214ca7a47SHans de Goede level = br->count - 3 - level; 67314ca7a47SHans de Goede if (br->levels[level + 2] == test_level) 67414ca7a47SHans de Goede br->flags._BQC_use_index = 1; 67514ca7a47SHans de Goede } 67614ca7a47SHans de Goede 67714ca7a47SHans de Goede if (!br->flags._BQC_use_index) 67814ca7a47SHans de Goede device->cap._BQC = device->cap._BCQ = 0; 67914ca7a47SHans de Goede } 68014ca7a47SHans de Goede 68114ca7a47SHans de Goede return 0; 68214ca7a47SHans de Goede } 68314ca7a47SHans de Goede 68414ca7a47SHans de Goede 68514ca7a47SHans de Goede /* 68614ca7a47SHans de Goede * Arg: 68714ca7a47SHans de Goede * device : video output device (LCD, CRT, ..) 68814ca7a47SHans de Goede * 68914ca7a47SHans de Goede * Return Value: 69014ca7a47SHans de Goede * Maximum brightness level 69114ca7a47SHans de Goede * 69214ca7a47SHans de Goede * Allocate and initialize device->brightness. 69314ca7a47SHans de Goede */ 69414ca7a47SHans de Goede 69514ca7a47SHans de Goede static int 69614ca7a47SHans de Goede acpi_video_init_brightness(struct acpi_video_device *device) 69714ca7a47SHans de Goede { 69814ca7a47SHans de Goede union acpi_object *obj = NULL; 69914ca7a47SHans de Goede int i, max_level = 0, count = 0, level_ac_battery = 0; 70014ca7a47SHans de Goede unsigned long long level, level_old; 70114ca7a47SHans de Goede union acpi_object *o; 70214ca7a47SHans de Goede struct acpi_video_device_brightness *br = NULL; 70314ca7a47SHans de Goede int result = -EINVAL; 70414ca7a47SHans de Goede u32 value; 70514ca7a47SHans de Goede 70614ca7a47SHans de Goede if (!ACPI_SUCCESS(acpi_video_device_lcd_query_levels(device, &obj))) { 70714ca7a47SHans de Goede ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Could not query available " 70814ca7a47SHans de Goede "LCD brightness level\n")); 70914ca7a47SHans de Goede goto out; 71014ca7a47SHans de Goede } 71114ca7a47SHans de Goede 71214ca7a47SHans de Goede if (obj->package.count < 2) 71314ca7a47SHans de Goede goto out; 71414ca7a47SHans de Goede 71514ca7a47SHans de Goede br = kzalloc(sizeof(*br), GFP_KERNEL); 71614ca7a47SHans de Goede if (!br) { 71714ca7a47SHans de Goede printk(KERN_ERR "can't allocate memory\n"); 71814ca7a47SHans de Goede result = -ENOMEM; 71914ca7a47SHans de Goede goto out; 72014ca7a47SHans de Goede } 72114ca7a47SHans de Goede 72214ca7a47SHans de Goede br->levels = kmalloc((obj->package.count + 2) * sizeof *(br->levels), 72314ca7a47SHans de Goede GFP_KERNEL); 72414ca7a47SHans de Goede if (!br->levels) { 72514ca7a47SHans de Goede result = -ENOMEM; 72614ca7a47SHans de Goede goto out_free; 72714ca7a47SHans de Goede } 72814ca7a47SHans de Goede 72914ca7a47SHans de Goede for (i = 0; i < obj->package.count; i++) { 73014ca7a47SHans de Goede o = (union acpi_object *)&obj->package.elements[i]; 73114ca7a47SHans de Goede if (o->type != ACPI_TYPE_INTEGER) { 73214ca7a47SHans de Goede printk(KERN_ERR PREFIX "Invalid data\n"); 73314ca7a47SHans de Goede continue; 73414ca7a47SHans de Goede } 73514ca7a47SHans de Goede value = (u32) o->integer.value; 73614ca7a47SHans de Goede /* Skip duplicate entries */ 73714ca7a47SHans de Goede if (count > 2 && br->levels[count - 1] == value) 73814ca7a47SHans de Goede continue; 73914ca7a47SHans de Goede 74014ca7a47SHans de Goede br->levels[count] = value; 74114ca7a47SHans de Goede 74214ca7a47SHans de Goede if (br->levels[count] > max_level) 74314ca7a47SHans de Goede max_level = br->levels[count]; 74414ca7a47SHans de Goede count++; 74514ca7a47SHans de Goede } 74614ca7a47SHans de Goede 74714ca7a47SHans de Goede /* 74814ca7a47SHans de Goede * some buggy BIOS don't export the levels 74914ca7a47SHans de Goede * when machine is on AC/Battery in _BCL package. 75014ca7a47SHans de Goede * In this case, the first two elements in _BCL packages 75114ca7a47SHans de Goede * are also supported brightness levels that OS should take care of. 75214ca7a47SHans de Goede */ 75314ca7a47SHans de Goede for (i = 2; i < count; i++) { 75414ca7a47SHans de Goede if (br->levels[i] == br->levels[0]) 75514ca7a47SHans de Goede level_ac_battery++; 75614ca7a47SHans de Goede if (br->levels[i] == br->levels[1]) 75714ca7a47SHans de Goede level_ac_battery++; 75814ca7a47SHans de Goede } 75914ca7a47SHans de Goede 76014ca7a47SHans de Goede if (level_ac_battery < 2) { 76114ca7a47SHans de Goede level_ac_battery = 2 - level_ac_battery; 76214ca7a47SHans de Goede br->flags._BCL_no_ac_battery_levels = 1; 76314ca7a47SHans de Goede for (i = (count - 1 + level_ac_battery); i >= 2; i--) 76414ca7a47SHans de Goede br->levels[i] = br->levels[i - level_ac_battery]; 76514ca7a47SHans de Goede count += level_ac_battery; 76614ca7a47SHans de Goede } else if (level_ac_battery > 2) 76714ca7a47SHans de Goede ACPI_ERROR((AE_INFO, "Too many duplicates in _BCL package")); 76814ca7a47SHans de Goede 76914ca7a47SHans de Goede /* Check if the _BCL package is in a reversed order */ 77014ca7a47SHans de Goede if (max_level == br->levels[2]) { 77114ca7a47SHans de Goede br->flags._BCL_reversed = 1; 77214ca7a47SHans de Goede sort(&br->levels[2], count - 2, sizeof(br->levels[2]), 77314ca7a47SHans de Goede acpi_video_cmp_level, NULL); 77414ca7a47SHans de Goede } else if (max_level != br->levels[count - 1]) 77514ca7a47SHans de Goede ACPI_ERROR((AE_INFO, 77614ca7a47SHans de Goede "Found unordered _BCL package")); 77714ca7a47SHans de Goede 77814ca7a47SHans de Goede br->count = count; 77914ca7a47SHans de Goede device->brightness = br; 78014ca7a47SHans de Goede 78114ca7a47SHans de Goede /* _BQC uses INDEX while _BCL uses VALUE in some laptops */ 78214ca7a47SHans de Goede br->curr = level = max_level; 78314ca7a47SHans de Goede 78414ca7a47SHans de Goede if (!device->cap._BQC) 78514ca7a47SHans de Goede goto set_level; 78614ca7a47SHans de Goede 78714ca7a47SHans de Goede result = acpi_video_device_lcd_get_level_current(device, 78814ca7a47SHans de Goede &level_old, true); 78914ca7a47SHans de Goede if (result) 79014ca7a47SHans de Goede goto out_free_levels; 79114ca7a47SHans de Goede 79214ca7a47SHans de Goede result = acpi_video_bqc_quirk(device, max_level, level_old); 79314ca7a47SHans de Goede if (result) 79414ca7a47SHans de Goede goto out_free_levels; 79514ca7a47SHans de Goede /* 79614ca7a47SHans de Goede * cap._BQC may get cleared due to _BQC is found to be broken 79714ca7a47SHans de Goede * in acpi_video_bqc_quirk, so check again here. 79814ca7a47SHans de Goede */ 79914ca7a47SHans de Goede if (!device->cap._BQC) 80014ca7a47SHans de Goede goto set_level; 80114ca7a47SHans de Goede 80214ca7a47SHans de Goede level = acpi_video_bqc_value_to_level(device, level_old); 80314ca7a47SHans de Goede /* 80414ca7a47SHans de Goede * On some buggy laptops, _BQC returns an uninitialized 80514ca7a47SHans de Goede * value when invoked for the first time, i.e. 80614ca7a47SHans de Goede * level_old is invalid (no matter whether it's a level 80714ca7a47SHans de Goede * or an index). Set the backlight to max_level in this case. 80814ca7a47SHans de Goede */ 80914ca7a47SHans de Goede for (i = 2; i < br->count; i++) 81014ca7a47SHans de Goede if (level == br->levels[i]) 81114ca7a47SHans de Goede break; 81214ca7a47SHans de Goede if (i == br->count || !level) 81314ca7a47SHans de Goede level = max_level; 81414ca7a47SHans de Goede 81514ca7a47SHans de Goede set_level: 81614ca7a47SHans de Goede result = acpi_video_device_lcd_set_level(device, level); 81714ca7a47SHans de Goede if (result) 81814ca7a47SHans de Goede goto out_free_levels; 81914ca7a47SHans de Goede 82014ca7a47SHans de Goede ACPI_DEBUG_PRINT((ACPI_DB_INFO, 82114ca7a47SHans de Goede "found %d brightness levels\n", count - 2)); 82214ca7a47SHans de Goede kfree(obj); 82314ca7a47SHans de Goede return result; 82414ca7a47SHans de Goede 82514ca7a47SHans de Goede out_free_levels: 82614ca7a47SHans de Goede kfree(br->levels); 82714ca7a47SHans de Goede out_free: 82814ca7a47SHans de Goede kfree(br); 82914ca7a47SHans de Goede out: 83014ca7a47SHans de Goede device->brightness = NULL; 83114ca7a47SHans de Goede kfree(obj); 83214ca7a47SHans de Goede return result; 83314ca7a47SHans de Goede } 83414ca7a47SHans de Goede 83514ca7a47SHans de Goede /* 83614ca7a47SHans de Goede * Arg: 83714ca7a47SHans de Goede * device : video output device (LCD, CRT, ..) 83814ca7a47SHans de Goede * 83914ca7a47SHans de Goede * Return Value: 84014ca7a47SHans de Goede * None 84114ca7a47SHans de Goede * 84214ca7a47SHans de Goede * Find out all required AML methods defined under the output 84314ca7a47SHans de Goede * device. 84414ca7a47SHans de Goede */ 84514ca7a47SHans de Goede 84614ca7a47SHans de Goede static void acpi_video_device_find_cap(struct acpi_video_device *device) 84714ca7a47SHans de Goede { 84814ca7a47SHans de Goede if (acpi_has_method(device->dev->handle, "_ADR")) 84914ca7a47SHans de Goede device->cap._ADR = 1; 85014ca7a47SHans de Goede if (acpi_has_method(device->dev->handle, "_BCL")) 85114ca7a47SHans de Goede device->cap._BCL = 1; 85214ca7a47SHans de Goede if (acpi_has_method(device->dev->handle, "_BCM")) 85314ca7a47SHans de Goede device->cap._BCM = 1; 85414ca7a47SHans de Goede if (acpi_has_method(device->dev->handle, "_BQC")) { 85514ca7a47SHans de Goede device->cap._BQC = 1; 85614ca7a47SHans de Goede } else if (acpi_has_method(device->dev->handle, "_BCQ")) { 85714ca7a47SHans de Goede printk(KERN_WARNING FW_BUG "_BCQ is used instead of _BQC\n"); 85814ca7a47SHans de Goede device->cap._BCQ = 1; 85914ca7a47SHans de Goede } 86014ca7a47SHans de Goede 86114ca7a47SHans de Goede if (acpi_has_method(device->dev->handle, "_DDC")) 86214ca7a47SHans de Goede device->cap._DDC = 1; 86314ca7a47SHans de Goede } 86414ca7a47SHans de Goede 86514ca7a47SHans de Goede /* 86614ca7a47SHans de Goede * Arg: 86714ca7a47SHans de Goede * device : video output device (VGA) 86814ca7a47SHans de Goede * 86914ca7a47SHans de Goede * Return Value: 87014ca7a47SHans de Goede * None 87114ca7a47SHans de Goede * 87214ca7a47SHans de Goede * Find out all required AML methods defined under the video bus device. 87314ca7a47SHans de Goede */ 87414ca7a47SHans de Goede 87514ca7a47SHans de Goede static void acpi_video_bus_find_cap(struct acpi_video_bus *video) 87614ca7a47SHans de Goede { 87714ca7a47SHans de Goede if (acpi_has_method(video->device->handle, "_DOS")) 87814ca7a47SHans de Goede video->cap._DOS = 1; 87914ca7a47SHans de Goede if (acpi_has_method(video->device->handle, "_DOD")) 88014ca7a47SHans de Goede video->cap._DOD = 1; 88114ca7a47SHans de Goede if (acpi_has_method(video->device->handle, "_ROM")) 88214ca7a47SHans de Goede video->cap._ROM = 1; 88314ca7a47SHans de Goede if (acpi_has_method(video->device->handle, "_GPD")) 88414ca7a47SHans de Goede video->cap._GPD = 1; 88514ca7a47SHans de Goede if (acpi_has_method(video->device->handle, "_SPD")) 88614ca7a47SHans de Goede video->cap._SPD = 1; 88714ca7a47SHans de Goede if (acpi_has_method(video->device->handle, "_VPO")) 88814ca7a47SHans de Goede video->cap._VPO = 1; 88914ca7a47SHans de Goede } 89014ca7a47SHans de Goede 89114ca7a47SHans de Goede /* 89214ca7a47SHans de Goede * Check whether the video bus device has required AML method to 89314ca7a47SHans de Goede * support the desired features 89414ca7a47SHans de Goede */ 89514ca7a47SHans de Goede 89614ca7a47SHans de Goede static int acpi_video_bus_check(struct acpi_video_bus *video) 89714ca7a47SHans de Goede { 89814ca7a47SHans de Goede acpi_status status = -ENOENT; 89914ca7a47SHans de Goede struct pci_dev *dev; 90014ca7a47SHans de Goede 90114ca7a47SHans de Goede if (!video) 90214ca7a47SHans de Goede return -EINVAL; 90314ca7a47SHans de Goede 90414ca7a47SHans de Goede dev = acpi_get_pci_dev(video->device->handle); 90514ca7a47SHans de Goede if (!dev) 90614ca7a47SHans de Goede return -ENODEV; 90714ca7a47SHans de Goede pci_dev_put(dev); 90814ca7a47SHans de Goede 90914ca7a47SHans de Goede /* 91014ca7a47SHans de Goede * Since there is no HID, CID and so on for VGA driver, we have 91114ca7a47SHans de Goede * to check well known required nodes. 91214ca7a47SHans de Goede */ 91314ca7a47SHans de Goede 91414ca7a47SHans de Goede /* Does this device support video switching? */ 91514ca7a47SHans de Goede if (video->cap._DOS || video->cap._DOD) { 91614ca7a47SHans de Goede if (!video->cap._DOS) { 91714ca7a47SHans de Goede printk(KERN_WARNING FW_BUG 91814ca7a47SHans de Goede "ACPI(%s) defines _DOD but not _DOS\n", 91914ca7a47SHans de Goede acpi_device_bid(video->device)); 92014ca7a47SHans de Goede } 92114ca7a47SHans de Goede video->flags.multihead = 1; 92214ca7a47SHans de Goede status = 0; 92314ca7a47SHans de Goede } 92414ca7a47SHans de Goede 92514ca7a47SHans de Goede /* Does this device support retrieving a video ROM? */ 92614ca7a47SHans de Goede if (video->cap._ROM) { 92714ca7a47SHans de Goede video->flags.rom = 1; 92814ca7a47SHans de Goede status = 0; 92914ca7a47SHans de Goede } 93014ca7a47SHans de Goede 93114ca7a47SHans de Goede /* Does this device support configuring which video device to POST? */ 93214ca7a47SHans de Goede if (video->cap._GPD && video->cap._SPD && video->cap._VPO) { 93314ca7a47SHans de Goede video->flags.post = 1; 93414ca7a47SHans de Goede status = 0; 93514ca7a47SHans de Goede } 93614ca7a47SHans de Goede 93714ca7a47SHans de Goede return status; 93814ca7a47SHans de Goede } 93914ca7a47SHans de Goede 94014ca7a47SHans de Goede /* 94114ca7a47SHans de Goede * -------------------------------------------------------------------------- 94214ca7a47SHans de Goede * Driver Interface 94314ca7a47SHans de Goede * -------------------------------------------------------------------------- 94414ca7a47SHans de Goede */ 94514ca7a47SHans de Goede 94614ca7a47SHans de Goede /* device interface */ 94714ca7a47SHans de Goede static struct acpi_video_device_attrib * 94814ca7a47SHans de Goede acpi_video_get_device_attr(struct acpi_video_bus *video, unsigned long device_id) 94914ca7a47SHans de Goede { 95014ca7a47SHans de Goede struct acpi_video_enumerated_device *ids; 95114ca7a47SHans de Goede int i; 95214ca7a47SHans de Goede 95314ca7a47SHans de Goede for (i = 0; i < video->attached_count; i++) { 95414ca7a47SHans de Goede ids = &video->attached_array[i]; 95514ca7a47SHans de Goede if ((ids->value.int_val & 0xffff) == device_id) 95614ca7a47SHans de Goede return &ids->value.attrib; 95714ca7a47SHans de Goede } 95814ca7a47SHans de Goede 95914ca7a47SHans de Goede return NULL; 96014ca7a47SHans de Goede } 96114ca7a47SHans de Goede 96214ca7a47SHans de Goede static int 96314ca7a47SHans de Goede acpi_video_get_device_type(struct acpi_video_bus *video, 96414ca7a47SHans de Goede unsigned long device_id) 96514ca7a47SHans de Goede { 96614ca7a47SHans de Goede struct acpi_video_enumerated_device *ids; 96714ca7a47SHans de Goede int i; 96814ca7a47SHans de Goede 96914ca7a47SHans de Goede for (i = 0; i < video->attached_count; i++) { 97014ca7a47SHans de Goede ids = &video->attached_array[i]; 97114ca7a47SHans de Goede if ((ids->value.int_val & 0xffff) == device_id) 97214ca7a47SHans de Goede return ids->value.int_val; 97314ca7a47SHans de Goede } 97414ca7a47SHans de Goede 97514ca7a47SHans de Goede return 0; 97614ca7a47SHans de Goede } 97714ca7a47SHans de Goede 97814ca7a47SHans de Goede static int 97914ca7a47SHans de Goede acpi_video_bus_get_one_device(struct acpi_device *device, 98014ca7a47SHans de Goede struct acpi_video_bus *video) 98114ca7a47SHans de Goede { 98214ca7a47SHans de Goede unsigned long long device_id; 98314ca7a47SHans de Goede int status, device_type; 98414ca7a47SHans de Goede struct acpi_video_device *data; 98514ca7a47SHans de Goede struct acpi_video_device_attrib *attribute; 98614ca7a47SHans de Goede 98714ca7a47SHans de Goede status = 98814ca7a47SHans de Goede acpi_evaluate_integer(device->handle, "_ADR", NULL, &device_id); 98914ca7a47SHans de Goede /* Some device omits _ADR, we skip them instead of fail */ 99014ca7a47SHans de Goede if (ACPI_FAILURE(status)) 99114ca7a47SHans de Goede return 0; 99214ca7a47SHans de Goede 99314ca7a47SHans de Goede data = kzalloc(sizeof(struct acpi_video_device), GFP_KERNEL); 99414ca7a47SHans de Goede if (!data) 99514ca7a47SHans de Goede return -ENOMEM; 99614ca7a47SHans de Goede 99714ca7a47SHans de Goede strcpy(acpi_device_name(device), ACPI_VIDEO_DEVICE_NAME); 99814ca7a47SHans de Goede strcpy(acpi_device_class(device), ACPI_VIDEO_CLASS); 99914ca7a47SHans de Goede device->driver_data = data; 100014ca7a47SHans de Goede 100114ca7a47SHans de Goede data->device_id = device_id; 100214ca7a47SHans de Goede data->video = video; 100314ca7a47SHans de Goede data->dev = device; 100414ca7a47SHans de Goede INIT_DELAYED_WORK(&data->switch_brightness_work, 100514ca7a47SHans de Goede acpi_video_switch_brightness); 100614ca7a47SHans de Goede 100714ca7a47SHans de Goede attribute = acpi_video_get_device_attr(video, device_id); 100814ca7a47SHans de Goede 100914ca7a47SHans de Goede if (attribute && attribute->device_id_scheme) { 101014ca7a47SHans de Goede switch (attribute->display_type) { 101114ca7a47SHans de Goede case ACPI_VIDEO_DISPLAY_CRT: 101214ca7a47SHans de Goede data->flags.crt = 1; 101314ca7a47SHans de Goede break; 101414ca7a47SHans de Goede case ACPI_VIDEO_DISPLAY_TV: 101514ca7a47SHans de Goede data->flags.tvout = 1; 101614ca7a47SHans de Goede break; 101714ca7a47SHans de Goede case ACPI_VIDEO_DISPLAY_DVI: 101814ca7a47SHans de Goede data->flags.dvi = 1; 101914ca7a47SHans de Goede break; 102014ca7a47SHans de Goede case ACPI_VIDEO_DISPLAY_LCD: 102114ca7a47SHans de Goede data->flags.lcd = 1; 102214ca7a47SHans de Goede break; 102314ca7a47SHans de Goede default: 102414ca7a47SHans de Goede data->flags.unknown = 1; 102514ca7a47SHans de Goede break; 102614ca7a47SHans de Goede } 102714ca7a47SHans de Goede if (attribute->bios_can_detect) 102814ca7a47SHans de Goede data->flags.bios = 1; 102914ca7a47SHans de Goede } else { 103014ca7a47SHans de Goede /* Check for legacy IDs */ 103114ca7a47SHans de Goede device_type = acpi_video_get_device_type(video, device_id); 103214ca7a47SHans de Goede /* Ignore bits 16 and 18-20 */ 103314ca7a47SHans de Goede switch (device_type & 0xffe2ffff) { 103414ca7a47SHans de Goede case ACPI_VIDEO_DISPLAY_LEGACY_MONITOR: 103514ca7a47SHans de Goede data->flags.crt = 1; 103614ca7a47SHans de Goede break; 103714ca7a47SHans de Goede case ACPI_VIDEO_DISPLAY_LEGACY_PANEL: 103814ca7a47SHans de Goede data->flags.lcd = 1; 103914ca7a47SHans de Goede break; 104014ca7a47SHans de Goede case ACPI_VIDEO_DISPLAY_LEGACY_TV: 104114ca7a47SHans de Goede data->flags.tvout = 1; 104214ca7a47SHans de Goede break; 104314ca7a47SHans de Goede default: 104414ca7a47SHans de Goede data->flags.unknown = 1; 104514ca7a47SHans de Goede } 104614ca7a47SHans de Goede } 104714ca7a47SHans de Goede 104814ca7a47SHans de Goede acpi_video_device_bind(video, data); 104914ca7a47SHans de Goede acpi_video_device_find_cap(data); 105014ca7a47SHans de Goede 105114ca7a47SHans de Goede mutex_lock(&video->device_list_lock); 105214ca7a47SHans de Goede list_add_tail(&data->entry, &video->video_device_list); 105314ca7a47SHans de Goede mutex_unlock(&video->device_list_lock); 105414ca7a47SHans de Goede 105514ca7a47SHans de Goede return status; 105614ca7a47SHans de Goede } 105714ca7a47SHans de Goede 105814ca7a47SHans de Goede /* 105914ca7a47SHans de Goede * Arg: 106014ca7a47SHans de Goede * video : video bus device 106114ca7a47SHans de Goede * 106214ca7a47SHans de Goede * Return: 106314ca7a47SHans de Goede * none 106414ca7a47SHans de Goede * 106514ca7a47SHans de Goede * Enumerate the video device list of the video bus, 106614ca7a47SHans de Goede * bind the ids with the corresponding video devices 106714ca7a47SHans de Goede * under the video bus. 106814ca7a47SHans de Goede */ 106914ca7a47SHans de Goede 107014ca7a47SHans de Goede static void acpi_video_device_rebind(struct acpi_video_bus *video) 107114ca7a47SHans de Goede { 107214ca7a47SHans de Goede struct acpi_video_device *dev; 107314ca7a47SHans de Goede 107414ca7a47SHans de Goede mutex_lock(&video->device_list_lock); 107514ca7a47SHans de Goede 107614ca7a47SHans de Goede list_for_each_entry(dev, &video->video_device_list, entry) 107714ca7a47SHans de Goede acpi_video_device_bind(video, dev); 107814ca7a47SHans de Goede 107914ca7a47SHans de Goede mutex_unlock(&video->device_list_lock); 108014ca7a47SHans de Goede } 108114ca7a47SHans de Goede 108214ca7a47SHans de Goede /* 108314ca7a47SHans de Goede * Arg: 108414ca7a47SHans de Goede * video : video bus device 108514ca7a47SHans de Goede * device : video output device under the video 108614ca7a47SHans de Goede * bus 108714ca7a47SHans de Goede * 108814ca7a47SHans de Goede * Return: 108914ca7a47SHans de Goede * none 109014ca7a47SHans de Goede * 109114ca7a47SHans de Goede * Bind the ids with the corresponding video devices 109214ca7a47SHans de Goede * under the video bus. 109314ca7a47SHans de Goede */ 109414ca7a47SHans de Goede 109514ca7a47SHans de Goede static void 109614ca7a47SHans de Goede acpi_video_device_bind(struct acpi_video_bus *video, 109714ca7a47SHans de Goede struct acpi_video_device *device) 109814ca7a47SHans de Goede { 109914ca7a47SHans de Goede struct acpi_video_enumerated_device *ids; 110014ca7a47SHans de Goede int i; 110114ca7a47SHans de Goede 110214ca7a47SHans de Goede for (i = 0; i < video->attached_count; i++) { 110314ca7a47SHans de Goede ids = &video->attached_array[i]; 110414ca7a47SHans de Goede if (device->device_id == (ids->value.int_val & 0xffff)) { 110514ca7a47SHans de Goede ids->bind_info = device; 110614ca7a47SHans de Goede ACPI_DEBUG_PRINT((ACPI_DB_INFO, "device_bind %d\n", i)); 110714ca7a47SHans de Goede } 110814ca7a47SHans de Goede } 110914ca7a47SHans de Goede } 111014ca7a47SHans de Goede 111114ca7a47SHans de Goede static bool acpi_video_device_in_dod(struct acpi_video_device *device) 111214ca7a47SHans de Goede { 111314ca7a47SHans de Goede struct acpi_video_bus *video = device->video; 111414ca7a47SHans de Goede int i; 111514ca7a47SHans de Goede 111614ca7a47SHans de Goede /* 111714ca7a47SHans de Goede * If we have a broken _DOD or we have more than 8 output devices 111814ca7a47SHans de Goede * under the graphics controller node that we can't proper deal with 111914ca7a47SHans de Goede * in the operation region code currently, no need to test. 112014ca7a47SHans de Goede */ 112114ca7a47SHans de Goede if (!video->attached_count || video->child_count > 8) 112214ca7a47SHans de Goede return true; 112314ca7a47SHans de Goede 112414ca7a47SHans de Goede for (i = 0; i < video->attached_count; i++) { 112514ca7a47SHans de Goede if ((video->attached_array[i].value.int_val & 0xfff) == 112614ca7a47SHans de Goede (device->device_id & 0xfff)) 112714ca7a47SHans de Goede return true; 112814ca7a47SHans de Goede } 112914ca7a47SHans de Goede 113014ca7a47SHans de Goede return false; 113114ca7a47SHans de Goede } 113214ca7a47SHans de Goede 113314ca7a47SHans de Goede /* 113414ca7a47SHans de Goede * Arg: 113514ca7a47SHans de Goede * video : video bus device 113614ca7a47SHans de Goede * 113714ca7a47SHans de Goede * Return: 113814ca7a47SHans de Goede * < 0 : error 113914ca7a47SHans de Goede * 114014ca7a47SHans de Goede * Call _DOD to enumerate all devices attached to display adapter 114114ca7a47SHans de Goede * 114214ca7a47SHans de Goede */ 114314ca7a47SHans de Goede 114414ca7a47SHans de Goede static int acpi_video_device_enumerate(struct acpi_video_bus *video) 114514ca7a47SHans de Goede { 114614ca7a47SHans de Goede int status; 114714ca7a47SHans de Goede int count; 114814ca7a47SHans de Goede int i; 114914ca7a47SHans de Goede struct acpi_video_enumerated_device *active_list; 115014ca7a47SHans de Goede struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; 115114ca7a47SHans de Goede union acpi_object *dod = NULL; 115214ca7a47SHans de Goede union acpi_object *obj; 115314ca7a47SHans de Goede 115414ca7a47SHans de Goede status = acpi_evaluate_object(video->device->handle, "_DOD", NULL, &buffer); 115514ca7a47SHans de Goede if (!ACPI_SUCCESS(status)) { 115614ca7a47SHans de Goede ACPI_EXCEPTION((AE_INFO, status, "Evaluating _DOD")); 115714ca7a47SHans de Goede return status; 115814ca7a47SHans de Goede } 115914ca7a47SHans de Goede 116014ca7a47SHans de Goede dod = buffer.pointer; 116114ca7a47SHans de Goede if (!dod || (dod->type != ACPI_TYPE_PACKAGE)) { 116214ca7a47SHans de Goede ACPI_EXCEPTION((AE_INFO, status, "Invalid _DOD data")); 116314ca7a47SHans de Goede status = -EFAULT; 116414ca7a47SHans de Goede goto out; 116514ca7a47SHans de Goede } 116614ca7a47SHans de Goede 116714ca7a47SHans de Goede ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Found %d video heads in _DOD\n", 116814ca7a47SHans de Goede dod->package.count)); 116914ca7a47SHans de Goede 117014ca7a47SHans de Goede active_list = kcalloc(1 + dod->package.count, 117114ca7a47SHans de Goede sizeof(struct acpi_video_enumerated_device), 117214ca7a47SHans de Goede GFP_KERNEL); 117314ca7a47SHans de Goede if (!active_list) { 117414ca7a47SHans de Goede status = -ENOMEM; 117514ca7a47SHans de Goede goto out; 117614ca7a47SHans de Goede } 117714ca7a47SHans de Goede 117814ca7a47SHans de Goede count = 0; 117914ca7a47SHans de Goede for (i = 0; i < dod->package.count; i++) { 118014ca7a47SHans de Goede obj = &dod->package.elements[i]; 118114ca7a47SHans de Goede 118214ca7a47SHans de Goede if (obj->type != ACPI_TYPE_INTEGER) { 118314ca7a47SHans de Goede printk(KERN_ERR PREFIX 118414ca7a47SHans de Goede "Invalid _DOD data in element %d\n", i); 118514ca7a47SHans de Goede continue; 118614ca7a47SHans de Goede } 118714ca7a47SHans de Goede 118814ca7a47SHans de Goede active_list[count].value.int_val = obj->integer.value; 118914ca7a47SHans de Goede active_list[count].bind_info = NULL; 119014ca7a47SHans de Goede ACPI_DEBUG_PRINT((ACPI_DB_INFO, "dod element[%d] = %d\n", i, 119114ca7a47SHans de Goede (int)obj->integer.value)); 119214ca7a47SHans de Goede count++; 119314ca7a47SHans de Goede } 119414ca7a47SHans de Goede 119514ca7a47SHans de Goede kfree(video->attached_array); 119614ca7a47SHans de Goede 119714ca7a47SHans de Goede video->attached_array = active_list; 119814ca7a47SHans de Goede video->attached_count = count; 119914ca7a47SHans de Goede 120014ca7a47SHans de Goede out: 120114ca7a47SHans de Goede kfree(buffer.pointer); 120214ca7a47SHans de Goede return status; 120314ca7a47SHans de Goede } 120414ca7a47SHans de Goede 120514ca7a47SHans de Goede static int 120614ca7a47SHans de Goede acpi_video_get_next_level(struct acpi_video_device *device, 120714ca7a47SHans de Goede u32 level_current, u32 event) 120814ca7a47SHans de Goede { 120914ca7a47SHans de Goede int min, max, min_above, max_below, i, l, delta = 255; 121014ca7a47SHans de Goede max = max_below = 0; 121114ca7a47SHans de Goede min = min_above = 255; 121214ca7a47SHans de Goede /* Find closest level to level_current */ 121314ca7a47SHans de Goede for (i = 2; i < device->brightness->count; i++) { 121414ca7a47SHans de Goede l = device->brightness->levels[i]; 121514ca7a47SHans de Goede if (abs(l - level_current) < abs(delta)) { 121614ca7a47SHans de Goede delta = l - level_current; 121714ca7a47SHans de Goede if (!delta) 121814ca7a47SHans de Goede break; 121914ca7a47SHans de Goede } 122014ca7a47SHans de Goede } 122114ca7a47SHans de Goede /* Ajust level_current to closest available level */ 122214ca7a47SHans de Goede level_current += delta; 122314ca7a47SHans de Goede for (i = 2; i < device->brightness->count; i++) { 122414ca7a47SHans de Goede l = device->brightness->levels[i]; 122514ca7a47SHans de Goede if (l < min) 122614ca7a47SHans de Goede min = l; 122714ca7a47SHans de Goede if (l > max) 122814ca7a47SHans de Goede max = l; 122914ca7a47SHans de Goede if (l < min_above && l > level_current) 123014ca7a47SHans de Goede min_above = l; 123114ca7a47SHans de Goede if (l > max_below && l < level_current) 123214ca7a47SHans de Goede max_below = l; 123314ca7a47SHans de Goede } 123414ca7a47SHans de Goede 123514ca7a47SHans de Goede switch (event) { 123614ca7a47SHans de Goede case ACPI_VIDEO_NOTIFY_CYCLE_BRIGHTNESS: 123714ca7a47SHans de Goede return (level_current < max) ? min_above : min; 123814ca7a47SHans de Goede case ACPI_VIDEO_NOTIFY_INC_BRIGHTNESS: 123914ca7a47SHans de Goede return (level_current < max) ? min_above : max; 124014ca7a47SHans de Goede case ACPI_VIDEO_NOTIFY_DEC_BRIGHTNESS: 124114ca7a47SHans de Goede return (level_current > min) ? max_below : min; 124214ca7a47SHans de Goede case ACPI_VIDEO_NOTIFY_ZERO_BRIGHTNESS: 124314ca7a47SHans de Goede case ACPI_VIDEO_NOTIFY_DISPLAY_OFF: 124414ca7a47SHans de Goede return 0; 124514ca7a47SHans de Goede default: 124614ca7a47SHans de Goede return level_current; 124714ca7a47SHans de Goede } 124814ca7a47SHans de Goede } 124914ca7a47SHans de Goede 125014ca7a47SHans de Goede static void 125114ca7a47SHans de Goede acpi_video_switch_brightness(struct work_struct *work) 125214ca7a47SHans de Goede { 125314ca7a47SHans de Goede struct acpi_video_device *device = container_of(to_delayed_work(work), 125414ca7a47SHans de Goede struct acpi_video_device, switch_brightness_work); 125514ca7a47SHans de Goede unsigned long long level_current, level_next; 125614ca7a47SHans de Goede int event = device->switch_brightness_event; 125714ca7a47SHans de Goede int result = -EINVAL; 125814ca7a47SHans de Goede 125914ca7a47SHans de Goede /* no warning message if acpi_backlight=vendor or a quirk is used */ 126014ca7a47SHans de Goede if (!device->backlight) 126114ca7a47SHans de Goede return; 126214ca7a47SHans de Goede 126314ca7a47SHans de Goede if (!device->brightness) 126414ca7a47SHans de Goede goto out; 126514ca7a47SHans de Goede 126614ca7a47SHans de Goede result = acpi_video_device_lcd_get_level_current(device, 126714ca7a47SHans de Goede &level_current, 126814ca7a47SHans de Goede false); 126914ca7a47SHans de Goede if (result) 127014ca7a47SHans de Goede goto out; 127114ca7a47SHans de Goede 127214ca7a47SHans de Goede level_next = acpi_video_get_next_level(device, level_current, event); 127314ca7a47SHans de Goede 127414ca7a47SHans de Goede result = acpi_video_device_lcd_set_level(device, level_next); 127514ca7a47SHans de Goede 127614ca7a47SHans de Goede if (!result) 127714ca7a47SHans de Goede backlight_force_update(device->backlight, 127814ca7a47SHans de Goede BACKLIGHT_UPDATE_HOTKEY); 127914ca7a47SHans de Goede 128014ca7a47SHans de Goede out: 128114ca7a47SHans de Goede if (result) 128214ca7a47SHans de Goede printk(KERN_ERR PREFIX "Failed to switch the brightness\n"); 128314ca7a47SHans de Goede } 128414ca7a47SHans de Goede 128514ca7a47SHans de Goede int acpi_video_get_edid(struct acpi_device *device, int type, int device_id, 128614ca7a47SHans de Goede void **edid) 128714ca7a47SHans de Goede { 128814ca7a47SHans de Goede struct acpi_video_bus *video; 128914ca7a47SHans de Goede struct acpi_video_device *video_device; 129014ca7a47SHans de Goede union acpi_object *buffer = NULL; 129114ca7a47SHans de Goede acpi_status status; 129214ca7a47SHans de Goede int i, length; 129314ca7a47SHans de Goede 129414ca7a47SHans de Goede if (!device || !acpi_driver_data(device)) 129514ca7a47SHans de Goede return -EINVAL; 129614ca7a47SHans de Goede 129714ca7a47SHans de Goede video = acpi_driver_data(device); 129814ca7a47SHans de Goede 129914ca7a47SHans de Goede for (i = 0; i < video->attached_count; i++) { 130014ca7a47SHans de Goede video_device = video->attached_array[i].bind_info; 130114ca7a47SHans de Goede length = 256; 130214ca7a47SHans de Goede 130314ca7a47SHans de Goede if (!video_device) 130414ca7a47SHans de Goede continue; 130514ca7a47SHans de Goede 130614ca7a47SHans de Goede if (!video_device->cap._DDC) 130714ca7a47SHans de Goede continue; 130814ca7a47SHans de Goede 130914ca7a47SHans de Goede if (type) { 131014ca7a47SHans de Goede switch (type) { 131114ca7a47SHans de Goede case ACPI_VIDEO_DISPLAY_CRT: 131214ca7a47SHans de Goede if (!video_device->flags.crt) 131314ca7a47SHans de Goede continue; 131414ca7a47SHans de Goede break; 131514ca7a47SHans de Goede case ACPI_VIDEO_DISPLAY_TV: 131614ca7a47SHans de Goede if (!video_device->flags.tvout) 131714ca7a47SHans de Goede continue; 131814ca7a47SHans de Goede break; 131914ca7a47SHans de Goede case ACPI_VIDEO_DISPLAY_DVI: 132014ca7a47SHans de Goede if (!video_device->flags.dvi) 132114ca7a47SHans de Goede continue; 132214ca7a47SHans de Goede break; 132314ca7a47SHans de Goede case ACPI_VIDEO_DISPLAY_LCD: 132414ca7a47SHans de Goede if (!video_device->flags.lcd) 132514ca7a47SHans de Goede continue; 132614ca7a47SHans de Goede break; 132714ca7a47SHans de Goede } 132814ca7a47SHans de Goede } else if (video_device->device_id != device_id) { 132914ca7a47SHans de Goede continue; 133014ca7a47SHans de Goede } 133114ca7a47SHans de Goede 133214ca7a47SHans de Goede status = acpi_video_device_EDID(video_device, &buffer, length); 133314ca7a47SHans de Goede 133414ca7a47SHans de Goede if (ACPI_FAILURE(status) || !buffer || 133514ca7a47SHans de Goede buffer->type != ACPI_TYPE_BUFFER) { 133614ca7a47SHans de Goede length = 128; 133714ca7a47SHans de Goede status = acpi_video_device_EDID(video_device, &buffer, 133814ca7a47SHans de Goede length); 133914ca7a47SHans de Goede if (ACPI_FAILURE(status) || !buffer || 134014ca7a47SHans de Goede buffer->type != ACPI_TYPE_BUFFER) { 134114ca7a47SHans de Goede continue; 134214ca7a47SHans de Goede } 134314ca7a47SHans de Goede } 134414ca7a47SHans de Goede 134514ca7a47SHans de Goede *edid = buffer->buffer.pointer; 134614ca7a47SHans de Goede return length; 134714ca7a47SHans de Goede } 134814ca7a47SHans de Goede 134914ca7a47SHans de Goede return -ENODEV; 135014ca7a47SHans de Goede } 135114ca7a47SHans de Goede EXPORT_SYMBOL(acpi_video_get_edid); 135214ca7a47SHans de Goede 135314ca7a47SHans de Goede static int 135414ca7a47SHans de Goede acpi_video_bus_get_devices(struct acpi_video_bus *video, 135514ca7a47SHans de Goede struct acpi_device *device) 135614ca7a47SHans de Goede { 135714ca7a47SHans de Goede int status = 0; 135814ca7a47SHans de Goede struct acpi_device *dev; 135914ca7a47SHans de Goede 136014ca7a47SHans de Goede /* 136114ca7a47SHans de Goede * There are systems where video module known to work fine regardless 136214ca7a47SHans de Goede * of broken _DOD and ignoring returned value here doesn't cause 136314ca7a47SHans de Goede * any issues later. 136414ca7a47SHans de Goede */ 136514ca7a47SHans de Goede acpi_video_device_enumerate(video); 136614ca7a47SHans de Goede 136714ca7a47SHans de Goede list_for_each_entry(dev, &device->children, node) { 136814ca7a47SHans de Goede 136914ca7a47SHans de Goede status = acpi_video_bus_get_one_device(dev, video); 137014ca7a47SHans de Goede if (status) { 137114ca7a47SHans de Goede dev_err(&dev->dev, "Can't attach device\n"); 137214ca7a47SHans de Goede break; 137314ca7a47SHans de Goede } 137414ca7a47SHans de Goede video->child_count++; 137514ca7a47SHans de Goede } 137614ca7a47SHans de Goede return status; 137714ca7a47SHans de Goede } 137814ca7a47SHans de Goede 137914ca7a47SHans de Goede /* acpi_video interface */ 138014ca7a47SHans de Goede 138114ca7a47SHans de Goede /* 138214ca7a47SHans de Goede * Win8 requires setting bit2 of _DOS to let firmware know it shouldn't 138314ca7a47SHans de Goede * preform any automatic brightness change on receiving a notification. 138414ca7a47SHans de Goede */ 138514ca7a47SHans de Goede static int acpi_video_bus_start_devices(struct acpi_video_bus *video) 138614ca7a47SHans de Goede { 138714ca7a47SHans de Goede return acpi_video_bus_DOS(video, 0, 138814ca7a47SHans de Goede acpi_osi_is_win8() ? 1 : 0); 138914ca7a47SHans de Goede } 139014ca7a47SHans de Goede 139114ca7a47SHans de Goede static int acpi_video_bus_stop_devices(struct acpi_video_bus *video) 139214ca7a47SHans de Goede { 139314ca7a47SHans de Goede return acpi_video_bus_DOS(video, 0, 139414ca7a47SHans de Goede acpi_osi_is_win8() ? 0 : 1); 139514ca7a47SHans de Goede } 139614ca7a47SHans de Goede 139714ca7a47SHans de Goede static void acpi_video_bus_notify(struct acpi_device *device, u32 event) 139814ca7a47SHans de Goede { 139914ca7a47SHans de Goede struct acpi_video_bus *video = acpi_driver_data(device); 140014ca7a47SHans de Goede struct input_dev *input; 140114ca7a47SHans de Goede int keycode = 0; 140214ca7a47SHans de Goede 140314ca7a47SHans de Goede if (!video || !video->input) 140414ca7a47SHans de Goede return; 140514ca7a47SHans de Goede 140614ca7a47SHans de Goede input = video->input; 140714ca7a47SHans de Goede 140814ca7a47SHans de Goede switch (event) { 140914ca7a47SHans de Goede case ACPI_VIDEO_NOTIFY_SWITCH: /* User requested a switch, 141014ca7a47SHans de Goede * most likely via hotkey. */ 141114ca7a47SHans de Goede keycode = KEY_SWITCHVIDEOMODE; 141214ca7a47SHans de Goede break; 141314ca7a47SHans de Goede 141414ca7a47SHans de Goede case ACPI_VIDEO_NOTIFY_PROBE: /* User plugged in or removed a video 141514ca7a47SHans de Goede * connector. */ 141614ca7a47SHans de Goede acpi_video_device_enumerate(video); 141714ca7a47SHans de Goede acpi_video_device_rebind(video); 141814ca7a47SHans de Goede keycode = KEY_SWITCHVIDEOMODE; 141914ca7a47SHans de Goede break; 142014ca7a47SHans de Goede 142114ca7a47SHans de Goede case ACPI_VIDEO_NOTIFY_CYCLE: /* Cycle Display output hotkey pressed. */ 142214ca7a47SHans de Goede keycode = KEY_SWITCHVIDEOMODE; 142314ca7a47SHans de Goede break; 142414ca7a47SHans de Goede case ACPI_VIDEO_NOTIFY_NEXT_OUTPUT: /* Next Display output hotkey pressed. */ 142514ca7a47SHans de Goede keycode = KEY_VIDEO_NEXT; 142614ca7a47SHans de Goede break; 142714ca7a47SHans de Goede case ACPI_VIDEO_NOTIFY_PREV_OUTPUT: /* previous Display output hotkey pressed. */ 142814ca7a47SHans de Goede keycode = KEY_VIDEO_PREV; 142914ca7a47SHans de Goede break; 143014ca7a47SHans de Goede 143114ca7a47SHans de Goede default: 143214ca7a47SHans de Goede ACPI_DEBUG_PRINT((ACPI_DB_INFO, 143314ca7a47SHans de Goede "Unsupported event [0x%x]\n", event)); 143414ca7a47SHans de Goede break; 143514ca7a47SHans de Goede } 143614ca7a47SHans de Goede 143714ca7a47SHans de Goede if (acpi_notifier_call_chain(device, event, 0)) 143814ca7a47SHans de Goede /* Something vetoed the keypress. */ 143914ca7a47SHans de Goede keycode = 0; 144014ca7a47SHans de Goede 144114ca7a47SHans de Goede if (keycode) { 144214ca7a47SHans de Goede input_report_key(input, keycode, 1); 144314ca7a47SHans de Goede input_sync(input); 144414ca7a47SHans de Goede input_report_key(input, keycode, 0); 144514ca7a47SHans de Goede input_sync(input); 144614ca7a47SHans de Goede } 144714ca7a47SHans de Goede 144814ca7a47SHans de Goede return; 144914ca7a47SHans de Goede } 145014ca7a47SHans de Goede 145114ca7a47SHans de Goede static void brightness_switch_event(struct acpi_video_device *video_device, 145214ca7a47SHans de Goede u32 event) 145314ca7a47SHans de Goede { 145414ca7a47SHans de Goede if (!brightness_switch_enabled) 145514ca7a47SHans de Goede return; 145614ca7a47SHans de Goede 145714ca7a47SHans de Goede video_device->switch_brightness_event = event; 145814ca7a47SHans de Goede schedule_delayed_work(&video_device->switch_brightness_work, HZ / 10); 145914ca7a47SHans de Goede } 146014ca7a47SHans de Goede 146114ca7a47SHans de Goede static void acpi_video_device_notify(acpi_handle handle, u32 event, void *data) 146214ca7a47SHans de Goede { 146314ca7a47SHans de Goede struct acpi_video_device *video_device = data; 146414ca7a47SHans de Goede struct acpi_device *device = NULL; 146514ca7a47SHans de Goede struct acpi_video_bus *bus; 146614ca7a47SHans de Goede struct input_dev *input; 146714ca7a47SHans de Goede int keycode = 0; 146814ca7a47SHans de Goede 146914ca7a47SHans de Goede if (!video_device) 147014ca7a47SHans de Goede return; 147114ca7a47SHans de Goede 147214ca7a47SHans de Goede device = video_device->dev; 147314ca7a47SHans de Goede bus = video_device->video; 147414ca7a47SHans de Goede input = bus->input; 147514ca7a47SHans de Goede 147614ca7a47SHans de Goede switch (event) { 147714ca7a47SHans de Goede case ACPI_VIDEO_NOTIFY_CYCLE_BRIGHTNESS: /* Cycle brightness */ 147814ca7a47SHans de Goede brightness_switch_event(video_device, event); 147914ca7a47SHans de Goede keycode = KEY_BRIGHTNESS_CYCLE; 148014ca7a47SHans de Goede break; 148114ca7a47SHans de Goede case ACPI_VIDEO_NOTIFY_INC_BRIGHTNESS: /* Increase brightness */ 148214ca7a47SHans de Goede brightness_switch_event(video_device, event); 148314ca7a47SHans de Goede keycode = KEY_BRIGHTNESSUP; 148414ca7a47SHans de Goede break; 148514ca7a47SHans de Goede case ACPI_VIDEO_NOTIFY_DEC_BRIGHTNESS: /* Decrease brightness */ 148614ca7a47SHans de Goede brightness_switch_event(video_device, event); 148714ca7a47SHans de Goede keycode = KEY_BRIGHTNESSDOWN; 148814ca7a47SHans de Goede break; 148914ca7a47SHans de Goede case ACPI_VIDEO_NOTIFY_ZERO_BRIGHTNESS: /* zero brightness */ 149014ca7a47SHans de Goede brightness_switch_event(video_device, event); 149114ca7a47SHans de Goede keycode = KEY_BRIGHTNESS_ZERO; 149214ca7a47SHans de Goede break; 149314ca7a47SHans de Goede case ACPI_VIDEO_NOTIFY_DISPLAY_OFF: /* display device off */ 149414ca7a47SHans de Goede brightness_switch_event(video_device, event); 149514ca7a47SHans de Goede keycode = KEY_DISPLAY_OFF; 149614ca7a47SHans de Goede break; 149714ca7a47SHans de Goede default: 149814ca7a47SHans de Goede ACPI_DEBUG_PRINT((ACPI_DB_INFO, 149914ca7a47SHans de Goede "Unsupported event [0x%x]\n", event)); 150014ca7a47SHans de Goede break; 150114ca7a47SHans de Goede } 150214ca7a47SHans de Goede 150314ca7a47SHans de Goede acpi_notifier_call_chain(device, event, 0); 150414ca7a47SHans de Goede 150514ca7a47SHans de Goede if (keycode) { 150614ca7a47SHans de Goede input_report_key(input, keycode, 1); 150714ca7a47SHans de Goede input_sync(input); 150814ca7a47SHans de Goede input_report_key(input, keycode, 0); 150914ca7a47SHans de Goede input_sync(input); 151014ca7a47SHans de Goede } 151114ca7a47SHans de Goede 151214ca7a47SHans de Goede return; 151314ca7a47SHans de Goede } 151414ca7a47SHans de Goede 151514ca7a47SHans de Goede static int acpi_video_resume(struct notifier_block *nb, 151614ca7a47SHans de Goede unsigned long val, void *ign) 151714ca7a47SHans de Goede { 151814ca7a47SHans de Goede struct acpi_video_bus *video; 151914ca7a47SHans de Goede struct acpi_video_device *video_device; 152014ca7a47SHans de Goede int i; 152114ca7a47SHans de Goede 152214ca7a47SHans de Goede switch (val) { 152314ca7a47SHans de Goede case PM_HIBERNATION_PREPARE: 152414ca7a47SHans de Goede case PM_SUSPEND_PREPARE: 152514ca7a47SHans de Goede case PM_RESTORE_PREPARE: 152614ca7a47SHans de Goede return NOTIFY_DONE; 152714ca7a47SHans de Goede } 152814ca7a47SHans de Goede 152914ca7a47SHans de Goede video = container_of(nb, struct acpi_video_bus, pm_nb); 153014ca7a47SHans de Goede 153114ca7a47SHans de Goede dev_info(&video->device->dev, "Restoring backlight state\n"); 153214ca7a47SHans de Goede 153314ca7a47SHans de Goede for (i = 0; i < video->attached_count; i++) { 153414ca7a47SHans de Goede video_device = video->attached_array[i].bind_info; 153514ca7a47SHans de Goede if (video_device && video_device->brightness) 153614ca7a47SHans de Goede acpi_video_device_lcd_set_level(video_device, 153714ca7a47SHans de Goede video_device->brightness->curr); 153814ca7a47SHans de Goede } 153914ca7a47SHans de Goede 154014ca7a47SHans de Goede return NOTIFY_OK; 154114ca7a47SHans de Goede } 154214ca7a47SHans de Goede 154314ca7a47SHans de Goede static acpi_status 154414ca7a47SHans de Goede acpi_video_bus_match(acpi_handle handle, u32 level, void *context, 154514ca7a47SHans de Goede void **return_value) 154614ca7a47SHans de Goede { 154714ca7a47SHans de Goede struct acpi_device *device = context; 154814ca7a47SHans de Goede struct acpi_device *sibling; 154914ca7a47SHans de Goede int result; 155014ca7a47SHans de Goede 155114ca7a47SHans de Goede if (handle == device->handle) 155214ca7a47SHans de Goede return AE_CTRL_TERMINATE; 155314ca7a47SHans de Goede 155414ca7a47SHans de Goede result = acpi_bus_get_device(handle, &sibling); 155514ca7a47SHans de Goede if (result) 155614ca7a47SHans de Goede return AE_OK; 155714ca7a47SHans de Goede 155814ca7a47SHans de Goede if (!strcmp(acpi_device_name(sibling), ACPI_VIDEO_BUS_NAME)) 155914ca7a47SHans de Goede return AE_ALREADY_EXISTS; 156014ca7a47SHans de Goede 156114ca7a47SHans de Goede return AE_OK; 156214ca7a47SHans de Goede } 156314ca7a47SHans de Goede 156414ca7a47SHans de Goede static void acpi_video_dev_register_backlight(struct acpi_video_device *device) 156514ca7a47SHans de Goede { 156614ca7a47SHans de Goede struct backlight_properties props; 156714ca7a47SHans de Goede struct pci_dev *pdev; 156814ca7a47SHans de Goede acpi_handle acpi_parent; 156914ca7a47SHans de Goede struct device *parent = NULL; 157014ca7a47SHans de Goede int result; 157114ca7a47SHans de Goede static int count; 157214ca7a47SHans de Goede char *name; 157314ca7a47SHans de Goede 157414ca7a47SHans de Goede /* 157514ca7a47SHans de Goede * Do not create backlight device for video output 157614ca7a47SHans de Goede * device that is not in the enumerated list. 157714ca7a47SHans de Goede */ 157814ca7a47SHans de Goede if (!acpi_video_device_in_dod(device)) { 157914ca7a47SHans de Goede dev_dbg(&device->dev->dev, "not in _DOD list, ignore\n"); 158014ca7a47SHans de Goede return; 158114ca7a47SHans de Goede } 158214ca7a47SHans de Goede 158314ca7a47SHans de Goede result = acpi_video_init_brightness(device); 158414ca7a47SHans de Goede if (result) 158514ca7a47SHans de Goede return; 158614ca7a47SHans de Goede 158714ca7a47SHans de Goede if (disable_backlight_sysfs_if > 0) 158814ca7a47SHans de Goede return; 158914ca7a47SHans de Goede 159014ca7a47SHans de Goede name = kasprintf(GFP_KERNEL, "acpi_video%d", count); 159114ca7a47SHans de Goede if (!name) 159214ca7a47SHans de Goede return; 159314ca7a47SHans de Goede count++; 159414ca7a47SHans de Goede 159514ca7a47SHans de Goede acpi_get_parent(device->dev->handle, &acpi_parent); 159614ca7a47SHans de Goede 159714ca7a47SHans de Goede pdev = acpi_get_pci_dev(acpi_parent); 159814ca7a47SHans de Goede if (pdev) { 159914ca7a47SHans de Goede parent = &pdev->dev; 160014ca7a47SHans de Goede pci_dev_put(pdev); 160114ca7a47SHans de Goede } 160214ca7a47SHans de Goede 160314ca7a47SHans de Goede memset(&props, 0, sizeof(struct backlight_properties)); 160414ca7a47SHans de Goede props.type = BACKLIGHT_FIRMWARE; 160514ca7a47SHans de Goede props.max_brightness = device->brightness->count - 3; 160614ca7a47SHans de Goede device->backlight = backlight_device_register(name, 160714ca7a47SHans de Goede parent, 160814ca7a47SHans de Goede device, 160914ca7a47SHans de Goede &acpi_backlight_ops, 161014ca7a47SHans de Goede &props); 161114ca7a47SHans de Goede kfree(name); 161214ca7a47SHans de Goede if (IS_ERR(device->backlight)) { 161314ca7a47SHans de Goede device->backlight = NULL; 161414ca7a47SHans de Goede return; 161514ca7a47SHans de Goede } 161614ca7a47SHans de Goede 161714ca7a47SHans de Goede /* 161814ca7a47SHans de Goede * Save current brightness level in case we have to restore it 161914ca7a47SHans de Goede * before acpi_video_device_lcd_set_level() is called next time. 162014ca7a47SHans de Goede */ 162114ca7a47SHans de Goede device->backlight->props.brightness = 162214ca7a47SHans de Goede acpi_video_get_brightness(device->backlight); 162314ca7a47SHans de Goede 162414ca7a47SHans de Goede device->cooling_dev = thermal_cooling_device_register("LCD", 162514ca7a47SHans de Goede device->dev, &video_cooling_ops); 162614ca7a47SHans de Goede if (IS_ERR(device->cooling_dev)) { 162714ca7a47SHans de Goede /* 162814ca7a47SHans de Goede * Set cooling_dev to NULL so we don't crash trying to free it. 162914ca7a47SHans de Goede * Also, why the hell we are returning early and not attempt to 163014ca7a47SHans de Goede * register video output if cooling device registration failed? 163114ca7a47SHans de Goede * -- dtor 163214ca7a47SHans de Goede */ 163314ca7a47SHans de Goede device->cooling_dev = NULL; 163414ca7a47SHans de Goede return; 163514ca7a47SHans de Goede } 163614ca7a47SHans de Goede 163714ca7a47SHans de Goede dev_info(&device->dev->dev, "registered as cooling_device%d\n", 163814ca7a47SHans de Goede device->cooling_dev->id); 163914ca7a47SHans de Goede result = sysfs_create_link(&device->dev->dev.kobj, 164014ca7a47SHans de Goede &device->cooling_dev->device.kobj, 164114ca7a47SHans de Goede "thermal_cooling"); 164214ca7a47SHans de Goede if (result) 164314ca7a47SHans de Goede printk(KERN_ERR PREFIX "Create sysfs link\n"); 164414ca7a47SHans de Goede result = sysfs_create_link(&device->cooling_dev->device.kobj, 164514ca7a47SHans de Goede &device->dev->dev.kobj, "device"); 164614ca7a47SHans de Goede if (result) 164714ca7a47SHans de Goede printk(KERN_ERR PREFIX "Create sysfs link\n"); 164814ca7a47SHans de Goede } 164914ca7a47SHans de Goede 165014ca7a47SHans de Goede static void acpi_video_run_bcl_for_osi(struct acpi_video_bus *video) 165114ca7a47SHans de Goede { 165214ca7a47SHans de Goede struct acpi_video_device *dev; 165314ca7a47SHans de Goede union acpi_object *levels; 165414ca7a47SHans de Goede 165514ca7a47SHans de Goede mutex_lock(&video->device_list_lock); 165614ca7a47SHans de Goede list_for_each_entry(dev, &video->video_device_list, entry) { 165714ca7a47SHans de Goede if (!acpi_video_device_lcd_query_levels(dev, &levels)) 165814ca7a47SHans de Goede kfree(levels); 165914ca7a47SHans de Goede } 166014ca7a47SHans de Goede mutex_unlock(&video->device_list_lock); 166114ca7a47SHans de Goede } 166214ca7a47SHans de Goede 166314ca7a47SHans de Goede static int acpi_video_bus_register_backlight(struct acpi_video_bus *video) 166414ca7a47SHans de Goede { 166514ca7a47SHans de Goede struct acpi_video_device *dev; 166614ca7a47SHans de Goede 166714ca7a47SHans de Goede if (video->backlight_registered) 166814ca7a47SHans de Goede return 0; 166914ca7a47SHans de Goede 167014ca7a47SHans de Goede acpi_video_run_bcl_for_osi(video); 167114ca7a47SHans de Goede 16723bd6bce3SHans de Goede if (acpi_video_get_backlight_type() != acpi_backlight_video) 167314ca7a47SHans de Goede return 0; 167414ca7a47SHans de Goede 167514ca7a47SHans de Goede mutex_lock(&video->device_list_lock); 167614ca7a47SHans de Goede list_for_each_entry(dev, &video->video_device_list, entry) 167714ca7a47SHans de Goede acpi_video_dev_register_backlight(dev); 167814ca7a47SHans de Goede mutex_unlock(&video->device_list_lock); 167914ca7a47SHans de Goede 168014ca7a47SHans de Goede video->backlight_registered = true; 168114ca7a47SHans de Goede 168214ca7a47SHans de Goede video->pm_nb.notifier_call = acpi_video_resume; 168314ca7a47SHans de Goede video->pm_nb.priority = 0; 168414ca7a47SHans de Goede return register_pm_notifier(&video->pm_nb); 168514ca7a47SHans de Goede } 168614ca7a47SHans de Goede 168714ca7a47SHans de Goede static void acpi_video_dev_unregister_backlight(struct acpi_video_device *device) 168814ca7a47SHans de Goede { 168914ca7a47SHans de Goede if (device->backlight) { 169014ca7a47SHans de Goede backlight_device_unregister(device->backlight); 169114ca7a47SHans de Goede device->backlight = NULL; 169214ca7a47SHans de Goede } 169314ca7a47SHans de Goede if (device->brightness) { 169414ca7a47SHans de Goede kfree(device->brightness->levels); 169514ca7a47SHans de Goede kfree(device->brightness); 169614ca7a47SHans de Goede device->brightness = NULL; 169714ca7a47SHans de Goede } 169814ca7a47SHans de Goede if (device->cooling_dev) { 169914ca7a47SHans de Goede sysfs_remove_link(&device->dev->dev.kobj, "thermal_cooling"); 170014ca7a47SHans de Goede sysfs_remove_link(&device->cooling_dev->device.kobj, "device"); 170114ca7a47SHans de Goede thermal_cooling_device_unregister(device->cooling_dev); 170214ca7a47SHans de Goede device->cooling_dev = NULL; 170314ca7a47SHans de Goede } 170414ca7a47SHans de Goede } 170514ca7a47SHans de Goede 170614ca7a47SHans de Goede static int acpi_video_bus_unregister_backlight(struct acpi_video_bus *video) 170714ca7a47SHans de Goede { 170814ca7a47SHans de Goede struct acpi_video_device *dev; 170914ca7a47SHans de Goede int error; 171014ca7a47SHans de Goede 171114ca7a47SHans de Goede if (!video->backlight_registered) 171214ca7a47SHans de Goede return 0; 171314ca7a47SHans de Goede 171414ca7a47SHans de Goede error = unregister_pm_notifier(&video->pm_nb); 171514ca7a47SHans de Goede 171614ca7a47SHans de Goede mutex_lock(&video->device_list_lock); 171714ca7a47SHans de Goede list_for_each_entry(dev, &video->video_device_list, entry) 171814ca7a47SHans de Goede acpi_video_dev_unregister_backlight(dev); 171914ca7a47SHans de Goede mutex_unlock(&video->device_list_lock); 172014ca7a47SHans de Goede 172114ca7a47SHans de Goede video->backlight_registered = false; 172214ca7a47SHans de Goede 172314ca7a47SHans de Goede return error; 172414ca7a47SHans de Goede } 172514ca7a47SHans de Goede 172614ca7a47SHans de Goede static void acpi_video_dev_add_notify_handler(struct acpi_video_device *device) 172714ca7a47SHans de Goede { 172814ca7a47SHans de Goede acpi_status status; 172914ca7a47SHans de Goede struct acpi_device *adev = device->dev; 173014ca7a47SHans de Goede 173114ca7a47SHans de Goede status = acpi_install_notify_handler(adev->handle, ACPI_DEVICE_NOTIFY, 173214ca7a47SHans de Goede acpi_video_device_notify, device); 173314ca7a47SHans de Goede if (ACPI_FAILURE(status)) 173414ca7a47SHans de Goede dev_err(&adev->dev, "Error installing notify handler\n"); 173514ca7a47SHans de Goede else 173614ca7a47SHans de Goede device->flags.notify = 1; 173714ca7a47SHans de Goede } 173814ca7a47SHans de Goede 173914ca7a47SHans de Goede static int acpi_video_bus_add_notify_handler(struct acpi_video_bus *video) 174014ca7a47SHans de Goede { 174114ca7a47SHans de Goede struct input_dev *input; 174214ca7a47SHans de Goede struct acpi_video_device *dev; 174314ca7a47SHans de Goede int error; 174414ca7a47SHans de Goede 174514ca7a47SHans de Goede video->input = input = input_allocate_device(); 174614ca7a47SHans de Goede if (!input) { 174714ca7a47SHans de Goede error = -ENOMEM; 174814ca7a47SHans de Goede goto out; 174914ca7a47SHans de Goede } 175014ca7a47SHans de Goede 175114ca7a47SHans de Goede error = acpi_video_bus_start_devices(video); 175214ca7a47SHans de Goede if (error) 175314ca7a47SHans de Goede goto err_free_input; 175414ca7a47SHans de Goede 175514ca7a47SHans de Goede snprintf(video->phys, sizeof(video->phys), 175614ca7a47SHans de Goede "%s/video/input0", acpi_device_hid(video->device)); 175714ca7a47SHans de Goede 175814ca7a47SHans de Goede input->name = acpi_device_name(video->device); 175914ca7a47SHans de Goede input->phys = video->phys; 176014ca7a47SHans de Goede input->id.bustype = BUS_HOST; 176114ca7a47SHans de Goede input->id.product = 0x06; 176214ca7a47SHans de Goede input->dev.parent = &video->device->dev; 176314ca7a47SHans de Goede input->evbit[0] = BIT(EV_KEY); 176414ca7a47SHans de Goede set_bit(KEY_SWITCHVIDEOMODE, input->keybit); 176514ca7a47SHans de Goede set_bit(KEY_VIDEO_NEXT, input->keybit); 176614ca7a47SHans de Goede set_bit(KEY_VIDEO_PREV, input->keybit); 176714ca7a47SHans de Goede set_bit(KEY_BRIGHTNESS_CYCLE, input->keybit); 176814ca7a47SHans de Goede set_bit(KEY_BRIGHTNESSUP, input->keybit); 176914ca7a47SHans de Goede set_bit(KEY_BRIGHTNESSDOWN, input->keybit); 177014ca7a47SHans de Goede set_bit(KEY_BRIGHTNESS_ZERO, input->keybit); 177114ca7a47SHans de Goede set_bit(KEY_DISPLAY_OFF, input->keybit); 177214ca7a47SHans de Goede 177314ca7a47SHans de Goede error = input_register_device(input); 177414ca7a47SHans de Goede if (error) 177514ca7a47SHans de Goede goto err_stop_dev; 177614ca7a47SHans de Goede 177714ca7a47SHans de Goede mutex_lock(&video->device_list_lock); 177814ca7a47SHans de Goede list_for_each_entry(dev, &video->video_device_list, entry) 177914ca7a47SHans de Goede acpi_video_dev_add_notify_handler(dev); 178014ca7a47SHans de Goede mutex_unlock(&video->device_list_lock); 178114ca7a47SHans de Goede 178214ca7a47SHans de Goede return 0; 178314ca7a47SHans de Goede 178414ca7a47SHans de Goede err_stop_dev: 178514ca7a47SHans de Goede acpi_video_bus_stop_devices(video); 178614ca7a47SHans de Goede err_free_input: 178714ca7a47SHans de Goede input_free_device(input); 178814ca7a47SHans de Goede video->input = NULL; 178914ca7a47SHans de Goede out: 179014ca7a47SHans de Goede return error; 179114ca7a47SHans de Goede } 179214ca7a47SHans de Goede 179314ca7a47SHans de Goede static void acpi_video_dev_remove_notify_handler(struct acpi_video_device *dev) 179414ca7a47SHans de Goede { 179514ca7a47SHans de Goede if (dev->flags.notify) { 179614ca7a47SHans de Goede acpi_remove_notify_handler(dev->dev->handle, ACPI_DEVICE_NOTIFY, 179714ca7a47SHans de Goede acpi_video_device_notify); 179814ca7a47SHans de Goede dev->flags.notify = 0; 179914ca7a47SHans de Goede } 180014ca7a47SHans de Goede } 180114ca7a47SHans de Goede 180214ca7a47SHans de Goede static void acpi_video_bus_remove_notify_handler(struct acpi_video_bus *video) 180314ca7a47SHans de Goede { 180414ca7a47SHans de Goede struct acpi_video_device *dev; 180514ca7a47SHans de Goede 180614ca7a47SHans de Goede mutex_lock(&video->device_list_lock); 180714ca7a47SHans de Goede list_for_each_entry(dev, &video->video_device_list, entry) 180814ca7a47SHans de Goede acpi_video_dev_remove_notify_handler(dev); 180914ca7a47SHans de Goede mutex_unlock(&video->device_list_lock); 181014ca7a47SHans de Goede 181114ca7a47SHans de Goede acpi_video_bus_stop_devices(video); 181214ca7a47SHans de Goede input_unregister_device(video->input); 181314ca7a47SHans de Goede video->input = NULL; 181414ca7a47SHans de Goede } 181514ca7a47SHans de Goede 181614ca7a47SHans de Goede static int acpi_video_bus_put_devices(struct acpi_video_bus *video) 181714ca7a47SHans de Goede { 181814ca7a47SHans de Goede struct acpi_video_device *dev, *next; 181914ca7a47SHans de Goede 182014ca7a47SHans de Goede mutex_lock(&video->device_list_lock); 182114ca7a47SHans de Goede list_for_each_entry_safe(dev, next, &video->video_device_list, entry) { 182214ca7a47SHans de Goede list_del(&dev->entry); 182314ca7a47SHans de Goede kfree(dev); 182414ca7a47SHans de Goede } 182514ca7a47SHans de Goede mutex_unlock(&video->device_list_lock); 182614ca7a47SHans de Goede 182714ca7a47SHans de Goede return 0; 182814ca7a47SHans de Goede } 182914ca7a47SHans de Goede 183014ca7a47SHans de Goede static int instance; 183114ca7a47SHans de Goede 183214ca7a47SHans de Goede static int acpi_video_bus_add(struct acpi_device *device) 183314ca7a47SHans de Goede { 183414ca7a47SHans de Goede struct acpi_video_bus *video; 183514ca7a47SHans de Goede int error; 183614ca7a47SHans de Goede acpi_status status; 183714ca7a47SHans de Goede 183814ca7a47SHans de Goede status = acpi_walk_namespace(ACPI_TYPE_DEVICE, 183914ca7a47SHans de Goede device->parent->handle, 1, 184014ca7a47SHans de Goede acpi_video_bus_match, NULL, 184114ca7a47SHans de Goede device, NULL); 184214ca7a47SHans de Goede if (status == AE_ALREADY_EXISTS) { 184314ca7a47SHans de Goede printk(KERN_WARNING FW_BUG 184414ca7a47SHans de Goede "Duplicate ACPI video bus devices for the" 184514ca7a47SHans de Goede " same VGA controller, please try module " 184614ca7a47SHans de Goede "parameter \"video.allow_duplicates=1\"" 184714ca7a47SHans de Goede "if the current driver doesn't work.\n"); 184814ca7a47SHans de Goede if (!allow_duplicates) 184914ca7a47SHans de Goede return -ENODEV; 185014ca7a47SHans de Goede } 185114ca7a47SHans de Goede 185214ca7a47SHans de Goede video = kzalloc(sizeof(struct acpi_video_bus), GFP_KERNEL); 185314ca7a47SHans de Goede if (!video) 185414ca7a47SHans de Goede return -ENOMEM; 185514ca7a47SHans de Goede 185614ca7a47SHans de Goede /* a hack to fix the duplicate name "VID" problem on T61 */ 185714ca7a47SHans de Goede if (!strcmp(device->pnp.bus_id, "VID")) { 185814ca7a47SHans de Goede if (instance) 185914ca7a47SHans de Goede device->pnp.bus_id[3] = '0' + instance; 186014ca7a47SHans de Goede instance++; 186114ca7a47SHans de Goede } 186214ca7a47SHans de Goede /* a hack to fix the duplicate name "VGA" problem on Pa 3553 */ 186314ca7a47SHans de Goede if (!strcmp(device->pnp.bus_id, "VGA")) { 186414ca7a47SHans de Goede if (instance) 186514ca7a47SHans de Goede device->pnp.bus_id[3] = '0' + instance; 186614ca7a47SHans de Goede instance++; 186714ca7a47SHans de Goede } 186814ca7a47SHans de Goede 186914ca7a47SHans de Goede video->device = device; 187014ca7a47SHans de Goede strcpy(acpi_device_name(device), ACPI_VIDEO_BUS_NAME); 187114ca7a47SHans de Goede strcpy(acpi_device_class(device), ACPI_VIDEO_CLASS); 187214ca7a47SHans de Goede device->driver_data = video; 187314ca7a47SHans de Goede 187414ca7a47SHans de Goede acpi_video_bus_find_cap(video); 187514ca7a47SHans de Goede error = acpi_video_bus_check(video); 187614ca7a47SHans de Goede if (error) 187714ca7a47SHans de Goede goto err_free_video; 187814ca7a47SHans de Goede 187914ca7a47SHans de Goede mutex_init(&video->device_list_lock); 188014ca7a47SHans de Goede INIT_LIST_HEAD(&video->video_device_list); 188114ca7a47SHans de Goede 188214ca7a47SHans de Goede error = acpi_video_bus_get_devices(video, device); 188314ca7a47SHans de Goede if (error) 188414ca7a47SHans de Goede goto err_put_video; 188514ca7a47SHans de Goede 188614ca7a47SHans de Goede printk(KERN_INFO PREFIX "%s [%s] (multi-head: %s rom: %s post: %s)\n", 188714ca7a47SHans de Goede ACPI_VIDEO_DEVICE_NAME, acpi_device_bid(device), 188814ca7a47SHans de Goede video->flags.multihead ? "yes" : "no", 188914ca7a47SHans de Goede video->flags.rom ? "yes" : "no", 189014ca7a47SHans de Goede video->flags.post ? "yes" : "no"); 189114ca7a47SHans de Goede mutex_lock(&video_list_lock); 189214ca7a47SHans de Goede list_add_tail(&video->entry, &video_bus_head); 189314ca7a47SHans de Goede mutex_unlock(&video_list_lock); 189414ca7a47SHans de Goede 189514ca7a47SHans de Goede acpi_video_bus_register_backlight(video); 189614ca7a47SHans de Goede acpi_video_bus_add_notify_handler(video); 189714ca7a47SHans de Goede 189814ca7a47SHans de Goede return 0; 189914ca7a47SHans de Goede 190014ca7a47SHans de Goede err_put_video: 190114ca7a47SHans de Goede acpi_video_bus_put_devices(video); 190214ca7a47SHans de Goede kfree(video->attached_array); 190314ca7a47SHans de Goede err_free_video: 190414ca7a47SHans de Goede kfree(video); 190514ca7a47SHans de Goede device->driver_data = NULL; 190614ca7a47SHans de Goede 190714ca7a47SHans de Goede return error; 190814ca7a47SHans de Goede } 190914ca7a47SHans de Goede 191014ca7a47SHans de Goede static int acpi_video_bus_remove(struct acpi_device *device) 191114ca7a47SHans de Goede { 191214ca7a47SHans de Goede struct acpi_video_bus *video = NULL; 191314ca7a47SHans de Goede 191414ca7a47SHans de Goede 191514ca7a47SHans de Goede if (!device || !acpi_driver_data(device)) 191614ca7a47SHans de Goede return -EINVAL; 191714ca7a47SHans de Goede 191814ca7a47SHans de Goede video = acpi_driver_data(device); 191914ca7a47SHans de Goede 192014ca7a47SHans de Goede acpi_video_bus_remove_notify_handler(video); 192114ca7a47SHans de Goede acpi_video_bus_unregister_backlight(video); 192214ca7a47SHans de Goede acpi_video_bus_put_devices(video); 192314ca7a47SHans de Goede 192414ca7a47SHans de Goede mutex_lock(&video_list_lock); 192514ca7a47SHans de Goede list_del(&video->entry); 192614ca7a47SHans de Goede mutex_unlock(&video_list_lock); 192714ca7a47SHans de Goede 192814ca7a47SHans de Goede kfree(video->attached_array); 192914ca7a47SHans de Goede kfree(video); 193014ca7a47SHans de Goede 193114ca7a47SHans de Goede return 0; 193214ca7a47SHans de Goede } 193314ca7a47SHans de Goede 193414ca7a47SHans de Goede static int __init is_i740(struct pci_dev *dev) 193514ca7a47SHans de Goede { 193614ca7a47SHans de Goede if (dev->device == 0x00D1) 193714ca7a47SHans de Goede return 1; 193814ca7a47SHans de Goede if (dev->device == 0x7000) 193914ca7a47SHans de Goede return 1; 194014ca7a47SHans de Goede return 0; 194114ca7a47SHans de Goede } 194214ca7a47SHans de Goede 194314ca7a47SHans de Goede static int __init intel_opregion_present(void) 194414ca7a47SHans de Goede { 194514ca7a47SHans de Goede int opregion = 0; 194614ca7a47SHans de Goede struct pci_dev *dev = NULL; 194714ca7a47SHans de Goede u32 address; 194814ca7a47SHans de Goede 194914ca7a47SHans de Goede for_each_pci_dev(dev) { 195014ca7a47SHans de Goede if ((dev->class >> 8) != PCI_CLASS_DISPLAY_VGA) 195114ca7a47SHans de Goede continue; 195214ca7a47SHans de Goede if (dev->vendor != PCI_VENDOR_ID_INTEL) 195314ca7a47SHans de Goede continue; 195414ca7a47SHans de Goede /* We don't want to poke around undefined i740 registers */ 195514ca7a47SHans de Goede if (is_i740(dev)) 195614ca7a47SHans de Goede continue; 195714ca7a47SHans de Goede pci_read_config_dword(dev, 0xfc, &address); 195814ca7a47SHans de Goede if (!address) 195914ca7a47SHans de Goede continue; 196014ca7a47SHans de Goede opregion = 1; 196114ca7a47SHans de Goede } 196214ca7a47SHans de Goede return opregion; 196314ca7a47SHans de Goede } 196414ca7a47SHans de Goede 196514ca7a47SHans de Goede int acpi_video_register(void) 196614ca7a47SHans de Goede { 196714ca7a47SHans de Goede int ret; 196814ca7a47SHans de Goede 196914ca7a47SHans de Goede if (register_count) { 197014ca7a47SHans de Goede /* 197114ca7a47SHans de Goede * if the function of acpi_video_register is already called, 197214ca7a47SHans de Goede * don't register the acpi_vide_bus again and return no error. 197314ca7a47SHans de Goede */ 197414ca7a47SHans de Goede return 0; 197514ca7a47SHans de Goede } 197614ca7a47SHans de Goede 197714ca7a47SHans de Goede mutex_init(&video_list_lock); 197814ca7a47SHans de Goede INIT_LIST_HEAD(&video_bus_head); 197914ca7a47SHans de Goede 198014ca7a47SHans de Goede ret = acpi_bus_register_driver(&acpi_video_bus); 198114ca7a47SHans de Goede if (ret) 198214ca7a47SHans de Goede return ret; 198314ca7a47SHans de Goede 198414ca7a47SHans de Goede /* 198514ca7a47SHans de Goede * When the acpi_video_bus is loaded successfully, increase 198614ca7a47SHans de Goede * the counter reference. 198714ca7a47SHans de Goede */ 198814ca7a47SHans de Goede register_count = 1; 198914ca7a47SHans de Goede 199014ca7a47SHans de Goede return 0; 199114ca7a47SHans de Goede } 199214ca7a47SHans de Goede EXPORT_SYMBOL(acpi_video_register); 199314ca7a47SHans de Goede 199414ca7a47SHans de Goede void acpi_video_unregister(void) 199514ca7a47SHans de Goede { 199614ca7a47SHans de Goede if (!register_count) { 199714ca7a47SHans de Goede /* 199814ca7a47SHans de Goede * If the acpi video bus is already unloaded, don't 199914ca7a47SHans de Goede * unload it again and return directly. 200014ca7a47SHans de Goede */ 200114ca7a47SHans de Goede return; 200214ca7a47SHans de Goede } 200314ca7a47SHans de Goede acpi_bus_unregister_driver(&acpi_video_bus); 200414ca7a47SHans de Goede 200514ca7a47SHans de Goede register_count = 0; 200614ca7a47SHans de Goede 200714ca7a47SHans de Goede return; 200814ca7a47SHans de Goede } 200914ca7a47SHans de Goede EXPORT_SYMBOL(acpi_video_unregister); 201014ca7a47SHans de Goede 201114ca7a47SHans de Goede void acpi_video_unregister_backlight(void) 201214ca7a47SHans de Goede { 201314ca7a47SHans de Goede struct acpi_video_bus *video; 201414ca7a47SHans de Goede 201514ca7a47SHans de Goede if (!register_count) 201614ca7a47SHans de Goede return; 201714ca7a47SHans de Goede 201814ca7a47SHans de Goede mutex_lock(&video_list_lock); 201914ca7a47SHans de Goede list_for_each_entry(video, &video_bus_head, entry) 202014ca7a47SHans de Goede acpi_video_bus_unregister_backlight(video); 202114ca7a47SHans de Goede mutex_unlock(&video_list_lock); 202214ca7a47SHans de Goede } 202314ca7a47SHans de Goede EXPORT_SYMBOL(acpi_video_unregister_backlight); 202414ca7a47SHans de Goede 202514ca7a47SHans de Goede /* 202614ca7a47SHans de Goede * This is kind of nasty. Hardware using Intel chipsets may require 202714ca7a47SHans de Goede * the video opregion code to be run first in order to initialise 202814ca7a47SHans de Goede * state before any ACPI video calls are made. To handle this we defer 202914ca7a47SHans de Goede * registration of the video class until the opregion code has run. 203014ca7a47SHans de Goede */ 203114ca7a47SHans de Goede 203214ca7a47SHans de Goede static int __init acpi_video_init(void) 203314ca7a47SHans de Goede { 203414ca7a47SHans de Goede /* 203514ca7a47SHans de Goede * Let the module load even if ACPI is disabled (e.g. due to 203614ca7a47SHans de Goede * a broken BIOS) so that i915.ko can still be loaded on such 203714ca7a47SHans de Goede * old systems without an AcpiOpRegion. 203814ca7a47SHans de Goede * 203914ca7a47SHans de Goede * acpi_video_register() will report -ENODEV later as well due 204014ca7a47SHans de Goede * to acpi_disabled when i915.ko tries to register itself afterwards. 204114ca7a47SHans de Goede */ 204214ca7a47SHans de Goede if (acpi_disabled) 204314ca7a47SHans de Goede return 0; 204414ca7a47SHans de Goede 204514ca7a47SHans de Goede dmi_check_system(video_dmi_table); 204614ca7a47SHans de Goede 204714ca7a47SHans de Goede if (intel_opregion_present()) 204814ca7a47SHans de Goede return 0; 204914ca7a47SHans de Goede 205014ca7a47SHans de Goede return acpi_video_register(); 205114ca7a47SHans de Goede } 205214ca7a47SHans de Goede 205314ca7a47SHans de Goede static void __exit acpi_video_exit(void) 205414ca7a47SHans de Goede { 2055*93a291dfSHans de Goede acpi_video_detect_exit(); 205614ca7a47SHans de Goede acpi_video_unregister(); 205714ca7a47SHans de Goede 205814ca7a47SHans de Goede return; 205914ca7a47SHans de Goede } 206014ca7a47SHans de Goede 206114ca7a47SHans de Goede module_init(acpi_video_init); 206214ca7a47SHans de Goede module_exit(acpi_video_exit); 2063