aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/media/rc
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/media/rc')
-rw-r--r--drivers/media/rc/Kconfig9
-rw-r--r--drivers/media/rc/Makefile1
-rw-r--r--drivers/media/rc/ir-sharp-decoder.c200
-rw-r--r--drivers/media/rc/rc-core-priv.h6
4 files changed, 216 insertions, 0 deletions
diff --git a/drivers/media/rc/Kconfig b/drivers/media/rc/Kconfig
index 904f11367c29..3b25887a9c09 100644
--- a/drivers/media/rc/Kconfig
+++ b/drivers/media/rc/Kconfig
@@ -106,6 +106,15 @@ config IR_SANYO_DECODER
106 uses the Sanyo protocol (Sanyo, Aiwa, Chinon remotes), 106 uses the Sanyo protocol (Sanyo, Aiwa, Chinon remotes),
107 and you need software decoding support. 107 and you need software decoding support.
108 108
109config IR_SHARP_DECODER
110 tristate "Enable IR raw decoder for the Sharp protocol"
111 depends on RC_CORE
112 default y
113
114 ---help---
115 Enable this option if you have an infrared remote control which
116 uses the Sharp protocol, and you need software decoding support.
117
109config IR_MCE_KBD_DECODER 118config IR_MCE_KBD_DECODER
110 tristate "Enable IR raw decoder for the MCE keyboard/mouse protocol" 119 tristate "Enable IR raw decoder for the MCE keyboard/mouse protocol"
111 depends on RC_CORE 120 depends on RC_CORE
diff --git a/drivers/media/rc/Makefile b/drivers/media/rc/Makefile
index f4eb32c0a455..36dafed412dd 100644
--- a/drivers/media/rc/Makefile
+++ b/drivers/media/rc/Makefile
@@ -11,6 +11,7 @@ obj-$(CONFIG_IR_JVC_DECODER) += ir-jvc-decoder.o
11obj-$(CONFIG_IR_SONY_DECODER) += ir-sony-decoder.o 11obj-$(CONFIG_IR_SONY_DECODER) += ir-sony-decoder.o
12obj-$(CONFIG_IR_RC5_SZ_DECODER) += ir-rc5-sz-decoder.o 12obj-$(CONFIG_IR_RC5_SZ_DECODER) += ir-rc5-sz-decoder.o
13obj-$(CONFIG_IR_SANYO_DECODER) += ir-sanyo-decoder.o 13obj-$(CONFIG_IR_SANYO_DECODER) += ir-sanyo-decoder.o
14obj-$(CONFIG_IR_SHARP_DECODER) += ir-sharp-decoder.o
14obj-$(CONFIG_IR_MCE_KBD_DECODER) += ir-mce_kbd-decoder.o 15obj-$(CONFIG_IR_MCE_KBD_DECODER) += ir-mce_kbd-decoder.o
15obj-$(CONFIG_IR_LIRC_CODEC) += ir-lirc-codec.o 16obj-$(CONFIG_IR_LIRC_CODEC) += ir-lirc-codec.o
16 17
diff --git a/drivers/media/rc/ir-sharp-decoder.c b/drivers/media/rc/ir-sharp-decoder.c
new file mode 100644
index 000000000000..4c17be5d68ba
--- /dev/null
+++ b/drivers/media/rc/ir-sharp-decoder.c
@@ -0,0 +1,200 @@
1/* ir-sharp-decoder.c - handle Sharp IR Pulse/Space protocol
2 *
3 * Copyright (C) 2013-2014 Imagination Technologies Ltd.
4 *
5 * Based on NEC decoder:
6 * Copyright (C) 2010 by Mauro Carvalho Chehab <mchehab@redhat.com>
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation version 2 of the License.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 */
17
18#include <linux/bitrev.h>
19#include <linux/module.h>
20#include "rc-core-priv.h"
21
22#define SHARP_NBITS 15
23#define SHARP_UNIT 40000 /* ns */
24#define SHARP_BIT_PULSE (8 * SHARP_UNIT) /* 320us */
25#define SHARP_BIT_0_PERIOD (25 * SHARP_UNIT) /* 1ms (680us space) */
26#define SHARP_BIT_1_PERIOD (50 * SHARP_UNIT) /* 2ms (1680ms space) */
27#define SHARP_ECHO_SPACE (1000 * SHARP_UNIT) /* 40 ms */
28#define SHARP_TRAILER_SPACE (125 * SHARP_UNIT) /* 5 ms (even longer) */
29
30enum sharp_state {
31 STATE_INACTIVE,
32 STATE_BIT_PULSE,
33 STATE_BIT_SPACE,
34 STATE_TRAILER_PULSE,
35 STATE_ECHO_SPACE,
36 STATE_TRAILER_SPACE,
37};
38
39/**
40 * ir_sharp_decode() - Decode one Sharp pulse or space
41 * @dev: the struct rc_dev descriptor of the device
42 * @duration: the struct ir_raw_event descriptor of the pulse/space
43 *
44 * This function returns -EINVAL if the pulse violates the state machine
45 */
46static int ir_sharp_decode(struct rc_dev *dev, struct ir_raw_event ev)
47{
48 struct sharp_dec *data = &dev->raw->sharp;
49 u32 msg, echo, address, command, scancode;
50
51 if (!(dev->enabled_protocols & RC_BIT_SHARP))
52 return 0;
53
54 if (!is_timing_event(ev)) {
55 if (ev.reset)
56 data->state = STATE_INACTIVE;
57 return 0;
58 }
59
60 IR_dprintk(2, "Sharp decode started at state %d (%uus %s)\n",
61 data->state, TO_US(ev.duration), TO_STR(ev.pulse));
62
63 switch (data->state) {
64
65 case STATE_INACTIVE:
66 if (!ev.pulse)
67 break;
68
69 if (!eq_margin(ev.duration, SHARP_BIT_PULSE,
70 SHARP_BIT_PULSE / 2))
71 break;
72
73 data->count = 0;
74 data->pulse_len = ev.duration;
75 data->state = STATE_BIT_SPACE;
76 return 0;
77
78 case STATE_BIT_PULSE:
79 if (!ev.pulse)
80 break;
81
82 if (!eq_margin(ev.duration, SHARP_BIT_PULSE,
83 SHARP_BIT_PULSE / 2))
84 break;
85
86 data->pulse_len = ev.duration;
87 data->state = STATE_BIT_SPACE;
88 return 0;
89
90 case STATE_BIT_SPACE:
91 if (ev.pulse)
92 break;
93
94 data->bits <<= 1;
95 if (eq_margin(data->pulse_len + ev.duration, SHARP_BIT_1_PERIOD,
96 SHARP_BIT_PULSE * 2))
97 data->bits |= 1;
98 else if (!eq_margin(data->pulse_len + ev.duration,
99 SHARP_BIT_0_PERIOD, SHARP_BIT_PULSE * 2))
100 break;
101 data->count++;
102
103 if (data->count == SHARP_NBITS ||
104 data->count == SHARP_NBITS * 2)
105 data->state = STATE_TRAILER_PULSE;
106 else
107 data->state = STATE_BIT_PULSE;
108
109 return 0;
110
111 case STATE_TRAILER_PULSE:
112 if (!ev.pulse)
113 break;
114
115 if (!eq_margin(ev.duration, SHARP_BIT_PULSE,
116 SHARP_BIT_PULSE / 2))
117 break;
118
119 if (data->count == SHARP_NBITS) {
120 /* exp,chk bits should be 1,0 */
121 if ((data->bits & 0x3) != 0x2)
122 break;
123 data->state = STATE_ECHO_SPACE;
124 } else {
125 data->state = STATE_TRAILER_SPACE;
126 }
127 return 0;
128
129 case STATE_ECHO_SPACE:
130 if (ev.pulse)
131 break;
132
133 if (!eq_margin(ev.duration, SHARP_ECHO_SPACE,
134 SHARP_ECHO_SPACE / 4))
135 break;
136
137 data->state = STATE_BIT_PULSE;
138
139 return 0;
140
141 case STATE_TRAILER_SPACE:
142 if (ev.pulse)
143 break;
144
145 if (!geq_margin(ev.duration, SHARP_TRAILER_SPACE,
146 SHARP_BIT_PULSE / 2))
147 break;
148
149 /* Validate - command, ext, chk should be inverted in 2nd */
150 msg = (data->bits >> 15) & 0x7fff;
151 echo = data->bits & 0x7fff;
152 if ((msg ^ echo) != 0x3ff) {
153 IR_dprintk(1,
154 "Sharp checksum error: received 0x%04x, 0x%04x\n",
155 msg, echo);
156 break;
157 }
158
159 address = bitrev8((msg >> 7) & 0xf8);
160 command = bitrev8((msg >> 2) & 0xff);
161
162 scancode = address << 8 | command;
163 IR_dprintk(1, "Sharp scancode 0x%04x\n", scancode);
164
165 rc_keydown(dev, scancode, 0);
166 data->state = STATE_INACTIVE;
167 return 0;
168 }
169
170 IR_dprintk(1, "Sharp decode failed at count %d state %d (%uus %s)\n",
171 data->count, data->state, TO_US(ev.duration),
172 TO_STR(ev.pulse));
173 data->state = STATE_INACTIVE;
174 return -EINVAL;
175}
176
177static struct ir_raw_handler sharp_handler = {
178 .protocols = RC_BIT_SHARP,
179 .decode = ir_sharp_decode,
180};
181
182static int __init ir_sharp_decode_init(void)
183{
184 ir_raw_handler_register(&sharp_handler);
185
186 pr_info("IR Sharp protocol handler initialized\n");
187 return 0;
188}
189
190static void __exit ir_sharp_decode_exit(void)
191{
192 ir_raw_handler_unregister(&sharp_handler);
193}
194
195module_init(ir_sharp_decode_init);
196module_exit(ir_sharp_decode_exit);
197
198MODULE_LICENSE("GPL");
199MODULE_AUTHOR("James Hogan <james.hogan@imgtec.com>");
200MODULE_DESCRIPTION("Sharp IR protocol decoder");
diff --git a/drivers/media/rc/rc-core-priv.h b/drivers/media/rc/rc-core-priv.h
index 70a180bb0bd0..c40d6660acac 100644
--- a/drivers/media/rc/rc-core-priv.h
+++ b/drivers/media/rc/rc-core-priv.h
@@ -88,6 +88,12 @@ struct ir_raw_event_ctrl {
88 unsigned count; 88 unsigned count;
89 u64 bits; 89 u64 bits;
90 } sanyo; 90 } sanyo;
91 struct sharp_dec {
92 int state;
93 unsigned count;
94 u32 bits;
95 unsigned int pulse_len;
96 } sharp;
91 struct mce_kbd_dec { 97 struct mce_kbd_dec {
92 struct input_dev *idev; 98 struct input_dev *idev;
93 struct timer_list rx_timeout; 99 struct timer_list rx_timeout;