Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
timed_output.c
Go to the documentation of this file.
1 /* drivers/misc/timed_output.c
2  *
3  * Copyright (C) 2009 Google, Inc.
4  * Author: Mike Lockwood <[email protected]>
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 
27 static struct class *timed_output_class;
28 static atomic_t device_count;
29 
30 static 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 
39 static ssize_t enable_store(
40  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 
46  if (sscanf(buf, "%d", &value) != 1)
47  return -EINVAL;
48 
49  tdev->enable(tdev, value);
50 
51  return size;
52 }
53 
54 static DEVICE_ATTR(enable, S_IRUGO | S_IWUSR, enable_show, enable_store);
55 
56 static int create_timed_output_class(void)
57 {
58  if (!timed_output_class) {
59  timed_output_class = class_create(THIS_MODULE, "timed_output");
60  if (IS_ERR(timed_output_class))
61  return PTR_ERR(timed_output_class);
62  atomic_set(&device_count, 0);
63  }
64 
65  return 0;
66 }
67 
69 {
70  int ret;
71 
72  if (!tdev || !tdev->name || !tdev->enable || !tdev->get_time)
73  return -EINVAL;
74 
75  ret = create_timed_output_class();
76  if (ret < 0)
77  return ret;
78 
79  tdev->index = atomic_inc_return(&device_count);
80  tdev->dev = device_create(timed_output_class, NULL,
81  MKDEV(0, tdev->index), NULL, tdev->name);
82  if (IS_ERR(tdev->dev))
83  return PTR_ERR(tdev->dev);
84 
85  ret = device_create_file(tdev->dev, &dev_attr_enable);
86  if (ret < 0)
87  goto err_create_file;
88 
89  dev_set_drvdata(tdev->dev, tdev);
90  tdev->state = 0;
91  return 0;
92 
93 err_create_file:
94  device_destroy(timed_output_class, MKDEV(0, tdev->index));
95  pr_err("failed to register driver %s\n",
96  tdev->name);
97 
98  return ret;
99 }
101 
103 {
104  tdev->enable(tdev, 0);
105  device_remove_file(tdev->dev, &dev_attr_enable);
106  device_destroy(timed_output_class, MKDEV(0, tdev->index));
107  dev_set_drvdata(tdev->dev, NULL);
108 }
110 
111 static int __init timed_output_init(void)
112 {
113  return create_timed_output_class();
114 }
115 
116 static void __exit timed_output_exit(void)
117 {
118  class_destroy(timed_output_class);
119 }
120 
121 module_init(timed_output_init);
122 module_exit(timed_output_exit);
123 
124 MODULE_AUTHOR("Mike Lockwood <[email protected]>");
125 MODULE_DESCRIPTION("timed output class driver");
126 MODULE_LICENSE("GPL");