From c8890f903a6fdf5711726e8e8d65cb13423f8833 Mon Sep 17 00:00:00 2001 From: Zhang Rui Date: Wed, 18 Mar 2009 16:27:08 +0800 Subject: ACPI video: check the return value of acpi_video_device_lcd_get_level_current Signed-off-by: Zhang Rui Acked-by: Matthew Garrett Acked-by: Thomas Renninger Signed-off-by: Len Brown --- drivers/acpi/video.c | 55 ++++++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 45 insertions(+), 10 deletions(-) (limited to 'drivers/acpi/video.c') diff --git a/drivers/acpi/video.c b/drivers/acpi/video.c index bb5ed059114..f0e6eb53416 100644 --- a/drivers/acpi/video.c +++ b/drivers/acpi/video.c @@ -294,7 +294,7 @@ static int acpi_video_device_lcd_get_level_current( unsigned long long *level); static int acpi_video_get_next_level(struct acpi_video_device *device, u32 level_current, u32 event); -static void acpi_video_switch_brightness(struct acpi_video_device *device, +static int acpi_video_switch_brightness(struct acpi_video_device *device, int event); static int acpi_video_device_get_state(struct acpi_video_device *device, unsigned long long *state); @@ -308,7 +308,9 @@ static int acpi_video_get_brightness(struct backlight_device *bd) 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); + + if (acpi_video_device_lcd_get_level_current(vd, &cur_level)) + return -EINVAL; for (i = 2; i < vd->brightness->count; i++) { if (vd->brightness->levels[i] == cur_level) /* The first two entries are special - see page 575 @@ -373,7 +375,8 @@ static int video_get_cur_state(struct thermal_cooling_device *cdev, char *buf) unsigned long long level; int state; - acpi_video_device_lcd_get_level_current(video, &level); + if (acpi_video_device_lcd_get_level_current(video, &level)) + return -EINVAL; for (state = 2; state < video->brightness->count; state++) if (level == video->brightness->levels[state]) return sprintf(buf, "%d\n", @@ -502,11 +505,29 @@ static int acpi_video_device_lcd_get_level_current(struct acpi_video_device *device, unsigned long long *level) { - if (device->cap._BQC) - return acpi_evaluate_integer(device->dev->handle, "_BQC", NULL, - level); + acpi_status status = AE_OK; + + if (device->cap._BQC) { + status = acpi_evaluate_integer(device->dev->handle, "_BQC", + NULL, level); + if (ACPI_SUCCESS(status)) { + device->brightness->curr = *level; + return 0; + } else { + /* Fixme: + * should we return an error or ignore this failure? + * dev->brightness->curr is a cached value which stores + * the correct current backlight level in most cases. + * ACPI video backlight still works w/ buggy _BQC. + * http://bugzilla.kernel.org/show_bug.cgi?id=12233 + */ + ACPI_WARNING((AE_INFO, "Evaluating _BQC failed")); + device->cap._BQC = 0; + } + } + *level = device->brightness->curr; - return AE_OK; + return 0; } static int @@ -1749,15 +1770,29 @@ acpi_video_get_next_level(struct acpi_video_device *device, } } -static void +static int acpi_video_switch_brightness(struct acpi_video_device *device, int event) { unsigned long long level_current, level_next; + int result = -EINVAL; + if (!device->brightness) - return; - acpi_video_device_lcd_get_level_current(device, &level_current); + goto out; + + result = acpi_video_device_lcd_get_level_current(device, + &level_current); + if (result) + goto out; + level_next = acpi_video_get_next_level(device, level_current, event); + acpi_video_device_lcd_set_level(device, level_next); + +out: + if (result) + printk(KERN_ERR PREFIX "Failed to switch the brightness\n"); + + return result; } static int -- cgit v1.2.3 From 24450c7add575cef53097738f16a4c1a720fa5cb Mon Sep 17 00:00:00 2001 From: Zhang Rui Date: Wed, 18 Mar 2009 16:27:10 +0800 Subject: ACPI video: check the return value of acpi_video_device_lcd_set_level Signed-off-by: Zhang Rui Acked-by: Matthew Garrett Acked-by: Thomas Renninger Signed-off-by: Len Brown --- drivers/acpi/video.c | 37 +++++++++++++++++++++---------------- 1 file changed, 21 insertions(+), 16 deletions(-) (limited to 'drivers/acpi/video.c') diff --git a/drivers/acpi/video.c b/drivers/acpi/video.c index f0e6eb53416..52f52b32b63 100644 --- a/drivers/acpi/video.c +++ b/drivers/acpi/video.c @@ -322,12 +322,12 @@ static int acpi_video_get_brightness(struct backlight_device *bd) static int acpi_video_set_brightness(struct backlight_device *bd) { - int request_level = bd->props.brightness+2; + 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, - vd->brightness->levels[request_level]); - return 0; + + return acpi_video_device_lcd_set_level(vd, + vd->brightness->levels[request_level]); } static struct backlight_ops acpi_backlight_ops = { @@ -482,23 +482,29 @@ acpi_video_device_lcd_query_levels(struct acpi_video_device *device, static int acpi_video_device_lcd_set_level(struct acpi_video_device *device, int level) { - int status = AE_OK; + int status; union acpi_object arg0 = { ACPI_TYPE_INTEGER }; struct acpi_object_list args = { 1, &arg0 }; int state; - arg0.integer.value = level; - if (device->cap._BCM) - status = acpi_evaluate_object(device->dev->handle, "_BCM", - &args, NULL); + status = acpi_evaluate_object(device->dev->handle, "_BCM", + &args, NULL); + if (ACPI_FAILURE(status)) { + ACPI_ERROR((AE_INFO, "Evaluating _BCM failed")); + return -EIO; + } + device->brightness->curr = level; for (state = 2; state < device->brightness->count; state++) - if (level == device->brightness->levels[state]) + if (level == device->brightness->levels[state]) { device->backlight->props.brightness = state - 2; + return 0; + } - return status; + ACPI_ERROR((AE_INFO, "Current brightness invalid")); + return -EINVAL; } static int @@ -1082,13 +1088,12 @@ acpi_video_device_write_brightness(struct file *file, /* validate through the list of available levels */ for (i = 2; i < dev->brightness->count; i++) if (level == dev->brightness->levels[i]) { - if (ACPI_SUCCESS - (acpi_video_device_lcd_set_level(dev, level))) - dev->brightness->curr = level; + if (!acpi_video_device_lcd_set_level(dev, level)) + return count; break; } - return count; + return -EINVAL; } static int acpi_video_device_EDID_seq_show(struct seq_file *seq, void *offset) @@ -1786,7 +1791,7 @@ acpi_video_switch_brightness(struct acpi_video_device *device, int event) level_next = acpi_video_get_next_level(device, level_current, event); - acpi_video_device_lcd_set_level(device, level_next); + result = acpi_video_device_lcd_set_level(device, level_next); out: if (result) -- cgit v1.2.3 From d32f69470c2081ffdfd82740ac19f940790f9e93 Mon Sep 17 00:00:00 2001 From: Zhang Rui Date: Wed, 18 Mar 2009 16:27:12 +0800 Subject: ACPI video: support _BCL packages that don't export brightness levels when machine is on AC/Battery Many buggy BIOSes don't export the brightness levels when machine is on AC/Battery in the _BCL method. Reformat the _BCL package for these laptops: now the elements in device->brightness->levels[] are like: levels[0]: brightness level when on AC power. levels[1]: brightness level when on Battery power. levels[2]: supported brightness level 1. levels[3]: supported brightness level 2. ... levels[n]: supported brightness level n-1. levels[n + 1]: supported brightness level n. So if there are n supported brightness levels on this laptop, we will have n+2 entries in device->brightnes->levels[]. level[0] and level[1] are invalid on the laptops that don't export the brightness levels on AC/Battery. Fortunately, we never use these two values at all, even for the valid ones. http://bugzilla.kernel.org/show_bug.cgi?id=12249 Signed-off-by: Zhang Rui Acked-by: Matthew Garrett Acked-by: Thomas Renninger Signed-off-by: Len Brown --- drivers/acpi/video.c | 37 ++++++++++++++++++++++++++++++------- 1 file changed, 30 insertions(+), 7 deletions(-) (limited to 'drivers/acpi/video.c') diff --git a/drivers/acpi/video.c b/drivers/acpi/video.c index 52f52b32b63..398b3eee37f 100644 --- a/drivers/acpi/video.c +++ b/drivers/acpi/video.c @@ -168,10 +168,15 @@ struct acpi_video_device_cap { u8 _DSS:1; /*Device state set */ }; +struct acpi_video_brightness_flags { + u8 _BCL_no_ac_battery_levels:1; /* no AC/Battery levels in _BCL */ +}; + struct acpi_video_device_brightness { int curr; int count; int *levels; + struct acpi_video_brightness_flags flags; }; struct acpi_video_device { @@ -682,7 +687,7 @@ static int acpi_video_init_brightness(struct acpi_video_device *device) { union acpi_object *obj = NULL; - int i, max_level = 0, count = 0; + int i, max_level = 0, count = 0, level_ac_battery = 0; union acpi_object *o; struct acpi_video_device_brightness *br = NULL; @@ -701,7 +706,7 @@ acpi_video_init_brightness(struct acpi_video_device *device) goto out; } - br->levels = kmalloc(obj->package.count * sizeof *(br->levels), + br->levels = kmalloc((obj->package.count + 2) * sizeof *(br->levels), GFP_KERNEL); if (!br->levels) goto out_free; @@ -719,16 +724,34 @@ acpi_video_init_brightness(struct acpi_video_device *device) count++; } - /* don't sort the first two brightness levels */ + /* + * some buggy BIOS don't export the levels + * when machine is on AC/Battery in _BCL package. + * In this case, the first two elements in _BCL packages + * are also supported brightness levels that OS should take care of. + */ + for (i = 2; i < count; i++) + if (br->levels[i] == br->levels[0] || + br->levels[i] == br->levels[1]) + level_ac_battery++; + + if (level_ac_battery < 2) { + level_ac_battery = 2 - level_ac_battery; + br->flags._BCL_no_ac_battery_levels = 1; + for (i = (count - 1 + level_ac_battery); i >= 2; i--) + br->levels[i] = br->levels[i - level_ac_battery]; + count += level_ac_battery; + } else if (level_ac_battery > 2) + ACPI_ERROR((AE_INFO, "Too many duplicates in _BCL package\n")); + + /* sort all the supported brightness levels */ sort(&br->levels[2], count - 2, sizeof(br->levels[2]), acpi_video_cmp_level, NULL); - if (count < 2) - goto out_free_levels; - br->count = count; device->brightness = br; - ACPI_DEBUG_PRINT((ACPI_DB_INFO, "found %d brightness levels\n", count)); + ACPI_DEBUG_PRINT((ACPI_DB_INFO, + "found %d brightness levels\n", count - 2)); kfree(obj); return max_level; -- cgit v1.2.3 From d80fb99fdcd56f4934f11cc44ca016463842dc8b Mon Sep 17 00:00:00 2001 From: Zhang Rui Date: Wed, 18 Mar 2009 16:27:14 +0800 Subject: ACPI video: support reversed _BCL method in ACPI video driver The brightness levels returned by _BCL package are in a reversed order on some laptops. http://bugzilla.kernel.org/show_bug.cgi?id=12037 http://bugzilla.kernel.org/show_bug.cgi?id=12302 http://bugzilla.kernel.org/show_bug.cgi?id=12235 sort the _BCL packge in case it's reversed. Signed-off-by: Zhang Rui Acked-by: Matthew Garrett Acked-by: Thomas Renninger Signed-off-by: Len Brown --- drivers/acpi/video.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) (limited to 'drivers/acpi/video.c') diff --git a/drivers/acpi/video.c b/drivers/acpi/video.c index 398b3eee37f..dc84970ce1e 100644 --- a/drivers/acpi/video.c +++ b/drivers/acpi/video.c @@ -170,6 +170,7 @@ struct acpi_video_device_cap { struct acpi_video_brightness_flags { u8 _BCL_no_ac_battery_levels:1; /* no AC/Battery levels in _BCL */ + u8 _BCL_reversed:1; /* _BCL package is in a reversed order*/ }; struct acpi_video_device_brightness { @@ -744,9 +745,14 @@ acpi_video_init_brightness(struct acpi_video_device *device) } else if (level_ac_battery > 2) ACPI_ERROR((AE_INFO, "Too many duplicates in _BCL package\n")); - /* sort all the supported brightness levels */ - sort(&br->levels[2], count - 2, sizeof(br->levels[2]), - acpi_video_cmp_level, NULL); + /* Check if the _BCL package is in a reversed order */ + if (max_level == br->levels[2]) { + br->flags._BCL_reversed = 1; + sort(&br->levels[2], count - 2, sizeof(br->levels[2]), + acpi_video_cmp_level, NULL); + } else if (max_level != br->levels[count - 1]) + ACPI_ERROR((AE_INFO, + "Found unordered _BCL package\n")); br->count = count; device->brightness = br; -- cgit v1.2.3 From 1a7c618a3f7bef1a20ae740df512eeba21397fa5 Mon Sep 17 00:00:00 2001 From: Zhang Rui Date: Wed, 18 Mar 2009 16:27:16 +0800 Subject: ACPI video: support _BQC/_BCL/_BCM methods that use index values The input/output of _BQC/_BCL/_BCM control methods should be represented by a number between 0 and 100, and can be thought of as a percentage. But some buggy _BQC/_BCL/_BCM methods use the index values instead. http://bugzilla.kernel.org/show_bug.cgi?id=12302 http://bugzilla.kernel.org/show_bug.cgi?id=12249 http://bugzilla.kernel.org/show_bug.cgi?id=12037 Add the functionality to support such kind of BIOSes in ACPI video driver. Signed-off-by: Zhang Rui Acked-by: Matthew Garrett Acked-by: Thomas Renninger Signed-off-by: Len Brown --- drivers/acpi/video.c | 91 ++++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 70 insertions(+), 21 deletions(-) (limited to 'drivers/acpi/video.c') diff --git a/drivers/acpi/video.c b/drivers/acpi/video.c index dc84970ce1e..1f1625c5100 100644 --- a/drivers/acpi/video.c +++ b/drivers/acpi/video.c @@ -171,6 +171,9 @@ struct acpi_video_device_cap { struct acpi_video_brightness_flags { u8 _BCL_no_ac_battery_levels:1; /* no AC/Battery levels in _BCL */ u8 _BCL_reversed:1; /* _BCL package is in a reversed order*/ + u8 _BCL_use_index:1; /* levels in _BCL are index values */ + u8 _BCM_use_index:1; /* input of _BCM is an index value */ + u8 _BQC_use_index:1; /* _BQC returns an index value */ }; struct acpi_video_device_brightness { @@ -505,7 +508,8 @@ acpi_video_device_lcd_set_level(struct acpi_video_device *device, int level) device->brightness->curr = level; for (state = 2; state < device->brightness->count; state++) if (level == device->brightness->levels[state]) { - device->backlight->props.brightness = state - 2; + if (device->backlight) + device->backlight->props.brightness = state - 2; return 0; } @@ -523,6 +527,13 @@ acpi_video_device_lcd_get_level_current(struct acpi_video_device *device, status = acpi_evaluate_integer(device->dev->handle, "_BQC", NULL, level); if (ACPI_SUCCESS(status)) { + if (device->brightness->flags._BQC_use_index) { + if (device->brightness->flags._BCL_reversed) + *level = device->brightness->count + - 3 - (*level); + *level = device->brightness->levels[*level + 2]; + + } device->brightness->curr = *level; return 0; } else { @@ -689,8 +700,10 @@ acpi_video_init_brightness(struct acpi_video_device *device) { union acpi_object *obj = NULL; int i, max_level = 0, count = 0, level_ac_battery = 0; + unsigned long long level, level_old; union acpi_object *o; struct acpi_video_device_brightness *br = NULL; + int result = -EINVAL; if (!ACPI_SUCCESS(acpi_video_device_lcd_query_levels(device, &obj))) { ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Could not query available " @@ -704,13 +717,16 @@ acpi_video_init_brightness(struct acpi_video_device *device) br = kzalloc(sizeof(*br), GFP_KERNEL); if (!br) { printk(KERN_ERR "can't allocate memory\n"); + result = -ENOMEM; goto out; } br->levels = kmalloc((obj->package.count + 2) * sizeof *(br->levels), GFP_KERNEL); - if (!br->levels) + if (!br->levels) { + result = -ENOMEM; goto out_free; + } for (i = 0; i < obj->package.count; i++) { o = (union acpi_object *)&obj->package.elements[i]; @@ -756,10 +772,55 @@ acpi_video_init_brightness(struct acpi_video_device *device) br->count = count; device->brightness = br; + + /* Check the input/output of _BQC/_BCL/_BCM */ + if ((max_level < 100) && (max_level <= (count - 2))) + br->flags._BCL_use_index = 1; + + /* + * _BCM is always consistent with _BCL, + * at least for all the laptops we have ever seen. + */ + br->flags._BCM_use_index = br->flags._BCL_use_index; + + /* _BQC uses INDEX while _BCL uses VALUE in some laptops */ + br->curr = max_level; + result = acpi_video_device_lcd_get_level_current(device, &level_old); + if (result) + goto out_free_levels; + + result = acpi_video_device_lcd_set_level(device, br->curr); + if (result) + goto out_free_levels; + + result = acpi_video_device_lcd_get_level_current(device, &level); + if (result) + goto out_free_levels; + + if ((level != level_old) && !br->flags._BCM_use_index) { + /* Note: + * This piece of code does not work correctly if the current + * brightness levels is 0. + * But I guess boxes that boot with such a dark screen are rare + * and no more code is needed to cover this specifial case. + */ + + if (level_ac_battery != 2) { + /* + * For now, we don't support the _BCL like this: + * 16, 15, 0, 1, 2, 3, ..., 14, 15, 16 + * because we may mess up the index returned by _BQC. + * Plus: we have not got a box like this. + */ + ACPI_ERROR((AE_INFO, "_BCL not supported\n")); + } + br->flags._BQC_use_index = 1; + } + ACPI_DEBUG_PRINT((ACPI_DB_INFO, "found %d brightness levels\n", count - 2)); kfree(obj); - return max_level; + return result; out_free_levels: kfree(br->levels); @@ -768,7 +829,7 @@ out_free: out: device->brightness = NULL; kfree(obj); - return 0; + return result; } /* @@ -785,7 +846,6 @@ out: static void acpi_video_device_find_cap(struct acpi_video_device *device) { acpi_handle h_dummy1; - u32 max_level = 0; memset(&device->cap, 0, sizeof(device->cap)); @@ -814,13 +874,14 @@ static void acpi_video_device_find_cap(struct acpi_video_device *device) device->cap._DSS = 1; } - if (acpi_video_backlight_support()) - max_level = acpi_video_init_brightness(device); - - if (device->cap._BCL && device->cap._BCM && max_level > 0) { + if (acpi_video_backlight_support()) { int result; static int count = 0; char *name; + + result = acpi_video_init_brightness(device); + if (result) + return; name = kzalloc(MAX_NAME_LEN, GFP_KERNEL); if (!name) return; @@ -829,18 +890,6 @@ static void acpi_video_device_find_cap(struct acpi_video_device *device) device->backlight = backlight_device_register(name, NULL, device, &acpi_backlight_ops); device->backlight->props.max_brightness = device->brightness->count-3; - /* - * If there exists the _BQC object, the _BQC object will be - * called to get the current backlight brightness. Otherwise - * the brightness will be set to the maximum. - */ - if (device->cap._BQC) - device->backlight->props.brightness = - acpi_video_get_brightness(device->backlight); - else - device->backlight->props.brightness = - device->backlight->props.max_brightness; - backlight_update_status(device->backlight); kfree(name); device->cdev = thermal_cooling_device_register("LCD", -- cgit v1.2.3 From c60d638e29c780b75b648283a197d0226e3576c3 Mon Sep 17 00:00:00 2001 From: Zhang Rui Date: Wed, 18 Mar 2009 16:27:18 +0800 Subject: ACPI video: support buggy BIOSes with _BCQ implemented Some buggy BIOSes implements _BCQ instead of _BQC. Male ACPI video driver support these buggy BIOS. Signed-off-by: Zhang Rui Signed-off-by: Len Brown --- drivers/acpi/video.c | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) (limited to 'drivers/acpi/video.c') diff --git a/drivers/acpi/video.c b/drivers/acpi/video.c index 1f1625c5100..9730ec16759 100644 --- a/drivers/acpi/video.c +++ b/drivers/acpi/video.c @@ -162,6 +162,7 @@ struct acpi_video_device_cap { u8 _BCL:1; /*Query list of brightness control levels supported */ u8 _BCM:1; /*Set the brightness level */ u8 _BQC:1; /* Get current brightness level */ + u8 _BCQ:1; /* Some buggy BIOS uses _BCQ instead of _BQC */ u8 _DDC:1; /*Return the EDID for this device */ u8 _DCS:1; /*Return status of output device */ u8 _DGS:1; /*Query graphics state */ @@ -523,8 +524,10 @@ acpi_video_device_lcd_get_level_current(struct acpi_video_device *device, { acpi_status status = AE_OK; - if (device->cap._BQC) { - status = acpi_evaluate_integer(device->dev->handle, "_BQC", + if (device->cap._BQC || device->cap._BCQ) { + char *buf = device->cap._BQC ? "_BQC" : "_BCQ"; + + status = acpi_evaluate_integer(device->dev->handle, buf, NULL, level); if (ACPI_SUCCESS(status)) { if (device->brightness->flags._BQC_use_index) { @@ -544,8 +547,8 @@ acpi_video_device_lcd_get_level_current(struct acpi_video_device *device, * ACPI video backlight still works w/ buggy _BQC. * http://bugzilla.kernel.org/show_bug.cgi?id=12233 */ - ACPI_WARNING((AE_INFO, "Evaluating _BQC failed")); - device->cap._BQC = 0; + ACPI_WARNING((AE_INFO, "Evaluating %s failed", buf)); + device->cap._BQC = device->cap._BCQ = 0; } } @@ -861,6 +864,12 @@ static void acpi_video_device_find_cap(struct acpi_video_device *device) } if (ACPI_SUCCESS(acpi_get_handle(device->dev->handle,"_BQC",&h_dummy1))) device->cap._BQC = 1; + else if (ACPI_SUCCESS(acpi_get_handle(device->dev->handle, "_BCQ", + &h_dummy1))) { + printk(KERN_WARNING FW_BUG "_BCQ is used instead of _BQC\n"); + device->cap._BCQ = 1; + } + if (ACPI_SUCCESS(acpi_get_handle(device->dev->handle, "_DDC", &h_dummy1))) { device->cap._DDC = 1; } -- cgit v1.2.3 From 74a365b3f354fafc537efa5867deb7a9fadbfe27 Mon Sep 17 00:00:00 2001 From: Matthew Garrett Date: Thu, 19 Mar 2009 21:35:39 +0000 Subject: ACPI: Populate DIDL before registering ACPI video device on Intel Intel graphics hardware that implements the ACPI IGD OpRegion spec requires that the list of display devices be populated before any ACPI video methods are called. Detect when this is the case and defer registration until the opregion code calls it. Fixes crashes on HP laptops. http://bugzilla.kernel.org/show_bug.cgi?id=11259 Signed-off-by: Matthew Garrett Acked-by: Eric Anholt Signed-off-by: Len Brown --- drivers/acpi/video.c | 40 +++++++++++++++++++++++++++++++++++++++- 1 file changed, 39 insertions(+), 1 deletion(-) (limited to 'drivers/acpi/video.c') diff --git a/drivers/acpi/video.c b/drivers/acpi/video.c index 9730ec16759..ae427100a1e 100644 --- a/drivers/acpi/video.c +++ b/drivers/acpi/video.c @@ -37,6 +37,8 @@ #include #include #include +#include +#include #include #include @@ -2251,7 +2253,27 @@ static int acpi_video_bus_remove(struct acpi_device *device, int type) return 0; } -static int __init acpi_video_init(void) +static int __init intel_opregion_present(void) +{ +#if defined(CONFIG_DRM_I915) || defined(CONFIG_DRM_I915_MODULE) + struct pci_dev *dev = NULL; + u32 address; + + for_each_pci_dev(dev) { + if ((dev->class >> 8) != PCI_CLASS_DISPLAY_VGA) + continue; + if (dev->vendor != PCI_VENDOR_ID_INTEL) + continue; + pci_read_config_dword(dev, 0xfc, &address); + if (!address) + continue; + return 1; + } +#endif + return 0; +} + +int acpi_video_register(void) { int result = 0; @@ -2268,6 +2290,22 @@ static int __init acpi_video_init(void) return 0; } +EXPORT_SYMBOL(acpi_video_register); + +/* + * This is kind of nasty. Hardware using Intel chipsets may require + * the video opregion code to be run first in order to initialise + * state before any ACPI video calls are made. To handle this we defer + * registration of the video class until the opregion code has run. + */ + +static int __init acpi_video_init(void) +{ + if (intel_opregion_present()) + return 0; + + return acpi_video_register(); +} static void __exit acpi_video_exit(void) { -- cgit v1.2.3