ir-lirc-codec.c revision 52b661449aecc47e652a164c0d8078b31e10aca0
1/* ir-lirc-codec.c - ir-core to classic lirc interface bridge
2 *
3 * Copyright (C) 2010 by Jarod Wilson <jarod@redhat.com>
4 *
5 * This program is free software; you can redistribute it and/or modify
6 *  it under the terms of the GNU General Public License as published by
7 *  the Free Software Foundation version 2 of the License.
8 *
9 *  This program is distributed in the hope that it will be useful,
10 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
11 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12 *  GNU General Public License for more details.
13 */
14
15#include <linux/sched.h>
16#include <linux/wait.h>
17#include <media/lirc.h>
18#include <media/lirc_dev.h>
19#include <media/rc-core.h>
20#include "rc-core-priv.h"
21
22#define LIRCBUF_SIZE 256
23
24/**
25 * ir_lirc_decode() - Send raw IR data to lirc_dev to be relayed to the
26 *		      lircd userspace daemon for decoding.
27 * @input_dev:	the struct rc_dev descriptor of the device
28 * @duration:	the struct ir_raw_event descriptor of the pulse/space
29 *
30 * This function returns -EINVAL if the lirc interfaces aren't wired up.
31 */
32static int ir_lirc_decode(struct rc_dev *dev, struct ir_raw_event ev)
33{
34	struct lirc_codec *lirc = &dev->raw->lirc;
35	int sample;
36
37	if (!(dev->raw->enabled_protocols & RC_TYPE_LIRC))
38		return 0;
39
40	if (!dev->raw->lirc.drv || !dev->raw->lirc.drv->rbuf)
41		return -EINVAL;
42
43	/* Packet start */
44	if (ev.reset)
45		return 0;
46
47	/* Carrier reports */
48	if (ev.carrier_report) {
49		sample = LIRC_FREQUENCY(ev.carrier);
50
51	/* Packet end */
52	} else if (ev.timeout) {
53
54		if (lirc->gap)
55			return 0;
56
57		lirc->gap_start = ktime_get();
58		lirc->gap = true;
59		lirc->gap_duration = ev.duration;
60
61		if (!lirc->send_timeout_reports)
62			return 0;
63
64		sample = LIRC_TIMEOUT(ev.duration / 1000);
65
66	/* Normal sample */
67	} else {
68
69		if (lirc->gap) {
70			int gap_sample;
71
72			lirc->gap_duration += ktime_to_ns(ktime_sub(ktime_get(),
73				lirc->gap_start));
74
75			/* Convert to ms and cap by LIRC_VALUE_MASK */
76			do_div(lirc->gap_duration, 1000);
77			lirc->gap_duration = min(lirc->gap_duration,
78							(u64)LIRC_VALUE_MASK);
79
80			gap_sample = LIRC_SPACE(lirc->gap_duration);
81			lirc_buffer_write(dev->raw->lirc.drv->rbuf,
82						(unsigned char *) &gap_sample);
83			lirc->gap = false;
84		}
85
86		sample = ev.pulse ? LIRC_PULSE(ev.duration / 1000) :
87					LIRC_SPACE(ev.duration / 1000);
88	}
89
90	lirc_buffer_write(dev->raw->lirc.drv->rbuf,
91			  (unsigned char *) &sample);
92	wake_up(&dev->raw->lirc.drv->rbuf->wait_poll);
93
94	return 0;
95}
96
97static ssize_t ir_lirc_transmit_ir(struct file *file, const char *buf,
98				   size_t n, loff_t *ppos)
99{
100	struct lirc_codec *lirc;
101	struct rc_dev *dev;
102	int *txbuf; /* buffer with values to transmit */
103	int ret = 0, count;
104
105	lirc = lirc_get_pdata(file);
106	if (!lirc)
107		return -EFAULT;
108
109	if (n % sizeof(int))
110		return -EINVAL;
111
112	count = n / sizeof(int);
113	if (count > LIRCBUF_SIZE || count % 2 == 0)
114		return -EINVAL;
115
116	txbuf = memdup_user(buf, n);
117	if (IS_ERR(txbuf))
118		return PTR_ERR(txbuf);
119
120	dev = lirc->dev;
121	if (!dev) {
122		ret = -EFAULT;
123		goto out;
124	}
125
126	if (dev->tx_ir)
127		ret = dev->tx_ir(dev, txbuf, (u32)n);
128
129out:
130	kfree(txbuf);
131	return ret;
132}
133
134static long ir_lirc_ioctl(struct file *filep, unsigned int cmd,
135			unsigned long __user arg)
136{
137	struct lirc_codec *lirc;
138	struct rc_dev *dev;
139	int ret = 0;
140	__u32 val = 0, tmp;
141
142	lirc = lirc_get_pdata(filep);
143	if (!lirc)
144		return -EFAULT;
145
146	dev = lirc->dev;
147	if (!dev)
148		return -EFAULT;
149
150	if (_IOC_DIR(cmd) & _IOC_WRITE) {
151		ret = get_user(val, (__u32 *)arg);
152		if (ret)
153			return ret;
154	}
155
156	switch (cmd) {
157
158	/* legacy support */
159	case LIRC_GET_SEND_MODE:
160		val = LIRC_CAN_SEND_PULSE & LIRC_CAN_SEND_MASK;
161		break;
162
163	case LIRC_SET_SEND_MODE:
164		if (val != (LIRC_MODE_PULSE & LIRC_CAN_SEND_MASK))
165			return -EINVAL;
166		return 0;
167
168	/* TX settings */
169	case LIRC_SET_TRANSMITTER_MASK:
170		if (!dev->s_tx_mask)
171			return -EINVAL;
172
173		return dev->s_tx_mask(dev, val);
174
175	case LIRC_SET_SEND_CARRIER:
176		if (!dev->s_tx_carrier)
177			return -EINVAL;
178
179		return dev->s_tx_carrier(dev, val);
180
181	case LIRC_SET_SEND_DUTY_CYCLE:
182		if (!dev->s_tx_duty_cycle)
183			return -ENOSYS;
184
185		if (val <= 0 || val >= 100)
186			return -EINVAL;
187
188		return dev->s_tx_duty_cycle(dev, val);
189
190	/* RX settings */
191	case LIRC_SET_REC_CARRIER:
192		if (!dev->s_rx_carrier_range)
193			return -ENOSYS;
194
195		if (val <= 0)
196			return -EINVAL;
197
198		return dev->s_rx_carrier_range(dev,
199					       dev->raw->lirc.carrier_low,
200					       val);
201
202	case LIRC_SET_REC_CARRIER_RANGE:
203		if (val <= 0)
204			return -EINVAL;
205
206		dev->raw->lirc.carrier_low = val;
207		return 0;
208
209	case LIRC_GET_REC_RESOLUTION:
210		val = dev->rx_resolution;
211		break;
212
213	case LIRC_SET_WIDEBAND_RECEIVER:
214		if (!dev->s_learning_mode)
215			return -ENOSYS;
216
217		return dev->s_learning_mode(dev, !!val);
218
219	case LIRC_SET_MEASURE_CARRIER_MODE:
220		if (!dev->s_carrier_report)
221			return -ENOSYS;
222
223		return dev->s_carrier_report(dev, !!val);
224
225	/* Generic timeout support */
226	case LIRC_GET_MIN_TIMEOUT:
227		if (!dev->max_timeout)
228			return -ENOSYS;
229		val = dev->min_timeout / 1000;
230		break;
231
232	case LIRC_GET_MAX_TIMEOUT:
233		if (!dev->max_timeout)
234			return -ENOSYS;
235		val = dev->max_timeout / 1000;
236		break;
237
238	case LIRC_SET_REC_TIMEOUT:
239		if (!dev->max_timeout)
240			return -ENOSYS;
241
242		tmp = val * 1000;
243
244		if (tmp < dev->min_timeout ||
245		    tmp > dev->max_timeout)
246				return -EINVAL;
247
248		dev->timeout = tmp;
249		break;
250
251	case LIRC_SET_REC_TIMEOUT_REPORTS:
252		lirc->send_timeout_reports = !!val;
253		break;
254
255	default:
256		return lirc_dev_fop_ioctl(filep, cmd, arg);
257	}
258
259	if (_IOC_DIR(cmd) & _IOC_READ)
260		ret = put_user(val, (__u32 *)arg);
261
262	return ret;
263}
264
265static int ir_lirc_open(void *data)
266{
267	return 0;
268}
269
270static void ir_lirc_close(void *data)
271{
272	return;
273}
274
275static struct file_operations lirc_fops = {
276	.owner		= THIS_MODULE,
277	.write		= ir_lirc_transmit_ir,
278	.unlocked_ioctl	= ir_lirc_ioctl,
279#ifdef CONFIG_COMPAT
280	.compat_ioctl	= ir_lirc_ioctl,
281#endif
282	.read		= lirc_dev_fop_read,
283	.poll		= lirc_dev_fop_poll,
284	.open		= lirc_dev_fop_open,
285	.release	= lirc_dev_fop_close,
286	.llseek		= no_llseek,
287};
288
289static int ir_lirc_register(struct rc_dev *dev)
290{
291	struct lirc_driver *drv;
292	struct lirc_buffer *rbuf;
293	int rc = -ENOMEM;
294	unsigned long features;
295
296	drv = kzalloc(sizeof(struct lirc_driver), GFP_KERNEL);
297	if (!drv)
298		return rc;
299
300	rbuf = kzalloc(sizeof(struct lirc_buffer), GFP_KERNEL);
301	if (!rbuf)
302		goto rbuf_alloc_failed;
303
304	rc = lirc_buffer_init(rbuf, sizeof(int), LIRCBUF_SIZE);
305	if (rc)
306		goto rbuf_init_failed;
307
308	features = LIRC_CAN_REC_MODE2;
309	if (dev->tx_ir) {
310		features |= LIRC_CAN_SEND_PULSE;
311		if (dev->s_tx_mask)
312			features |= LIRC_CAN_SET_TRANSMITTER_MASK;
313		if (dev->s_tx_carrier)
314			features |= LIRC_CAN_SET_SEND_CARRIER;
315		if (dev->s_tx_duty_cycle)
316			features |= LIRC_CAN_SET_SEND_DUTY_CYCLE;
317	}
318
319	if (dev->s_rx_carrier_range)
320		features |= LIRC_CAN_SET_REC_CARRIER |
321			LIRC_CAN_SET_REC_CARRIER_RANGE;
322
323	if (dev->s_learning_mode)
324		features |= LIRC_CAN_USE_WIDEBAND_RECEIVER;
325
326	if (dev->s_carrier_report)
327		features |= LIRC_CAN_MEASURE_CARRIER;
328
329	if (dev->max_timeout)
330		features |= LIRC_CAN_SET_REC_TIMEOUT;
331
332	snprintf(drv->name, sizeof(drv->name), "ir-lirc-codec (%s)",
333		 dev->driver_name);
334	drv->minor = -1;
335	drv->features = features;
336	drv->data = &dev->raw->lirc;
337	drv->rbuf = rbuf;
338	drv->set_use_inc = &ir_lirc_open;
339	drv->set_use_dec = &ir_lirc_close;
340	drv->code_length = sizeof(struct ir_raw_event) * 8;
341	drv->fops = &lirc_fops;
342	drv->dev = &dev->dev;
343	drv->owner = THIS_MODULE;
344
345	drv->minor = lirc_register_driver(drv);
346	if (drv->minor < 0) {
347		rc = -ENODEV;
348		goto lirc_register_failed;
349	}
350
351	dev->raw->lirc.drv = drv;
352	dev->raw->lirc.dev = dev;
353	return 0;
354
355lirc_register_failed:
356rbuf_init_failed:
357	kfree(rbuf);
358rbuf_alloc_failed:
359	kfree(drv);
360
361	return rc;
362}
363
364static int ir_lirc_unregister(struct rc_dev *dev)
365{
366	struct lirc_codec *lirc = &dev->raw->lirc;
367
368	lirc_unregister_driver(lirc->drv->minor);
369	lirc_buffer_free(lirc->drv->rbuf);
370	kfree(lirc->drv);
371
372	return 0;
373}
374
375static struct ir_raw_handler lirc_handler = {
376	.protocols	= RC_TYPE_LIRC,
377	.decode		= ir_lirc_decode,
378	.raw_register	= ir_lirc_register,
379	.raw_unregister	= ir_lirc_unregister,
380};
381
382static int __init ir_lirc_codec_init(void)
383{
384	ir_raw_handler_register(&lirc_handler);
385
386	printk(KERN_INFO "IR LIRC bridge handler initialized\n");
387	return 0;
388}
389
390static void __exit ir_lirc_codec_exit(void)
391{
392	ir_raw_handler_unregister(&lirc_handler);
393}
394
395module_init(ir_lirc_codec_init);
396module_exit(ir_lirc_codec_exit);
397
398MODULE_LICENSE("GPL");
399MODULE_AUTHOR("Jarod Wilson <jarod@redhat.com>");
400MODULE_AUTHOR("Red Hat Inc. (http://www.redhat.com)");
401MODULE_DESCRIPTION("LIRC IR handler bridge");
402