ALSA: hda: Use LPIB for Dell Latitude 131L
[safe/jmp/linux-2.6] / drivers / acpi / video.c
index a8432c2..72e76b4 100644 (file)
 #include <linux/pci.h>
 #include <linux/pci_ids.h>
 #include <asm/uaccess.h>
-
+#include <linux/dmi.h>
 #include <acpi/acpi_bus.h>
 #include <acpi/acpi_drivers.h>
 
+#define PREFIX "ACPI: "
+
 #define ACPI_VIDEO_CLASS               "video"
 #define ACPI_VIDEO_BUS_NAME            "Video Bus"
 #define ACPI_VIDEO_DEVICE_NAME         "Video Device"
@@ -283,7 +285,7 @@ static int acpi_video_device_brightness_open_fs(struct inode *inode,
                                                struct file *file);
 static ssize_t acpi_video_device_write_brightness(struct file *file,
        const char __user *buffer, size_t count, loff_t *data);
-static struct file_operations acpi_video_device_brightness_fops = {
+static const struct file_operations acpi_video_device_brightness_fops = {
        .owner = THIS_MODULE,
        .open = acpi_video_device_brightness_open_fs,
        .read = seq_read,
@@ -878,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;
@@ -900,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;
 
@@ -987,8 +999,10 @@ static void acpi_video_device_find_cap(struct acpi_video_device *device)
                sprintf(name, "acpi_video%d", count++);
                device->backlight = backlight_device_register(name,
                        NULL, device, &acpi_backlight_ops);
-               device->backlight->props.max_brightness = device->brightness->count-3;
                kfree(name);
+               if (IS_ERR(device->backlight))
+                       return;
+               device->backlight->props.max_brightness = device->brightness->count-3;
 
                result = sysfs_create_link(&device->backlight->dev.kobj,
                                           &device->dev->dev.kobj, "device");
@@ -1097,7 +1111,12 @@ static int acpi_video_bus_check(struct acpi_video_bus *video)
         */
 
        /* Does this device support video switching? */
-       if (video->cap._DOS) {
+       if (video->cap._DOS || video->cap._DOD) {
+               if (!video->cap._DOS) {
+                       printk(KERN_WARNING FW_BUG
+                               "ACPI(%s) defines _DOD but not _DOS\n",
+                               acpi_device_bid(video->device));
+               }
                video->flags.multihead = 1;
                status = 0;
        }
@@ -1206,7 +1225,7 @@ acpi_video_device_write_state(struct file *file,
        u32 state = 0;
 
 
-       if (!dev || count + 1 > sizeof str)
+       if (!dev || count >= sizeof(str))
                return -EINVAL;
 
        if (copy_from_user(str, buffer, count))
@@ -1263,7 +1282,7 @@ acpi_video_device_write_brightness(struct file *file,
        int i;
 
 
-       if (!dev || !dev->brightness || count + 1 > sizeof str)
+       if (!dev || !dev->brightness || count >= sizeof(str))
                return -EINVAL;
 
        if (copy_from_user(str, buffer, count))
@@ -1545,7 +1564,7 @@ acpi_video_bus_write_POST(struct file *file,
        unsigned long long opt, options;
 
 
-       if (!video || count + 1 > sizeof str)
+       if (!video || count >= sizeof(str))
                return -EINVAL;
 
        status = acpi_video_bus_POST_options(video, &options);
@@ -1585,7 +1604,7 @@ acpi_video_bus_write_DOS(struct file *file,
        unsigned long opt;
 
 
-       if (!video || count + 1 > sizeof str)
+       if (!video || count >= sizeof(str))
                return -EINVAL;
 
        if (copy_from_user(str, buffer, count))
@@ -1962,6 +1981,10 @@ acpi_video_switch_brightness(struct acpi_video_device *device, int event)
        unsigned long long level_current, level_next;
        int result = -EINVAL;
 
+       /* no warning message if acpi_backlight=vendor is used */
+       if (!acpi_video_backlight_support())
+               return 0;
+
        if (!device->brightness)
                goto out;
 
@@ -1974,6 +1997,10 @@ acpi_video_switch_brightness(struct acpi_video_device *device, int event)
 
        result = acpi_video_device_lcd_set_level(device, level_next);
 
+       if (!result)
+               backlight_force_update(device->backlight,
+                                      BACKLIGHT_UPDATE_HOTKEY);
+
 out:
        if (result)
                printk(KERN_ERR PREFIX "Failed to switch the brightness\n");
@@ -2018,8 +2045,11 @@ static int acpi_video_bus_put_one_device(struct acpi_video_device *device)
        status = acpi_remove_notify_handler(device->dev->handle,
                                            ACPI_DEVICE_NOTIFY,
                                            acpi_video_device_notify);
-       sysfs_remove_link(&device->backlight->dev.kobj, "device");
-       backlight_device_unregister(device->backlight);
+       if (device->backlight) {
+               sysfs_remove_link(&device->backlight->dev.kobj, "device");
+               backlight_device_unregister(device->backlight);
+               device->backlight = NULL;
+       }
        if (device->cooling_dev) {
                sysfs_remove_link(&device->dev->dev.kobj,
                                  "thermal_cooling");