230 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/* ir-jvc-decoder.c - handle JVC IR Pulse/Space protocol3 *4 * Copyright (C) 2010 by David Härdeman <david@hardeman.nu>5 */6 7#include <linux/bitrev.h>8#include <linux/module.h>9#include "rc-core-priv.h"10 11#define JVC_NBITS 16 /* dev(8) + func(8) */12#define JVC_UNIT 525 /* us */13#define JVC_HEADER_PULSE (16 * JVC_UNIT) /* lack of header -> repeat */14#define JVC_HEADER_SPACE (8 * JVC_UNIT)15#define JVC_BIT_PULSE (1 * JVC_UNIT)16#define JVC_BIT_0_SPACE (1 * JVC_UNIT)17#define JVC_BIT_1_SPACE (3 * JVC_UNIT)18#define JVC_TRAILER_PULSE (1 * JVC_UNIT)19#define JVC_TRAILER_SPACE (35 * JVC_UNIT)20 21enum jvc_state {22 STATE_INACTIVE,23 STATE_HEADER_SPACE,24 STATE_BIT_PULSE,25 STATE_BIT_SPACE,26 STATE_TRAILER_PULSE,27 STATE_TRAILER_SPACE,28 STATE_CHECK_REPEAT,29};30 31/**32 * ir_jvc_decode() - Decode one JVC pulse or space33 * @dev: the struct rc_dev descriptor of the device34 * @ev: the struct ir_raw_event descriptor of the pulse/space35 *36 * This function returns -EINVAL if the pulse violates the state machine37 */38static int ir_jvc_decode(struct rc_dev *dev, struct ir_raw_event ev)39{40 struct jvc_dec *data = &dev->raw->jvc;41 42 if (!is_timing_event(ev)) {43 if (ev.overflow)44 data->state = STATE_INACTIVE;45 return 0;46 }47 48 if (!geq_margin(ev.duration, JVC_UNIT, JVC_UNIT / 2))49 goto out;50 51 dev_dbg(&dev->dev, "JVC decode started at state %d (%uus %s)\n",52 data->state, ev.duration, TO_STR(ev.pulse));53 54again:55 switch (data->state) {56 57 case STATE_INACTIVE:58 if (!ev.pulse)59 break;60 61 if (!eq_margin(ev.duration, JVC_HEADER_PULSE, JVC_UNIT / 2))62 break;63 64 data->count = 0;65 data->first = true;66 data->toggle = !data->toggle;67 data->state = STATE_HEADER_SPACE;68 return 0;69 70 case STATE_HEADER_SPACE:71 if (ev.pulse)72 break;73 74 if (!eq_margin(ev.duration, JVC_HEADER_SPACE, JVC_UNIT / 2))75 break;76 77 data->state = STATE_BIT_PULSE;78 return 0;79 80 case STATE_BIT_PULSE:81 if (!ev.pulse)82 break;83 84 if (!eq_margin(ev.duration, JVC_BIT_PULSE, JVC_UNIT / 2))85 break;86 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(ev.duration, JVC_BIT_1_SPACE, JVC_UNIT / 2)) {96 data->bits |= 1;97 decrease_duration(&ev, JVC_BIT_1_SPACE);98 } else if (eq_margin(ev.duration, JVC_BIT_0_SPACE, JVC_UNIT / 2))99 decrease_duration(&ev, JVC_BIT_0_SPACE);100 else101 break;102 data->count++;103 104 if (data->count == JVC_NBITS)105 data->state = STATE_TRAILER_PULSE;106 else107 data->state = STATE_BIT_PULSE;108 return 0;109 110 case STATE_TRAILER_PULSE:111 if (!ev.pulse)112 break;113 114 if (!eq_margin(ev.duration, JVC_TRAILER_PULSE, JVC_UNIT / 2))115 break;116 117 data->state = STATE_TRAILER_SPACE;118 return 0;119 120 case STATE_TRAILER_SPACE:121 if (ev.pulse)122 break;123 124 if (!geq_margin(ev.duration, JVC_TRAILER_SPACE, JVC_UNIT / 2))125 break;126 127 if (data->first) {128 u32 scancode;129 scancode = (bitrev8((data->bits >> 8) & 0xff) << 8) |130 (bitrev8((data->bits >> 0) & 0xff) << 0);131 dev_dbg(&dev->dev, "JVC scancode 0x%04x\n", scancode);132 rc_keydown(dev, RC_PROTO_JVC, scancode, data->toggle);133 data->first = false;134 data->old_bits = data->bits;135 } else if (data->bits == data->old_bits) {136 dev_dbg(&dev->dev, "JVC repeat\n");137 rc_repeat(dev);138 } else {139 dev_dbg(&dev->dev, "JVC invalid repeat msg\n");140 break;141 }142 143 data->count = 0;144 data->state = STATE_CHECK_REPEAT;145 return 0;146 147 case STATE_CHECK_REPEAT:148 if (!ev.pulse)149 break;150 151 if (eq_margin(ev.duration, JVC_HEADER_PULSE, JVC_UNIT / 2))152 data->state = STATE_INACTIVE;153 else154 data->state = STATE_BIT_PULSE;155 goto again;156 }157 158out:159 dev_dbg(&dev->dev, "JVC decode failed at state %d (%uus %s)\n",160 data->state, ev.duration, TO_STR(ev.pulse));161 data->state = STATE_INACTIVE;162 return -EINVAL;163}164 165static const struct ir_raw_timings_pd ir_jvc_timings = {166 .header_pulse = JVC_HEADER_PULSE,167 .header_space = JVC_HEADER_SPACE,168 .bit_pulse = JVC_BIT_PULSE,169 .bit_space[0] = JVC_BIT_0_SPACE,170 .bit_space[1] = JVC_BIT_1_SPACE,171 .trailer_pulse = JVC_TRAILER_PULSE,172 .trailer_space = JVC_TRAILER_SPACE,173 .msb_first = 1,174};175 176/**177 * ir_jvc_encode() - Encode a scancode as a stream of raw events178 *179 * @protocol: protocol to encode180 * @scancode: scancode to encode181 * @events: array of raw ir events to write into182 * @max: maximum size of @events183 *184 * Returns: The number of events written.185 * -ENOBUFS if there isn't enough space in the array to fit the186 * encoding. In this case all @max events will have been written.187 */188static int ir_jvc_encode(enum rc_proto protocol, u32 scancode,189 struct ir_raw_event *events, unsigned int max)190{191 struct ir_raw_event *e = events;192 int ret;193 u32 raw = (bitrev8((scancode >> 8) & 0xff) << 8) |194 (bitrev8((scancode >> 0) & 0xff) << 0);195 196 ret = ir_raw_gen_pd(&e, max, &ir_jvc_timings, JVC_NBITS, raw);197 if (ret < 0)198 return ret;199 200 return e - events;201}202 203static struct ir_raw_handler jvc_handler = {204 .protocols = RC_PROTO_BIT_JVC,205 .decode = ir_jvc_decode,206 .encode = ir_jvc_encode,207 .carrier = 38000,208 .min_timeout = JVC_TRAILER_SPACE,209};210 211static int __init ir_jvc_decode_init(void)212{213 ir_raw_handler_register(&jvc_handler);214 215 printk(KERN_INFO "IR JVC protocol handler initialized\n");216 return 0;217}218 219static void __exit ir_jvc_decode_exit(void)220{221 ir_raw_handler_unregister(&jvc_handler);222}223 224module_init(ir_jvc_decode_init);225module_exit(ir_jvc_decode_exit);226 227MODULE_LICENSE("GPL");228MODULE_AUTHOR("David Härdeman <david@hardeman.nu>");229MODULE_DESCRIPTION("JVC IR protocol decoder");230