xref: /openbmc/linux/drivers/media/rc/rc-ir-raw.c (revision 963761a0)
14924a311SDavid Härdeman /* rc-ir-raw.c - handle IR pulse/space events
24924a311SDavid Härdeman  *
34924a311SDavid Härdeman  * Copyright (C) 2010 by Mauro Carvalho Chehab
44924a311SDavid Härdeman  *
54924a311SDavid Härdeman  * This program is free software; you can redistribute it and/or modify
64924a311SDavid Härdeman  *  it under the terms of the GNU General Public License as published by
74924a311SDavid Härdeman  *  the Free Software Foundation version 2 of the License.
84924a311SDavid Härdeman  *
94924a311SDavid Härdeman  *  This program is distributed in the hope that it will be useful,
104924a311SDavid Härdeman  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
114924a311SDavid Härdeman  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
124924a311SDavid Härdeman  *  GNU General Public License for more details.
134924a311SDavid Härdeman  */
144924a311SDavid Härdeman 
154924a311SDavid Härdeman #include <linux/export.h>
164924a311SDavid Härdeman #include <linux/kthread.h>
174924a311SDavid Härdeman #include <linux/mutex.h>
184924a311SDavid Härdeman #include <linux/kmod.h>
194924a311SDavid Härdeman #include <linux/sched.h>
204924a311SDavid Härdeman #include "rc-core-priv.h"
214924a311SDavid Härdeman 
224924a311SDavid Härdeman /* Used to keep track of IR raw clients, protected by ir_raw_handler_lock */
234924a311SDavid Härdeman static LIST_HEAD(ir_raw_client_list);
244924a311SDavid Härdeman 
254924a311SDavid Härdeman /* Used to handle IR raw handler extensions */
264924a311SDavid Härdeman static DEFINE_MUTEX(ir_raw_handler_lock);
274924a311SDavid Härdeman static LIST_HEAD(ir_raw_handler_list);
2837e90a22SHeiner Kallweit static atomic64_t available_protocols = ATOMIC64_INIT(0);
294924a311SDavid Härdeman 
304924a311SDavid Härdeman static int ir_raw_event_thread(void *data)
314924a311SDavid Härdeman {
324924a311SDavid Härdeman 	struct ir_raw_event ev;
334924a311SDavid Härdeman 	struct ir_raw_handler *handler;
344924a311SDavid Härdeman 	struct ir_raw_event_ctrl *raw = (struct ir_raw_event_ctrl *)data;
354924a311SDavid Härdeman 
3674d47d75SHeiner Kallweit 	while (1) {
374924a311SDavid Härdeman 		mutex_lock(&ir_raw_handler_lock);
3874d47d75SHeiner Kallweit 		while (kfifo_out(&raw->kfifo, &ev, 1)) {
394924a311SDavid Härdeman 			list_for_each_entry(handler, &ir_raw_handler_list, list)
4074d47d75SHeiner Kallweit 				if (raw->dev->enabled_protocols &
4174d47d75SHeiner Kallweit 				    handler->protocols || !handler->protocols)
424924a311SDavid Härdeman 					handler->decode(raw->dev, ev);
434924a311SDavid Härdeman 			raw->prev_ev = ev;
4474d47d75SHeiner Kallweit 		}
454924a311SDavid Härdeman 		mutex_unlock(&ir_raw_handler_lock);
4674d47d75SHeiner Kallweit 
4774d47d75SHeiner Kallweit 		set_current_state(TASK_INTERRUPTIBLE);
4874d47d75SHeiner Kallweit 
4974d47d75SHeiner Kallweit 		if (kthread_should_stop()) {
5074d47d75SHeiner Kallweit 			__set_current_state(TASK_RUNNING);
5174d47d75SHeiner Kallweit 			break;
5274d47d75SHeiner Kallweit 		} else if (!kfifo_is_empty(&raw->kfifo))
5374d47d75SHeiner Kallweit 			set_current_state(TASK_RUNNING);
5474d47d75SHeiner Kallweit 
5574d47d75SHeiner Kallweit 		schedule();
564924a311SDavid Härdeman 	}
574924a311SDavid Härdeman 
584924a311SDavid Härdeman 	return 0;
594924a311SDavid Härdeman }
604924a311SDavid Härdeman 
614924a311SDavid Härdeman /**
624924a311SDavid Härdeman  * ir_raw_event_store() - pass a pulse/space duration to the raw ir decoders
634924a311SDavid Härdeman  * @dev:	the struct rc_dev device descriptor
644924a311SDavid Härdeman  * @ev:		the struct ir_raw_event descriptor of the pulse/space
654924a311SDavid Härdeman  *
664924a311SDavid Härdeman  * This routine (which may be called from an interrupt context) stores a
674924a311SDavid Härdeman  * pulse/space duration for the raw ir decoding state machines. Pulses are
684924a311SDavid Härdeman  * signalled as positive values and spaces as negative values. A zero value
694924a311SDavid Härdeman  * will reset the decoding state machines.
704924a311SDavid Härdeman  */
714924a311SDavid Härdeman int ir_raw_event_store(struct rc_dev *dev, struct ir_raw_event *ev)
724924a311SDavid Härdeman {
734924a311SDavid Härdeman 	if (!dev->raw)
744924a311SDavid Härdeman 		return -EINVAL;
754924a311SDavid Härdeman 
764924a311SDavid Härdeman 	IR_dprintk(2, "sample: (%05dus %s)\n",
774924a311SDavid Härdeman 		   TO_US(ev->duration), TO_STR(ev->pulse));
784924a311SDavid Härdeman 
79464254e5SHeiner Kallweit 	if (!kfifo_put(&dev->raw->kfifo, *ev)) {
80464254e5SHeiner Kallweit 		dev_err(&dev->dev, "IR event FIFO is full!\n");
81464254e5SHeiner Kallweit 		return -ENOSPC;
82464254e5SHeiner Kallweit 	}
834924a311SDavid Härdeman 
844924a311SDavid Härdeman 	return 0;
854924a311SDavid Härdeman }
864924a311SDavid Härdeman EXPORT_SYMBOL_GPL(ir_raw_event_store);
874924a311SDavid Härdeman 
884924a311SDavid Härdeman /**
894924a311SDavid Härdeman  * ir_raw_event_store_edge() - notify raw ir decoders of the start of a pulse/space
904924a311SDavid Härdeman  * @dev:	the struct rc_dev device descriptor
914924a311SDavid Härdeman  * @type:	the type of the event that has occurred
924924a311SDavid Härdeman  *
934924a311SDavid Härdeman  * This routine (which may be called from an interrupt context) is used to
944924a311SDavid Härdeman  * store the beginning of an ir pulse or space (or the start/end of ir
954924a311SDavid Härdeman  * reception) for the raw ir decoding state machines. This is used by
964924a311SDavid Härdeman  * hardware which does not provide durations directly but only interrupts
974924a311SDavid Härdeman  * (or similar events) on state change.
984924a311SDavid Härdeman  */
994924a311SDavid Härdeman int ir_raw_event_store_edge(struct rc_dev *dev, enum raw_event_type type)
1004924a311SDavid Härdeman {
1014924a311SDavid Härdeman 	ktime_t			now;
1024924a311SDavid Härdeman 	s64			delta; /* ns */
1034924a311SDavid Härdeman 	DEFINE_IR_RAW_EVENT(ev);
1044924a311SDavid Härdeman 	int			rc = 0;
1054924a311SDavid Härdeman 	int			delay;
1064924a311SDavid Härdeman 
1074924a311SDavid Härdeman 	if (!dev->raw)
1084924a311SDavid Härdeman 		return -EINVAL;
1094924a311SDavid Härdeman 
1104924a311SDavid Härdeman 	now = ktime_get();
1114924a311SDavid Härdeman 	delta = ktime_to_ns(ktime_sub(now, dev->raw->last_event));
1124924a311SDavid Härdeman 	delay = MS_TO_NS(dev->input_dev->rep[REP_DELAY]);
1134924a311SDavid Härdeman 
1144924a311SDavid Härdeman 	/* Check for a long duration since last event or if we're
1154924a311SDavid Härdeman 	 * being called for the first time, note that delta can't
1164924a311SDavid Härdeman 	 * possibly be negative.
1174924a311SDavid Härdeman 	 */
1184924a311SDavid Härdeman 	if (delta > delay || !dev->raw->last_type)
1194924a311SDavid Härdeman 		type |= IR_START_EVENT;
1204924a311SDavid Härdeman 	else
1214924a311SDavid Härdeman 		ev.duration = delta;
1224924a311SDavid Härdeman 
1234924a311SDavid Härdeman 	if (type & IR_START_EVENT)
1244924a311SDavid Härdeman 		ir_raw_event_reset(dev);
1254924a311SDavid Härdeman 	else if (dev->raw->last_type & IR_SPACE) {
1264924a311SDavid Härdeman 		ev.pulse = false;
1274924a311SDavid Härdeman 		rc = ir_raw_event_store(dev, &ev);
1284924a311SDavid Härdeman 	} else if (dev->raw->last_type & IR_PULSE) {
1294924a311SDavid Härdeman 		ev.pulse = true;
1304924a311SDavid Härdeman 		rc = ir_raw_event_store(dev, &ev);
1314924a311SDavid Härdeman 	} else
1324924a311SDavid Härdeman 		return 0;
1334924a311SDavid Härdeman 
1344924a311SDavid Härdeman 	dev->raw->last_event = now;
1354924a311SDavid Härdeman 	dev->raw->last_type = type;
1364924a311SDavid Härdeman 	return rc;
1374924a311SDavid Härdeman }
1384924a311SDavid Härdeman EXPORT_SYMBOL_GPL(ir_raw_event_store_edge);
1394924a311SDavid Härdeman 
1404924a311SDavid Härdeman /**
1414924a311SDavid Härdeman  * ir_raw_event_store_with_filter() - pass next pulse/space to decoders with some processing
1424924a311SDavid Härdeman  * @dev:	the struct rc_dev device descriptor
1434924a311SDavid Härdeman  * @type:	the type of the event that has occurred
1444924a311SDavid Härdeman  *
1454924a311SDavid Härdeman  * This routine (which may be called from an interrupt context) works
1464924a311SDavid Härdeman  * in similar manner to ir_raw_event_store_edge.
1474924a311SDavid Härdeman  * This routine is intended for devices with limited internal buffer
1484924a311SDavid Härdeman  * It automerges samples of same type, and handles timeouts. Returns non-zero
1494924a311SDavid Härdeman  * if the event was added, and zero if the event was ignored due to idle
1504924a311SDavid Härdeman  * processing.
1514924a311SDavid Härdeman  */
1524924a311SDavid Härdeman int ir_raw_event_store_with_filter(struct rc_dev *dev, struct ir_raw_event *ev)
1534924a311SDavid Härdeman {
1544924a311SDavid Härdeman 	if (!dev->raw)
1554924a311SDavid Härdeman 		return -EINVAL;
1564924a311SDavid Härdeman 
1574924a311SDavid Härdeman 	/* Ignore spaces in idle mode */
1584924a311SDavid Härdeman 	if (dev->idle && !ev->pulse)
1594924a311SDavid Härdeman 		return 0;
1604924a311SDavid Härdeman 	else if (dev->idle)
1614924a311SDavid Härdeman 		ir_raw_event_set_idle(dev, false);
1624924a311SDavid Härdeman 
1634924a311SDavid Härdeman 	if (!dev->raw->this_ev.duration)
1644924a311SDavid Härdeman 		dev->raw->this_ev = *ev;
1654924a311SDavid Härdeman 	else if (ev->pulse == dev->raw->this_ev.pulse)
1664924a311SDavid Härdeman 		dev->raw->this_ev.duration += ev->duration;
1674924a311SDavid Härdeman 	else {
1684924a311SDavid Härdeman 		ir_raw_event_store(dev, &dev->raw->this_ev);
1694924a311SDavid Härdeman 		dev->raw->this_ev = *ev;
1704924a311SDavid Härdeman 	}
1714924a311SDavid Härdeman 
1724924a311SDavid Härdeman 	/* Enter idle mode if nessesary */
1734924a311SDavid Härdeman 	if (!ev->pulse && dev->timeout &&
1744924a311SDavid Härdeman 	    dev->raw->this_ev.duration >= dev->timeout)
1754924a311SDavid Härdeman 		ir_raw_event_set_idle(dev, true);
1764924a311SDavid Härdeman 
1774924a311SDavid Härdeman 	return 1;
1784924a311SDavid Härdeman }
1794924a311SDavid Härdeman EXPORT_SYMBOL_GPL(ir_raw_event_store_with_filter);
1804924a311SDavid Härdeman 
1814924a311SDavid Härdeman /**
1824924a311SDavid Härdeman  * ir_raw_event_set_idle() - provide hint to rc-core when the device is idle or not
1834924a311SDavid Härdeman  * @dev:	the struct rc_dev device descriptor
1844924a311SDavid Härdeman  * @idle:	whether the device is idle or not
1854924a311SDavid Härdeman  */
1864924a311SDavid Härdeman void ir_raw_event_set_idle(struct rc_dev *dev, bool idle)
1874924a311SDavid Härdeman {
1884924a311SDavid Härdeman 	if (!dev->raw)
1894924a311SDavid Härdeman 		return;
1904924a311SDavid Härdeman 
1914924a311SDavid Härdeman 	IR_dprintk(2, "%s idle mode\n", idle ? "enter" : "leave");
1924924a311SDavid Härdeman 
1934924a311SDavid Härdeman 	if (idle) {
1944924a311SDavid Härdeman 		dev->raw->this_ev.timeout = true;
1954924a311SDavid Härdeman 		ir_raw_event_store(dev, &dev->raw->this_ev);
1964924a311SDavid Härdeman 		init_ir_raw_event(&dev->raw->this_ev);
1974924a311SDavid Härdeman 	}
1984924a311SDavid Härdeman 
1994924a311SDavid Härdeman 	if (dev->s_idle)
2004924a311SDavid Härdeman 		dev->s_idle(dev, idle);
2014924a311SDavid Härdeman 
2024924a311SDavid Härdeman 	dev->idle = idle;
2034924a311SDavid Härdeman }
2044924a311SDavid Härdeman EXPORT_SYMBOL_GPL(ir_raw_event_set_idle);
2054924a311SDavid Härdeman 
2064924a311SDavid Härdeman /**
2074924a311SDavid Härdeman  * ir_raw_event_handle() - schedules the decoding of stored ir data
2084924a311SDavid Härdeman  * @dev:	the struct rc_dev device descriptor
2094924a311SDavid Härdeman  *
2104924a311SDavid Härdeman  * This routine will tell rc-core to start decoding stored ir data.
2114924a311SDavid Härdeman  */
2124924a311SDavid Härdeman void ir_raw_event_handle(struct rc_dev *dev)
2134924a311SDavid Härdeman {
214963761a0SSean Young 	if (!dev->raw || !dev->raw->thread)
2154924a311SDavid Härdeman 		return;
2164924a311SDavid Härdeman 
2174924a311SDavid Härdeman 	wake_up_process(dev->raw->thread);
2184924a311SDavid Härdeman }
2194924a311SDavid Härdeman EXPORT_SYMBOL_GPL(ir_raw_event_handle);
2204924a311SDavid Härdeman 
2214924a311SDavid Härdeman /* used internally by the sysfs interface */
2224924a311SDavid Härdeman u64
2234924a311SDavid Härdeman ir_raw_get_allowed_protocols(void)
2244924a311SDavid Härdeman {
22537e90a22SHeiner Kallweit 	return atomic64_read(&available_protocols);
2264924a311SDavid Härdeman }
2274924a311SDavid Härdeman 
2284924a311SDavid Härdeman static int change_protocol(struct rc_dev *dev, u64 *rc_type)
2294924a311SDavid Härdeman {
2304924a311SDavid Härdeman 	/* the caller will update dev->enabled_protocols */
2314924a311SDavid Härdeman 	return 0;
2324924a311SDavid Härdeman }
2334924a311SDavid Härdeman 
23493cffffcSHeiner Kallweit static void ir_raw_disable_protocols(struct rc_dev *dev, u64 protocols)
23593cffffcSHeiner Kallweit {
23693cffffcSHeiner Kallweit 	mutex_lock(&dev->lock);
23793cffffcSHeiner Kallweit 	dev->enabled_protocols &= ~protocols;
23893cffffcSHeiner Kallweit 	mutex_unlock(&dev->lock);
23993cffffcSHeiner Kallweit }
24093cffffcSHeiner Kallweit 
2413875233dSJames Hogan /**
242844a4f45SAntti Seppälä  * ir_raw_gen_manchester() - Encode data with Manchester (bi-phase) modulation.
243844a4f45SAntti Seppälä  * @ev:		Pointer to pointer to next free event. *@ev is incremented for
244844a4f45SAntti Seppälä  *		each raw event filled.
245844a4f45SAntti Seppälä  * @max:	Maximum number of raw events to fill.
246844a4f45SAntti Seppälä  * @timings:	Manchester modulation timings.
247844a4f45SAntti Seppälä  * @n:		Number of bits of data.
248844a4f45SAntti Seppälä  * @data:	Data bits to encode.
249844a4f45SAntti Seppälä  *
250844a4f45SAntti Seppälä  * Encodes the @n least significant bits of @data using Manchester (bi-phase)
251844a4f45SAntti Seppälä  * modulation with the timing characteristics described by @timings, writing up
252844a4f45SAntti Seppälä  * to @max raw IR events using the *@ev pointer.
253844a4f45SAntti Seppälä  *
254844a4f45SAntti Seppälä  * Returns:	0 on success.
255844a4f45SAntti Seppälä  *		-ENOBUFS if there isn't enough space in the array to fit the
256844a4f45SAntti Seppälä  *		full encoded data. In this case all @max events will have been
257844a4f45SAntti Seppälä  *		written.
258844a4f45SAntti Seppälä  */
259844a4f45SAntti Seppälä int ir_raw_gen_manchester(struct ir_raw_event **ev, unsigned int max,
260844a4f45SAntti Seppälä 			  const struct ir_raw_timings_manchester *timings,
261b73bc16dSSean Young 			  unsigned int n, u64 data)
262844a4f45SAntti Seppälä {
263844a4f45SAntti Seppälä 	bool need_pulse;
264b73bc16dSSean Young 	u64 i;
265844a4f45SAntti Seppälä 	int ret = -ENOBUFS;
266844a4f45SAntti Seppälä 
267b73bc16dSSean Young 	i = BIT_ULL(n - 1);
268844a4f45SAntti Seppälä 
269844a4f45SAntti Seppälä 	if (timings->leader) {
270844a4f45SAntti Seppälä 		if (!max--)
271844a4f45SAntti Seppälä 			return ret;
272844a4f45SAntti Seppälä 		if (timings->pulse_space_start) {
273844a4f45SAntti Seppälä 			init_ir_raw_event_duration((*ev)++, 1, timings->leader);
274844a4f45SAntti Seppälä 
275844a4f45SAntti Seppälä 			if (!max--)
276844a4f45SAntti Seppälä 				return ret;
277844a4f45SAntti Seppälä 			init_ir_raw_event_duration((*ev), 0, timings->leader);
278844a4f45SAntti Seppälä 		} else {
279844a4f45SAntti Seppälä 			init_ir_raw_event_duration((*ev), 1, timings->leader);
280844a4f45SAntti Seppälä 		}
281844a4f45SAntti Seppälä 		i >>= 1;
282844a4f45SAntti Seppälä 	} else {
283844a4f45SAntti Seppälä 		/* continue existing signal */
284844a4f45SAntti Seppälä 		--(*ev);
285844a4f45SAntti Seppälä 	}
286844a4f45SAntti Seppälä 	/* from here on *ev will point to the last event rather than the next */
287844a4f45SAntti Seppälä 
288844a4f45SAntti Seppälä 	while (n && i > 0) {
289844a4f45SAntti Seppälä 		need_pulse = !(data & i);
290844a4f45SAntti Seppälä 		if (timings->invert)
291844a4f45SAntti Seppälä 			need_pulse = !need_pulse;
292844a4f45SAntti Seppälä 		if (need_pulse == !!(*ev)->pulse) {
293844a4f45SAntti Seppälä 			(*ev)->duration += timings->clock;
294844a4f45SAntti Seppälä 		} else {
295844a4f45SAntti Seppälä 			if (!max--)
296844a4f45SAntti Seppälä 				goto nobufs;
297844a4f45SAntti Seppälä 			init_ir_raw_event_duration(++(*ev), need_pulse,
298844a4f45SAntti Seppälä 						   timings->clock);
299844a4f45SAntti Seppälä 		}
300844a4f45SAntti Seppälä 
301844a4f45SAntti Seppälä 		if (!max--)
302844a4f45SAntti Seppälä 			goto nobufs;
303844a4f45SAntti Seppälä 		init_ir_raw_event_duration(++(*ev), !need_pulse,
304844a4f45SAntti Seppälä 					   timings->clock);
305844a4f45SAntti Seppälä 		i >>= 1;
306844a4f45SAntti Seppälä 	}
307844a4f45SAntti Seppälä 
308844a4f45SAntti Seppälä 	if (timings->trailer_space) {
309844a4f45SAntti Seppälä 		if (!(*ev)->pulse)
310844a4f45SAntti Seppälä 			(*ev)->duration += timings->trailer_space;
311844a4f45SAntti Seppälä 		else if (!max--)
312844a4f45SAntti Seppälä 			goto nobufs;
313844a4f45SAntti Seppälä 		else
314844a4f45SAntti Seppälä 			init_ir_raw_event_duration(++(*ev), 0,
315844a4f45SAntti Seppälä 						   timings->trailer_space);
316844a4f45SAntti Seppälä 	}
317844a4f45SAntti Seppälä 
318844a4f45SAntti Seppälä 	ret = 0;
319844a4f45SAntti Seppälä nobufs:
320844a4f45SAntti Seppälä 	/* point to the next event rather than last event before returning */
321844a4f45SAntti Seppälä 	++(*ev);
322844a4f45SAntti Seppälä 	return ret;
323844a4f45SAntti Seppälä }
324844a4f45SAntti Seppälä EXPORT_SYMBOL(ir_raw_gen_manchester);
325844a4f45SAntti Seppälä 
326844a4f45SAntti Seppälä /**
327caec0984SJames Hogan  * ir_raw_gen_pd() - Encode data to raw events with pulse-distance modulation.
328caec0984SJames Hogan  * @ev:		Pointer to pointer to next free event. *@ev is incremented for
329caec0984SJames Hogan  *		each raw event filled.
330caec0984SJames Hogan  * @max:	Maximum number of raw events to fill.
331caec0984SJames Hogan  * @timings:	Pulse distance modulation timings.
332caec0984SJames Hogan  * @n:		Number of bits of data.
333caec0984SJames Hogan  * @data:	Data bits to encode.
334caec0984SJames Hogan  *
335caec0984SJames Hogan  * Encodes the @n least significant bits of @data using pulse-distance
336caec0984SJames Hogan  * modulation with the timing characteristics described by @timings, writing up
337caec0984SJames Hogan  * to @max raw IR events using the *@ev pointer.
338caec0984SJames Hogan  *
339caec0984SJames Hogan  * Returns:	0 on success.
340caec0984SJames Hogan  *		-ENOBUFS if there isn't enough space in the array to fit the
341caec0984SJames Hogan  *		full encoded data. In this case all @max events will have been
342caec0984SJames Hogan  *		written.
343caec0984SJames Hogan  */
344caec0984SJames Hogan int ir_raw_gen_pd(struct ir_raw_event **ev, unsigned int max,
345caec0984SJames Hogan 		  const struct ir_raw_timings_pd *timings,
346caec0984SJames Hogan 		  unsigned int n, u64 data)
347caec0984SJames Hogan {
348caec0984SJames Hogan 	int i;
349caec0984SJames Hogan 	int ret;
350caec0984SJames Hogan 	unsigned int space;
351caec0984SJames Hogan 
352caec0984SJames Hogan 	if (timings->header_pulse) {
353caec0984SJames Hogan 		ret = ir_raw_gen_pulse_space(ev, &max, timings->header_pulse,
354caec0984SJames Hogan 					     timings->header_space);
355caec0984SJames Hogan 		if (ret)
356caec0984SJames Hogan 			return ret;
357caec0984SJames Hogan 	}
358caec0984SJames Hogan 
359caec0984SJames Hogan 	if (timings->msb_first) {
360caec0984SJames Hogan 		for (i = n - 1; i >= 0; --i) {
361caec0984SJames Hogan 			space = timings->bit_space[(data >> i) & 1];
362caec0984SJames Hogan 			ret = ir_raw_gen_pulse_space(ev, &max,
363caec0984SJames Hogan 						     timings->bit_pulse,
364caec0984SJames Hogan 						     space);
365caec0984SJames Hogan 			if (ret)
366caec0984SJames Hogan 				return ret;
367caec0984SJames Hogan 		}
368caec0984SJames Hogan 	} else {
369caec0984SJames Hogan 		for (i = 0; i < n; ++i, data >>= 1) {
370caec0984SJames Hogan 			space = timings->bit_space[data & 1];
371caec0984SJames Hogan 			ret = ir_raw_gen_pulse_space(ev, &max,
372caec0984SJames Hogan 						     timings->bit_pulse,
373caec0984SJames Hogan 						     space);
374caec0984SJames Hogan 			if (ret)
375caec0984SJames Hogan 				return ret;
376caec0984SJames Hogan 		}
377caec0984SJames Hogan 	}
378caec0984SJames Hogan 
379caec0984SJames Hogan 	ret = ir_raw_gen_pulse_space(ev, &max, timings->trailer_pulse,
380caec0984SJames Hogan 				     timings->trailer_space);
381caec0984SJames Hogan 	return ret;
382caec0984SJames Hogan }
383caec0984SJames Hogan EXPORT_SYMBOL(ir_raw_gen_pd);
384caec0984SJames Hogan 
385caec0984SJames Hogan /**
386103293beSSean Young  * ir_raw_gen_pl() - Encode data to raw events with pulse-length modulation.
387103293beSSean Young  * @ev:		Pointer to pointer to next free event. *@ev is incremented for
388103293beSSean Young  *		each raw event filled.
389103293beSSean Young  * @max:	Maximum number of raw events to fill.
390103293beSSean Young  * @timings:	Pulse distance modulation timings.
391103293beSSean Young  * @n:		Number of bits of data.
392103293beSSean Young  * @data:	Data bits to encode.
393103293beSSean Young  *
394103293beSSean Young  * Encodes the @n least significant bits of @data using space-distance
395103293beSSean Young  * modulation with the timing characteristics described by @timings, writing up
396103293beSSean Young  * to @max raw IR events using the *@ev pointer.
397103293beSSean Young  *
398103293beSSean Young  * Returns:	0 on success.
399103293beSSean Young  *		-ENOBUFS if there isn't enough space in the array to fit the
400103293beSSean Young  *		full encoded data. In this case all @max events will have been
401103293beSSean Young  *		written.
402103293beSSean Young  */
403103293beSSean Young int ir_raw_gen_pl(struct ir_raw_event **ev, unsigned int max,
404103293beSSean Young 		  const struct ir_raw_timings_pl *timings,
405103293beSSean Young 		  unsigned int n, u64 data)
406103293beSSean Young {
407103293beSSean Young 	int i;
408103293beSSean Young 	int ret = -ENOBUFS;
409103293beSSean Young 	unsigned int pulse;
410103293beSSean Young 
411103293beSSean Young 	if (!max--)
412103293beSSean Young 		return ret;
413103293beSSean Young 
414103293beSSean Young 	init_ir_raw_event_duration((*ev)++, 1, timings->header_pulse);
415103293beSSean Young 
416103293beSSean Young 	if (timings->msb_first) {
417103293beSSean Young 		for (i = n - 1; i >= 0; --i) {
418103293beSSean Young 			if (!max--)
419103293beSSean Young 				return ret;
420103293beSSean Young 			init_ir_raw_event_duration((*ev)++, 0,
421103293beSSean Young 						   timings->bit_space);
422103293beSSean Young 			if (!max--)
423103293beSSean Young 				return ret;
424103293beSSean Young 			pulse = timings->bit_pulse[(data >> i) & 1];
425103293beSSean Young 			init_ir_raw_event_duration((*ev)++, 1, pulse);
426103293beSSean Young 		}
427103293beSSean Young 	} else {
428103293beSSean Young 		for (i = 0; i < n; ++i, data >>= 1) {
429103293beSSean Young 			if (!max--)
430103293beSSean Young 				return ret;
431103293beSSean Young 			init_ir_raw_event_duration((*ev)++, 0,
432103293beSSean Young 						   timings->bit_space);
433103293beSSean Young 			if (!max--)
434103293beSSean Young 				return ret;
435103293beSSean Young 			pulse = timings->bit_pulse[data & 1];
436103293beSSean Young 			init_ir_raw_event_duration((*ev)++, 1, pulse);
437103293beSSean Young 		}
438103293beSSean Young 	}
439103293beSSean Young 
440103293beSSean Young 	if (!max--)
441103293beSSean Young 		return ret;
442103293beSSean Young 
443103293beSSean Young 	init_ir_raw_event_duration((*ev)++, 0, timings->trailer_space);
444103293beSSean Young 
445103293beSSean Young 	return 0;
446103293beSSean Young }
447103293beSSean Young EXPORT_SYMBOL(ir_raw_gen_pl);
448103293beSSean Young 
449103293beSSean Young /**
4503875233dSJames Hogan  * ir_raw_encode_scancode() - Encode a scancode as raw events
4513875233dSJames Hogan  *
4523875233dSJames Hogan  * @protocol:		protocol
4533875233dSJames Hogan  * @scancode:		scancode filter describing a single scancode
4543875233dSJames Hogan  * @events:		array of raw events to write into
4553875233dSJames Hogan  * @max:		max number of raw events
4563875233dSJames Hogan  *
4573875233dSJames Hogan  * Attempts to encode the scancode as raw events.
4583875233dSJames Hogan  *
4593875233dSJames Hogan  * Returns:	The number of events written.
4603875233dSJames Hogan  *		-ENOBUFS if there isn't enough space in the array to fit the
4613875233dSJames Hogan  *		encoding. In this case all @max events will have been written.
4623875233dSJames Hogan  *		-EINVAL if the scancode is ambiguous or invalid, or if no
4633875233dSJames Hogan  *		compatible encoder was found.
4643875233dSJames Hogan  */
4653875233dSJames Hogan int ir_raw_encode_scancode(enum rc_type protocol, u32 scancode,
4663875233dSJames Hogan 			   struct ir_raw_event *events, unsigned int max)
4673875233dSJames Hogan {
4683875233dSJames Hogan 	struct ir_raw_handler *handler;
4693875233dSJames Hogan 	int ret = -EINVAL;
4703875233dSJames Hogan 	u64 mask = 1ULL << protocol;
4713875233dSJames Hogan 
4723875233dSJames Hogan 	mutex_lock(&ir_raw_handler_lock);
4733875233dSJames Hogan 	list_for_each_entry(handler, &ir_raw_handler_list, list) {
4743875233dSJames Hogan 		if (handler->protocols & mask && handler->encode) {
4753875233dSJames Hogan 			ret = handler->encode(protocol, scancode, events, max);
4763875233dSJames Hogan 			if (ret >= 0 || ret == -ENOBUFS)
4773875233dSJames Hogan 				break;
4783875233dSJames Hogan 		}
4793875233dSJames Hogan 	}
4803875233dSJames Hogan 	mutex_unlock(&ir_raw_handler_lock);
4813875233dSJames Hogan 
4823875233dSJames Hogan 	return ret;
4833875233dSJames Hogan }
4843875233dSJames Hogan EXPORT_SYMBOL(ir_raw_encode_scancode);
4853875233dSJames Hogan 
4864924a311SDavid Härdeman /*
4874924a311SDavid Härdeman  * Used to (un)register raw event clients
4884924a311SDavid Härdeman  */
4894924a311SDavid Härdeman int ir_raw_event_register(struct rc_dev *dev)
4904924a311SDavid Härdeman {
4914924a311SDavid Härdeman 	int rc;
4924924a311SDavid Härdeman 	struct ir_raw_handler *handler;
493963761a0SSean Young 	struct task_struct *thread;
4944924a311SDavid Härdeman 
4954924a311SDavid Härdeman 	if (!dev)
4964924a311SDavid Härdeman 		return -EINVAL;
4974924a311SDavid Härdeman 
4984924a311SDavid Härdeman 	dev->raw = kzalloc(sizeof(*dev->raw), GFP_KERNEL);
4994924a311SDavid Härdeman 	if (!dev->raw)
5004924a311SDavid Härdeman 		return -ENOMEM;
5014924a311SDavid Härdeman 
5024924a311SDavid Härdeman 	dev->raw->dev = dev;
5034924a311SDavid Härdeman 	dev->change_protocol = change_protocol;
504464254e5SHeiner Kallweit 	INIT_KFIFO(dev->raw->kfifo);
5054924a311SDavid Härdeman 
506d5083677SAndi Shyti 	/*
507d5083677SAndi Shyti 	 * raw transmitters do not need any event registration
508d5083677SAndi Shyti 	 * because the event is coming from userspace
509d5083677SAndi Shyti 	 */
510d5083677SAndi Shyti 	if (dev->driver_type != RC_DRIVER_IR_RAW_TX) {
511963761a0SSean Young 		thread = kthread_run(ir_raw_event_thread, dev->raw, "rc%u",
512963761a0SSean Young 				     dev->minor);
5134924a311SDavid Härdeman 
514963761a0SSean Young 		if (IS_ERR(thread)) {
515963761a0SSean Young 			rc = PTR_ERR(thread);
5164924a311SDavid Härdeman 			goto out;
5174924a311SDavid Härdeman 		}
518963761a0SSean Young 
519963761a0SSean Young 		dev->raw->thread = thread;
520d5083677SAndi Shyti 	}
5214924a311SDavid Härdeman 
5224924a311SDavid Härdeman 	mutex_lock(&ir_raw_handler_lock);
5234924a311SDavid Härdeman 	list_add_tail(&dev->raw->list, &ir_raw_client_list);
5244924a311SDavid Härdeman 	list_for_each_entry(handler, &ir_raw_handler_list, list)
5254924a311SDavid Härdeman 		if (handler->raw_register)
5264924a311SDavid Härdeman 			handler->raw_register(dev);
5274924a311SDavid Härdeman 	mutex_unlock(&ir_raw_handler_lock);
5284924a311SDavid Härdeman 
5294924a311SDavid Härdeman 	return 0;
5304924a311SDavid Härdeman 
5314924a311SDavid Härdeman out:
5324924a311SDavid Härdeman 	kfree(dev->raw);
5334924a311SDavid Härdeman 	dev->raw = NULL;
5344924a311SDavid Härdeman 	return rc;
5354924a311SDavid Härdeman }
5364924a311SDavid Härdeman 
5374924a311SDavid Härdeman void ir_raw_event_unregister(struct rc_dev *dev)
5384924a311SDavid Härdeman {
5394924a311SDavid Härdeman 	struct ir_raw_handler *handler;
5404924a311SDavid Härdeman 
5414924a311SDavid Härdeman 	if (!dev || !dev->raw)
5424924a311SDavid Härdeman 		return;
5434924a311SDavid Härdeman 
5444924a311SDavid Härdeman 	kthread_stop(dev->raw->thread);
5454924a311SDavid Härdeman 
5464924a311SDavid Härdeman 	mutex_lock(&ir_raw_handler_lock);
5474924a311SDavid Härdeman 	list_del(&dev->raw->list);
5484924a311SDavid Härdeman 	list_for_each_entry(handler, &ir_raw_handler_list, list)
5494924a311SDavid Härdeman 		if (handler->raw_unregister)
5504924a311SDavid Härdeman 			handler->raw_unregister(dev);
5514924a311SDavid Härdeman 	mutex_unlock(&ir_raw_handler_lock);
5524924a311SDavid Härdeman 
5534924a311SDavid Härdeman 	kfree(dev->raw);
5544924a311SDavid Härdeman 	dev->raw = NULL;
5554924a311SDavid Härdeman }
5564924a311SDavid Härdeman 
5574924a311SDavid Härdeman /*
5584924a311SDavid Härdeman  * Extension interface - used to register the IR decoders
5594924a311SDavid Härdeman  */
5604924a311SDavid Härdeman 
5614924a311SDavid Härdeman int ir_raw_handler_register(struct ir_raw_handler *ir_raw_handler)
5624924a311SDavid Härdeman {
5634924a311SDavid Härdeman 	struct ir_raw_event_ctrl *raw;
5644924a311SDavid Härdeman 
5654924a311SDavid Härdeman 	mutex_lock(&ir_raw_handler_lock);
5664924a311SDavid Härdeman 	list_add_tail(&ir_raw_handler->list, &ir_raw_handler_list);
5674924a311SDavid Härdeman 	if (ir_raw_handler->raw_register)
5684924a311SDavid Härdeman 		list_for_each_entry(raw, &ir_raw_client_list, list)
5694924a311SDavid Härdeman 			ir_raw_handler->raw_register(raw->dev);
57037e90a22SHeiner Kallweit 	atomic64_or(ir_raw_handler->protocols, &available_protocols);
5714924a311SDavid Härdeman 	mutex_unlock(&ir_raw_handler_lock);
5724924a311SDavid Härdeman 
5734924a311SDavid Härdeman 	return 0;
5744924a311SDavid Härdeman }
5754924a311SDavid Härdeman EXPORT_SYMBOL(ir_raw_handler_register);
5764924a311SDavid Härdeman 
5774924a311SDavid Härdeman void ir_raw_handler_unregister(struct ir_raw_handler *ir_raw_handler)
5784924a311SDavid Härdeman {
5794924a311SDavid Härdeman 	struct ir_raw_event_ctrl *raw;
58093cffffcSHeiner Kallweit 	u64 protocols = ir_raw_handler->protocols;
5814924a311SDavid Härdeman 
5824924a311SDavid Härdeman 	mutex_lock(&ir_raw_handler_lock);
5834924a311SDavid Härdeman 	list_del(&ir_raw_handler->list);
58493cffffcSHeiner Kallweit 	list_for_each_entry(raw, &ir_raw_client_list, list) {
58593cffffcSHeiner Kallweit 		ir_raw_disable_protocols(raw->dev, protocols);
5864924a311SDavid Härdeman 		if (ir_raw_handler->raw_unregister)
5874924a311SDavid Härdeman 			ir_raw_handler->raw_unregister(raw->dev);
58893cffffcSHeiner Kallweit 	}
58937e90a22SHeiner Kallweit 	atomic64_andnot(protocols, &available_protocols);
5904924a311SDavid Härdeman 	mutex_unlock(&ir_raw_handler_lock);
5914924a311SDavid Härdeman }
5924924a311SDavid Härdeman EXPORT_SYMBOL(ir_raw_handler_unregister);
593