root/drivers/media/rc/rc-loopback.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. loop_set_tx_mask
  2. loop_set_tx_carrier
  3. loop_set_tx_duty_cycle
  4. loop_set_rx_carrier_range
  5. loop_tx_ir
  6. loop_set_idle
  7. loop_set_learning_mode
  8. loop_set_carrier_report
  9. loop_set_wakeup_filter
  10. loop_init
  11. loop_exit

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

/* [<][>][^][v][top][bottom][index][help] */