V4L/DVB: ir: use a real device instead of a virtual class
[platform/kernel/linux-arm64.git] / drivers / media / IR / ir-sysfs.c
1 /* ir-register.c - handle IR scancode->keycode tables
2  *
3  * Copyright (C) 2009 by Mauro Carvalho Chehab <mchehab@redhat.com>
4  *
5  * This program is free software; you can redistribute it and/or modify
6  *  it under the terms of the GNU General Public License as published by
7  *  the Free Software Foundation version 2 of the License.
8  *
9  *  This program is distributed in the hope that it will be useful,
10  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
11  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  *  GNU General Public License for more details.
13  */
14
15 #include <linux/slab.h>
16 #include <linux/input.h>
17 #include <linux/device.h>
18 #include <media/ir-core.h>
19
20 #define IRRCV_NUM_DEVICES       256
21
22 /* bit array to represent IR sysfs device number */
23 static unsigned long ir_core_dev_number;
24
25 /* class for /sys/class/irrcv */
26 static char *ir_devnode(struct device *dev, mode_t *mode)
27 {
28         return kasprintf(GFP_KERNEL, "irrcv/%s", dev_name(dev));
29 }
30
31 struct class ir_input_class = {
32         .name           = "irrcv",
33         .devnode        = ir_devnode,
34 };
35
36 /**
37  * show_protocol() - shows the current IR protocol
38  * @d:          the device descriptor
39  * @mattr:      the device attribute struct (unused)
40  * @buf:        a pointer to the output buffer
41  *
42  * This routine is a callback routine for input read the IR protocol type.
43  * it is trigged by reading /sys/class/irrcv/irrcv?/current_protocol.
44  * It returns the protocol name, as understood by the driver.
45  */
46 static ssize_t show_protocol(struct device *d,
47                              struct device_attribute *mattr, char *buf)
48 {
49         char *s;
50         struct ir_input_dev *ir_dev = dev_get_drvdata(d);
51         u64 ir_type = ir_dev->rc_tab.ir_type;
52
53         IR_dprintk(1, "Current protocol is %lld\n", (long long)ir_type);
54
55         /* FIXME: doesn't support multiple protocols at the same time */
56         if (ir_type == IR_TYPE_UNKNOWN)
57                 s = "Unknown";
58         else if (ir_type == IR_TYPE_RC5)
59                 s = "RC-5";
60         else if (ir_type == IR_TYPE_PD)
61                 s = "Pulse/distance";
62         else if (ir_type == IR_TYPE_NEC)
63                 s = "NEC";
64         else
65                 s = "Other";
66
67         return sprintf(buf, "%s\n", s);
68 }
69
70 /**
71  * store_protocol() - shows the current IR protocol
72  * @d:          the device descriptor
73  * @mattr:      the device attribute struct (unused)
74  * @buf:        a pointer to the input buffer
75  * @len:        length of the input buffer
76  *
77  * This routine is a callback routine for changing the IR protocol type.
78  * it is trigged by reading /sys/class/irrcv/irrcv?/current_protocol.
79  * It changes the IR the protocol name, if the IR type is recognized
80  * by the driver.
81  * If an unknown protocol name is used, returns -EINVAL.
82  */
83 static ssize_t store_protocol(struct device *d,
84                               struct device_attribute *mattr,
85                               const char *data,
86                               size_t len)
87 {
88         struct ir_input_dev *ir_dev = dev_get_drvdata(d);
89         u64 ir_type = IR_TYPE_UNKNOWN;
90         int rc = -EINVAL;
91         unsigned long flags;
92         char *buf;
93
94         buf = strsep((char **) &data, "\n");
95
96         if (!strcasecmp(buf, "rc-5"))
97                 ir_type = IR_TYPE_RC5;
98         else if (!strcasecmp(buf, "pd"))
99                 ir_type = IR_TYPE_PD;
100         else if (!strcasecmp(buf, "nec"))
101                 ir_type = IR_TYPE_NEC;
102
103         if (ir_type == IR_TYPE_UNKNOWN) {
104                 IR_dprintk(1, "Error setting protocol to %lld\n",
105                            (long long)ir_type);
106                 return -EINVAL;
107         }
108
109         if (ir_dev->props && ir_dev->props->change_protocol)
110                 rc = ir_dev->props->change_protocol(ir_dev->props->priv,
111                                                     ir_type);
112
113         if (rc < 0) {
114                 IR_dprintk(1, "Error setting protocol to %lld\n",
115                            (long long)ir_type);
116                 return -EINVAL;
117         }
118
119         spin_lock_irqsave(&ir_dev->rc_tab.lock, flags);
120         ir_dev->rc_tab.ir_type = ir_type;
121         spin_unlock_irqrestore(&ir_dev->rc_tab.lock, flags);
122
123         IR_dprintk(1, "Current protocol is %lld\n",
124                    (long long)ir_type);
125
126         return len;
127 }
128
129 /*
130  * Static device attribute struct with the sysfs attributes for IR's
131  */
132 static DEVICE_ATTR(current_protocol, S_IRUGO | S_IWUSR,
133                    show_protocol, store_protocol);
134
135 static struct attribute *ir_dev_attrs[] = {
136         &dev_attr_current_protocol.attr,
137         NULL,
138 };
139
140 static struct attribute_group ir_dev_attr_grp = {
141         .attrs  = ir_dev_attrs,
142 };
143
144 static const struct attribute_group *ir_dev_attr_groups[] = {
145         &ir_dev_attr_grp,
146         NULL
147 };
148
149 static struct device_type ir_dev_type = {
150         .groups         = ir_dev_attr_groups,
151 };
152
153
154 /**
155  * ir_register_class() - creates the sysfs for /sys/class/irrcv/irrcv?
156  * @input_dev:  the struct input_dev descriptor of the device
157  *
158  * This routine is used to register the syfs code for IR class
159  */
160 int ir_register_class(struct input_dev *input_dev)
161 {
162         int rc;
163         const char *path;
164
165         struct ir_input_dev *ir_dev = input_get_drvdata(input_dev);
166         int devno = find_first_zero_bit(&ir_core_dev_number,
167                                         IRRCV_NUM_DEVICES);
168
169         if (unlikely(devno < 0))
170                 return devno;
171
172         ir_dev->dev.type = &ir_dev_type;
173         ir_dev->dev.class = &ir_input_class;
174         ir_dev->dev.parent = input_dev->dev.parent;
175         dev_set_name(&ir_dev->dev, "irrcv%d", devno);
176         rc = device_register(&ir_dev->dev);
177         if (rc)
178                 return rc;
179
180
181         input_dev->dev.parent = &ir_dev->dev;
182         rc = input_register_device(input_dev);
183         if (rc < 0) {
184                 device_del(&ir_dev->dev);
185                 return rc;
186         }
187
188         __module_get(THIS_MODULE);
189
190         path = kobject_get_path(&input_dev->dev.kobj, GFP_KERNEL);
191         printk(KERN_INFO "%s: %s associated with sysfs %s\n",
192                 dev_name(&ir_dev->dev),
193                 input_dev->name ? input_dev->name : "Unspecified device",
194                 path ? path : "N/A");
195         kfree(path);
196
197         ir_dev->devno = devno;
198         set_bit(devno, &ir_core_dev_number);
199
200         return 0;
201 };
202
203 /**
204  * ir_unregister_class() - removes the sysfs for sysfs for
205  *                         /sys/class/irrcv/irrcv?
206  * @input_dev:  the struct input_dev descriptor of the device
207  *
208  * This routine is used to unregister the syfs code for IR class
209  */
210 void ir_unregister_class(struct input_dev *input_dev)
211 {
212         struct ir_input_dev *ir_dev = input_get_drvdata(input_dev);
213
214         clear_bit(ir_dev->devno, &ir_core_dev_number);
215         input_unregister_device(input_dev);
216         device_del(&ir_dev->dev);
217
218         module_put(THIS_MODULE);
219 }
220
221 /*
222  * Init/exit code for the module. Basically, creates/removes /sys/class/irrcv
223  */
224
225 static int __init ir_core_init(void)
226 {
227         int rc = class_register(&ir_input_class);
228         if (rc) {
229                 printk(KERN_ERR "ir_core: unable to register irrcv class\n");
230                 return rc;
231         }
232
233         return 0;
234 }
235
236 static void __exit ir_core_exit(void)
237 {
238         class_unregister(&ir_input_class);
239 }
240
241 module_init(ir_core_init);
242 module_exit(ir_core_exit);