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

rc-loopback.c (6435B)


      1// SPDX-License-Identifier: GPL-2.0-or-later
      2/*
      3 * Loopback driver for rc-core,
      4 *
      5 * Copyright (c) 2010 David Härdeman <david@hardeman.nu>
      6 *
      7 * This driver receives TX data and passes it back as RX data,
      8 * which is useful for (scripted) debugging of rc-core without
      9 * having to use actual hardware.
     10 */
     11
     12#include <linux/device.h>
     13#include <linux/module.h>
     14#include <linux/sched.h>
     15#include <linux/slab.h>
     16#include <media/rc-core.h>
     17
     18#define DRIVER_NAME		"rc-loopback"
     19#define RXMASK_NARROWBAND	0x1
     20#define RXMASK_WIDEBAND		0x2
     21
     22struct loopback_dev {
     23	struct rc_dev *dev;
     24	u32 txmask;
     25	u32 txcarrier;
     26	u32 txduty;
     27	bool idle;
     28	bool wideband;
     29	bool carrierreport;
     30	u32 rxcarriermin;
     31	u32 rxcarriermax;
     32};
     33
     34static struct loopback_dev loopdev;
     35
     36static int loop_set_tx_mask(struct rc_dev *dev, u32 mask)
     37{
     38	struct loopback_dev *lodev = dev->priv;
     39
     40	if ((mask & (RXMASK_NARROWBAND | RXMASK_WIDEBAND)) != mask) {
     41		dev_dbg(&dev->dev, "invalid tx mask: %u\n", mask);
     42		return 2;
     43	}
     44
     45	dev_dbg(&dev->dev, "setting tx mask: %u\n", mask);
     46	lodev->txmask = mask;
     47	return 0;
     48}
     49
     50static int loop_set_tx_carrier(struct rc_dev *dev, u32 carrier)
     51{
     52	struct loopback_dev *lodev = dev->priv;
     53
     54	dev_dbg(&dev->dev, "setting tx carrier: %u\n", carrier);
     55	lodev->txcarrier = carrier;
     56	return 0;
     57}
     58
     59static int loop_set_tx_duty_cycle(struct rc_dev *dev, u32 duty_cycle)
     60{
     61	struct loopback_dev *lodev = dev->priv;
     62
     63	if (duty_cycle < 1 || duty_cycle > 99) {
     64		dev_dbg(&dev->dev, "invalid duty cycle: %u\n", duty_cycle);
     65		return -EINVAL;
     66	}
     67
     68	dev_dbg(&dev->dev, "setting duty cycle: %u\n", duty_cycle);
     69	lodev->txduty = duty_cycle;
     70	return 0;
     71}
     72
     73static int loop_set_rx_carrier_range(struct rc_dev *dev, u32 min, u32 max)
     74{
     75	struct loopback_dev *lodev = dev->priv;
     76
     77	if (min < 1 || min > max) {
     78		dev_dbg(&dev->dev, "invalid rx carrier range %u to %u\n", min, max);
     79		return -EINVAL;
     80	}
     81
     82	dev_dbg(&dev->dev, "setting rx carrier range %u to %u\n", min, max);
     83	lodev->rxcarriermin = min;
     84	lodev->rxcarriermax = max;
     85	return 0;
     86}
     87
     88static int loop_tx_ir(struct rc_dev *dev, unsigned *txbuf, unsigned count)
     89{
     90	struct loopback_dev *lodev = dev->priv;
     91	u32 rxmask;
     92	unsigned i;
     93	struct ir_raw_event rawir = {};
     94
     95	if (lodev->txcarrier < lodev->rxcarriermin ||
     96	    lodev->txcarrier > lodev->rxcarriermax) {
     97		dev_dbg(&dev->dev, "ignoring tx, carrier out of range\n");
     98		goto out;
     99	}
    100
    101	if (lodev->wideband)
    102		rxmask = RXMASK_WIDEBAND;
    103	else
    104		rxmask = RXMASK_NARROWBAND;
    105
    106	if (!(rxmask & lodev->txmask)) {
    107		dev_dbg(&dev->dev, "ignoring tx, rx mask mismatch\n");
    108		goto out;
    109	}
    110
    111	for (i = 0; i < count; i++) {
    112		rawir.pulse = i % 2 ? false : true;
    113		rawir.duration = txbuf[i];
    114
    115		/* simulate overflow if ridiculously long pulse was sent */
    116		if (rawir.pulse && rawir.duration > MS_TO_US(50))
    117			ir_raw_event_overflow(dev);
    118		else
    119			ir_raw_event_store_with_filter(dev, &rawir);
    120	}
    121
    122	if (lodev->carrierreport) {
    123		rawir.pulse = false;
    124		rawir.carrier_report = true;
    125		rawir.carrier = lodev->txcarrier;
    126
    127		ir_raw_event_store(dev, &rawir);
    128	}
    129
    130	/* Fake a silence long enough to cause us to go idle */
    131	rawir.pulse = false;
    132	rawir.duration = dev->timeout;
    133	ir_raw_event_store_with_filter(dev, &rawir);
    134
    135	ir_raw_event_handle(dev);
    136
    137out:
    138	return count;
    139}
    140
    141static void loop_set_idle(struct rc_dev *dev, bool enable)
    142{
    143	struct loopback_dev *lodev = dev->priv;
    144
    145	if (lodev->idle != enable) {
    146		dev_dbg(&dev->dev, "%sing idle mode\n", enable ? "enter" : "exit");
    147		lodev->idle = enable;
    148	}
    149}
    150
    151static int loop_set_wideband_receiver(struct rc_dev *dev, int enable)
    152{
    153	struct loopback_dev *lodev = dev->priv;
    154
    155	if (lodev->wideband != enable) {
    156		dev_dbg(&dev->dev, "using %sband receiver\n", enable ? "wide" : "narrow");
    157		lodev->wideband = !!enable;
    158	}
    159
    160	return 0;
    161}
    162
    163static int loop_set_carrier_report(struct rc_dev *dev, int enable)
    164{
    165	struct loopback_dev *lodev = dev->priv;
    166
    167	if (lodev->carrierreport != enable) {
    168		dev_dbg(&dev->dev, "%sabling carrier reports\n", enable ? "en" : "dis");
    169		lodev->carrierreport = !!enable;
    170	}
    171
    172	return 0;
    173}
    174
    175static int loop_set_wakeup_filter(struct rc_dev *dev,
    176				  struct rc_scancode_filter *sc)
    177{
    178	static const unsigned int max = 512;
    179	struct ir_raw_event *raw;
    180	int ret;
    181	int i;
    182
    183	/* fine to disable filter */
    184	if (!sc->mask)
    185		return 0;
    186
    187	/* encode the specified filter and loop it back */
    188	raw = kmalloc_array(max, sizeof(*raw), GFP_KERNEL);
    189	if (!raw)
    190		return -ENOMEM;
    191
    192	ret = ir_raw_encode_scancode(dev->wakeup_protocol, sc->data, raw, max);
    193	/* still loop back the partial raw IR even if it's incomplete */
    194	if (ret == -ENOBUFS)
    195		ret = max;
    196	if (ret >= 0) {
    197		/* do the loopback */
    198		for (i = 0; i < ret; ++i)
    199			ir_raw_event_store(dev, &raw[i]);
    200		ir_raw_event_handle(dev);
    201
    202		ret = 0;
    203	}
    204
    205	kfree(raw);
    206
    207	return ret;
    208}
    209
    210static int __init loop_init(void)
    211{
    212	struct rc_dev *rc;
    213	int ret;
    214
    215	rc = rc_allocate_device(RC_DRIVER_IR_RAW);
    216	if (!rc)
    217		return -ENOMEM;
    218
    219	rc->device_name		= "rc-core loopback device";
    220	rc->input_phys		= "rc-core/virtual";
    221	rc->input_id.bustype	= BUS_VIRTUAL;
    222	rc->input_id.version	= 1;
    223	rc->driver_name		= DRIVER_NAME;
    224	rc->map_name		= RC_MAP_EMPTY;
    225	rc->priv		= &loopdev;
    226	rc->allowed_protocols	= RC_PROTO_BIT_ALL_IR_DECODER;
    227	rc->allowed_wakeup_protocols = RC_PROTO_BIT_ALL_IR_ENCODER;
    228	rc->encode_wakeup	= true;
    229	rc->timeout		= IR_DEFAULT_TIMEOUT;
    230	rc->min_timeout		= 1;
    231	rc->max_timeout		= IR_MAX_TIMEOUT;
    232	rc->rx_resolution	= 1;
    233	rc->tx_resolution	= 1;
    234	rc->s_tx_mask		= loop_set_tx_mask;
    235	rc->s_tx_carrier	= loop_set_tx_carrier;
    236	rc->s_tx_duty_cycle	= loop_set_tx_duty_cycle;
    237	rc->s_rx_carrier_range	= loop_set_rx_carrier_range;
    238	rc->tx_ir		= loop_tx_ir;
    239	rc->s_idle		= loop_set_idle;
    240	rc->s_wideband_receiver	= loop_set_wideband_receiver;
    241	rc->s_carrier_report	= loop_set_carrier_report;
    242	rc->s_wakeup_filter	= loop_set_wakeup_filter;
    243
    244	loopdev.txmask		= RXMASK_NARROWBAND;
    245	loopdev.txcarrier	= 36000;
    246	loopdev.txduty		= 50;
    247	loopdev.rxcarriermin	= 1;
    248	loopdev.rxcarriermax	= ~0;
    249	loopdev.idle		= true;
    250	loopdev.wideband	= false;
    251	loopdev.carrierreport	= false;
    252
    253	ret = rc_register_device(rc);
    254	if (ret < 0) {
    255		dev_err(&rc->dev, "rc_dev registration failed\n");
    256		rc_free_device(rc);
    257		return ret;
    258	}
    259
    260	loopdev.dev = rc;
    261	return 0;
    262}
    263
    264static void __exit loop_exit(void)
    265{
    266	rc_unregister_device(loopdev.dev);
    267}
    268
    269module_init(loop_init);
    270module_exit(loop_exit);
    271
    272MODULE_DESCRIPTION("Loopback device for rc-core debugging");
    273MODULE_AUTHOR("David Härdeman <david@hardeman.nu>");
    274MODULE_LICENSE("GPL");