• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 	if (sscanf(buf, "%d", &value) != 1)
45 		return -EINVAL;
46 
47 	tdev->enable(tdev, value);
48 
49 	return size;
50 }
51 
52 static DEVICE_ATTR(enable, S_IRUGO | S_IWUSR, enable_show, enable_store);
53 
create_timed_output_class(void)54 static 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 
timed_output_dev_register(struct timed_output_dev * tdev)66 int 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 
91 err_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 }
98 EXPORT_SYMBOL_GPL(timed_output_dev_register);
99 
timed_output_dev_unregister(struct timed_output_dev * tdev)100 void timed_output_dev_unregister(struct timed_output_dev *tdev)
101 {
102 	device_remove_file(tdev->dev, &dev_attr_enable);
103 	device_destroy(timed_output_class, MKDEV(0, tdev->index));
104 	dev_set_drvdata(tdev->dev, NULL);
105 }
106 EXPORT_SYMBOL_GPL(timed_output_dev_unregister);
107 
timed_output_init(void)108 static int __init timed_output_init(void)
109 {
110 	return create_timed_output_class();
111 }
112 
timed_output_exit(void)113 static void __exit timed_output_exit(void)
114 {
115 	class_destroy(timed_output_class);
116 }
117 
118 module_init(timed_output_init);
119 module_exit(timed_output_exit);
120 
121 MODULE_AUTHOR("Mike Lockwood <lockwood@android.com>");
122 MODULE_DESCRIPTION("timed output class driver");
123 MODULE_LICENSE("GPL");
124