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