timed_output.c revision b28e7d5807051184270c40d4bc48db947189f107
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(struct device *dev, struct device_attribute *attr, 40 const char *buf, size_t size) 41{ 42 struct timed_output_dev *tdev = dev_get_drvdata(dev); 43 int value; 44 45 if (sscanf(buf, "%d", &value) != 1) 46 return -EINVAL; 47 48 tdev->enable(tdev, value); 49 50 return size; 51} 52static DEVICE_ATTR_RW(enable); 53 54static struct attribute *timed_output_attrs[] = { 55 &dev_attr_enable.attr, 56 NULL, 57}; 58ATTRIBUTE_GROUPS(timed_output); 59 60static int create_timed_output_class(void) 61{ 62 if (!timed_output_class) { 63 timed_output_class = class_create(THIS_MODULE, "timed_output"); 64 if (IS_ERR(timed_output_class)) 65 return PTR_ERR(timed_output_class); 66 atomic_set(&device_count, 0); 67 timed_output_class->dev_groups = timed_output_groups; 68 } 69 70 return 0; 71} 72 73int timed_output_dev_register(struct timed_output_dev *tdev) 74{ 75 int ret; 76 77 if (!tdev || !tdev->name || !tdev->enable || !tdev->get_time) 78 return -EINVAL; 79 80 ret = create_timed_output_class(); 81 if (ret < 0) 82 return ret; 83 84 tdev->index = atomic_inc_return(&device_count); 85 tdev->dev = device_create(timed_output_class, NULL, 86 MKDEV(0, tdev->index), NULL, "%s", tdev->name); 87 if (IS_ERR(tdev->dev)) 88 return PTR_ERR(tdev->dev); 89 90 dev_set_drvdata(tdev->dev, tdev); 91 tdev->state = 0; 92 return 0; 93} 94EXPORT_SYMBOL_GPL(timed_output_dev_register); 95 96void timed_output_dev_unregister(struct timed_output_dev *tdev) 97{ 98 tdev->enable(tdev, 0); 99 device_destroy(timed_output_class, MKDEV(0, tdev->index)); 100} 101EXPORT_SYMBOL_GPL(timed_output_dev_unregister); 102 103static int __init timed_output_init(void) 104{ 105 return create_timed_output_class(); 106} 107 108static void __exit timed_output_exit(void) 109{ 110 class_destroy(timed_output_class); 111} 112 113module_init(timed_output_init); 114module_exit(timed_output_exit); 115 116MODULE_AUTHOR("Mike Lockwood <lockwood@android.com>"); 117MODULE_DESCRIPTION("timed output class driver"); 118MODULE_LICENSE("GPL"); 119