ir-jvc-decoder.c (5518B)
1// SPDX-License-Identifier: GPL-2.0-only 2/* ir-jvc-decoder.c - handle JVC IR Pulse/Space protocol 3 * 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 space 33 * @dev: the struct rc_dev descriptor of the device 34 * @ev: the struct ir_raw_event descriptor of the pulse/space 35 * 36 * This function returns -EINVAL if the pulse violates the state machine 37 */ 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 else 101 break; 102 data->count++; 103 104 if (data->count == JVC_NBITS) 105 data->state = STATE_TRAILER_PULSE; 106 else 107 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 else 154 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 events 178 * 179 * @protocol: protocol to encode 180 * @scancode: scancode to encode 181 * @events: array of raw ir events to write into 182 * @max: maximum size of @events 183 * 184 * Returns: The number of events written. 185 * -ENOBUFS if there isn't enough space in the array to fit the 186 * 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");