lkml.org 
[lkml]   [2007]   [Oct]   [28]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    Date
    From
    SubjectRe: [PATCH] backlight dimmer
    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 <jack@antonello.org>
    + *
    + * 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 <jack@antonello.org>
    + *
    + * 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 majordomo@vger.kernel.org
    More majordomo info at http://vger.kernel.org/majordomo-info.html
    Please read the FAQ at http://www.tux.org/lkml/

    \
     
     \ /
      Last update: 2007-10-28 23:03    [W:0.047 / U:62.748 seconds]
    ©2003-2016 Jasper Spaans. hosted at Digital OceanAdvertise on this site