diff options
Diffstat (limited to 'drivers/media/IR/ir-sysfs.c')
-rw-r--r-- | drivers/media/IR/ir-sysfs.c | 211 |
1 files changed, 211 insertions, 0 deletions
diff --git a/drivers/media/IR/ir-sysfs.c b/drivers/media/IR/ir-sysfs.c new file mode 100644 index 000000000000..bf5fbcd84238 --- /dev/null +++ b/drivers/media/IR/ir-sysfs.c | |||
@@ -0,0 +1,211 @@ | |||
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/input.h> | ||
16 | #include <linux/device.h> | ||
17 | #include <media/ir-core.h> | ||
18 | |||
19 | #define IRRCV_NUM_DEVICES 256 | ||
20 | |||
21 | /* bit array to represent IR sysfs device number */ | ||
22 | static unsigned long ir_core_dev_number; | ||
23 | |||
24 | /* class for /sys/class/irrcv */ | ||
25 | static struct class *ir_input_class; | ||
26 | |||
27 | /** | ||
28 | * show_protocol() - shows the current IR protocol | ||
29 | * @d: the device descriptor | ||
30 | * @mattr: the device attribute struct (unused) | ||
31 | * @buf: a pointer to the output buffer | ||
32 | * | ||
33 | * This routine is a callback routine for input read the IR protocol type. | ||
34 | * it is trigged by reading /sys/class/irrcv/irrcv?/current_protocol. | ||
35 | * It returns the protocol name, as understood by the driver. | ||
36 | */ | ||
37 | static ssize_t show_protocol(struct device *d, | ||
38 | struct device_attribute *mattr, char *buf) | ||
39 | { | ||
40 | char *s; | ||
41 | struct ir_input_dev *ir_dev = dev_get_drvdata(d); | ||
42 | u64 ir_type = ir_dev->rc_tab.ir_type; | ||
43 | |||
44 | IR_dprintk(1, "Current protocol is %lld\n", (long long)ir_type); | ||
45 | |||
46 | /* FIXME: doesn't support multiple protocols at the same time */ | ||
47 | if (ir_type == IR_TYPE_UNKNOWN) | ||
48 | s = "Unknown"; | ||
49 | else if (ir_type == IR_TYPE_RC5) | ||
50 | s = "RC-5"; | ||
51 | else if (ir_type == IR_TYPE_PD) | ||
52 | s = "Pulse/distance"; | ||
53 | else if (ir_type == IR_TYPE_NEC) | ||
54 | s = "NEC"; | ||
55 | else | ||
56 | s = "Other"; | ||
57 | |||
58 | return sprintf(buf, "%s\n", s); | ||
59 | } | ||
60 | |||
61 | /** | ||
62 | * store_protocol() - shows the current IR protocol | ||
63 | * @d: the device descriptor | ||
64 | * @mattr: the device attribute struct (unused) | ||
65 | * @buf: a pointer to the input buffer | ||
66 | * @len: length of the input buffer | ||
67 | * | ||
68 | * This routine is a callback routine for changing the IR protocol type. | ||
69 | * it is trigged by reading /sys/class/irrcv/irrcv?/current_protocol. | ||
70 | * It changes the IR the protocol name, if the IR type is recognized | ||
71 | * by the driver. | ||
72 | * If an unknown protocol name is used, returns -EINVAL. | ||
73 | */ | ||
74 | static ssize_t store_protocol(struct device *d, | ||
75 | struct device_attribute *mattr, | ||
76 | const char *data, | ||
77 | size_t len) | ||
78 | { | ||
79 | struct ir_input_dev *ir_dev = dev_get_drvdata(d); | ||
80 | u64 ir_type = IR_TYPE_UNKNOWN; | ||
81 | int rc = -EINVAL; | ||
82 | unsigned long flags; | ||
83 | char *buf; | ||
84 | |||
85 | buf = strsep((char **) &data, "\n"); | ||
86 | |||
87 | if (!strcasecmp(buf, "rc-5")) | ||
88 | ir_type = IR_TYPE_RC5; | ||
89 | else if (!strcasecmp(buf, "pd")) | ||
90 | ir_type = IR_TYPE_PD; | ||
91 | else if (!strcasecmp(buf, "nec")) | ||
92 | ir_type = IR_TYPE_NEC; | ||
93 | |||
94 | if (ir_type == IR_TYPE_UNKNOWN) { | ||
95 | IR_dprintk(1, "Error setting protocol to %lld\n", | ||
96 | (long long)ir_type); | ||
97 | return -EINVAL; | ||
98 | } | ||
99 | |||
100 | if (ir_dev->props && ir_dev->props->change_protocol) | ||
101 | rc = ir_dev->props->change_protocol(ir_dev->props->priv, | ||
102 | ir_type); | ||
103 | |||
104 | if (rc < 0) { | ||
105 | IR_dprintk(1, "Error setting protocol to %lld\n", | ||
106 | (long long)ir_type); | ||
107 | return -EINVAL; | ||
108 | } | ||
109 | |||
110 | spin_lock_irqsave(&ir_dev->rc_tab.lock, flags); | ||
111 | ir_dev->rc_tab.ir_type = ir_type; | ||
112 | spin_unlock_irqrestore(&ir_dev->rc_tab.lock, flags); | ||
113 | |||
114 | IR_dprintk(1, "Current protocol is %lld\n", | ||
115 | (long long)ir_type); | ||
116 | |||
117 | return len; | ||
118 | } | ||
119 | |||
120 | /* | ||
121 | * Static device attribute struct with the sysfs attributes for IR's | ||
122 | */ | ||
123 | static DEVICE_ATTR(current_protocol, S_IRUGO | S_IWUSR, | ||
124 | show_protocol, store_protocol); | ||
125 | |||
126 | static struct attribute *ir_dev_attrs[] = { | ||
127 | &dev_attr_current_protocol.attr, | ||
128 | NULL, | ||
129 | }; | ||
130 | |||
131 | /** | ||
132 | * ir_register_class() - creates the sysfs for /sys/class/irrcv/irrcv? | ||
133 | * @input_dev: the struct input_dev descriptor of the device | ||
134 | * | ||
135 | * This routine is used to register the syfs code for IR class | ||
136 | */ | ||
137 | int ir_register_class(struct input_dev *input_dev) | ||
138 | { | ||
139 | int rc; | ||
140 | struct kobject *kobj; | ||
141 | |||
142 | struct ir_input_dev *ir_dev = input_get_drvdata(input_dev); | ||
143 | int devno = find_first_zero_bit(&ir_core_dev_number, | ||
144 | IRRCV_NUM_DEVICES); | ||
145 | |||
146 | if (unlikely(devno < 0)) | ||
147 | return devno; | ||
148 | |||
149 | ir_dev->attr.attrs = ir_dev_attrs; | ||
150 | ir_dev->class_dev = device_create(ir_input_class, NULL, | ||
151 | input_dev->dev.devt, ir_dev, | ||
152 | "irrcv%d", devno); | ||
153 | kobj = &ir_dev->class_dev->kobj; | ||
154 | |||
155 | printk(KERN_WARNING "Creating IR device %s\n", kobject_name(kobj)); | ||
156 | rc = sysfs_create_group(kobj, &ir_dev->attr); | ||
157 | if (unlikely(rc < 0)) { | ||
158 | device_destroy(ir_input_class, input_dev->dev.devt); | ||
159 | return -ENOMEM; | ||
160 | } | ||
161 | |||
162 | ir_dev->devno = devno; | ||
163 | set_bit(devno, &ir_core_dev_number); | ||
164 | |||
165 | return 0; | ||
166 | }; | ||
167 | |||
168 | /** | ||
169 | * ir_unregister_class() - removes the sysfs for sysfs for | ||
170 | * /sys/class/irrcv/irrcv? | ||
171 | * @input_dev: the struct input_dev descriptor of the device | ||
172 | * | ||
173 | * This routine is used to unregister the syfs code for IR class | ||
174 | */ | ||
175 | void ir_unregister_class(struct input_dev *input_dev) | ||
176 | { | ||
177 | struct ir_input_dev *ir_dev = input_get_drvdata(input_dev); | ||
178 | struct kobject *kobj; | ||
179 | |||
180 | clear_bit(ir_dev->devno, &ir_core_dev_number); | ||
181 | |||
182 | kobj = &ir_dev->class_dev->kobj; | ||
183 | |||
184 | sysfs_remove_group(kobj, &ir_dev->attr); | ||
185 | device_destroy(ir_input_class, input_dev->dev.devt); | ||
186 | |||
187 | kfree(ir_dev->attr.name); | ||
188 | } | ||
189 | |||
190 | /* | ||
191 | * Init/exit code for the module. Basically, creates/removes /sys/class/irrcv | ||
192 | */ | ||
193 | |||
194 | static int __init ir_core_init(void) | ||
195 | { | ||
196 | ir_input_class = class_create(THIS_MODULE, "irrcv"); | ||
197 | if (IS_ERR(ir_input_class)) { | ||
198 | printk(KERN_ERR "ir_core: unable to register irrcv class\n"); | ||
199 | return PTR_ERR(ir_input_class); | ||
200 | } | ||
201 | |||
202 | return 0; | ||
203 | } | ||
204 | |||
205 | static void __exit ir_core_exit(void) | ||
206 | { | ||
207 | class_destroy(ir_input_class); | ||
208 | } | ||
209 | |||
210 | module_init(ir_core_init); | ||
211 | module_exit(ir_core_exit); | ||