^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) // SPDX-License-Identifier: GPL-2.0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) // ir-rc5-decoder.c - decoder for RC5(x) and StreamZap protocols
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) //
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) // Copyright (C) 2010 by Mauro Carvalho Chehab
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) // Copyright (C) 2010 by Jarod Wilson <jarod@redhat.com>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) * This decoder handles the 14 bit RC5 protocol, 15 bit "StreamZap" protocol
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) * and 20 bit RC5x protocol.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) #include "rc-core-priv.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) #include <linux/module.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) #define RC5_NBITS 14
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) #define RC5_SZ_NBITS 15
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) #define RC5X_NBITS 20
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) #define CHECK_RC5X_NBITS 8
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) #define RC5_UNIT 889 /* us */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) #define RC5_BIT_START (1 * RC5_UNIT)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) #define RC5_BIT_END (1 * RC5_UNIT)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) #define RC5X_SPACE (4 * RC5_UNIT)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) #define RC5_TRAILER (6 * RC5_UNIT) /* In reality, approx 100 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) enum rc5_state {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) STATE_INACTIVE,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) STATE_BIT_START,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) STATE_BIT_END,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) STATE_CHECK_RC5X,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) STATE_FINISHED,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) * ir_rc5_decode() - Decode one RC-5 pulse or space
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) * @dev: the struct rc_dev descriptor of the device
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) * @ev: the struct ir_raw_event descriptor of the pulse/space
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) * This function returns -EINVAL if the pulse violates the state machine
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) static int ir_rc5_decode(struct rc_dev *dev, struct ir_raw_event ev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) struct rc5_dec *data = &dev->raw->rc5;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) u8 toggle;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) u32 scancode;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) enum rc_proto protocol;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) if (!is_timing_event(ev)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) if (ev.reset)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) data->state = STATE_INACTIVE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) if (!geq_margin(ev.duration, RC5_UNIT, RC5_UNIT / 2))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) again:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) dev_dbg(&dev->dev, "RC5(x/sz) decode started at state %i (%uus %s)\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) data->state, ev.duration, TO_STR(ev.pulse));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) if (!geq_margin(ev.duration, RC5_UNIT, RC5_UNIT / 2))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) switch (data->state) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) case STATE_INACTIVE:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) if (!ev.pulse)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) data->state = STATE_BIT_START;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) data->count = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) decrease_duration(&ev, RC5_BIT_START);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) goto again;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) case STATE_BIT_START:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) if (!ev.pulse && geq_margin(ev.duration, RC5_TRAILER, RC5_UNIT / 2)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) data->state = STATE_FINISHED;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) goto again;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) if (!eq_margin(ev.duration, RC5_BIT_START, RC5_UNIT / 2))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) data->bits <<= 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) if (!ev.pulse)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) data->bits |= 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) data->count++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) data->state = STATE_BIT_END;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) case STATE_BIT_END:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) if (data->count == CHECK_RC5X_NBITS)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) data->state = STATE_CHECK_RC5X;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) data->state = STATE_BIT_START;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) decrease_duration(&ev, RC5_BIT_END);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) goto again;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) case STATE_CHECK_RC5X:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) if (!ev.pulse && geq_margin(ev.duration, RC5X_SPACE, RC5_UNIT / 2)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) data->is_rc5x = true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) decrease_duration(&ev, RC5X_SPACE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) } else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) data->is_rc5x = false;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) data->state = STATE_BIT_START;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) goto again;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) case STATE_FINISHED:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) if (ev.pulse)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) if (data->is_rc5x && data->count == RC5X_NBITS) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) /* RC5X */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) u8 xdata, command, system;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) if (!(dev->enabled_protocols & RC_PROTO_BIT_RC5X_20)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) data->state = STATE_INACTIVE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) xdata = (data->bits & 0x0003F) >> 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) command = (data->bits & 0x00FC0) >> 6;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) system = (data->bits & 0x1F000) >> 12;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) toggle = (data->bits & 0x20000) ? 1 : 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) command += (data->bits & 0x40000) ? 0 : 0x40;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) scancode = system << 16 | command << 8 | xdata;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) protocol = RC_PROTO_RC5X_20;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) } else if (!data->is_rc5x && data->count == RC5_NBITS) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) /* RC5 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) u8 command, system;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) if (!(dev->enabled_protocols & RC_PROTO_BIT_RC5)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) data->state = STATE_INACTIVE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) command = (data->bits & 0x0003F) >> 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) system = (data->bits & 0x007C0) >> 6;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) toggle = (data->bits & 0x00800) ? 1 : 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) command += (data->bits & 0x01000) ? 0 : 0x40;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) scancode = system << 8 | command;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) protocol = RC_PROTO_RC5;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) } else if (!data->is_rc5x && data->count == RC5_SZ_NBITS) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) /* RC5 StreamZap */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) u8 command, system;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) if (!(dev->enabled_protocols & RC_PROTO_BIT_RC5_SZ)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) data->state = STATE_INACTIVE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) command = (data->bits & 0x0003F) >> 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149) system = (data->bits & 0x02FC0) >> 6;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150) toggle = (data->bits & 0x01000) ? 1 : 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) scancode = system << 6 | command;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152) protocol = RC_PROTO_RC5_SZ;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154) } else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157) dev_dbg(&dev->dev, "RC5(x/sz) scancode 0x%06x (p: %u, t: %u)\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158) scancode, protocol, toggle);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160) rc_keydown(dev, protocol, scancode, toggle);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161) data->state = STATE_INACTIVE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165) out:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166) dev_dbg(&dev->dev, "RC5(x/sz) decode failed at state %i count %d (%uus %s)\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167) data->state, data->count, ev.duration, TO_STR(ev.pulse));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168) data->state = STATE_INACTIVE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172) static const struct ir_raw_timings_manchester ir_rc5_timings = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173) .leader_pulse = RC5_UNIT,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174) .clock = RC5_UNIT,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175) .trailer_space = RC5_UNIT * 10,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178) static const struct ir_raw_timings_manchester ir_rc5x_timings[2] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180) .leader_pulse = RC5_UNIT,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181) .clock = RC5_UNIT,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182) .trailer_space = RC5X_SPACE,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 183) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 184) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 185) .clock = RC5_UNIT,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 186) .trailer_space = RC5_UNIT * 10,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 187) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 188) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 189)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 190) static const struct ir_raw_timings_manchester ir_rc5_sz_timings = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 191) .leader_pulse = RC5_UNIT,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 192) .clock = RC5_UNIT,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 193) .trailer_space = RC5_UNIT * 10,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 194) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 195)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 196) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 197) * ir_rc5_encode() - Encode a scancode as a stream of raw events
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 198) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 199) * @protocol: protocol variant to encode
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 200) * @scancode: scancode to encode
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 201) * @events: array of raw ir events to write into
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 202) * @max: maximum size of @events
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 203) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 204) * Returns: The number of events written.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 205) * -ENOBUFS if there isn't enough space in the array to fit the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 206) * encoding. In this case all @max events will have been written.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 207) * -EINVAL if the scancode is ambiguous or invalid.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 208) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 209) static int ir_rc5_encode(enum rc_proto protocol, u32 scancode,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 210) struct ir_raw_event *events, unsigned int max)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 211) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 212) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 213) struct ir_raw_event *e = events;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 214) unsigned int data, xdata, command, commandx, system, pre_space_data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 215)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 216) /* Detect protocol and convert scancode to raw data */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 217) if (protocol == RC_PROTO_RC5) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 218) /* decode scancode */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 219) command = (scancode & 0x003f) >> 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 220) commandx = (scancode & 0x0040) >> 6;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 221) system = (scancode & 0x1f00) >> 8;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 222) /* encode data */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 223) data = !commandx << 12 | system << 6 | command;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 224)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 225) /* First bit is encoded by leader_pulse */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 226) ret = ir_raw_gen_manchester(&e, max, &ir_rc5_timings,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 227) RC5_NBITS - 1, data);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 228) if (ret < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 229) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 230) } else if (protocol == RC_PROTO_RC5X_20) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 231) /* decode scancode */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 232) xdata = (scancode & 0x00003f) >> 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 233) command = (scancode & 0x003f00) >> 8;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 234) commandx = !(scancode & 0x004000);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 235) system = (scancode & 0x1f0000) >> 16;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 236)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 237) /* encode data */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 238) data = commandx << 18 | system << 12 | command << 6 | xdata;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 239)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 240) /* First bit is encoded by leader_pulse */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 241) pre_space_data = data >> (RC5X_NBITS - CHECK_RC5X_NBITS);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 242) ret = ir_raw_gen_manchester(&e, max, &ir_rc5x_timings[0],
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 243) CHECK_RC5X_NBITS - 1,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 244) pre_space_data);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 245) if (ret < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 246) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 247) ret = ir_raw_gen_manchester(&e, max - (e - events),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 248) &ir_rc5x_timings[1],
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 249) RC5X_NBITS - CHECK_RC5X_NBITS,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 250) data);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 251) if (ret < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 252) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 253) } else if (protocol == RC_PROTO_RC5_SZ) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 254) /* RC5-SZ scancode is raw enough for Manchester as it is */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 255) /* First bit is encoded by leader_pulse */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 256) ret = ir_raw_gen_manchester(&e, max, &ir_rc5_sz_timings,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 257) RC5_SZ_NBITS - 1,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 258) scancode & 0x2fff);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 259) if (ret < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 260) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 261) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 262) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 263) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 264)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 265) return e - events;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 266) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 267)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 268) static struct ir_raw_handler rc5_handler = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 269) .protocols = RC_PROTO_BIT_RC5 | RC_PROTO_BIT_RC5X_20 |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 270) RC_PROTO_BIT_RC5_SZ,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 271) .decode = ir_rc5_decode,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 272) .encode = ir_rc5_encode,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 273) .carrier = 36000,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 274) .min_timeout = RC5_TRAILER,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 275) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 276)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 277) static int __init ir_rc5_decode_init(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 278) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 279) ir_raw_handler_register(&rc5_handler);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 280)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 281) printk(KERN_INFO "IR RC5(x/sz) protocol handler initialized\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 282) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 283) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 284)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 285) static void __exit ir_rc5_decode_exit(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 286) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 287) ir_raw_handler_unregister(&rc5_handler);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 288) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 289)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 290) module_init(ir_rc5_decode_init);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 291) module_exit(ir_rc5_decode_exit);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 292)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 293) MODULE_LICENSE("GPL v2");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 294) MODULE_AUTHOR("Mauro Carvalho Chehab and Jarod Wilson");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 295) MODULE_AUTHOR("Red Hat Inc. (http://www.redhat.com)");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 296) MODULE_DESCRIPTION("RC5(x/sz) IR protocol decoder");