diff options
Diffstat (limited to 'drivers/acpi/video.c')
-rw-r--r-- | drivers/acpi/video.c | 127 |
1 files changed, 119 insertions, 8 deletions
diff --git a/drivers/acpi/video.c b/drivers/acpi/video.c index 970c01a7f8f4..7f714fa2a454 100644 --- a/drivers/acpi/video.c +++ b/drivers/acpi/video.c @@ -34,6 +34,7 @@ #include <linux/seq_file.h> #include <linux/input.h> #include <linux/backlight.h> +#include <linux/thermal.h> #include <linux/video_output.h> #include <asm/uaccess.h> @@ -184,6 +185,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 output_device *output_dev; }; @@ -296,18 +298,26 @@ static int acpi_video_device_set_state(struct acpi_video_device *device, int sta static int acpi_video_get_brightness(struct backlight_device *bd) { unsigned long cur_level; + int i; struct acpi_video_device *vd = (struct acpi_video_device *)bl_get_data(bd); acpi_video_device_lcd_get_level_current(vd, &cur_level); - return (int) cur_level; + for (i = 2; i < vd->brightness->count; i++) { + if (vd->brightness->levels[i] == cur_level) + /* The first two entries are special - see page 575 + of the ACPI spec 3.0 */ + return i-2; + } + return 0; } static int acpi_video_set_brightness(struct backlight_device *bd) { - int request_level = bd->props.brightness; + int request_level = bd->props.brightness+2; struct acpi_video_device *vd = (struct acpi_video_device *)bl_get_data(bd); - acpi_video_device_lcd_set_level(vd, request_level); + acpi_video_device_lcd_set_level(vd, + vd->brightness->levels[request_level]); return 0; } @@ -338,6 +348,54 @@ static struct output_properties acpi_output_properties = { .set_state = acpi_video_output_set, .get_status = acpi_video_output_get, }; + + +/* thermal cooling device callbacks */ +static int video_get_max_state(struct thermal_cooling_device *cdev, char *buf) +{ + struct acpi_device *device = cdev->devdata; + struct acpi_video_device *video = acpi_driver_data(device); + + return sprintf(buf, "%d\n", video->brightness->count - 3); +} + +static int video_get_cur_state(struct thermal_cooling_device *cdev, char *buf) +{ + struct acpi_device *device = cdev->devdata; + struct acpi_video_device *video = acpi_driver_data(device); + unsigned long level; + int state; + + acpi_video_device_lcd_get_level_current(video, &level); + for (state = 2; state < video->brightness->count; state++) + if (level == video->brightness->levels[state]) + return sprintf(buf, "%d\n", + video->brightness->count - state - 1); + + return -EINVAL; +} + +static int +video_set_cur_state(struct thermal_cooling_device *cdev, unsigned int state) +{ + struct acpi_device *device = cdev->devdata; + struct acpi_video_device *video = acpi_driver_data(device); + int level; + + if ( state >= video->brightness->count - 2) + return -EINVAL; + + state = video->brightness->count - state; + level = video->brightness->levels[state -1]; + return acpi_video_device_lcd_set_level(video, level); +} + +static struct thermal_cooling_device_ops video_cooling_ops = { + .get_max_state = video_get_max_state, + .get_cur_state = video_get_cur_state, + .set_cur_state = video_set_cur_state, +}; + /* -------------------------------------------------------------------------- Video Management -------------------------------------------------------------------------- */ @@ -656,7 +714,7 @@ static void acpi_video_device_find_cap(struct acpi_video_device *device) kfree(obj); if (device->cap._BCL && device->cap._BCM && device->cap._BQC && max_level > 0){ - unsigned long tmp; + int result; static int count = 0; char *name; name = kzalloc(MAX_NAME_LEN, GFP_KERNEL); @@ -664,14 +722,30 @@ static void acpi_video_device_find_cap(struct acpi_video_device *device) return; sprintf(name, "acpi_video%d", count++); - acpi_video_device_lcd_get_level_current(device, &tmp); device->backlight = backlight_device_register(name, NULL, device, &acpi_backlight_ops); - device->backlight->props.max_brightness = max_level; - device->backlight->props.brightness = (int)tmp; + device->backlight->props.max_brightness = device->brightness->count-3; + device->backlight->props.brightness = acpi_video_get_brightness(device->backlight); backlight_update_status(device->backlight); - kfree(name); + + device->cdev = thermal_cooling_device_register("LCD", + device->dev, &video_cooling_ops); + if (device->cdev) { + printk(KERN_INFO PREFIX + "%s is registered as cooling_device%d\n", + device->dev->dev.bus_id, device->cdev->id); + result = sysfs_create_link(&device->dev->dev.kobj, + &device->cdev->device.kobj, + "thermal_cooling"); + if (result) + printk(KERN_ERR PREFIX "Create sysfs link\n"); + result = sysfs_create_link(&device->cdev->device.kobj, + &device->dev->dev.kobj, + "device"); + if (result) + printk(KERN_ERR PREFIX "Create sysfs link\n"); + } } if (device->cap._DCS && device->cap._DSS){ static int count = 0; @@ -1289,8 +1363,37 @@ acpi_video_bus_write_DOS(struct file *file, static int acpi_video_bus_add_fs(struct acpi_device *device) { + long device_id; + int status; struct proc_dir_entry *entry = NULL; struct acpi_video_bus *video; + struct device *dev; + + status = + acpi_evaluate_integer(device->handle, "_ADR", NULL, &device_id); + + if (!ACPI_SUCCESS(status)) + return -ENODEV; + + /* We need to attempt to determine whether the _ADR refers to a + PCI device or not. There's no terribly good way to do this, + so the best we can hope for is to assume that there'll never + be a video device in the host bridge */ + if (device_id >= 0x10000) { + /* It looks like a PCI device. Does it exist? */ + dev = acpi_get_physical_device(device->handle); + } else { + /* It doesn't look like a PCI device. Does its parent + exist? */ + acpi_handle phandle; + if (acpi_get_parent(device->handle, &phandle)) + return -ENODEV; + dev = acpi_get_physical_device(phandle); + } + if (!dev) + return -ENODEV; + put_device(dev); + video = acpi_driver_data(device); @@ -1704,6 +1807,14 @@ static int acpi_video_bus_put_one_device(struct acpi_video_device *device) ACPI_DEVICE_NOTIFY, acpi_video_device_notify); backlight_device_unregister(device->backlight); + if (device->cdev) { + sysfs_remove_link(&device->dev->dev.kobj, + "thermal_cooling"); + sysfs_remove_link(&device->cdev->device.kobj, + "device"); + thermal_cooling_device_unregister(device->cdev); + device->cdev = NULL; + } video_output_unregister(device->output_dev); return 0; |