cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

ir-imon-decoder.c (6660B)


      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		416 /* us */
     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	STATE_ERROR,
     36};
     37
     38static void ir_imon_decode_scancode(struct rc_dev *dev)
     39{
     40	struct imon_dec *imon = &dev->raw->imon;
     41
     42	/* Keyboard/Mouse toggle */
     43	if (imon->bits == 0x299115b7)
     44		imon->stick_keyboard = !imon->stick_keyboard;
     45
     46	if ((imon->bits & 0xfc0000ff) == 0x680000b7) {
     47		int rel_x, rel_y;
     48		u8 buf;
     49
     50		buf = imon->bits >> 16;
     51		rel_x = (buf & 0x08) | (buf & 0x10) >> 2 |
     52			(buf & 0x20) >> 4 | (buf & 0x40) >> 6;
     53		if (imon->bits & 0x02000000)
     54			rel_x |= ~0x0f;
     55		buf = imon->bits >> 8;
     56		rel_y = (buf & 0x08) | (buf & 0x10) >> 2 |
     57			(buf & 0x20) >> 4 | (buf & 0x40) >> 6;
     58		if (imon->bits & 0x01000000)
     59			rel_y |= ~0x0f;
     60
     61		if (rel_x && rel_y && imon->stick_keyboard) {
     62			if (abs(rel_y) > abs(rel_x))
     63				imon->bits = rel_y > 0 ?
     64					0x289515b7 : /* KEY_DOWN */
     65					0x2aa515b7;  /* KEY_UP */
     66			else
     67				imon->bits = rel_x > 0 ?
     68					0x2ba515b7 : /* KEY_RIGHT */
     69					0x29a515b7;  /* KEY_LEFT */
     70		}
     71
     72		if (!imon->stick_keyboard) {
     73			input_report_rel(dev->input_dev, REL_X, rel_x);
     74			input_report_rel(dev->input_dev, REL_Y, rel_y);
     75
     76			input_report_key(dev->input_dev, BTN_LEFT,
     77					 (imon->bits & 0x00010000) != 0);
     78			input_report_key(dev->input_dev, BTN_RIGHT,
     79					 (imon->bits & 0x00040000) != 0);
     80		}
     81	}
     82
     83	rc_keydown(dev, RC_PROTO_IMON, imon->bits, 0);
     84}
     85
     86/**
     87 * ir_imon_decode() - Decode one iMON pulse or space
     88 * @dev:	the struct rc_dev descriptor of the device
     89 * @ev:		the struct ir_raw_event descriptor of the pulse/space
     90 *
     91 * This function returns -EINVAL if the pulse violates the state machine
     92 */
     93static int ir_imon_decode(struct rc_dev *dev, struct ir_raw_event ev)
     94{
     95	struct imon_dec *data = &dev->raw->imon;
     96
     97	if (!is_timing_event(ev)) {
     98		if (ev.overflow)
     99			data->state = STATE_INACTIVE;
    100		return 0;
    101	}
    102
    103	dev_dbg(&dev->dev,
    104		"iMON decode started at state %d bitno %d (%uus %s)\n",
    105		data->state, data->count, ev.duration, TO_STR(ev.pulse));
    106
    107	/*
    108	 * Since iMON protocol is a series of bits, if at any point
    109	 * we encounter an error, make sure that any remaining bits
    110	 * aren't parsed as a scancode made up of less bits.
    111	 *
    112	 * Note that if the stick is held, then the remote repeats
    113	 * the scancode with about 12ms between them. So, make sure
    114	 * we have at least 10ms of space after an error. That way,
    115	 * we're at a new scancode.
    116	 */
    117	if (data->state == STATE_ERROR) {
    118		if (!ev.pulse && ev.duration > MS_TO_US(10))
    119			data->state = STATE_INACTIVE;
    120		return 0;
    121	}
    122
    123	for (;;) {
    124		if (!geq_margin(ev.duration, IMON_UNIT, IMON_UNIT / 2))
    125			return 0;
    126
    127		decrease_duration(&ev, IMON_UNIT);
    128
    129		switch (data->state) {
    130		case STATE_INACTIVE:
    131			if (ev.pulse) {
    132				data->state = STATE_BIT_CHK;
    133				data->bits = 0;
    134				data->count = IMON_BITS;
    135			}
    136			break;
    137		case STATE_BIT_CHK:
    138			if (IMON_CHKBITS & BIT(data->count))
    139				data->last_chk = ev.pulse;
    140			else if (ev.pulse)
    141				goto err_out;
    142			data->state = STATE_BIT_START;
    143			break;
    144		case STATE_BIT_START:
    145			data->bits <<= 1;
    146			if (!ev.pulse)
    147				data->bits |= 1;
    148
    149			if (IMON_CHKBITS & BIT(data->count)) {
    150				if (data->last_chk != !(data->bits & 3))
    151					goto err_out;
    152			}
    153
    154			if (!data->count--)
    155				data->state = STATE_FINISHED;
    156			else
    157				data->state = STATE_BIT_CHK;
    158			break;
    159		case STATE_FINISHED:
    160			if (ev.pulse)
    161				goto err_out;
    162			ir_imon_decode_scancode(dev);
    163			data->state = STATE_INACTIVE;
    164			break;
    165		}
    166	}
    167
    168err_out:
    169	dev_dbg(&dev->dev,
    170		"iMON decode failed at state %d bitno %d (%uus %s)\n",
    171		data->state, data->count, ev.duration, TO_STR(ev.pulse));
    172
    173	data->state = STATE_ERROR;
    174
    175	return -EINVAL;
    176}
    177
    178/**
    179 * ir_imon_encode() - Encode a scancode as a stream of raw events
    180 *
    181 * @protocol:	protocol to encode
    182 * @scancode:	scancode to encode
    183 * @events:	array of raw ir events to write into
    184 * @max:	maximum size of @events
    185 *
    186 * Returns:	The number of events written.
    187 *		-ENOBUFS if there isn't enough space in the array to fit the
    188 *		encoding. In this case all @max events will have been written.
    189 */
    190static int ir_imon_encode(enum rc_proto protocol, u32 scancode,
    191			  struct ir_raw_event *events, unsigned int max)
    192{
    193	struct ir_raw_event *e = events;
    194	int i, pulse;
    195
    196	if (!max--)
    197		return -ENOBUFS;
    198	init_ir_raw_event_duration(e, 1, IMON_UNIT);
    199
    200	for (i = IMON_BITS; i >= 0; i--) {
    201		if (BIT(i) & IMON_CHKBITS)
    202			pulse = !(scancode & (BIT(i) | BIT(i + 1)));
    203		else
    204			pulse = 0;
    205
    206		if (pulse == e->pulse) {
    207			e->duration += IMON_UNIT;
    208		} else {
    209			if (!max--)
    210				return -ENOBUFS;
    211			init_ir_raw_event_duration(++e, pulse, IMON_UNIT);
    212		}
    213
    214		pulse = !(scancode & BIT(i));
    215
    216		if (pulse == e->pulse) {
    217			e->duration += IMON_UNIT;
    218		} else {
    219			if (!max--)
    220				return -ENOBUFS;
    221			init_ir_raw_event_duration(++e, pulse, IMON_UNIT);
    222		}
    223	}
    224
    225	if (e->pulse)
    226		e++;
    227
    228	return e - events;
    229}
    230
    231static int ir_imon_register(struct rc_dev *dev)
    232{
    233	struct imon_dec *imon = &dev->raw->imon;
    234
    235	imon->stick_keyboard = false;
    236
    237	return 0;
    238}
    239
    240static struct ir_raw_handler imon_handler = {
    241	.protocols	= RC_PROTO_BIT_IMON,
    242	.decode		= ir_imon_decode,
    243	.encode		= ir_imon_encode,
    244	.carrier	= 38000,
    245	.raw_register	= ir_imon_register,
    246	.min_timeout	= IMON_UNIT * IMON_BITS * 2,
    247};
    248
    249static int __init ir_imon_decode_init(void)
    250{
    251	ir_raw_handler_register(&imon_handler);
    252
    253	pr_info("IR iMON protocol handler initialized\n");
    254	return 0;
    255}
    256
    257static void __exit ir_imon_decode_exit(void)
    258{
    259	ir_raw_handler_unregister(&imon_handler);
    260}
    261
    262module_init(ir_imon_decode_init);
    263module_exit(ir_imon_decode_exit);
    264
    265MODULE_LICENSE("GPL");
    266MODULE_AUTHOR("Sean Young <sean@mess.org>");
    267MODULE_DESCRIPTION("iMON IR protocol decoder");