Re: [PATCH] backlight dimmer

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Ok,
 now checkpatch.pl only complains about a missing signed-off-by.
Is this ok for review?

jacopo


--- linux-2.6.23.1/include/linux/backlight.h	2007-10-12 18:43:44.000000000 +0200
+++ b/include/linux/backlight.h	2007-10-28 21:14:21.000000000 +0100
@@ -11,6 +11,7 @@
#include <linux/device.h>
#include <linux/mutex.h>
#include <linux/notifier.h>
+#include <linux/timeout.h>

/* Notes on locking:
 *
@@ -70,6 +71,12 @@ struct backlight_device {
	/* The framebuffer notifier block */
	struct notifier_block fb_notif;

+  /* dimmer stuff */
+	struct timeout *timeout;
+	struct input_handler *input_handler;
+	unsigned short dimmer_low_level;
+	unsigned short dimmer_high_level;
+
	struct device dev;
};

--- linux-2.6.23.1/drivers/video/backlight/Makefile	2007-10-12 18:43:44.000000000 +0200
+++ b/drivers/video/backlight/Makefile	2007-10-28 16:42:09.000000000 +0100
@@ -1,7 +1,7 @@
# Backlight & LCD drivers

obj-$(CONFIG_LCD_CLASS_DEVICE)     += lcd.o
-obj-$(CONFIG_BACKLIGHT_CLASS_DEVICE) += backlight.o
+obj-$(CONFIG_BACKLIGHT_CLASS_DEVICE) += backlight.o timeout.o
obj-$(CONFIG_BACKLIGHT_CORGI)	+= corgi_bl.o
obj-$(CONFIG_BACKLIGHT_HP680)	+= hp680_bl.o
obj-$(CONFIG_BACKLIGHT_LOCOMO)	+= locomolcd.o
--- linux-2.6.23.1/include/linux/timeout.h	1970-01-01 01:00:00.000000000 +0100
+++ b/include/linux/timeout.h	2007-10-28 21:14:27.000000000 +0100
@@ -0,0 +1,68 @@
+/*
+ *  timeout.h - simple timeout
+ *
+ *
+ *  Copyright (C) 2007 Jacopo Antonello <[email protected]>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ *  02110-1301, USA.
+ */
+
+#ifndef _TIMEOUT_H_
+#define _TIMEOUT_H_
+
+#include <linux/workqueue.h>
+#include <linux/mutex.h>
+#include <linux/spinlock.h>
+
+enum timeout_state {
+	TIMEOUT_RUNNING,
+	TIMEOUT_TRIGGERED,
+	TIMEOUT_FINILIZED
+};
+
+struct timeout {
+	/* allow either start() or trigger() at a time */
+	struct mutex lock;
+	/* serialize updates to latest */
+	spinlock_t latest_lock;
+	struct delayed_work trigger_worker;
+	struct work_struct start_worker;
+	unsigned long latest;
+	enum timeout_state state;
+
+	unsigned long duration; /* client defined duration */
+	unsigned long data; /* client data */
+	void (*trigger)(unsigned long); /* client function */
+	void (*start)(unsigned long); /* client function */
+};
+
+extern void timeout_touch(struct timeout *timeout);
+
+extern void timeout_init(struct timeout *timeout);
+
+extern void timeout_kill(struct timeout *timeout);
+
+static inline int timeout_sec2jiffies(int secs)
+{
+	return secs * HZ;
+}
+
+static inline int timeout_jif2sec(unsigned long jif)
+{
+	return jif / HZ;
+}
+
+#endif
--- linux-2.6.23.1/drivers/video/backlight/timeout.c	1970-01-01 01:00:00.000000000 +0100
+++ b/drivers/video/backlight/timeout.c	2007-10-28 21:18:09.000000000 +0100
@@ -0,0 +1,135 @@
+/*
+ *  timeout.c - simple timeout
+ *
+ *
+ *  Copyright (C) 2007 Jacopo Antonello <[email protected]>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ *  02110-1301, USA.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/jiffies.h>
+#include <linux/timeout.h>
+
+
+/* atomic context helpers for timeout->latest */
+static inline unsigned long read_latest(struct timeout *timeout)
+{
+	unsigned long ret;
+	spin_lock(&timeout->latest_lock);
+	ret = timeout->latest;
+	spin_unlock(&timeout->latest_lock);
+	return ret;
+}
+
+static inline unsigned long elapsed(struct timeout *timeout)
+{
+	unsigned long elapsed;
+	spin_lock(&timeout->latest_lock);
+	elapsed = jiffies - timeout->latest;
+	spin_unlock(&timeout->latest_lock);
+	return elapsed;
+}
+
+static inline void touch_latest(struct timeout *timeout)
+{
+	spin_lock(&timeout->latest_lock);
+	timeout->latest = jiffies;
+	spin_unlock(&timeout->latest_lock);
+}
+
+/* non-atomic context */
+static void trigger_worker_function(struct work_struct *work)
+{
+	struct timeout *timeout = container_of(work, struct timeout,
+			trigger_worker.work);
+
+	mutex_lock(&timeout->lock);
+
+	/* flag to kill worker */
+	if (timeout->state != TIMEOUT_RUNNING)
+		goto exit;
+
+	if (elapsed(timeout) >= timeout->duration) {
+    pr_debug("tigger_worker_function() -> timeout->trigger()"
+				" (elapsed: %ld ms) \n",
+				(elapsed(timeout) * 1000 / (HZ)));
+		timeout->state = TIMEOUT_TRIGGERED;
+		timeout->trigger(timeout->data);
+	} else {
+		unsigned long new_delay = (read_latest(timeout) - jiffies) +
+			timeout->duration;
+		pr_debug("tigger_worker_function() -> schedule_delayed_work() "
+				"(new_delay: %ld jif %ld ms)\n",
+				new_delay, new_delay * 1000 / (HZ));
+		schedule_delayed_work(&timeout->trigger_worker, new_delay);
+	}
+
+exit:
+		mutex_unlock(&timeout->lock);
+}
+
+/* non-atomic context */
+static void start_worker_function(struct work_struct *work)
+{
+	struct timeout *timeout = container_of(work,
+			struct timeout, start_worker);
+
+	pr_debug("start_worker_function() -> timeout->start()\n");
+	timeout->start(timeout->data);
+	schedule_delayed_work(&timeout->trigger_worker, timeout->duration);
+}
+
+/* atomic context touch */
+void timeout_touch(struct timeout *timeout)
+{
+	touch_latest(timeout);
+
+	if (timeout->state == TIMEOUT_TRIGGERED &&
+			mutex_trylock(&timeout->lock)) {
+
+		if (timeout->state == TIMEOUT_TRIGGERED) {
+			timeout->state = TIMEOUT_RUNNING;
+			schedule_work(&timeout->start_worker);
+		}
+
+		mutex_unlock(&timeout->lock);
+	}
+}
+EXPORT_SYMBOL(timeout_touch);
+
+void timeout_init(struct timeout *timeout)
+{
+	mutex_init(&timeout->lock);
+	spin_lock_init(&timeout->latest_lock);
+	INIT_DELAYED_WORK(&timeout->trigger_worker, trigger_worker_function);
+	INIT_WORK(&timeout->start_worker, start_worker_function);
+	timeout->state = TIMEOUT_TRIGGERED;
+}
+EXPORT_SYMBOL(timeout_init);
+
+void timeout_kill(struct timeout *timeout)
+{
+	mutex_lock(&timeout->lock);
+	if (timeout->state == TIMEOUT_RUNNING)
+		cancel_delayed_work_sync(&timeout->trigger_worker);
+
+	flush_scheduled_work();
+	timeout->state = TIMEOUT_FINILIZED;
+	mutex_unlock(&timeout->lock);
+}
+EXPORT_SYMBOL(timeout_kill);
--- linux-2.6.23.1/drivers/video/backlight/backlight.c	2007-10-12 18:43:44.000000000 +0200
+++ b/drivers/video/backlight/backlight.c	2007-10-28 21:29:18.000000000 +0100
@@ -8,6 +8,7 @@
#include <linux/module.h>
#include <linux/init.h>
#include <linux/device.h>
+#include <linux/input.h>
#include <linux/backlight.h>
#include <linux/notifier.h>
#include <linux/ctype.h>
@@ -172,13 +173,282 @@ static void bl_device_release(struct dev
	kfree(bd);
}

