xref: /openbmc/linux/drivers/media/rc/rc-loopback.c (revision 256bf685)
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 
22 struct 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 
34 static struct loopback_dev loopdev;
35 
36 static 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 
50 static 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 
59 static 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 
73 static 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 
88 static 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 
137 out:
138 	return count;
139 }
140 
141 static 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 
151 static 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 
163 static 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 
175 static 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 
210 static 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 
264 static void __exit loop_exit(void)
265 {
266 	rc_unregister_device(loopdev.dev);
267 }
268 
269 module_init(loop_init);
270 module_exit(loop_exit);
271 
272 MODULE_DESCRIPTION("Loopback device for rc-core debugging");
273 MODULE_AUTHOR("David Härdeman <david@hardeman.nu>");
274 MODULE_LICENSE("GPL");
275