History

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.

Sean Young committed 8 years ago

Commit 447dcc01 parent 8d406888 files · +220 −5Browse files

Unified · Split

8 files
  1. drivers/media/rc/Kconfig +9 −0
  2. drivers/media/rc/Makefile +1 −0
  3. drivers/media/rc/ir-imon-decoder.c +193 −0
  4. drivers/media/rc/keymaps/rc-imon-pad.c +1 −2
  5. drivers/media/rc/rc-core-priv.h +6 −0
  6. drivers/media/rc/rc-main.c +3 −0
  7. include/media/rc-map.h +5 −3
  8. include/uapi/linux/lirc.h +2 −0
drivers/media/rc/Kconfig+9−0
@@ -111,6 +111,15 @@ config IR_XMP_DECODER · 110 unmodified lines
111 ---help---111 ---help---
112 Enable this option if you have IR with XMP protocol, and112 Enable this option if you have IR with XMP protocol, and
113 if the IR is decoded in software113 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_DECODERS123endif #RC_DECODERS
115 124
116menuconfig RC_DEVICES125menuconfig RC_DEVICES
drivers/media/rc/Makefile+1−0
@@ -14,6 +14,7 @@ obj-$(CONFIG_IR_SANYO_DECODER) += ir-sanyo-decoder.o · 13 unmodified lines
14obj-$(CONFIG_IR_SHARP_DECODER) += ir-sharp-decoder.o14obj-$(CONFIG_IR_SHARP_DECODER) += ir-sharp-decoder.o
15obj-$(CONFIG_IR_MCE_KBD_DECODER) += ir-mce_kbd-decoder.o15obj-$(CONFIG_IR_MCE_KBD_DECODER) += ir-mce_kbd-decoder.o
16obj-$(CONFIG_IR_XMP_DECODER) += ir-xmp-decoder.o16obj-$(CONFIG_IR_XMP_DECODER) += ir-xmp-decoder.o
17obj-$(CONFIG_IR_IMON_DECODER) += ir-imon-decoder.o
17 18
18# stand-alone IR receivers/transmitters19# stand-alone IR receivers/transmitters
19obj-$(CONFIG_RC_ATI_REMOTE) += ati_remote.o20obj-$(CONFIG_RC_ATI_REMOTE) += ati_remote.o
drivers/media/rc/ir-imon-decoder.c+193−0
@@ -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");
drivers/media/rc/keymaps/rc-imon-pad.c+1−2
@@ -134,8 +134,7 @@ static struct rc_map_list imon_pad_map = { · 133 unmodified lines
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};
drivers/media/rc/rc-core-priv.h+6−0
@@ -118,6 +118,12 @@ struct ir_raw_event_ctrl { · 117 unmodified lines
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 */
drivers/media/rc/rc-main.c+3−0
@@ -68,6 +68,8 @@ static const struct { · 67 unmodified lines
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 { · 930 unmodified lines
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/**
include/media/rc-map.h+5−3
@@ -36,6 +36,7 @@ · 35 unmodified lines
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 @@ · 7 unmodified lines
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 @@ · 6 unmodified lines
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 @@ · 6 unmodified lines
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)
include/uapi/linux/lirc.h+2−0
@@ -186,6 +186,7 @@ struct lirc_scancode { · 185 unmodified lines
186 * @RC_PROTO_SHARP: Sharp protocol186 * @RC_PROTO_SHARP: Sharp protocol
187 * @RC_PROTO_XMP: XMP protocol187 * @RC_PROTO_XMP: XMP protocol
188 * @RC_PROTO_CEC: CEC protocol188 * @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 { · 19 unmodified lines
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#endif218#endif