+/*
+ * ---------------------------------------------------
+ *           backlight dimmer
+ * --------------------------------------------------
+ */
+
+static const struct input_device_id idi_dimmer[] = {
+	{
+		.flags = INPUT_DEVICE_ID_MATCH_EVBIT,
+		.evbit = { BIT(EV_KEY) },
+	}, /* key event */
+	{
+		.flags = INPUT_DEVICE_ID_MATCH_RELBIT,
+		.relbit = { BIT(REL_X) | BIT(REL_Y) | BIT(REL_WHEEL) },
+	},	/* rel axes */
+	{
+		.flags = INPUT_DEVICE_ID_MATCH_ABSBIT,
+		.absbit = { BIT(ABS_X) | BIT(ABS_Y) },
+	},	/* abs axes */
+	{ }
+};
+
+static void handler_event(struct input_handle *handle, unsigned int type,
+		unsigned int code, int value)
+{
+	struct backlight_device *dev =
+		(struct backlight_device *)handle->private;
+
+	switch (type) {
+	case EV_KEY:
+	case EV_REL:
+			timeout_touch(dev->timeout);
+	}
+}
+
+static void dimmer_start(unsigned long data)
+{
+	struct backlight_device *bd = (struct backlight_device *)data;
+
+	pr_debug("switch to high level\n");
+	bd->props.brightness = bd->dimmer_high_level;
+	backlight_update_status(bd);
+}
+
+static void dimmer_trigger(unsigned long data)
+{
+	struct backlight_device *bd = (struct backlight_device *)data;
+
+	pr_debug("switch to low level\n");
+	bd->props.brightness = bd->dimmer_low_level;
+	backlight_update_status(bd);
+}
+
+static int handler_connect(struct input_handler *handler, struct input_dev *dev,
+		const struct input_device_id *id)
+{
+	int error = 0;
+	struct input_handle *handle;
+
+
+	handle = kzalloc(sizeof(struct input_handle), GFP_KERNEL);
+	if (!handle)
+		return -ENOMEM;
+
+	handle->handler = handler;
+	handle->dev = dev;
+	handle->name = "backlight";
+	handle->private = handler->private;
+
+	error = input_register_handle(handle);
+	if (error)
+		goto err_free_handle;
+
+	error = input_open_device(handle);
+	if (error)
+		goto err_unregister_handle;
+
+	return 0;
+
+err_unregister_handle:
+		input_unregister_handle(handle);
+err_free_handle:
+		kfree(handle);
+	return error;
+}
+
+static void handler_disconnect(struct input_handle *handle)
+{
+	input_close_device(handle);
+	input_unregister_handle(handle);
+	kfree(handle);
+}
+
+static int enable_dimmer(struct backlight_device *dev)
+{
+	pr_debug("enable_dimmer()\n");
+	dev->input_handler = kzalloc(sizeof(struct input_handler), GFP_KERNEL);
+	if (!dev->input_handler)
+		return -ENOMEM;
+
+	if (!dev->dimmer_low_level)
+		dev->dimmer_low_level = dev->props.max_brightness/2;
+	if (!dev->dimmer_high_level)
+		dev->dimmer_high_level = dev->props.max_brightness;
+
+	dev->input_handler->event = handler_event;
+	dev->input_handler->connect = handler_connect;
+	dev->input_handler->disconnect = handler_disconnect;
+	dev->input_handler->name = "backlight";
+	dev->input_handler->id_table = idi_dimmer;
+	dev->input_handler->private = dev;
+
+	dev->timeout = kzalloc(sizeof(struct timeout), GFP_KERNEL);
+	if (!dev->timeout)
+		goto free_handler;
+
+	timeout_init(dev->timeout);
+	dev->timeout->duration = timeout_sec2jiffies(5);
+	dev->timeout->data = (unsigned long)dev;
+	dev->timeout->trigger = dimmer_trigger;
+	dev->timeout->start = dimmer_start;
+
+	if (!input_register_handler(dev->input_handler))
+		return 0; /* success */
+	/* else go on & cleanup */
+
+free_handler:
+		kfree(dev->input_handler);
+		dev->input_handler = NULL;
+		return -ENOMEM;
+}
+
+static void disable_dimmer(struct backlight_device *dev)
+{
+	if (!dev->input_handler)
+		return;
+
+	input_unregister_handler(dev->input_handler);
+	timeout_kill(dev->timeout);
+	kfree(dev->input_handler);
+	kfree(dev->timeout);
+	dev->input_handler = NULL;
+	dev->timeout = NULL;
+	pr_debug("disable_dimmer()\n");
+}
+
+/* show */
+static ssize_t show_dimmer_control(struct device *dev,
+		struct device_attribute *attr, char *buf)
+{
+	struct backlight_device *bd = to_backlight_device(dev);
+
+	return snprintf(buf, PAGE_SIZE, "%d\n",
+			(bd->input_handler != NULL));
+}
+
+static ssize_t show_dimmer_timeout(struct device *dev,
+		struct device_attribute *attr, char *buf)
+{
+	struct backlight_device *bd = to_backlight_device(dev);
+
+	if (bd->timeout)
+		return snprintf(buf, PAGE_SIZE, "%d\n",
+				timeout_jif2sec(bd->timeout->duration));
+	else
+		return 0;
+}
+
+static ssize_t show_dimmer_low_level(struct device *dev,
+		struct device_attribute *attr, char *buf)
+{
+	struct backlight_device *bd = to_backlight_device(dev);
+
+	return snprintf(buf, PAGE_SIZE, "%d\n",
+			bd->dimmer_low_level);
+}
+
+static ssize_t show_dimmer_high_level(struct device *dev,
+		struct device_attribute *attr, char *buf)
+{
+	struct backlight_device *bd = to_backlight_device(dev);
+
+	return snprintf(buf, PAGE_SIZE, "%d\n",
+			bd->dimmer_high_level);
+}
+
+/* store */
+static ssize_t store_dimmer_control(struct device *dev,
+		struct device_attribute *attr, const char *buf, size_t count)
+{
+	struct backlight_device *bd = to_backlight_device(dev);
+
+	char *endp;
+	int control = simple_strtoul(buf, &endp, 0);
+
+	mutex_lock(&bd->ops_lock);
+	if (control == 1 && !bd->input_handler)
+		enable_dimmer(bd);
+	else if (control == 0 && bd->input_handler)
+		disable_dimmer(bd);
+	mutex_unlock(&bd->ops_lock);
+
+	return count;
+}
+
+static ssize_t store_dimmer_timeout(struct device *dev,
+		struct device_attribute *attr, const char *buf, size_t count)
+{
+	struct backlight_device *bd = to_backlight_device(dev);
+
+	char *endp;
+	int timeout = simple_strtoul(buf, &endp, 0);
+
+	if (timeout <= 0 || timeout >= 60*30)
+		return -ENXIO;
+
+	mutex_lock(&bd->ops_lock);
+	if (!bd->timeout) {
+		mutex_unlock(&bd->ops_lock);
+		return -ENXIO;
+	}
+	bd->timeout->duration = timeout_sec2jiffies(timeout);
+	mutex_unlock(&bd->ops_lock);
+
+	return count;
+}
+
+static ssize_t store_dimmer_low_level(struct device *dev,
+		struct device_attribute *attr, const char *buf, size_t count)
+{
+	struct backlight_device *bd = to_backlight_device(dev);
+
+	char *endp;
+	int low = simple_strtoul(buf, &endp, 0);
+
+	if (low < 0 || low > bd->props.max_brightness)
+		return -ENXIO;
+
+	mutex_lock(&bd->ops_lock);
+	bd->dimmer_low_level = low;
+	mutex_unlock(&bd->ops_lock);
+
+	return count;
+}
+
+static ssize_t store_dimmer_high_level(struct device *dev,
+		struct device_attribute *attr, const char *buf, size_t count)
+{
+	struct backlight_device *bd = to_backlight_device(dev);
+
+	char *endp;
+	int high = simple_strtoul(buf, &endp, 0);
+
+	if (high < 0 || high > bd->props.max_brightness)
+		return -ENXIO;
+
+	mutex_lock(&bd->ops_lock);
+	bd->dimmer_high_level = high;
+	mutex_unlock(&bd->ops_lock);
+
+	return count;
+}
+
static struct device_attribute bl_device_attributes[] = {
	__ATTR(bl_power, 0644, backlight_show_power, backlight_store_power),
	__ATTR(brightness, 0644, backlight_show_brightness,
-		     backlight_store_brightness),
+				 backlight_store_brightness),
	__ATTR(actual_brightness, 0444, backlight_show_actual_brightness,
-		     NULL),
+				 NULL),
	__ATTR(max_brightness, 0444, backlight_show_max_brightness, NULL),
+	__ATTR(dimmer_control, 0666, show_dimmer_control, store_dimmer_control),
+	__ATTR(dimmer_timeout, 0666, show_dimmer_timeout, store_dimmer_timeout),
+	__ATTR(dimmer_low_level, 0666, show_dimmer_low_level,
+			store_dimmer_low_level),
+	__ATTR(dimmer_high_level, 0666, show_dimmer_high_level,
+			store_dimmer_high_level),
	__ATTR_NULL,
};

@@ -259,6 +529,7 @@ void backlight_device_unregister(struct #endif
	mutex_lock(&bd->ops_lock);
	bd->ops = NULL;
+	disable_dimmer(bd);
	mutex_unlock(&bd->ops_lock);

	backlight_unregister_fb(bd);

-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to [email protected]
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

[Index of Archives]     [Kernel Newbies]     [Netfilter]     [Bugtraq]     [Photo]     [Stuff]     [Gimp]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Video 4 Linux]     [Linux for the blind]     [Linux Resources]
  Powered by Linux