aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/media/IR/Kconfig9
-rw-r--r--drivers/media/IR/Makefile1
-rw-r--r--drivers/media/IR/ir-core-priv.h7
-rw-r--r--drivers/media/IR/ir-raw-event.c1
-rw-r--r--drivers/media/IR/ir-sony-decoder.c312
-rw-r--r--drivers/media/IR/ir-sysfs.c4
-rw-r--r--include/media/rc-map.h1
7 files changed, 335 insertions, 0 deletions
diff --git a/drivers/media/IR/Kconfig b/drivers/media/IR/Kconfig
index e87242af9b35..195c6cf359f6 100644
--- a/drivers/media/IR/Kconfig
+++ b/drivers/media/IR/Kconfig
@@ -46,6 +46,15 @@ config IR_JVC_DECODER
46 Enable this option if you have an infrared remote control which 46 Enable this option if you have an infrared remote control which
47 uses the JVC protocol, and you need software decoding support. 47 uses the JVC protocol, and you need software decoding support.
48 48
49config IR_SONY_DECODER
50 tristate "Enable IR raw decoder for the Sony protocol"
51 depends on IR_CORE
52 default y
53
54 ---help---
55 Enable this option if you have an infrared remote control which
56 uses the Sony protocol, and you need software decoding support.
57
49config IR_IMON 58config IR_IMON
50 tristate "SoundGraph iMON Receiver and Display" 59 tristate "SoundGraph iMON Receiver and Display"
51 depends on USB_ARCH_HAS_HCD 60 depends on USB_ARCH_HAS_HCD
diff --git a/drivers/media/IR/Makefile b/drivers/media/IR/Makefile
index 937cbdedc7c1..b998fcced2e4 100644
--- a/drivers/media/IR/Makefile
+++ b/drivers/media/IR/Makefile
@@ -9,6 +9,7 @@ obj-$(CONFIG_IR_NEC_DECODER) += ir-nec-decoder.o
9obj-$(CONFIG_IR_RC5_DECODER) += ir-rc5-decoder.o 9obj-$(CONFIG_IR_RC5_DECODER) += ir-rc5-decoder.o
10obj-$(CONFIG_IR_RC6_DECODER) += ir-rc6-decoder.o 10obj-$(CONFIG_IR_RC6_DECODER) += ir-rc6-decoder.o
11obj-$(CONFIG_IR_JVC_DECODER) += ir-jvc-decoder.o 11obj-$(CONFIG_IR_JVC_DECODER) += ir-jvc-decoder.o
12obj-$(CONFIG_IR_SONY_DECODER) += ir-sony-decoder.o
12 13
13# stand-alone IR receivers/transmitters 14# stand-alone IR receivers/transmitters
14obj-$(CONFIG_IR_IMON) += imon.o 15obj-$(CONFIG_IR_IMON) += imon.o
diff --git a/drivers/media/IR/ir-core-priv.h b/drivers/media/IR/ir-core-priv.h
index 464e392f24cf..9a5e65a471a5 100644
--- a/drivers/media/IR/ir-core-priv.h
+++ b/drivers/media/IR/ir-core-priv.h
@@ -116,4 +116,11 @@ void ir_raw_init(void);
116#define load_jvc_decode() 0 116#define load_jvc_decode() 0
117#endif 117#endif
118 118
119/* from ir-sony-decoder.c */
120#ifdef CONFIG_IR_SONY_DECODER_MODULE
121#define load_sony_decode() request_module("ir-sony-decoder")
122#else
123#define load_sony_decode() 0
124#endif
125
119#endif /* _IR_RAW_EVENT */ 126#endif /* _IR_RAW_EVENT */
diff --git a/drivers/media/IR/ir-raw-event.c b/drivers/media/IR/ir-raw-event.c
index 7eef6bf4404f..ea68a3f2effa 100644
--- a/drivers/media/IR/ir-raw-event.c
+++ b/drivers/media/IR/ir-raw-event.c
@@ -234,6 +234,7 @@ static void init_decoders(struct work_struct *work)
234 load_rc5_decode(); 234 load_rc5_decode();
235 load_rc6_decode(); 235 load_rc6_decode();
236 load_jvc_decode(); 236 load_jvc_decode();
237 load_sony_decode();
237 238
238 /* If needed, we may later add some init code. In this case, 239 /* If needed, we may later add some init code. In this case,
239 it is needed to change the CONFIG_MODULE test at ir-core.h 240 it is needed to change the CONFIG_MODULE test at ir-core.h
diff --git a/drivers/media/IR/ir-sony-decoder.c b/drivers/media/IR/ir-sony-decoder.c
new file mode 100644
index 000000000000..9f440c5c060d
--- /dev/null
+++ b/drivers/media/IR/ir-sony-decoder.c
@@ -0,0 +1,312 @@
1/* ir-sony-decoder.c - handle Sony IR Pulse/Space protocol
2 *
3 * Copyright (C) 2010 by David Härdeman <david@hardeman.nu>
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/bitrev.h>
16#include "ir-core-priv.h"
17
18#define SONY_UNIT 600000 /* ns */
19#define SONY_HEADER_PULSE (4 * SONY_UNIT)
20#define SONY_HEADER_SPACE (1 * SONY_UNIT)
21#define SONY_BIT_0_PULSE (1 * SONY_UNIT)
22#define SONY_BIT_1_PULSE (2 * SONY_UNIT)
23#define SONY_BIT_SPACE (1 * SONY_UNIT)
24#define SONY_TRAILER_SPACE (10 * SONY_UNIT) /* minimum */
25
26/* Used to register sony_decoder clients */
27static LIST_HEAD(decoder_list);
28static DEFINE_SPINLOCK(decoder_lock);
29
30enum sony_state {
31 STATE_INACTIVE,
32 STATE_HEADER_SPACE,
33 STATE_BIT_PULSE,
34 STATE_BIT_SPACE,
35 STATE_FINISHED,
36};
37
38struct decoder_data {
39 struct list_head list;
40 struct ir_input_dev *ir_dev;
41 int enabled:1;
42
43 /* State machine control */
44 enum sony_state state;
45 u32 sony_bits;
46 unsigned count;
47};
48
49
50/**
51 * get_decoder_data() - gets decoder data
52 * @input_dev: input device
53 *
54 * Returns the struct decoder_data that corresponds to a device
55 */
56static struct decoder_data *get_decoder_data(struct ir_input_dev *ir_dev)
57{
58 struct decoder_data *data = NULL;
59
60 spin_lock(&decoder_lock);
61 list_for_each_entry(data, &decoder_list, list) {
62 if (data->ir_dev == ir_dev)
63 break;
64 }
65 spin_unlock(&decoder_lock);
66 return data;
67}
68
69static ssize_t store_enabled(struct device *d,
70 struct device_attribute *mattr,
71 const char *buf,
72 size_t len)
73{
74 unsigned long value;
75 struct ir_input_dev *ir_dev = dev_get_drvdata(d);
76 struct decoder_data *data = get_decoder_data(ir_dev);
77
78 if (!data)
79 return -EINVAL;
80
81 if (strict_strtoul(buf, 10, &value) || value > 1)
82 return -EINVAL;
83
84 data->enabled = value;
85
86 return len;
87}
88
89static ssize_t show_enabled(struct device *d,
90 struct device_attribute *mattr, char *buf)
91{
92 struct ir_input_dev *ir_dev = dev_get_drvdata(d);
93 struct decoder_data *data = get_decoder_data(ir_dev);
94
95 if (!data)
96 return -EINVAL;
97
98 if (data->enabled)
99 return sprintf(buf, "1\n");
100 else
101 return sprintf(buf, "0\n");
102}
103
104static DEVICE_ATTR(enabled, S_IRUGO | S_IWUSR, show_enabled, store_enabled);
105
106static struct attribute *decoder_attributes[] = {
107 &dev_attr_enabled.attr,
108 NULL
109};
110
111static struct attribute_group decoder_attribute_group = {
112 .name = "sony_decoder",
113 .attrs = decoder_attributes,
114};
115
116/**
117 * ir_sony_decode() - Decode one Sony pulse or space
118 * @input_dev: the struct input_dev descriptor of the device
119 * @ev: the struct ir_raw_event descriptor of the pulse/space
120 *
121 * This function returns -EINVAL if the pulse violates the state machine
122 */
123static int ir_sony_decode(struct input_dev *input_dev, struct ir_raw_event ev)
124{
125 struct decoder_data *data;
126 struct ir_input_dev *ir_dev = input_get_drvdata(input_dev);
127 u32 scancode;
128 u8 device, subdevice, function;
129
130 data = get_decoder_data(ir_dev);
131 if (!data)
132 return -EINVAL;
133
134 if (!data->enabled)
135 return 0;
136
137 if (IS_RESET(ev)) {
138 data->state = STATE_INACTIVE;
139 return 0;
140 }
141
142 if (!geq_margin(ev.duration, SONY_UNIT, SONY_UNIT / 2))
143 goto out;
144
145 IR_dprintk(2, "Sony decode started at state %d (%uus %s)\n",
146 data->state, TO_US(ev.duration), TO_STR(ev.pulse));
147
148 switch (data->state) {
149
150 case STATE_INACTIVE:
151 if (!ev.pulse)
152 break;
153
154 if (!eq_margin(ev.duration, SONY_HEADER_PULSE, SONY_UNIT / 2))
155 break;
156
157 data->count = 0;
158 data->state = STATE_HEADER_SPACE;
159 return 0;
160
161 case STATE_HEADER_SPACE:
162 if (ev.pulse)
163 break;
164
165 if (!eq_margin(ev.duration, SONY_HEADER_SPACE, SONY_UNIT / 2))
166 break;
167
168 data->state = STATE_BIT_PULSE;
169 return 0;
170
171 case STATE_BIT_PULSE:
172 if (!ev.pulse)
173 break;
174
175 data->sony_bits <<= 1;
176 if (eq_margin(ev.duration, SONY_BIT_1_PULSE, SONY_UNIT / 2))
177 data->sony_bits |= 1;
178 else if (!eq_margin(ev.duration, SONY_BIT_0_PULSE, SONY_UNIT / 2))
179 break;
180
181 data->count++;
182 data->state = STATE_BIT_SPACE;
183 return 0;
184
185 case STATE_BIT_SPACE:
186 if (ev.pulse)
187 break;
188
189 if (!geq_margin(ev.duration, SONY_BIT_SPACE, SONY_UNIT / 2))
190 break;
191
192 decrease_duration(&ev, SONY_BIT_SPACE);
193
194 if (!geq_margin(ev.duration, SONY_UNIT, SONY_UNIT / 2)) {
195 data->state = STATE_BIT_PULSE;
196 return 0;
197 }
198
199 data->state = STATE_FINISHED;
200 /* Fall through */
201
202 case STATE_FINISHED:
203 if (ev.pulse)
204 break;
205
206 if (!geq_margin(ev.duration, SONY_TRAILER_SPACE, SONY_UNIT / 2))
207 break;
208
209 switch (data->count) {
210 case 12:
211 device = bitrev8((data->sony_bits << 3) & 0xF8);
212 subdevice = 0;
213 function = bitrev8((data->sony_bits >> 4) & 0xFE);
214 break;
215 case 15:
216 device = bitrev8((data->sony_bits >> 0) & 0xFF);
217 subdevice = 0;
218 function = bitrev8((data->sony_bits >> 7) & 0xFD);
219 break;
220 case 20:
221 device = bitrev8((data->sony_bits >> 5) & 0xF8);
222 subdevice = bitrev8((data->sony_bits >> 0) & 0xFF);
223 function = bitrev8((data->sony_bits >> 12) & 0xFE);
224 break;
225 default:
226 IR_dprintk(1, "Sony invalid bitcount %u\n", data->count);
227 goto out;
228 }
229
230 scancode = device << 16 | subdevice << 8 | function;
231 IR_dprintk(1, "Sony(%u) scancode 0x%05x\n", data->count, scancode);
232 ir_keydown(input_dev, scancode, 0);
233 data->state = STATE_INACTIVE;
234 return 0;
235 }
236
237out:
238 IR_dprintk(1, "Sony decode failed at state %d (%uus %s)\n",
239 data->state, TO_US(ev.duration), TO_STR(ev.pulse));
240 data->state = STATE_INACTIVE;
241 return -EINVAL;
242}
243
244static int ir_sony_register(struct input_dev *input_dev)
245{
246 struct ir_input_dev *ir_dev = input_get_drvdata(input_dev);
247 struct decoder_data *data;
248 int rc;
249
250 rc = sysfs_create_group(&ir_dev->dev.kobj, &decoder_attribute_group);
251 if (rc < 0)
252 return rc;
253
254 data = kzalloc(sizeof(*data), GFP_KERNEL);
255 if (!data) {
256 sysfs_remove_group(&ir_dev->dev.kobj, &decoder_attribute_group);
257 return -ENOMEM;
258 }
259
260 data->ir_dev = ir_dev;
261 data->enabled = 1;
262
263 spin_lock(&decoder_lock);
264 list_add_tail(&data->list, &decoder_list);
265 spin_unlock(&decoder_lock);
266
267 return 0;
268}
269
270static int ir_sony_unregister(struct input_dev *input_dev)
271{
272 struct ir_input_dev *ir_dev = input_get_drvdata(input_dev);
273 static struct decoder_data *data;
274
275 data = get_decoder_data(ir_dev);
276 if (!data)
277 return 0;
278
279 sysfs_remove_group(&ir_dev->dev.kobj, &decoder_attribute_group);
280
281 spin_lock(&decoder_lock);
282 list_del(&data->list);
283 spin_unlock(&decoder_lock);
284
285 return 0;
286}
287
288static struct ir_raw_handler sony_handler = {
289 .decode = ir_sony_decode,
290 .raw_register = ir_sony_register,
291 .raw_unregister = ir_sony_unregister,
292};
293
294static int __init ir_sony_decode_init(void)
295{
296 ir_raw_handler_register(&sony_handler);
297
298 printk(KERN_INFO "IR Sony protocol handler initialized\n");
299 return 0;
300}
301
302static void __exit ir_sony_decode_exit(void)
303{
304 ir_raw_handler_unregister(&sony_handler);
305}
306
307module_init(ir_sony_decode_init);
308module_exit(ir_sony_decode_exit);
309
310MODULE_LICENSE("GPL");
311MODULE_AUTHOR("David Härdeman <david@hardeman.nu>");
312MODULE_DESCRIPTION("Sony IR protocol decoder");
diff --git a/drivers/media/IR/ir-sysfs.c b/drivers/media/IR/ir-sysfs.c
index 3ec760a98061..4c0bc32dcbaf 100644
--- a/drivers/media/IR/ir-sysfs.c
+++ b/drivers/media/IR/ir-sysfs.c
@@ -65,6 +65,8 @@ static ssize_t show_protocol(struct device *d,
65 s = "rc6"; 65 s = "rc6";
66 else if (ir_type == IR_TYPE_JVC) 66 else if (ir_type == IR_TYPE_JVC)
67 s = "jvc"; 67 s = "jvc";
68 else if (ir_type == IR_TYPE_SONY)
69 s = "sony";
68 else 70 else
69 s = "other"; 71 s = "other";
70 72
@@ -104,6 +106,8 @@ static ssize_t store_protocol(struct device *d,
104 ir_type |= IR_TYPE_NEC; 106 ir_type |= IR_TYPE_NEC;
105 if (!strcasecmp(buf, "jvc")) 107 if (!strcasecmp(buf, "jvc"))
106 ir_type |= IR_TYPE_JVC; 108 ir_type |= IR_TYPE_JVC;
109 if (!strcasecmp(buf, "sony"))
110 ir_type |= IR_TYPE_SONY;
107 } 111 }
108 112
109 if (!ir_type) { 113 if (!ir_type) {
diff --git a/include/media/rc-map.h b/include/media/rc-map.h
index 5814ec045559..280d1ed9a9a0 100644
--- a/include/media/rc-map.h
+++ b/include/media/rc-map.h
@@ -17,6 +17,7 @@
17#define IR_TYPE_NEC (1 << 2) 17#define IR_TYPE_NEC (1 << 2)
18#define IR_TYPE_RC6 (1 << 3) /* Philips RC6 protocol */ 18#define IR_TYPE_RC6 (1 << 3) /* Philips RC6 protocol */
19#define IR_TYPE_JVC (1 << 4) /* JVC protocol */ 19#define IR_TYPE_JVC (1 << 4) /* JVC protocol */
20#define IR_TYPE_SONY (1 << 5) /* Sony12/15/20 protocol */
20#define IR_TYPE_OTHER (1u << 31) 21#define IR_TYPE_OTHER (1u << 31)
21 22
22struct ir_scancode { 23struct ir_scancode {