Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 12648810 authored by Len Brown's avatar Len Brown
Browse files

Merge branch 'video' into release



Conflicts:
	drivers/acpi/video.c

Signed-off-by: default avatarLen Brown <len.brown@intel.com>
parents 7329e935 03ae61dd
Loading
Loading
Loading
Loading
+222 −57
Original line number Diff line number Diff line
@@ -37,6 +37,8 @@
#include <linux/thermal.h>
#include <linux/video_output.h>
#include <linux/sort.h>
#include <linux/pci.h>
#include <linux/pci_ids.h>
#include <asm/uaccess.h>

#include <acpi/acpi_bus.h>
@@ -162,16 +164,26 @@ 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 */
	u8 _DSS:1;		/*Device state set */
};

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 {
	int curr;
	int count;
	int *levels;
	struct acpi_video_brightness_flags flags;
};

struct acpi_video_device {
@@ -294,7 +306,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 +320,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
@@ -323,9 +337,9 @@ static int acpi_video_set_brightness(struct backlight_device *bd)
	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,

	return acpi_video_device_lcd_set_level(vd,
				vd->brightness->levels[request_level]);
	return 0;
}

static struct backlight_ops acpi_backlight_ops = {
@@ -376,7 +390,8 @@ static int video_get_cur_state(struct thermal_cooling_device *cdev, unsigned
	unsigned long long level;
	int offset;

	acpi_video_device_lcd_get_level_current(video, &level);
	if (acpi_video_device_lcd_get_level_current(video, &level))
		return -EINVAL;
	for (offset = 2; offset < video->brightness->count; offset++)
		if (level == video->brightness->levels[offset]) {
			*state = video->brightness->count - offset - 1;
@@ -483,34 +498,68 @@ 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);
	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]) {
			if (device->backlight)
				device->backlight->props.brightness = state - 2;
			return 0;
		}

	return status;
	ACPI_ERROR((AE_INFO, "Current brightness invalid"));
	return -EINVAL;
}

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 || 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) {
				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 {
			/* 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 %s failed", buf));
			device->cap._BQC = device->cap._BCQ = 0;
		}
	}

	*level = device->brightness->curr;
	return AE_OK;
	return 0;
}

static int
@@ -659,9 +708,11 @@ 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;
	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 "
@@ -675,13 +726,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 * sizeof *(br->levels),
	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];
@@ -696,18 +750,86 @@ 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"));

	/* 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);

	if (count < 2)
		goto out_free_levels;
	} else if (max_level != br->levels[count - 1])
		ACPI_ERROR((AE_INFO,
			    "Found unordered _BCL package\n"));

	br->count = count;
	device->brightness = br;
	ACPI_DEBUG_PRINT((ACPI_DB_INFO, "found %d brightness levels\n", count));

	/* 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);
@@ -716,7 +838,7 @@ acpi_video_init_brightness(struct acpi_video_device *device)
out:
	device->brightness = NULL;
	kfree(obj);
	return 0;
	return result;
}

/*
@@ -733,7 +855,6 @@ acpi_video_init_brightness(struct acpi_video_device *device)
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));
@@ -749,6 +870,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;
	}
@@ -762,13 +889,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;
@@ -777,18 +905,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",
@@ -1065,13 +1181,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)
@@ -1753,15 +1868,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);

	result = 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
@@ -2128,7 +2257,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;

@@ -2145,6 +2294,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)
{
+3 −0
Original line number Diff line number Diff line
@@ -55,6 +55,9 @@ acpi_backlight_cap_match(acpi_handle handle, u32 level, void *context,
		ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Found generic backlight "
				  "support\n"));
		*cap |= ACPI_VIDEO_BACKLIGHT;
		if (ACPI_FAILURE(acpi_get_handle(handle, "_BQC", &h_dummy)))
			printk(KERN_WARNING FW_BUG PREFIX "ACPI brightness "
					"control misses _BQC function\n");
		/* We have backlight support, no need to scan further */
		return AE_CTRL_TERMINATE;
	}
+3 −2
Original line number Diff line number Diff line
@@ -1144,8 +1144,6 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags)
	if (!IS_I945G(dev) && !IS_I945GM(dev))
		pci_enable_msi(dev->pdev);

	intel_opregion_init(dev);

	spin_lock_init(&dev_priv->user_irq_lock);
	dev_priv->user_irq_refcount = 0;

@@ -1164,6 +1162,9 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags)
		}
	}

	/* Must be done after probing outputs */
	intel_opregion_init(dev, 0);

	return 0;

out_iomapfree:
+1 −1
Original line number Diff line number Diff line
@@ -99,7 +99,7 @@ static int i915_resume(struct drm_device *dev)

	i915_restore_state(dev);

	intel_opregion_init(dev);
	intel_opregion_init(dev, 1);

	/* KMS EnterVT equivalent */
	if (drm_core_check_feature(dev, DRIVER_MODESET)) {
+2 −2
Original line number Diff line number Diff line
@@ -659,12 +659,12 @@ extern int i915_restore_state(struct drm_device *dev);

#ifdef CONFIG_ACPI
/* i915_opregion.c */
extern int intel_opregion_init(struct drm_device *dev);
extern int intel_opregion_init(struct drm_device *dev, int resume);
extern void intel_opregion_free(struct drm_device *dev);
extern void opregion_asle_intr(struct drm_device *dev);
extern void opregion_enable_asle(struct drm_device *dev);
#else
static inline int intel_opregion_init(struct drm_device *dev) { return 0; }
static inline int intel_opregion_init(struct drm_device *dev, int resume) { return 0; }
static inline void intel_opregion_free(struct drm_device *dev) { return; }
static inline void opregion_asle_intr(struct drm_device *dev) { return; }
static inline void opregion_enable_asle(struct drm_device *dev) { return; }
Loading