|
@@ -200,7 +200,7 @@ struct acpi_video_device {
|
|
|
struct acpi_device *dev;
|
|
|
struct acpi_video_device_brightness *brightness;
|
|
|
struct backlight_device *backlight;
|
|
|
- struct thermal_cooling_device *cdev;
|
|
|
+ struct thermal_cooling_device *cooling_dev;
|
|
|
struct output_device *output_dev;
|
|
|
};
|
|
|
|
|
@@ -389,20 +389,20 @@ static struct output_properties acpi_output_properties = {
|
|
|
|
|
|
|
|
|
/* thermal cooling device callbacks */
|
|
|
-static int video_get_max_state(struct thermal_cooling_device *cdev, unsigned
|
|
|
+static int video_get_max_state(struct thermal_cooling_device *cooling_dev, unsigned
|
|
|
long *state)
|
|
|
{
|
|
|
- struct acpi_device *device = cdev->devdata;
|
|
|
+ struct acpi_device *device = cooling_dev->devdata;
|
|
|
struct acpi_video_device *video = acpi_driver_data(device);
|
|
|
|
|
|
*state = video->brightness->count - 3;
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
-static int video_get_cur_state(struct thermal_cooling_device *cdev, unsigned
|
|
|
+static int video_get_cur_state(struct thermal_cooling_device *cooling_dev, unsigned
|
|
|
long *state)
|
|
|
{
|
|
|
- struct acpi_device *device = cdev->devdata;
|
|
|
+ struct acpi_device *device = cooling_dev->devdata;
|
|
|
struct acpi_video_device *video = acpi_driver_data(device);
|
|
|
unsigned long long level;
|
|
|
int offset;
|
|
@@ -419,9 +419,9 @@ static int video_get_cur_state(struct thermal_cooling_device *cdev, unsigned
|
|
|
}
|
|
|
|
|
|
static int
|
|
|
-video_set_cur_state(struct thermal_cooling_device *cdev, unsigned long state)
|
|
|
+video_set_cur_state(struct thermal_cooling_device *cooling_dev, unsigned long state)
|
|
|
{
|
|
|
- struct acpi_device *device = cdev->devdata;
|
|
|
+ struct acpi_device *device = cooling_dev->devdata;
|
|
|
struct acpi_video_device *video = acpi_driver_data(device);
|
|
|
int level;
|
|
|
|
|
@@ -605,6 +605,7 @@ acpi_video_device_lcd_get_level_current(struct acpi_video_device *device,
|
|
|
unsigned long long *level)
|
|
|
{
|
|
|
acpi_status status = AE_OK;
|
|
|
+ int i;
|
|
|
|
|
|
if (device->cap._BQC || device->cap._BCQ) {
|
|
|
char *buf = device->cap._BQC ? "_BQC" : "_BCQ";
|
|
@@ -620,8 +621,15 @@ acpi_video_device_lcd_get_level_current(struct acpi_video_device *device,
|
|
|
|
|
|
}
|
|
|
*level += bqc_offset_aml_bug_workaround;
|
|
|
- device->brightness->curr = *level;
|
|
|
- return 0;
|
|
|
+ for (i = 2; i < device->brightness->count; i++)
|
|
|
+ if (device->brightness->levels[i] == *level) {
|
|
|
+ device->brightness->curr = *level;
|
|
|
+ return 0;
|
|
|
+ }
|
|
|
+ /* BQC returned an invalid level. Stop using it. */
|
|
|
+ ACPI_WARNING((AE_INFO, "%s returned an invalid level",
|
|
|
+ buf));
|
|
|
+ device->cap._BQC = device->cap._BCQ = 0;
|
|
|
} else {
|
|
|
/* Fixme:
|
|
|
* should we return an error or ignore this failure?
|
|
@@ -872,7 +880,7 @@ acpi_video_init_brightness(struct acpi_video_device *device)
|
|
|
br->flags._BCM_use_index = br->flags._BCL_use_index;
|
|
|
|
|
|
/* _BQC uses INDEX while _BCL uses VALUE in some laptops */
|
|
|
- br->curr = level_old = max_level;
|
|
|
+ br->curr = level = max_level;
|
|
|
|
|
|
if (!device->cap._BQC)
|
|
|
goto set_level;
|
|
@@ -894,15 +902,25 @@ acpi_video_init_brightness(struct acpi_video_device *device)
|
|
|
|
|
|
br->flags._BQC_use_index = (level == max_level ? 0 : 1);
|
|
|
|
|
|
- if (!br->flags._BQC_use_index)
|
|
|
+ if (!br->flags._BQC_use_index) {
|
|
|
+ /*
|
|
|
+ * Set the backlight to the initial state.
|
|
|
+ * On some buggy laptops, _BQC returns an uninitialized value
|
|
|
+ * when invoked for the first time, i.e. level_old is invalid.
|
|
|
+ * set the backlight to max_level in this case
|
|
|
+ */
|
|
|
+ for (i = 2; i < br->count; i++)
|
|
|
+ if (level_old == br->levels[i])
|
|
|
+ level = level_old;
|
|
|
goto set_level;
|
|
|
+ }
|
|
|
|
|
|
if (br->flags._BCL_reversed)
|
|
|
level_old = (br->count - 1) - level_old;
|
|
|
- level_old = br->levels[level_old];
|
|
|
+ level = br->levels[level_old];
|
|
|
|
|
|
set_level:
|
|
|
- result = acpi_video_device_lcd_set_level(device, level_old);
|
|
|
+ result = acpi_video_device_lcd_set_level(device, level);
|
|
|
if (result)
|
|
|
goto out_free_levels;
|
|
|
|
|
@@ -936,9 +954,6 @@ static void acpi_video_device_find_cap(struct acpi_video_device *device)
|
|
|
{
|
|
|
acpi_handle h_dummy1;
|
|
|
|
|
|
-
|
|
|
- memset(&device->cap, 0, sizeof(device->cap));
|
|
|
-
|
|
|
if (ACPI_SUCCESS(acpi_get_handle(device->dev->handle, "_ADR", &h_dummy1))) {
|
|
|
device->cap._ADR = 1;
|
|
|
}
|
|
@@ -992,19 +1007,29 @@ static void acpi_video_device_find_cap(struct acpi_video_device *device)
|
|
|
if (result)
|
|
|
printk(KERN_ERR PREFIX "Create sysfs link\n");
|
|
|
|
|
|
- device->cdev = thermal_cooling_device_register("LCD",
|
|
|
+ device->cooling_dev = thermal_cooling_device_register("LCD",
|
|
|
device->dev, &video_cooling_ops);
|
|
|
- if (IS_ERR(device->cdev))
|
|
|
+ if (IS_ERR(device->cooling_dev)) {
|
|
|
+ /*
|
|
|
+ * Set cooling_dev to NULL so we don't crash trying to
|
|
|
+ * free it.
|
|
|
+ * Also, why the hell we are returning early and
|
|
|
+ * not attempt to register video output if cooling
|
|
|
+ * device registration failed?
|
|
|
+ * -- dtor
|
|
|
+ */
|
|
|
+ device->cooling_dev = NULL;
|
|
|
return;
|
|
|
+ }
|
|
|
|
|
|
dev_info(&device->dev->dev, "registered as cooling_device%d\n",
|
|
|
- device->cdev->id);
|
|
|
+ device->cooling_dev->id);
|
|
|
result = sysfs_create_link(&device->dev->dev.kobj,
|
|
|
- &device->cdev->device.kobj,
|
|
|
+ &device->cooling_dev->device.kobj,
|
|
|
"thermal_cooling");
|
|
|
if (result)
|
|
|
printk(KERN_ERR PREFIX "Create sysfs link\n");
|
|
|
- result = sysfs_create_link(&device->cdev->device.kobj,
|
|
|
+ result = sysfs_create_link(&device->cooling_dev->device.kobj,
|
|
|
&device->dev->dev.kobj, "device");
|
|
|
if (result)
|
|
|
printk(KERN_ERR PREFIX "Create sysfs link\n");
|
|
@@ -1041,7 +1066,6 @@ static void acpi_video_bus_find_cap(struct acpi_video_bus *video)
|
|
|
{
|
|
|
acpi_handle h_dummy1;
|
|
|
|
|
|
- memset(&video->cap, 0, sizeof(video->cap));
|
|
|
if (ACPI_SUCCESS(acpi_get_handle(video->device->handle, "_DOS", &h_dummy1))) {
|
|
|
video->cap._DOS = 1;
|
|
|
}
|
|
@@ -2011,13 +2035,13 @@ static int acpi_video_bus_put_one_device(struct acpi_video_device *device)
|
|
|
backlight_device_unregister(device->backlight);
|
|
|
device->backlight = NULL;
|
|
|
}
|
|
|
- if (device->cdev) {
|
|
|
+ if (device->cooling_dev) {
|
|
|
sysfs_remove_link(&device->dev->dev.kobj,
|
|
|
"thermal_cooling");
|
|
|
- sysfs_remove_link(&device->cdev->device.kobj,
|
|
|
+ sysfs_remove_link(&device->cooling_dev->device.kobj,
|
|
|
"device");
|
|
|
- thermal_cooling_device_unregister(device->cdev);
|
|
|
- device->cdev = NULL;
|
|
|
+ thermal_cooling_device_unregister(device->cooling_dev);
|
|
|
+ device->cooling_dev = NULL;
|
|
|
}
|
|
|
video_output_unregister(device->output_dev);
|
|
|
|