timed_output.c revision d9a861d55e0cf60829956d7c6e18b7de0b02ab92
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#include <linux/module.h> 18#include <linux/types.h> 19#include <linux/device.h> 20#include <linux/fs.h> 21#include <linux/err.h> 22 23#include "timed_output.h" 24 25static struct class *timed_output_class; 26static atomic_t device_count; 27 28static ssize_t enable_show(struct device *dev, struct device_attribute *attr, 29 char *buf) 30{ 31 struct timed_output_dev *tdev = dev_get_drvdata(dev); 32 int remaining = tdev->get_time(tdev); 33 34 return sprintf(buf, "%d\n", remaining); 35} 36 37static ssize_t enable_store( 38 struct device *dev, struct device_attribute *attr, 39 const char *buf, size_t size) 40{ 41 struct timed_output_dev *tdev = dev_get_drvdata(dev); 42 int value; 43 44 if (sscanf(buf, "%d", &value) != 1) 45 return -EINVAL; 46 47 tdev->enable(tdev, value); 48 49 return size; 50} 51 52static DEVICE_ATTR(enable, S_IRUGO | S_IWUSR, enable_show, enable_store); 53 54static int create_timed_output_class(void) 55{ 56 if (!timed_output_class) { 57 timed_output_class = class_create(THIS_MODULE, "timed_output"); 58 if (IS_ERR(timed_output_class)) 59 return PTR_ERR(timed_output_class); 60 atomic_set(&device_count, 0); 61 } 62 63 return 0; 64} 65 66int timed_output_dev_register(struct timed_output_dev *tdev) 67{ 68 int ret; 69 70 if (!tdev || !tdev->name || !tdev->enable || !tdev->get_time) 71 return -EINVAL; 72 73 ret = create_timed_output_class(); 74 if (ret < 0) 75 return ret; 76 77 tdev->index = atomic_inc_return(&device_count); 78 tdev->dev = device_create(timed_output_class, NULL, 79 MKDEV(0, tdev->index), NULL, tdev->name); 80 if (IS_ERR(tdev->dev)) 81 return PTR_ERR(tdev->dev); 82 83 ret = device_create_file(tdev->dev, &dev_attr_enable); 84 if (ret < 0) 85 goto err_create_file; 86 87 dev_set_drvdata(tdev->dev, tdev); 88 tdev->state = 0; 89 return 0; 90 91err_create_file: 92 device_destroy(timed_output_class, MKDEV(0, tdev->index)); 93 printk(KERN_ERR "timed_output: Failed to register driver %s\n", 94 tdev->name); 95 96 return ret; 97} 98EXPORT_SYMBOL_GPL(timed_output_dev_register); 99 100void timed_output_dev_unregister(struct timed_output_dev *tdev) 101{ 102 tdev->enable(tdev, 0); 103 device_remove_file(tdev->dev, &dev_attr_enable); 104 device_destroy(timed_output_class, MKDEV(0, tdev->index)); 105 dev_set_drvdata(tdev->dev, NULL); 106} 107EXPORT_SYMBOL_GPL(timed_output_dev_unregister); 108 109static int __init timed_output_init(void) 110{ 111 return create_timed_output_class(); 112} 113 114static void __exit timed_output_exit(void) 115{ 116 class_destroy(timed_output_class); 117} 118 119module_init(timed_output_init); 120module_exit(timed_output_exit); 121 122MODULE_AUTHOR("Mike Lockwood <lockwood@android.com>"); 123MODULE_DESCRIPTION("timed output class driver"); 124MODULE_LICENSE("GPL"); 125