[GFS2] Fix up merge of Linus' kernel into GFS2
[pandora-kernel.git] / arch / powerpc / platforms / powermac / backlight.c
index 69f65e2..afa593a 100644 (file)
 #include <linux/kernel.h>
 #include <linux/fb.h>
 #include <linux/backlight.h>
+#include <linux/adb.h>
+#include <linux/pmu.h>
+#include <asm/atomic.h>
 #include <asm/prom.h>
 #include <asm/backlight.h>
 
 #define OLD_BACKLIGHT_MAX 15
 
+static void pmac_backlight_key_worker(void *data);
+static void pmac_backlight_set_legacy_worker(void *data);
+
+static DECLARE_WORK(pmac_backlight_key_work, pmac_backlight_key_worker, NULL);
+static DECLARE_WORK(pmac_backlight_set_legacy_work, pmac_backlight_set_legacy_worker, NULL);
+
+/* Although these variables are used in interrupt context, it makes no sense to
+ * protect them. No user is able to produce enough key events per second and
+ * notice the errors that might happen.
+ */
+static int pmac_backlight_key_queued;
+static int pmac_backlight_set_legacy_queued;
+
+/* The via-pmu code allows the backlight to be grabbed, in which case the
+ * in-kernel control of the brightness needs to be disabled. This should
+ * only be used by really old PowerBooks.
+ */
+static atomic_t kernel_backlight_disabled = ATOMIC_INIT(0);
+
 /* Protect the pmac_backlight variable */
 DEFINE_MUTEX(pmac_backlight_mutex);
 
@@ -38,7 +60,8 @@ int pmac_has_backlight_type(const char *type)
        struct device_node* bk_node = find_devices("backlight");
 
        if (bk_node) {
-               char *prop = get_property(bk_node, "backlight-control", NULL);
+               const char *prop = get_property(bk_node,
+                               "backlight-control", NULL);
                if (prop && strncmp(prop, type, strlen(type)) == 0)
                        return 1;
        }
@@ -71,8 +94,11 @@ int pmac_backlight_curve_lookup(struct fb_info *info, int value)
        return level;
 }
 
-static void pmac_backlight_key(int direction)
+static void pmac_backlight_key_worker(void *data)
 {
+       if (atomic_read(&kernel_backlight_disabled))
+               return;
+
        mutex_lock(&pmac_backlight_mutex);
        if (pmac_backlight) {
                struct backlight_properties *props;
@@ -82,7 +108,8 @@ static void pmac_backlight_key(int direction)
                props = pmac_backlight->props;
 
                brightness = props->brightness +
-                       ((direction?-1:1) * (props->max_brightness / 15));
+                       ((pmac_backlight_key_queued?-1:1) *
+                        (props->max_brightness / 15));
 
                if (brightness < 0)
                        brightness = 0;
@@ -97,17 +124,20 @@ static void pmac_backlight_key(int direction)
        mutex_unlock(&pmac_backlight_mutex);
 }
 
-void pmac_backlight_key_up()
+/* This function is called in interrupt context */
+void pmac_backlight_key(int direction)
 {
-       pmac_backlight_key(0);
+       if (atomic_read(&kernel_backlight_disabled))
+               return;
+
+       /* we can receive multiple interrupts here, but the scheduled work
+        * will run only once, with the last value
+        */
+       pmac_backlight_key_queued = direction;
+       schedule_work(&pmac_backlight_key_work);
 }
 
-void pmac_backlight_key_down()
-{
-       pmac_backlight_key(1);
-}
-
-int pmac_backlight_set_legacy_brightness(int brightness)
+static int __pmac_backlight_set_legacy_brightness(int brightness)
 {
        int error = -ENXIO;
 
@@ -136,6 +166,28 @@ int pmac_backlight_set_legacy_brightness(int brightness)
        return error;
 }
 
+static void pmac_backlight_set_legacy_worker(void *data)
+{
+       if (atomic_read(&kernel_backlight_disabled))
+               return;
+
+       __pmac_backlight_set_legacy_brightness(pmac_backlight_set_legacy_queued);
+}
+
+/* This function is called in interrupt context */
+void pmac_backlight_set_legacy_brightness_pmu(int brightness) {
+       if (atomic_read(&kernel_backlight_disabled))
+               return;
+
+       pmac_backlight_set_legacy_queued = brightness;
+       schedule_work(&pmac_backlight_set_legacy_work);
+}
+
+int pmac_backlight_set_legacy_brightness(int brightness)
+{
+       return __pmac_backlight_set_legacy_brightness(brightness);
+}
+
 int pmac_backlight_get_legacy_brightness()
 {
        int result = -ENXIO;
@@ -157,3 +209,17 @@ int pmac_backlight_get_legacy_brightness()
 
        return result;
 }
+
+void pmac_backlight_disable()
+{
+       atomic_inc(&kernel_backlight_disabled);
+}
+
+void pmac_backlight_enable()
+{
+       atomic_dec(&kernel_backlight_disabled);
+}
+
+EXPORT_SYMBOL_GPL(pmac_backlight);
+EXPORT_SYMBOL_GPL(pmac_backlight_mutex);
+EXPORT_SYMBOL_GPL(pmac_has_backlight_type);