drm/i915: more conversion from connector_list walk to encoder_list
[safe/jmp/linux-2.6] / drivers / acpi / video.c
index 94b1a4c..cbe6f39 100644 (file)
@@ -78,6 +78,13 @@ MODULE_LICENSE("GPL");
 static int brightness_switch_enabled = 1;
 module_param(brightness_switch_enabled, bool, 0644);
 
+/*
+ * By default, we don't allow duplicate ACPI video bus devices
+ * under the same VGA controller
+ */
+static int allow_duplicates;
+module_param(allow_duplicates, bool, 0644);
+
 static int register_count = 0;
 static int acpi_video_bus_add(struct acpi_device *device);
 static int acpi_video_bus_remove(struct acpi_device *device, int type);
@@ -285,7 +292,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,
@@ -320,7 +327,7 @@ static int acpi_video_device_lcd_set_level(struct acpi_video_device *device,
                        int level);
 static int acpi_video_device_lcd_get_level_current(
                        struct acpi_video_device *device,
-                       unsigned long long *level);
+                       unsigned long long *level, int init);
 static int acpi_video_get_next_level(struct acpi_video_device *device,
                                     u32 level_current, u32 event);
 static int acpi_video_switch_brightness(struct acpi_video_device *device,
@@ -338,7 +345,7 @@ static int acpi_video_get_brightness(struct backlight_device *bd)
        struct acpi_video_device *vd =
                (struct acpi_video_device *)bl_get_data(bd);
 
-       if (acpi_video_device_lcd_get_level_current(vd, &cur_level))
+       if (acpi_video_device_lcd_get_level_current(vd, &cur_level, 0))
                return -EINVAL;
        for (i = 2; i < vd->brightness->count; i++) {
                if (vd->brightness->levels[i] == cur_level)
@@ -407,7 +414,7 @@ static int video_get_cur_state(struct thermal_cooling_device *cooling_dev, unsig
        unsigned long long level;
        int offset;
 
-       if (acpi_video_device_lcd_get_level_current(video, &level))
+       if (acpi_video_device_lcd_get_level_current(video, &level, 0))
                return -EINVAL;
        for (offset = 2; offset < video->brightness->count; offset++)
                if (level == video->brightness->levels[offset]) {
@@ -602,7 +609,7 @@ static struct dmi_system_id video_dmi_table[] __initdata = {
 
 static int
 acpi_video_device_lcd_get_level_current(struct acpi_video_device *device,
-                                       unsigned long long *level)
+                                       unsigned long long *level, int init)
 {
        acpi_status status = AE_OK;
        int i;
@@ -626,10 +633,16 @@ acpi_video_device_lcd_get_level_current(struct acpi_video_device *device,
                                        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;
+                       if (!init) {
+                               /*
+                                * 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?
@@ -752,7 +765,7 @@ acpi_video_bus_POST_options(struct acpi_video_bus *video,
 static int
 acpi_video_bus_DOS(struct acpi_video_bus *video, int bios_flag, int lcd_flag)
 {
-       acpi_integer status = 0;
+       u64 status = 0;
        union acpi_object arg0 = { ACPI_TYPE_INTEGER };
        struct acpi_object_list args = { 1, &arg0 };
 
@@ -885,7 +898,7 @@ acpi_video_init_brightness(struct acpi_video_device *device)
        if (!device->cap._BQC)
                goto set_level;
 
-       result = acpi_video_device_lcd_get_level_current(device, &level_old);
+       result = acpi_video_device_lcd_get_level_current(device, &level_old, 1);
        if (result)
                goto out_free_levels;
 
@@ -896,7 +909,7 @@ acpi_video_init_brightness(struct acpi_video_device *device)
        if (result)
                goto out_free_levels;
 
-       result = acpi_video_device_lcd_get_level_current(device, &level);
+       result = acpi_video_device_lcd_get_level_current(device, &level, 0);
        if (result)
                goto out_free_levels;
 
@@ -985,6 +998,7 @@ static void acpi_video_device_find_cap(struct acpi_video_device *device)
        }
 
        if (acpi_video_backlight_support()) {
+               struct backlight_properties props;
                int result;
                static int count = 0;
                char *name;
@@ -997,10 +1011,14 @@ static void acpi_video_device_find_cap(struct acpi_video_device *device)
                        return;
 
                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;
+               memset(&props, 0, sizeof(struct backlight_properties));
+               props.max_brightness = device->brightness->count - 3;
+               device->backlight = backlight_device_register(name, NULL, device,
+                                                             &acpi_backlight_ops,
+                                                             &props);
                kfree(name);
+               if (IS_ERR(device->backlight))
+                       return;
 
                result = sysfs_create_link(&device->backlight->dev.kobj,
                                           &device->dev->dev.kobj, "device");
@@ -1109,7 +1127,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;
        }
@@ -1218,7 +1241,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))
@@ -1275,7 +1298,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))
@@ -1557,7 +1580,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);
@@ -1597,7 +1620,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))
@@ -1974,11 +1997,15 @@ 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;
 
        result = acpi_video_device_lcd_get_level_current(device,
-                                                        &level_current);
+                                                        &level_current, 0);
        if (result)
                goto out;
 
@@ -1986,6 +2013,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");
@@ -2224,11 +2255,47 @@ static int acpi_video_resume(struct acpi_device *device)
        return AE_OK;
 }
 
+static acpi_status
+acpi_video_bus_match(acpi_handle handle, u32 level, void *context,
+                       void **return_value)
+{
+       struct acpi_device *device = context;
+       struct acpi_device *sibling;
+       int result;
+
+       if (handle == device->handle)
+               return AE_CTRL_TERMINATE;
+
+       result = acpi_bus_get_device(handle, &sibling);
+       if (result)
+               return AE_OK;
+
+       if (!strcmp(acpi_device_name(sibling), ACPI_VIDEO_BUS_NAME))
+                       return AE_ALREADY_EXISTS;
+
+       return AE_OK;
+}
+
 static int acpi_video_bus_add(struct acpi_device *device)
 {
        struct acpi_video_bus *video;
        struct input_dev *input;
        int error;
+       acpi_status status;
+
+       status = acpi_walk_namespace(ACPI_TYPE_DEVICE,
+                               device->parent->handle, 1,
+                               acpi_video_bus_match, NULL,
+                               device, NULL);
+       if (status == AE_ALREADY_EXISTS) {
+               printk(KERN_WARNING FW_BUG
+                       "Duplicate ACPI video bus devices for the"
+                       " same VGA controller, please try module "
+                       "parameter \"video.allow_duplicates=1\""
+                       "if the current driver doesn't work.\n");
+               if (!allow_duplicates)
+                       return -ENODEV;
+       }
 
        video = kzalloc(sizeof(struct acpi_video_bus), GFP_KERNEL);
        if (!video)