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