• 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 #define pr_fmt(fmt) "timed_output: " fmt
18 
19 #include <linux/init.h>
20 #include <linux/export.h>
21 #include <linux/types.h>
22 #include <linux/device.h>
23 #include <linux/fs.h>
24 #include <linux/err.h>
25 
26 #include "timed_output.h"
27 
28 static struct class *timed_output_class;
29 static atomic_t device_count;
30 
enable_show(struct device * dev,struct device_attribute * attr,char * buf)31 static ssize_t enable_show(struct device *dev, struct device_attribute *attr,
32 			   char *buf)
33 {
34 	struct timed_output_dev *tdev = dev_get_drvdata(dev);
35 	int remaining = tdev->get_time(tdev);
36 
37 	return sprintf(buf, "%d\n", remaining);
38 }
39 
enable_store(struct device * dev,struct device_attribute * attr,const char * buf,size_t size)40 static ssize_t enable_store(struct device *dev, struct device_attribute *attr,
41 			    const char *buf, size_t size)
42 {
43 	struct timed_output_dev *tdev = dev_get_drvdata(dev);
44 	int value;
45 	int rc;
46 
47 	rc = kstrtoint(buf, 0, &value);
48 	if (rc != 0)
49 		return -EINVAL;
50 
51 	tdev->enable(tdev, value);
52 
53 	return size;
54 }
55 static DEVICE_ATTR_RW(enable);
56 
57 static struct attribute *timed_output_attrs[] = {
58 	&dev_attr_enable.attr,
59 	NULL,
60 };
61 ATTRIBUTE_GROUPS(timed_output);
62 
create_timed_output_class(void)63 static int create_timed_output_class(void)
64 {
65 	if (!timed_output_class) {
66 		timed_output_class = class_create(THIS_MODULE, "timed_output");
67 		if (IS_ERR(timed_output_class))
68 			return PTR_ERR(timed_output_class);
69 		atomic_set(&device_count, 0);
70 		timed_output_class->dev_groups = timed_output_groups;
71 	}
72 
73 	return 0;
74 }
75 
timed_output_dev_register(struct timed_output_dev * tdev)76 int timed_output_dev_register(struct timed_output_dev *tdev)
77 {
78 	int ret;
79 
80 	if (!tdev || !tdev->name || !tdev->enable || !tdev->get_time)
81 		return -EINVAL;
82 
83 	ret = create_timed_output_class();
84 	if (ret < 0)
85 		return ret;
86 
87 	tdev->index = atomic_inc_return(&device_count);
88 	tdev->dev = device_create(timed_output_class, NULL,
89 		MKDEV(0, tdev->index), NULL, "%s", tdev->name);
90 	if (IS_ERR(tdev->dev))
91 		return PTR_ERR(tdev->dev);
92 
93 	dev_set_drvdata(tdev->dev, tdev);
94 	tdev->state = 0;
95 	return 0;
96 }
97 EXPORT_SYMBOL_GPL(timed_output_dev_register);
98 
timed_output_dev_unregister(struct timed_output_dev * tdev)99 void timed_output_dev_unregister(struct timed_output_dev *tdev)
100 {
101 	tdev->enable(tdev, 0);
102 	device_destroy(timed_output_class, MKDEV(0, tdev->index));
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 device_initcall(timed_output_init);
111