aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSean Young <sean@mess.org>2017-12-03 11:06:54 -0500
committerMauro Carvalho Chehab <mchehab@s-opensource.com>2018-03-21 11:12:29 -0400
commit447dcc0cf12922fcda67731559dd970bde7b35a6 (patch)
tree0fc2c5a035448b53e44d19b9bd150fb52ffdc2e9
parent8d4068810d9926250dd2435719a080b889eb44c3 (diff)
media: rc: add new imon protocol decoder and encoder
This makes it possible to use the various iMON remotes with any raw IR RC device. Signed-off-by: Sean Young <sean@mess.org> Signed-off-by: Mauro Carvalho Chehab <mchehab@s-opensource.com>
-rw-r--r--drivers/media/rc/Kconfig9
-rw-r--r--drivers/media/rc/Makefile1
-rw-r--r--drivers/media/rc/ir-imon-decoder.c193
-rw-r--r--drivers/media/rc/keymaps/rc-imon-pad.c3
-rw-r--r--drivers/media/rc/rc-core-priv.h6
-rw-r--r--drivers/media/rc/rc-main.c3
-rw-r--r--include/media/rc-map.h8
-rw-r--r--include/uapi/linux/lirc.h2
8 files changed, 220 insertions, 5 deletions
diff --git a/drivers/media/rc/Kconfig b/drivers/media/rc/Kconfig
index 7ad05a6ef350..eb2c3b6eca7f 100644
--- a/drivers/media/rc/Kconfig
+++ b/drivers/media/rc/Kconfig
@@ -111,6 +111,15 @@ config IR_XMP_DECODER
111 ---help--- 111 ---help---
112 Enable this option if you have IR with XMP protocol, and 112 Enable this option if you have IR with XMP protocol, and
113 if the IR is decoded in software 113 if the IR is decoded in software
114
115config IR_IMON_DECODER
116 tristate "Enable IR raw decoder for the iMON protocol"
117 depends on RC_CORE
118 ---help---
119 Enable this option if you have iMON PAD or Antec Veris infrared
120 remote control and you would like to use it with a raw IR
121 receiver, or if you wish to use an encoder to transmit this IR.
122
114endif #RC_DECODERS 123endif #RC_DECODERS
115 124
116menuconfig RC_DEVICES 125menuconfig RC_DEVICES
diff --git a/drivers/media/rc/Makefile b/drivers/media/rc/Makefile
index e098e127b26a..2e1c87066f6c 100644
--- a/drivers/media/rc/Makefile
+++ b/drivers/media/rc/Makefile
@@ -14,6 +14,7 @@ obj-$(CONFIG_IR_SANYO_DECODER) += ir-sanyo-decoder.o
14obj-$(CONFIG_IR_SHARP_DECODER) += ir-sharp-decoder.o 14obj-$(CONFIG_IR_SHARP_DECODER) += ir-sharp-decoder.o
15obj-$(CONFIG_IR_MCE_KBD_DECODER) += ir-mce_kbd-decoder.o 15obj-$(CONFIG_IR_MCE_KBD_DECODER) += ir-mce_kbd-decoder.o
16obj-$(CONFIG_IR_XMP_DECODER) += ir-xmp-decoder.o 16obj-$(CONFIG_IR_XMP_DECODER) += ir-xmp-decoder.o
17obj-$(CONFIG_IR_IMON_DECODER) += ir-imon-decoder.o
17 18
18# stand-alone IR receivers/transmitters 19# stand-alone IR receivers/transmitters
19obj-$(CONFIG_RC_ATI_REMOTE) += ati_remote.o 20obj-$(CONFIG_RC_ATI_REMOTE) += ati_remote.o
diff --git a/drivers/media/rc/ir-imon-decoder.c b/drivers/media/rc/ir-imon-decoder.c
new file mode 100644
index 000000000000..a1ff06a26542
--- /dev/null
+++ b/drivers/media/rc/ir-imon-decoder.c
@@ -0,0 +1,193 @@
1// SPDX-License-Identifier: GPL-2.0+
2// ir-imon-decoder.c - handle iMon protocol
3//
4// Copyright (C) 2018 by Sean Young <sean@mess.org>
5
6#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
7
8#include <linux/module.h>
9#include "rc-core-priv.h"
10
11#define IMON_UNIT 415662 /* ns */
12#define IMON_BITS 30
13#define IMON_CHKBITS (BIT(30) | BIT(25) | BIT(24) | BIT(22) | \
14 BIT(21) | BIT(20) | BIT(19) | BIT(18) | \
15 BIT(17) | BIT(16) | BIT(14) | BIT(13) | \
16 BIT(12) | BIT(11) | BIT(10) | BIT(9))
17
18/*
19 * This protocol has 30 bits. The format is one IMON_UNIT header pulse,
20 * followed by 30 bits. Each bit is one IMON_UNIT check field, and then
21 * one IMON_UNIT field with the actual bit (1=space, 0=pulse).
22 * The check field is always space for some bits, for others it is pulse if
23 * both the preceding and current bit are zero, else space. IMON_CHKBITS
24 * defines which bits are of type check.
25 *
26 * There is no way to distinguish an incomplete message from one where
27 * the lower bits are all set, iow. the last pulse is for the lowest
28 * bit which is 0.
29 */
30enum imon_state {
31 STATE_INACTIVE,
32 STATE_BIT_CHK,
33 STATE_BIT_START,
34 STATE_FINISHED
35};
36
37/**
38 * ir_imon_decode() - Decode one iMON pulse or space
39 * @dev: the struct rc_dev descriptor of the device
40 * @ev: the struct ir_raw_event descriptor of the pulse/space
41 *
42 * This function returns -EINVAL if the pulse violates the state machine
43 */
44static int ir_imon_decode(struct rc_dev *dev, struct ir_raw_event ev)
45{
46 struct imon_dec *data = &dev->raw->imon;
47
48 if (!is_timing_event(ev)) {
49 if (ev.reset)
50 data->state = STATE_INACTIVE;
51 return 0;
52 }
53
54 dev_dbg(&dev->dev,
55 "iMON decode started at state %d bitno %d (%uus %s)\n",
56 data->state, data->count, TO_US(ev.duration),
57 TO_STR(ev.pulse));
58
59 for (;;) {
60 if (!geq_margin(ev.duration, IMON_UNIT, IMON_UNIT / 2))
61 return 0;
62
63 decrease_duration(&ev, IMON_UNIT);
64
65 switch (data->state) {
66 case STATE_INACTIVE:
67 if (ev.pulse) {
68 data->state = STATE_BIT_CHK;
69 data->bits = 0;
70 data->count = IMON_BITS;
71 }
72 break;
73 case STATE_BIT_CHK:
74 if (IMON_CHKBITS & BIT(data->count))
75 data->last_chk = ev.pulse;
76 else if (ev.pulse)
77 goto err_out;
78 data->state = STATE_BIT_START;
79 break;
80 case STATE_BIT_START:
81 data->bits <<= 1;
82 if (!ev.pulse)
83 data->bits |= 1;
84
85 if (IMON_CHKBITS & BIT(data->count)) {
86 if (data->last_chk != !(data->bits & 3))
87 goto err_out;
88 }
89
90 if (!data->count--)
91 data->state = STATE_FINISHED;
92 else
93 data->state = STATE_BIT_CHK;
94 break;
95 case STATE_FINISHED:
96 if (ev.pulse)
97 goto err_out;
98 rc_keydown(dev, RC_PROTO_IMON, data->bits, 0);
99 data->state = STATE_INACTIVE;
100 break;
101 }
102 }
103
104err_out:
105 dev_dbg(&dev->dev,
106 "iMON decode failed at state %d bitno %d (%uus %s)\n",
107 data->state, data->count, TO_US(ev.duration),
108 TO_STR(ev.pulse));
109
110 data->state = STATE_INACTIVE;
111
112 return -EINVAL;
113}
114
115/**
116 * ir_imon_encode() - Encode a scancode as a stream of raw events
117 *
118 * @protocol: protocol to encode
119 * @scancode: scancode to encode
120 * @events: array of raw ir events to write into
121 * @max: maximum size of @events
122 *
123 * Returns: The number of events written.
124 * -ENOBUFS if there isn't enough space in the array to fit the
125 * encoding. In this case all @max events will have been written.
126 */
127static int ir_imon_encode(enum rc_proto protocol, u32 scancode,
128 struct ir_raw_event *events, unsigned int max)
129{
130 struct ir_raw_event *e = events;
131 int i, pulse;
132
133 if (!max--)
134 return -ENOBUFS;
135 init_ir_raw_event_duration(e, 1, IMON_UNIT);
136
137 for (i = IMON_BITS; i >= 0; i--) {
138 if (BIT(i) & IMON_CHKBITS)
139 pulse = !(scancode & (BIT(i) | BIT(i + 1)));
140 else
141 pulse = 0;
142
143 if (pulse == e->pulse) {
144 e->duration += IMON_UNIT;
145 } else {
146 if (!max--)
147 return -ENOBUFS;
148 init_ir_raw_event_duration(++e, pulse, IMON_UNIT);
149 }
150
151 pulse = !(scancode & BIT(i));
152
153 if (pulse == e->pulse) {
154 e->duration += IMON_UNIT;
155 } else {
156 if (!max--)
157 return -ENOBUFS;
158 init_ir_raw_event_duration(++e, pulse, IMON_UNIT);
159 }
160 }
161
162 if (e->pulse)
163 e++;
164
165 return e - events;
166}
167
168static struct ir_raw_handler imon_handler = {
169 .protocols = RC_PROTO_BIT_IMON,
170 .decode = ir_imon_decode,
171 .encode = ir_imon_encode,
172 .carrier = 38000,
173};
174
175static int __init ir_imon_decode_init(void)
176{
177 ir_raw_handler_register(&imon_handler);
178
179 pr_info("IR iMON protocol handler initialized\n");
180 return 0;
181}
182
183static void __exit ir_imon_decode_exit(void)
184{
185 ir_raw_handler_unregister(&imon_handler);
186}
187
188module_init(ir_imon_decode_init);
189module_exit(ir_imon_decode_exit);
190
191MODULE_LICENSE("GPL");
192MODULE_AUTHOR("Sean Young <sean@mess.org>");
193MODULE_DESCRIPTION("iMON IR protocol decoder");
diff --git a/drivers/media/rc/keymaps/rc-imon-pad.c b/drivers/media/rc/keymaps/rc-imon-pad.c
index a7296ffbf218..8501cf0a3253 100644
--- a/drivers/media/rc/keymaps/rc-imon-pad.c
+++ b/drivers/media/rc/keymaps/rc-imon-pad.c
@@ -134,8 +134,7 @@ static struct rc_map_list imon_pad_map = {
134 .map = { 134 .map = {
135 .scan = imon_pad, 135 .scan = imon_pad,
136 .size = ARRAY_SIZE(imon_pad), 136 .size = ARRAY_SIZE(imon_pad),
137 /* actual protocol details unknown, hardware decoder */ 137 .rc_proto = RC_PROTO_IMON,
138 .rc_proto = RC_PROTO_OTHER,
139 .name = RC_MAP_IMON_PAD, 138 .name = RC_MAP_IMON_PAD,
140 } 139 }
141}; 140};
diff --git a/drivers/media/rc/rc-core-priv.h b/drivers/media/rc/rc-core-priv.h
index 5e80b4273e2d..e0e6a17460f6 100644
--- a/drivers/media/rc/rc-core-priv.h
+++ b/drivers/media/rc/rc-core-priv.h
@@ -118,6 +118,12 @@ struct ir_raw_event_ctrl {
118 unsigned count; 118 unsigned count;
119 u32 durations[16]; 119 u32 durations[16];
120 } xmp; 120 } xmp;
121 struct imon_dec {
122 int state;
123 int count;
124 int last_chk;
125 unsigned int bits;
126 } imon;
121}; 127};
122 128
123/* macros for IR decoders */ 129/* macros for IR decoders */
diff --git a/drivers/media/rc/rc-main.c b/drivers/media/rc/rc-main.c
index 8621761a680f..b67be33bd62f 100644
--- a/drivers/media/rc/rc-main.c
+++ b/drivers/media/rc/rc-main.c
@@ -68,6 +68,8 @@ static const struct {
68 .scancode_bits = 0x1fff, .repeat_period = 250 }, 68 .scancode_bits = 0x1fff, .repeat_period = 250 },
69 [RC_PROTO_XMP] = { .name = "xmp", .repeat_period = 250 }, 69 [RC_PROTO_XMP] = { .name = "xmp", .repeat_period = 250 },
70 [RC_PROTO_CEC] = { .name = "cec", .repeat_period = 550 }, 70 [RC_PROTO_CEC] = { .name = "cec", .repeat_period = 550 },
71 [RC_PROTO_IMON] = { .name = "imon",
72 .scancode_bits = 0x7fffffff, .repeat_period = 250 },
71}; 73};
72 74
73/* Used to keep track of known keymaps */ 75/* Used to keep track of known keymaps */
@@ -1004,6 +1006,7 @@ static const struct {
1004 RC_PROTO_BIT_MCIR2_MSE, "mce_kbd", "ir-mce_kbd-decoder" }, 1006 RC_PROTO_BIT_MCIR2_MSE, "mce_kbd", "ir-mce_kbd-decoder" },
1005 { RC_PROTO_BIT_XMP, "xmp", "ir-xmp-decoder" }, 1007 { RC_PROTO_BIT_XMP, "xmp", "ir-xmp-decoder" },
1006 { RC_PROTO_BIT_CEC, "cec", NULL }, 1008 { RC_PROTO_BIT_CEC, "cec", NULL },
1009 { RC_PROTO_BIT_IMON, "imon", "ir-imon-decoder" },
1007}; 1010};
1008 1011
1009/** 1012/**
diff --git a/include/media/rc-map.h b/include/media/rc-map.h
index 7fc84991bd12..bfa3017cecba 100644
--- a/include/media/rc-map.h
+++ b/include/media/rc-map.h
@@ -36,6 +36,7 @@
36#define RC_PROTO_BIT_SHARP BIT_ULL(RC_PROTO_SHARP) 36#define RC_PROTO_BIT_SHARP BIT_ULL(RC_PROTO_SHARP)
37#define RC_PROTO_BIT_XMP BIT_ULL(RC_PROTO_XMP) 37#define RC_PROTO_BIT_XMP BIT_ULL(RC_PROTO_XMP)
38#define RC_PROTO_BIT_CEC BIT_ULL(RC_PROTO_CEC) 38#define RC_PROTO_BIT_CEC BIT_ULL(RC_PROTO_CEC)
39#define RC_PROTO_BIT_IMON BIT_ULL(RC_PROTO_IMON)
39 40
40#define RC_PROTO_BIT_ALL \ 41#define RC_PROTO_BIT_ALL \
41 (RC_PROTO_BIT_UNKNOWN | RC_PROTO_BIT_OTHER | \ 42 (RC_PROTO_BIT_UNKNOWN | RC_PROTO_BIT_OTHER | \
@@ -49,7 +50,8 @@
49 RC_PROTO_BIT_RC6_0 | RC_PROTO_BIT_RC6_6A_20 | \ 50 RC_PROTO_BIT_RC6_0 | RC_PROTO_BIT_RC6_6A_20 | \
50 RC_PROTO_BIT_RC6_6A_24 | RC_PROTO_BIT_RC6_6A_32 | \ 51 RC_PROTO_BIT_RC6_6A_24 | RC_PROTO_BIT_RC6_6A_32 | \
51 RC_PROTO_BIT_RC6_MCE | RC_PROTO_BIT_SHARP | \ 52 RC_PROTO_BIT_RC6_MCE | RC_PROTO_BIT_SHARP | \
52 RC_PROTO_BIT_XMP | RC_PROTO_BIT_CEC) 53 RC_PROTO_BIT_XMP | RC_PROTO_BIT_CEC | \
54 RC_PROTO_BIT_IMON)
53/* All rc protocols for which we have decoders */ 55/* All rc protocols for which we have decoders */
54#define RC_PROTO_BIT_ALL_IR_DECODER \ 56#define RC_PROTO_BIT_ALL_IR_DECODER \
55 (RC_PROTO_BIT_RC5 | RC_PROTO_BIT_RC5X_20 | \ 57 (RC_PROTO_BIT_RC5 | RC_PROTO_BIT_RC5X_20 | \
@@ -62,7 +64,7 @@
62 RC_PROTO_BIT_RC6_0 | RC_PROTO_BIT_RC6_6A_20 | \ 64 RC_PROTO_BIT_RC6_0 | RC_PROTO_BIT_RC6_6A_20 | \
63 RC_PROTO_BIT_RC6_6A_24 | RC_PROTO_BIT_RC6_6A_32 | \ 65 RC_PROTO_BIT_RC6_6A_24 | RC_PROTO_BIT_RC6_6A_32 | \
64 RC_PROTO_BIT_RC6_MCE | RC_PROTO_BIT_SHARP | \ 66 RC_PROTO_BIT_RC6_MCE | RC_PROTO_BIT_SHARP | \
65 RC_PROTO_BIT_XMP) 67 RC_PROTO_BIT_XMP | RC_PROTO_BIT_IMON)
66 68
67#define RC_PROTO_BIT_ALL_IR_ENCODER \ 69#define RC_PROTO_BIT_ALL_IR_ENCODER \
68 (RC_PROTO_BIT_RC5 | RC_PROTO_BIT_RC5X_20 | \ 70 (RC_PROTO_BIT_RC5 | RC_PROTO_BIT_RC5X_20 | \
@@ -75,7 +77,7 @@
75 RC_PROTO_BIT_RC6_0 | RC_PROTO_BIT_RC6_6A_20 | \ 77 RC_PROTO_BIT_RC6_0 | RC_PROTO_BIT_RC6_6A_20 | \
76 RC_PROTO_BIT_RC6_6A_24 | \ 78 RC_PROTO_BIT_RC6_6A_24 | \
77 RC_PROTO_BIT_RC6_6A_32 | RC_PROTO_BIT_RC6_MCE | \ 79 RC_PROTO_BIT_RC6_6A_32 | RC_PROTO_BIT_RC6_MCE | \
78 RC_PROTO_BIT_SHARP) 80 RC_PROTO_BIT_SHARP | RC_PROTO_BIT_IMON)
79 81
80#define RC_SCANCODE_UNKNOWN(x) (x) 82#define RC_SCANCODE_UNKNOWN(x) (x)
81#define RC_SCANCODE_OTHER(x) (x) 83#define RC_SCANCODE_OTHER(x) (x)
diff --git a/include/uapi/linux/lirc.h b/include/uapi/linux/lirc.h
index 4fe580d36e41..948d9a491083 100644
--- a/include/uapi/linux/lirc.h
+++ b/include/uapi/linux/lirc.h
@@ -186,6 +186,7 @@ struct lirc_scancode {
186 * @RC_PROTO_SHARP: Sharp protocol 186 * @RC_PROTO_SHARP: Sharp protocol
187 * @RC_PROTO_XMP: XMP protocol 187 * @RC_PROTO_XMP: XMP protocol
188 * @RC_PROTO_CEC: CEC protocol 188 * @RC_PROTO_CEC: CEC protocol
189 * @RC_PROTO_IMON: iMon Pad protocol
189 */ 190 */
190enum rc_proto { 191enum rc_proto {
191 RC_PROTO_UNKNOWN = 0, 192 RC_PROTO_UNKNOWN = 0,
@@ -211,6 +212,7 @@ enum rc_proto {
211 RC_PROTO_SHARP = 20, 212 RC_PROTO_SHARP = 20,
212 RC_PROTO_XMP = 21, 213 RC_PROTO_XMP = 21,
213 RC_PROTO_CEC = 22, 214 RC_PROTO_CEC = 22,
215 RC_PROTO_IMON = 23,
214}; 216};
215 217
216#endif 218#endif