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