aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRafael J. Wysocki <rafael.j.wysocki@intel.com>2014-06-03 17:12:37 -0400
committerRafael J. Wysocki <rafael.j.wysocki@intel.com>2014-06-03 17:12:37 -0400
commitd9bd44933cb21faf2cfe09798c1a2c95563a0bcb (patch)
treef16d3375cd246e2740651ffcf6cd8dbc30f2e0b4
parent0e36d43c9c87554cdb18aa865eec9edccda17324 (diff)
parent0dc6b96ac20c538a28bd8442ae74b87fc6b6f6e0 (diff)
Merge branch 'acpi-video'
* acpi-video: ACPI / video: Add 4 new models to the use_native_backlight DMI list ACPI / video: Add use native backlight quirk for the ThinkPad W530 ACPI / video: Unregister the backlight device if a raw one shows up later backlight: Add backlight device (un)registration notification nouveau: Don't check acpi_video_backlight_support() before registering backlight acer-wmi: Add Aspire 5741 to video_vendor_dmi_table acer-wmi: Switch to acpi_video_unregister_backlight ACPI / video: Add an acpi_video_unregister_backlight function ACPI / video: Don't register acpi_video_resume notifier without backlight devices ACPI / video: change acpi-video brightness_switch_enabled default to 0
-rw-r--r--Documentation/kernel-parameters.txt2
-rw-r--r--drivers/acpi/video.c252
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_backlight.c9
-rw-r--r--drivers/platform/x86/acer-wmi.c10
-rw-r--r--drivers/video/backlight/backlight.c40
-rw-r--r--include/acpi/video.h2
-rw-r--r--include/linux/backlight.h7
7 files changed, 245 insertions, 77 deletions
diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt
index c6e72ee53903..0933ec4924d3 100644
--- a/Documentation/kernel-parameters.txt
+++ b/Documentation/kernel-parameters.txt
@@ -3481,7 +3481,7 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
3481 the allocated input device; If set to 0, video driver 3481 the allocated input device; If set to 0, video driver
3482 will only send out the event without touching backlight 3482 will only send out the event without touching backlight
3483 brightness level. 3483 brightness level.
3484 default: 1 3484 default: 0
3485 3485
3486 virtio_mmio.device= 3486 virtio_mmio.device=
3487 [VMMIO] Memory mapped virtio (platform) device. 3487 [VMMIO] Memory mapped virtio (platform) device.
diff --git a/drivers/acpi/video.c b/drivers/acpi/video.c
index f8bc5a755dda..101fb090dcb9 100644
--- a/drivers/acpi/video.c
+++ b/drivers/acpi/video.c
@@ -68,7 +68,7 @@ MODULE_AUTHOR("Bruno Ducrot");
68MODULE_DESCRIPTION("ACPI Video Driver"); 68MODULE_DESCRIPTION("ACPI Video Driver");
69MODULE_LICENSE("GPL"); 69MODULE_LICENSE("GPL");
70 70
71static bool brightness_switch_enabled = 1; 71static bool brightness_switch_enabled;
72module_param(brightness_switch_enabled, bool, 0644); 72module_param(brightness_switch_enabled, bool, 0644);
73 73
74/* 74/*
@@ -150,6 +150,8 @@ struct acpi_video_enumerated_device {
150 150
151struct acpi_video_bus { 151struct acpi_video_bus {
152 struct acpi_device *device; 152 struct acpi_device *device;
153 bool backlight_registered;
154 bool backlight_notifier_registered;
153 u8 dos_setting; 155 u8 dos_setting;
154 struct acpi_video_enumerated_device *attached_array; 156 struct acpi_video_enumerated_device *attached_array;
155 u8 attached_count; 157 u8 attached_count;
@@ -161,6 +163,7 @@ struct acpi_video_bus {
161 struct input_dev *input; 163 struct input_dev *input;
162 char phys[32]; /* for input device */ 164 char phys[32]; /* for input device */
163 struct notifier_block pm_nb; 165 struct notifier_block pm_nb;
166 struct notifier_block backlight_nb;
164}; 167};
165 168
166struct acpi_video_device_flags { 169struct acpi_video_device_flags {
@@ -473,6 +476,14 @@ static struct dmi_system_id video_dmi_table[] __initdata = {
473 }, 476 },
474 { 477 {
475 .callback = video_set_use_native_backlight, 478 .callback = video_set_use_native_backlight,
479 .ident = "ThinkPad W530",
480 .matches = {
481 DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
482 DMI_MATCH(DMI_PRODUCT_VERSION, "ThinkPad W530"),
483 },
484 },
485 {
486 .callback = video_set_use_native_backlight,
476 .ident = "ThinkPad X1 Carbon", 487 .ident = "ThinkPad X1 Carbon",
477 .matches = { 488 .matches = {
478 DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"), 489 DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
@@ -488,6 +499,14 @@ static struct dmi_system_id video_dmi_table[] __initdata = {
488 }, 499 },
489 }, 500 },
490 { 501 {
502 .callback = video_set_use_native_backlight,
503 .ident = "Lenovo Yoga 2 11",
504 .matches = {
505 DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
506 DMI_MATCH(DMI_PRODUCT_VERSION, "Lenovo Yoga 2 11"),
507 },
508 },
509 {
491 .callback = video_set_use_native_backlight, 510 .callback = video_set_use_native_backlight,
492 .ident = "Thinkpad Helix", 511 .ident = "Thinkpad Helix",
493 .matches = { 512 .matches = {
@@ -521,6 +540,14 @@ static struct dmi_system_id video_dmi_table[] __initdata = {
521 }, 540 },
522 { 541 {
523 .callback = video_set_use_native_backlight, 542 .callback = video_set_use_native_backlight,
543 .ident = "Acer Aspire V5-171",
544 .matches = {
545 DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
546 DMI_MATCH(DMI_PRODUCT_NAME, "V5-171"),
547 },
548 },
549 {
550 .callback = video_set_use_native_backlight,
524 .ident = "Acer Aspire V5-431", 551 .ident = "Acer Aspire V5-431",
525 .matches = { 552 .matches = {
526 DMI_MATCH(DMI_SYS_VENDOR, "Acer"), 553 DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
@@ -528,6 +555,14 @@ static struct dmi_system_id video_dmi_table[] __initdata = {
528 }, 555 },
529 }, 556 },
530 { 557 {
558 .callback = video_set_use_native_backlight,
559 .ident = "Acer Aspire V5-471G",
560 .matches = {
561 DMI_MATCH(DMI_BOARD_VENDOR, "Acer"),
562 DMI_MATCH(DMI_PRODUCT_NAME, "Aspire V5-471G"),
563 },
564 },
565 {
531 .callback = video_set_use_native_backlight, 566 .callback = video_set_use_native_backlight,
532 .ident = "HP ProBook 4340s", 567 .ident = "HP ProBook 4340s",
533 .matches = { 568 .matches = {
@@ -579,6 +614,14 @@ static struct dmi_system_id video_dmi_table[] __initdata = {
579 }, 614 },
580 { 615 {
581 .callback = video_set_use_native_backlight, 616 .callback = video_set_use_native_backlight,
617 .ident = "HP EliteBook 8470p",
618 .matches = {
619 DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"),
620 DMI_MATCH(DMI_PRODUCT_NAME, "HP EliteBook 8470p"),
621 },
622 },
623 {
624 .callback = video_set_use_native_backlight,
582 .ident = "HP EliteBook 8780w", 625 .ident = "HP EliteBook 8780w",
583 .matches = { 626 .matches = {
584 DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"), 627 DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"),
@@ -1658,88 +1701,92 @@ acpi_video_bus_match(acpi_handle handle, u32 level, void *context,
1658 1701
1659static void acpi_video_dev_register_backlight(struct acpi_video_device *device) 1702static void acpi_video_dev_register_backlight(struct acpi_video_device *device)
1660{ 1703{
1661 if (acpi_video_verify_backlight_support()) { 1704 struct backlight_properties props;
1662 struct backlight_properties props; 1705 struct pci_dev *pdev;
1663 struct pci_dev *pdev; 1706 acpi_handle acpi_parent;
1664 acpi_handle acpi_parent; 1707 struct device *parent = NULL;
1665 struct device *parent = NULL; 1708 int result;
1666 int result; 1709 static int count;
1667 static int count; 1710 char *name;
1668 char *name;
1669
1670 result = acpi_video_init_brightness(device);
1671 if (result)
1672 return;
1673 name = kasprintf(GFP_KERNEL, "acpi_video%d", count);
1674 if (!name)
1675 return;
1676 count++;
1677 1711
1678 acpi_get_parent(device->dev->handle, &acpi_parent); 1712 result = acpi_video_init_brightness(device);
1713 if (result)
1714 return;
1715 name = kasprintf(GFP_KERNEL, "acpi_video%d", count);
1716 if (!name)
1717 return;
1718 count++;
1679 1719
1680 pdev = acpi_get_pci_dev(acpi_parent); 1720 acpi_get_parent(device->dev->handle, &acpi_parent);
1681 if (pdev) {
1682 parent = &pdev->dev;
1683 pci_dev_put(pdev);
1684 }
1685 1721
1686 memset(&props, 0, sizeof(struct backlight_properties)); 1722 pdev = acpi_get_pci_dev(acpi_parent);
1687 props.type = BACKLIGHT_FIRMWARE; 1723 if (pdev) {
1688 props.max_brightness = device->brightness->count - 3; 1724 parent = &pdev->dev;
1689 device->backlight = backlight_device_register(name, 1725 pci_dev_put(pdev);
1690 parent, 1726 }
1691 device,
1692 &acpi_backlight_ops,
1693 &props);
1694 kfree(name);
1695 if (IS_ERR(device->backlight))
1696 return;
1697 1727
1698 /* 1728 memset(&props, 0, sizeof(struct backlight_properties));
1699 * Save current brightness level in case we have to restore it 1729 props.type = BACKLIGHT_FIRMWARE;
1700 * before acpi_video_device_lcd_set_level() is called next time. 1730 props.max_brightness = device->brightness->count - 3;
1701 */ 1731 device->backlight = backlight_device_register(name,
1702 device->backlight->props.brightness = 1732 parent,
1703 acpi_video_get_brightness(device->backlight); 1733 device,
1734 &acpi_backlight_ops,
1735 &props);
1736 kfree(name);
1737 if (IS_ERR(device->backlight))
1738 return;
1704 1739
1705 device->cooling_dev = thermal_cooling_device_register("LCD", 1740 /*
1706 device->dev, &video_cooling_ops); 1741 * Save current brightness level in case we have to restore it
1707 if (IS_ERR(device->cooling_dev)) { 1742 * before acpi_video_device_lcd_set_level() is called next time.
1708 /* 1743 */
1709 * Set cooling_dev to NULL so we don't crash trying to 1744 device->backlight->props.brightness =
1710 * free it. 1745 acpi_video_get_brightness(device->backlight);
1711 * Also, why the hell we are returning early and
1712 * not attempt to register video output if cooling
1713 * device registration failed?
1714 * -- dtor
1715 */
1716 device->cooling_dev = NULL;
1717 return;
1718 }
1719 1746
1720 dev_info(&device->dev->dev, "registered as cooling_device%d\n", 1747 device->cooling_dev = thermal_cooling_device_register("LCD",
1721 device->cooling_dev->id); 1748 device->dev, &video_cooling_ops);
1722 result = sysfs_create_link(&device->dev->dev.kobj, 1749 if (IS_ERR(device->cooling_dev)) {
1723 &device->cooling_dev->device.kobj, 1750 /*
1724 "thermal_cooling"); 1751 * Set cooling_dev to NULL so we don't crash trying to free it.
1725 if (result) 1752 * Also, why the hell we are returning early and not attempt to
1726 printk(KERN_ERR PREFIX "Create sysfs link\n"); 1753 * register video output if cooling device registration failed?
1727 result = sysfs_create_link(&device->cooling_dev->device.kobj, 1754 * -- dtor
1728 &device->dev->dev.kobj, "device"); 1755 */
1729 if (result) 1756 device->cooling_dev = NULL;
1730 printk(KERN_ERR PREFIX "Create sysfs link\n"); 1757 return;
1731 } 1758 }
1759
1760 dev_info(&device->dev->dev, "registered as cooling_device%d\n",
1761 device->cooling_dev->id);
1762 result = sysfs_create_link(&device->dev->dev.kobj,
1763 &device->cooling_dev->device.kobj,
1764 "thermal_cooling");
1765 if (result)
1766 printk(KERN_ERR PREFIX "Create sysfs link\n");
1767 result = sysfs_create_link(&device->cooling_dev->device.kobj,
1768 &device->dev->dev.kobj, "device");
1769 if (result)
1770 printk(KERN_ERR PREFIX "Create sysfs link\n");
1732} 1771}
1733 1772
1734static int acpi_video_bus_register_backlight(struct acpi_video_bus *video) 1773static int acpi_video_bus_register_backlight(struct acpi_video_bus *video)
1735{ 1774{
1736 struct acpi_video_device *dev; 1775 struct acpi_video_device *dev;
1737 1776
1777 if (video->backlight_registered)
1778 return 0;
1779
1780 if (!acpi_video_verify_backlight_support())
1781 return 0;
1782
1738 mutex_lock(&video->device_list_lock); 1783 mutex_lock(&video->device_list_lock);
1739 list_for_each_entry(dev, &video->video_device_list, entry) 1784 list_for_each_entry(dev, &video->video_device_list, entry)
1740 acpi_video_dev_register_backlight(dev); 1785 acpi_video_dev_register_backlight(dev);
1741 mutex_unlock(&video->device_list_lock); 1786 mutex_unlock(&video->device_list_lock);
1742 1787
1788 video->backlight_registered = true;
1789
1743 video->pm_nb.notifier_call = acpi_video_resume; 1790 video->pm_nb.notifier_call = acpi_video_resume;
1744 video->pm_nb.priority = 0; 1791 video->pm_nb.priority = 0;
1745 return register_pm_notifier(&video->pm_nb); 1792 return register_pm_notifier(&video->pm_nb);
@@ -1767,13 +1814,20 @@ static void acpi_video_dev_unregister_backlight(struct acpi_video_device *device
1767static int acpi_video_bus_unregister_backlight(struct acpi_video_bus *video) 1814static int acpi_video_bus_unregister_backlight(struct acpi_video_bus *video)
1768{ 1815{
1769 struct acpi_video_device *dev; 1816 struct acpi_video_device *dev;
1770 int error = unregister_pm_notifier(&video->pm_nb); 1817 int error;
1818
1819 if (!video->backlight_registered)
1820 return 0;
1821
1822 error = unregister_pm_notifier(&video->pm_nb);
1771 1823
1772 mutex_lock(&video->device_list_lock); 1824 mutex_lock(&video->device_list_lock);
1773 list_for_each_entry(dev, &video->video_device_list, entry) 1825 list_for_each_entry(dev, &video->video_device_list, entry)
1774 acpi_video_dev_unregister_backlight(dev); 1826 acpi_video_dev_unregister_backlight(dev);
1775 mutex_unlock(&video->device_list_lock); 1827 mutex_unlock(&video->device_list_lock);
1776 1828
1829 video->backlight_registered = false;
1830
1777 return error; 1831 return error;
1778} 1832}
1779 1833
@@ -1867,6 +1921,56 @@ static void acpi_video_bus_remove_notify_handler(struct acpi_video_bus *video)
1867 video->input = NULL; 1921 video->input = NULL;
1868} 1922}
1869 1923
1924static int acpi_video_backlight_notify(struct notifier_block *nb,
1925 unsigned long val, void *bd)
1926{
1927 struct backlight_device *backlight = bd;
1928 struct acpi_video_bus *video;
1929
1930 /* acpi_video_verify_backlight_support only cares about raw devices */
1931 if (backlight->props.type != BACKLIGHT_RAW)
1932 return NOTIFY_DONE;
1933
1934 video = container_of(nb, struct acpi_video_bus, backlight_nb);
1935
1936 switch (val) {
1937 case BACKLIGHT_REGISTERED:
1938 if (!acpi_video_verify_backlight_support())
1939 acpi_video_bus_unregister_backlight(video);
1940 break;
1941 case BACKLIGHT_UNREGISTERED:
1942 acpi_video_bus_register_backlight(video);
1943 break;
1944 }
1945
1946 return NOTIFY_OK;
1947}
1948
1949static int acpi_video_bus_add_backlight_notify_handler(
1950 struct acpi_video_bus *video)
1951{
1952 int error;
1953
1954 video->backlight_nb.notifier_call = acpi_video_backlight_notify;
1955 video->backlight_nb.priority = 0;
1956 error = backlight_register_notifier(&video->backlight_nb);
1957 if (error == 0)
1958 video->backlight_notifier_registered = true;
1959
1960 return error;
1961}
1962
1963static int acpi_video_bus_remove_backlight_notify_handler(
1964 struct acpi_video_bus *video)
1965{
1966 if (!video->backlight_notifier_registered)
1967 return 0;
1968
1969 video->backlight_notifier_registered = false;
1970
1971 return backlight_unregister_notifier(&video->backlight_nb);
1972}
1973
1870static int acpi_video_bus_put_devices(struct acpi_video_bus *video) 1974static int acpi_video_bus_put_devices(struct acpi_video_bus *video)
1871{ 1975{
1872 struct acpi_video_device *dev, *next; 1976 struct acpi_video_device *dev, *next;
@@ -1948,6 +2052,7 @@ static int acpi_video_bus_add(struct acpi_device *device)
1948 2052
1949 acpi_video_bus_register_backlight(video); 2053 acpi_video_bus_register_backlight(video);
1950 acpi_video_bus_add_notify_handler(video); 2054 acpi_video_bus_add_notify_handler(video);
2055 acpi_video_bus_add_backlight_notify_handler(video);
1951 2056
1952 return 0; 2057 return 0;
1953 2058
@@ -1971,6 +2076,7 @@ static int acpi_video_bus_remove(struct acpi_device *device)
1971 2076
1972 video = acpi_driver_data(device); 2077 video = acpi_driver_data(device);
1973 2078
2079 acpi_video_bus_remove_backlight_notify_handler(video);
1974 acpi_video_bus_remove_notify_handler(video); 2080 acpi_video_bus_remove_notify_handler(video);
1975 acpi_video_bus_unregister_backlight(video); 2081 acpi_video_bus_unregister_backlight(video);
1976 acpi_video_bus_put_devices(video); 2082 acpi_video_bus_put_devices(video);
@@ -2061,6 +2167,20 @@ void acpi_video_unregister(void)
2061} 2167}
2062EXPORT_SYMBOL(acpi_video_unregister); 2168EXPORT_SYMBOL(acpi_video_unregister);
2063 2169
2170void acpi_video_unregister_backlight(void)
2171{
2172 struct acpi_video_bus *video;
2173
2174 if (!register_count)
2175 return;
2176
2177 mutex_lock(&video_list_lock);
2178 list_for_each_entry(video, &video_bus_head, entry)
2179 acpi_video_bus_unregister_backlight(video);
2180 mutex_unlock(&video_list_lock);
2181}
2182EXPORT_SYMBOL(acpi_video_unregister_backlight);
2183
2064/* 2184/*
2065 * This is kind of nasty. Hardware using Intel chipsets may require 2185 * This is kind of nasty. Hardware using Intel chipsets may require
2066 * the video opregion code to be run first in order to initialise 2186 * the video opregion code to be run first in order to initialise
diff --git a/drivers/gpu/drm/nouveau/nouveau_backlight.c b/drivers/gpu/drm/nouveau/nouveau_backlight.c
index 630f6e84fc01..2c1e4aad7da3 100644
--- a/drivers/gpu/drm/nouveau/nouveau_backlight.c
+++ b/drivers/gpu/drm/nouveau/nouveau_backlight.c
@@ -31,7 +31,6 @@
31 */ 31 */
32 32
33#include <linux/backlight.h> 33#include <linux/backlight.h>
34#include <linux/acpi.h>
35 34
36#include "nouveau_drm.h" 35#include "nouveau_drm.h"
37#include "nouveau_reg.h" 36#include "nouveau_reg.h"
@@ -222,14 +221,6 @@ nouveau_backlight_init(struct drm_device *dev)
222 struct nouveau_device *device = nv_device(drm->device); 221 struct nouveau_device *device = nv_device(drm->device);
223 struct drm_connector *connector; 222 struct drm_connector *connector;
224 223
225#ifdef CONFIG_ACPI
226 if (acpi_video_backlight_support()) {
227 NV_INFO(drm, "ACPI backlight interface available, "
228 "not registering our own\n");
229 return 0;
230 }
231#endif
232
233 list_for_each_entry(connector, &dev->mode_config.connector_list, head) { 224 list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
234 if (connector->connector_type != DRM_MODE_CONNECTOR_LVDS && 225 if (connector->connector_type != DRM_MODE_CONNECTOR_LVDS &&
235 connector->connector_type != DRM_MODE_CONNECTOR_eDP) 226 connector->connector_type != DRM_MODE_CONNECTOR_eDP)
diff --git a/drivers/platform/x86/acer-wmi.c b/drivers/platform/x86/acer-wmi.c
index c91f69b39db4..bbf78b2d6d93 100644
--- a/drivers/platform/x86/acer-wmi.c
+++ b/drivers/platform/x86/acer-wmi.c
@@ -570,6 +570,14 @@ static const struct dmi_system_id video_vendor_dmi_table[] = {
570 DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5750"), 570 DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5750"),
571 }, 571 },
572 }, 572 },
573 {
574 .callback = video_set_backlight_video_vendor,
575 .ident = "Acer Aspire 5741",
576 .matches = {
577 DMI_MATCH(DMI_BOARD_VENDOR, "Acer"),
578 DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5741"),
579 },
580 },
573 {} 581 {}
574}; 582};
575 583
@@ -2228,7 +2236,7 @@ static int __init acer_wmi_init(void)
2228 pr_info("Brightness must be controlled by acpi video driver\n"); 2236 pr_info("Brightness must be controlled by acpi video driver\n");
2229 } else { 2237 } else {
2230 pr_info("Disabling ACPI video driver\n"); 2238 pr_info("Disabling ACPI video driver\n");
2231 acpi_video_unregister(); 2239 acpi_video_unregister_backlight();
2232 } 2240 }
2233 2241
2234 if (wmi_has_guid(WMID_GUID3)) { 2242 if (wmi_has_guid(WMID_GUID3)) {
diff --git a/drivers/video/backlight/backlight.c b/drivers/video/backlight/backlight.c
index bd2172c2d650..428089009cd5 100644
--- a/drivers/video/backlight/backlight.c
+++ b/drivers/video/backlight/backlight.c
@@ -23,6 +23,7 @@
23 23
24static struct list_head backlight_dev_list; 24static struct list_head backlight_dev_list;
25static struct mutex backlight_dev_list_mutex; 25static struct mutex backlight_dev_list_mutex;
26static struct blocking_notifier_head backlight_notifier;
26 27
27static const char *const backlight_types[] = { 28static const char *const backlight_types[] = {
28 [BACKLIGHT_RAW] = "raw", 29 [BACKLIGHT_RAW] = "raw",
@@ -370,6 +371,9 @@ struct backlight_device *backlight_device_register(const char *name,
370 list_add(&new_bd->entry, &backlight_dev_list); 371 list_add(&new_bd->entry, &backlight_dev_list);
371 mutex_unlock(&backlight_dev_list_mutex); 372 mutex_unlock(&backlight_dev_list_mutex);
372 373
374 blocking_notifier_call_chain(&backlight_notifier,
375 BACKLIGHT_REGISTERED, new_bd);
376
373 return new_bd; 377 return new_bd;
374} 378}
375EXPORT_SYMBOL(backlight_device_register); 379EXPORT_SYMBOL(backlight_device_register);
@@ -413,6 +417,10 @@ void backlight_device_unregister(struct backlight_device *bd)
413 pmac_backlight = NULL; 417 pmac_backlight = NULL;
414 mutex_unlock(&pmac_backlight_mutex); 418 mutex_unlock(&pmac_backlight_mutex);
415#endif 419#endif
420
421 blocking_notifier_call_chain(&backlight_notifier,
422 BACKLIGHT_UNREGISTERED, bd);
423
416 mutex_lock(&bd->ops_lock); 424 mutex_lock(&bd->ops_lock);
417 bd->ops = NULL; 425 bd->ops = NULL;
418 mutex_unlock(&bd->ops_lock); 426 mutex_unlock(&bd->ops_lock);
@@ -438,6 +446,36 @@ static int devm_backlight_device_match(struct device *dev, void *res,
438} 446}
439 447
440/** 448/**
449 * backlight_register_notifier - get notified of backlight (un)registration
450 * @nb: notifier block with the notifier to call on backlight (un)registration
451 *
452 * @return 0 on success, otherwise a negative error code
453 *
454 * Register a notifier to get notified when backlight devices get registered
455 * or unregistered.
456 */
457int backlight_register_notifier(struct notifier_block *nb)
458{
459 return blocking_notifier_chain_register(&backlight_notifier, nb);
460}
461EXPORT_SYMBOL(backlight_register_notifier);
462
463/**
464 * backlight_unregister_notifier - unregister a backlight notifier
465 * @nb: notifier block to unregister
466 *
467 * @return 0 on success, otherwise a negative error code
468 *
469 * Register a notifier to get notified when backlight devices get registered
470 * or unregistered.
471 */
472int backlight_unregister_notifier(struct notifier_block *nb)
473{
474 return blocking_notifier_chain_unregister(&backlight_notifier, nb);
475}
476EXPORT_SYMBOL(backlight_unregister_notifier);
477
478/**
441 * devm_backlight_device_register - resource managed backlight_device_register() 479 * devm_backlight_device_register - resource managed backlight_device_register()
442 * @dev: the device to register 480 * @dev: the device to register
443 * @name: the name of the device 481 * @name: the name of the device
@@ -544,6 +582,8 @@ static int __init backlight_class_init(void)
544 backlight_class->pm = &backlight_class_dev_pm_ops; 582 backlight_class->pm = &backlight_class_dev_pm_ops;
545 INIT_LIST_HEAD(&backlight_dev_list); 583 INIT_LIST_HEAD(&backlight_dev_list);
546 mutex_init(&backlight_dev_list_mutex); 584 mutex_init(&backlight_dev_list_mutex);
585 BLOCKING_INIT_NOTIFIER_HEAD(&backlight_notifier);
586
547 return 0; 587 return 0;
548} 588}
549 589
diff --git a/include/acpi/video.h b/include/acpi/video.h
index 61109f2609fc..ea4c7bbded4d 100644
--- a/include/acpi/video.h
+++ b/include/acpi/video.h
@@ -19,11 +19,13 @@ struct acpi_device;
19#if (defined CONFIG_ACPI_VIDEO || defined CONFIG_ACPI_VIDEO_MODULE) 19#if (defined CONFIG_ACPI_VIDEO || defined CONFIG_ACPI_VIDEO_MODULE)
20extern int acpi_video_register(void); 20extern int acpi_video_register(void);
21extern void acpi_video_unregister(void); 21extern void acpi_video_unregister(void);
22extern void acpi_video_unregister_backlight(void);
22extern int acpi_video_get_edid(struct acpi_device *device, int type, 23extern int acpi_video_get_edid(struct acpi_device *device, int type,
23 int device_id, void **edid); 24 int device_id, void **edid);
24#else 25#else
25static inline int acpi_video_register(void) { return 0; } 26static inline int acpi_video_register(void) { return 0; }
26static inline void acpi_video_unregister(void) { return; } 27static inline void acpi_video_unregister(void) { return; }
28static inline void acpi_video_unregister_backlight(void) { return; }
27static inline int acpi_video_get_edid(struct acpi_device *device, int type, 29static inline int acpi_video_get_edid(struct acpi_device *device, int type,
28 int device_id, void **edid) 30 int device_id, void **edid)
29{ 31{
diff --git a/include/linux/backlight.h b/include/linux/backlight.h
index 72647429adf6..adb14a8616df 100644
--- a/include/linux/backlight.h
+++ b/include/linux/backlight.h
@@ -40,6 +40,11 @@ enum backlight_type {
40 BACKLIGHT_TYPE_MAX, 40 BACKLIGHT_TYPE_MAX,
41}; 41};
42 42
43enum backlight_notification {
44 BACKLIGHT_REGISTERED,
45 BACKLIGHT_UNREGISTERED,
46};
47
43struct backlight_device; 48struct backlight_device;
44struct fb_info; 49struct fb_info;
45 50
@@ -133,6 +138,8 @@ extern void devm_backlight_device_unregister(struct device *dev,
133extern void backlight_force_update(struct backlight_device *bd, 138extern void backlight_force_update(struct backlight_device *bd,
134 enum backlight_update_reason reason); 139 enum backlight_update_reason reason);
135extern bool backlight_device_registered(enum backlight_type type); 140extern bool backlight_device_registered(enum backlight_type type);
141extern int backlight_register_notifier(struct notifier_block *nb);
142extern int backlight_unregister_notifier(struct notifier_block *nb);
136 143
137#define to_backlight_device(obj) container_of(obj, struct backlight_device, dev) 144#define to_backlight_device(obj) container_of(obj, struct backlight_device, dev)
138 145