timed_output.c revision 02aa2a37636c8fa4fb9322d91be46ff8225b7de0
1/* drivers/misc/timed_output.c 2 * 3 * Copyright (C) 2009 Google, Inc. 4 * Author: Mike Lockwood <lockwood@android.com> 5 * 6 * This software is licensed under the terms of the GNU General Public 7 * License version 2, as published by the Free Software Foundation, and 8 * may be copied, distributed, and modified under those terms. 9 * 10 * This program is distributed in the hope that it will be useful, 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 * GNU General Public License for more details. 14 * 15 */ 16 17#define pr_fmt(fmt) "timed_output: " fmt 18 19#include <linux/module.h> 20#include <linux/types.h> 21#include <linux/device.h> 22#include <linux/fs.h> 23#include <linux/err.h> 24 25#include "timed_output.h" 26 27static struct class *timed_output_class; 28static atomic_t device_count; 29 30static ssize_t enable_show(struct device *dev, struct device_attribute *attr, 31 char *buf) 32{ 33 struct timed_output_dev *tdev = dev_get_drvdata(dev); 34 int remaining = tdev->get_time(tdev); 35 36 return sprintf(buf, "%d\n", remaining); 37} 38 39static ssize_t enable_store( 40 struct device *dev, struct device_attribute *attr, 41 const char *buf, size_t size) 42{ 43 struct timed_output_dev *tdev = dev_get_drvdata(dev); 44 int value; 45 46 if (sscanf(buf, "%d", &value) != 1) 47 return -EINVAL; 48 49 tdev->enable(tdev, value); 50 51 return size; 52} 53 54static DEVICE_ATTR(enable, S_IRUGO | S_IWUSR, enable_show, enable_store); 55 56static int create_timed_output_class(void) 57{ 58 if (!timed_output_class) { 59 timed_output_class = class_create(THIS_MODULE, "timed_output"); 60 if (IS_ERR(timed_output_class)) 61 return PTR_ERR(timed_output_class); 62 atomic_set(&device_count, 0); 63 } 64 65 return 0; 66} 67 68int timed_output_dev_register(struct timed_output_dev *tdev) 69{ 70 int ret; 71 72 if (!tdev || !tdev->name || !tdev->enable || !tdev->get_time) 73 return -EINVAL; 74 75 ret = create_timed_output_class(); 76 if (ret < 0) 77 return ret; 78 79 tdev->index = atomic_inc_return(&device_count); 80 tdev->dev = device_create(timed_output_class, NULL, 81 MKDEV(0, tdev->index), NULL, "%s", tdev->name); 82 if (IS_ERR(tdev->dev)) 83 return PTR_ERR(tdev->dev); 84 85 ret = device_create_file(tdev->dev, &dev_attr_enable); 86 if (ret < 0) 87 goto err_create_file; 88 89 dev_set_drvdata(tdev->dev, tdev); 90 tdev->state = 0; 91 return 0; 92 93err_create_file: 94 device_destroy(timed_output_class, MKDEV(0, tdev->index)); 95 pr_err("failed to register driver %s\n", 96 tdev->name); 97 98 return ret; 99} 100EXPORT_SYMBOL_GPL(timed_output_dev_register); 101 102void timed_output_dev_unregister(struct timed_output_dev *tdev) 103{ 104 tdev->enable(tdev, 0); 105 device_remove_file(tdev->dev, &dev_attr_enable); 106 device_destroy(timed_output_class, MKDEV(0, tdev->index)); 107 dev_set_drvdata(tdev->dev, NULL); 108} 109EXPORT_SYMBOL_GPL(timed_output_dev_unregister); 110 111static int __init timed_output_init(void) 112{ 113 return create_timed_output_class(); 114} 115 116static void __exit timed_output_exit(void) 117{ 118 class_destroy(timed_output_class); 119} 120 121module_init(timed_output_init); 122module_exit(timed_output_exit); 123 124MODULE_AUTHOR("Mike Lockwood <lockwood@android.com>"); 125MODULE_DESCRIPTION("timed output class driver"); 126MODULE_LICENSE("GPL"); 127