aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/acpi/video.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/acpi/video.c')
-rw-r--r--drivers/acpi/video.c80
1 files changed, 53 insertions, 27 deletions
diff --git a/drivers/acpi/video.c b/drivers/acpi/video.c
index 60ea984c84a0..94b1a4c5abab 100644
--- a/drivers/acpi/video.c
+++ b/drivers/acpi/video.c
@@ -40,10 +40,12 @@
40#include <linux/pci.h> 40#include <linux/pci.h>
41#include <linux/pci_ids.h> 41#include <linux/pci_ids.h>
42#include <asm/uaccess.h> 42#include <asm/uaccess.h>
43 43#include <linux/dmi.h>
44#include <acpi/acpi_bus.h> 44#include <acpi/acpi_bus.h>
45#include <acpi/acpi_drivers.h> 45#include <acpi/acpi_drivers.h>
46 46
47#define PREFIX "ACPI: "
48
47#define ACPI_VIDEO_CLASS "video" 49#define ACPI_VIDEO_CLASS "video"
48#define ACPI_VIDEO_BUS_NAME "Video Bus" 50#define ACPI_VIDEO_BUS_NAME "Video Bus"
49#define ACPI_VIDEO_DEVICE_NAME "Video Device" 51#define ACPI_VIDEO_DEVICE_NAME "Video Device"
@@ -198,7 +200,7 @@ struct acpi_video_device {
198 struct acpi_device *dev; 200 struct acpi_device *dev;
199 struct acpi_video_device_brightness *brightness; 201 struct acpi_video_device_brightness *brightness;
200 struct backlight_device *backlight; 202 struct backlight_device *backlight;
201 struct thermal_cooling_device *cdev; 203 struct thermal_cooling_device *cooling_dev;
202 struct output_device *output_dev; 204 struct output_device *output_dev;
203}; 205};
204 206
@@ -387,20 +389,20 @@ static struct output_properties acpi_output_properties = {
387 389
388 390
389/* thermal cooling device callbacks */ 391/* thermal cooling device callbacks */
390static int video_get_max_state(struct thermal_cooling_device *cdev, unsigned 392static int video_get_max_state(struct thermal_cooling_device *cooling_dev, unsigned
391 long *state) 393 long *state)
392{ 394{
393 struct acpi_device *device = cdev->devdata; 395 struct acpi_device *device = cooling_dev->devdata;
394 struct acpi_video_device *video = acpi_driver_data(device); 396 struct acpi_video_device *video = acpi_driver_data(device);
395 397
396 *state = video->brightness->count - 3; 398 *state = video->brightness->count - 3;
397 return 0; 399 return 0;
398} 400}
399 401
400static int video_get_cur_state(struct thermal_cooling_device *cdev, unsigned 402static int video_get_cur_state(struct thermal_cooling_device *cooling_dev, unsigned
401 long *state) 403 long *state)
402{ 404{
403 struct acpi_device *device = cdev->devdata; 405 struct acpi_device *device = cooling_dev->devdata;
404 struct acpi_video_device *video = acpi_driver_data(device); 406 struct acpi_video_device *video = acpi_driver_data(device);
405 unsigned long long level; 407 unsigned long long level;
406 int offset; 408 int offset;
@@ -417,9 +419,9 @@ static int video_get_cur_state(struct thermal_cooling_device *cdev, unsigned
417} 419}
418 420
419static int 421static int
420video_set_cur_state(struct thermal_cooling_device *cdev, unsigned long state) 422video_set_cur_state(struct thermal_cooling_device *cooling_dev, unsigned long state)
421{ 423{
422 struct acpi_device *device = cdev->devdata; 424 struct acpi_device *device = cooling_dev->devdata;
423 struct acpi_video_device *video = acpi_driver_data(device); 425 struct acpi_video_device *video = acpi_driver_data(device);
424 int level; 426 int level;
425 427
@@ -603,6 +605,7 @@ acpi_video_device_lcd_get_level_current(struct acpi_video_device *device,
603 unsigned long long *level) 605 unsigned long long *level)
604{ 606{
605 acpi_status status = AE_OK; 607 acpi_status status = AE_OK;
608 int i;
606 609
607 if (device->cap._BQC || device->cap._BCQ) { 610 if (device->cap._BQC || device->cap._BCQ) {
608 char *buf = device->cap._BQC ? "_BQC" : "_BCQ"; 611 char *buf = device->cap._BQC ? "_BQC" : "_BCQ";
@@ -618,8 +621,15 @@ acpi_video_device_lcd_get_level_current(struct acpi_video_device *device,
618 621
619 } 622 }
620 *level += bqc_offset_aml_bug_workaround; 623 *level += bqc_offset_aml_bug_workaround;
621 device->brightness->curr = *level; 624 for (i = 2; i < device->brightness->count; i++)
622 return 0; 625 if (device->brightness->levels[i] == *level) {
626 device->brightness->curr = *level;
627 return 0;
628 }
629 /* BQC returned an invalid level. Stop using it. */
630 ACPI_WARNING((AE_INFO, "%s returned an invalid level",
631 buf));
632 device->cap._BQC = device->cap._BCQ = 0;
623 } else { 633 } else {
624 /* Fixme: 634 /* Fixme:
625 * should we return an error or ignore this failure? 635 * should we return an error or ignore this failure?
@@ -870,7 +880,7 @@ acpi_video_init_brightness(struct acpi_video_device *device)
870 br->flags._BCM_use_index = br->flags._BCL_use_index; 880 br->flags._BCM_use_index = br->flags._BCL_use_index;
871 881
872 /* _BQC uses INDEX while _BCL uses VALUE in some laptops */ 882 /* _BQC uses INDEX while _BCL uses VALUE in some laptops */
873 br->curr = level_old = max_level; 883 br->curr = level = max_level;
874 884
875 if (!device->cap._BQC) 885 if (!device->cap._BQC)
876 goto set_level; 886 goto set_level;
@@ -892,15 +902,25 @@ acpi_video_init_brightness(struct acpi_video_device *device)
892 902
893 br->flags._BQC_use_index = (level == max_level ? 0 : 1); 903 br->flags._BQC_use_index = (level == max_level ? 0 : 1);
894 904
895 if (!br->flags._BQC_use_index) 905 if (!br->flags._BQC_use_index) {
906 /*
907 * Set the backlight to the initial state.
908 * On some buggy laptops, _BQC returns an uninitialized value
909 * when invoked for the first time, i.e. level_old is invalid.
910 * set the backlight to max_level in this case
911 */
912 for (i = 2; i < br->count; i++)
913 if (level_old == br->levels[i])
914 level = level_old;
896 goto set_level; 915 goto set_level;
916 }
897 917
898 if (br->flags._BCL_reversed) 918 if (br->flags._BCL_reversed)
899 level_old = (br->count - 1) - level_old; 919 level_old = (br->count - 1) - level_old;
900 level_old = br->levels[level_old]; 920 level = br->levels[level_old];
901 921
902set_level: 922set_level:
903 result = acpi_video_device_lcd_set_level(device, level_old); 923 result = acpi_video_device_lcd_set_level(device, level);
904 if (result) 924 if (result)
905 goto out_free_levels; 925 goto out_free_levels;
906 926
@@ -934,9 +954,6 @@ static void acpi_video_device_find_cap(struct acpi_video_device *device)
934{ 954{
935 acpi_handle h_dummy1; 955 acpi_handle h_dummy1;
936 956
937
938 memset(&device->cap, 0, sizeof(device->cap));
939
940 if (ACPI_SUCCESS(acpi_get_handle(device->dev->handle, "_ADR", &h_dummy1))) { 957 if (ACPI_SUCCESS(acpi_get_handle(device->dev->handle, "_ADR", &h_dummy1))) {
941 device->cap._ADR = 1; 958 device->cap._ADR = 1;
942 } 959 }
@@ -990,19 +1007,29 @@ static void acpi_video_device_find_cap(struct acpi_video_device *device)
990 if (result) 1007 if (result)
991 printk(KERN_ERR PREFIX "Create sysfs link\n"); 1008 printk(KERN_ERR PREFIX "Create sysfs link\n");
992 1009
993 device->cdev = thermal_cooling_device_register("LCD", 1010 device->cooling_dev = thermal_cooling_device_register("LCD",
994 device->dev, &video_cooling_ops); 1011 device->dev, &video_cooling_ops);
995 if (IS_ERR(device->cdev)) 1012 if (IS_ERR(device->cooling_dev)) {
1013 /*
1014 * Set cooling_dev to NULL so we don't crash trying to
1015 * free it.
1016 * Also, why the hell we are returning early and
1017 * not attempt to register video output if cooling
1018 * device registration failed?
1019 * -- dtor
1020 */
1021 device->cooling_dev = NULL;
996 return; 1022 return;
1023 }
997 1024
998 dev_info(&device->dev->dev, "registered as cooling_device%d\n", 1025 dev_info(&device->dev->dev, "registered as cooling_device%d\n",
999 device->cdev->id); 1026 device->cooling_dev->id);
1000 result = sysfs_create_link(&device->dev->dev.kobj, 1027 result = sysfs_create_link(&device->dev->dev.kobj,
1001 &device->cdev->device.kobj, 1028 &device->cooling_dev->device.kobj,
1002 "thermal_cooling"); 1029 "thermal_cooling");
1003 if (result) 1030 if (result)
1004 printk(KERN_ERR PREFIX "Create sysfs link\n"); 1031 printk(KERN_ERR PREFIX "Create sysfs link\n");
1005 result = sysfs_create_link(&device->cdev->device.kobj, 1032 result = sysfs_create_link(&device->cooling_dev->device.kobj,
1006 &device->dev->dev.kobj, "device"); 1033 &device->dev->dev.kobj, "device");
1007 if (result) 1034 if (result)
1008 printk(KERN_ERR PREFIX "Create sysfs link\n"); 1035 printk(KERN_ERR PREFIX "Create sysfs link\n");
@@ -1039,7 +1066,6 @@ static void acpi_video_bus_find_cap(struct acpi_video_bus *video)
1039{ 1066{
1040 acpi_handle h_dummy1; 1067 acpi_handle h_dummy1;
1041 1068
1042 memset(&video->cap, 0, sizeof(video->cap));
1043 if (ACPI_SUCCESS(acpi_get_handle(video->device->handle, "_DOS", &h_dummy1))) { 1069 if (ACPI_SUCCESS(acpi_get_handle(video->device->handle, "_DOS", &h_dummy1))) {
1044 video->cap._DOS = 1; 1070 video->cap._DOS = 1;
1045 } 1071 }
@@ -2009,13 +2035,13 @@ static int acpi_video_bus_put_one_device(struct acpi_video_device *device)
2009 backlight_device_unregister(device->backlight); 2035 backlight_device_unregister(device->backlight);
2010 device->backlight = NULL; 2036 device->backlight = NULL;
2011 } 2037 }
2012 if (device->cdev) { 2038 if (device->cooling_dev) {
2013 sysfs_remove_link(&device->dev->dev.kobj, 2039 sysfs_remove_link(&device->dev->dev.kobj,
2014 "thermal_cooling"); 2040 "thermal_cooling");
2015 sysfs_remove_link(&device->cdev->device.kobj, 2041 sysfs_remove_link(&device->cooling_dev->device.kobj,
2016 "device"); 2042 "device");
2017 thermal_cooling_device_unregister(device->cdev); 2043 thermal_cooling_device_unregister(device->cooling_dev);
2018 device->cdev = NULL; 2044 device->cooling_dev = NULL;
2019 } 2045 }
2020 video_output_unregister(device->output_dev); 2046 video_output_unregister(device->output_dev);
2021 2047