diff options
Diffstat (limited to 'target/linux/goldfish/patches-2.6.30/0054-timed_gpio-Separate-timed_output-class-into-a-separ.patch')
-rw-r--r-- | target/linux/goldfish/patches-2.6.30/0054-timed_gpio-Separate-timed_output-class-into-a-separ.patch | 432 |
1 files changed, 432 insertions, 0 deletions
diff --git a/target/linux/goldfish/patches-2.6.30/0054-timed_gpio-Separate-timed_output-class-into-a-separ.patch b/target/linux/goldfish/patches-2.6.30/0054-timed_gpio-Separate-timed_output-class-into-a-separ.patch new file mode 100644 index 0000000000..fac656e0cb --- /dev/null +++ b/target/linux/goldfish/patches-2.6.30/0054-timed_gpio-Separate-timed_output-class-into-a-separ.patch @@ -0,0 +1,432 @@ +From e4c9c5d7d6d5deb124083678fe5d839d3133f60a Mon Sep 17 00:00:00 2001 +From: Mike Lockwood <lockwood@android.com> +Date: Mon, 12 Jan 2009 13:25:05 -0500 +Subject: [PATCH 054/134] timed_gpio: Separate timed_output class into a separate driver. +MIME-Version: 1.0 +Content-Type: text/plain; charset=utf-8 +Content-Transfer-Encoding: 8bit + +Signed-off-by: Mike Lockwood <lockwood@android.com> +Signed-off-by: Arve Hjønnevåg <arve@android.com> +--- + drivers/staging/android/Kconfig | 6 ++- + drivers/staging/android/Makefile | 1 + + drivers/staging/android/timed_gpio.c | 98 +++++++++++-------------- + drivers/staging/android/timed_gpio.h | 4 +- + drivers/staging/android/timed_output.c | 121 ++++++++++++++++++++++++++++++++ + drivers/staging/android/timed_output.h | 37 ++++++++++ + 6 files changed, 210 insertions(+), 57 deletions(-) + create mode 100644 drivers/staging/android/timed_output.c + create mode 100644 drivers/staging/android/timed_output.h + +diff --git a/drivers/staging/android/Kconfig b/drivers/staging/android/Kconfig +index 604bd1e..1784508 100644 +--- a/drivers/staging/android/Kconfig ++++ b/drivers/staging/android/Kconfig +@@ -73,9 +73,13 @@ config ANDROID_RAM_CONSOLE_EARLY_SIZE + default 0 + depends on ANDROID_RAM_CONSOLE_EARLY_INIT + ++config ANDROID_TIMED_OUTPUT ++ bool "Timed output class driver" ++ default y ++ + config ANDROID_TIMED_GPIO + tristate "Android timed gpio driver" +- depends on GENERIC_GPIO ++ depends on GENERIC_GPIO && ANDROID_TIMED_OUTPUT + default n + + config ANDROID_LOW_MEMORY_KILLER +diff --git a/drivers/staging/android/Makefile b/drivers/staging/android/Makefile +index 95209d6..8e057e6 100644 +--- a/drivers/staging/android/Makefile ++++ b/drivers/staging/android/Makefile +@@ -1,5 +1,6 @@ + obj-$(CONFIG_ANDROID_BINDER_IPC) += binder.o + obj-$(CONFIG_ANDROID_LOGGER) += logger.o + obj-$(CONFIG_ANDROID_RAM_CONSOLE) += ram_console.o ++obj-$(CONFIG_ANDROID_TIMED_OUTPUT) += timed_output.o + obj-$(CONFIG_ANDROID_TIMED_GPIO) += timed_gpio.o + obj-$(CONFIG_ANDROID_LOW_MEMORY_KILLER) += lowmemorykiller.o +diff --git a/drivers/staging/android/timed_gpio.c b/drivers/staging/android/timed_gpio.c +index 33daff0..be7cdaa 100644 +--- a/drivers/staging/android/timed_gpio.c ++++ b/drivers/staging/android/timed_gpio.c +@@ -20,13 +20,12 @@ + #include <linux/err.h> + #include <linux/gpio.h> + ++#include "timed_output.h" + #include "timed_gpio.h" + + +-static struct class *timed_gpio_class; +- + struct timed_gpio_data { +- struct device *dev; ++ struct timed_output_dev dev; + struct hrtimer timer; + spinlock_t lock; + unsigned gpio; +@@ -36,70 +35,62 @@ struct timed_gpio_data { + + static enum hrtimer_restart gpio_timer_func(struct hrtimer *timer) + { +- struct timed_gpio_data *gpio_data = container_of(timer, struct timed_gpio_data, timer); ++ struct timed_gpio_data *data = ++ container_of(timer, struct timed_gpio_data, timer); + +- gpio_direction_output(gpio_data->gpio, gpio_data->active_low ? 1 : 0); ++ gpio_direction_output(data->gpio, data->active_low ? 1 : 0); + return HRTIMER_NORESTART; + } + +-static ssize_t gpio_enable_show(struct device *dev, struct device_attribute *attr, char *buf) ++static int gpio_get_time(struct timed_output_dev *dev) + { +- struct timed_gpio_data *gpio_data = dev_get_drvdata(dev); +- int remaining; ++ struct timed_gpio_data *data = ++ container_of(dev, struct timed_gpio_data, dev); + +- if (hrtimer_active(&gpio_data->timer)) { +- ktime_t r = hrtimer_get_remaining(&gpio_data->timer); ++ if (hrtimer_active(&data->timer)) { ++ ktime_t r = hrtimer_get_remaining(&data->timer); + struct timeval t = ktime_to_timeval(r); +- remaining = t.tv_sec * 1000 + t.tv_usec / 1000; ++ return t.tv_sec * 1000 + t.tv_usec / 1000; + } else +- remaining = 0; +- +- return sprintf(buf, "%d\n", remaining); ++ return 0; + } + +-static ssize_t gpio_enable_store( +- struct device *dev, struct device_attribute *attr, +- const char *buf, size_t size) ++static void gpio_enable(struct timed_output_dev *dev, int value) + { +- struct timed_gpio_data *gpio_data = dev_get_drvdata(dev); +- int value; ++ struct timed_gpio_data *data = ++ container_of(dev, struct timed_gpio_data, dev); + unsigned long flags; + +- sscanf(buf, "%d", &value); +- +- spin_lock_irqsave(&gpio_data->lock, flags); ++ spin_lock_irqsave(&data->lock, flags); + + /* cancel previous timer and set GPIO according to value */ +- hrtimer_cancel(&gpio_data->timer); +- gpio_direction_output(gpio_data->gpio, gpio_data->active_low ? !value : !!value); ++ hrtimer_cancel(&data->timer); ++ gpio_direction_output(data->gpio, data->active_low ? !value : !!value); + + if (value > 0) { +- if (value > gpio_data->max_timeout) +- value = gpio_data->max_timeout; ++ if (value > data->max_timeout) ++ value = data->max_timeout; + +- hrtimer_start(&gpio_data->timer, +- ktime_set(value / 1000, (value % 1000) * 1000000), +- HRTIMER_MODE_REL); ++ hrtimer_start(&data->timer, ++ ktime_set(value / 1000, (value % 1000) * 1000000), ++ HRTIMER_MODE_REL); + } + +- spin_unlock_irqrestore(&gpio_data->lock, flags); +- +- return size; ++ spin_unlock_irqrestore(&data->lock, flags); + } + +-static DEVICE_ATTR(enable, S_IRUGO | S_IWUSR, gpio_enable_show, gpio_enable_store); +- + static int timed_gpio_probe(struct platform_device *pdev) + { + struct timed_gpio_platform_data *pdata = pdev->dev.platform_data; + struct timed_gpio *cur_gpio; + struct timed_gpio_data *gpio_data, *gpio_dat; +- int i, ret = 0; ++ int i, j, ret = 0; + + if (!pdata) + return -EBUSY; + +- gpio_data = kzalloc(sizeof(struct timed_gpio_data) * pdata->num_gpios, GFP_KERNEL); ++ gpio_data = kzalloc(sizeof(struct timed_gpio_data) * pdata->num_gpios, ++ GFP_KERNEL); + if (!gpio_data) + return -ENOMEM; + +@@ -107,23 +98,26 @@ static int timed_gpio_probe(struct platform_device *pdev) + cur_gpio = &pdata->gpios[i]; + gpio_dat = &gpio_data[i]; + +- hrtimer_init(&gpio_dat->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); ++ hrtimer_init(&gpio_dat->timer, CLOCK_MONOTONIC, ++ HRTIMER_MODE_REL); + gpio_dat->timer.function = gpio_timer_func; + spin_lock_init(&gpio_dat->lock); + ++ gpio_dat->dev.name = cur_gpio->name; ++ gpio_dat->dev.get_time = gpio_get_time; ++ gpio_dat->dev.enable = gpio_enable; ++ ret = timed_output_dev_register(&gpio_dat->dev); ++ if (ret < 0) { ++ for (j = 0; j < i; j++) ++ timed_output_dev_unregister(&gpio_data[i].dev); ++ kfree(gpio_data); ++ return ret; ++ } ++ + gpio_dat->gpio = cur_gpio->gpio; + gpio_dat->max_timeout = cur_gpio->max_timeout; + gpio_dat->active_low = cur_gpio->active_low; + gpio_direction_output(gpio_dat->gpio, gpio_dat->active_low); +- +- gpio_dat->dev = device_create(timed_gpio_class, &pdev->dev, 0, "%s", cur_gpio->name); +- if (unlikely(IS_ERR(gpio_dat->dev))) +- return PTR_ERR(gpio_dat->dev); +- +- dev_set_drvdata(gpio_dat->dev, gpio_dat); +- ret = device_create_file(gpio_dat->dev, &dev_attr_enable); +- if (ret) +- return ret; + } + + platform_set_drvdata(pdev, gpio_data); +@@ -137,10 +131,8 @@ static int timed_gpio_remove(struct platform_device *pdev) + struct timed_gpio_data *gpio_data = platform_get_drvdata(pdev); + int i; + +- for (i = 0; i < pdata->num_gpios; i++) { +- device_remove_file(gpio_data[i].dev, &dev_attr_enable); +- device_unregister(gpio_data[i].dev); +- } ++ for (i = 0; i < pdata->num_gpios; i++) ++ timed_output_dev_unregister(&gpio_data[i].dev); + + kfree(gpio_data); + +@@ -151,22 +143,18 @@ static struct platform_driver timed_gpio_driver = { + .probe = timed_gpio_probe, + .remove = timed_gpio_remove, + .driver = { +- .name = "timed-gpio", ++ .name = TIMED_GPIO_NAME, + .owner = THIS_MODULE, + }, + }; + + static int __init timed_gpio_init(void) + { +- timed_gpio_class = class_create(THIS_MODULE, "timed_output"); +- if (IS_ERR(timed_gpio_class)) +- return PTR_ERR(timed_gpio_class); + return platform_driver_register(&timed_gpio_driver); + } + + static void __exit timed_gpio_exit(void) + { +- class_destroy(timed_gpio_class); + platform_driver_unregister(&timed_gpio_driver); + } + +diff --git a/drivers/staging/android/timed_gpio.h b/drivers/staging/android/timed_gpio.h +index 78449b2..a0e15f8 100644 +--- a/drivers/staging/android/timed_gpio.h ++++ b/drivers/staging/android/timed_gpio.h +@@ -16,10 +16,12 @@ + #ifndef _LINUX_TIMED_GPIO_H + #define _LINUX_TIMED_GPIO_H + ++#define TIMED_GPIO_NAME "timed-gpio" ++ + struct timed_gpio { + const char *name; + unsigned gpio; +- int max_timeout; ++ int max_timeout; + u8 active_low; + }; + +diff --git a/drivers/staging/android/timed_output.c b/drivers/staging/android/timed_output.c +new file mode 100644 +index 0000000..62e7918 +--- /dev/null ++++ b/drivers/staging/android/timed_output.c +@@ -0,0 +1,121 @@ ++/* drivers/misc/timed_output.c ++ * ++ * Copyright (C) 2009 Google, Inc. ++ * Author: Mike Lockwood <lockwood@android.com> ++ * ++ * This software is licensed under the terms of the GNU General Public ++ * License version 2, as published by the Free Software Foundation, and ++ * may be copied, distributed, and modified under those terms. ++ * ++ * 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. ++ * ++ */ ++ ++#include <linux/module.h> ++#include <linux/types.h> ++#include <linux/device.h> ++#include <linux/fs.h> ++#include <linux/err.h> ++ ++#include "timed_output.h" ++ ++static struct class *timed_output_class; ++static atomic_t device_count; ++ ++static ssize_t enable_show(struct device *dev, struct device_attribute *attr, ++ char *buf) ++{ ++ struct timed_output_dev *tdev = dev_get_drvdata(dev); ++ int remaining = tdev->get_time(tdev); ++ ++ return sprintf(buf, "%d\n", remaining); ++} ++ ++static ssize_t enable_store( ++ struct device *dev, struct device_attribute *attr, ++ const char *buf, size_t size) ++{ ++ struct timed_output_dev *tdev = dev_get_drvdata(dev); ++ int value; ++ ++ sscanf(buf, "%d", &value); ++ tdev->enable(tdev, value); ++ ++ return size; ++} ++ ++static DEVICE_ATTR(enable, S_IRUGO | S_IWUSR, enable_show, enable_store); ++ ++static int create_timed_output_class(void) ++{ ++ if (!timed_output_class) { ++ timed_output_class = class_create(THIS_MODULE, "timed_output"); ++ if (IS_ERR(timed_output_class)) ++ return PTR_ERR(timed_output_class); ++ atomic_set(&device_count, 0); ++ } ++ ++ return 0; ++} ++ ++int timed_output_dev_register(struct timed_output_dev *tdev) ++{ ++ int ret; ++ ++ if (!tdev || !tdev->name || !tdev->enable || !tdev->get_time) ++ return -EINVAL; ++ ++ ret = create_timed_output_class(); ++ if (ret < 0) ++ return ret; ++ ++ tdev->index = atomic_inc_return(&device_count); ++ tdev->dev = device_create(timed_output_class, NULL, ++ MKDEV(0, tdev->index), NULL, tdev->name); ++ if (IS_ERR(tdev->dev)) ++ return PTR_ERR(tdev->dev); ++ ++ ret = device_create_file(tdev->dev, &dev_attr_enable); ++ if (ret < 0) ++ goto err_create_file; ++ ++ dev_set_drvdata(tdev->dev, tdev); ++ tdev->state = 0; ++ return 0; ++ ++err_create_file: ++ device_destroy(timed_output_class, MKDEV(0, tdev->index)); ++ printk(KERN_ERR "timed_output: Failed to register driver %s\n", ++ tdev->name); ++ ++ return ret; ++} ++EXPORT_SYMBOL_GPL(timed_output_dev_register); ++ ++void timed_output_dev_unregister(struct timed_output_dev *tdev) ++{ ++ device_remove_file(tdev->dev, &dev_attr_enable); ++ device_destroy(timed_output_class, MKDEV(0, tdev->index)); ++ dev_set_drvdata(tdev->dev, NULL); ++} ++EXPORT_SYMBOL_GPL(timed_output_dev_unregister); ++ ++static int __init timed_output_init(void) ++{ ++ return create_timed_output_class(); ++} ++ ++static void __exit timed_output_exit(void) ++{ ++ class_destroy(timed_output_class); ++} ++ ++module_init(timed_output_init); ++module_exit(timed_output_exit); ++ ++MODULE_AUTHOR("Mike Lockwood <lockwood@android.com>"); ++MODULE_DESCRIPTION("timed output class driver"); ++MODULE_LICENSE("GPL"); +diff --git a/drivers/staging/android/timed_output.h b/drivers/staging/android/timed_output.h +new file mode 100644 +index 0000000..ec907ab +--- /dev/null ++++ b/drivers/staging/android/timed_output.h +@@ -0,0 +1,37 @@ ++/* include/linux/timed_output.h ++ * ++ * Copyright (C) 2008 Google, Inc. ++ * ++ * This software is licensed under the terms of the GNU General Public ++ * License version 2, as published by the Free Software Foundation, and ++ * may be copied, distributed, and modified under those terms. ++ * ++ * 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. ++ * ++*/ ++ ++#ifndef _LINUX_TIMED_OUTPUT_H ++#define _LINUX_TIMED_OUTPUT_H ++ ++struct timed_output_dev { ++ const char *name; ++ ++ /* enable the output and set the timer */ ++ void (*enable)(struct timed_output_dev *sdev, int timeout); ++ ++ /* returns the current number of milliseconds remaining on the timer */ ++ int (*get_time)(struct timed_output_dev *sdev); ++ ++ /* private data */ ++ struct device *dev; ++ int index; ++ int state; ++}; ++ ++extern int timed_output_dev_register(struct timed_output_dev *dev); ++extern void timed_output_dev_unregister(struct timed_output_dev *dev); ++ ++#endif +-- +1.6.2 + |